From c63fa78351c49399257354a03289aaa2a230384a Mon Sep 17 00:00:00 2001 From: alex Date: Sat, 10 Jan 2004 21:01:15 +0000 Subject: [PATCH] - vanilla-2.4.24 series and needed patches NOTE: do not use it for a while, please. ext3-delete-thread must be reworked first. --- .../patches/gfp_memalloc-2.4.24.patch | 59 + .../patches/linux-2.4.24-xattr-0.8.54.patch | 5474 +++ .../patches/uml-export-end_iomem.patch | 12 + .../patches/uml-patch-2.4.23-1.patch | 42024 +++++++++++++++++++ lustre/kernel_patches/series/vanilla-2.4.24 | 35 + 5 files changed, 47604 insertions(+) create mode 100644 lustre/kernel_patches/patches/gfp_memalloc-2.4.24.patch create mode 100644 lustre/kernel_patches/patches/linux-2.4.24-xattr-0.8.54.patch create mode 100644 lustre/kernel_patches/patches/uml-export-end_iomem.patch create mode 100644 lustre/kernel_patches/patches/uml-patch-2.4.23-1.patch create mode 100644 lustre/kernel_patches/series/vanilla-2.4.24 diff --git a/lustre/kernel_patches/patches/gfp_memalloc-2.4.24.patch b/lustre/kernel_patches/patches/gfp_memalloc-2.4.24.patch new file mode 100644 index 0000000..5780b1b --- /dev/null +++ b/lustre/kernel_patches/patches/gfp_memalloc-2.4.24.patch @@ -0,0 +1,59 @@ +Index: linux-2.4.21-suse2/include/linux/mm.h +=================================================================== +--- linux-2.4.21-suse2.orig/include/linux/mm.h 2004-01-10 15:51:22.000000000 +0300 ++++ linux-2.4.21-suse2/include/linux/mm.h 2004-01-10 16:02:42.000000000 +0300 +@@ -661,6 +661,7 @@ + #define __GFP_IO 0x40 /* Can start low memory physical IO? */ + #define __GFP_HIGHIO 0x80 /* Can start high mem physical IO? */ + #define __GFP_FS 0x100 /* Can call down to low-level FS? */ ++#define __GFP_MEMALLOC 0x200 /* like PF_MEMALLOC: see __alloc_pages */ + + #define GFP_NOHIGHIO (__GFP_HIGH | __GFP_WAIT | __GFP_IO) + #define GFP_NOIO (__GFP_HIGH | __GFP_WAIT) +@@ -671,6 +672,7 @@ + #define GFP_KERNEL (__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS) + #define GFP_NFS (__GFP_HIGH | __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS) + #define GFP_KSWAPD ( __GFP_WAIT | __GFP_IO | __GFP_HIGHIO | __GFP_FS) ++#define GFP_MEMALLOC __GFP_MEMALLOC + + /* Flag - indicates that the buffer will be suitable for DMA. Ignored on some + platforms, used as appropriate on others */ +Index: linux-2.4.21-suse2/include/linux/slab.h +=================================================================== +--- linux-2.4.21-suse2.orig/include/linux/slab.h 2004-01-10 12:48:36.000000000 +0300 ++++ linux-2.4.21-suse2/include/linux/slab.h 2004-01-10 16:02:42.000000000 +0300 +@@ -23,6 +23,7 @@ + #define SLAB_KERNEL GFP_KERNEL + #define SLAB_NFS GFP_NFS + #define SLAB_DMA GFP_DMA ++#define SLAB_MEMALLOC GFP_MEMALLOC + + #define SLAB_LEVEL_MASK (__GFP_WAIT|__GFP_HIGH|__GFP_IO|__GFP_HIGHIO|__GFP_FS) + #define SLAB_NO_GROW 0x00001000UL /* don't grow a cache */ +Index: linux-2.4.21-suse2/mm/page_alloc.c +=================================================================== +--- linux-2.4.21-suse2.orig/mm/page_alloc.c 2004-01-10 14:56:13.000000000 +0300 ++++ linux-2.4.21-suse2/mm/page_alloc.c 2004-01-10 16:03:20.000000000 +0300 +@@ -448,7 +448,8 @@ + + /* here we're in the low on memory slow path */ + +- if (current->flags & PF_MEMALLOC && !in_interrupt()) { ++ if (((current->flags & PF_MEMALLOC) || (gfp_mask & __GFP_MEMALLOC)) ++ && !in_interrupt()) { + zone = zonelist->zones; + for (;;) { + zone_t *z = *(zone++); +Index: linux-2.4.21-suse2/mm/slab.c +=================================================================== +--- linux-2.4.21-suse2.orig/mm/slab.c 2003-10-28 21:33:57.000000000 +0300 ++++ linux-2.4.21-suse2/mm/slab.c 2004-01-10 16:02:42.000000000 +0300 +@@ -1115,7 +1115,7 @@ + /* Be lazy and only check for valid flags here, + * keeping it out of the critical path in kmem_cache_alloc(). + */ +- if (flags & ~(SLAB_DMA|SLAB_LEVEL_MASK|SLAB_NO_GROW)) ++ if (flags & ~(SLAB_DMA|SLAB_LEVEL_MASK|SLAB_NO_GROW|SLAB_MEMALLOC)) + BUG(); + if (flags & SLAB_NO_GROW) + return 0; diff --git a/lustre/kernel_patches/patches/linux-2.4.24-xattr-0.8.54.patch b/lustre/kernel_patches/patches/linux-2.4.24-xattr-0.8.54.patch new file mode 100644 index 0000000..144ff3f --- /dev/null +++ b/lustre/kernel_patches/patches/linux-2.4.24-xattr-0.8.54.patch @@ -0,0 +1,5474 @@ + Documentation/Configure.help | 66 ++ + arch/alpha/defconfig | 7 + arch/alpha/kernel/entry.S | 12 + arch/arm/defconfig | 7 + arch/arm/kernel/calls.S | 24 + arch/i386/defconfig | 7 + arch/ia64/defconfig | 7 + arch/ia64/kernel/entry.S | 24 + arch/m68k/defconfig | 7 + arch/mips/defconfig | 7 + arch/mips64/defconfig | 7 + arch/ppc/defconfig | 14 + arch/ppc64/kernel/misc.S | 2 + arch/s390/defconfig | 7 + arch/s390/kernel/entry.S | 24 + arch/s390x/defconfig | 7 + arch/s390x/kernel/entry.S | 24 + arch/s390x/kernel/wrapper32.S | 92 +++ + arch/sparc/defconfig | 7 + arch/sparc/kernel/systbls.S | 10 + arch/sparc64/defconfig | 7 + arch/sparc64/kernel/systbls.S | 20 + fs/Config.in | 14 + fs/Makefile | 3 + fs/ext2/Makefile | 4 + fs/ext2/file.c | 5 + fs/ext2/ialloc.c | 2 + fs/ext2/inode.c | 34 - + fs/ext2/namei.c | 14 + fs/ext2/super.c | 29 + fs/ext2/symlink.c | 14 + fs/ext2/xattr.c | 1212 +++++++++++++++++++++++++++++++++++++++++ + fs/ext2/xattr_user.c | 103 +++ + fs/ext3/Makefile | 10 + fs/ext3/file.c | 5 + fs/ext3/ialloc.c | 2 + fs/ext3/inode.c | 35 - + fs/ext3/namei.c | 21 + fs/ext3/super.c | 36 + + fs/ext3/symlink.c | 14 + fs/ext3/xattr.c | 1225 ++++++++++++++++++++++++++++++++++++++++++ + fs/ext3/xattr_user.c | 111 +++ + fs/jfs/jfs_xattr.h | 6 + fs/jfs/xattr.c | 6 + fs/mbcache.c | 648 ++++++++++++++++++++++ + include/asm-arm/unistd.h | 2 + include/asm-ia64/unistd.h | 13 + include/asm-ppc64/unistd.h | 2 + include/asm-s390/unistd.h | 15 + include/asm-s390x/unistd.h | 15 + include/asm-sparc/unistd.h | 24 + include/asm-sparc64/unistd.h | 24 + include/linux/cache_def.h | 15 + include/linux/errno.h | 4 + include/linux/ext2_fs.h | 31 - + include/linux/ext2_xattr.h | 157 +++++ + include/linux/ext3_fs.h | 31 - + include/linux/ext3_jbd.h | 8 + include/linux/ext3_xattr.h | 157 +++++ + include/linux/fs.h | 2 + include/linux/mbcache.h | 69 ++ + kernel/ksyms.c | 4 + mm/vmscan.c | 35 + + fs/ext3/ext3-exports.c | 14 + + 64 files changed, 4355 insertions(+), 195 deletions(-) + +Index: linux-2.4.24-vanilla/Documentation/Configure.help +=================================================================== +--- linux-2.4.24-vanilla.orig/Documentation/Configure.help 2004-01-10 17:05:37.000000000 +0300 ++++ linux-2.4.24-vanilla/Documentation/Configure.help 2004-01-10 17:20:28.000000000 +0300 +@@ -16295,6 +16295,39 @@ + be compiled as a module, and so this could be dangerous. Most + everyone wants to say Y here. + ++Ext2 extended attributes ++CONFIG_EXT2_FS_XATTR ++ Extended attributes are name:value pairs associated with inodes by ++ the kernel or by users (see the attr(5) manual page, or visit ++ for details). ++ ++ If unsure, say N. ++ ++Ext2 extended attribute block sharing ++CONFIG_EXT2_FS_XATTR_SHARING ++ This options enables code for sharing identical extended attribute ++ blocks among multiple inodes. ++ ++ Usually, say Y. ++ ++Ext2 extended user attributes ++CONFIG_EXT2_FS_XATTR_USER ++ This option enables extended user attributes on ext2. Processes can ++ associate extended user attributes with inodes to store additional ++ information such as the character encoding of files, etc. (see the ++ attr(5) manual page, or visit for details). ++ ++ If unsure, say N. ++ ++Ext2 trusted extended attributes ++CONFIG_EXT2_FS_XATTR_TRUSTED ++ This option enables extended attributes on ext2 that are accessible ++ (and visible) only to users capable of CAP_SYS_ADMIN. Usually this ++ is only the super user. Trusted extended attributes are meant for ++ implementing system/security services. ++ ++ If unsure, say N. ++ + Ext3 journalling file system support (EXPERIMENTAL) + CONFIG_EXT3_FS + This is the journalling version of the Second extended file system +@@ -16327,6 +16360,39 @@ + of your root partition (the one containing the directory /) cannot + be compiled as a module, and so this may be dangerous. + ++Ext3 extended attributes ++CONFIG_EXT3_FS_XATTR ++ Extended attributes are name:value pairs associated with inodes by ++ the kernel or by users (see the attr(5) manual page, or visit ++ for details). ++ ++ If unsure, say N. ++ ++Ext3 extended attribute block sharing ++CONFIG_EXT3_FS_XATTR_SHARING ++ This options enables code for sharing identical extended attribute ++ blocks among multiple inodes. ++ ++ Usually, say Y. ++ ++Ext3 extended user attributes ++CONFIG_EXT3_FS_XATTR_USER ++ This option enables extended user attributes on ext3. Processes can ++ associate extended user attributes with inodes to store additional ++ information such as the character encoding of files, etc. (see the ++ attr(5) manual page, or visit for details). ++ ++ If unsure, say N. ++ ++Ext3 trusted extended attributes ++CONFIG_EXT3_FS_XATTR_TRUSTED ++ This option enables extended attributes on ext3 that are accessible ++ (and visible) only to users capable of CAP_SYS_ADMIN. Usually this ++ is only the super user. Trusted extended attributes are meant for ++ implementing system/security services. ++ ++ If unsure, say N. ++ + Journal Block Device support (JBD for ext3) (EXPERIMENTAL) + CONFIG_JBD + This is a generic journalling layer for block devices. It is +Index: linux-2.4.24-vanilla/arch/alpha/defconfig +=================================================================== +--- linux-2.4.24-vanilla.orig/arch/alpha/defconfig 2004-01-10 17:04:37.000000000 +0300 ++++ linux-2.4.24-vanilla/arch/alpha/defconfig 2004-01-10 17:20:28.000000000 +0300 +@@ -1,6 +1,13 @@ + # + # Automatically generated make config: don't edit + # ++# CONFIG_EXT3_FS_XATTR is not set ++# CONFIG_EXT3_FS_XATTR_SHARING is not set ++# CONFIG_EXT3_FS_XATTR_USER is not set ++# CONFIG_EXT2_FS_XATTR is not set ++# CONFIG_EXT2_FS_XATTR_SHARING is not set ++# CONFIG_EXT2_FS_XATTR_USER is not set ++# CONFIG_FS_MBCACHE is not set + CONFIG_ALPHA=y + # CONFIG_UID16 is not set + # CONFIG_RWSEM_GENERIC_SPINLOCK is not set +Index: linux-2.4.24-vanilla/arch/alpha/kernel/entry.S +=================================================================== +--- linux-2.4.24-vanilla.orig/arch/alpha/kernel/entry.S 2004-01-10 17:04:37.000000000 +0300 ++++ linux-2.4.24-vanilla/arch/alpha/kernel/entry.S 2004-01-10 17:20:28.000000000 +0300 +@@ -1154,6 +1154,18 @@ + .quad sys_readahead + .quad sys_ni_syscall /* 380, sys_security */ + .quad sys_tkill ++ .quad sys_setxattr ++ .quad sys_lsetxattr ++ .quad sys_fsetxattr ++ .quad sys_getxattr /* 385 */ ++ .quad sys_lgetxattr ++ .quad sys_fgetxattr ++ .quad sys_listxattr ++ .quad sys_llistxattr ++ .quad sys_flistxattr /* 390 */ ++ .quad sys_removexattr ++ .quad sys_lremovexattr ++ .quad sys_fremovexattr + + /* Remember to update everything, kids. */ + .ifne (. - sys_call_table) - (NR_SYSCALLS * 8) +Index: linux-2.4.24-vanilla/arch/arm/defconfig +=================================================================== +--- linux-2.4.24-vanilla.orig/arch/arm/defconfig 2001-05-20 04:43:05.000000000 +0400 ++++ linux-2.4.24-vanilla/arch/arm/defconfig 2004-01-10 17:20:28.000000000 +0300 +@@ -1,6 +1,13 @@ + # + # Automatically generated make config: don't edit + # ++# CONFIG_EXT3_FS_XATTR is not set ++# CONFIG_EXT3_FS_XATTR_SHARING is not set ++# CONFIG_EXT3_FS_XATTR_USER is not set ++# CONFIG_EXT2_FS_XATTR is not set ++# CONFIG_EXT2_FS_XATTR_SHARING is not set ++# CONFIG_EXT2_FS_XATTR_USER is not set ++# CONFIG_FS_MBCACHE is not set + CONFIG_ARM=y + # CONFIG_EISA is not set + # CONFIG_SBUS is not set +Index: linux-2.4.24-vanilla/arch/arm/kernel/calls.S +=================================================================== +--- linux-2.4.24-vanilla.orig/arch/arm/kernel/calls.S 2004-01-10 17:04:58.000000000 +0300 ++++ linux-2.4.24-vanilla/arch/arm/kernel/calls.S 2004-01-10 17:20:28.000000000 +0300 +@@ -240,18 +240,18 @@ + .long SYMBOL_NAME(sys_ni_syscall) /* Security */ + .long SYMBOL_NAME(sys_gettid) + /* 225 */ .long SYMBOL_NAME(sys_readahead) +- .long SYMBOL_NAME(sys_ni_syscall) /* setxattr */ +- .long SYMBOL_NAME(sys_ni_syscall) /* lsetxattr */ +- .long SYMBOL_NAME(sys_ni_syscall) /* fsetxattr */ +- .long SYMBOL_NAME(sys_ni_syscall) /* getxattr */ +-/* 230 */ .long SYMBOL_NAME(sys_ni_syscall) /* lgetxattr */ +- .long SYMBOL_NAME(sys_ni_syscall) /* fgetxattr */ +- .long SYMBOL_NAME(sys_ni_syscall) /* listxattr */ +- .long SYMBOL_NAME(sys_ni_syscall) /* llistxattr */ +- .long SYMBOL_NAME(sys_ni_syscall) /* flistxattr */ +-/* 235 */ .long SYMBOL_NAME(sys_ni_syscall) /* removexattr */ +- .long SYMBOL_NAME(sys_ni_syscall) /* lremovexattr */ +- .long SYMBOL_NAME(sys_ni_syscall) /* fremovexattr */ ++ .long SYMBOL_NAME(sys_setxattr) ++ .long SYMBOL_NAME(sys_lsetxattr) ++ .long SYMBOL_NAME(sys_fsetxattr) ++ .long SYMBOL_NAME(sys_getxattr) ++/* 230 */ .long SYMBOL_NAME(sys_lgetxattr) ++ .long SYMBOL_NAME(sys_fgetxattr) ++ .long SYMBOL_NAME(sys_listxattr) ++ .long SYMBOL_NAME(sys_llistxattr) ++ .long SYMBOL_NAME(sys_flistxattr) ++/* 235 */ .long SYMBOL_NAME(sys_removexattr) ++ .long SYMBOL_NAME(sys_lremovexattr) ++ .long SYMBOL_NAME(sys_fremovexattr) + .long SYMBOL_NAME(sys_tkill) + .long SYMBOL_NAME(sys_ni_syscall) /* sendfile64 */ + /* 240 */ .long SYMBOL_NAME(sys_ni_syscall) /* futex */ +Index: linux-2.4.24-vanilla/arch/i386/defconfig +=================================================================== +--- linux-2.4.24-vanilla.orig/arch/i386/defconfig 2004-01-10 17:05:45.000000000 +0300 ++++ linux-2.4.24-vanilla/arch/i386/defconfig 2004-01-10 17:20:28.000000000 +0300 +@@ -1,6 +1,13 @@ + # + # Automatically generated make config: don't edit + # ++# CONFIG_EXT3_FS_XATTR is not set ++# CONFIG_EXT3_FS_XATTR_SHARING is not set ++# CONFIG_EXT3_FS_XATTR_USER is not set ++# CONFIG_EXT2_FS_XATTR is not set ++# CONFIG_EXT2_FS_XATTR_SHARING is not set ++# CONFIG_EXT2_FS_XATTR_USER is not set ++# CONFIG_FS_MBCACHE is not set + CONFIG_X86=y + CONFIG_ISA=y + # CONFIG_SBUS is not set +Index: linux-2.4.24-vanilla/arch/ia64/defconfig +=================================================================== +--- linux-2.4.24-vanilla.orig/arch/ia64/defconfig 2004-01-10 17:05:52.000000000 +0300 ++++ linux-2.4.24-vanilla/arch/ia64/defconfig 2004-01-10 17:20:28.000000000 +0300 +@@ -1,6 +1,13 @@ + # + # Automatically generated make config: don't edit + # ++# CONFIG_EXT3_FS_XATTR is not set ++# CONFIG_EXT3_FS_XATTR_SHARING is not set ++# CONFIG_EXT3_FS_XATTR_USER is not set ++# CONFIG_EXT2_FS_XATTR is not set ++# CONFIG_EXT2_FS_XATTR_SHARING is not set ++# CONFIG_EXT2_FS_XATTR_USER is not set ++# CONFIG_FS_MBCACHE is not set + + # + # Code maturity level options +Index: linux-2.4.24-vanilla/arch/m68k/defconfig +=================================================================== +--- linux-2.4.24-vanilla.orig/arch/m68k/defconfig 2004-01-10 17:05:52.000000000 +0300 ++++ linux-2.4.24-vanilla/arch/m68k/defconfig 2004-01-10 17:20:28.000000000 +0300 +@@ -1,6 +1,13 @@ + # + # Automatically generated make config: don't edit + # ++# CONFIG_EXT3_FS_XATTR is not set ++# CONFIG_EXT3_FS_XATTR_SHARING is not set ++# CONFIG_EXT3_FS_XATTR_USER is not set ++# CONFIG_EXT2_FS_XATTR is not set ++# CONFIG_EXT2_FS_XATTR_SHARING is not set ++# CONFIG_EXT2_FS_XATTR_USER is not set ++# CONFIG_FS_MBCACHE is not set + CONFIG_UID16=y + + # +Index: linux-2.4.24-vanilla/arch/mips/defconfig +=================================================================== +--- linux-2.4.24-vanilla.orig/arch/mips/defconfig 2004-01-10 17:04:59.000000000 +0300 ++++ linux-2.4.24-vanilla/arch/mips/defconfig 2004-01-10 17:20:28.000000000 +0300 +@@ -1,6 +1,13 @@ + # + # Automatically generated make config: don't edit + # ++# CONFIG_EXT3_FS_XATTR is not set ++# CONFIG_EXT3_FS_XATTR_SHARING is not set ++# CONFIG_EXT3_FS_XATTR_USER is not set ++# CONFIG_EXT2_FS_XATTR is not set ++# CONFIG_EXT2_FS_XATTR_SHARING is not set ++# CONFIG_EXT2_FS_XATTR_USER is not set ++# CONFIG_FS_MBCACHE is not set + CONFIG_MIPS=y + CONFIG_MIPS32=y + # CONFIG_MIPS64 is not set +Index: linux-2.4.24-vanilla/arch/mips64/defconfig +=================================================================== +--- linux-2.4.24-vanilla.orig/arch/mips64/defconfig 2004-01-10 17:05:52.000000000 +0300 ++++ linux-2.4.24-vanilla/arch/mips64/defconfig 2004-01-10 17:20:28.000000000 +0300 +@@ -1,6 +1,13 @@ + # + # Automatically generated make config: don't edit + # ++# CONFIG_EXT3_FS_XATTR is not set ++# CONFIG_EXT3_FS_XATTR_SHARING is not set ++# CONFIG_EXT3_FS_XATTR_USER is not set ++# CONFIG_EXT2_FS_XATTR is not set ++# CONFIG_EXT2_FS_XATTR_SHARING is not set ++# CONFIG_EXT2_FS_XATTR_USER is not set ++# CONFIG_FS_MBCACHE is not set + CONFIG_MIPS=y + # CONFIG_MIPS32 is not set + CONFIG_MIPS64=y +Index: linux-2.4.24-vanilla/arch/s390/defconfig +=================================================================== +--- linux-2.4.24-vanilla.orig/arch/s390/defconfig 2004-01-10 17:05:52.000000000 +0300 ++++ linux-2.4.24-vanilla/arch/s390/defconfig 2004-01-10 17:20:28.000000000 +0300 +@@ -1,6 +1,13 @@ + # + # Automatically generated make config: don't edit + # ++# CONFIG_EXT3_FS_XATTR is not set ++# CONFIG_EXT3_FS_XATTR_SHARING is not set ++# CONFIG_EXT3_FS_XATTR_USER is not set ++# CONFIG_EXT2_FS_XATTR is not set ++# CONFIG_EXT2_FS_XATTR_SHARING is not set ++# CONFIG_EXT2_FS_XATTR_USER is not set ++# CONFIG_FS_MBCACHE is not set + # CONFIG_ISA is not set + # CONFIG_EISA is not set + # CONFIG_MCA is not set +Index: linux-2.4.24-vanilla/arch/s390/kernel/entry.S +=================================================================== +--- linux-2.4.24-vanilla.orig/arch/s390/kernel/entry.S 2004-01-10 17:04:39.000000000 +0300 ++++ linux-2.4.24-vanilla/arch/s390/kernel/entry.S 2004-01-10 17:20:28.000000000 +0300 +@@ -558,18 +558,18 @@ + .long sys_fcntl64 + .long sys_readahead + .long sys_ni_syscall +- .long sys_ni_syscall /* 224 - reserved for setxattr */ +- .long sys_ni_syscall /* 225 - reserved for lsetxattr */ +- .long sys_ni_syscall /* 226 - reserved for fsetxattr */ +- .long sys_ni_syscall /* 227 - reserved for getxattr */ +- .long sys_ni_syscall /* 228 - reserved for lgetxattr */ +- .long sys_ni_syscall /* 229 - reserved for fgetxattr */ +- .long sys_ni_syscall /* 230 - reserved for listxattr */ +- .long sys_ni_syscall /* 231 - reserved for llistxattr */ +- .long sys_ni_syscall /* 232 - reserved for flistxattr */ +- .long sys_ni_syscall /* 233 - reserved for removexattr */ +- .long sys_ni_syscall /* 234 - reserved for lremovexattr */ +- .long sys_ni_syscall /* 235 - reserved for fremovexattr */ ++ .long sys_setxattr ++ .long sys_lsetxattr /* 225 */ ++ .long sys_fsetxattr ++ .long sys_getxattr ++ .long sys_lgetxattr ++ .long sys_fgetxattr ++ .long sys_listxattr /* 230 */ ++ .long sys_llistxattr ++ .long sys_flistxattr ++ .long sys_removexattr ++ .long sys_lremovexattr ++ .long sys_fremovexattr /* 235 */ + .long sys_gettid + .long sys_tkill + .rept 255-237 +Index: linux-2.4.24-vanilla/arch/s390x/defconfig +=================================================================== +--- linux-2.4.24-vanilla.orig/arch/s390x/defconfig 2004-01-10 17:05:52.000000000 +0300 ++++ linux-2.4.24-vanilla/arch/s390x/defconfig 2004-01-10 17:20:28.000000000 +0300 +@@ -1,6 +1,13 @@ + # + # Automatically generated make config: don't edit + # ++# CONFIG_EXT3_FS_XATTR is not set ++# CONFIG_EXT3_FS_XATTR_SHARING is not set ++# CONFIG_EXT3_FS_XATTR_USER is not set ++# CONFIG_EXT2_FS_XATTR is not set ++# CONFIG_EXT2_FS_XATTR_SHARING is not set ++# CONFIG_EXT2_FS_XATTR_USER is not set ++# CONFIG_FS_MBCACHE is not set + # CONFIG_ISA is not set + # CONFIG_EISA is not set + # CONFIG_MCA is not set +Index: linux-2.4.24-vanilla/arch/s390x/kernel/entry.S +=================================================================== +--- linux-2.4.24-vanilla.orig/arch/s390x/kernel/entry.S 2004-01-10 17:05:00.000000000 +0300 ++++ linux-2.4.24-vanilla/arch/s390x/kernel/entry.S 2004-01-10 17:20:28.000000000 +0300 +@@ -591,18 +591,18 @@ + .long SYSCALL(sys_ni_syscall,sys32_fcntl64_wrapper) + .long SYSCALL(sys_readahead,sys32_readahead) + .long SYSCALL(sys_ni_syscall,sys_ni_syscall) +- .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 224 - reserved for setxattr */ +- .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 225 - reserved for lsetxattr */ +- .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 226 - reserved for fsetxattr */ +- .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 227 - reserved for getxattr */ +- .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 228 - reserved for lgetxattr */ +- .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 229 - reserved for fgetxattr */ +- .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 230 - reserved for listxattr */ +- .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 231 - reserved for llistxattr */ +- .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 232 - reserved for flistxattr */ +- .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 233 - reserved for removexattr */ +- .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 234 - reserved for lremovexattr */ +- .long SYSCALL(sys_ni_syscall,sys_ni_syscall) /* 235 - reserved for fremovexattr */ ++ .long SYSCALL(sys_setxattr,sys32_setxattr_wrapper) ++ .long SYSCALL(sys_lsetxattr,sys32_lsetxattr_wrapper) /* 225 */ ++ .long SYSCALL(sys_fsetxattr,sys32_fsetxattr_wrapper) ++ .long SYSCALL(sys_getxattr,sys32_getxattr_wrapper) ++ .long SYSCALL(sys_lgetxattr,sys32_lgetxattr_wrapper) ++ .long SYSCALL(sys_fgetxattr,sys32_fgetxattr_wrapper) ++ .long SYSCALL(sys_listxattr,sys32_listxattr_wrapper) /* 230 */ ++ .long SYSCALL(sys_llistxattr,sys32_llistxattr_wrapper) ++ .long SYSCALL(sys_flistxattr,sys32_flistxattr_wrapper) ++ .long SYSCALL(sys_removexattr,sys32_removexattr_wrapper) ++ .long SYSCALL(sys_lremovexattr,sys32_lremovexattr_wrapper) ++ .long SYSCALL(sys_fremovexattr,sys32_fremovexattr_wrapper)/* 235 */ + .long SYSCALL(sys_gettid,sys_gettid) + .long SYSCALL(sys_tkill,sys_tkill) + .rept 255-237 +Index: linux-2.4.24-vanilla/arch/s390x/kernel/wrapper32.S +=================================================================== +--- linux-2.4.24-vanilla.orig/arch/s390x/kernel/wrapper32.S 2004-01-10 17:05:00.000000000 +0300 ++++ linux-2.4.24-vanilla/arch/s390x/kernel/wrapper32.S 2004-01-10 17:20:28.000000000 +0300 +@@ -1098,6 +1098,98 @@ + llgfr %r4,%r4 # long + jg sys32_fstat64 # branch to system call + ++ .globl sys32_setxattr_wrapper ++sys32_setxattr_wrapper: ++ llgtr %r2,%r2 # char * ++ llgtr %r3,%r3 # char * ++ llgtr %r4,%r4 # void * ++ llgfr %r5,%r5 # size_t ++ lgfr %r6,%r6 # int ++ jg sys_setxattr ++ ++ .globl sys32_lsetxattr_wrapper ++sys32_lsetxattr_wrapper: ++ llgtr %r2,%r2 # char * ++ llgtr %r3,%r3 # char * ++ llgtr %r4,%r4 # void * ++ llgfr %r5,%r5 # size_t ++ lgfr %r6,%r6 # int ++ jg sys_lsetxattr ++ ++ .globl sys32_fsetxattr_wrapper ++sys32_fsetxattr_wrapper: ++ lgfr %r2,%r2 # int ++ llgtr %r3,%r3 # char * ++ llgtr %r4,%r4 # void * ++ llgfr %r5,%r5 # size_t ++ lgfr %r6,%r6 # int ++ jg sys_fsetxattr ++ ++ .globl sys32_getxattr_wrapper ++sys32_getxattr_wrapper: ++ llgtr %r2,%r2 # char * ++ llgtr %r3,%r3 # char * ++ llgtr %r4,%r4 # void * ++ llgfr %r5,%r5 # size_t ++ jg sys_getxattr ++ ++ .globl sys32_lgetxattr_wrapper ++sys32_lgetxattr_wrapper: ++ llgtr %r2,%r2 # char * ++ llgtr %r3,%r3 # char * ++ llgtr %r4,%r4 # void * ++ llgfr %r5,%r5 # size_t ++ jg sys_lgetxattr ++ ++ .globl sys32_fgetxattr_wrapper ++sys32_fgetxattr_wrapper: ++ lgfr %r2,%r2 # int ++ llgtr %r3,%r3 # char * ++ llgtr %r4,%r4 # void * ++ llgfr %r5,%r5 # size_t ++ jg sys_fgetxattr ++ ++ .globl sys32_listxattr_wrapper ++sys32_listxattr_wrapper: ++ llgtr %r2,%r2 # char * ++ llgtr %r3,%r3 # char * ++ llgfr %r4,%r4 # size_t ++ jg sys_listxattr ++ ++ .globl sys32_llistxattr_wrapper ++sys32_llistxattr_wrapper: ++ llgtr %r2,%r2 # char * ++ llgtr %r3,%r3 # char * ++ llgfr %r4,%r4 # size_t ++ jg sys_llistxattr ++ ++ .globl sys32_flistxattr_wrapper ++sys32_flistxattr_wrapper: ++ lgfr %r2,%r2 # int ++ llgtr %r3,%r3 # char * ++ llgfr %r4,%r4 # size_t ++ jg sys_flistxattr ++ ++ .globl sys32_removexattr_wrapper ++sys32_removexattr_wrapper: ++ llgtr %r2,%r2 # char * ++ llgtr %r3,%r3 # char * ++ jg sys_removexattr ++ ++ .globl sys32_lremovexattr_wrapper ++sys32_lremovexattr_wrapper: ++ llgtr %r2,%r2 # char * ++ llgtr %r3,%r3 # char * ++ jg sys_lremovexattr ++ ++ .globl sys32_fremovexattr_wrapper ++sys32_fremovexattr_wrapper: ++ lgfr %r2,%r2 # int ++ llgtr %r3,%r3 # char * ++ jg sys_fremovexattr ++ ++ ++ + .globl sys32_stime_wrapper + sys32_stime_wrapper: + llgtr %r2,%r2 # int * +Index: linux-2.4.24-vanilla/arch/sparc64/defconfig +=================================================================== +--- linux-2.4.24-vanilla.orig/arch/sparc64/defconfig 2004-01-10 17:05:52.000000000 +0300 ++++ linux-2.4.24-vanilla/arch/sparc64/defconfig 2004-01-10 17:20:28.000000000 +0300 +@@ -1,6 +1,13 @@ + # + # Automatically generated make config: don't edit + # ++# CONFIG_EXT3_FS_XATTR is not set ++# CONFIG_EXT3_FS_XATTR_SHARING is not set ++# CONFIG_EXT3_FS_XATTR_USER is not set ++# CONFIG_EXT2_FS_XATTR is not set ++# CONFIG_EXT2_FS_XATTR_SHARING is not set ++# CONFIG_EXT2_FS_XATTR_USER is not set ++# CONFIG_FS_MBCACHE is not set + + # + # Code maturity level options +Index: linux-2.4.24-vanilla/fs/Config.in +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/Config.in 2004-01-10 17:05:55.000000000 +0300 ++++ linux-2.4.24-vanilla/fs/Config.in 2004-01-10 17:20:28.000000000 +0300 +@@ -29,6 +29,11 @@ + dep_tristate 'BFS file system support (EXPERIMENTAL)' CONFIG_BFS_FS $CONFIG_EXPERIMENTAL + + tristate 'Ext3 journalling file system support' CONFIG_EXT3_FS ++dep_mbool ' Ext3 extended attributes' CONFIG_EXT3_FS_XATTR $CONFIG_EXT3_FS ++dep_bool ' Ext3 extended attribute block sharing' \ ++ CONFIG_EXT3_FS_XATTR_SHARING $CONFIG_EXT3_FS_XATTR ++dep_bool ' Ext3 extended user attributes' \ ++ CONFIG_EXT3_FS_XATTR_USER $CONFIG_EXT3_FS_XATTR + # CONFIG_JBD could be its own option (even modular), but until there are + # other users than ext3, we will simply make it be the same as CONFIG_EXT3_FS + # dep_tristate ' Journal Block Device support (JBD for ext3)' CONFIG_JBD $CONFIG_EXT3_FS +@@ -92,6 +97,11 @@ + tristate 'ROM file system support' CONFIG_ROMFS_FS + + tristate 'Second extended fs support' CONFIG_EXT2_FS ++dep_mbool ' Ext2 extended attributes' CONFIG_EXT2_FS_XATTR $CONFIG_EXT2_FS ++dep_bool ' Ext2 extended attribute block sharing' \ ++ CONFIG_EXT2_FS_XATTR_SHARING $CONFIG_EXT2_FS_XATTR ++dep_bool ' Ext2 extended user attributes' \ ++ CONFIG_EXT2_FS_XATTR_USER $CONFIG_EXT2_FS_XATTR + + tristate 'System V/Xenix/V7/Coherent file system support' CONFIG_SYSV_FS + +@@ -164,6 +174,10 @@ + define_tristate CONFIG_ZISOFS_FS n + fi + ++# Meta block cache for Extended Attributes (ext2/ext3) ++#tristate 'Meta block cache' CONFIG_FS_MBCACHE ++define_tristate CONFIG_FS_MBCACHE y ++ + mainmenu_option next_comment + comment 'Partition Types' + source fs/partitions/Config.in +Index: linux-2.4.24-vanilla/fs/Makefile +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/Makefile 2004-01-10 17:11:48.000000000 +0300 ++++ linux-2.4.24-vanilla/fs/Makefile 2004-01-10 17:20:28.000000000 +0300 +@@ -77,6 +77,9 @@ + + obj-$(CONFIG_BINFMT_ELF) += binfmt_elf.o + ++export-objs += mbcache.o ++obj-$(CONFIG_FS_MBCACHE) += mbcache.o ++ + # persistent filesystems + obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o)) + +Index: linux-2.4.24-vanilla/fs/ext2/Makefile +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/ext2/Makefile 2001-10-11 19:05:18.000000000 +0400 ++++ linux-2.4.24-vanilla/fs/ext2/Makefile 2004-01-10 17:20:28.000000000 +0300 +@@ -13,4 +13,8 @@ + ioctl.o namei.o super.o symlink.o + obj-m := $(O_TARGET) + ++export-objs += xattr.o ++obj-$(CONFIG_EXT2_FS_XATTR) += xattr.o ++obj-$(CONFIG_EXT2_FS_XATTR_USER) += xattr_user.o ++ + include $(TOPDIR)/Rules.make +Index: linux-2.4.24-vanilla/fs/ext2/file.c +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/ext2/file.c 2001-10-11 19:05:18.000000000 +0400 ++++ linux-2.4.24-vanilla/fs/ext2/file.c 2004-01-10 17:20:28.000000000 +0300 +@@ -20,6 +20,7 @@ + + #include + #include ++#include + #include + + /* +@@ -51,4 +52,8 @@ + + struct inode_operations ext2_file_inode_operations = { + truncate: ext2_truncate, ++ setxattr: ext2_setxattr, ++ getxattr: ext2_getxattr, ++ listxattr: ext2_listxattr, ++ removexattr: ext2_removexattr, + }; +Index: linux-2.4.24-vanilla/fs/ext2/ialloc.c +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/ext2/ialloc.c 2004-01-10 17:04:42.000000000 +0300 ++++ linux-2.4.24-vanilla/fs/ext2/ialloc.c 2004-01-10 17:20:28.000000000 +0300 +@@ -15,6 +15,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -167,6 +168,7 @@ + */ + if (!is_bad_inode(inode)) { + /* Quota is already initialized in iput() */ ++ ext2_xattr_delete_inode(inode); + DQUOT_FREE_INODE(inode); + DQUOT_DROP(inode); + } +Index: linux-2.4.24-vanilla/fs/ext2/inode.c +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/ext2/inode.c 2004-01-10 17:04:42.000000000 +0300 ++++ linux-2.4.24-vanilla/fs/ext2/inode.c 2004-01-10 17:20:28.000000000 +0300 +@@ -39,6 +39,18 @@ + static int ext2_update_inode(struct inode * inode, int do_sync); + + /* ++ * Test whether an inode is a fast symlink. ++ */ ++static inline int ext2_inode_is_fast_symlink(struct inode *inode) ++{ ++ int ea_blocks = inode->u.ext2_i.i_file_acl ? ++ (inode->i_sb->s_blocksize >> 9) : 0; ++ ++ return (S_ISLNK(inode->i_mode) && ++ inode->i_blocks - ea_blocks == 0); ++} ++ ++/* + * Called at each iput() + */ + void ext2_put_inode (struct inode * inode) +@@ -53,9 +65,7 @@ + { + lock_kernel(); + +- if (is_bad_inode(inode) || +- inode->i_ino == EXT2_ACL_IDX_INO || +- inode->i_ino == EXT2_ACL_DATA_INO) ++ if (is_bad_inode(inode)) + goto no_delete; + inode->u.ext2_i.i_dtime = CURRENT_TIME; + mark_inode_dirty(inode); +@@ -801,6 +811,8 @@ + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return; ++ if (ext2_inode_is_fast_symlink(inode)) ++ return; + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + return; + +@@ -903,8 +915,7 @@ + unsigned long offset; + struct ext2_group_desc * gdp; + +- if ((inode->i_ino != EXT2_ROOT_INO && inode->i_ino != EXT2_ACL_IDX_INO && +- inode->i_ino != EXT2_ACL_DATA_INO && ++ if ((inode->i_ino != EXT2_ROOT_INO && + inode->i_ino < EXT2_FIRST_INO(inode->i_sb)) || + inode->i_ino > le32_to_cpu(inode->i_sb->u.ext2_sb.s_es->s_inodes_count)) { + ext2_error (inode->i_sb, "ext2_read_inode", +@@ -989,10 +1000,7 @@ + for (block = 0; block < EXT2_N_BLOCKS; block++) + inode->u.ext2_i.i_data[block] = raw_inode->i_block[block]; + +- if (inode->i_ino == EXT2_ACL_IDX_INO || +- inode->i_ino == EXT2_ACL_DATA_INO) +- /* Nothing to do */ ; +- else if (S_ISREG(inode->i_mode)) { ++ if (S_ISREG(inode->i_mode)) { + inode->i_op = &ext2_file_inode_operations; + inode->i_fop = &ext2_file_operations; + inode->i_mapping->a_ops = &ext2_aops; +@@ -1001,15 +1009,17 @@ + inode->i_fop = &ext2_dir_operations; + inode->i_mapping->a_ops = &ext2_aops; + } else if (S_ISLNK(inode->i_mode)) { +- if (!inode->i_blocks) ++ if (ext2_inode_is_fast_symlink(inode)) + inode->i_op = &ext2_fast_symlink_inode_operations; + else { +- inode->i_op = &page_symlink_inode_operations; ++ inode->i_op = &ext2_symlink_inode_operations; + inode->i_mapping->a_ops = &ext2_aops; + } +- } else ++ } else { ++ inode->i_op = &ext2_special_inode_operations; + init_special_inode(inode, inode->i_mode, + le32_to_cpu(raw_inode->i_block[0])); ++ } + brelse (bh); + inode->i_attr_flags = 0; + ext2_set_inode_flags(inode); +Index: linux-2.4.24-vanilla/fs/ext2/namei.c +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/ext2/namei.c 2001-10-04 09:57:36.000000000 +0400 ++++ linux-2.4.24-vanilla/fs/ext2/namei.c 2004-01-10 17:20:28.000000000 +0300 +@@ -31,6 +31,7 @@ + + #include + #include ++#include + #include + + /* +@@ -136,7 +137,7 @@ + + if (l > sizeof (inode->u.ext2_i.i_data)) { + /* slow symlink */ +- inode->i_op = &page_symlink_inode_operations; ++ inode->i_op = &ext2_symlink_inode_operations; + inode->i_mapping->a_ops = &ext2_aops; + err = block_symlink(inode, symname, l); + if (err) +@@ -345,4 +346,15 @@ + rmdir: ext2_rmdir, + mknod: ext2_mknod, + rename: ext2_rename, ++ setxattr: ext2_setxattr, ++ getxattr: ext2_getxattr, ++ listxattr: ext2_listxattr, ++ removexattr: ext2_removexattr, ++}; ++ ++struct inode_operations ext2_special_inode_operations = { ++ setxattr: ext2_setxattr, ++ getxattr: ext2_getxattr, ++ listxattr: ext2_listxattr, ++ removexattr: ext2_removexattr, + }; +Index: linux-2.4.24-vanilla/fs/ext2/super.c +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/ext2/super.c 2003-05-16 05:29:12.000000000 +0400 ++++ linux-2.4.24-vanilla/fs/ext2/super.c 2004-01-10 17:20:28.000000000 +0300 +@@ -21,6 +21,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -125,6 +126,7 @@ + int db_count; + int i; + ++ ext2_xattr_put_super(sb); + if (!(sb->s_flags & MS_RDONLY)) { + struct ext2_super_block *es = EXT2_SB(sb)->s_es; + +@@ -175,6 +177,13 @@ + this_char = strtok (NULL, ",")) { + if ((value = strchr (this_char, '=')) != NULL) + *value++ = 0; ++#ifdef CONFIG_EXT2_FS_XATTR_USER ++ if (!strcmp (this_char, "user_xattr")) ++ set_opt (*mount_options, XATTR_USER); ++ else if (!strcmp (this_char, "nouser_xattr")) ++ clear_opt (*mount_options, XATTR_USER); ++ else ++#endif + if (!strcmp (this_char, "bsddf")) + clear_opt (*mount_options, MINIX_DF); + else if (!strcmp (this_char, "nouid32")) { +@@ -424,6 +433,9 @@ + blocksize = BLOCK_SIZE; + + sb->u.ext2_sb.s_mount_opt = 0; ++#ifdef CONFIG_EXT2_FS_XATTR_USER ++ /* set_opt (sb->u.ext2_sb.s_mount_opt, XATTR_USER); */ ++#endif + if (!parse_options ((char *) data, &sb_block, &resuid, &resgid, + &sb->u.ext2_sb.s_mount_opt)) { + return NULL; +@@ -813,12 +825,27 @@ + + static int __init init_ext2_fs(void) + { +- return register_filesystem(&ext2_fs_type); ++ int error = init_ext2_xattr(); ++ if (error) ++ return error; ++ error = init_ext2_xattr_user(); ++ if (error) ++ goto fail; ++ error = register_filesystem(&ext2_fs_type); ++ if (!error) ++ return 0; ++ ++ exit_ext2_xattr_user(); ++fail: ++ exit_ext2_xattr(); ++ return error; + } + + static void __exit exit_ext2_fs(void) + { + unregister_filesystem(&ext2_fs_type); ++ exit_ext2_xattr_user(); ++ exit_ext2_xattr(); + } + + EXPORT_NO_SYMBOLS; +Index: linux-2.4.24-vanilla/fs/ext2/symlink.c +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/ext2/symlink.c 2000-09-28 00:41:33.000000000 +0400 ++++ linux-2.4.24-vanilla/fs/ext2/symlink.c 2004-01-10 17:20:28.000000000 +0300 +@@ -19,6 +19,7 @@ + + #include + #include ++#include + + static int ext2_readlink(struct dentry *dentry, char *buffer, int buflen) + { +@@ -32,7 +33,20 @@ + return vfs_follow_link(nd, s); + } + ++struct inode_operations ext2_symlink_inode_operations = { ++ readlink: page_readlink, ++ follow_link: page_follow_link, ++ setxattr: ext2_setxattr, ++ getxattr: ext2_getxattr, ++ listxattr: ext2_listxattr, ++ removexattr: ext2_removexattr, ++}; ++ + struct inode_operations ext2_fast_symlink_inode_operations = { + readlink: ext2_readlink, + follow_link: ext2_follow_link, ++ setxattr: ext2_setxattr, ++ getxattr: ext2_getxattr, ++ listxattr: ext2_listxattr, ++ removexattr: ext2_removexattr, + }; +Index: linux-2.4.24-vanilla/fs/ext2/xattr.c +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/ext2/xattr.c 2003-01-30 13:24:37.000000000 +0300 ++++ linux-2.4.24-vanilla/fs/ext2/xattr.c 2004-01-10 17:20:28.000000000 +0300 +@@ -0,0 +1,1212 @@ ++/* ++ * linux/fs/ext2/xattr.c ++ * ++ * Copyright (C) 2001 by Andreas Gruenbacher, ++ * ++ * Fix by Harrison Xing . ++ * Extended attributes for symlinks and special files added per ++ * suggestion of Luka Renko . ++ */ ++ ++/* ++ * Extended attributes are stored on disk blocks allocated outside of ++ * any inode. The i_file_acl field is then made to point to this allocated ++ * block. If all extended attributes of an inode are identical, these ++ * inodes may share the same extended attribute block. Such situations ++ * are automatically detected by keeping a cache of recent attribute block ++ * numbers and hashes over the block's contents in memory. ++ * ++ * ++ * Extended attribute block layout: ++ * ++ * +------------------+ ++ * | header | ++ * | entry 1 | | ++ * | entry 2 | | growing downwards ++ * | entry 3 | v ++ * | four null bytes | ++ * | . . . | ++ * | value 1 | ^ ++ * | value 3 | | growing upwards ++ * | value 2 | | ++ * +------------------+ ++ * ++ * The block header is followed by multiple entry descriptors. These entry ++ * descriptors are variable in size, and alligned to EXT2_XATTR_PAD ++ * byte boundaries. The entry descriptors are sorted by attribute name, ++ * so that two extended attribute blocks can be compared efficiently. ++ * ++ * Attribute values are aligned to the end of the block, stored in ++ * no specific order. They are also padded to EXT2_XATTR_PAD byte ++ * boundaries. No additional gaps are left between them. ++ * ++ * Locking strategy ++ * ---------------- ++ * The VFS already holds the BKL and the inode->i_sem semaphore when any of ++ * the xattr inode operations are called, so we are guaranteed that only one ++ * processes accesses extended attributes of an inode at any time. ++ * ++ * For writing we also grab the ext2_xattr_sem semaphore. This ensures that ++ * only a single process is modifying an extended attribute block, even ++ * if the block is shared among inodes. ++ * ++ * Note for porting to 2.5 ++ * ----------------------- ++ * The BKL will no longer be held in the xattr inode operations. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++/* These symbols may be needed by a module. */ ++EXPORT_SYMBOL(ext2_xattr_register); ++EXPORT_SYMBOL(ext2_xattr_unregister); ++EXPORT_SYMBOL(ext2_xattr_get); ++EXPORT_SYMBOL(ext2_xattr_list); ++EXPORT_SYMBOL(ext2_xattr_set); ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) ++# define mark_buffer_dirty(bh) mark_buffer_dirty(bh, 1) ++#endif ++ ++#define HDR(bh) ((struct ext2_xattr_header *)((bh)->b_data)) ++#define ENTRY(ptr) ((struct ext2_xattr_entry *)(ptr)) ++#define FIRST_ENTRY(bh) ENTRY(HDR(bh)+1) ++#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0) ++ ++#ifdef EXT2_XATTR_DEBUG ++# define ea_idebug(inode, f...) do { \ ++ printk(KERN_DEBUG "inode %s:%ld: ", \ ++ kdevname(inode->i_dev), inode->i_ino); \ ++ printk(f); \ ++ printk("\n"); \ ++ } while (0) ++# define ea_bdebug(bh, f...) do { \ ++ printk(KERN_DEBUG "block %s:%ld: ", \ ++ kdevname(bh->b_dev), bh->b_blocknr); \ ++ printk(f); \ ++ printk("\n"); \ ++ } while (0) ++#else ++# define ea_idebug(f...) ++# define ea_bdebug(f...) ++#endif ++ ++static int ext2_xattr_set2(struct inode *, struct buffer_head *, ++ struct ext2_xattr_header *); ++ ++#ifdef CONFIG_EXT2_FS_XATTR_SHARING ++ ++static int ext2_xattr_cache_insert(struct buffer_head *); ++static struct buffer_head *ext2_xattr_cache_find(struct inode *, ++ struct ext2_xattr_header *); ++static void ext2_xattr_cache_remove(struct buffer_head *); ++static void ext2_xattr_rehash(struct ext2_xattr_header *, ++ struct ext2_xattr_entry *); ++ ++static struct mb_cache *ext2_xattr_cache; ++ ++#else ++# define ext2_xattr_cache_insert(bh) 0 ++# define ext2_xattr_cache_find(inode, header) NULL ++# define ext2_xattr_cache_remove(bh) while(0) {} ++# define ext2_xattr_rehash(header, entry) while(0) {} ++#endif ++ ++/* ++ * If a file system does not share extended attributes among inodes, ++ * we should not need the ext2_xattr_sem semaphore. However, the ++ * filesystem may still contain shared blocks, so we always take ++ * the lock. ++ */ ++ ++DECLARE_MUTEX(ext2_xattr_sem); ++ ++static inline int ++ext2_xattr_new_block(struct inode *inode, int * errp, int force) ++{ ++ struct super_block *sb = inode->i_sb; ++ int goal = le32_to_cpu(EXT2_SB(sb)->s_es->s_first_data_block) + ++ EXT2_I(inode)->i_block_group * EXT2_BLOCKS_PER_GROUP(sb); ++ ++ /* How can we enforce the allocation? */ ++ int block = ext2_new_block(inode, goal, 0, 0, errp); ++#ifdef OLD_QUOTAS ++ if (!*errp) ++ inode->i_blocks += inode->i_sb->s_blocksize >> 9; ++#endif ++ return block; ++} ++ ++static inline int ++ext2_xattr_quota_alloc(struct inode *inode, int force) ++{ ++ /* How can we enforce the allocation? */ ++#ifdef OLD_QUOTAS ++ int error = DQUOT_ALLOC_BLOCK(inode->i_sb, inode, 1); ++ if (!error) ++ inode->i_blocks += inode->i_sb->s_blocksize >> 9; ++#else ++ int error = DQUOT_ALLOC_BLOCK(inode, 1); ++#endif ++ return error; ++} ++ ++#ifdef OLD_QUOTAS ++ ++static inline void ++ext2_xattr_quota_free(struct inode *inode) ++{ ++ DQUOT_FREE_BLOCK(inode->i_sb, inode, 1); ++ inode->i_blocks -= inode->i_sb->s_blocksize >> 9; ++} ++ ++static inline void ++ext2_xattr_free_block(struct inode * inode, unsigned long block) ++{ ++ ext2_free_blocks(inode, block, 1); ++ inode->i_blocks -= inode->i_sb->s_blocksize >> 9; ++} ++ ++#else ++# define ext2_xattr_quota_free(inode) \ ++ DQUOT_FREE_BLOCK(inode, 1) ++# define ext2_xattr_free_block(inode, block) \ ++ ext2_free_blocks(inode, block, 1) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18) ++ ++static inline struct buffer_head * ++sb_bread(struct super_block *sb, int block) ++{ ++ return bread(sb->s_dev, block, sb->s_blocksize); ++} ++ ++static inline struct buffer_head * ++sb_getblk(struct super_block *sb, int block) ++{ ++ return getblk(sb->s_dev, block, sb->s_blocksize); ++} ++ ++#endif ++ ++struct ext2_xattr_handler *ext2_xattr_handlers[EXT2_XATTR_INDEX_MAX]; ++rwlock_t ext2_handler_lock = RW_LOCK_UNLOCKED; ++ ++int ++ext2_xattr_register(int name_index, struct ext2_xattr_handler *handler) ++{ ++ int error = -EINVAL; ++ ++ if (name_index > 0 && name_index <= EXT2_XATTR_INDEX_MAX) { ++ write_lock(&ext2_handler_lock); ++ if (!ext2_xattr_handlers[name_index-1]) { ++ ext2_xattr_handlers[name_index-1] = handler; ++ error = 0; ++ } ++ write_unlock(&ext2_handler_lock); ++ } ++ return error; ++} ++ ++void ++ext2_xattr_unregister(int name_index, struct ext2_xattr_handler *handler) ++{ ++ if (name_index > 0 || name_index <= EXT2_XATTR_INDEX_MAX) { ++ write_lock(&ext2_handler_lock); ++ ext2_xattr_handlers[name_index-1] = NULL; ++ write_unlock(&ext2_handler_lock); ++ } ++} ++ ++static inline const char * ++strcmp_prefix(const char *a, const char *a_prefix) ++{ ++ while (*a_prefix && *a == *a_prefix) { ++ a++; ++ a_prefix++; ++ } ++ return *a_prefix ? NULL : a; ++} ++ ++/* ++ * Decode the extended attribute name, and translate it into ++ * the name_index and name suffix. ++ */ ++static struct ext2_xattr_handler * ++ext2_xattr_resolve_name(const char **name) ++{ ++ struct ext2_xattr_handler *handler = NULL; ++ int i; ++ ++ if (!*name) ++ return NULL; ++ read_lock(&ext2_handler_lock); ++ for (i=0; iprefix); ++ if (n) { ++ handler = ext2_xattr_handlers[i]; ++ *name = n; ++ break; ++ } ++ } ++ } ++ read_unlock(&ext2_handler_lock); ++ return handler; ++} ++ ++static inline struct ext2_xattr_handler * ++ext2_xattr_handler(int name_index) ++{ ++ struct ext2_xattr_handler *handler = NULL; ++ if (name_index > 0 && name_index <= EXT2_XATTR_INDEX_MAX) { ++ read_lock(&ext2_handler_lock); ++ handler = ext2_xattr_handlers[name_index-1]; ++ read_unlock(&ext2_handler_lock); ++ } ++ return handler; ++} ++ ++/* ++ * Inode operation getxattr() ++ * ++ * dentry->d_inode->i_sem down ++ * BKL held [before 2.5.x] ++ */ ++ssize_t ++ext2_getxattr(struct dentry *dentry, const char *name, ++ void *buffer, size_t size) ++{ ++ struct ext2_xattr_handler *handler; ++ struct inode *inode = dentry->d_inode; ++ ++ handler = ext2_xattr_resolve_name(&name); ++ if (!handler) ++ return -ENOTSUP; ++ return handler->get(inode, name, buffer, size); ++} ++ ++/* ++ * Inode operation listxattr() ++ * ++ * dentry->d_inode->i_sem down ++ * BKL held [before 2.5.x] ++ */ ++ssize_t ++ext2_listxattr(struct dentry *dentry, char *buffer, size_t size) ++{ ++ return ext2_xattr_list(dentry->d_inode, buffer, size); ++} ++ ++/* ++ * Inode operation setxattr() ++ * ++ * dentry->d_inode->i_sem down ++ * BKL held [before 2.5.x] ++ */ ++int ++ext2_setxattr(struct dentry *dentry, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ struct ext2_xattr_handler *handler; ++ struct inode *inode = dentry->d_inode; ++ ++ if (size == 0) ++ value = ""; /* empty EA, do not remove */ ++ handler = ext2_xattr_resolve_name(&name); ++ if (!handler) ++ return -ENOTSUP; ++ return handler->set(inode, name, value, size, flags); ++} ++ ++/* ++ * Inode operation removexattr() ++ * ++ * dentry->d_inode->i_sem down ++ * BKL held [before 2.5.x] ++ */ ++int ++ext2_removexattr(struct dentry *dentry, const char *name) ++{ ++ struct ext2_xattr_handler *handler; ++ struct inode *inode = dentry->d_inode; ++ ++ handler = ext2_xattr_resolve_name(&name); ++ if (!handler) ++ return -ENOTSUP; ++ return handler->set(inode, name, NULL, 0, XATTR_REPLACE); ++} ++ ++/* ++ * ext2_xattr_get() ++ * ++ * Copy an extended attribute into the buffer ++ * provided, or compute the buffer size required. ++ * Buffer is NULL to compute the size of the buffer required. ++ * ++ * Returns a negative error number on failure, or the number of bytes ++ * used / required on success. ++ */ ++int ++ext2_xattr_get(struct inode *inode, int name_index, const char *name, ++ void *buffer, size_t buffer_size) ++{ ++ struct buffer_head *bh = NULL; ++ struct ext2_xattr_entry *entry; ++ unsigned int block, size; ++ char *end; ++ int name_len, error; ++ ++ ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld", ++ name_index, name, buffer, (long)buffer_size); ++ ++ if (name == NULL) ++ return -EINVAL; ++ if (!EXT2_I(inode)->i_file_acl) ++ return -ENOATTR; ++ block = EXT2_I(inode)->i_file_acl; ++ ea_idebug(inode, "reading block %d", block); ++ bh = sb_bread(inode->i_sb, block); ++ if (!bh) ++ return -EIO; ++ ea_bdebug(bh, "b_count=%d, refcount=%d", ++ atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); ++ end = bh->b_data + bh->b_size; ++ if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || ++ HDR(bh)->h_blocks != cpu_to_le32(1)) { ++bad_block: ext2_error(inode->i_sb, "ext2_xattr_get", ++ "inode %ld: bad block %d", inode->i_ino, block); ++ error = -EIO; ++ goto cleanup; ++ } ++ /* find named attribute */ ++ name_len = strlen(name); ++ ++ error = -ERANGE; ++ if (name_len > 255) ++ goto cleanup; ++ entry = FIRST_ENTRY(bh); ++ while (!IS_LAST_ENTRY(entry)) { ++ struct ext2_xattr_entry *next = ++ EXT2_XATTR_NEXT(entry); ++ if ((char *)next >= end) ++ goto bad_block; ++ if (name_index == entry->e_name_index && ++ name_len == entry->e_name_len && ++ memcmp(name, entry->e_name, name_len) == 0) ++ goto found; ++ entry = next; ++ } ++ /* Check the remaining name entries */ ++ while (!IS_LAST_ENTRY(entry)) { ++ struct ext2_xattr_entry *next = ++ EXT2_XATTR_NEXT(entry); ++ if ((char *)next >= end) ++ goto bad_block; ++ entry = next; ++ } ++ if (ext2_xattr_cache_insert(bh)) ++ ea_idebug(inode, "cache insert failed"); ++ error = -ENOATTR; ++ goto cleanup; ++found: ++ /* check the buffer size */ ++ if (entry->e_value_block != 0) ++ goto bad_block; ++ size = le32_to_cpu(entry->e_value_size); ++ if (size > inode->i_sb->s_blocksize || ++ le16_to_cpu(entry->e_value_offs) + size > inode->i_sb->s_blocksize) ++ goto bad_block; ++ ++ if (ext2_xattr_cache_insert(bh)) ++ ea_idebug(inode, "cache insert failed"); ++ if (buffer) { ++ error = -ERANGE; ++ if (size > buffer_size) ++ goto cleanup; ++ /* return value of attribute */ ++ memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs), ++ size); ++ } ++ error = size; ++ ++cleanup: ++ brelse(bh); ++ ++ return error; ++} ++ ++/* ++ * ext2_xattr_list() ++ * ++ * Copy a list of attribute names into the buffer ++ * provided, or compute the buffer size required. ++ * Buffer is NULL to compute the size of the buffer required. ++ * ++ * Returns a negative error number on failure, or the number of bytes ++ * used / required on success. ++ */ ++int ++ext2_xattr_list(struct inode *inode, char *buffer, size_t buffer_size) ++{ ++ struct buffer_head *bh = NULL; ++ struct ext2_xattr_entry *entry; ++ unsigned int block, size = 0; ++ char *buf, *end; ++ int error; ++ ++ ea_idebug(inode, "buffer=%p, buffer_size=%ld", ++ buffer, (long)buffer_size); ++ ++ if (!EXT2_I(inode)->i_file_acl) ++ return 0; ++ block = EXT2_I(inode)->i_file_acl; ++ ea_idebug(inode, "reading block %d", block); ++ bh = sb_bread(inode->i_sb, block); ++ if (!bh) ++ return -EIO; ++ ea_bdebug(bh, "b_count=%d, refcount=%d", ++ atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); ++ end = bh->b_data + bh->b_size; ++ if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || ++ HDR(bh)->h_blocks != cpu_to_le32(1)) { ++bad_block: ext2_error(inode->i_sb, "ext2_xattr_list", ++ "inode %ld: bad block %d", inode->i_ino, block); ++ error = -EIO; ++ goto cleanup; ++ } ++ /* compute the size required for the list of attribute names */ ++ for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry); ++ entry = EXT2_XATTR_NEXT(entry)) { ++ struct ext2_xattr_handler *handler; ++ struct ext2_xattr_entry *next = ++ EXT2_XATTR_NEXT(entry); ++ if ((char *)next >= end) ++ goto bad_block; ++ ++ handler = ext2_xattr_handler(entry->e_name_index); ++ if (handler) ++ size += handler->list(NULL, inode, entry->e_name, ++ entry->e_name_len); ++ } ++ ++ if (ext2_xattr_cache_insert(bh)) ++ ea_idebug(inode, "cache insert failed"); ++ if (!buffer) { ++ error = size; ++ goto cleanup; ++ } else { ++ error = -ERANGE; ++ if (size > buffer_size) ++ goto cleanup; ++ } ++ ++ /* list the attribute names */ ++ buf = buffer; ++ for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry); ++ entry = EXT2_XATTR_NEXT(entry)) { ++ struct ext2_xattr_handler *handler; ++ ++ handler = ext2_xattr_handler(entry->e_name_index); ++ if (handler) ++ buf += handler->list(buf, inode, entry->e_name, ++ entry->e_name_len); ++ } ++ error = size; ++ ++cleanup: ++ brelse(bh); ++ ++ return error; ++} ++ ++/* ++ * If the EXT2_FEATURE_COMPAT_EXT_ATTR feature of this file system is ++ * not set, set it. ++ */ ++static void ext2_xattr_update_super_block(struct super_block *sb) ++{ ++ if (EXT2_HAS_COMPAT_FEATURE(sb, EXT2_FEATURE_COMPAT_EXT_ATTR)) ++ return; ++ ++ lock_super(sb); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) ++ EXT2_SB(sb)->s_feature_compat |= EXT2_FEATURE_COMPAT_EXT_ATTR; ++#endif ++ EXT2_SB(sb)->s_es->s_feature_compat |= ++ cpu_to_le32(EXT2_FEATURE_COMPAT_EXT_ATTR); ++ sb->s_dirt = 1; ++ mark_buffer_dirty(EXT2_SB(sb)->s_sbh); ++ unlock_super(sb); ++} ++ ++/* ++ * ext2_xattr_set() ++ * ++ * Create, replace or remove an extended attribute for this inode. Buffer ++ * is NULL to remove an existing extended attribute, and non-NULL to ++ * either replace an existing extended attribute, or create a new extended ++ * attribute. The flags XATTR_REPLACE and XATTR_CREATE ++ * specify that an extended attribute must exist and must not exist ++ * previous to the call, respectively. ++ * ++ * Returns 0, or a negative error number on failure. ++ */ ++int ++ext2_xattr_set(struct inode *inode, int name_index, const char *name, ++ const void *value, size_t value_len, int flags) ++{ ++ struct super_block *sb = inode->i_sb; ++ struct buffer_head *bh = NULL; ++ struct ext2_xattr_header *header = NULL; ++ struct ext2_xattr_entry *here, *last; ++ unsigned int name_len; ++ int block = EXT2_I(inode)->i_file_acl; ++ int min_offs = sb->s_blocksize, not_found = 1, free, error; ++ char *end; ++ ++ /* ++ * header -- Points either into bh, or to a temporarily ++ * allocated buffer. ++ * here -- The named entry found, or the place for inserting, within ++ * the block pointed to by header. ++ * last -- Points right after the last named entry within the block ++ * pointed to by header. ++ * min_offs -- The offset of the first value (values are aligned ++ * towards the end of the block). ++ * end -- Points right after the block pointed to by header. ++ */ ++ ++ ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld", ++ name_index, name, value, (long)value_len); ++ ++ if (IS_RDONLY(inode)) ++ return -EROFS; ++ if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) ++ return -EPERM; ++ if (value == NULL) ++ value_len = 0; ++ if (name == NULL) ++ return -EINVAL; ++ name_len = strlen(name); ++ if (name_len > 255 || value_len > sb->s_blocksize) ++ return -ERANGE; ++ down(&ext2_xattr_sem); ++ ++ if (block) { ++ /* The inode already has an extended attribute block. */ ++ ++ bh = sb_bread(sb, block); ++ error = -EIO; ++ if (!bh) ++ goto cleanup; ++ ea_bdebug(bh, "b_count=%d, refcount=%d", ++ atomic_read(&(bh->b_count)), ++ le32_to_cpu(HDR(bh)->h_refcount)); ++ header = HDR(bh); ++ end = bh->b_data + bh->b_size; ++ if (header->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || ++ header->h_blocks != cpu_to_le32(1)) { ++bad_block: ext2_error(sb, "ext2_xattr_set", ++ "inode %ld: bad block %d", inode->i_ino, block); ++ error = -EIO; ++ goto cleanup; ++ } ++ /* Find the named attribute. */ ++ here = FIRST_ENTRY(bh); ++ while (!IS_LAST_ENTRY(here)) { ++ struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(here); ++ if ((char *)next >= end) ++ goto bad_block; ++ if (!here->e_value_block && here->e_value_size) { ++ int offs = le16_to_cpu(here->e_value_offs); ++ if (offs < min_offs) ++ min_offs = offs; ++ } ++ not_found = name_index - here->e_name_index; ++ if (!not_found) ++ not_found = name_len - here->e_name_len; ++ if (!not_found) ++ not_found = memcmp(name, here->e_name,name_len); ++ if (not_found <= 0) ++ break; ++ here = next; ++ } ++ last = here; ++ /* We still need to compute min_offs and last. */ ++ while (!IS_LAST_ENTRY(last)) { ++ struct ext2_xattr_entry *next = EXT2_XATTR_NEXT(last); ++ if ((char *)next >= end) ++ goto bad_block; ++ if (!last->e_value_block && last->e_value_size) { ++ int offs = le16_to_cpu(last->e_value_offs); ++ if (offs < min_offs) ++ min_offs = offs; ++ } ++ last = next; ++ } ++ ++ /* Check whether we have enough space left. */ ++ free = min_offs - ((char*)last - (char*)header) - sizeof(__u32); ++ } else { ++ /* We will use a new extended attribute block. */ ++ free = sb->s_blocksize - ++ sizeof(struct ext2_xattr_header) - sizeof(__u32); ++ here = last = NULL; /* avoid gcc uninitialized warning. */ ++ } ++ ++ if (not_found) { ++ /* Request to remove a nonexistent attribute? */ ++ error = -ENOATTR; ++ if (flags & XATTR_REPLACE) ++ goto cleanup; ++ error = 0; ++ if (value == NULL) ++ goto cleanup; ++ else ++ free -= EXT2_XATTR_LEN(name_len); ++ } else { ++ /* Request to create an existing attribute? */ ++ error = -EEXIST; ++ if (flags & XATTR_CREATE) ++ goto cleanup; ++ if (!here->e_value_block && here->e_value_size) { ++ unsigned int size = le32_to_cpu(here->e_value_size); ++ ++ if (le16_to_cpu(here->e_value_offs) + size > ++ sb->s_blocksize || size > sb->s_blocksize) ++ goto bad_block; ++ free += EXT2_XATTR_SIZE(size); ++ } ++ } ++ free -= EXT2_XATTR_SIZE(value_len); ++ error = -ENOSPC; ++ if (free < 0) ++ goto cleanup; ++ ++ /* Here we know that we can set the new attribute. */ ++ ++ if (header) { ++ if (header->h_refcount == cpu_to_le32(1)) { ++ ea_bdebug(bh, "modifying in-place"); ++ ext2_xattr_cache_remove(bh); ++ } else { ++ int offset; ++ ++ ea_bdebug(bh, "cloning"); ++ header = kmalloc(bh->b_size, GFP_KERNEL); ++ error = -ENOMEM; ++ if (header == NULL) ++ goto cleanup; ++ memcpy(header, HDR(bh), bh->b_size); ++ header->h_refcount = cpu_to_le32(1); ++ offset = (char *)header - bh->b_data; ++ here = ENTRY((char *)here + offset); ++ last = ENTRY((char *)last + offset); ++ } ++ } else { ++ /* Allocate a buffer where we construct the new block. */ ++ header = kmalloc(sb->s_blocksize, GFP_KERNEL); ++ error = -ENOMEM; ++ if (header == NULL) ++ goto cleanup; ++ memset(header, 0, sb->s_blocksize); ++ end = (char *)header + sb->s_blocksize; ++ header->h_magic = cpu_to_le32(EXT2_XATTR_MAGIC); ++ header->h_blocks = header->h_refcount = cpu_to_le32(1); ++ last = here = ENTRY(header+1); ++ } ++ ++ if (not_found) { ++ /* Insert the new name. */ ++ int size = EXT2_XATTR_LEN(name_len); ++ int rest = (char *)last - (char *)here; ++ memmove((char *)here + size, here, rest); ++ memset(here, 0, size); ++ here->e_name_index = name_index; ++ here->e_name_len = name_len; ++ memcpy(here->e_name, name, name_len); ++ } else { ++ /* Remove the old value. */ ++ if (!here->e_value_block && here->e_value_size) { ++ char *first_val = (char *)header + min_offs; ++ int offs = le16_to_cpu(here->e_value_offs); ++ char *val = (char *)header + offs; ++ size_t size = EXT2_XATTR_SIZE( ++ le32_to_cpu(here->e_value_size)); ++ memmove(first_val + size, first_val, val - first_val); ++ memset(first_val, 0, size); ++ here->e_value_offs = 0; ++ min_offs += size; ++ ++ /* Adjust all value offsets. */ ++ last = ENTRY(header+1); ++ while (!IS_LAST_ENTRY(last)) { ++ int o = le16_to_cpu(last->e_value_offs); ++ if (!last->e_value_block && o < offs) ++ last->e_value_offs = ++ cpu_to_le16(o + size); ++ last = EXT2_XATTR_NEXT(last); ++ } ++ } ++ if (value == NULL) { ++ /* Remove this attribute. */ ++ if (EXT2_XATTR_NEXT(ENTRY(header+1)) == last) { ++ /* This block is now empty. */ ++ error = ext2_xattr_set2(inode, bh, NULL); ++ goto cleanup; ++ } else { ++ /* Remove the old name. */ ++ int size = EXT2_XATTR_LEN(name_len); ++ last = ENTRY((char *)last - size); ++ memmove(here, (char*)here + size, ++ (char*)last - (char*)here); ++ memset(last, 0, size); ++ } ++ } ++ } ++ ++ if (value != NULL) { ++ /* Insert the new value. */ ++ here->e_value_size = cpu_to_le32(value_len); ++ if (value_len) { ++ size_t size = EXT2_XATTR_SIZE(value_len); ++ char *val = (char *)header + min_offs - size; ++ here->e_value_offs = ++ cpu_to_le16((char *)val - (char *)header); ++ memset(val + size - EXT2_XATTR_PAD, 0, ++ EXT2_XATTR_PAD); /* Clear the pad bytes. */ ++ memcpy(val, value, value_len); ++ } ++ } ++ ext2_xattr_rehash(header, here); ++ ++ error = ext2_xattr_set2(inode, bh, header); ++ ++cleanup: ++ brelse(bh); ++ if (!(bh && header == HDR(bh))) ++ kfree(header); ++ up(&ext2_xattr_sem); ++ ++ return error; ++} ++ ++/* ++ * Second half of ext2_xattr_set(): Update the file system. ++ */ ++static int ++ext2_xattr_set2(struct inode *inode, struct buffer_head *old_bh, ++ struct ext2_xattr_header *header) ++{ ++ struct super_block *sb = inode->i_sb; ++ struct buffer_head *new_bh = NULL; ++ int error; ++ ++ if (header) { ++ new_bh = ext2_xattr_cache_find(inode, header); ++ if (new_bh) { ++ /* ++ * We found an identical block in the cache. ++ * The old block will be released after updating ++ * the inode. ++ */ ++ ea_bdebug(old_bh, "reusing block %ld", ++ new_bh->b_blocknr); ++ ++ error = -EDQUOT; ++ if (ext2_xattr_quota_alloc(inode, 1)) ++ goto cleanup; ++ ++ HDR(new_bh)->h_refcount = cpu_to_le32( ++ le32_to_cpu(HDR(new_bh)->h_refcount) + 1); ++ ea_bdebug(new_bh, "refcount now=%d", ++ le32_to_cpu(HDR(new_bh)->h_refcount)); ++ } else if (old_bh && header == HDR(old_bh)) { ++ /* Keep this block. */ ++ new_bh = old_bh; ++ ext2_xattr_cache_insert(new_bh); ++ } else { ++ /* We need to allocate a new block */ ++ int force = EXT2_I(inode)->i_file_acl != 0; ++ int block = ext2_xattr_new_block(inode, &error, force); ++ if (error) ++ goto cleanup; ++ ea_idebug(inode, "creating block %d", block); ++ ++ new_bh = sb_getblk(sb, block); ++ if (!new_bh) { ++ ext2_xattr_free_block(inode, block); ++ error = -EIO; ++ goto cleanup; ++ } ++ lock_buffer(new_bh); ++ memcpy(new_bh->b_data, header, new_bh->b_size); ++ mark_buffer_uptodate(new_bh, 1); ++ unlock_buffer(new_bh); ++ ext2_xattr_cache_insert(new_bh); ++ ++ ext2_xattr_update_super_block(sb); ++ } ++ mark_buffer_dirty(new_bh); ++ if (IS_SYNC(inode)) { ++ ll_rw_block(WRITE, 1, &new_bh); ++ wait_on_buffer(new_bh); ++ error = -EIO; ++ if (buffer_req(new_bh) && !buffer_uptodate(new_bh)) ++ goto cleanup; ++ } ++ } ++ ++ /* Update the inode. */ ++ EXT2_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0; ++ inode->i_ctime = CURRENT_TIME; ++ if (IS_SYNC(inode)) { ++ error = ext2_sync_inode (inode); ++ if (error) ++ goto cleanup; ++ } else ++ mark_inode_dirty(inode); ++ ++ error = 0; ++ if (old_bh && old_bh != new_bh) { ++ /* ++ * If there was an old block, and we are not still using it, ++ * we now release the old block. ++ */ ++ unsigned int refcount = le32_to_cpu(HDR(old_bh)->h_refcount); ++ ++ if (refcount == 1) { ++ /* Free the old block. */ ++ ea_bdebug(old_bh, "freeing"); ++ ext2_xattr_free_block(inode, old_bh->b_blocknr); ++ mark_buffer_clean(old_bh); ++ } else { ++ /* Decrement the refcount only. */ ++ refcount--; ++ HDR(old_bh)->h_refcount = cpu_to_le32(refcount); ++ ext2_xattr_quota_free(inode); ++ mark_buffer_dirty(old_bh); ++ ea_bdebug(old_bh, "refcount now=%d", refcount); ++ } ++ } ++ ++cleanup: ++ if (old_bh != new_bh) ++ brelse(new_bh); ++ ++ return error; ++} ++ ++/* ++ * ext2_xattr_delete_inode() ++ * ++ * Free extended attribute resources associated with this inode. This ++ * is called immediately before an inode is freed. ++ */ ++void ++ext2_xattr_delete_inode(struct inode *inode) ++{ ++ struct buffer_head *bh; ++ unsigned int block = EXT2_I(inode)->i_file_acl; ++ ++ if (!block) ++ return; ++ down(&ext2_xattr_sem); ++ ++ bh = sb_bread(inode->i_sb, block); ++ if (!bh) { ++ ext2_error(inode->i_sb, "ext2_xattr_delete_inode", ++ "inode %ld: block %d read error", inode->i_ino, block); ++ goto cleanup; ++ } ++ ea_bdebug(bh, "b_count=%d", atomic_read(&(bh->b_count))); ++ if (HDR(bh)->h_magic != cpu_to_le32(EXT2_XATTR_MAGIC) || ++ HDR(bh)->h_blocks != cpu_to_le32(1)) { ++ ext2_error(inode->i_sb, "ext2_xattr_delete_inode", ++ "inode %ld: bad block %d", inode->i_ino, block); ++ goto cleanup; ++ } ++ ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1); ++ if (HDR(bh)->h_refcount == cpu_to_le32(1)) { ++ ext2_xattr_cache_remove(bh); ++ ext2_xattr_free_block(inode, block); ++ bforget(bh); ++ bh = NULL; ++ } else { ++ HDR(bh)->h_refcount = cpu_to_le32( ++ le32_to_cpu(HDR(bh)->h_refcount) - 1); ++ mark_buffer_dirty(bh); ++ if (IS_SYNC(inode)) { ++ ll_rw_block(WRITE, 1, &bh); ++ wait_on_buffer(bh); ++ } ++ ext2_xattr_quota_free(inode); ++ } ++ EXT2_I(inode)->i_file_acl = 0; ++ ++cleanup: ++ brelse(bh); ++ up(&ext2_xattr_sem); ++} ++ ++/* ++ * ext2_xattr_put_super() ++ * ++ * This is called when a file system is unmounted. ++ */ ++void ++ext2_xattr_put_super(struct super_block *sb) ++{ ++#ifdef CONFIG_EXT2_FS_XATTR_SHARING ++ mb_cache_shrink(ext2_xattr_cache, sb->s_dev); ++#endif ++} ++ ++#ifdef CONFIG_EXT2_FS_XATTR_SHARING ++ ++/* ++ * ext2_xattr_cache_insert() ++ * ++ * Create a new entry in the extended attribute cache, and insert ++ * it unless such an entry is already in the cache. ++ * ++ * Returns 0, or a negative error number on failure. ++ */ ++static int ++ext2_xattr_cache_insert(struct buffer_head *bh) ++{ ++ __u32 hash = le32_to_cpu(HDR(bh)->h_hash); ++ struct mb_cache_entry *ce; ++ int error; ++ ++ ce = mb_cache_entry_alloc(ext2_xattr_cache); ++ if (!ce) ++ return -ENOMEM; ++ error = mb_cache_entry_insert(ce, bh->b_dev, bh->b_blocknr, &hash); ++ if (error) { ++ mb_cache_entry_free(ce); ++ if (error == -EBUSY) { ++ ea_bdebug(bh, "already in cache (%d cache entries)", ++ atomic_read(&ext2_xattr_cache->c_entry_count)); ++ error = 0; ++ } ++ } else { ++ ea_bdebug(bh, "inserting [%x] (%d cache entries)", (int)hash, ++ atomic_read(&ext2_xattr_cache->c_entry_count)); ++ mb_cache_entry_release(ce); ++ } ++ return error; ++} ++ ++/* ++ * ext2_xattr_cmp() ++ * ++ * Compare two extended attribute blocks for equality. ++ * ++ * Returns 0 if the blocks are equal, 1 if they differ, and ++ * a negative error number on errors. ++ */ ++static int ++ext2_xattr_cmp(struct ext2_xattr_header *header1, ++ struct ext2_xattr_header *header2) ++{ ++ struct ext2_xattr_entry *entry1, *entry2; ++ ++ entry1 = ENTRY(header1+1); ++ entry2 = ENTRY(header2+1); ++ while (!IS_LAST_ENTRY(entry1)) { ++ if (IS_LAST_ENTRY(entry2)) ++ return 1; ++ if (entry1->e_hash != entry2->e_hash || ++ entry1->e_name_len != entry2->e_name_len || ++ entry1->e_value_size != entry2->e_value_size || ++ memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len)) ++ return 1; ++ if (entry1->e_value_block != 0 || entry2->e_value_block != 0) ++ return -EIO; ++ if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs), ++ (char *)header2 + le16_to_cpu(entry2->e_value_offs), ++ le32_to_cpu(entry1->e_value_size))) ++ return 1; ++ ++ entry1 = EXT2_XATTR_NEXT(entry1); ++ entry2 = EXT2_XATTR_NEXT(entry2); ++ } ++ if (!IS_LAST_ENTRY(entry2)) ++ return 1; ++ return 0; ++} ++ ++/* ++ * ext2_xattr_cache_find() ++ * ++ * Find an identical extended attribute block. ++ * ++ * Returns a pointer to the block found, or NULL if such a block was ++ * not found or an error occurred. ++ */ ++static struct buffer_head * ++ext2_xattr_cache_find(struct inode *inode, struct ext2_xattr_header *header) ++{ ++ __u32 hash = le32_to_cpu(header->h_hash); ++ struct mb_cache_entry *ce; ++ ++ if (!header->h_hash) ++ return NULL; /* never share */ ++ ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); ++ ce = mb_cache_entry_find_first(ext2_xattr_cache, 0, inode->i_dev, hash); ++ while (ce) { ++ struct buffer_head *bh = sb_bread(inode->i_sb, ce->e_block); ++ ++ if (!bh) { ++ ext2_error(inode->i_sb, "ext2_xattr_cache_find", ++ "inode %ld: block %ld read error", ++ inode->i_ino, ce->e_block); ++ } else if (le32_to_cpu(HDR(bh)->h_refcount) > ++ EXT2_XATTR_REFCOUNT_MAX) { ++ ea_idebug(inode, "block %ld refcount %d>%d",ce->e_block, ++ le32_to_cpu(HDR(bh)->h_refcount), ++ EXT2_XATTR_REFCOUNT_MAX); ++ } else if (!ext2_xattr_cmp(header, HDR(bh))) { ++ ea_bdebug(bh, "b_count=%d",atomic_read(&(bh->b_count))); ++ mb_cache_entry_release(ce); ++ return bh; ++ } ++ brelse(bh); ++ ce = mb_cache_entry_find_next(ce, 0, inode->i_dev, hash); ++ } ++ return NULL; ++} ++ ++/* ++ * ext2_xattr_cache_remove() ++ * ++ * Remove the cache entry of a block from the cache. Called when a ++ * block becomes invalid. ++ */ ++static void ++ext2_xattr_cache_remove(struct buffer_head *bh) ++{ ++ struct mb_cache_entry *ce; ++ ++ ce = mb_cache_entry_get(ext2_xattr_cache, bh->b_dev, bh->b_blocknr); ++ if (ce) { ++ ea_bdebug(bh, "removing (%d cache entries remaining)", ++ atomic_read(&ext2_xattr_cache->c_entry_count)-1); ++ mb_cache_entry_free(ce); ++ } else ++ ea_bdebug(bh, "no cache entry"); ++} ++ ++#define NAME_HASH_SHIFT 5 ++#define VALUE_HASH_SHIFT 16 ++ ++/* ++ * ext2_xattr_hash_entry() ++ * ++ * Compute the hash of an extended attribute. ++ */ ++static inline void ext2_xattr_hash_entry(struct ext2_xattr_header *header, ++ struct ext2_xattr_entry *entry) ++{ ++ __u32 hash = 0; ++ char *name = entry->e_name; ++ int n; ++ ++ for (n=0; n < entry->e_name_len; n++) { ++ hash = (hash << NAME_HASH_SHIFT) ^ ++ (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^ ++ *name++; ++ } ++ ++ if (entry->e_value_block == 0 && entry->e_value_size != 0) { ++ __u32 *value = (__u32 *)((char *)header + ++ le16_to_cpu(entry->e_value_offs)); ++ for (n = (le32_to_cpu(entry->e_value_size) + ++ EXT2_XATTR_ROUND) >> EXT2_XATTR_PAD_BITS; n; n--) { ++ hash = (hash << VALUE_HASH_SHIFT) ^ ++ (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^ ++ le32_to_cpu(*value++); ++ } ++ } ++ entry->e_hash = cpu_to_le32(hash); ++} ++ ++#undef NAME_HASH_SHIFT ++#undef VALUE_HASH_SHIFT ++ ++#define BLOCK_HASH_SHIFT 16 ++ ++/* ++ * ext2_xattr_rehash() ++ * ++ * Re-compute the extended attribute hash value after an entry has changed. ++ */ ++static void ext2_xattr_rehash(struct ext2_xattr_header *header, ++ struct ext2_xattr_entry *entry) ++{ ++ struct ext2_xattr_entry *here; ++ __u32 hash = 0; ++ ++ ext2_xattr_hash_entry(header, entry); ++ here = ENTRY(header+1); ++ while (!IS_LAST_ENTRY(here)) { ++ if (!here->e_hash) { ++ /* Block is not shared if an entry's hash value == 0 */ ++ hash = 0; ++ break; ++ } ++ hash = (hash << BLOCK_HASH_SHIFT) ^ ++ (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^ ++ le32_to_cpu(here->e_hash); ++ here = EXT2_XATTR_NEXT(here); ++ } ++ header->h_hash = cpu_to_le32(hash); ++} ++ ++#undef BLOCK_HASH_SHIFT ++ ++int __init ++init_ext2_xattr(void) ++{ ++ ext2_xattr_cache = mb_cache_create("ext2_xattr", NULL, ++ sizeof(struct mb_cache_entry) + ++ sizeof(struct mb_cache_entry_index), 1, 61); ++ if (!ext2_xattr_cache) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++void ++exit_ext2_xattr(void) ++{ ++ mb_cache_destroy(ext2_xattr_cache); ++} ++ ++#else /* CONFIG_EXT2_FS_XATTR_SHARING */ ++ ++int __init ++init_ext2_xattr(void) ++{ ++ return 0; ++} ++ ++void ++exit_ext2_xattr(void) ++{ ++} ++ ++#endif /* CONFIG_EXT2_FS_XATTR_SHARING */ +Index: linux-2.4.24-vanilla/fs/ext2/xattr_user.c +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/ext2/xattr_user.c 2003-01-30 13:24:37.000000000 +0300 ++++ linux-2.4.24-vanilla/fs/ext2/xattr_user.c 2004-01-10 17:20:28.000000000 +0300 +@@ -0,0 +1,103 @@ ++/* ++ * linux/fs/ext2/xattr_user.c ++ * Handler for extended user attributes. ++ * ++ * Copyright (C) 2001 by Andreas Gruenbacher, ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_EXT2_FS_POSIX_ACL ++# include ++#endif ++ ++#define XATTR_USER_PREFIX "user." ++ ++static size_t ++ext2_xattr_user_list(char *list, struct inode *inode, ++ const char *name, int name_len) ++{ ++ const int prefix_len = sizeof(XATTR_USER_PREFIX)-1; ++ ++ if (!test_opt(inode->i_sb, XATTR_USER)) ++ return 0; ++ ++ if (list) { ++ memcpy(list, XATTR_USER_PREFIX, prefix_len); ++ memcpy(list+prefix_len, name, name_len); ++ list[prefix_len + name_len] = '\0'; ++ } ++ return prefix_len + name_len + 1; ++} ++ ++static int ++ext2_xattr_user_get(struct inode *inode, const char *name, ++ void *buffer, size_t size) ++{ ++ int error; ++ ++ if (strcmp(name, "") == 0) ++ return -EINVAL; ++ if (!test_opt(inode->i_sb, XATTR_USER)) ++ return -ENOTSUP; ++#ifdef CONFIG_EXT2_FS_POSIX_ACL ++ error = ext2_permission_locked(inode, MAY_READ); ++#else ++ error = permission(inode, MAY_READ); ++#endif ++ if (error) ++ return error; ++ ++ return ext2_xattr_get(inode, EXT2_XATTR_INDEX_USER, name, ++ buffer, size); ++} ++ ++static int ++ext2_xattr_user_set(struct inode *inode, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ int error; ++ ++ if (strcmp(name, "") == 0) ++ return -EINVAL; ++ if (!test_opt(inode->i_sb, XATTR_USER)) ++ return -ENOTSUP; ++ if ( !S_ISREG(inode->i_mode) && ++ (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX)) ++ return -EPERM; ++#ifdef CONFIG_EXT2_FS_POSIX_ACL ++ error = ext2_permission_locked(inode, MAY_WRITE); ++#else ++ error = permission(inode, MAY_WRITE); ++#endif ++ if (error) ++ return error; ++ ++ return ext2_xattr_set(inode, EXT2_XATTR_INDEX_USER, name, ++ value, size, flags); ++} ++ ++struct ext2_xattr_handler ext2_xattr_user_handler = { ++ prefix: XATTR_USER_PREFIX, ++ list: ext2_xattr_user_list, ++ get: ext2_xattr_user_get, ++ set: ext2_xattr_user_set, ++}; ++ ++int __init ++init_ext2_xattr_user(void) ++{ ++ return ext2_xattr_register(EXT2_XATTR_INDEX_USER, ++ &ext2_xattr_user_handler); ++} ++ ++void ++exit_ext2_xattr_user(void) ++{ ++ ext2_xattr_unregister(EXT2_XATTR_INDEX_USER, ++ &ext2_xattr_user_handler); ++} +Index: linux-2.4.24-vanilla/fs/ext3/Makefile +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/ext3/Makefile 2004-01-10 17:11:50.000000000 +0300 ++++ linux-2.4.24-vanilla/fs/ext3/Makefile 2004-01-10 17:20:28.000000000 +0300 +@@ -1,5 +1,5 @@ + # +-# Makefile for the linux ext2-filesystem routines. ++# Makefile for the linux ext3-filesystem routines. + # + # Note! Dependencies are done automagically by 'make dep', which also + # removes any old dependencies. DON'T put your own dependencies here +@@ -9,10 +9,14 @@ + + O_TARGET := ext3.o + +-export-objs := super.o inode.o ++export-objs := ext3-exports.o + + obj-y := balloc.o bitmap.o dir.o file.o fsync.o ialloc.o inode.o \ +- ioctl.o namei.o super.o symlink.o hash.o ++ ioctl.o namei.o super.o symlink.o hash.o ext3-exports.o + obj-m := $(O_TARGET) + ++export-objs += xattr.o ++obj-$(CONFIG_EXT3_FS_XATTR) += xattr.o ++obj-$(CONFIG_EXT3_FS_XATTR_USER) += xattr_user.o ++ + include $(TOPDIR)/Rules.make +Index: linux-2.4.24-vanilla/fs/ext3/file.c +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/ext3/file.c 2004-01-10 17:11:50.000000000 +0300 ++++ linux-2.4.24-vanilla/fs/ext3/file.c 2004-01-10 17:20:28.000000000 +0300 +@@ -23,6 +23,7 @@ + #include + #include + #include ++#include + #include + #include + +@@ -127,5 +128,9 @@ + struct inode_operations ext3_file_inode_operations = { + truncate: ext3_truncate, /* BKL held */ + setattr: ext3_setattr, /* BKL held */ ++ setxattr: ext3_setxattr, /* BKL held */ ++ getxattr: ext3_getxattr, /* BKL held */ ++ listxattr: ext3_listxattr, /* BKL held */ ++ removexattr: ext3_removexattr, /* BKL held */ + }; + +Index: linux-2.4.24-vanilla/fs/ext3/ialloc.c +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/ext3/ialloc.c 2004-01-10 17:04:42.000000000 +0300 ++++ linux-2.4.24-vanilla/fs/ext3/ialloc.c 2004-01-10 17:20:28.000000000 +0300 +@@ -17,6 +17,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -216,6 +217,7 @@ + * as writing the quota to disk may need the lock as well. + */ + DQUOT_INIT(inode); ++ ext3_xattr_delete_inode(handle, inode); + DQUOT_FREE_INODE(inode); + DQUOT_DROP(inode); + +Index: linux-2.4.24-vanilla/fs/ext3/inode.c +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/ext3/inode.c 2004-01-10 17:05:05.000000000 +0300 ++++ linux-2.4.24-vanilla/fs/ext3/inode.c 2004-01-10 17:20:28.000000000 +0300 +@@ -39,6 +39,18 @@ + */ + #undef SEARCH_FROM_ZERO + ++/* ++ * Test whether an inode is a fast symlink. ++ */ ++static inline int ext3_inode_is_fast_symlink(struct inode *inode) ++{ ++ int ea_blocks = inode->u.ext3_i.i_file_acl ? ++ (inode->i_sb->s_blocksize >> 9) : 0; ++ ++ return (S_ISLNK(inode->i_mode) && ++ inode->i_blocks - ea_blocks == 0); ++} ++ + /* The ext3 forget function must perform a revoke if we are freeing data + * which has been journaled. Metadata (eg. indirect blocks) must be + * revoked in all cases. +@@ -48,7 +60,7 @@ + * still needs to be revoked. + */ + +-static int ext3_forget(handle_t *handle, int is_metadata, ++int ext3_forget(handle_t *handle, int is_metadata, + struct inode *inode, struct buffer_head *bh, + int blocknr) + { +@@ -179,9 +191,7 @@ + { + handle_t *handle; + +- if (is_bad_inode(inode) || +- inode->i_ino == EXT3_ACL_IDX_INO || +- inode->i_ino == EXT3_ACL_DATA_INO) ++ if (is_bad_inode(inode)) + goto no_delete; + + lock_kernel(); +@@ -1870,6 +1880,8 @@ + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return; ++ if (ext3_inode_is_fast_symlink(inode)) ++ return; + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + return; + +@@ -2017,8 +2029,6 @@ + struct ext3_group_desc * gdp; + + if ((inode->i_ino != EXT3_ROOT_INO && +- inode->i_ino != EXT3_ACL_IDX_INO && +- inode->i_ino != EXT3_ACL_DATA_INO && + inode->i_ino != EXT3_JOURNAL_INO && + inode->i_ino < EXT3_FIRST_INO(inode->i_sb)) || + inode->i_ino > le32_to_cpu( +@@ -2159,10 +2169,7 @@ + inode->u.ext3_i.i_data[block] = iloc.raw_inode->i_block[block]; + INIT_LIST_HEAD(&inode->u.ext3_i.i_orphan); + +- if (inode->i_ino == EXT3_ACL_IDX_INO || +- inode->i_ino == EXT3_ACL_DATA_INO) +- /* Nothing to do */ ; +- else if (S_ISREG(inode->i_mode)) { ++ if (S_ISREG(inode->i_mode)) { + inode->i_op = &ext3_file_inode_operations; + inode->i_fop = &ext3_file_operations; + inode->i_mapping->a_ops = &ext3_aops; +@@ -2170,15 +2177,17 @@ + inode->i_op = &ext3_dir_inode_operations; + inode->i_fop = &ext3_dir_operations; + } else if (S_ISLNK(inode->i_mode)) { +- if (!inode->i_blocks) ++ if (ext3_inode_is_fast_symlink(inode)) + inode->i_op = &ext3_fast_symlink_inode_operations; + else { +- inode->i_op = &page_symlink_inode_operations; ++ inode->i_op = &ext3_symlink_inode_operations; + inode->i_mapping->a_ops = &ext3_aops; + } +- } else ++ } else { ++ inode->i_op = &ext3_special_inode_operations; + init_special_inode(inode, inode->i_mode, + le32_to_cpu(iloc.raw_inode->i_block[0])); ++ } + brelse(iloc.bh); + ext3_set_inode_flags(inode); + return; +Index: linux-2.4.24-vanilla/fs/ext3/namei.c +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/ext3/namei.c 2004-01-10 17:11:50.000000000 +0300 ++++ linux-2.4.24-vanilla/fs/ext3/namei.c 2004-01-10 17:20:28.000000000 +0300 +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -1613,7 +1614,7 @@ + if (IS_SYNC(dir)) + handle->h_sync = 1; + +- inode = ext3_new_inode (handle, dir, S_IFDIR); ++ inode = ext3_new_inode (handle, dir, S_IFDIR | mode); + err = PTR_ERR(inode); + if (IS_ERR(inode)) + goto out_stop; +@@ -1621,7 +1622,6 @@ + inode->i_op = &ext3_dir_inode_operations; + inode->i_fop = &ext3_dir_operations; + inode->i_size = EXT3_I(inode)->i_disksize = inode->i_sb->s_blocksize; +- inode->i_blocks = 0; + dir_block = ext3_bread (handle, inode, 0, 1, &err); + if (!dir_block) { + inode->i_nlink--; /* is this nlink == 0? */ +@@ -1648,9 +1648,6 @@ + BUFFER_TRACE(dir_block, "call ext3_journal_dirty_metadata"); + ext3_journal_dirty_metadata(handle, dir_block); + brelse (dir_block); +- inode->i_mode = S_IFDIR | mode; +- if (dir->i_mode & S_ISGID) +- inode->i_mode |= S_ISGID; + ext3_mark_inode_dirty(handle, inode); + err = ext3_add_entry (handle, dentry, inode); + if (err) { +@@ -2019,7 +2016,7 @@ + goto out_stop; + + if (l > sizeof (EXT3_I(inode)->i_data)) { +- inode->i_op = &page_symlink_inode_operations; ++ inode->i_op = &ext3_symlink_inode_operations; + inode->i_mapping->a_ops = &ext3_aops; + /* + * block_symlink() calls back into ext3_prepare/commit_write. +@@ -2244,4 +2241,16 @@ + rmdir: ext3_rmdir, /* BKL held */ + mknod: ext3_mknod, /* BKL held */ + rename: ext3_rename, /* BKL held */ ++ setxattr: ext3_setxattr, /* BKL held */ ++ getxattr: ext3_getxattr, /* BKL held */ ++ listxattr: ext3_listxattr, /* BKL held */ ++ removexattr: ext3_removexattr, /* BKL held */ + }; ++ ++struct inode_operations ext3_special_inode_operations = { ++ setxattr: ext3_setxattr, /* BKL held */ ++ getxattr: ext3_getxattr, /* BKL held */ ++ listxattr: ext3_listxattr, /* BKL held */ ++ removexattr: ext3_removexattr, /* BKL held */ ++}; ++ +Index: linux-2.4.24-vanilla/fs/ext3/super.c +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/ext3/super.c 2004-01-10 17:11:50.000000000 +0300 ++++ linux-2.4.24-vanilla/fs/ext3/super.c 2004-01-10 17:20:28.000000000 +0300 +@@ -24,6 +24,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -406,6 +407,7 @@ + kdev_t j_dev = sbi->s_journal->j_dev; + int i; + ++ ext3_xattr_put_super(sb); + journal_destroy(sbi->s_journal); + if (!(sb->s_flags & MS_RDONLY)) { + EXT3_CLEAR_INCOMPAT_FEATURE(sb, EXT3_FEATURE_INCOMPAT_RECOVER); +@@ -505,6 +507,7 @@ + int is_remount) + { + unsigned long *mount_options = &sbi->s_mount_opt; ++ + uid_t *resuid = &sbi->s_resuid; + gid_t *resgid = &sbi->s_resgid; + char * this_char; +@@ -517,6 +520,13 @@ + this_char = strtok (NULL, ",")) { + if ((value = strchr (this_char, '=')) != NULL) + *value++ = 0; ++#ifdef CONFIG_EXT3_FS_XATTR_USER ++ if (!strcmp (this_char, "user_xattr")) ++ set_opt (*mount_options, XATTR_USER); ++ else if (!strcmp (this_char, "nouser_xattr")) ++ clear_opt (*mount_options, XATTR_USER); ++ else ++#endif + if (!strcmp (this_char, "bsddf")) + clear_opt (*mount_options, MINIX_DF); + else if (!strcmp (this_char, "nouid32")) { +@@ -934,6 +944,12 @@ + sbi->s_mount_opt = 0; + sbi->s_resuid = EXT3_DEF_RESUID; + sbi->s_resgid = EXT3_DEF_RESGID; ++ ++ /* Default extended attribute flags */ ++#ifdef CONFIG_EXT3_FS_XATTR_USER ++ /* set_opt(sbi->s_mount_opt, XATTR_USER); */ ++#endif ++ + if (!parse_options ((char *) data, &sb_block, sbi, &journal_inum, 0)) { + sb->s_dev = 0; + goto out_fail; +@@ -1822,22 +1838,35 @@ + + static int __init init_ext3_fs(void) + { ++ int error; + #ifdef CONFIG_QUOTA + init_dquot_operations(&ext3_qops); + old_sync_dquot = ext3_qops.sync_dquot; + ext3_qops.sync_dquot = ext3_sync_dquot; + #endif +- return register_filesystem(&ext3_fs_type); ++ error = init_ext3_xattr(); ++ if (error) ++ return error; ++ error = init_ext3_xattr_user(); ++ if (error) ++ goto fail; ++ error = register_filesystem(&ext3_fs_type); ++ if (!error) ++ return 0; ++ ++ exit_ext3_xattr_user(); ++fail: ++ exit_ext3_xattr(); ++ return error; + } + + static void __exit exit_ext3_fs(void) + { + unregister_filesystem(&ext3_fs_type); ++ exit_ext3_xattr_user(); ++ exit_ext3_xattr(); + } + +-EXPORT_SYMBOL(ext3_force_commit); +-EXPORT_SYMBOL(ext3_bread); +- + MODULE_AUTHOR("Remy Card, Stephen Tweedie, Andrew Morton, Andreas Dilger, Theodore Ts'o and others"); + MODULE_DESCRIPTION("Second Extended Filesystem with journaling extensions"); + MODULE_LICENSE("GPL"); +Index: linux-2.4.24-vanilla/fs/ext3/symlink.c +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/ext3/symlink.c 2001-11-10 01:25:04.000000000 +0300 ++++ linux-2.4.24-vanilla/fs/ext3/symlink.c 2004-01-10 17:20:28.000000000 +0300 +@@ -20,6 +20,7 @@ + #include + #include + #include ++#include + + static int ext3_readlink(struct dentry *dentry, char *buffer, int buflen) + { +@@ -33,7 +34,20 @@ + return vfs_follow_link(nd, s); + } + ++struct inode_operations ext3_symlink_inode_operations = { ++ readlink: page_readlink, /* BKL not held. Don't need */ ++ follow_link: page_follow_link, /* BKL not held. Don't need */ ++ setxattr: ext3_setxattr, /* BKL held */ ++ getxattr: ext3_getxattr, /* BKL held */ ++ listxattr: ext3_listxattr, /* BKL held */ ++ removexattr: ext3_removexattr, /* BKL held */ ++}; ++ + struct inode_operations ext3_fast_symlink_inode_operations = { + readlink: ext3_readlink, /* BKL not held. Don't need */ + follow_link: ext3_follow_link, /* BKL not held. Don't need */ ++ setxattr: ext3_setxattr, /* BKL held */ ++ getxattr: ext3_getxattr, /* BKL held */ ++ listxattr: ext3_listxattr, /* BKL held */ ++ removexattr: ext3_removexattr, /* BKL held */ + }; +Index: linux-2.4.24-vanilla/fs/ext3/xattr.c +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/ext3/xattr.c 2003-01-30 13:24:37.000000000 +0300 ++++ linux-2.4.24-vanilla/fs/ext3/xattr.c 2004-01-10 17:20:28.000000000 +0300 +@@ -0,0 +1,1225 @@ ++/* ++ * linux/fs/ext3/xattr.c ++ * ++ * Copyright (C) 2001 by Andreas Gruenbacher, ++ * ++ * Fix by Harrison Xing . ++ * Ext3 code with a lot of help from Eric Jarman . ++ * Extended attributes for symlinks and special files added per ++ * suggestion of Luka Renko . ++ */ ++ ++/* ++ * Extended attributes are stored on disk blocks allocated outside of ++ * any inode. The i_file_acl field is then made to point to this allocated ++ * block. If all extended attributes of an inode are identical, these ++ * inodes may share the same extended attribute block. Such situations ++ * are automatically detected by keeping a cache of recent attribute block ++ * numbers and hashes over the block's contents in memory. ++ * ++ * ++ * Extended attribute block layout: ++ * ++ * +------------------+ ++ * | header | ++ * | entry 1 | | ++ * | entry 2 | | growing downwards ++ * | entry 3 | v ++ * | four null bytes | ++ * | . . . | ++ * | value 1 | ^ ++ * | value 3 | | growing upwards ++ * | value 2 | | ++ * +------------------+ ++ * ++ * The block header is followed by multiple entry descriptors. These entry ++ * descriptors are variable in size, and alligned to EXT3_XATTR_PAD ++ * byte boundaries. The entry descriptors are sorted by attribute name, ++ * so that two extended attribute blocks can be compared efficiently. ++ * ++ * Attribute values are aligned to the end of the block, stored in ++ * no specific order. They are also padded to EXT3_XATTR_PAD byte ++ * boundaries. No additional gaps are left between them. ++ * ++ * Locking strategy ++ * ---------------- ++ * The VFS already holds the BKL and the inode->i_sem semaphore when any of ++ * the xattr inode operations are called, so we are guaranteed that only one ++ * processes accesses extended attributes of an inode at any time. ++ * ++ * For writing we also grab the ext3_xattr_sem semaphore. This ensures that ++ * only a single process is modifying an extended attribute block, even ++ * if the block is shared among inodes. ++ * ++ * Note for porting to 2.5 ++ * ----------------------- ++ * The BKL will no longer be held in the xattr inode operations. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#define EXT3_EA_USER "user." ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) ++# define mark_buffer_dirty(bh) mark_buffer_dirty(bh, 1) ++#endif ++ ++#define HDR(bh) ((struct ext3_xattr_header *)((bh)->b_data)) ++#define ENTRY(ptr) ((struct ext3_xattr_entry *)(ptr)) ++#define FIRST_ENTRY(bh) ENTRY(HDR(bh)+1) ++#define IS_LAST_ENTRY(entry) (*(__u32 *)(entry) == 0) ++ ++#ifdef EXT3_XATTR_DEBUG ++# define ea_idebug(inode, f...) do { \ ++ printk(KERN_DEBUG "inode %s:%ld: ", \ ++ kdevname(inode->i_dev), inode->i_ino); \ ++ printk(f); \ ++ printk("\n"); \ ++ } while (0) ++# define ea_bdebug(bh, f...) do { \ ++ printk(KERN_DEBUG "block %s:%ld: ", \ ++ kdevname(bh->b_dev), bh->b_blocknr); \ ++ printk(f); \ ++ printk("\n"); \ ++ } while (0) ++#else ++# define ea_idebug(f...) ++# define ea_bdebug(f...) ++#endif ++ ++static int ext3_xattr_set2(handle_t *, struct inode *, struct buffer_head *, ++ struct ext3_xattr_header *); ++ ++#ifdef CONFIG_EXT3_FS_XATTR_SHARING ++ ++static int ext3_xattr_cache_insert(struct buffer_head *); ++static struct buffer_head *ext3_xattr_cache_find(struct inode *, ++ struct ext3_xattr_header *); ++static void ext3_xattr_cache_remove(struct buffer_head *); ++static void ext3_xattr_rehash(struct ext3_xattr_header *, ++ struct ext3_xattr_entry *); ++ ++static struct mb_cache *ext3_xattr_cache; ++ ++#else ++# define ext3_xattr_cache_insert(bh) 0 ++# define ext3_xattr_cache_find(inode, header) NULL ++# define ext3_xattr_cache_remove(bh) while(0) {} ++# define ext3_xattr_rehash(header, entry) while(0) {} ++#endif ++ ++/* ++ * If a file system does not share extended attributes among inodes, ++ * we should not need the ext3_xattr_sem semaphore. However, the ++ * filesystem may still contain shared blocks, so we always take ++ * the lock. ++ */ ++ ++DECLARE_MUTEX(ext3_xattr_sem); ++ ++static inline int ++ext3_xattr_new_block(handle_t *handle, struct inode *inode, ++ int * errp, int force) ++{ ++ struct super_block *sb = inode->i_sb; ++ int goal = le32_to_cpu(EXT3_SB(sb)->s_es->s_first_data_block) + ++ EXT3_I(inode)->i_block_group * EXT3_BLOCKS_PER_GROUP(sb); ++ ++ /* How can we enforce the allocation? */ ++ int block = ext3_new_block(handle, inode, goal, 0, 0, errp); ++#ifdef OLD_QUOTAS ++ if (!*errp) ++ inode->i_blocks += inode->i_sb->s_blocksize >> 9; ++#endif ++ return block; ++} ++ ++static inline int ++ext3_xattr_quota_alloc(struct inode *inode, int force) ++{ ++ /* How can we enforce the allocation? */ ++#ifdef OLD_QUOTAS ++ int error = DQUOT_ALLOC_BLOCK(inode->i_sb, inode, 1); ++ if (!error) ++ inode->i_blocks += inode->i_sb->s_blocksize >> 9; ++#else ++ int error = DQUOT_ALLOC_BLOCK(inode, 1); ++#endif ++ return error; ++} ++ ++#ifdef OLD_QUOTAS ++ ++static inline void ++ext3_xattr_quota_free(struct inode *inode) ++{ ++ DQUOT_FREE_BLOCK(inode->i_sb, inode, 1); ++ inode->i_blocks -= inode->i_sb->s_blocksize >> 9; ++} ++ ++static inline void ++ext3_xattr_free_block(handle_t *handle, struct inode * inode, ++ unsigned long block) ++{ ++ ext3_free_blocks(handle, inode, block, 1); ++ inode->i_blocks -= inode->i_sb->s_blocksize >> 9; ++} ++ ++#else ++# define ext3_xattr_quota_free(inode) \ ++ DQUOT_FREE_BLOCK(inode, 1) ++# define ext3_xattr_free_block(handle, inode, block) \ ++ ext3_free_blocks(handle, inode, block, 1) ++#endif ++ ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,18) ++ ++static inline struct buffer_head * ++sb_bread(struct super_block *sb, int block) ++{ ++ return bread(sb->s_dev, block, sb->s_blocksize); ++} ++ ++static inline struct buffer_head * ++sb_getblk(struct super_block *sb, int block) ++{ ++ return getblk(sb->s_dev, block, sb->s_blocksize); ++} ++ ++#endif ++ ++struct ext3_xattr_handler *ext3_xattr_handlers[EXT3_XATTR_INDEX_MAX]; ++rwlock_t ext3_handler_lock = RW_LOCK_UNLOCKED; ++ ++int ++ext3_xattr_register(int name_index, struct ext3_xattr_handler *handler) ++{ ++ int error = -EINVAL; ++ ++ if (name_index > 0 && name_index <= EXT3_XATTR_INDEX_MAX) { ++ write_lock(&ext3_handler_lock); ++ if (!ext3_xattr_handlers[name_index-1]) { ++ ext3_xattr_handlers[name_index-1] = handler; ++ error = 0; ++ } ++ write_unlock(&ext3_handler_lock); ++ } ++ return error; ++} ++ ++void ++ext3_xattr_unregister(int name_index, struct ext3_xattr_handler *handler) ++{ ++ if (name_index > 0 || name_index <= EXT3_XATTR_INDEX_MAX) { ++ write_lock(&ext3_handler_lock); ++ ext3_xattr_handlers[name_index-1] = NULL; ++ write_unlock(&ext3_handler_lock); ++ } ++} ++ ++static inline const char * ++strcmp_prefix(const char *a, const char *a_prefix) ++{ ++ while (*a_prefix && *a == *a_prefix) { ++ a++; ++ a_prefix++; ++ } ++ return *a_prefix ? NULL : a; ++} ++ ++/* ++ * Decode the extended attribute name, and translate it into ++ * the name_index and name suffix. ++ */ ++static inline struct ext3_xattr_handler * ++ext3_xattr_resolve_name(const char **name) ++{ ++ struct ext3_xattr_handler *handler = NULL; ++ int i; ++ ++ if (!*name) ++ return NULL; ++ read_lock(&ext3_handler_lock); ++ for (i=0; iprefix); ++ if (n) { ++ handler = ext3_xattr_handlers[i]; ++ *name = n; ++ break; ++ } ++ } ++ } ++ read_unlock(&ext3_handler_lock); ++ return handler; ++} ++ ++static inline struct ext3_xattr_handler * ++ext3_xattr_handler(int name_index) ++{ ++ struct ext3_xattr_handler *handler = NULL; ++ if (name_index > 0 && name_index <= EXT3_XATTR_INDEX_MAX) { ++ read_lock(&ext3_handler_lock); ++ handler = ext3_xattr_handlers[name_index-1]; ++ read_unlock(&ext3_handler_lock); ++ } ++ return handler; ++} ++ ++/* ++ * Inode operation getxattr() ++ * ++ * dentry->d_inode->i_sem down ++ * BKL held [before 2.5.x] ++ */ ++ssize_t ++ext3_getxattr(struct dentry *dentry, const char *name, ++ void *buffer, size_t size) ++{ ++ struct ext3_xattr_handler *handler; ++ struct inode *inode = dentry->d_inode; ++ ++ handler = ext3_xattr_resolve_name(&name); ++ if (!handler) ++ return -ENOTSUP; ++ return handler->get(inode, name, buffer, size); ++} ++ ++/* ++ * Inode operation listxattr() ++ * ++ * dentry->d_inode->i_sem down ++ * BKL held [before 2.5.x] ++ */ ++ssize_t ++ext3_listxattr(struct dentry *dentry, char *buffer, size_t size) ++{ ++ return ext3_xattr_list(dentry->d_inode, buffer, size); ++} ++ ++/* ++ * Inode operation setxattr() ++ * ++ * dentry->d_inode->i_sem down ++ * BKL held [before 2.5.x] ++ */ ++int ++ext3_setxattr(struct dentry *dentry, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ struct ext3_xattr_handler *handler; ++ struct inode *inode = dentry->d_inode; ++ ++ if (size == 0) ++ value = ""; /* empty EA, do not remove */ ++ handler = ext3_xattr_resolve_name(&name); ++ if (!handler) ++ return -ENOTSUP; ++ return handler->set(inode, name, value, size, flags); ++} ++ ++/* ++ * Inode operation removexattr() ++ * ++ * dentry->d_inode->i_sem down ++ * BKL held [before 2.5.x] ++ */ ++int ++ext3_removexattr(struct dentry *dentry, const char *name) ++{ ++ struct ext3_xattr_handler *handler; ++ struct inode *inode = dentry->d_inode; ++ ++ handler = ext3_xattr_resolve_name(&name); ++ if (!handler) ++ return -ENOTSUP; ++ return handler->set(inode, name, NULL, 0, XATTR_REPLACE); ++} ++ ++/* ++ * ext3_xattr_get() ++ * ++ * Copy an extended attribute into the buffer ++ * provided, or compute the buffer size required. ++ * Buffer is NULL to compute the size of the buffer required. ++ * ++ * Returns a negative error number on failure, or the number of bytes ++ * used / required on success. ++ */ ++int ++ext3_xattr_get(struct inode *inode, int name_index, const char *name, ++ void *buffer, size_t buffer_size) ++{ ++ struct buffer_head *bh = NULL; ++ struct ext3_xattr_entry *entry; ++ unsigned int block, size; ++ char *end; ++ int name_len, error; ++ ++ ea_idebug(inode, "name=%d.%s, buffer=%p, buffer_size=%ld", ++ name_index, name, buffer, (long)buffer_size); ++ ++ if (name == NULL) ++ return -EINVAL; ++ if (!EXT3_I(inode)->i_file_acl) ++ return -ENOATTR; ++ block = EXT3_I(inode)->i_file_acl; ++ ea_idebug(inode, "reading block %d", block); ++ bh = sb_bread(inode->i_sb, block); ++ if (!bh) ++ return -EIO; ++ ea_bdebug(bh, "b_count=%d, refcount=%d", ++ atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); ++ end = bh->b_data + bh->b_size; ++ if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) || ++ HDR(bh)->h_blocks != cpu_to_le32(1)) { ++bad_block: ext3_error(inode->i_sb, "ext3_xattr_get", ++ "inode %ld: bad block %d", inode->i_ino, block); ++ error = -EIO; ++ goto cleanup; ++ } ++ /* find named attribute */ ++ name_len = strlen(name); ++ ++ error = -ERANGE; ++ if (name_len > 255) ++ goto cleanup; ++ entry = FIRST_ENTRY(bh); ++ while (!IS_LAST_ENTRY(entry)) { ++ struct ext3_xattr_entry *next = ++ EXT3_XATTR_NEXT(entry); ++ if ((char *)next >= end) ++ goto bad_block; ++ if (name_index == entry->e_name_index && ++ name_len == entry->e_name_len && ++ memcmp(name, entry->e_name, name_len) == 0) ++ goto found; ++ entry = next; ++ } ++ /* Check the remaining name entries */ ++ while (!IS_LAST_ENTRY(entry)) { ++ struct ext3_xattr_entry *next = ++ EXT3_XATTR_NEXT(entry); ++ if ((char *)next >= end) ++ goto bad_block; ++ entry = next; ++ } ++ if (ext3_xattr_cache_insert(bh)) ++ ea_idebug(inode, "cache insert failed"); ++ error = -ENOATTR; ++ goto cleanup; ++found: ++ /* check the buffer size */ ++ if (entry->e_value_block != 0) ++ goto bad_block; ++ size = le32_to_cpu(entry->e_value_size); ++ if (size > inode->i_sb->s_blocksize || ++ le16_to_cpu(entry->e_value_offs) + size > inode->i_sb->s_blocksize) ++ goto bad_block; ++ ++ if (ext3_xattr_cache_insert(bh)) ++ ea_idebug(inode, "cache insert failed"); ++ if (buffer) { ++ error = -ERANGE; ++ if (size > buffer_size) ++ goto cleanup; ++ /* return value of attribute */ ++ memcpy(buffer, bh->b_data + le16_to_cpu(entry->e_value_offs), ++ size); ++ } ++ error = size; ++ ++cleanup: ++ brelse(bh); ++ ++ return error; ++} ++ ++/* ++ * ext3_xattr_list() ++ * ++ * Copy a list of attribute names into the buffer ++ * provided, or compute the buffer size required. ++ * Buffer is NULL to compute the size of the buffer required. ++ * ++ * Returns a negative error number on failure, or the number of bytes ++ * used / required on success. ++ */ ++int ++ext3_xattr_list(struct inode *inode, char *buffer, size_t buffer_size) ++{ ++ struct buffer_head *bh = NULL; ++ struct ext3_xattr_entry *entry; ++ unsigned int block, size = 0; ++ char *buf, *end; ++ int error; ++ ++ ea_idebug(inode, "buffer=%p, buffer_size=%ld", ++ buffer, (long)buffer_size); ++ ++ if (!EXT3_I(inode)->i_file_acl) ++ return 0; ++ block = EXT3_I(inode)->i_file_acl; ++ ea_idebug(inode, "reading block %d", block); ++ bh = sb_bread(inode->i_sb, block); ++ if (!bh) ++ return -EIO; ++ ea_bdebug(bh, "b_count=%d, refcount=%d", ++ atomic_read(&(bh->b_count)), le32_to_cpu(HDR(bh)->h_refcount)); ++ end = bh->b_data + bh->b_size; ++ if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) || ++ HDR(bh)->h_blocks != cpu_to_le32(1)) { ++bad_block: ext3_error(inode->i_sb, "ext3_xattr_list", ++ "inode %ld: bad block %d", inode->i_ino, block); ++ error = -EIO; ++ goto cleanup; ++ } ++ /* compute the size required for the list of attribute names */ ++ for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry); ++ entry = EXT3_XATTR_NEXT(entry)) { ++ struct ext3_xattr_handler *handler; ++ struct ext3_xattr_entry *next = ++ EXT3_XATTR_NEXT(entry); ++ if ((char *)next >= end) ++ goto bad_block; ++ ++ handler = ext3_xattr_handler(entry->e_name_index); ++ if (handler) ++ size += handler->list(NULL, inode, entry->e_name, ++ entry->e_name_len); ++ } ++ ++ if (ext3_xattr_cache_insert(bh)) ++ ea_idebug(inode, "cache insert failed"); ++ if (!buffer) { ++ error = size; ++ goto cleanup; ++ } else { ++ error = -ERANGE; ++ if (size > buffer_size) ++ goto cleanup; ++ } ++ ++ /* list the attribute names */ ++ buf = buffer; ++ for (entry = FIRST_ENTRY(bh); !IS_LAST_ENTRY(entry); ++ entry = EXT3_XATTR_NEXT(entry)) { ++ struct ext3_xattr_handler *handler; ++ ++ handler = ext3_xattr_handler(entry->e_name_index); ++ if (handler) ++ buf += handler->list(buf, inode, entry->e_name, ++ entry->e_name_len); ++ } ++ error = size; ++ ++cleanup: ++ brelse(bh); ++ ++ return error; ++} ++ ++/* ++ * If the EXT3_FEATURE_COMPAT_EXT_ATTR feature of this file system is ++ * not set, set it. ++ */ ++static void ext3_xattr_update_super_block(handle_t *handle, ++ struct super_block *sb) ++{ ++ if (EXT3_HAS_COMPAT_FEATURE(sb, EXT3_FEATURE_COMPAT_EXT_ATTR)) ++ return; ++ ++ lock_super(sb); ++ ext3_journal_get_write_access(handle, EXT3_SB(sb)->s_sbh); ++#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0) ++ EXT3_SB(sb)->s_feature_compat |= EXT3_FEATURE_COMPAT_EXT_ATTR; ++#endif ++ EXT3_SB(sb)->s_es->s_feature_compat |= ++ cpu_to_le32(EXT3_FEATURE_COMPAT_EXT_ATTR); ++ sb->s_dirt = 1; ++ ext3_journal_dirty_metadata(handle, EXT3_SB(sb)->s_sbh); ++ unlock_super(sb); ++} ++ ++/* ++ * ext3_xattr_set() ++ * ++ * Create, replace or remove an extended attribute for this inode. Buffer ++ * is NULL to remove an existing extended attribute, and non-NULL to ++ * either replace an existing extended attribute, or create a new extended ++ * attribute. The flags XATTR_REPLACE and XATTR_CREATE ++ * specify that an extended attribute must exist and must not exist ++ * previous to the call, respectively. ++ * ++ * Returns 0, or a negative error number on failure. ++ */ ++int ++ext3_xattr_set(handle_t *handle, struct inode *inode, int name_index, ++ const char *name, const void *value, size_t value_len, int flags) ++{ ++ struct super_block *sb = inode->i_sb; ++ struct buffer_head *bh = NULL; ++ struct ext3_xattr_header *header = NULL; ++ struct ext3_xattr_entry *here, *last; ++ unsigned int name_len; ++ int block = EXT3_I(inode)->i_file_acl; ++ int min_offs = sb->s_blocksize, not_found = 1, free, error; ++ char *end; ++ ++ /* ++ * header -- Points either into bh, or to a temporarily ++ * allocated buffer. ++ * here -- The named entry found, or the place for inserting, within ++ * the block pointed to by header. ++ * last -- Points right after the last named entry within the block ++ * pointed to by header. ++ * min_offs -- The offset of the first value (values are aligned ++ * towards the end of the block). ++ * end -- Points right after the block pointed to by header. ++ */ ++ ++ ea_idebug(inode, "name=%d.%s, value=%p, value_len=%ld", ++ name_index, name, value, (long)value_len); ++ ++ if (IS_RDONLY(inode)) ++ return -EROFS; ++ if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) ++ return -EPERM; ++ if (value == NULL) ++ value_len = 0; ++ if (name == NULL) ++ return -EINVAL; ++ name_len = strlen(name); ++ if (name_len > 255 || value_len > sb->s_blocksize) ++ return -ERANGE; ++ down(&ext3_xattr_sem); ++ ++ if (block) { ++ /* The inode already has an extended attribute block. */ ++ bh = sb_bread(sb, block); ++ error = -EIO; ++ if (!bh) ++ goto cleanup; ++ ea_bdebug(bh, "b_count=%d, refcount=%d", ++ atomic_read(&(bh->b_count)), ++ le32_to_cpu(HDR(bh)->h_refcount)); ++ header = HDR(bh); ++ end = bh->b_data + bh->b_size; ++ if (header->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) || ++ header->h_blocks != cpu_to_le32(1)) { ++bad_block: ext3_error(sb, "ext3_xattr_set", ++ "inode %ld: bad block %d", inode->i_ino, block); ++ error = -EIO; ++ goto cleanup; ++ } ++ /* Find the named attribute. */ ++ here = FIRST_ENTRY(bh); ++ while (!IS_LAST_ENTRY(here)) { ++ struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(here); ++ if ((char *)next >= end) ++ goto bad_block; ++ if (!here->e_value_block && here->e_value_size) { ++ int offs = le16_to_cpu(here->e_value_offs); ++ if (offs < min_offs) ++ min_offs = offs; ++ } ++ not_found = name_index - here->e_name_index; ++ if (!not_found) ++ not_found = name_len - here->e_name_len; ++ if (!not_found) ++ not_found = memcmp(name, here->e_name,name_len); ++ if (not_found <= 0) ++ break; ++ here = next; ++ } ++ last = here; ++ /* We still need to compute min_offs and last. */ ++ while (!IS_LAST_ENTRY(last)) { ++ struct ext3_xattr_entry *next = EXT3_XATTR_NEXT(last); ++ if ((char *)next >= end) ++ goto bad_block; ++ if (!last->e_value_block && last->e_value_size) { ++ int offs = le16_to_cpu(last->e_value_offs); ++ if (offs < min_offs) ++ min_offs = offs; ++ } ++ last = next; ++ } ++ ++ /* Check whether we have enough space left. */ ++ free = min_offs - ((char*)last - (char*)header) - sizeof(__u32); ++ } else { ++ /* We will use a new extended attribute block. */ ++ free = sb->s_blocksize - ++ sizeof(struct ext3_xattr_header) - sizeof(__u32); ++ here = last = NULL; /* avoid gcc uninitialized warning. */ ++ } ++ ++ if (not_found) { ++ /* Request to remove a nonexistent attribute? */ ++ error = -ENOATTR; ++ if (flags & XATTR_REPLACE) ++ goto cleanup; ++ error = 0; ++ if (value == NULL) ++ goto cleanup; ++ else ++ free -= EXT3_XATTR_LEN(name_len); ++ } else { ++ /* Request to create an existing attribute? */ ++ error = -EEXIST; ++ if (flags & XATTR_CREATE) ++ goto cleanup; ++ if (!here->e_value_block && here->e_value_size) { ++ unsigned int size = le32_to_cpu(here->e_value_size); ++ ++ if (le16_to_cpu(here->e_value_offs) + size > ++ sb->s_blocksize || size > sb->s_blocksize) ++ goto bad_block; ++ free += EXT3_XATTR_SIZE(size); ++ } ++ } ++ free -= EXT3_XATTR_SIZE(value_len); ++ error = -ENOSPC; ++ if (free < 0) ++ goto cleanup; ++ ++ /* Here we know that we can set the new attribute. */ ++ ++ if (header) { ++ if (header->h_refcount == cpu_to_le32(1)) { ++ ea_bdebug(bh, "modifying in-place"); ++ ext3_xattr_cache_remove(bh); ++ error = ext3_journal_get_write_access(handle, bh); ++ if (error) ++ goto cleanup; ++ } else { ++ int offset; ++ ++ ea_bdebug(bh, "cloning"); ++ header = kmalloc(bh->b_size, GFP_KERNEL); ++ error = -ENOMEM; ++ if (header == NULL) ++ goto cleanup; ++ memcpy(header, HDR(bh), bh->b_size); ++ header->h_refcount = cpu_to_le32(1); ++ offset = (char *)header - bh->b_data; ++ here = ENTRY((char *)here + offset); ++ last = ENTRY((char *)last + offset); ++ } ++ } else { ++ /* Allocate a buffer where we construct the new block. */ ++ header = kmalloc(sb->s_blocksize, GFP_KERNEL); ++ error = -ENOMEM; ++ if (header == NULL) ++ goto cleanup; ++ memset(header, 0, sb->s_blocksize); ++ end = (char *)header + sb->s_blocksize; ++ header->h_magic = cpu_to_le32(EXT3_XATTR_MAGIC); ++ header->h_blocks = header->h_refcount = cpu_to_le32(1); ++ last = here = ENTRY(header+1); ++ } ++ ++ if (not_found) { ++ /* Insert the new name. */ ++ int size = EXT3_XATTR_LEN(name_len); ++ int rest = (char *)last - (char *)here; ++ memmove((char *)here + size, here, rest); ++ memset(here, 0, size); ++ here->e_name_index = name_index; ++ here->e_name_len = name_len; ++ memcpy(here->e_name, name, name_len); ++ } else { ++ /* Remove the old value. */ ++ if (!here->e_value_block && here->e_value_size) { ++ char *first_val = (char *)header + min_offs; ++ int offs = le16_to_cpu(here->e_value_offs); ++ char *val = (char *)header + offs; ++ size_t size = EXT3_XATTR_SIZE( ++ le32_to_cpu(here->e_value_size)); ++ memmove(first_val + size, first_val, val - first_val); ++ memset(first_val, 0, size); ++ here->e_value_offs = 0; ++ min_offs += size; ++ ++ /* Adjust all value offsets. */ ++ last = ENTRY(header+1); ++ while (!IS_LAST_ENTRY(last)) { ++ int o = le16_to_cpu(last->e_value_offs); ++ if (!last->e_value_block && o < offs) ++ last->e_value_offs = ++ cpu_to_le16(o + size); ++ last = EXT3_XATTR_NEXT(last); ++ } ++ } ++ if (value == NULL) { ++ /* Remove this attribute. */ ++ if (EXT3_XATTR_NEXT(ENTRY(header+1)) == last) { ++ /* This block is now empty. */ ++ error = ext3_xattr_set2(handle, inode, bh,NULL); ++ goto cleanup; ++ } else { ++ /* Remove the old name. */ ++ int size = EXT3_XATTR_LEN(name_len); ++ last = ENTRY((char *)last - size); ++ memmove(here, (char*)here + size, ++ (char*)last - (char*)here); ++ memset(last, 0, size); ++ } ++ } ++ } ++ ++ if (value != NULL) { ++ /* Insert the new value. */ ++ here->e_value_size = cpu_to_le32(value_len); ++ if (value_len) { ++ size_t size = EXT3_XATTR_SIZE(value_len); ++ char *val = (char *)header + min_offs - size; ++ here->e_value_offs = ++ cpu_to_le16((char *)val - (char *)header); ++ memset(val + size - EXT3_XATTR_PAD, 0, ++ EXT3_XATTR_PAD); /* Clear the pad bytes. */ ++ memcpy(val, value, value_len); ++ } ++ } ++ ext3_xattr_rehash(header, here); ++ ++ error = ext3_xattr_set2(handle, inode, bh, header); ++ ++cleanup: ++ brelse(bh); ++ if (!(bh && header == HDR(bh))) ++ kfree(header); ++ up(&ext3_xattr_sem); ++ ++ return error; ++} ++ ++/* ++ * Second half of ext3_xattr_set(): Update the file system. ++ */ ++static int ++ext3_xattr_set2(handle_t *handle, struct inode *inode, ++ struct buffer_head *old_bh, struct ext3_xattr_header *header) ++{ ++ struct super_block *sb = inode->i_sb; ++ struct buffer_head *new_bh = NULL; ++ int error; ++ ++ if (header) { ++ new_bh = ext3_xattr_cache_find(inode, header); ++ if (new_bh) { ++ /* ++ * We found an identical block in the cache. ++ * The old block will be released after updating ++ * the inode. ++ */ ++ ea_bdebug(old_bh, "reusing block %ld", ++ new_bh->b_blocknr); ++ ++ error = -EDQUOT; ++ if (ext3_xattr_quota_alloc(inode, 1)) ++ goto cleanup; ++ ++ error = ext3_journal_get_write_access(handle, new_bh); ++ if (error) ++ goto cleanup; ++ HDR(new_bh)->h_refcount = cpu_to_le32( ++ le32_to_cpu(HDR(new_bh)->h_refcount) + 1); ++ ea_bdebug(new_bh, "refcount now=%d", ++ le32_to_cpu(HDR(new_bh)->h_refcount)); ++ } else if (old_bh && header == HDR(old_bh)) { ++ /* Keep this block. */ ++ new_bh = old_bh; ++ ext3_xattr_cache_insert(new_bh); ++ } else { ++ /* We need to allocate a new block */ ++ int force = EXT3_I(inode)->i_file_acl != 0; ++ int block = ext3_xattr_new_block(handle, inode, ++ &error, force); ++ if (error) ++ goto cleanup; ++ ea_idebug(inode, "creating block %d", block); ++ ++ new_bh = sb_getblk(sb, block); ++ if (!new_bh) { ++getblk_failed: ext3_xattr_free_block(handle, inode, block); ++ error = -EIO; ++ goto cleanup; ++ } ++ lock_buffer(new_bh); ++ error = ext3_journal_get_create_access(handle, new_bh); ++ if (error) { ++ unlock_buffer(new_bh); ++ goto getblk_failed; ++ } ++ memcpy(new_bh->b_data, header, new_bh->b_size); ++ mark_buffer_uptodate(new_bh, 1); ++ unlock_buffer(new_bh); ++ ext3_xattr_cache_insert(new_bh); ++ ++ ext3_xattr_update_super_block(handle, sb); ++ } ++ error = ext3_journal_dirty_metadata(handle, new_bh); ++ if (error) ++ goto cleanup; ++ } ++ ++ /* Update the inode. */ ++ EXT3_I(inode)->i_file_acl = new_bh ? new_bh->b_blocknr : 0; ++ inode->i_ctime = CURRENT_TIME; ++ ext3_mark_inode_dirty(handle, inode); ++ if (IS_SYNC(inode)) ++ handle->h_sync = 1; ++ ++ error = 0; ++ if (old_bh && old_bh != new_bh) { ++ /* ++ * If there was an old block, and we are not still using it, ++ * we now release the old block. ++ */ ++ unsigned int refcount = le32_to_cpu(HDR(old_bh)->h_refcount); ++ ++ error = ext3_journal_get_write_access(handle, old_bh); ++ if (error) ++ goto cleanup; ++ if (refcount == 1) { ++ /* Free the old block. */ ++ ea_bdebug(old_bh, "freeing"); ++ ext3_xattr_free_block(handle, inode, old_bh->b_blocknr); ++ ++ /* ext3_forget() calls bforget() for us, but we ++ let our caller release old_bh, so we need to ++ duplicate the handle before. */ ++ get_bh(old_bh); ++ ext3_forget(handle, 1, inode, old_bh,old_bh->b_blocknr); ++ } else { ++ /* Decrement the refcount only. */ ++ refcount--; ++ HDR(old_bh)->h_refcount = cpu_to_le32(refcount); ++ ext3_xattr_quota_free(inode); ++ ext3_journal_dirty_metadata(handle, old_bh); ++ ea_bdebug(old_bh, "refcount now=%d", refcount); ++ } ++ } ++ ++cleanup: ++ if (old_bh != new_bh) ++ brelse(new_bh); ++ ++ return error; ++} ++ ++/* ++ * ext3_xattr_delete_inode() ++ * ++ * Free extended attribute resources associated with this inode. This ++ * is called immediately before an inode is freed. ++ */ ++void ++ext3_xattr_delete_inode(handle_t *handle, struct inode *inode) ++{ ++ struct buffer_head *bh; ++ unsigned int block = EXT3_I(inode)->i_file_acl; ++ ++ if (!block) ++ return; ++ down(&ext3_xattr_sem); ++ ++ bh = sb_bread(inode->i_sb, block); ++ if (!bh) { ++ ext3_error(inode->i_sb, "ext3_xattr_delete_inode", ++ "inode %ld: block %d read error", inode->i_ino, block); ++ goto cleanup; ++ } ++ ea_bdebug(bh, "b_count=%d", atomic_read(&(bh->b_count))); ++ if (HDR(bh)->h_magic != cpu_to_le32(EXT3_XATTR_MAGIC) || ++ HDR(bh)->h_blocks != cpu_to_le32(1)) { ++ ext3_error(inode->i_sb, "ext3_xattr_delete_inode", ++ "inode %ld: bad block %d", inode->i_ino, block); ++ goto cleanup; ++ } ++ ext3_journal_get_write_access(handle, bh); ++ ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1); ++ if (HDR(bh)->h_refcount == cpu_to_le32(1)) { ++ ext3_xattr_cache_remove(bh); ++ ext3_xattr_free_block(handle, inode, block); ++ ext3_forget(handle, 1, inode, bh, block); ++ bh = NULL; ++ } else { ++ HDR(bh)->h_refcount = cpu_to_le32( ++ le32_to_cpu(HDR(bh)->h_refcount) - 1); ++ ext3_journal_dirty_metadata(handle, bh); ++ if (IS_SYNC(inode)) ++ handle->h_sync = 1; ++ ext3_xattr_quota_free(inode); ++ } ++ EXT3_I(inode)->i_file_acl = 0; ++ ++cleanup: ++ brelse(bh); ++ up(&ext3_xattr_sem); ++} ++ ++/* ++ * ext3_xattr_put_super() ++ * ++ * This is called when a file system is unmounted. ++ */ ++void ++ext3_xattr_put_super(struct super_block *sb) ++{ ++#ifdef CONFIG_EXT3_FS_XATTR_SHARING ++ mb_cache_shrink(ext3_xattr_cache, sb->s_dev); ++#endif ++} ++ ++#ifdef CONFIG_EXT3_FS_XATTR_SHARING ++ ++/* ++ * ext3_xattr_cache_insert() ++ * ++ * Create a new entry in the extended attribute cache, and insert ++ * it unless such an entry is already in the cache. ++ * ++ * Returns 0, or a negative error number on failure. ++ */ ++static int ++ext3_xattr_cache_insert(struct buffer_head *bh) ++{ ++ __u32 hash = le32_to_cpu(HDR(bh)->h_hash); ++ struct mb_cache_entry *ce; ++ int error; ++ ++ ce = mb_cache_entry_alloc(ext3_xattr_cache); ++ if (!ce) ++ return -ENOMEM; ++ error = mb_cache_entry_insert(ce, bh->b_dev, bh->b_blocknr, &hash); ++ if (error) { ++ mb_cache_entry_free(ce); ++ if (error == -EBUSY) { ++ ea_bdebug(bh, "already in cache (%d cache entries)", ++ atomic_read(&ext3_xattr_cache->c_entry_count)); ++ error = 0; ++ } ++ } else { ++ ea_bdebug(bh, "inserting [%x] (%d cache entries)", (int)hash, ++ atomic_read(&ext3_xattr_cache->c_entry_count)); ++ mb_cache_entry_release(ce); ++ } ++ return error; ++} ++ ++/* ++ * ext3_xattr_cmp() ++ * ++ * Compare two extended attribute blocks for equality. ++ * ++ * Returns 0 if the blocks are equal, 1 if they differ, and ++ * a negative error number on errors. ++ */ ++static int ++ext3_xattr_cmp(struct ext3_xattr_header *header1, ++ struct ext3_xattr_header *header2) ++{ ++ struct ext3_xattr_entry *entry1, *entry2; ++ ++ entry1 = ENTRY(header1+1); ++ entry2 = ENTRY(header2+1); ++ while (!IS_LAST_ENTRY(entry1)) { ++ if (IS_LAST_ENTRY(entry2)) ++ return 1; ++ if (entry1->e_hash != entry2->e_hash || ++ entry1->e_name_len != entry2->e_name_len || ++ entry1->e_value_size != entry2->e_value_size || ++ memcmp(entry1->e_name, entry2->e_name, entry1->e_name_len)) ++ return 1; ++ if (entry1->e_value_block != 0 || entry2->e_value_block != 0) ++ return -EIO; ++ if (memcmp((char *)header1 + le16_to_cpu(entry1->e_value_offs), ++ (char *)header2 + le16_to_cpu(entry2->e_value_offs), ++ le32_to_cpu(entry1->e_value_size))) ++ return 1; ++ ++ entry1 = EXT3_XATTR_NEXT(entry1); ++ entry2 = EXT3_XATTR_NEXT(entry2); ++ } ++ if (!IS_LAST_ENTRY(entry2)) ++ return 1; ++ return 0; ++} ++ ++/* ++ * ext3_xattr_cache_find() ++ * ++ * Find an identical extended attribute block. ++ * ++ * Returns a pointer to the block found, or NULL if such a block was ++ * not found or an error occurred. ++ */ ++static struct buffer_head * ++ext3_xattr_cache_find(struct inode *inode, struct ext3_xattr_header *header) ++{ ++ __u32 hash = le32_to_cpu(header->h_hash); ++ struct mb_cache_entry *ce; ++ ++ if (!header->h_hash) ++ return NULL; /* never share */ ++ ea_idebug(inode, "looking for cached blocks [%x]", (int)hash); ++ ce = mb_cache_entry_find_first(ext3_xattr_cache, 0, inode->i_dev, hash); ++ while (ce) { ++ struct buffer_head *bh = sb_bread(inode->i_sb, ce->e_block); ++ ++ if (!bh) { ++ ext3_error(inode->i_sb, "ext3_xattr_cache_find", ++ "inode %ld: block %ld read error", ++ inode->i_ino, ce->e_block); ++ } else if (le32_to_cpu(HDR(bh)->h_refcount) > ++ EXT3_XATTR_REFCOUNT_MAX) { ++ ea_idebug(inode, "block %ld refcount %d>%d",ce->e_block, ++ le32_to_cpu(HDR(bh)->h_refcount), ++ EXT3_XATTR_REFCOUNT_MAX); ++ } else if (!ext3_xattr_cmp(header, HDR(bh))) { ++ ea_bdebug(bh, "b_count=%d",atomic_read(&(bh->b_count))); ++ mb_cache_entry_release(ce); ++ return bh; ++ } ++ brelse(bh); ++ ce = mb_cache_entry_find_next(ce, 0, inode->i_dev, hash); ++ } ++ return NULL; ++} ++ ++/* ++ * ext3_xattr_cache_remove() ++ * ++ * Remove the cache entry of a block from the cache. Called when a ++ * block becomes invalid. ++ */ ++static void ++ext3_xattr_cache_remove(struct buffer_head *bh) ++{ ++ struct mb_cache_entry *ce; ++ ++ ce = mb_cache_entry_get(ext3_xattr_cache, bh->b_dev, bh->b_blocknr); ++ if (ce) { ++ ea_bdebug(bh, "removing (%d cache entries remaining)", ++ atomic_read(&ext3_xattr_cache->c_entry_count)-1); ++ mb_cache_entry_free(ce); ++ } else ++ ea_bdebug(bh, "no cache entry"); ++} ++ ++#define NAME_HASH_SHIFT 5 ++#define VALUE_HASH_SHIFT 16 ++ ++/* ++ * ext3_xattr_hash_entry() ++ * ++ * Compute the hash of an extended attribute. ++ */ ++static inline void ext3_xattr_hash_entry(struct ext3_xattr_header *header, ++ struct ext3_xattr_entry *entry) ++{ ++ __u32 hash = 0; ++ char *name = entry->e_name; ++ int n; ++ ++ for (n=0; n < entry->e_name_len; n++) { ++ hash = (hash << NAME_HASH_SHIFT) ^ ++ (hash >> (8*sizeof(hash) - NAME_HASH_SHIFT)) ^ ++ *name++; ++ } ++ ++ if (entry->e_value_block == 0 && entry->e_value_size != 0) { ++ __u32 *value = (__u32 *)((char *)header + ++ le16_to_cpu(entry->e_value_offs)); ++ for (n = (le32_to_cpu(entry->e_value_size) + ++ EXT3_XATTR_ROUND) >> EXT3_XATTR_PAD_BITS; n; n--) { ++ hash = (hash << VALUE_HASH_SHIFT) ^ ++ (hash >> (8*sizeof(hash) - VALUE_HASH_SHIFT)) ^ ++ le32_to_cpu(*value++); ++ } ++ } ++ entry->e_hash = cpu_to_le32(hash); ++} ++ ++#undef NAME_HASH_SHIFT ++#undef VALUE_HASH_SHIFT ++ ++#define BLOCK_HASH_SHIFT 16 ++ ++/* ++ * ext3_xattr_rehash() ++ * ++ * Re-compute the extended attribute hash value after an entry has changed. ++ */ ++static void ext3_xattr_rehash(struct ext3_xattr_header *header, ++ struct ext3_xattr_entry *entry) ++{ ++ struct ext3_xattr_entry *here; ++ __u32 hash = 0; ++ ++ ext3_xattr_hash_entry(header, entry); ++ here = ENTRY(header+1); ++ while (!IS_LAST_ENTRY(here)) { ++ if (!here->e_hash) { ++ /* Block is not shared if an entry's hash value == 0 */ ++ hash = 0; ++ break; ++ } ++ hash = (hash << BLOCK_HASH_SHIFT) ^ ++ (hash >> (8*sizeof(hash) - BLOCK_HASH_SHIFT)) ^ ++ le32_to_cpu(here->e_hash); ++ here = EXT3_XATTR_NEXT(here); ++ } ++ header->h_hash = cpu_to_le32(hash); ++} ++ ++#undef BLOCK_HASH_SHIFT ++ ++int __init ++init_ext3_xattr(void) ++{ ++ ext3_xattr_cache = mb_cache_create("ext3_xattr", NULL, ++ sizeof(struct mb_cache_entry) + ++ sizeof(struct mb_cache_entry_index), 1, 61); ++ if (!ext3_xattr_cache) ++ return -ENOMEM; ++ ++ return 0; ++} ++ ++void ++exit_ext3_xattr(void) ++{ ++ if (ext3_xattr_cache) ++ mb_cache_destroy(ext3_xattr_cache); ++ ext3_xattr_cache = NULL; ++} ++ ++#else /* CONFIG_EXT3_FS_XATTR_SHARING */ ++ ++int __init ++init_ext3_xattr(void) ++{ ++ return 0; ++} ++ ++void ++exit_ext3_xattr(void) ++{ ++} ++ ++#endif /* CONFIG_EXT3_FS_XATTR_SHARING */ +Index: linux-2.4.24-vanilla/fs/ext3/xattr_user.c +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/ext3/xattr_user.c 2003-01-30 13:24:37.000000000 +0300 ++++ linux-2.4.24-vanilla/fs/ext3/xattr_user.c 2004-01-10 17:20:28.000000000 +0300 +@@ -0,0 +1,111 @@ ++/* ++ * linux/fs/ext3/xattr_user.c ++ * Handler for extended user attributes. ++ * ++ * Copyright (C) 2001 by Andreas Gruenbacher, ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#ifdef CONFIG_EXT3_FS_POSIX_ACL ++# include ++#endif ++ ++#define XATTR_USER_PREFIX "user." ++ ++static size_t ++ext3_xattr_user_list(char *list, struct inode *inode, ++ const char *name, int name_len) ++{ ++ const int prefix_len = sizeof(XATTR_USER_PREFIX)-1; ++ ++ if (!test_opt(inode->i_sb, XATTR_USER)) ++ return 0; ++ ++ if (list) { ++ memcpy(list, XATTR_USER_PREFIX, prefix_len); ++ memcpy(list+prefix_len, name, name_len); ++ list[prefix_len + name_len] = '\0'; ++ } ++ return prefix_len + name_len + 1; ++} ++ ++static int ++ext3_xattr_user_get(struct inode *inode, const char *name, ++ void *buffer, size_t size) ++{ ++ int error; ++ ++ if (strcmp(name, "") == 0) ++ return -EINVAL; ++ if (!test_opt(inode->i_sb, XATTR_USER)) ++ return -ENOTSUP; ++#ifdef CONFIG_EXT3_FS_POSIX_ACL ++ error = ext3_permission_locked(inode, MAY_READ); ++#else ++ error = permission(inode, MAY_READ); ++#endif ++ if (error) ++ return error; ++ ++ return ext3_xattr_get(inode, EXT3_XATTR_INDEX_USER, name, ++ buffer, size); ++} ++ ++static int ++ext3_xattr_user_set(struct inode *inode, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ handle_t *handle; ++ int error; ++ ++ if (strcmp(name, "") == 0) ++ return -EINVAL; ++ if (!test_opt(inode->i_sb, XATTR_USER)) ++ return -ENOTSUP; ++ if ( !S_ISREG(inode->i_mode) && ++ (!S_ISDIR(inode->i_mode) || inode->i_mode & S_ISVTX)) ++ return -EPERM; ++#ifdef CONFIG_EXT3_FS_POSIX_ACL ++ error = ext3_permission_locked(inode, MAY_WRITE); ++#else ++ error = permission(inode, MAY_WRITE); ++#endif ++ if (error) ++ return error; ++ ++ handle = ext3_journal_start(inode, EXT3_XATTR_TRANS_BLOCKS); ++ if (IS_ERR(handle)) ++ return PTR_ERR(handle); ++ error = ext3_xattr_set(handle, inode, EXT3_XATTR_INDEX_USER, name, ++ value, size, flags); ++ ext3_journal_stop(handle, inode); ++ ++ return error; ++} ++ ++struct ext3_xattr_handler ext3_xattr_user_handler = { ++ prefix: XATTR_USER_PREFIX, ++ list: ext3_xattr_user_list, ++ get: ext3_xattr_user_get, ++ set: ext3_xattr_user_set, ++}; ++ ++int __init ++init_ext3_xattr_user(void) ++{ ++ return ext3_xattr_register(EXT3_XATTR_INDEX_USER, ++ &ext3_xattr_user_handler); ++} ++ ++void ++exit_ext3_xattr_user(void) ++{ ++ ext3_xattr_unregister(EXT3_XATTR_INDEX_USER, ++ &ext3_xattr_user_handler); ++} +Index: linux-2.4.24-vanilla/fs/ext3/ext3-exports.c +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/ext3/ext3-exports.c 2003-01-30 13:24:37.000000000 +0300 ++++ linux-2.4.24-vanilla/fs/ext3/ext3-exports.c 2004-01-10 17:20:28.000000000 +0300 +@@ -0,0 +1,13 @@ ++#include ++#include ++#include ++#include ++#include ++ ++EXPORT_SYMBOL(ext3_force_commit); ++EXPORT_SYMBOL(ext3_bread); ++EXPORT_SYMBOL(ext3_xattr_register); ++EXPORT_SYMBOL(ext3_xattr_unregister); ++EXPORT_SYMBOL(ext3_xattr_get); ++EXPORT_SYMBOL(ext3_xattr_list); ++EXPORT_SYMBOL(ext3_xattr_set); +Index: linux-2.4.24-vanilla/fs/jfs/jfs_xattr.h +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/jfs/jfs_xattr.h 2003-05-16 05:29:12.000000000 +0400 ++++ linux-2.4.24-vanilla/fs/jfs/jfs_xattr.h 2004-01-10 17:20:28.000000000 +0300 +@@ -52,8 +52,10 @@ + #define END_EALIST(ealist) \ + ((struct jfs_ea *) (((char *) (ealist)) + EALIST_SIZE(ealist))) + +-extern int __jfs_setxattr(struct inode *, const char *, void *, size_t, int); +-extern int jfs_setxattr(struct dentry *, const char *, void *, size_t, int); ++extern int __jfs_setxattr(struct inode *, const char *, const void *, size_t, ++ int); ++extern int jfs_setxattr(struct dentry *, const char *, const void *, size_t, ++ int); + extern ssize_t __jfs_getxattr(struct inode *, const char *, void *, size_t); + extern ssize_t jfs_getxattr(struct dentry *, const char *, void *, size_t); + extern ssize_t jfs_listxattr(struct dentry *, char *, size_t); +Index: linux-2.4.24-vanilla/fs/jfs/xattr.c +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/jfs/xattr.c 2004-01-10 17:05:55.000000000 +0300 ++++ linux-2.4.24-vanilla/fs/jfs/xattr.c 2004-01-10 17:20:28.000000000 +0300 +@@ -648,7 +648,7 @@ + } + + static int can_set_xattr(struct inode *inode, const char *name, +- void *value, size_t value_len) ++ const void *value, size_t value_len) + { + if (IS_RDONLY(inode)) + return -EROFS; +@@ -667,7 +667,7 @@ + return permission(inode, MAY_WRITE); + } + +-int __jfs_setxattr(struct inode *inode, const char *name, void *value, ++int __jfs_setxattr(struct inode *inode, const char *name, const void *value, + size_t value_len, int flags) + { + struct jfs_ea_list *ealist; +@@ -806,7 +806,7 @@ + return rc; + } + +-int jfs_setxattr(struct dentry *dentry, const char *name, void *value, ++int jfs_setxattr(struct dentry *dentry, const char *name, const void *value, + size_t value_len, int flags) + { + if (value == NULL) { /* empty EA, do not remove */ +Index: linux-2.4.24-vanilla/fs/mbcache.c +=================================================================== +--- linux-2.4.24-vanilla.orig/fs/mbcache.c 2003-01-30 13:24:37.000000000 +0300 ++++ linux-2.4.24-vanilla/fs/mbcache.c 2004-01-10 17:20:28.000000000 +0300 +@@ -0,0 +1,648 @@ ++/* ++ * linux/fs/mbcache.c ++ * (C) 2001-2002 Andreas Gruenbacher, ++ */ ++ ++/* ++ * Filesystem Meta Information Block Cache (mbcache) ++ * ++ * The mbcache caches blocks of block devices that need to be located ++ * by their device/block number, as well as by other criteria (such ++ * as the block's contents). ++ * ++ * There can only be one cache entry in a cache per device and block number. ++ * Additional indexes need not be unique in this sense. The number of ++ * additional indexes (=other criteria) can be hardwired at compile time ++ * or specified at cache create time. ++ * ++ * Each cache entry is of fixed size. An entry may be `valid' or `invalid' ++ * in the cache. A valid entry is in the main hash tables of the cache, ++ * and may also be in the lru list. An invalid entry is not in any hashes ++ * or lists. ++ * ++ * A valid cache entry is only in the lru list if no handles refer to it. ++ * Invalid cache entries will be freed when the last handle to the cache ++ * entry is released. Entries that cannot be freed immediately are put ++ * back on the lru list. ++ */ ++ ++#include ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++ ++#ifdef MB_CACHE_DEBUG ++# define mb_debug(f...) do { \ ++ printk(KERN_DEBUG f); \ ++ printk("\n"); \ ++ } while (0) ++#define mb_assert(c) do { if (!(c)) \ ++ printk(KERN_ERR "assertion " #c " failed\n"); \ ++ } while(0) ++#else ++# define mb_debug(f...) do { } while(0) ++# define mb_assert(c) do { } while(0) ++#endif ++#define mb_error(f...) do { \ ++ printk(KERN_ERR f); \ ++ printk("\n"); \ ++ } while(0) ++ ++MODULE_AUTHOR("Andreas Gruenbacher "); ++MODULE_DESCRIPTION("Meta block cache (for extended attributes)"); ++#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) ++MODULE_LICENSE("GPL"); ++#endif ++ ++EXPORT_SYMBOL(mb_cache_create); ++EXPORT_SYMBOL(mb_cache_shrink); ++EXPORT_SYMBOL(mb_cache_destroy); ++EXPORT_SYMBOL(mb_cache_entry_alloc); ++EXPORT_SYMBOL(mb_cache_entry_insert); ++EXPORT_SYMBOL(mb_cache_entry_release); ++EXPORT_SYMBOL(mb_cache_entry_takeout); ++EXPORT_SYMBOL(mb_cache_entry_free); ++EXPORT_SYMBOL(mb_cache_entry_dup); ++EXPORT_SYMBOL(mb_cache_entry_get); ++#if !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0) ++EXPORT_SYMBOL(mb_cache_entry_find_first); ++EXPORT_SYMBOL(mb_cache_entry_find_next); ++#endif ++ ++ ++/* ++ * Global data: list of all mbcache's, lru list, and a spinlock for ++ * accessing cache data structures on SMP machines. The lru list is ++ * global across all mbcaches. ++ */ ++ ++static LIST_HEAD(mb_cache_list); ++static LIST_HEAD(mb_cache_lru_list); ++static spinlock_t mb_cache_spinlock = SPIN_LOCK_UNLOCKED; ++ ++static inline int ++mb_cache_indexes(struct mb_cache *cache) ++{ ++#ifdef MB_CACHE_INDEXES_COUNT ++ return MB_CACHE_INDEXES_COUNT; ++#else ++ return cache->c_indexes_count; ++#endif ++} ++ ++/* ++ * What the mbcache registers as to get shrunk dynamically. ++ */ ++ ++static void ++mb_cache_memory_pressure(int priority, unsigned int gfp_mask); ++ ++static struct cache_definition mb_cache_definition = { ++ "mb_cache", ++ mb_cache_memory_pressure ++}; ++ ++ ++static inline int ++__mb_cache_entry_is_hashed(struct mb_cache_entry *ce) ++{ ++ return !list_empty(&ce->e_block_list); ++} ++ ++ ++static inline void ++__mb_cache_entry_unhash(struct mb_cache_entry *ce) ++{ ++ int n; ++ ++ if (__mb_cache_entry_is_hashed(ce)) { ++ list_del_init(&ce->e_block_list); ++ for (n=0; ne_cache); n++) ++ list_del(&ce->e_indexes[n].o_list); ++ } ++} ++ ++ ++static inline void ++__mb_cache_entry_forget(struct mb_cache_entry *ce, int gfp_mask) ++{ ++ struct mb_cache *cache = ce->e_cache; ++ ++ mb_assert(atomic_read(&ce->e_used) == 0); ++ if (cache->c_op.free && cache->c_op.free(ce, gfp_mask)) { ++ /* free failed -- put back on the lru list ++ for freeing later. */ ++ spin_lock(&mb_cache_spinlock); ++ list_add(&ce->e_lru_list, &mb_cache_lru_list); ++ spin_unlock(&mb_cache_spinlock); ++ } else { ++ kmem_cache_free(cache->c_entry_cache, ce); ++ atomic_dec(&cache->c_entry_count); ++ } ++} ++ ++ ++static inline void ++__mb_cache_entry_release_unlock(struct mb_cache_entry *ce) ++{ ++ if (atomic_dec_and_test(&ce->e_used)) { ++ if (__mb_cache_entry_is_hashed(ce)) ++ list_add_tail(&ce->e_lru_list, &mb_cache_lru_list); ++ else { ++ spin_unlock(&mb_cache_spinlock); ++ __mb_cache_entry_forget(ce, GFP_KERNEL); ++ return; ++ } ++ } ++ spin_unlock(&mb_cache_spinlock); ++} ++ ++ ++/* ++ * mb_cache_memory_pressure() memory pressure callback ++ * ++ * This function is called by the kernel memory management when memory ++ * gets low. ++ * ++ * @priority: Amount by which to shrink the cache (0 = highes priority) ++ * @gfp_mask: (ignored) ++ */ ++static void ++mb_cache_memory_pressure(int priority, unsigned int gfp_mask) ++{ ++ LIST_HEAD(free_list); ++ struct list_head *l, *ltmp; ++ int count = 0; ++ ++ spin_lock(&mb_cache_spinlock); ++ list_for_each(l, &mb_cache_list) { ++ struct mb_cache *cache = ++ list_entry(l, struct mb_cache, c_cache_list); ++ mb_debug("cache %s (%d)", cache->c_name, ++ atomic_read(&cache->c_entry_count)); ++ count += atomic_read(&cache->c_entry_count); ++ } ++ mb_debug("trying to free %d of %d entries", ++ count / (priority ? priority : 1), count); ++ if (priority) ++ count /= priority; ++ while (count-- && !list_empty(&mb_cache_lru_list)) { ++ struct mb_cache_entry *ce = ++ list_entry(mb_cache_lru_list.next, ++ struct mb_cache_entry, e_lru_list); ++ list_del(&ce->e_lru_list); ++ __mb_cache_entry_unhash(ce); ++ list_add_tail(&ce->e_lru_list, &free_list); ++ } ++ spin_unlock(&mb_cache_spinlock); ++ list_for_each_safe(l, ltmp, &free_list) { ++ __mb_cache_entry_forget(list_entry(l, struct mb_cache_entry, ++ e_lru_list), gfp_mask); ++ } ++} ++ ++ ++/* ++ * mb_cache_create() create a new cache ++ * ++ * All entries in one cache are equal size. Cache entries may be from ++ * multiple devices. If this is the first mbcache created, registers ++ * the cache with kernel memory management. Returns NULL if no more ++ * memory was available. ++ * ++ * @name: name of the cache (informal) ++ * @cache_op: contains the callback called when freeing a cache entry ++ * @entry_size: The size of a cache entry, including ++ * struct mb_cache_entry ++ * @indexes_count: number of additional indexes in the cache. Must equal ++ * MB_CACHE_INDEXES_COUNT if the number of indexes is ++ * hardwired. ++ * @bucket_count: number of hash buckets ++ */ ++struct mb_cache * ++mb_cache_create(const char *name, struct mb_cache_op *cache_op, ++ size_t entry_size, int indexes_count, int bucket_count) ++{ ++ int m=0, n; ++ struct mb_cache *cache = NULL; ++ ++ if(entry_size < sizeof(struct mb_cache_entry) + ++ indexes_count * sizeof(struct mb_cache_entry_index)) ++ return NULL; ++ ++ MOD_INC_USE_COUNT; ++ cache = kmalloc(sizeof(struct mb_cache) + ++ indexes_count * sizeof(struct list_head), GFP_KERNEL); ++ if (!cache) ++ goto fail; ++ cache->c_name = name; ++ cache->c_op.free = NULL; ++ if (cache_op) ++ cache->c_op.free = cache_op->free; ++ atomic_set(&cache->c_entry_count, 0); ++ cache->c_bucket_count = bucket_count; ++#ifdef MB_CACHE_INDEXES_COUNT ++ mb_assert(indexes_count == MB_CACHE_INDEXES_COUNT); ++#else ++ cache->c_indexes_count = indexes_count; ++#endif ++ cache->c_block_hash = kmalloc(bucket_count * sizeof(struct list_head), ++ GFP_KERNEL); ++ if (!cache->c_block_hash) ++ goto fail; ++ for (n=0; nc_block_hash[n]); ++ for (m=0; mc_indexes_hash[m] = kmalloc(bucket_count * ++ sizeof(struct list_head), ++ GFP_KERNEL); ++ if (!cache->c_indexes_hash[m]) ++ goto fail; ++ for (n=0; nc_indexes_hash[m][n]); ++ } ++ cache->c_entry_cache = kmem_cache_create(name, entry_size, 0, ++ 0 /*SLAB_POISON | SLAB_RED_ZONE*/, NULL, NULL); ++ if (!cache->c_entry_cache) ++ goto fail; ++ ++ spin_lock(&mb_cache_spinlock); ++ list_add(&cache->c_cache_list, &mb_cache_list); ++ spin_unlock(&mb_cache_spinlock); ++ return cache; ++ ++fail: ++ if (cache) { ++ while (--m >= 0) ++ kfree(cache->c_indexes_hash[m]); ++ if (cache->c_block_hash) ++ kfree(cache->c_block_hash); ++ kfree(cache); ++ } ++ MOD_DEC_USE_COUNT; ++ return NULL; ++} ++ ++ ++/* ++ * mb_cache_shrink() ++ * ++ * Removes all cache entires of a device from the cache. All cache entries ++ * currently in use cannot be freed, and thus remain in the cache. ++ * ++ * @cache: which cache to shrink ++ * @dev: which device's cache entries to shrink ++ */ ++void ++mb_cache_shrink(struct mb_cache *cache, kdev_t dev) ++{ ++ LIST_HEAD(free_list); ++ struct list_head *l, *ltmp; ++ ++ spin_lock(&mb_cache_spinlock); ++ list_for_each_safe(l, ltmp, &mb_cache_lru_list) { ++ struct mb_cache_entry *ce = ++ list_entry(l, struct mb_cache_entry, e_lru_list); ++ if (ce->e_dev == dev) { ++ list_del(&ce->e_lru_list); ++ list_add_tail(&ce->e_lru_list, &free_list); ++ __mb_cache_entry_unhash(ce); ++ } ++ } ++ spin_unlock(&mb_cache_spinlock); ++ list_for_each_safe(l, ltmp, &free_list) { ++ __mb_cache_entry_forget(list_entry(l, struct mb_cache_entry, ++ e_lru_list), GFP_KERNEL); ++ } ++} ++ ++ ++/* ++ * mb_cache_destroy() ++ * ++ * Shrinks the cache to its minimum possible size (hopefully 0 entries), ++ * and then destroys it. If this was the last mbcache, un-registers the ++ * mbcache from kernel memory management. ++ */ ++void ++mb_cache_destroy(struct mb_cache *cache) ++{ ++ LIST_HEAD(free_list); ++ struct list_head *l, *ltmp; ++ int n; ++ ++ spin_lock(&mb_cache_spinlock); ++ list_for_each_safe(l, ltmp, &mb_cache_lru_list) { ++ struct mb_cache_entry *ce = ++ list_entry(l, struct mb_cache_entry, e_lru_list); ++ if (ce->e_cache == cache) { ++ list_del(&ce->e_lru_list); ++ list_add_tail(&ce->e_lru_list, &free_list); ++ __mb_cache_entry_unhash(ce); ++ } ++ } ++ list_del(&cache->c_cache_list); ++ spin_unlock(&mb_cache_spinlock); ++ list_for_each_safe(l, ltmp, &free_list) { ++ __mb_cache_entry_forget(list_entry(l, struct mb_cache_entry, ++ e_lru_list), GFP_KERNEL); ++ } ++ ++ if (atomic_read(&cache->c_entry_count) > 0) { ++ mb_error("cache %s: %d orphaned entries", ++ cache->c_name, ++ atomic_read(&cache->c_entry_count)); ++ } ++ ++#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)) ++ /* We don't have kmem_cache_destroy() in 2.2.x */ ++ kmem_cache_shrink(cache->c_entry_cache); ++#else ++ kmem_cache_destroy(cache->c_entry_cache); ++#endif ++ for (n=0; n < mb_cache_indexes(cache); n++) ++ kfree(cache->c_indexes_hash[n]); ++ kfree(cache->c_block_hash); ++ kfree(cache); ++ ++ MOD_DEC_USE_COUNT; ++} ++ ++ ++/* ++ * mb_cache_entry_alloc() ++ * ++ * Allocates a new cache entry. The new entry will not be valid initially, ++ * and thus cannot be looked up yet. It should be filled with data, and ++ * then inserted into the cache using mb_cache_entry_insert(). Returns NULL ++ * if no more memory was available. ++ */ ++struct mb_cache_entry * ++mb_cache_entry_alloc(struct mb_cache *cache) ++{ ++ struct mb_cache_entry *ce; ++ ++ atomic_inc(&cache->c_entry_count); ++ ce = kmem_cache_alloc(cache->c_entry_cache, GFP_KERNEL); ++ if (ce) { ++ INIT_LIST_HEAD(&ce->e_lru_list); ++ INIT_LIST_HEAD(&ce->e_block_list); ++ ce->e_cache = cache; ++ atomic_set(&ce->e_used, 1); ++ } ++ return ce; ++} ++ ++ ++/* ++ * mb_cache_entry_insert() ++ * ++ * Inserts an entry that was allocated using mb_cache_entry_alloc() into ++ * the cache. After this, the cache entry can be looked up, but is not yet ++ * in the lru list as the caller still holds a handle to it. Returns 0 on ++ * success, or -EBUSY if a cache entry for that device + inode exists ++ * already (this may happen after a failed lookup, if another process has ++ * inserted the same cache entry in the meantime). ++ * ++ * @dev: device the cache entry belongs to ++ * @block: block number ++ * @keys: array of additional keys. There must be indexes_count entries ++ * in the array (as specified when creating the cache). ++ */ ++int ++mb_cache_entry_insert(struct mb_cache_entry *ce, kdev_t dev, ++ unsigned long block, unsigned int keys[]) ++{ ++ struct mb_cache *cache = ce->e_cache; ++ unsigned int bucket = (HASHDEV(dev) + block) % cache->c_bucket_count; ++ struct list_head *l; ++ int error = -EBUSY, n; ++ ++ spin_lock(&mb_cache_spinlock); ++ list_for_each(l, &cache->c_block_hash[bucket]) { ++ struct mb_cache_entry *ce = ++ list_entry(l, struct mb_cache_entry, e_block_list); ++ if (ce->e_dev == dev && ce->e_block == block) ++ goto out; ++ } ++ __mb_cache_entry_unhash(ce); ++ ce->e_dev = dev; ++ ce->e_block = block; ++ list_add(&ce->e_block_list, &cache->c_block_hash[bucket]); ++ for (n=0; ne_indexes[n].o_key = keys[n]; ++ bucket = keys[n] % cache->c_bucket_count; ++ list_add(&ce->e_indexes[n].o_list, ++ &cache->c_indexes_hash[n][bucket]); ++ } ++out: ++ spin_unlock(&mb_cache_spinlock); ++ return error; ++} ++ ++ ++/* ++ * mb_cache_entry_release() ++ * ++ * Release a handle to a cache entry. When the last handle to a cache entry ++ * is released it is either freed (if it is invalid) or otherwise inserted ++ * in to the lru list. ++ */ ++void ++mb_cache_entry_release(struct mb_cache_entry *ce) ++{ ++ spin_lock(&mb_cache_spinlock); ++ __mb_cache_entry_release_unlock(ce); ++} ++ ++ ++/* ++ * mb_cache_entry_takeout() ++ * ++ * Take a cache entry out of the cache, making it invalid. The entry can later ++ * be re-inserted using mb_cache_entry_insert(), or released using ++ * mb_cache_entry_release(). ++ */ ++void ++mb_cache_entry_takeout(struct mb_cache_entry *ce) ++{ ++ spin_lock(&mb_cache_spinlock); ++ mb_assert(list_empty(&ce->e_lru_list)); ++ __mb_cache_entry_unhash(ce); ++ spin_unlock(&mb_cache_spinlock); ++} ++ ++ ++/* ++ * mb_cache_entry_free() ++ * ++ * This is equivalent to the sequence mb_cache_entry_takeout() -- ++ * mb_cache_entry_release(). ++ */ ++void ++mb_cache_entry_free(struct mb_cache_entry *ce) ++{ ++ spin_lock(&mb_cache_spinlock); ++ mb_assert(list_empty(&ce->e_lru_list)); ++ __mb_cache_entry_unhash(ce); ++ __mb_cache_entry_release_unlock(ce); ++} ++ ++ ++/* ++ * mb_cache_entry_dup() ++ * ++ * Duplicate a handle to a cache entry (does not duplicate the cache entry ++ * itself). After the call, both the old and the new handle must be released. ++ */ ++struct mb_cache_entry * ++mb_cache_entry_dup(struct mb_cache_entry *ce) ++{ ++ atomic_inc(&ce->e_used); ++ return ce; ++} ++ ++ ++/* ++ * mb_cache_entry_get() ++ * ++ * Get a cache entry by device / block number. (There can only be one entry ++ * in the cache per device and block.) Returns NULL if no such cache entry ++ * exists. ++ */ ++struct mb_cache_entry * ++mb_cache_entry_get(struct mb_cache *cache, kdev_t dev, unsigned long block) ++{ ++ unsigned int bucket = (HASHDEV(dev) + block) % cache->c_bucket_count; ++ struct list_head *l; ++ struct mb_cache_entry *ce; ++ ++ spin_lock(&mb_cache_spinlock); ++ list_for_each(l, &cache->c_block_hash[bucket]) { ++ ce = list_entry(l, struct mb_cache_entry, e_block_list); ++ if (ce->e_dev == dev && ce->e_block == block) { ++ if (!list_empty(&ce->e_lru_list)) ++ list_del_init(&ce->e_lru_list); ++ atomic_inc(&ce->e_used); ++ goto cleanup; ++ } ++ } ++ ce = NULL; ++ ++cleanup: ++ spin_unlock(&mb_cache_spinlock); ++ return ce; ++} ++ ++#if !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0) ++ ++static struct mb_cache_entry * ++__mb_cache_entry_find(struct list_head *l, struct list_head *head, ++ int index, kdev_t dev, unsigned int key) ++{ ++ while (l != head) { ++ struct mb_cache_entry *ce = ++ list_entry(l, struct mb_cache_entry, ++ e_indexes[index].o_list); ++ if (ce->e_dev == dev && ce->e_indexes[index].o_key == key) { ++ if (!list_empty(&ce->e_lru_list)) ++ list_del_init(&ce->e_lru_list); ++ atomic_inc(&ce->e_used); ++ return ce; ++ } ++ l = l->next; ++ } ++ return NULL; ++} ++ ++ ++/* ++ * mb_cache_entry_find_first() ++ * ++ * Find the first cache entry on a given device with a certain key in ++ * an additional index. Additonal matches can be found with ++ * mb_cache_entry_find_next(). Returns NULL if no match was found. ++ * ++ * @cache: the cache to search ++ * @index: the number of the additonal index to search (0<=indexc_bucket_count; ++ struct list_head *l; ++ struct mb_cache_entry *ce; ++ ++ mb_assert(index < mb_cache_indexes(cache)); ++ spin_lock(&mb_cache_spinlock); ++ l = cache->c_indexes_hash[index][bucket].next; ++ ce = __mb_cache_entry_find(l, &cache->c_indexes_hash[index][bucket], ++ index, dev, key); ++ spin_unlock(&mb_cache_spinlock); ++ return ce; ++} ++ ++ ++/* ++ * mb_cache_entry_find_next() ++ * ++ * Find the next cache entry on a given device with a certain key in an ++ * additional index. Returns NULL if no match could be found. The previous ++ * entry is atomatically released, so that mb_cache_entry_find_next() can ++ * be called like this: ++ * ++ * entry = mb_cache_entry_find_first(); ++ * while (entry) { ++ * ... ++ * entry = mb_cache_entry_find_next(entry, ...); ++ * } ++ * ++ * @prev: The previous match ++ * @index: the number of the additonal index to search (0<=indexe_cache; ++ unsigned int bucket = key % cache->c_bucket_count; ++ struct list_head *l; ++ struct mb_cache_entry *ce; ++ ++ mb_assert(index < mb_cache_indexes(cache)); ++ spin_lock(&mb_cache_spinlock); ++ l = prev->e_indexes[index].o_list.next; ++ ce = __mb_cache_entry_find(l, &cache->c_indexes_hash[index][bucket], ++ index, dev, key); ++ __mb_cache_entry_release_unlock(prev); ++ return ce; ++} ++ ++#endif /* !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0) */ ++ ++static int __init init_mbcache(void) ++{ ++ register_cache(&mb_cache_definition); ++ return 0; ++} ++ ++static void __exit exit_mbcache(void) ++{ ++ unregister_cache(&mb_cache_definition); ++} ++ ++module_init(init_mbcache) ++module_exit(exit_mbcache) ++ +Index: linux-2.4.24-vanilla/include/asm-arm/unistd.h +=================================================================== +--- linux-2.4.24-vanilla.orig/include/asm-arm/unistd.h 2004-01-10 17:05:06.000000000 +0300 ++++ linux-2.4.24-vanilla/include/asm-arm/unistd.h 2004-01-10 17:20:28.000000000 +0300 +@@ -250,7 +250,6 @@ + #define __NR_security (__NR_SYSCALL_BASE+223) + #define __NR_gettid (__NR_SYSCALL_BASE+224) + #define __NR_readahead (__NR_SYSCALL_BASE+225) +-#if 0 /* allocated in 2.5 */ + #define __NR_setxattr (__NR_SYSCALL_BASE+226) + #define __NR_lsetxattr (__NR_SYSCALL_BASE+227) + #define __NR_fsetxattr (__NR_SYSCALL_BASE+228) +@@ -263,7 +262,6 @@ + #define __NR_removexattr (__NR_SYSCALL_BASE+235) + #define __NR_lremovexattr (__NR_SYSCALL_BASE+236) + #define __NR_fremovexattr (__NR_SYSCALL_BASE+237) +-#endif + #define __NR_tkill (__NR_SYSCALL_BASE+238) + #if 0 /* allocated in 2.5 */ + #define __NR_sendfile64 (__NR_SYSCALL_BASE+239) +Index: linux-2.4.24-vanilla/include/asm-ppc64/unistd.h +=================================================================== +--- linux-2.4.24-vanilla.orig/include/asm-ppc64/unistd.h 2004-01-10 17:05:59.000000000 +0300 ++++ linux-2.4.24-vanilla/include/asm-ppc64/unistd.h 2004-01-10 17:20:28.000000000 +0300 +@@ -218,6 +218,7 @@ + #define __NR_mincore 206 + #define __NR_gettid 207 + #define __NR_tkill 208 ++#endif + #define __NR_setxattr 209 + #define __NR_lsetxattr 210 + #define __NR_fsetxattr 211 +@@ -230,6 +231,7 @@ + #define __NR_removexattr 218 + #define __NR_lremovexattr 219 + #define __NR_fremovexattr 220 ++#if 0 /* Reserved syscalls */ + #define __NR_futex 221 + #define __NR_sched_setaffinity 222 + #define __NR_sched_getaffinity 223 +Index: linux-2.4.24-vanilla/include/asm-s390/unistd.h +=================================================================== +--- linux-2.4.24-vanilla.orig/include/asm-s390/unistd.h 2004-01-10 17:04:42.000000000 +0300 ++++ linux-2.4.24-vanilla/include/asm-s390/unistd.h 2004-01-10 17:20:28.000000000 +0300 +@@ -213,9 +213,18 @@ + #define __NR_getdents64 220 + #define __NR_fcntl64 221 + #define __NR_readahead 222 +-/* +- * Numbers 224-235 are reserved for posix acl +- */ ++#define __NR_setxattr 224 ++#define __NR_lsetxattr 225 ++#define __NR_fsetxattr 226 ++#define __NR_getxattr 227 ++#define __NR_lgetxattr 228 ++#define __NR_fgetxattr 229 ++#define __NR_listxattr 230 ++#define __NR_llistxattr 231 ++#define __NR_flistxattr 232 ++#define __NR_removexattr 233 ++#define __NR_lremovexattr 234 ++#define __NR_fremovexattr 235 + #define __NR_gettid 236 + #define __NR_tkill 237 + +Index: linux-2.4.24-vanilla/include/asm-s390x/unistd.h +=================================================================== +--- linux-2.4.24-vanilla.orig/include/asm-s390x/unistd.h 2004-01-10 17:04:42.000000000 +0300 ++++ linux-2.4.24-vanilla/include/asm-s390x/unistd.h 2004-01-10 17:20:28.000000000 +0300 +@@ -181,9 +181,18 @@ + #define __NR_mincore 218 + #define __NR_madvise 219 + #define __NR_readahead 222 +-/* +- * Numbers 224-235 are reserved for posix acl +- */ ++#define __NR_setxattr 224 ++#define __NR_lsetxattr 225 ++#define __NR_fsetxattr 226 ++#define __NR_getxattr 227 ++#define __NR_lgetxattr 228 ++#define __NR_fgetxattr 229 ++#define __NR_listxattr 230 ++#define __NR_llistxattr 231 ++#define __NR_flistxattr 232 ++#define __NR_removexattr 233 ++#define __NR_lremovexattr 234 ++#define __NR_fremovexattr 235 + #define __NR_gettid 236 + #define __NR_tkill 237 + +Index: linux-2.4.24-vanilla/include/linux/cache_def.h +=================================================================== +--- linux-2.4.24-vanilla.orig/include/linux/cache_def.h 2003-01-30 13:24:37.000000000 +0300 ++++ linux-2.4.24-vanilla/include/linux/cache_def.h 2004-01-10 17:20:28.000000000 +0300 +@@ -0,0 +1,15 @@ ++/* ++ * linux/cache_def.h ++ * Handling of caches defined in drivers, filesystems, ... ++ * ++ * Copyright (C) 2002 by Andreas Gruenbacher, ++ */ ++ ++struct cache_definition { ++ const char *name; ++ void (*shrink)(int, unsigned int); ++ struct list_head link; ++}; ++ ++extern void register_cache(struct cache_definition *); ++extern void unregister_cache(struct cache_definition *); +Index: linux-2.4.24-vanilla/include/linux/errno.h +=================================================================== +--- linux-2.4.24-vanilla.orig/include/linux/errno.h 2001-02-10 01:46:13.000000000 +0300 ++++ linux-2.4.24-vanilla/include/linux/errno.h 2004-01-10 17:20:28.000000000 +0300 +@@ -23,4 +23,8 @@ + + #endif + ++/* Defined for extended attributes */ ++#define ENOATTR ENODATA /* No such attribute */ ++#define ENOTSUP EOPNOTSUPP /* Operation not supported */ ++ + #endif +Index: linux-2.4.24-vanilla/include/linux/ext2_fs.h +=================================================================== +--- linux-2.4.24-vanilla.orig/include/linux/ext2_fs.h 2004-01-10 17:04:42.000000000 +0300 ++++ linux-2.4.24-vanilla/include/linux/ext2_fs.h 2004-01-10 17:20:28.000000000 +0300 +@@ -57,8 +57,6 @@ + */ + #define EXT2_BAD_INO 1 /* Bad blocks inode */ + #define EXT2_ROOT_INO 2 /* Root inode */ +-#define EXT2_ACL_IDX_INO 3 /* ACL inode */ +-#define EXT2_ACL_DATA_INO 4 /* ACL inode */ + #define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */ + #define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */ + +@@ -86,7 +84,6 @@ + #else + # define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size) + #endif +-#define EXT2_ACLE_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry)) + #define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (__u32)) + #ifdef __KERNEL__ + # define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits) +@@ -121,28 +118,6 @@ + #endif + + /* +- * ACL structures +- */ +-struct ext2_acl_header /* Header of Access Control Lists */ +-{ +- __u32 aclh_size; +- __u32 aclh_file_count; +- __u32 aclh_acle_count; +- __u32 aclh_first_acle; +-}; +- +-struct ext2_acl_entry /* Access Control List Entry */ +-{ +- __u32 acle_size; +- __u16 acle_perms; /* Access permissions */ +- __u16 acle_type; /* Type of entry */ +- __u16 acle_tag; /* User or group identity */ +- __u16 acle_pad1; +- __u32 acle_next; /* Pointer on next entry for the */ +- /* same inode or on next free entry */ +-}; +- +-/* + * Structure of a blocks group descriptor + */ + struct ext2_group_desc +@@ -314,6 +289,7 @@ + #define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */ + #define EXT2_MOUNT_MINIX_DF 0x0080 /* Mimics the Minix statfs */ + #define EXT2_MOUNT_NO_UID32 0x0200 /* Disable 32-bit UIDs */ ++#define EXT2_MOUNT_XATTR_USER 0x4000 /* Extended user attributes */ + + #define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt + #define set_opt(o, opt) o |= EXT2_MOUNT_##opt +@@ -397,6 +373,7 @@ + + #ifdef __KERNEL__ + #define EXT2_SB(sb) (&((sb)->u.ext2_sb)) ++#define EXT2_I(inode) (&((inode)->u.ext2_i)) + #else + /* Assume that user mode programs are passing in an ext2fs superblock, not + * a kernel struct super_block. This will allow us to call the feature-test +@@ -466,7 +443,7 @@ + #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 + #define EXT2_FEATURE_INCOMPAT_ANY 0xffffffff + +-#define EXT2_FEATURE_COMPAT_SUPP 0 ++#define EXT2_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR + #define EXT2_FEATURE_INCOMPAT_SUPP EXT2_FEATURE_INCOMPAT_FILETYPE + #define EXT2_FEATURE_RO_COMPAT_SUPP (EXT2_FEATURE_RO_COMPAT_SPARSE_SUPER| \ + EXT2_FEATURE_RO_COMPAT_LARGE_FILE| \ +@@ -624,8 +601,10 @@ + + /* namei.c */ + extern struct inode_operations ext2_dir_inode_operations; ++extern struct inode_operations ext2_special_inode_operations; + + /* symlink.c */ ++extern struct inode_operations ext2_symlink_inode_operations; + extern struct inode_operations ext2_fast_symlink_inode_operations; + + #endif /* __KERNEL__ */ +Index: linux-2.4.24-vanilla/include/linux/ext2_xattr.h +=================================================================== +--- linux-2.4.24-vanilla.orig/include/linux/ext2_xattr.h 2003-01-30 13:24:37.000000000 +0300 ++++ linux-2.4.24-vanilla/include/linux/ext2_xattr.h 2004-01-10 17:20:28.000000000 +0300 +@@ -0,0 +1,157 @@ ++/* ++ File: linux/ext2_xattr.h ++ ++ On-disk format of extended attributes for the ext2 filesystem. ++ ++ (C) 2001 Andreas Gruenbacher, ++*/ ++ ++#include ++#include ++#include ++ ++/* Magic value in attribute blocks */ ++#define EXT2_XATTR_MAGIC 0xEA020000 ++ ++/* Maximum number of references to one attribute block */ ++#define EXT2_XATTR_REFCOUNT_MAX 1024 ++ ++/* Name indexes */ ++#define EXT2_XATTR_INDEX_MAX 10 ++#define EXT2_XATTR_INDEX_USER 1 ++#define EXT2_XATTR_INDEX_POSIX_ACL_ACCESS 2 ++#define EXT2_XATTR_INDEX_POSIX_ACL_DEFAULT 3 ++ ++struct ext2_xattr_header { ++ __u32 h_magic; /* magic number for identification */ ++ __u32 h_refcount; /* reference count */ ++ __u32 h_blocks; /* number of disk blocks used */ ++ __u32 h_hash; /* hash value of all attributes */ ++ __u32 h_reserved[4]; /* zero right now */ ++}; ++ ++struct ext2_xattr_entry { ++ __u8 e_name_len; /* length of name */ ++ __u8 e_name_index; /* attribute name index */ ++ __u16 e_value_offs; /* offset in disk block of value */ ++ __u32 e_value_block; /* disk block attribute is stored on (n/i) */ ++ __u32 e_value_size; /* size of attribute value */ ++ __u32 e_hash; /* hash value of name and value */ ++ char e_name[0]; /* attribute name */ ++}; ++ ++#define EXT2_XATTR_PAD_BITS 2 ++#define EXT2_XATTR_PAD (1<e_name_len)) ) ++#define EXT2_XATTR_SIZE(size) \ ++ (((size) + EXT2_XATTR_ROUND) & ~EXT2_XATTR_ROUND) ++ ++#ifdef __KERNEL__ ++ ++# ifdef CONFIG_EXT2_FS_XATTR ++ ++struct ext2_xattr_handler { ++ char *prefix; ++ size_t (*list)(char *list, struct inode *inode, const char *name, ++ int name_len); ++ int (*get)(struct inode *inode, const char *name, void *buffer, ++ size_t size); ++ int (*set)(struct inode *inode, const char *name, const void *buffer, ++ size_t size, int flags); ++}; ++ ++extern int ext2_xattr_register(int, struct ext2_xattr_handler *); ++extern void ext2_xattr_unregister(int, struct ext2_xattr_handler *); ++ ++extern int ext2_setxattr(struct dentry *, const char *, const void *, size_t, int); ++extern ssize_t ext2_getxattr(struct dentry *, const char *, void *, size_t); ++extern ssize_t ext2_listxattr(struct dentry *, char *, size_t); ++extern int ext2_removexattr(struct dentry *, const char *); ++ ++extern int ext2_xattr_get(struct inode *, int, const char *, void *, size_t); ++extern int ext2_xattr_list(struct inode *, char *, size_t); ++extern int ext2_xattr_set(struct inode *, int, const char *, const void *, size_t, int); ++ ++extern void ext2_xattr_delete_inode(struct inode *); ++extern void ext2_xattr_put_super(struct super_block *); ++ ++extern int init_ext2_xattr(void) __init; ++extern void exit_ext2_xattr(void); ++ ++# else /* CONFIG_EXT2_FS_XATTR */ ++# define ext2_setxattr NULL ++# define ext2_getxattr NULL ++# define ext2_listxattr NULL ++# define ext2_removexattr NULL ++ ++static inline int ++ext2_xattr_get(struct inode *inode, int name_index, ++ const char *name, void *buffer, size_t size) ++{ ++ return -ENOTSUP; ++} ++ ++static inline int ++ext2_xattr_list(struct inode *inode, char *buffer, size_t size) ++{ ++ return -ENOTSUP; ++} ++ ++static inline int ++ext2_xattr_set(struct inode *inode, int name_index, const char *name, ++ const void *value, size_t size, int flags) ++{ ++ return -ENOTSUP; ++} ++ ++static inline void ++ext2_xattr_delete_inode(struct inode *inode) ++{ ++} ++ ++static inline void ++ext2_xattr_put_super(struct super_block *sb) ++{ ++} ++ ++static inline int ++init_ext2_xattr(void) ++{ ++ return 0; ++} ++ ++static inline void ++exit_ext2_xattr(void) ++{ ++} ++ ++# endif /* CONFIG_EXT2_FS_XATTR */ ++ ++# ifdef CONFIG_EXT2_FS_XATTR_USER ++ ++extern int init_ext2_xattr_user(void) __init; ++extern void exit_ext2_xattr_user(void); ++ ++# else /* CONFIG_EXT2_FS_XATTR_USER */ ++ ++static inline int ++init_ext2_xattr_user(void) ++{ ++ return 0; ++} ++ ++static inline void ++exit_ext2_xattr_user(void) ++{ ++} ++ ++# endif /* CONFIG_EXT2_FS_XATTR_USER */ ++ ++#endif /* __KERNEL__ */ ++ +Index: linux-2.4.24-vanilla/include/linux/ext3_fs.h +=================================================================== +--- linux-2.4.24-vanilla.orig/include/linux/ext3_fs.h 2004-01-10 17:11:50.000000000 +0300 ++++ linux-2.4.24-vanilla/include/linux/ext3_fs.h 2004-01-10 17:20:28.000000000 +0300 +@@ -63,8 +63,6 @@ + */ + #define EXT3_BAD_INO 1 /* Bad blocks inode */ + #define EXT3_ROOT_INO 2 /* Root inode */ +-#define EXT3_ACL_IDX_INO 3 /* ACL inode */ +-#define EXT3_ACL_DATA_INO 4 /* ACL inode */ + #define EXT3_BOOT_LOADER_INO 5 /* Boot loader inode */ + #define EXT3_UNDEL_DIR_INO 6 /* Undelete directory inode */ + #define EXT3_RESIZE_INO 7 /* Reserved group descriptors inode */ +@@ -94,7 +92,6 @@ + #else + # define EXT3_BLOCK_SIZE(s) (EXT3_MIN_BLOCK_SIZE << (s)->s_log_block_size) + #endif +-#define EXT3_ACLE_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / sizeof (struct ext3_acl_entry)) + #define EXT3_ADDR_PER_BLOCK(s) (EXT3_BLOCK_SIZE(s) / sizeof (__u32)) + #ifdef __KERNEL__ + # define EXT3_BLOCK_SIZE_BITS(s) ((s)->s_blocksize_bits) +@@ -129,28 +126,6 @@ + #endif + + /* +- * ACL structures +- */ +-struct ext3_acl_header /* Header of Access Control Lists */ +-{ +- __u32 aclh_size; +- __u32 aclh_file_count; +- __u32 aclh_acle_count; +- __u32 aclh_first_acle; +-}; +- +-struct ext3_acl_entry /* Access Control List Entry */ +-{ +- __u32 acle_size; +- __u16 acle_perms; /* Access permissions */ +- __u16 acle_type; /* Type of entry */ +- __u16 acle_tag; /* User or group identity */ +- __u16 acle_pad1; +- __u32 acle_next; /* Pointer on next entry for the */ +- /* same inode or on next free entry */ +-}; +- +-/* + * Structure of a blocks group descriptor + */ + struct ext3_group_desc +@@ -344,6 +319,7 @@ + #define EXT3_MOUNT_WRITEBACK_DATA 0x0C00 /* No data ordering */ + #define EXT3_MOUNT_UPDATE_JOURNAL 0x1000 /* Update the journal format */ + #define EXT3_MOUNT_NO_UID32 0x2000 /* Disable 32-bit UIDs */ ++#define EXT3_MOUNT_XATTR_USER 0x4000 /* Extended user attributes */ + + /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */ + #ifndef _LINUX_EXT2_FS_H +@@ -521,7 +497,7 @@ + #define EXT3_FEATURE_INCOMPAT_RECOVER 0x0004 /* Needs recovery */ + #define EXT3_FEATURE_INCOMPAT_JOURNAL_DEV 0x0008 /* Journal device */ + +-#define EXT3_FEATURE_COMPAT_SUPP 0 ++#define EXT3_FEATURE_COMPAT_SUPP EXT2_FEATURE_COMPAT_EXT_ATTR + #define EXT3_FEATURE_INCOMPAT_SUPP (EXT3_FEATURE_INCOMPAT_FILETYPE| \ + EXT3_FEATURE_INCOMPAT_RECOVER) + #define EXT3_FEATURE_RO_COMPAT_SUPP (EXT3_FEATURE_RO_COMPAT_SPARSE_SUPER| \ +@@ -704,6 +680,7 @@ + extern unsigned long ext3_count_free (struct buffer_head *, unsigned); + + /* inode.c */ ++extern int ext3_forget(handle_t *, int, struct inode *, struct buffer_head *, int); + extern struct buffer_head * ext3_getblk (handle_t *, struct inode *, long, int, int *); + extern struct buffer_head * ext3_bread (handle_t *, struct inode *, int, int, int *); + +@@ -773,8 +750,10 @@ + + /* namei.c */ + extern struct inode_operations ext3_dir_inode_operations; ++extern struct inode_operations ext3_special_inode_operations; + + /* symlink.c */ ++extern struct inode_operations ext3_symlink_inode_operations; + extern struct inode_operations ext3_fast_symlink_inode_operations; + + +Index: linux-2.4.24-vanilla/include/linux/ext3_jbd.h +=================================================================== +--- linux-2.4.24-vanilla.orig/include/linux/ext3_jbd.h 2004-01-10 17:11:50.000000000 +0300 ++++ linux-2.4.24-vanilla/include/linux/ext3_jbd.h 2004-01-10 17:20:28.000000000 +0300 +@@ -30,13 +30,19 @@ + + #define EXT3_SINGLEDATA_TRANS_BLOCKS 8U + ++/* Extended attributes may touch two data buffers, two bitmap buffers, ++ * and two group and summaries. */ ++ ++#define EXT3_XATTR_TRANS_BLOCKS 8 ++ + /* Define the minimum size for a transaction which modifies data. This + * needs to take into account the fact that we may end up modifying two + * quota files too (one for the group, one for the user quota). The + * superblock only gets updated once, of course, so don't bother + * counting that again for the quota updates. */ + +-#define EXT3_DATA_TRANS_BLOCKS (3 * EXT3_SINGLEDATA_TRANS_BLOCKS - 2) ++#define EXT3_DATA_TRANS_BLOCKS (3 * EXT3_SINGLEDATA_TRANS_BLOCKS + \ ++ EXT3_XATTR_TRANS_BLOCKS - 2) + + extern int ext3_writepage_trans_blocks(struct inode *inode); + +Index: linux-2.4.24-vanilla/include/linux/ext3_xattr.h +=================================================================== +--- linux-2.4.24-vanilla.orig/include/linux/ext3_xattr.h 2003-01-30 13:24:37.000000000 +0300 ++++ linux-2.4.24-vanilla/include/linux/ext3_xattr.h 2004-01-10 17:20:28.000000000 +0300 +@@ -0,0 +1,157 @@ ++/* ++ File: linux/ext3_xattr.h ++ ++ On-disk format of extended attributes for the ext3 filesystem. ++ ++ (C) 2001 Andreas Gruenbacher, ++*/ ++ ++#include ++#include ++#include ++ ++/* Magic value in attribute blocks */ ++#define EXT3_XATTR_MAGIC 0xEA020000 ++ ++/* Maximum number of references to one attribute block */ ++#define EXT3_XATTR_REFCOUNT_MAX 1024 ++ ++/* Name indexes */ ++#define EXT3_XATTR_INDEX_MAX 10 ++#define EXT3_XATTR_INDEX_USER 1 ++#define EXT3_XATTR_INDEX_POSIX_ACL_ACCESS 2 ++#define EXT3_XATTR_INDEX_POSIX_ACL_DEFAULT 3 ++ ++struct ext3_xattr_header { ++ __u32 h_magic; /* magic number for identification */ ++ __u32 h_refcount; /* reference count */ ++ __u32 h_blocks; /* number of disk blocks used */ ++ __u32 h_hash; /* hash value of all attributes */ ++ __u32 h_reserved[4]; /* zero right now */ ++}; ++ ++struct ext3_xattr_entry { ++ __u8 e_name_len; /* length of name */ ++ __u8 e_name_index; /* attribute name index */ ++ __u16 e_value_offs; /* offset in disk block of value */ ++ __u32 e_value_block; /* disk block attribute is stored on (n/i) */ ++ __u32 e_value_size; /* size of attribute value */ ++ __u32 e_hash; /* hash value of name and value */ ++ char e_name[0]; /* attribute name */ ++}; ++ ++#define EXT3_XATTR_PAD_BITS 2 ++#define EXT3_XATTR_PAD (1<e_name_len)) ) ++#define EXT3_XATTR_SIZE(size) \ ++ (((size) + EXT3_XATTR_ROUND) & ~EXT3_XATTR_ROUND) ++ ++#ifdef __KERNEL__ ++ ++# ifdef CONFIG_EXT3_FS_XATTR ++ ++struct ext3_xattr_handler { ++ char *prefix; ++ size_t (*list)(char *list, struct inode *inode, const char *name, ++ int name_len); ++ int (*get)(struct inode *inode, const char *name, void *buffer, ++ size_t size); ++ int (*set)(struct inode *inode, const char *name, const void *buffer, ++ size_t size, int flags); ++}; ++ ++extern int ext3_xattr_register(int, struct ext3_xattr_handler *); ++extern void ext3_xattr_unregister(int, struct ext3_xattr_handler *); ++ ++extern int ext3_setxattr(struct dentry *, const char *, const void *, size_t, int); ++extern ssize_t ext3_getxattr(struct dentry *, const char *, void *, size_t); ++extern ssize_t ext3_listxattr(struct dentry *, char *, size_t); ++extern int ext3_removexattr(struct dentry *, const char *); ++ ++extern int ext3_xattr_get(struct inode *, int, const char *, void *, size_t); ++extern int ext3_xattr_list(struct inode *, char *, size_t); ++extern int ext3_xattr_set(handle_t *handle, struct inode *, int, const char *, const void *, size_t, int); ++ ++extern void ext3_xattr_delete_inode(handle_t *, struct inode *); ++extern void ext3_xattr_put_super(struct super_block *); ++ ++extern int init_ext3_xattr(void) __init; ++extern void exit_ext3_xattr(void); ++ ++# else /* CONFIG_EXT3_FS_XATTR */ ++# define ext3_setxattr NULL ++# define ext3_getxattr NULL ++# define ext3_listxattr NULL ++# define ext3_removexattr NULL ++ ++static inline int ++ext3_xattr_get(struct inode *inode, int name_index, const char *name, ++ void *buffer, size_t size) ++{ ++ return -ENOTSUP; ++} ++ ++static inline int ++ext3_xattr_list(struct inode *inode, void *buffer, size_t size) ++{ ++ return -ENOTSUP; ++} ++ ++static inline int ++ext3_xattr_set(handle_t *handle, struct inode *inode, int name_index, ++ const char *name, const void *value, size_t size, int flags) ++{ ++ return -ENOTSUP; ++} ++ ++static inline void ++ext3_xattr_delete_inode(handle_t *handle, struct inode *inode) ++{ ++} ++ ++static inline void ++ext3_xattr_put_super(struct super_block *sb) ++{ ++} ++ ++static inline int ++init_ext3_xattr(void) ++{ ++ return 0; ++} ++ ++static inline void ++exit_ext3_xattr(void) ++{ ++} ++ ++# endif /* CONFIG_EXT3_FS_XATTR */ ++ ++# ifdef CONFIG_EXT3_FS_XATTR_USER ++ ++extern int init_ext3_xattr_user(void) __init; ++extern void exit_ext3_xattr_user(void); ++ ++# else /* CONFIG_EXT3_FS_XATTR_USER */ ++ ++static inline int ++init_ext3_xattr_user(void) ++{ ++ return 0; ++} ++ ++static inline void ++exit_ext3_xattr_user(void) ++{ ++} ++ ++#endif /* CONFIG_EXT3_FS_XATTR_USER */ ++ ++#endif /* __KERNEL__ */ ++ +Index: linux-2.4.24-vanilla/include/linux/fs.h +=================================================================== +--- linux-2.4.24-vanilla.orig/include/linux/fs.h 2004-01-10 17:11:45.000000000 +0300 ++++ linux-2.4.24-vanilla/include/linux/fs.h 2004-01-10 17:20:28.000000000 +0300 +@@ -913,7 +913,7 @@ + int (*setattr) (struct dentry *, struct iattr *); + int (*setattr_raw) (struct inode *, struct iattr *); + int (*getattr) (struct dentry *, struct iattr *); +- int (*setxattr) (struct dentry *, const char *, void *, size_t, int); ++ int (*setxattr) (struct dentry *, const char *, const void *, size_t, int); + ssize_t (*getxattr) (struct dentry *, const char *, void *, size_t); + ssize_t (*listxattr) (struct dentry *, char *, size_t); + int (*removexattr) (struct dentry *, const char *); +Index: linux-2.4.24-vanilla/include/linux/mbcache.h +=================================================================== +--- linux-2.4.24-vanilla.orig/include/linux/mbcache.h 2003-01-30 13:24:37.000000000 +0300 ++++ linux-2.4.24-vanilla/include/linux/mbcache.h 2004-01-10 17:20:28.000000000 +0300 +@@ -0,0 +1,69 @@ ++/* ++ File: linux/mbcache.h ++ ++ (C) 2001 by Andreas Gruenbacher, ++*/ ++ ++/* Hardwire the number of additional indexes */ ++#define MB_CACHE_INDEXES_COUNT 1 ++ ++struct mb_cache_entry; ++ ++struct mb_cache_op { ++ int (*free)(struct mb_cache_entry *, int); ++}; ++ ++struct mb_cache { ++ struct list_head c_cache_list; ++ const char *c_name; ++ struct mb_cache_op c_op; ++ atomic_t c_entry_count; ++ int c_bucket_count; ++#ifndef MB_CACHE_INDEXES_COUNT ++ int c_indexes_count; ++#endif ++ kmem_cache_t *c_entry_cache; ++ struct list_head *c_block_hash; ++ struct list_head *c_indexes_hash[0]; ++}; ++ ++struct mb_cache_entry_index { ++ struct list_head o_list; ++ unsigned int o_key; ++}; ++ ++struct mb_cache_entry { ++ struct list_head e_lru_list; ++ struct mb_cache *e_cache; ++ atomic_t e_used; ++ kdev_t e_dev; ++ unsigned long e_block; ++ struct list_head e_block_list; ++ struct mb_cache_entry_index e_indexes[0]; ++}; ++ ++/* Functions on caches */ ++ ++struct mb_cache * mb_cache_create(const char *, struct mb_cache_op *, size_t, ++ int, int); ++void mb_cache_shrink(struct mb_cache *, kdev_t); ++void mb_cache_destroy(struct mb_cache *); ++ ++/* Functions on cache entries */ ++ ++struct mb_cache_entry *mb_cache_entry_alloc(struct mb_cache *); ++int mb_cache_entry_insert(struct mb_cache_entry *, kdev_t, unsigned long, ++ unsigned int[]); ++void mb_cache_entry_rehash(struct mb_cache_entry *, unsigned int[]); ++void mb_cache_entry_release(struct mb_cache_entry *); ++void mb_cache_entry_takeout(struct mb_cache_entry *); ++void mb_cache_entry_free(struct mb_cache_entry *); ++struct mb_cache_entry *mb_cache_entry_dup(struct mb_cache_entry *); ++struct mb_cache_entry *mb_cache_entry_get(struct mb_cache *, kdev_t, ++ unsigned long); ++#if !defined(MB_CACHE_INDEXES_COUNT) || (MB_CACHE_INDEXES_COUNT > 0) ++struct mb_cache_entry *mb_cache_entry_find_first(struct mb_cache *cache, int, ++ kdev_t, unsigned int); ++struct mb_cache_entry *mb_cache_entry_find_next(struct mb_cache_entry *, int, ++ kdev_t, unsigned int); ++#endif +Index: linux-2.4.24-vanilla/kernel/ksyms.c +=================================================================== +--- linux-2.4.24-vanilla.orig/kernel/ksyms.c 2004-01-10 17:11:43.000000000 +0300 ++++ linux-2.4.24-vanilla/kernel/ksyms.c 2004-01-10 17:20:28.000000000 +0300 +@@ -11,6 +11,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -92,6 +93,7 @@ + EXPORT_SYMBOL(exit_files); + EXPORT_SYMBOL(exit_fs); + EXPORT_SYMBOL(exit_sighand); ++EXPORT_SYMBOL(copy_fs_struct); + + /* internal kernel memory management */ + EXPORT_SYMBOL(_alloc_pages); +@@ -109,6 +111,8 @@ + EXPORT_SYMBOL(kmem_cache_alloc); + EXPORT_SYMBOL(kmem_cache_free); + EXPORT_SYMBOL(kmem_cache_size); ++EXPORT_SYMBOL(register_cache); ++EXPORT_SYMBOL(unregister_cache); + EXPORT_SYMBOL(kmalloc); + EXPORT_SYMBOL(kfree); + EXPORT_SYMBOL(vfree); +Index: linux-2.4.24-vanilla/mm/vmscan.c +=================================================================== +--- linux-2.4.24-vanilla.orig/mm/vmscan.c 2004-01-10 17:06:00.000000000 +0300 ++++ linux-2.4.24-vanilla/mm/vmscan.c 2004-01-10 17:21:00.000000000 +0300 +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -34,6 +35,39 @@ + */ + int vm_passes = 60; + ++static DECLARE_MUTEX(other_caches_sem); ++static LIST_HEAD(cache_definitions); ++ ++void register_cache(struct cache_definition *cache) ++{ ++ down(&other_caches_sem); ++ list_add(&cache->link, &cache_definitions); ++ up(&other_caches_sem); ++} ++ ++void unregister_cache(struct cache_definition *cache) ++{ ++ down(&other_caches_sem); ++ list_del(&cache->link); ++ up(&other_caches_sem); ++} ++ ++static void shrink_other_caches(unsigned int priority, int gfp_mask) ++{ ++ struct list_head *p; ++ ++ if (down_trylock(&other_caches_sem)) ++ return; ++ ++ list_for_each_prev(p, &cache_definitions) { ++ struct cache_definition *cache = ++ list_entry(p, struct cache_definition, link); ++ ++ cache->shrink(priority, gfp_mask); ++ } ++ up(&other_caches_sem); ++} ++ + /* + * "vm_cache_scan_ratio" is how much of the inactive LRU queue we will scan + * in one go. A value of 6 for vm_cache_scan_ratio implies that we'll +@@ -523,6 +557,7 @@ + #ifdef CONFIG_QUOTA + shrink_dqcache_memory(vm_vfs_scan_ratio, gfp_mask); + #endif ++ shrink_other_caches(vm_vfs_scan_ratio, gfp_mask); + + if (!*failed_swapout) + *failed_swapout = !swap_out(classzone); +@@ -645,6 +680,7 @@ + #ifdef CONFIG_QUOTA + shrink_dqcache_memory(vm_vfs_scan_ratio, gfp_mask); + #endif ++ shrink_other_caches(vm_vfs_scan_ratio, gfp_mask); + if (!failed_swapout) + failed_swapout = !swap_out(classzone); + } while (--tries); diff --git a/lustre/kernel_patches/patches/uml-export-end_iomem.patch b/lustre/kernel_patches/patches/uml-export-end_iomem.patch new file mode 100644 index 0000000..ab8a84b --- /dev/null +++ b/lustre/kernel_patches/patches/uml-export-end_iomem.patch @@ -0,0 +1,12 @@ +Index: linux-2.4.24-vanilla/arch/um/kernel/ksyms.c +=================================================================== +--- linux-2.4.24-vanilla.orig/arch/um/kernel/ksyms.c 2004-01-10 17:47:10.000000000 +0300 ++++ linux-2.4.24-vanilla/arch/um/kernel/ksyms.c 2004-01-10 18:22:30.000000000 +0300 +@@ -34,6 +34,7 @@ + EXPORT_SYMBOL(host_task_size); + EXPORT_SYMBOL(arch_validate); + EXPORT_SYMBOL(get_kmem_end); ++EXPORT_SYMBOL(end_iomem); + + EXPORT_SYMBOL(high_physmem); + EXPORT_SYMBOL(empty_zero_page); diff --git a/lustre/kernel_patches/patches/uml-patch-2.4.23-1.patch b/lustre/kernel_patches/patches/uml-patch-2.4.23-1.patch new file mode 100644 index 0000000..7e1d17e --- /dev/null +++ b/lustre/kernel_patches/patches/uml-patch-2.4.23-1.patch @@ -0,0 +1,42024 @@ +diff -Naur -X ../exclude-files orig/arch/um/common.ld.in um/arch/um/common.ld.in +--- orig/arch/um/common.ld.in 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/common.ld.in 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,53 @@ ++ .kstrtab : { *(.kstrtab) } ++ ++ . = ALIGN(16); /* Exception table */ ++ __start___ex_table = .; ++ __ex_table : { *(__ex_table) } ++ __stop___ex_table = .; ++ ++ __start___ksymtab = .; /* Kernel symbol table */ ++ __ksymtab : { *(__ksymtab) } ++ __stop___ksymtab = .; ++ ++ .unprotected : { *(.unprotected) } ++ . = ALIGN(4096); ++ PROVIDE (_unprotected_end = .); ++ ++ . = ALIGN(4096); ++ __uml_setup_start = .; ++ .uml.setup.init : { *(.uml.setup.init) } ++ __uml_setup_end = .; ++ __uml_help_start = .; ++ .uml.help.init : { *(.uml.help.init) } ++ __uml_help_end = .; ++ __uml_postsetup_start = .; ++ .uml.postsetup.init : { *(.uml.postsetup.init) } ++ __uml_postsetup_end = .; ++ __setup_start = .; ++ .setup.init : { *(.setup.init) } ++ __setup_end = .; ++ __initcall_start = .; ++ .initcall.init : { *(.initcall.init) } ++ __initcall_end = .; ++ __uml_initcall_start = .; ++ .uml.initcall.init : { *(.uml.initcall.init) } ++ __uml_initcall_end = .; ++ __init_end = .; ++ __exitcall_begin = .; ++ .exitcall : { *(.exitcall.exit) } ++ __exitcall_end = .; ++ __uml_exitcall_begin = .; ++ .uml.exitcall : { *(.uml.exitcall.exit) } ++ __uml_exitcall_end = .; ++ ++ __preinit_array_start = .; ++ .preinit_array : { *(.preinit_array) } ++ __preinit_array_end = .; ++ __init_array_start = .; ++ .init_array : { *(.init_array) } ++ __init_array_end = .; ++ __fini_array_start = .; ++ .fini_array : { *(.fini_array) } ++ __fini_array_end = .; ++ ++ .data.init : { *(.data.init) } +diff -Naur -X ../exclude-files orig/arch/um/config_block.in um/arch/um/config_block.in +--- orig/arch/um/config_block.in 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/config_block.in 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,22 @@ ++mainmenu_option next_comment ++comment 'Block Devices' ++ ++bool 'Virtual block device' CONFIG_BLK_DEV_UBD ++dep_bool ' Always do synchronous disk IO for UBD' CONFIG_BLK_DEV_UBD_SYNC $CONFIG_BLK_DEV_UBD ++bool 'COW device' CONFIG_COW ++ ++if [ "$CONFIG_BLK_DEV_UBD" = "y" -o "$CONFIG_COW" = "y" ] ; then ++ define_bool CONFIG_COW_COMMON y ++fi ++ ++tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP ++dep_tristate 'Network block device support' CONFIG_BLK_DEV_NBD $CONFIG_NET ++tristate 'RAM disk support' CONFIG_BLK_DEV_RAM ++if [ "$CONFIG_BLK_DEV_RAM" = "y" -o "$CONFIG_BLK_DEV_RAM" = "m" ]; then ++ int ' Default RAM disk size' CONFIG_BLK_DEV_RAM_SIZE 4096 ++fi ++dep_bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD $CONFIG_BLK_DEV_RAM ++ ++tristate 'Example IO memory driver' CONFIG_MMAPPER ++ ++endmenu +diff -Naur -X ../exclude-files orig/arch/um/config_char.in um/arch/um/config_char.in +--- orig/arch/um/config_char.in 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/config_char.in 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,37 @@ ++mainmenu_option next_comment ++comment 'Character Devices' ++ ++define_bool CONFIG_STDIO_CONSOLE y ++ ++bool 'Virtual serial line' CONFIG_SSL ++ ++bool 'file descriptor channel support' CONFIG_FD_CHAN ++bool 'null channel support' CONFIG_NULL_CHAN ++bool 'port channel support' CONFIG_PORT_CHAN ++bool 'pty channel support' CONFIG_PTY_CHAN ++bool 'tty channel support' CONFIG_TTY_CHAN ++bool 'xterm channel support' CONFIG_XTERM_CHAN ++string 'Default main console channel initialization' CONFIG_CON_ZERO_CHAN \ ++ "fd:0,fd:1" ++string 'Default console channel initialization' CONFIG_CON_CHAN "xterm" ++string 'Default serial line channel initialization' CONFIG_SSL_CHAN "pty" ++ ++ ++bool 'Unix98 PTY support' CONFIG_UNIX98_PTYS ++if [ "$CONFIG_UNIX98_PTYS" = "y" ]; then ++ int 'Maximum number of Unix98 PTYs in use (0-2048)' CONFIG_UNIX98_PTY_COUNT 256 ++fi ++ ++bool 'Watchdog Timer Support' CONFIG_WATCHDOG ++dep_bool ' Disable watchdog shutdown on close' CONFIG_WATCHDOG_NOWAYOUT \ ++ $CONFIG_WATCHDOG ++dep_tristate ' Software Watchdog' CONFIG_SOFT_WATCHDOG $CONFIG_WATCHDOG ++dep_tristate ' UML watchdog' CONFIG_UML_WATCHDOG $CONFIG_WATCHDOG ++ ++tristate 'Sound support' CONFIG_UML_SOUND ++define_tristate CONFIG_SOUND $CONFIG_UML_SOUND ++define_tristate CONFIG_HOSTAUDIO $CONFIG_UML_SOUND ++ ++bool 'Enable tty logging' CONFIG_TTY_LOG ++ ++endmenu +diff -Naur -X ../exclude-files orig/arch/um/config.in um/arch/um/config.in +--- orig/arch/um/config.in 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/config.in 2003-12-14 11:34:02.000000000 -0500 +@@ -0,0 +1,105 @@ ++define_bool CONFIG_USERMODE y ++ ++mainmenu_name "Linux/Usermode Kernel Configuration" ++ ++define_bool CONFIG_ISA n ++define_bool CONFIG_SBUS n ++define_bool CONFIG_PCI n ++ ++define_bool CONFIG_UID16 y ++ ++define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y ++ ++mainmenu_option next_comment ++comment 'Code maturity level options' ++bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL ++endmenu ++ ++mainmenu_option next_comment ++comment 'General Setup' ++ ++bool 'Separate kernel address space support' CONFIG_MODE_SKAS ++ ++# This is to ensure that at least one of the modes is enabled. When neither ++# is present in defconfig, they default to N, which is bad. ++if [ "$CONFIG_MODE_SKAS" != "y" ]; then ++ define_bool CONFIG_MODE_TT y ++fi ++ ++bool 'Tracing thread support' CONFIG_MODE_TT ++if [ "$CONFIG_MODE_TT" != "y" ]; then ++ bool 'Statically linked binary when CONFIG_MODE_TT is disabled' CONFIG_STATIC_LINK ++fi ++bool 'Networking support' CONFIG_NET ++bool 'System V IPC' CONFIG_SYSVIPC ++bool 'BSD Process Accounting' CONFIG_BSD_PROCESS_ACCT ++bool 'Sysctl support' CONFIG_SYSCTL ++tristate 'Kernel support for a.out binaries' CONFIG_BINFMT_AOUT ++tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF ++tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC ++tristate 'Host filesystem' CONFIG_HOSTFS ++tristate 'Honeypot proc filesystem' CONFIG_HPPFS ++bool 'Management console' CONFIG_MCONSOLE ++dep_bool 'Magic SysRq key' CONFIG_MAGIC_SYSRQ $CONFIG_MCONSOLE ++bool '2G/2G host address space split' CONFIG_HOST_2G_2G ++bool 'Symmetric multi-processing support' CONFIG_UML_SMP ++define_bool CONFIG_SMP $CONFIG_UML_SMP ++int 'Nesting level' CONFIG_NEST_LEVEL 0 ++int 'Kernel address space size (in .5G units)' CONFIG_KERNEL_HALF_GIGS 1 ++bool 'Highmem support' CONFIG_HIGHMEM ++bool '/proc/mm' CONFIG_PROC_MM ++int 'Kernel stack size order' CONFIG_KERNEL_STACK_ORDER 2 ++bool 'Real-time Clock' CONFIG_UML_REAL_TIME_CLOCK ++endmenu ++ ++mainmenu_option next_comment ++comment 'Loadable module support' ++bool 'Enable loadable module support' CONFIG_MODULES ++if [ "$CONFIG_MODULES" = "y" ]; then ++# MODVERSIONS does not yet work in this architecture ++# bool ' Set version information on all module symbols' CONFIG_MODVERSIONS ++ bool ' Kernel module loader' CONFIG_KMOD ++fi ++endmenu ++ ++source arch/um/config_char.in ++ ++source arch/um/config_block.in ++ ++define_bool CONFIG_NETDEVICES $CONFIG_NET ++ ++if [ "$CONFIG_NET" = "y" ]; then ++ source arch/um/config_net.in ++ source net/Config.in ++fi ++ ++source fs/Config.in ++ ++mainmenu_option next_comment ++comment 'SCSI support' ++ ++tristate 'SCSI support' CONFIG_SCSI ++ ++if [ "$CONFIG_SCSI" != "n" ]; then ++ source arch/um/config_scsi.in ++fi ++endmenu ++ ++source drivers/md/Config.in ++ ++source drivers/mtd/Config.in ++ ++source lib/Config.in ++ ++mainmenu_option next_comment ++comment 'Kernel hacking' ++bool 'Debug memory allocations' CONFIG_DEBUG_SLAB ++bool 'Enable kernel debugging symbols' CONFIG_DEBUGSYM ++if [ "$CONFIG_XTERM_CHAN" = "y" ]; then ++ dep_bool 'Enable ptrace proxy' CONFIG_PT_PROXY $CONFIG_DEBUGSYM ++else ++ define_bool CONFIG_PT_PROXY n ++fi ++dep_bool 'Enable gprof support' CONFIG_GPROF $CONFIG_DEBUGSYM ++dep_bool 'Enable gcov support' CONFIG_GCOV $CONFIG_DEBUGSYM ++endmenu +diff -Naur -X ../exclude-files orig/arch/um/config_net.in um/arch/um/config_net.in +--- orig/arch/um/config_net.in 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/config_net.in 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,47 @@ ++mainmenu_option next_comment ++comment 'Network Devices' ++ ++# UML virtual driver ++bool 'Virtual network device' CONFIG_UML_NET ++ ++dep_bool ' Ethertap transport' CONFIG_UML_NET_ETHERTAP $CONFIG_UML_NET ++dep_bool ' TUN/TAP transport' CONFIG_UML_NET_TUNTAP $CONFIG_UML_NET ++dep_bool ' SLIP transport' CONFIG_UML_NET_SLIP $CONFIG_UML_NET ++dep_bool ' SLiRP transport' CONFIG_UML_NET_SLIRP $CONFIG_UML_NET ++dep_bool ' Daemon transport' CONFIG_UML_NET_DAEMON $CONFIG_UML_NET ++dep_bool ' Multicast transport' CONFIG_UML_NET_MCAST $CONFIG_UML_NET ++dep_bool ' pcap transport' CONFIG_UML_NET_PCAP $CONFIG_UML_NET ++ ++# Below are hardware-independent drivers mirrored from ++# drivers/net/Config.in. It would be nice if Linux ++# had HW independent drivers separated from the other ++# but it does not. Until then each non-ISA/PCI arch ++# needs to provide it's own menu of network drivers ++ ++tristate 'Dummy net driver support' CONFIG_DUMMY ++tristate 'Bonding driver support' CONFIG_BONDING ++tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER ++tristate 'Universal TUN/TAP device driver support' CONFIG_TUN ++if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then ++ if [ "$CONFIG_NETLINK" = "y" ]; then ++ tristate 'Ethertap network tap (OBSOLETE)' CONFIG_ETHERTAP ++ fi ++fi ++ ++tristate 'PPP (point-to-point protocol) support' CONFIG_PPP ++if [ ! "$CONFIG_PPP" = "n" ]; then ++ dep_bool ' PPP multilink support (EXPERIMENTAL)' CONFIG_PPP_MULTILINK $CONFIG_EXPERIMENTAL ++ dep_bool ' PPP filtering' CONFIG_PPP_FILTER $CONFIG_FILTER ++ dep_tristate ' PPP support for async serial ports' CONFIG_PPP_ASYNC $CONFIG_PPP ++ dep_tristate ' PPP support for sync tty ports' CONFIG_PPP_SYNC_TTY $CONFIG_PPP ++ dep_tristate ' PPP Deflate compression' CONFIG_PPP_DEFLATE $CONFIG_PPP ++ dep_tristate ' PPP BSD-Compress compression' CONFIG_PPP_BSDCOMP $CONFIG_PPP ++ dep_tristate ' PPP over Ethernet (EXPERIMENTAL)' CONFIG_PPPOE $CONFIG_PPP $CONFIG_EXPERIMENTAL ++fi ++ ++tristate 'SLIP (serial line) support' CONFIG_SLIP ++dep_bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED $CONFIG_SLIP ++dep_bool ' Keepalive and linefill' CONFIG_SLIP_SMART $CONFIG_SLIP ++dep_bool ' Six bit SLIP encapsulation' CONFIG_SLIP_MODE_SLIP6 $CONFIG_SLIP ++ ++endmenu +diff -Naur -X ../exclude-files orig/arch/um/config.release um/arch/um/config.release +--- orig/arch/um/config.release 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/config.release 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,302 @@ ++# ++# Automatically generated make config: don't edit ++# ++CONFIG_USERMODE=y ++# CONFIG_ISA is not set ++# CONFIG_SBUS is not set ++# CONFIG_PCI is not set ++CONFIG_UID16=y ++CONFIG_RWSEM_XCHGADD_ALGORITHM=y ++ ++# ++# Code maturity level options ++# ++CONFIG_EXPERIMENTAL=y ++ ++# ++# General Setup ++# ++CONFIG_NET=y ++CONFIG_SYSVIPC=y ++CONFIG_BSD_PROCESS_ACCT=y ++CONFIG_SYSCTL=y ++CONFIG_BINFMT_AOUT=y ++CONFIG_BINFMT_ELF=y ++CONFIG_BINFMT_MISC=y ++CONFIG_HOSTFS=y ++# CONFIG_HPPFS is not set ++CONFIG_MCONSOLE=y ++CONFIG_MAGIC_SYSRQ=y ++# CONFIG_HOST_2G_2G is not set ++# CONFIG_UML_SMP is not set ++# CONFIG_SMP is not set ++CONFIG_NEST_LEVEL=0 ++CONFIG_KERNEL_HALF_GIGS=1 ++ ++# ++# Loadable module support ++# ++CONFIG_MODULES=y ++CONFIG_KMOD=y ++ ++# ++# Character Devices ++# ++CONFIG_STDIO_CONSOLE=y ++CONFIG_SSL=y ++CONFIG_FD_CHAN=y ++# CONFIG_NULL_CHAN is not set ++CONFIG_PORT_CHAN=y ++CONFIG_PTY_CHAN=y ++CONFIG_TTY_CHAN=y ++CONFIG_XTERM_CHAN=y ++CONFIG_CON_ZERO_CHAN="fd:0,fd:1" ++CONFIG_CON_CHAN="xterm" ++CONFIG_SSL_CHAN="pty" ++CONFIG_UNIX98_PTYS=y ++CONFIG_UNIX98_PTY_COUNT=256 ++# CONFIG_WATCHDOG is not set ++CONFIG_UML_SOUND=y ++CONFIG_SOUND=y ++CONFIG_HOSTAUDIO=y ++# CONFIG_TTY_LOG is not set ++ ++# ++# Block Devices ++# ++CONFIG_BLK_DEV_UBD=y ++# CONFIG_BLK_DEV_UBD_SYNC is not set ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_BLK_DEV_NBD=y ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_SIZE=4096 ++CONFIG_BLK_DEV_INITRD=y ++# CONFIG_MMAPPER is not set ++CONFIG_NETDEVICES=y ++ ++# ++# Network Devices ++# ++CONFIG_UML_NET=y ++CONFIG_UML_NET_ETHERTAP=y ++CONFIG_UML_NET_TUNTAP=y ++CONFIG_UML_NET_SLIP=y ++CONFIG_UML_NET_DAEMON=y ++CONFIG_UML_NET_MCAST=y ++CONFIG_DUMMY=y ++CONFIG_BONDING=m ++CONFIG_EQUALIZER=m ++CONFIG_TUN=y ++CONFIG_PPP=m ++CONFIG_PPP_MULTILINK=y ++# CONFIG_PPP_ASYNC is not set ++CONFIG_PPP_SYNC_TTY=m ++CONFIG_PPP_DEFLATE=m ++CONFIG_PPP_BSDCOMP=m ++CONFIG_PPPOE=m ++CONFIG_SLIP=m ++ ++# ++# Networking options ++# ++CONFIG_PACKET=y ++CONFIG_PACKET_MMAP=y ++# CONFIG_NETLINK_DEV is not set ++# CONFIG_NETFILTER is not set ++# CONFIG_FILTER is not set ++CONFIG_UNIX=y ++CONFIG_INET=y ++# CONFIG_IP_MULTICAST is not set ++# CONFIG_IP_ADVANCED_ROUTER is not set ++# CONFIG_IP_PNP is not set ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE is not set ++# CONFIG_ARPD is not set ++# CONFIG_INET_ECN is not set ++# CONFIG_SYN_COOKIES is not set ++# CONFIG_IPV6 is not set ++# CONFIG_KHTTPD is not set ++# CONFIG_ATM is not set ++# CONFIG_VLAN_8021Q is not set ++ ++# ++# ++# ++# CONFIG_IPX is not set ++# CONFIG_ATALK is not set ++ ++# ++# Appletalk devices ++# ++# CONFIG_DECNET is not set ++# CONFIG_BRIDGE is not set ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_LLC is not set ++# CONFIG_NET_DIVERT is not set ++# CONFIG_ECONET is not set ++# CONFIG_WAN_ROUTER is not set ++# CONFIG_NET_FASTROUTE is not set ++# CONFIG_NET_HW_FLOWCONTROL is not set ++ ++# ++# QoS and/or fair queueing ++# ++# CONFIG_NET_SCHED is not set ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++ ++# ++# File systems ++# ++CONFIG_QUOTA=y ++CONFIG_AUTOFS_FS=m ++CONFIG_AUTOFS4_FS=m ++CONFIG_REISERFS_FS=m ++# CONFIG_REISERFS_CHECK is not set ++# CONFIG_REISERFS_PROC_INFO is not set ++CONFIG_ADFS_FS=m ++# CONFIG_ADFS_FS_RW is not set ++CONFIG_AFFS_FS=m ++CONFIG_HFS_FS=m ++CONFIG_BFS_FS=m ++CONFIG_EXT3_FS=y ++CONFIG_JBD=y ++# CONFIG_JBD_DEBUG is not set ++CONFIG_FAT_FS=y ++CONFIG_MSDOS_FS=y ++CONFIG_UMSDOS_FS=y ++CONFIG_VFAT_FS=y ++CONFIG_EFS_FS=m ++CONFIG_CRAMFS=m ++CONFIG_TMPFS=y ++CONFIG_RAMFS=y ++CONFIG_ISO9660_FS=y ++# CONFIG_JOLIET is not set ++# CONFIG_ZISOFS is not set ++CONFIG_MINIX_FS=m ++CONFIG_VXFS_FS=m ++# CONFIG_NTFS_FS is not set ++CONFIG_HPFS_FS=m ++CONFIG_PROC_FS=y ++CONFIG_DEVFS_FS=y ++CONFIG_DEVFS_MOUNT=y ++# CONFIG_DEVFS_DEBUG is not set ++CONFIG_DEVPTS_FS=y ++CONFIG_QNX4FS_FS=m ++# CONFIG_QNX4FS_RW is not set ++CONFIG_ROMFS_FS=m ++CONFIG_EXT2_FS=y ++CONFIG_SYSV_FS=m ++CONFIG_UDF_FS=m ++# CONFIG_UDF_RW is not set ++CONFIG_UFS_FS=m ++# CONFIG_UFS_FS_WRITE is not set ++ ++# ++# Network File Systems ++# ++# CONFIG_CODA_FS is not set ++# CONFIG_INTERMEZZO_FS is not set ++CONFIG_NFS_FS=y ++CONFIG_NFS_V3=y ++CONFIG_NFSD=y ++CONFIG_NFSD_V3=y ++CONFIG_SUNRPC=y ++CONFIG_LOCKD=y ++CONFIG_LOCKD_V4=y ++# CONFIG_SMB_FS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_ZISOFS_FS is not set ++CONFIG_ZLIB_FS_INFLATE=m ++ ++# ++# Partition Types ++# ++# CONFIG_PARTITION_ADVANCED is not set ++CONFIG_MSDOS_PARTITION=y ++# CONFIG_SMB_NLS is not set ++CONFIG_NLS=y ++ ++# ++# Native Language Support ++# ++CONFIG_NLS_DEFAULT="iso8859-1" ++# CONFIG_NLS_CODEPAGE_437 is not set ++# CONFIG_NLS_CODEPAGE_737 is not set ++# CONFIG_NLS_CODEPAGE_775 is not set ++# CONFIG_NLS_CODEPAGE_850 is not set ++# CONFIG_NLS_CODEPAGE_852 is not set ++# CONFIG_NLS_CODEPAGE_855 is not set ++# CONFIG_NLS_CODEPAGE_857 is not set ++# CONFIG_NLS_CODEPAGE_860 is not set ++# CONFIG_NLS_CODEPAGE_861 is not set ++# CONFIG_NLS_CODEPAGE_862 is not set ++# CONFIG_NLS_CODEPAGE_863 is not set ++# CONFIG_NLS_CODEPAGE_864 is not set ++# CONFIG_NLS_CODEPAGE_865 is not set ++# CONFIG_NLS_CODEPAGE_866 is not set ++# CONFIG_NLS_CODEPAGE_869 is not set ++# CONFIG_NLS_CODEPAGE_936 is not set ++# CONFIG_NLS_CODEPAGE_950 is not set ++# CONFIG_NLS_CODEPAGE_932 is not set ++# CONFIG_NLS_CODEPAGE_949 is not set ++# CONFIG_NLS_CODEPAGE_874 is not set ++# CONFIG_NLS_ISO8859_8 is not set ++# CONFIG_NLS_CODEPAGE_1250 is not set ++# CONFIG_NLS_CODEPAGE_1251 is not set ++# CONFIG_NLS_ISO8859_1 is not set ++# CONFIG_NLS_ISO8859_2 is not set ++# CONFIG_NLS_ISO8859_3 is not set ++# CONFIG_NLS_ISO8859_4 is not set ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++# CONFIG_NLS_UTF8 is not set ++ ++# ++# SCSI support ++# ++CONFIG_SCSI=y ++ ++# ++# SCSI support type (disk, tape, CD-ROM) ++# ++# CONFIG_BLK_DEV_SD is not set ++# CONFIG_CHR_DEV_ST is not set ++# CONFIG_BLK_DEV_SR is not set ++# CONFIG_CHR_DEV_SG is not set ++ ++# ++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs ++# ++# CONFIG_SCSI_DEBUG_QUEUES is not set ++# CONFIG_SCSI_MULTI_LUN is not set ++# CONFIG_SCSI_CONSTANTS is not set ++# CONFIG_SCSI_LOGGING is not set ++CONFIG_SCSI_DEBUG=m ++ ++# ++# Multi-device support (RAID and LVM) ++# ++# CONFIG_MD is not set ++ ++# ++# Memory Technology Devices (MTD) ++# ++# CONFIG_MTD is not set ++ ++# ++# Kernel hacking ++# ++# CONFIG_DEBUG_SLAB is not set ++# CONFIG_DEBUGSYM is not set +diff -Naur -X ../exclude-files orig/arch/um/config_scsi.in um/arch/um/config_scsi.in +--- orig/arch/um/config_scsi.in 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/config_scsi.in 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,30 @@ ++comment 'SCSI support type (disk, tape, CD-ROM)' ++ ++dep_tristate ' SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI ++ ++if [ "$CONFIG_BLK_DEV_SD" != "n" ]; then ++ int 'Maximum number of SCSI disks that can be loaded as modules' CONFIG_SD_EXTRA_DEVS 40 ++fi ++ ++dep_tristate ' SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI ++ ++dep_tristate ' SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI ++ ++if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then ++ bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR ++ int 'Maximum number of CDROM devices that can be loaded as modules' CONFIG_SR_EXTRA_DEVS 2 ++fi ++dep_tristate ' SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI ++ ++comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' ++ ++#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then ++ bool ' Enable extra checks in new queueing code' CONFIG_SCSI_DEBUG_QUEUES ++#fi ++ ++bool ' Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN ++ ++bool ' Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS ++bool ' SCSI logging facility' CONFIG_SCSI_LOGGING ++ ++dep_tristate 'SCSI debugging host simulator (EXPERIMENTAL)' CONFIG_SCSI_DEBUG $CONFIG_SCSI +diff -Naur -X ../exclude-files orig/arch/um/defconfig um/arch/um/defconfig +--- orig/arch/um/defconfig 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/defconfig 2003-12-17 02:15:39.000000000 -0500 +@@ -0,0 +1,423 @@ ++# ++# Automatically generated make config: don't edit ++# ++CONFIG_USERMODE=y ++# CONFIG_ISA is not set ++# CONFIG_SBUS is not set ++# CONFIG_PCI is not set ++CONFIG_UID16=y ++CONFIG_RWSEM_XCHGADD_ALGORITHM=y ++ ++# ++# Code maturity level options ++# ++CONFIG_EXPERIMENTAL=y ++ ++# ++# General Setup ++# ++CONFIG_MODE_SKAS=y ++CONFIG_MODE_TT=y ++CONFIG_NET=y ++CONFIG_SYSVIPC=y ++CONFIG_BSD_PROCESS_ACCT=y ++CONFIG_SYSCTL=y ++CONFIG_BINFMT_AOUT=y ++CONFIG_BINFMT_ELF=y ++CONFIG_BINFMT_MISC=y ++CONFIG_HOSTFS=y ++CONFIG_HPPFS=y ++CONFIG_MCONSOLE=y ++CONFIG_MAGIC_SYSRQ=y ++# CONFIG_HOST_2G_2G is not set ++# CONFIG_UML_SMP is not set ++# CONFIG_SMP is not set ++CONFIG_NEST_LEVEL=0 ++CONFIG_KERNEL_HALF_GIGS=1 ++# CONFIG_HIGHMEM is not set ++CONFIG_PROC_MM=y ++CONFIG_KERNEL_STACK_ORDER=2 ++CONFIG_UML_REAL_TIME_CLOCK=y ++ ++# ++# Loadable module support ++# ++CONFIG_MODULES=y ++# CONFIG_KMOD is not set ++ ++# ++# Character Devices ++# ++CONFIG_STDIO_CONSOLE=y ++CONFIG_SSL=y ++CONFIG_FD_CHAN=y ++CONFIG_NULL_CHAN=y ++CONFIG_PORT_CHAN=y ++CONFIG_PTY_CHAN=y ++CONFIG_TTY_CHAN=y ++CONFIG_XTERM_CHAN=y ++CONFIG_CON_ZERO_CHAN="fd:0,fd:1" ++CONFIG_CON_CHAN="xterm" ++CONFIG_SSL_CHAN="pty" ++CONFIG_UNIX98_PTYS=y ++CONFIG_UNIX98_PTY_COUNT=256 ++# CONFIG_WATCHDOG is not set ++# CONFIG_WATCHDOG_NOWAYOUT is not set ++# CONFIG_SOFT_WATCHDOG is not set ++# CONFIG_UML_WATCHDOG is not set ++CONFIG_UML_SOUND=y ++CONFIG_SOUND=y ++CONFIG_HOSTAUDIO=y ++# CONFIG_TTY_LOG is not set ++ ++# ++# Block Devices ++# ++CONFIG_BLK_DEV_UBD=y ++# CONFIG_BLK_DEV_UBD_SYNC is not set ++# CONFIG_COW is not set ++CONFIG_COW_COMMON=y ++CONFIG_BLK_DEV_LOOP=y ++CONFIG_BLK_DEV_NBD=y ++CONFIG_BLK_DEV_RAM=y ++CONFIG_BLK_DEV_RAM_SIZE=4096 ++CONFIG_BLK_DEV_INITRD=y ++# CONFIG_MMAPPER is not set ++CONFIG_NETDEVICES=y ++ ++# ++# Network Devices ++# ++CONFIG_UML_NET=y ++CONFIG_UML_NET_ETHERTAP=y ++CONFIG_UML_NET_TUNTAP=y ++CONFIG_UML_NET_SLIP=y ++CONFIG_UML_NET_SLIRP=y ++CONFIG_UML_NET_DAEMON=y ++CONFIG_UML_NET_MCAST=y ++# CONFIG_UML_NET_PCAP is not set ++CONFIG_DUMMY=y ++# CONFIG_BONDING is not set ++# CONFIG_EQUALIZER is not set ++CONFIG_TUN=y ++CONFIG_PPP=y ++# CONFIG_PPP_MULTILINK is not set ++# CONFIG_PPP_FILTER is not set ++# CONFIG_PPP_ASYNC is not set ++# CONFIG_PPP_SYNC_TTY is not set ++# CONFIG_PPP_DEFLATE is not set ++# CONFIG_PPP_BSDCOMP is not set ++# CONFIG_PPPOE is not set ++CONFIG_SLIP=y ++# CONFIG_SLIP_COMPRESSED is not set ++# CONFIG_SLIP_SMART is not set ++# CONFIG_SLIP_MODE_SLIP6 is not set ++ ++# ++# Networking options ++# ++CONFIG_PACKET=y ++CONFIG_PACKET_MMAP=y ++# CONFIG_NETLINK_DEV is not set ++# CONFIG_NETFILTER is not set ++# CONFIG_FILTER is not set ++CONFIG_UNIX=y ++CONFIG_INET=y ++# CONFIG_IP_MULTICAST is not set ++# CONFIG_IP_ADVANCED_ROUTER is not set ++# CONFIG_IP_PNP is not set ++# CONFIG_NET_IPIP is not set ++# CONFIG_NET_IPGRE is not set ++# CONFIG_ARPD is not set ++# CONFIG_INET_ECN is not set ++# CONFIG_SYN_COOKIES is not set ++# CONFIG_IPV6 is not set ++# CONFIG_KHTTPD is not set ++ ++# ++# SCTP Configuration (EXPERIMENTAL) ++# ++CONFIG_IPV6_SCTP__=y ++# CONFIG_IP_SCTP is not set ++# CONFIG_ATM is not set ++# CONFIG_VLAN_8021Q is not set ++ ++# ++# ++# ++# CONFIG_IPX is not set ++# CONFIG_ATALK is not set ++ ++# ++# Appletalk devices ++# ++# CONFIG_DEV_APPLETALK is not set ++# CONFIG_DECNET is not set ++# CONFIG_BRIDGE is not set ++# CONFIG_X25 is not set ++# CONFIG_LAPB is not set ++# CONFIG_LLC is not set ++# CONFIG_NET_DIVERT is not set ++# CONFIG_ECONET is not set ++# CONFIG_WAN_ROUTER is not set ++# CONFIG_NET_FASTROUTE is not set ++# CONFIG_NET_HW_FLOWCONTROL is not set ++ ++# ++# QoS and/or fair queueing ++# ++# CONFIG_NET_SCHED is not set ++ ++# ++# Network testing ++# ++# CONFIG_NET_PKTGEN is not set ++ ++# ++# File systems ++# ++CONFIG_QUOTA=y ++# CONFIG_QFMT_V2 is not set ++CONFIG_AUTOFS_FS=y ++CONFIG_AUTOFS4_FS=y ++CONFIG_REISERFS_FS=y ++# CONFIG_REISERFS_CHECK is not set ++# CONFIG_REISERFS_PROC_INFO is not set ++# CONFIG_ADFS_FS is not set ++# CONFIG_ADFS_FS_RW is not set ++# CONFIG_AFFS_FS is not set ++# CONFIG_HFS_FS is not set ++# CONFIG_HFSPLUS_FS is not set ++# CONFIG_BEFS_FS is not set ++# CONFIG_BEFS_DEBUG is not set ++# CONFIG_BFS_FS is not set ++# CONFIG_EXT3_FS is not set ++# CONFIG_JBD is not set ++# CONFIG_JBD_DEBUG is not set ++CONFIG_FAT_FS=y ++CONFIG_MSDOS_FS=y ++CONFIG_UMSDOS_FS=y ++CONFIG_VFAT_FS=y ++# CONFIG_EFS_FS is not set ++CONFIG_JFFS_FS=y ++CONFIG_JFFS_FS_VERBOSE=0 ++CONFIG_JFFS_PROC_FS=y ++CONFIG_JFFS2_FS=y ++CONFIG_JFFS2_FS_DEBUG=0 ++# CONFIG_CRAMFS is not set ++# CONFIG_TMPFS is not set ++CONFIG_RAMFS=y ++CONFIG_ISO9660_FS=y ++# CONFIG_JOLIET is not set ++# CONFIG_ZISOFS is not set ++# CONFIG_JFS_FS is not set ++# CONFIG_JFS_DEBUG is not set ++# CONFIG_JFS_STATISTICS is not set ++CONFIG_MINIX_FS=y ++# CONFIG_VXFS_FS is not set ++# CONFIG_NTFS_FS is not set ++# CONFIG_NTFS_RW is not set ++# CONFIG_HPFS_FS is not set ++CONFIG_PROC_FS=y ++CONFIG_DEVFS_FS=y ++CONFIG_DEVFS_MOUNT=y ++# CONFIG_DEVFS_DEBUG is not set ++CONFIG_DEVPTS_FS=y ++# CONFIG_QNX4FS_FS is not set ++# CONFIG_QNX4FS_RW is not set ++# CONFIG_ROMFS_FS is not set ++CONFIG_EXT2_FS=y ++# CONFIG_SYSV_FS is not set ++# CONFIG_UDF_FS is not set ++# CONFIG_UDF_RW is not set ++# CONFIG_UFS_FS is not set ++# CONFIG_UFS_FS_WRITE is not set ++ ++# ++# Network File Systems ++# ++# CONFIG_CODA_FS is not set ++# CONFIG_INTERMEZZO_FS is not set ++# CONFIG_NFS_FS is not set ++# CONFIG_NFS_V3 is not set ++# CONFIG_NFS_DIRECTIO is not set ++# CONFIG_ROOT_NFS is not set ++# CONFIG_NFSD is not set ++# CONFIG_NFSD_V3 is not set ++# CONFIG_NFSD_TCP is not set ++# CONFIG_SUNRPC is not set ++# CONFIG_LOCKD is not set ++# CONFIG_SMB_FS is not set ++# CONFIG_NCP_FS is not set ++# CONFIG_NCPFS_PACKET_SIGNING is not set ++# CONFIG_NCPFS_IOCTL_LOCKING is not set ++# CONFIG_NCPFS_STRONG is not set ++# CONFIG_NCPFS_NFS_NS is not set ++# CONFIG_NCPFS_OS2_NS is not set ++# CONFIG_NCPFS_SMALLDOS is not set ++# CONFIG_NCPFS_NLS is not set ++# CONFIG_NCPFS_EXTRAS is not set ++# CONFIG_ZISOFS_FS is not set ++ ++# ++# Partition Types ++# ++# CONFIG_PARTITION_ADVANCED is not set ++CONFIG_MSDOS_PARTITION=y ++# CONFIG_SMB_NLS is not set ++CONFIG_NLS=y ++ ++# ++# Native Language Support ++# ++CONFIG_NLS_DEFAULT="iso8859-1" ++# CONFIG_NLS_CODEPAGE_437 is not set ++# CONFIG_NLS_CODEPAGE_737 is not set ++# CONFIG_NLS_CODEPAGE_775 is not set ++# CONFIG_NLS_CODEPAGE_850 is not set ++# CONFIG_NLS_CODEPAGE_852 is not set ++# CONFIG_NLS_CODEPAGE_855 is not set ++# CONFIG_NLS_CODEPAGE_857 is not set ++# CONFIG_NLS_CODEPAGE_860 is not set ++# CONFIG_NLS_CODEPAGE_861 is not set ++# CONFIG_NLS_CODEPAGE_862 is not set ++# CONFIG_NLS_CODEPAGE_863 is not set ++# CONFIG_NLS_CODEPAGE_864 is not set ++# CONFIG_NLS_CODEPAGE_865 is not set ++# CONFIG_NLS_CODEPAGE_866 is not set ++# CONFIG_NLS_CODEPAGE_869 is not set ++# CONFIG_NLS_CODEPAGE_936 is not set ++# CONFIG_NLS_CODEPAGE_950 is not set ++# CONFIG_NLS_CODEPAGE_932 is not set ++# CONFIG_NLS_CODEPAGE_949 is not set ++# CONFIG_NLS_CODEPAGE_874 is not set ++# CONFIG_NLS_ISO8859_8 is not set ++# CONFIG_NLS_CODEPAGE_1250 is not set ++# CONFIG_NLS_CODEPAGE_1251 is not set ++# CONFIG_NLS_ISO8859_1 is not set ++# CONFIG_NLS_ISO8859_2 is not set ++# CONFIG_NLS_ISO8859_3 is not set ++# CONFIG_NLS_ISO8859_4 is not set ++# CONFIG_NLS_ISO8859_5 is not set ++# CONFIG_NLS_ISO8859_6 is not set ++# CONFIG_NLS_ISO8859_7 is not set ++# CONFIG_NLS_ISO8859_9 is not set ++# CONFIG_NLS_ISO8859_13 is not set ++# CONFIG_NLS_ISO8859_14 is not set ++# CONFIG_NLS_ISO8859_15 is not set ++# CONFIG_NLS_KOI8_R is not set ++# CONFIG_NLS_KOI8_U is not set ++# CONFIG_NLS_UTF8 is not set ++ ++# ++# SCSI support ++# ++CONFIG_SCSI=y ++ ++# ++# SCSI support type (disk, tape, CD-ROM) ++# ++# CONFIG_BLK_DEV_SD is not set ++# CONFIG_CHR_DEV_ST is not set ++# CONFIG_BLK_DEV_SR is not set ++# CONFIG_CHR_DEV_SG is not set ++ ++# ++# Some SCSI devices (e.g. CD jukebox) support multiple LUNs ++# ++# CONFIG_SCSI_DEBUG_QUEUES is not set ++# CONFIG_SCSI_MULTI_LUN is not set ++# CONFIG_SCSI_CONSTANTS is not set ++# CONFIG_SCSI_LOGGING is not set ++CONFIG_SCSI_DEBUG=y ++ ++# ++# Multi-device support (RAID and LVM) ++# ++# CONFIG_MD is not set ++# CONFIG_BLK_DEV_MD is not set ++# CONFIG_MD_LINEAR is not set ++# CONFIG_MD_RAID0 is not set ++# CONFIG_MD_RAID1 is not set ++# CONFIG_MD_RAID5 is not set ++# CONFIG_MD_MULTIPATH is not set ++# CONFIG_BLK_DEV_LVM is not set ++ ++# ++# Memory Technology Devices (MTD) ++# ++CONFIG_MTD=y ++# CONFIG_MTD_DEBUG is not set ++# CONFIG_MTD_PARTITIONS is not set ++# CONFIG_MTD_CONCAT is not set ++# CONFIG_MTD_REDBOOT_PARTS is not set ++# CONFIG_MTD_CMDLINE_PARTS is not set ++ ++# ++# User Modules And Translation Layers ++# ++CONFIG_MTD_CHAR=y ++CONFIG_MTD_BLOCK=y ++# CONFIG_FTL is not set ++# CONFIG_NFTL is not set ++ ++# ++# RAM/ROM/Flash chip drivers ++# ++# CONFIG_MTD_CFI is not set ++# CONFIG_MTD_JEDECPROBE is not set ++# CONFIG_MTD_GEN_PROBE is not set ++# CONFIG_MTD_CFI_INTELEXT is not set ++# CONFIG_MTD_CFI_AMDSTD is not set ++# CONFIG_MTD_CFI_STAA is not set ++# CONFIG_MTD_RAM is not set ++# CONFIG_MTD_ROM is not set ++# CONFIG_MTD_ABSENT is not set ++# CONFIG_MTD_OBSOLETE_CHIPS is not set ++# CONFIG_MTD_AMDSTD is not set ++# CONFIG_MTD_SHARP is not set ++# CONFIG_MTD_JEDEC is not set ++ ++# ++# Mapping drivers for chip access ++# ++# CONFIG_MTD_PHYSMAP is not set ++# CONFIG_MTD_PCI is not set ++# CONFIG_MTD_PCMCIA is not set ++ ++# ++# Self-contained MTD device drivers ++# ++# CONFIG_MTD_PMC551 is not set ++# CONFIG_MTD_SLRAM is not set ++# CONFIG_MTD_MTDRAM is not set ++CONFIG_MTD_BLKMTD=y ++ ++# ++# Disk-On-Chip Device Drivers ++# ++# CONFIG_MTD_DOC1000 is not set ++# CONFIG_MTD_DOC2000 is not set ++# CONFIG_MTD_DOC2001 is not set ++# CONFIG_MTD_DOCPROBE is not set ++ ++# ++# NAND Flash Device Drivers ++# ++# CONFIG_MTD_NAND is not set ++ ++# ++# Library routines ++# ++# CONFIG_CRC32 is not set ++CONFIG_ZLIB_INFLATE=y ++CONFIG_ZLIB_DEFLATE=y ++ ++# ++# Kernel hacking ++# ++# CONFIG_DEBUG_SLAB is not set ++CONFIG_DEBUGSYM=y ++CONFIG_PT_PROXY=y ++# CONFIG_GPROF is not set ++# CONFIG_GCOV is not set +diff -Naur -X ../exclude-files orig/arch/um/drivers/chan_kern.c um/arch/um/drivers/chan_kern.c +--- orig/arch/um/drivers/chan_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/chan_kern.c 2003-11-07 07:25:34.000000000 -0500 +@@ -0,0 +1,519 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "chan_kern.h" ++#include "user_util.h" ++#include "kern.h" ++#include "irq_user.h" ++#include "sigio.h" ++#include "line.h" ++ ++static void *not_configged_init(char *str, int device, struct chan_opts *opts) ++{ ++ printk(KERN_ERR "Using a channel type which is configured out of " ++ "UML\n"); ++ return(NULL); ++} ++ ++static int not_configged_open(int input, int output, int primary, void *data, ++ char **dev_out) ++{ ++ printk(KERN_ERR "Using a channel type which is configured out of " ++ "UML\n"); ++ return(-ENODEV); ++} ++ ++static void not_configged_close(int fd, void *data) ++{ ++ printk(KERN_ERR "Using a channel type which is configured out of " ++ "UML\n"); ++} ++ ++static int not_configged_read(int fd, char *c_out, void *data) ++{ ++ printk(KERN_ERR "Using a channel type which is configured out of " ++ "UML\n"); ++ return(-EIO); ++} ++ ++static int not_configged_write(int fd, const char *buf, int len, void *data) ++{ ++ printk(KERN_ERR "Using a channel type which is configured out of " ++ "UML\n"); ++ return(-EIO); ++} ++ ++static int not_configged_console_write(int fd, const char *buf, int len, ++ void *data) ++{ ++ printk(KERN_ERR "Using a channel type which is configured out of " ++ "UML\n"); ++ return(-EIO); ++} ++ ++static int not_configged_window_size(int fd, void *data, unsigned short *rows, ++ unsigned short *cols) ++{ ++ printk(KERN_ERR "Using a channel type which is configured out of " ++ "UML\n"); ++ return(-ENODEV); ++} ++ ++static void not_configged_free(void *data) ++{ ++ printk(KERN_ERR "Using a channel type which is configured out of " ++ "UML\n"); ++} ++ ++static struct chan_ops not_configged_ops = { ++ .init = not_configged_init, ++ .open = not_configged_open, ++ .close = not_configged_close, ++ .read = not_configged_read, ++ .write = not_configged_write, ++ .console_write = not_configged_console_write, ++ .window_size = not_configged_window_size, ++ .free = not_configged_free, ++ .winch = 0, ++}; ++ ++static void tty_receive_char(struct tty_struct *tty, char ch) ++{ ++ if(tty == NULL) return; ++ ++ if(I_IXON(tty) && !I_IXOFF(tty) && !tty->raw) { ++ if(ch == STOP_CHAR(tty)){ ++ stop_tty(tty); ++ return; ++ } ++ else if(ch == START_CHAR(tty)){ ++ start_tty(tty); ++ return; ++ } ++ } ++ ++ if((tty->flip.flag_buf_ptr == NULL) || ++ (tty->flip.char_buf_ptr == NULL)) ++ return; ++ tty_insert_flip_char(tty, ch, TTY_NORMAL); ++} ++ ++static int open_one_chan(struct chan *chan, int input, int output, int primary) ++{ ++ int fd; ++ ++ if(chan->opened) return(0); ++ if(chan->ops->open == NULL) fd = 0; ++ else fd = (*chan->ops->open)(input, output, primary, chan->data, ++ &chan->dev); ++ if(fd < 0) return(fd); ++ chan->fd = fd; ++ ++ chan->opened = 1; ++ return(0); ++} ++ ++int open_chan(struct list_head *chans) ++{ ++ struct list_head *ele; ++ struct chan *chan; ++ int ret, err = 0; ++ ++ list_for_each(ele, chans){ ++ chan = list_entry(ele, struct chan, list); ++ ret = open_one_chan(chan, chan->input, chan->output, ++ chan->primary); ++ if(chan->primary) err = ret; ++ } ++ return(err); ++} ++ ++void chan_enable_winch(struct list_head *chans, void *line) ++{ ++ struct list_head *ele; ++ struct chan *chan; ++ ++ list_for_each(ele, chans){ ++ chan = list_entry(ele, struct chan, list); ++ if(chan->primary && chan->output && chan->ops->winch){ ++ register_winch(chan->fd, line); ++ return; ++ } ++ } ++} ++ ++void enable_chan(struct list_head *chans, void *data) ++{ ++ struct list_head *ele; ++ struct chan *chan; ++ ++ list_for_each(ele, chans){ ++ chan = list_entry(ele, struct chan, list); ++ if(!chan->opened) continue; ++ ++ line_setup_irq(chan->fd, chan->input, chan->output, data); ++ } ++} ++ ++void close_chan(struct list_head *chans) ++{ ++ struct list_head *ele; ++ struct chan *chan; ++ ++ /* Close in reverse order as open in case more than one of them ++ * refers to the same device and they save and restore that device's ++ * state. Then, the first one opened will have the original state, ++ * so it must be the last closed. ++ */ ++ for(ele = chans->prev; ele != chans; ele = ele->prev){ ++ chan = list_entry(ele, struct chan, list); ++ if(!chan->opened) continue; ++ if(chan->ops->close != NULL) ++ (*chan->ops->close)(chan->fd, chan->data); ++ chan->opened = 0; ++ chan->fd = -1; ++ } ++} ++ ++int write_chan(struct list_head *chans, const char *buf, int len, ++ int write_irq) ++{ ++ struct list_head *ele; ++ struct chan *chan; ++ int n, ret = 0; ++ ++ list_for_each(ele, chans){ ++ chan = list_entry(ele, struct chan, list); ++ if(!chan->output || (chan->ops->write == NULL)) continue; ++ n = chan->ops->write(chan->fd, buf, len, chan->data); ++ if(chan->primary){ ++ ret = n; ++ if((ret == -EAGAIN) || ((ret >= 0) && (ret < len))){ ++ reactivate_fd(chan->fd, write_irq); ++ if(ret == -EAGAIN) ret = 0; ++ } ++ } ++ } ++ return(ret); ++} ++ ++int console_write_chan(struct list_head *chans, const char *buf, int len) ++{ ++ struct list_head *ele; ++ struct chan *chan; ++ int n, ret = 0; ++ ++ list_for_each(ele, chans){ ++ chan = list_entry(ele, struct chan, list); ++ if(!chan->output || (chan->ops->console_write == NULL)) ++ continue; ++ n = chan->ops->console_write(chan->fd, buf, len, chan->data); ++ if(chan->primary) ret = n; ++ } ++ return(ret); ++} ++ ++int chan_window_size(struct list_head *chans, unsigned short *rows_out, ++ unsigned short *cols_out) ++{ ++ struct list_head *ele; ++ struct chan *chan; ++ ++ list_for_each(ele, chans){ ++ chan = list_entry(ele, struct chan, list); ++ if(chan->primary){ ++ if(chan->ops->window_size == NULL) return(0); ++ return(chan->ops->window_size(chan->fd, chan->data, ++ rows_out, cols_out)); ++ } ++ } ++ return(0); ++} ++ ++void free_one_chan(struct chan *chan) ++{ ++ list_del(&chan->list); ++ if(chan->ops->free != NULL) ++ (*chan->ops->free)(chan->data); ++ free_irq_by_fd(chan->fd); ++ if(chan->primary && chan->output) ignore_sigio_fd(chan->fd); ++ kfree(chan); ++} ++ ++void free_chan(struct list_head *chans) ++{ ++ struct list_head *ele, *next; ++ struct chan *chan; ++ ++ list_for_each_safe(ele, next, chans){ ++ chan = list_entry(ele, struct chan, list); ++ free_one_chan(chan); ++ } ++} ++ ++static int one_chan_config_string(struct chan *chan, char *str, int size, ++ char **error_out) ++{ ++ int n = 0; ++ ++ if(chan == NULL){ ++ CONFIG_CHUNK(str, size, n, "none", 1); ++ return(n); ++ } ++ ++ CONFIG_CHUNK(str, size, n, chan->ops->type, 0); ++ ++ if(chan->dev == NULL){ ++ CONFIG_CHUNK(str, size, n, "", 1); ++ return(n); ++ } ++ ++ CONFIG_CHUNK(str, size, n, ":", 0); ++ CONFIG_CHUNK(str, size, n, chan->dev, 0); ++ ++ return(n); ++} ++ ++static int chan_pair_config_string(struct chan *in, struct chan *out, ++ char *str, int size, char **error_out) ++{ ++ int n; ++ ++ n = one_chan_config_string(in, str, size, error_out); ++ str += n; ++ size -= n; ++ ++ if(in == out){ ++ CONFIG_CHUNK(str, size, n, "", 1); ++ return(n); ++ } ++ ++ CONFIG_CHUNK(str, size, n, ",", 1); ++ n = one_chan_config_string(out, str, size, error_out); ++ str += n; ++ size -= n; ++ CONFIG_CHUNK(str, size, n, "", 1); ++ ++ return(n); ++} ++ ++int chan_config_string(struct list_head *chans, char *str, int size, ++ char **error_out) ++{ ++ struct list_head *ele; ++ struct chan *chan, *in = NULL, *out = NULL; ++ ++ list_for_each(ele, chans){ ++ chan = list_entry(ele, struct chan, list); ++ if(!chan->primary) ++ continue; ++ if(chan->input) ++ in = chan; ++ if(chan->output) ++ out = chan; ++ } ++ ++ return(chan_pair_config_string(in, out, str, size, error_out)); ++} ++ ++struct chan_type { ++ char *key; ++ struct chan_ops *ops; ++}; ++ ++struct chan_type chan_table[] = { ++#ifdef CONFIG_FD_CHAN ++ { "fd", &fd_ops }, ++#else ++ { "fd", ¬_configged_ops }, ++#endif ++ ++#ifdef CONFIG_NULL_CHAN ++ { "null", &null_ops }, ++#else ++ { "null", ¬_configged_ops }, ++#endif ++ ++#ifdef CONFIG_PORT_CHAN ++ { "port", &port_ops }, ++#else ++ { "port", ¬_configged_ops }, ++#endif ++ ++#ifdef CONFIG_PTY_CHAN ++ { "pty", &pty_ops }, ++ { "pts", &pts_ops }, ++#else ++ { "pty", ¬_configged_ops }, ++ { "pts", ¬_configged_ops }, ++#endif ++ ++#ifdef CONFIG_TTY_CHAN ++ { "tty", &tty_ops }, ++#else ++ { "tty", ¬_configged_ops }, ++#endif ++ ++#ifdef CONFIG_XTERM_CHAN ++ { "xterm", &xterm_ops }, ++#else ++ { "xterm", ¬_configged_ops }, ++#endif ++}; ++ ++static struct chan *parse_chan(char *str, int pri, int device, ++ struct chan_opts *opts) ++{ ++ struct chan_type *entry; ++ struct chan_ops *ops; ++ struct chan *chan; ++ void *data; ++ int i; ++ ++ ops = NULL; ++ data = NULL; ++ for(i = 0; i < sizeof(chan_table)/sizeof(chan_table[0]); i++){ ++ entry = &chan_table[i]; ++ if(!strncmp(str, entry->key, strlen(entry->key))){ ++ ops = entry->ops; ++ str += strlen(entry->key); ++ break; ++ } ++ } ++ if(ops == NULL){ ++ printk(KERN_ERR "parse_chan couldn't parse \"%s\"\n", ++ str); ++ return(NULL); ++ } ++ if(ops->init == NULL) return(NULL); ++ data = (*ops->init)(str, device, opts); ++ if(data == NULL) return(NULL); ++ ++ chan = kmalloc(sizeof(*chan), GFP_KERNEL); ++ if(chan == NULL) return(NULL); ++ *chan = ((struct chan) { .list = LIST_HEAD_INIT(chan->list), ++ .primary = 1, ++ .input = 0, ++ .output = 0, ++ .opened = 0, ++ .fd = -1, ++ .pri = pri, ++ .ops = ops, ++ .data = data }); ++ return(chan); ++} ++ ++int parse_chan_pair(char *str, struct list_head *chans, int pri, int device, ++ struct chan_opts *opts) ++{ ++ struct chan *new, *chan; ++ char *in, *out; ++ ++ if(!list_empty(chans)){ ++ chan = list_entry(chans->next, struct chan, list); ++ if(chan->pri >= pri) return(0); ++ free_chan(chans); ++ INIT_LIST_HEAD(chans); ++ } ++ ++ out = strchr(str, ','); ++ if(out != NULL){ ++ in = str; ++ *out = '\0'; ++ out++; ++ new = parse_chan(in, pri, device, opts); ++ if(new == NULL) return(-1); ++ new->input = 1; ++ list_add(&new->list, chans); ++ ++ new = parse_chan(out, pri, device, opts); ++ if(new == NULL) return(-1); ++ list_add(&new->list, chans); ++ new->output = 1; ++ } ++ else { ++ new = parse_chan(str, pri, device, opts); ++ if(new == NULL) return(-1); ++ list_add(&new->list, chans); ++ new->input = 1; ++ new->output = 1; ++ } ++ return(0); ++} ++ ++int chan_out_fd(struct list_head *chans) ++{ ++ struct list_head *ele; ++ struct chan *chan; ++ ++ list_for_each(ele, chans){ ++ chan = list_entry(ele, struct chan, list); ++ if(chan->primary && chan->output) ++ return(chan->fd); ++ } ++ return(-1); ++} ++ ++void chan_interrupt(struct list_head *chans, struct tq_struct *task, ++ struct tty_struct *tty, int irq, void *dev) ++{ ++ struct list_head *ele, *next; ++ struct chan *chan; ++ int err; ++ char c; ++ ++ list_for_each_safe(ele, next, chans){ ++ chan = list_entry(ele, struct chan, list); ++ if(!chan->input || (chan->ops->read == NULL)) continue; ++ do { ++ if((tty != NULL) && ++ (tty->flip.count >= TTY_FLIPBUF_SIZE)){ ++ queue_task(task, &tq_timer); ++ goto out; ++ } ++ err = chan->ops->read(chan->fd, &c, chan->data); ++ if(err > 0) ++ tty_receive_char(tty, c); ++ } while(err > 0); ++ ++ if(err == 0) reactivate_fd(chan->fd, irq); ++ if(err == -EIO){ ++ if(chan->primary){ ++ if(tty != NULL) ++ tty_hangup(tty); ++ line_disable(dev, irq); ++ close_chan(chans); ++ free_chan(chans); ++ return; ++ } ++ else { ++ if(chan->ops->close != NULL) ++ chan->ops->close(chan->fd, chan->data); ++ free_one_chan(chan); ++ } ++ } ++ } ++ out: ++ if(tty) tty_flip_buffer_push(tty); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/chan_user.c um/arch/um/drivers/chan_user.c +--- orig/arch/um/drivers/chan_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/chan_user.c 2003-11-07 07:23:45.000000000 -0500 +@@ -0,0 +1,217 @@ ++/* ++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) ++ * Licensed under the GPL ++ */ ++ ++#include ++#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" ++ ++void generic_close(int fd, void *unused) ++{ ++ os_close_file(fd); ++} ++ ++int generic_read(int fd, char *c_out, void *unused) ++{ ++ int n; ++ ++ n = os_read_file(fd, c_out, sizeof(*c_out)); ++ ++ if(n == -EAGAIN) ++ return(0); ++ else if(n == 0) ++ return(-EIO); ++ return(n); ++} ++ ++/* XXX Trivial wrapper around os_write_file */ ++ ++int generic_write(int fd, const char *buf, int n, void *unused) ++{ ++ return(os_write_file(fd, buf, n)); ++} ++ ++int generic_console_write(int fd, const char *buf, int n, void *unused) ++{ ++ struct termios save, new; ++ int err; ++ ++ if(isatty(fd)){ ++ tcgetattr(fd, &save); ++ new = save; ++ new.c_oflag |= OPOST; ++ tcsetattr(fd, TCSAFLUSH, &new); ++ } ++ err = generic_write(fd, buf, n, NULL); ++ if(isatty(fd)) tcsetattr(fd, TCSAFLUSH, &save); ++ return(err); ++} ++ ++int generic_window_size(int fd, void *unused, unsigned short *rows_out, ++ unsigned short *cols_out) ++{ ++ int rows, cols; ++ int ret; ++ ++ ret = os_window_size(fd, &rows, &cols); ++ if(ret < 0) ++ return(ret); ++ ++ ret = ((*rows_out != rows) || (*cols_out != cols)); ++ ++ *rows_out = rows; ++ *cols_out = cols; ++ ++ return(ret); ++} ++ ++void generic_free(void *data) ++{ ++ kfree(data); ++} ++ ++static void winch_handler(int sig) ++{ ++} ++ ++struct winch_data { ++ int pty_fd; ++ int pipe_fd; ++ int close_me; ++}; ++ ++static int winch_thread(void *arg) ++{ ++ struct winch_data *data = arg; ++ sigset_t sigs; ++ int pty_fd, pipe_fd; ++ int count, err; ++ char c = 1; ++ ++ os_close_file(data->close_me); ++ pty_fd = data->pty_fd; ++ pipe_fd = data->pipe_fd; ++ count = os_write_file(pipe_fd, &c, sizeof(c)); ++ if(count != sizeof(c)) ++ printk("winch_thread : failed to write synchronization " ++ "byte, err = %d\n", -count); ++ ++ signal(SIGWINCH, winch_handler); ++ sigfillset(&sigs); ++ sigdelset(&sigs, SIGWINCH); ++ if(sigprocmask(SIG_SETMASK, &sigs, NULL) < 0){ ++ printk("winch_thread : sigprocmask failed, errno = %d\n", ++ errno); ++ exit(1); ++ } ++ ++ if(setsid() < 0){ ++ printk("winch_thread : setsid failed, errno = %d\n", errno); ++ exit(1); ++ } ++ ++ err = os_new_tty_pgrp(pty_fd, os_getpid()); ++ if(err < 0){ ++ printk("winch_thread : new_tty_pgrp failed, err = %d\n", -err); ++ exit(1); ++ } ++ ++ count = os_read_file(pipe_fd, &c, sizeof(c)); ++ if(count != sizeof(c)) ++ printk("winch_thread : failed to read synchronization byte, " ++ "err = %d\n", -count); ++ ++ while(1){ ++ pause(); ++ ++ count = os_write_file(pipe_fd, &c, sizeof(c)); ++ if(count != sizeof(c)) ++ printk("winch_thread : write failed, err = %d\n", ++ -count); ++ } ++} ++ ++static int winch_tramp(int fd, void *device_data, int *fd_out) ++{ ++ struct winch_data data; ++ unsigned long stack; ++ int fds[2], pid, n, err; ++ char c; ++ ++ err = os_pipe(fds, 1, 1); ++ if(err < 0){ ++ printk("winch_tramp : os_pipe failed, err = %d\n", -err); ++ return(err); ++ } ++ ++ data = ((struct winch_data) { .pty_fd = fd, ++ .pipe_fd = fds[1], ++ .close_me = fds[0] } ); ++ pid = run_helper_thread(winch_thread, &data, 0, &stack, 0); ++ if(pid < 0){ ++ printk("fork of winch_thread failed - errno = %d\n", errno); ++ return(pid); ++ } ++ ++ os_close_file(fds[1]); ++ *fd_out = fds[0]; ++ n = os_read_file(fds[0], &c, sizeof(c)); ++ if(n != sizeof(c)){ ++ printk("winch_tramp : failed to read synchronization byte\n"); ++ printk("read failed, err = %d\n", -n); ++ printk("fd %d will not support SIGWINCH\n", fd); ++ *fd_out = -1; ++ } ++ return(pid); ++} ++ ++void register_winch(int fd, void *device_data) ++{ ++ int pid, thread, thread_fd; ++ int count; ++ char c = 1; ++ ++ if(!isatty(fd)) ++ return; ++ ++ pid = tcgetpgrp(fd); ++ if(!CHOOSE_MODE_PROC(is_tracer_winch, is_skas_winch, pid, fd, ++ device_data) && (pid == -1)){ ++ thread = winch_tramp(fd, device_data, &thread_fd); ++ if(fd != -1){ ++ register_winch_irq(thread_fd, fd, thread, device_data); ++ ++ count = os_write_file(thread_fd, &c, sizeof(c)); ++ if(count != sizeof(c)) ++ printk("register_winch : failed to write " ++ "synchronization byte, err = %d\n", ++ -count); ++ } ++ } ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/cow.h um/arch/um/drivers/cow.h +--- orig/arch/um/drivers/cow.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/cow.h 2003-12-15 00:32:23.000000000 -0500 +@@ -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: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/cow_kern.c um/arch/um/drivers/cow_kern.c +--- orig/arch/um/drivers/cow_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/cow_kern.c 2003-10-21 03:26:06.000000000 -0400 +@@ -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: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/cow_sys.h um/arch/um/drivers/cow_sys.h +--- orig/arch/um/drivers/cow_sys.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/cow_sys.h 2003-12-17 10:53:03.000000000 -0500 +@@ -0,0 +1,48 @@ ++#ifndef __COW_SYS_H__ ++#define __COW_SYS_H__ ++ ++#include "kern_util.h" ++#include "user_util.h" ++#include "os.h" ++#include "user.h" ++ ++static inline void *cow_malloc(int size) ++{ ++ return(um_kmalloc(size)); ++} ++ ++static inline void cow_free(void *ptr) ++{ ++ kfree(ptr); ++} ++ ++#define cow_printf printk ++ ++static inline char *cow_strdup(char *str) ++{ ++ return(uml_strdup(str)); ++} ++ ++static inline int cow_seek_file(int fd, __u64 offset) ++{ ++ return(os_seek_file(fd, offset)); ++} ++ ++static inline int cow_file_size(char *file, __u64 *size_out) ++{ ++ return(os_file_size(file, size_out)); ++} ++ ++static inline int cow_write_file(int fd, char *buf, int size) ++{ ++ return(os_write_file(fd, buf, size)); ++} ++ ++#endif ++ ++/* ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/cow_user.c um/arch/um/drivers/cow_user.c +--- orig/arch/um/drivers/cow_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/cow_user.c 2003-11-08 06:29:47.000000000 -0500 +@@ -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 { ++ unsigned long magic; ++ unsigned long version; ++ char backing_file[PATH_LEN_V2]; ++ time_t mtime; ++ __u64 size; ++ int sectorsize; ++}; ++ ++/* Define PATH_LEN_V3 as the usual value of MAXPATHLEN, just hard-code it in ++ * case other systems have different values for MAXPATHLEN ++ */ ++#define PATH_LEN_V3 4096 ++ ++/* Changes from V2 - ++ * PATH_LEN_V3 as described above ++ * Explicitly specify field bit lengths for systems with different ++ * lengths for the usual C types. Not sure whether char or ++ * time_t should be changed, this can be changed later without ++ * breaking compatibility ++ * Add alignment field so that different alignments can be used for the ++ * bitmap and data ++ * Add cow_format field to allow for the possibility of different ways ++ * of specifying the COW blocks. For now, the only value is 0, ++ * for the traditional COW bitmap. ++ * Move the backing_file field to the end of the header. This allows ++ * for the possibility of expanding it into the padding required ++ * by the bitmap alignment. ++ * The bitmap and data portions of the file will be aligned as specified ++ * by the alignment field. This is to allow COW files to be ++ * put on devices with restrictions on access alignments, such as ++ * /dev/raw, with a 512 byte alignment restriction. This also ++ * allows the data to be more aligned more strictly than on ++ * sector boundaries. This is needed for ubd-mmap, which needs ++ * the data to be page aligned. ++ * Fixed (finally!) the rounding bug ++ */ ++ ++struct cow_header_v3 { ++ __u32 magic; ++ __u32 version; ++ time_t mtime; ++ __u64 size; ++ __u32 sectorsize; ++ __u32 alignment; ++ __u32 cow_format; ++ char backing_file[PATH_LEN_V3]; ++}; ++ ++/* COW format definitions - for now, we have only the usual COW bitmap */ ++#define COW_BITMAP 0 ++ ++union cow_header { ++ struct cow_header_v1 v1; ++ struct cow_header_v2 v2; ++ struct cow_header_v3 v3; ++}; ++ ++#define COW_MAGIC 0x4f4f4f4d /* MOOO */ ++#define COW_VERSION 3 ++ ++#define DIV_ROUND(x, len) (((x) + (len) - 1) / (len)) ++#define ROUND_UP(x, align) DIV_ROUND(x, align) * (align) ++ ++void cow_sizes(int version, __u64 size, int sectorsize, int align, ++ int bitmap_offset, unsigned long *bitmap_len_out, ++ int *data_offset_out) ++{ ++ if(version < 3){ ++ *bitmap_len_out = (size + sectorsize - 1) / (8 * sectorsize); ++ ++ *data_offset_out = bitmap_offset + *bitmap_len_out; ++ *data_offset_out = (*data_offset_out + sectorsize - 1) / ++ sectorsize; ++ *data_offset_out *= sectorsize; ++ } ++ else { ++ *bitmap_len_out = DIV_ROUND(size, sectorsize); ++ *bitmap_len_out = DIV_ROUND(*bitmap_len_out, 8); ++ ++ *data_offset_out = bitmap_offset + *bitmap_len_out; ++ *data_offset_out = ROUND_UP(*data_offset_out, align); ++ } ++} ++ ++static int absolutize(char *to, int size, char *from) ++{ ++ char save_cwd[256], *slash; ++ int remaining; ++ ++ if(getcwd(save_cwd, sizeof(save_cwd)) == NULL) { ++ cow_printf("absolutize : unable to get cwd - errno = %d\n", ++ errno); ++ return(-1); ++ } ++ slash = strrchr(from, '/'); ++ if(slash != NULL){ ++ *slash = '\0'; ++ if(chdir(from)){ ++ *slash = '/'; ++ cow_printf("absolutize : Can't cd to '%s' - " ++ "errno = %d\n", from, errno); ++ return(-1); ++ } ++ *slash = '/'; ++ if(getcwd(to, size) == NULL){ ++ cow_printf("absolutize : unable to get cwd of '%s' - " ++ "errno = %d\n", from, errno); ++ return(-1); ++ } ++ remaining = size - strlen(to); ++ if(strlen(slash) + 1 > remaining){ ++ cow_printf("absolutize : unable to fit '%s' into %d " ++ "chars\n", from, size); ++ return(-1); ++ } ++ strcat(to, slash); ++ } ++ else { ++ if(strlen(save_cwd) + 1 + strlen(from) + 1 > size){ ++ cow_printf("absolutize : unable to fit '%s' into %d " ++ "chars\n", from, size); ++ return(-1); ++ } ++ strcpy(to, save_cwd); ++ strcat(to, "/"); ++ strcat(to, from); ++ } ++ chdir(save_cwd); ++ return(0); ++} ++ ++int write_cow_header(char *cow_file, int fd, char *backing_file, ++ int sectorsize, int alignment, long long *size) ++{ ++ struct cow_header_v3 *header; ++ unsigned long modtime; ++ int err; ++ ++ err = cow_seek_file(fd, 0); ++ if(err < 0){ ++ cow_printf("write_cow_header - lseek failed, err = %d\n", -err); ++ goto out; ++ } ++ ++ err = -ENOMEM; ++ header = cow_malloc(sizeof(*header)); ++ if(header == NULL){ ++ cow_printf("Failed to allocate COW V3 header\n"); ++ goto out; ++ } ++ header->magic = htonl(COW_MAGIC); ++ header->version = htonl(COW_VERSION); ++ ++ err = -EINVAL; ++ if(strlen(backing_file) > sizeof(header->backing_file) - 1){ ++ cow_printf("Backing file name \"%s\" is too long - names are " ++ "limited to %d characters\n", backing_file, ++ sizeof(header->backing_file) - 1); ++ goto out_free; ++ } ++ ++ if(absolutize(header->backing_file, sizeof(header->backing_file), ++ backing_file)) ++ goto out_free; ++ ++ err = os_file_modtime(header->backing_file, &modtime); ++ if(err < 0){ ++ cow_printf("Backing file '%s' mtime request failed, " ++ "err = %d\n", header->backing_file, -err); ++ goto out_free; ++ } ++ ++ err = cow_file_size(header->backing_file, size); ++ if(err < 0){ ++ cow_printf("Couldn't get size of backing file '%s', " ++ "err = %d\n", header->backing_file, -err); ++ goto out_free; ++ } ++ ++ header->mtime = htonl(modtime); ++ header->size = htonll(*size); ++ header->sectorsize = htonl(sectorsize); ++ header->alignment = htonl(alignment); ++ header->cow_format = COW_BITMAP; ++ ++ err = os_write_file(fd, header, sizeof(*header)); ++ if(err != sizeof(*header)){ ++ cow_printf("Write of header to new COW file '%s' failed, " ++ "err = %d\n", cow_file, -err); ++ goto out_free; ++ } ++ err = 0; ++ out_free: ++ cow_free(header); ++ out: ++ return(err); ++} ++ ++int file_reader(__u64 offset, char *buf, int len, void *arg) ++{ ++ int fd = *((int *) arg); ++ ++ return(pread(fd, buf, len, offset)); ++} ++ ++/* XXX Need to sanity-check the values read from the header */ ++ ++int read_cow_header(int (*reader)(__u64, char *, int, void *), void *arg, ++ __u32 *version_out, char **backing_file_out, ++ time_t *mtime_out, __u64 *size_out, ++ int *sectorsize_out, __u32 *align_out, ++ int *bitmap_offset_out) ++{ ++ union cow_header *header; ++ char *file; ++ int err, n; ++ unsigned long version, magic; ++ ++ header = cow_malloc(sizeof(*header)); ++ if(header == NULL){ ++ cow_printf("read_cow_header - Failed to allocate header\n"); ++ return(-ENOMEM); ++ } ++ err = -EINVAL; ++ n = (*reader)(0, (char *) header, sizeof(*header), arg); ++ if(n < offsetof(typeof(header->v1), backing_file)){ ++ cow_printf("read_cow_header - short header\n"); ++ goto out; ++ } ++ ++ magic = header->v1.magic; ++ if(magic == COW_MAGIC) { ++ version = header->v1.version; ++ } ++ else if(magic == ntohl(COW_MAGIC)){ ++ version = ntohl(header->v1.version); ++ } ++ /* No error printed because the non-COW case comes through here */ ++ else goto out; ++ ++ *version_out = version; ++ ++ if(version == 1){ ++ if(n < sizeof(header->v1)){ ++ cow_printf("read_cow_header - failed to read V1 " ++ "header\n"); ++ goto out; ++ } ++ *mtime_out = header->v1.mtime; ++ *size_out = header->v1.size; ++ *sectorsize_out = header->v1.sectorsize; ++ *bitmap_offset_out = sizeof(header->v1); ++ *align_out = *sectorsize_out; ++ file = header->v1.backing_file; ++ } ++ else if(version == 2){ ++ if(n < sizeof(header->v2)){ ++ cow_printf("read_cow_header - failed to read V2 " ++ "header\n"); ++ goto out; ++ } ++ *mtime_out = ntohl(header->v2.mtime); ++ *size_out = ntohll(header->v2.size); ++ *sectorsize_out = ntohl(header->v2.sectorsize); ++ *bitmap_offset_out = sizeof(header->v2); ++ *align_out = *sectorsize_out; ++ file = header->v2.backing_file; ++ } ++ else if(version == 3){ ++ if(n < sizeof(header->v3)){ ++ cow_printf("read_cow_header - failed to read V2 " ++ "header\n"); ++ goto out; ++ } ++ *mtime_out = ntohl(header->v3.mtime); ++ *size_out = ntohll(header->v3.size); ++ *sectorsize_out = ntohl(header->v3.sectorsize); ++ *align_out = ntohl(header->v3.alignment); ++ *bitmap_offset_out = ROUND_UP(sizeof(header->v3), *align_out); ++ file = header->v3.backing_file; ++ } ++ else { ++ cow_printf("read_cow_header - invalid COW version\n"); ++ goto out; ++ } ++ err = -ENOMEM; ++ *backing_file_out = cow_strdup(file); ++ if(*backing_file_out == NULL){ ++ cow_printf("read_cow_header - failed to allocate backing " ++ "file\n"); ++ goto out; ++ } ++ err = 0; ++ out: ++ cow_free(header); ++ return(err); ++} ++ ++int init_cow_file(int fd, char *cow_file, char *backing_file, int sectorsize, ++ int alignment, int *bitmap_offset_out, ++ unsigned long *bitmap_len_out, int *data_offset_out) ++{ ++ __u64 size, offset; ++ char zero = 0; ++ int err; ++ ++ err = write_cow_header(cow_file, fd, backing_file, sectorsize, ++ alignment, &size); ++ if(err) ++ goto out; ++ ++ *bitmap_offset_out = ROUND_UP(sizeof(struct cow_header_v3), alignment); ++ cow_sizes(COW_VERSION, size, sectorsize, alignment, *bitmap_offset_out, ++ bitmap_len_out, data_offset_out); ++ ++ offset = *data_offset_out + size - sizeof(zero); ++ err = cow_seek_file(fd, offset); ++ if(err < 0){ ++ cow_printf("cow bitmap lseek failed : err = %d\n", -err); ++ goto out; ++ } ++ ++ /* does not really matter how much we write it is just to set EOF ++ * this also sets the entire COW bitmap ++ * to zero without having to allocate it ++ */ ++ err = cow_write_file(fd, &zero, sizeof(zero)); ++ if(err != sizeof(zero)){ ++ cow_printf("Write of bitmap to new COW file '%s' failed, " ++ "err = %d\n", cow_file, -err); ++ err = -EINVAL; ++ goto out; ++ } ++ ++ return(0); ++ ++ out: ++ return(err); ++} ++ ++/* ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/daemon.h um/arch/um/drivers/daemon.h +--- orig/arch/um/drivers/daemon.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/daemon.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,35 @@ ++/* ++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "net_user.h" ++ ++#define SWITCH_VERSION 3 ++ ++struct daemon_data { ++ char *sock_type; ++ char *ctl_sock; ++ void *ctl_addr; ++ void *data_addr; ++ void *local_addr; ++ int fd; ++ int control; ++ void *dev; ++}; ++ ++extern struct net_user_info daemon_user_info; ++ ++extern int daemon_user_write(int fd, void *buf, int len, ++ struct daemon_data *pri); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/daemon_kern.c um/arch/um/drivers/daemon_kern.c +--- orig/arch/um/drivers/daemon_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/daemon_kern.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,113 @@ ++/* ++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and ++ * James Leu (jleu@mindspring.net). ++ * Copyright (C) 2001 by various other people who didn't put their name here. ++ * Licensed under the GPL. ++ */ ++ ++#include "linux/kernel.h" ++#include "linux/init.h" ++#include "linux/netdevice.h" ++#include "linux/etherdevice.h" ++#include "net_kern.h" ++#include "net_user.h" ++#include "daemon.h" ++ ++struct daemon_init { ++ char *sock_type; ++ char *ctl_sock; ++}; ++ ++void daemon_init(struct net_device *dev, void *data) ++{ ++ struct uml_net_private *pri; ++ struct daemon_data *dpri; ++ struct daemon_init *init = data; ++ ++ init_etherdev(dev, 0); ++ pri = dev->priv; ++ dpri = (struct daemon_data *) pri->user; ++ *dpri = ((struct daemon_data) ++ { .sock_type = init->sock_type, ++ .ctl_sock = init->ctl_sock, ++ .ctl_addr = NULL, ++ .data_addr = NULL, ++ .local_addr = NULL, ++ .fd = -1, ++ .control = -1, ++ .dev = dev }); ++ ++ printk("daemon backend (uml_switch version %d) - %s:%s", ++ SWITCH_VERSION, dpri->sock_type, dpri->ctl_sock); ++ printk("\n"); ++} ++ ++static int daemon_read(int fd, struct sk_buff **skb, ++ struct uml_net_private *lp) ++{ ++ *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER); ++ if(*skb == NULL) return(-ENOMEM); ++ return(net_recvfrom(fd, (*skb)->mac.raw, ++ (*skb)->dev->mtu + ETH_HEADER_OTHER)); ++} ++ ++static int daemon_write(int fd, struct sk_buff **skb, ++ struct uml_net_private *lp) ++{ ++ return(daemon_user_write(fd, (*skb)->data, (*skb)->len, ++ (struct daemon_data *) &lp->user)); ++} ++ ++static struct net_kern_info daemon_kern_info = { ++ .init = daemon_init, ++ .protocol = eth_protocol, ++ .read = daemon_read, ++ .write = daemon_write, ++}; ++ ++int daemon_setup(char *str, char **mac_out, void *data) ++{ ++ struct daemon_init *init = data; ++ char *remain; ++ ++ *init = ((struct daemon_init) ++ { .sock_type = "unix", ++ .ctl_sock = "/tmp/uml.ctl" }); ++ ++ remain = split_if_spec(str, mac_out, &init->sock_type, &init->ctl_sock, ++ NULL); ++ if(remain != NULL) ++ printk(KERN_WARNING "daemon_setup : Ignoring data socket " ++ "specification\n"); ++ ++ return(1); ++} ++ ++static struct transport daemon_transport = { ++ .list = LIST_HEAD_INIT(daemon_transport.list), ++ .name = "daemon", ++ .setup = daemon_setup, ++ .user = &daemon_user_info, ++ .kern = &daemon_kern_info, ++ .private_size = sizeof(struct daemon_data), ++ .setup_size = sizeof(struct daemon_init), ++}; ++ ++static int register_daemon(void) ++{ ++ register_transport(&daemon_transport); ++ return(1); ++} ++ ++__initcall(register_daemon); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/daemon_user.c um/arch/um/drivers/daemon_user.c +--- orig/arch/um/drivers/daemon_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/daemon_user.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,197 @@ ++/* ++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and ++ * James Leu (jleu@mindspring.net). ++ * Copyright (C) 2001 by various other people who didn't put their name here. ++ * Licensed under the GPL. ++ */ ++ ++#include ++#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: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/fd.c um/arch/um/drivers/fd.c +--- orig/arch/um/drivers/fd.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/fd.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,97 @@ ++/* ++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include ++#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; ++ ++ if(data->raw && isatty(data->fd)){ ++ tcgetattr(data->fd, &data->tt); ++ raw(data->fd, 0); ++ } ++ sprintf(data->str, "%d", data->fd); ++ *dev_out = data->str; ++ return(data->fd); ++} ++ ++void fd_close(int fd, void *d) ++{ ++ struct fd_chan *data = d; ++ ++ if(data->raw && isatty(fd)){ ++ tcsetattr(fd, TCSAFLUSH, &data->tt); ++ data->raw = 0; ++ } ++} ++ ++int fd_console_write(int fd, const char *buf, int n, void *d) ++{ ++ struct fd_chan *data = d; ++ ++ return(generic_console_write(fd, buf, n, &data->tt)); ++} ++ ++struct chan_ops fd_ops = { ++ .type = "fd", ++ .init = fd_init, ++ .open = fd_open, ++ .close = fd_close, ++ .read = generic_read, ++ .write = generic_write, ++ .console_write = fd_console_write, ++ .window_size = generic_window_size, ++ .free = generic_free, ++ .winch = 1, ++}; ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/harddog_kern.c um/arch/um/drivers/harddog_kern.c +--- orig/arch/um/drivers/harddog_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/harddog_kern.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,194 @@ ++/* UML hardware watchdog, shamelessly stolen from: ++ * ++ * SoftDog 0.05: A Software Watchdog Device ++ * ++ * (c) Copyright 1996 Alan Cox , 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: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/harddog_user.c um/arch/um/drivers/harddog_user.c +--- orig/arch/um/drivers/harddog_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/harddog_user.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,143 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include ++#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: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/hostaudio_kern.c um/arch/um/drivers/hostaudio_kern.c +--- orig/arch/um/drivers/hostaudio_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/hostaudio_kern.c 2003-11-10 00:04:23.000000000 -0500 +@@ -0,0 +1,339 @@ ++/* ++ * Copyright (C) 2002 Steve Schmidtke ++ * Licensed under the GPL ++ */ ++ ++#include "linux/config.h" ++#include "linux/module.h" ++#include "linux/version.h" ++#include "linux/init.h" ++#include "linux/slab.h" ++#include "linux/fs.h" ++#include "linux/sound.h" ++#include "linux/soundcard.h" ++#include "asm/uaccess.h" ++#include "kern_util.h" ++#include "init.h" ++#include "hostaudio.h" ++ ++/* 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 = hostaudio_read_user(state, kbuf, count, ppos); ++ 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 = hostaudio_write_user(state, kbuf, count, ppos); ++ if(err < 0) ++ goto out; ++ ++ 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 = hostaudio_ioctl_user(state, 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 = hostaudio_open_user(state, r, w, dsp); ++ if(ret < 0){ ++ kfree(state); ++ return(ret); ++ } ++ ++ file->private_data = state; ++ return(0); ++} ++ ++static int hostaudio_release(struct inode *inode, struct file *file) ++{ ++ struct hostaudio_state *state = file->private_data; ++ int ret; ++ ++#ifdef DEBUG ++ printk("hostaudio: release called\n"); ++#endif ++ ++ ret = hostaudio_release_user(state); ++ kfree(state); ++ ++ return(ret); ++} ++ ++/* /dev/mixer file operations */ ++ ++static int hostmixer_ioctl_mixdev(struct inode *inode, struct file *file, ++ unsigned int cmd, unsigned long arg) ++{ ++ struct hostmixer_state *state = file->private_data; ++ ++#ifdef DEBUG ++ printk("hostmixer: ioctl called\n"); ++#endif ++ ++ return(hostmixer_ioctl_mixdev_user(state, cmd, arg)); ++} ++ ++static int hostmixer_open_mixdev(struct inode *inode, struct file *file) ++{ ++ struct hostmixer_state *state; ++ int r = 0, w = 0; ++ int ret; ++ ++#ifdef DEBUG ++ printk("hostmixer: open called (host: %s)\n", mixer); ++#endif ++ ++ state = kmalloc(sizeof(struct hostmixer_state), GFP_KERNEL); ++ if(state == NULL) return(-ENOMEM); ++ ++ if(file->f_mode & FMODE_READ) r = 1; ++ if(file->f_mode & FMODE_WRITE) w = 1; ++ ++ ret = hostmixer_open_mixdev_user(state, r, w, mixer); ++ ++ if(ret < 0){ ++ kfree(state); ++ return(ret); ++ } ++ ++ file->private_data = state; ++ return(0); ++} ++ ++static int hostmixer_release(struct inode *inode, struct file *file) ++{ ++ struct hostmixer_state *state = file->private_data; ++ int ret; ++ ++#ifdef DEBUG ++ printk("hostmixer: release called\n"); ++#endif ++ ++ ret = hostmixer_release_mixdev_user(state); ++ kfree(state); ++ ++ return(ret); ++} ++ ++ ++/* kernel module operations */ ++ ++static struct file_operations hostaudio_fops = { ++ .owner = THIS_MODULE, ++ .llseek = no_llseek, ++ .read = hostaudio_read, ++ .write = hostaudio_write, ++ .poll = hostaudio_poll, ++ .ioctl = hostaudio_ioctl, ++ .mmap = NULL, ++ .open = hostaudio_open, ++ .release = hostaudio_release, ++}; ++ ++static struct file_operations hostmixer_fops = { ++ .owner = THIS_MODULE, ++ .llseek = no_llseek, ++ .ioctl = hostmixer_ioctl_mixdev, ++ .open = hostmixer_open_mixdev, ++ .release = hostmixer_release, ++}; ++ ++struct { ++ int dev_audio; ++ int dev_mixer; ++} module_data; ++ ++MODULE_AUTHOR("Steve Schmidtke"); ++MODULE_DESCRIPTION("UML Audio Relay"); ++MODULE_LICENSE("GPL"); ++ ++static int __init hostaudio_init_module(void) ++{ ++ printk(KERN_INFO "UML Audio Relay (host dsp = %s, host mixer = %s)\n", ++ dsp, mixer); ++ ++ module_data.dev_audio = register_sound_dsp(&hostaudio_fops, -1); ++ if(module_data.dev_audio < 0){ ++ printk(KERN_ERR "hostaudio: couldn't register DSP device!\n"); ++ return -ENODEV; ++ } ++ ++ module_data.dev_mixer = register_sound_mixer(&hostmixer_fops, -1); ++ if(module_data.dev_mixer < 0){ ++ printk(KERN_ERR "hostmixer: couldn't register mixer " ++ "device!\n"); ++ unregister_sound_dsp(module_data.dev_audio); ++ return -ENODEV; ++ } ++ ++ return 0; ++} ++ ++static void __exit hostaudio_cleanup_module (void) ++{ ++ unregister_sound_mixer(module_data.dev_mixer); ++ unregister_sound_dsp(module_data.dev_audio); ++} ++ ++module_init(hostaudio_init_module); ++module_exit(hostaudio_cleanup_module); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/hostaudio_user.c um/arch/um/drivers/hostaudio_user.c +--- orig/arch/um/drivers/hostaudio_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/hostaudio_user.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,134 @@ ++/* ++ * Copyright (C) 2002 Steve Schmidtke ++ * Licensed under the GPL ++ */ ++ ++#include ++#include ++#include ++#include "hostaudio.h" ++#include "user_util.h" ++#include "kern_util.h" ++#include "user.h" ++#include "os.h" ++ ++/* /dev/dsp file operations */ ++ ++ssize_t hostaudio_read_user(struct hostaudio_state *state, char *buffer, ++ size_t count, loff_t *ppos) ++{ ++#ifdef DEBUG ++ printk("hostaudio: read_user called, count = %d\n", count); ++#endif ++ ++ return(os_read_file(state->fd, buffer, count)); ++} ++ ++ssize_t hostaudio_write_user(struct hostaudio_state *state, const char *buffer, ++ size_t count, loff_t *ppos) ++{ ++ ssize_t ret; ++ ++#ifdef DEBUG ++ printk("hostaudio: write_user called, count = %d\n", count); ++#endif ++ ++ return(os_write_file(state->fd, buffer, count)); ++ ++ return(ret); ++} ++ ++int hostaudio_ioctl_user(struct hostaudio_state *state, unsigned int cmd, ++ unsigned long arg) ++{ ++#ifdef DEBUG ++ printk("hostaudio: ioctl_user called, cmd = %u\n", cmd); ++#endif ++ ++ return(os_ioctl_generic(state->fd, cmd, arg)); ++} ++ ++int hostaudio_open_user(struct hostaudio_state *state, int r, int w, char *dsp) ++{ ++#ifdef DEBUG ++ printk("hostaudio: open_user called\n"); ++#endif ++ ++ state->fd = os_open_file(dsp, of_set_rw(OPENFLAGS(), r, w), 0); ++ ++ if(state->fd < 0) { ++ printk("hostaudio_open_user failed to open '%s', err = %d\n", ++ dsp, -state->fd); ++ return(state->fd); ++ } ++ ++ return(0); ++} ++ ++int hostaudio_release_user(struct hostaudio_state *state) ++{ ++#ifdef DEBUG ++ printk("hostaudio: release called\n"); ++#endif ++ if(state->fd >= 0){ ++ os_close_file(state->fd); ++ state->fd = -1; ++ } ++ ++ return(0); ++} ++ ++/* /dev/mixer file operations */ ++ ++int hostmixer_ioctl_mixdev_user(struct hostmixer_state *state, ++ unsigned int cmd, unsigned long arg) ++{ ++#ifdef DEBUG ++ printk("hostmixer: ioctl_user called cmd = %u\n",cmd); ++#endif ++ ++ return(os_ioctl_generic(state->fd, cmd, arg)); ++} ++ ++int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, int w, ++ char *mixer) ++{ ++#ifdef DEBUG ++ printk("hostmixer: open_user called\n"); ++#endif ++ ++ state->fd = os_open_file(mixer, of_set_rw(OPENFLAGS(), r, w), 0); ++ ++ if(state->fd < 0) { ++ printk("hostaudio_open_mixdev_user failed to open '%s', " ++ "err = %d\n", mixer, state->fd); ++ return(state->fd); ++ } ++ ++ return(0); ++} ++ ++int hostmixer_release_mixdev_user(struct hostmixer_state *state) ++{ ++#ifdef DEBUG ++ printk("hostmixer: release_user called\n"); ++#endif ++ ++ if(state->fd >= 0){ ++ os_close_file(state->fd); ++ state->fd = -1; ++ } ++ ++ return 0; ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/line.c um/arch/um/drivers/line.c +--- orig/arch/um/drivers/line.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/line.c 2003-11-07 03:03:57.000000000 -0500 +@@ -0,0 +1,610 @@ ++/* ++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/sched.h" ++#include "linux/slab.h" ++#include "linux/list.h" ++#include "linux/devfs_fs_kernel.h" ++#include "asm/irq.h" ++#include "asm/uaccess.h" ++#include "chan_kern.h" ++#include "irq_user.h" ++#include "line.h" ++#include "kern.h" ++#include "user_util.h" ++#include "kern_util.h" ++#include "os.h" ++#include "irq_kern.h" ++ ++#define LINE_BUFSIZE 4096 ++ ++static void line_interrupt(int irq, void *data, struct pt_regs *unused) ++{ ++ struct line *dev = data; ++ ++ if(dev->count > 0) ++ chan_interrupt(&dev->chan_list, &dev->task, dev->tty, irq, ++ dev); ++} ++ ++static void line_timer_cb(void *arg) ++{ ++ struct line *dev = arg; ++ ++ line_interrupt(dev->driver->read_irq, dev, NULL); ++} ++ ++static int write_room(struct line *dev) ++{ ++ int n; ++ ++ if(dev->buffer == NULL) return(LINE_BUFSIZE - 1); ++ ++ n = dev->head - dev->tail; ++ if(n <= 0) n = LINE_BUFSIZE + n; ++ return(n - 1); ++} ++ ++static int buffer_data(struct line *line, const char *buf, int len) ++{ ++ int end, room; ++ ++ if(line->buffer == NULL){ ++ line->buffer = kmalloc(LINE_BUFSIZE, GFP_ATOMIC); ++ if(line->buffer == NULL){ ++ printk("buffer_data - atomic allocation failed\n"); ++ return(0); ++ } ++ line->head = line->buffer; ++ line->tail = line->buffer; ++ } ++ ++ room = write_room(line); ++ len = (len > room) ? room : len; ++ ++ end = line->buffer + LINE_BUFSIZE - line->tail; ++ if(len < end){ ++ memcpy(line->tail, buf, len); ++ line->tail += len; ++ } ++ else { ++ memcpy(line->tail, buf, end); ++ buf += end; ++ len -= end; ++ memcpy(line->buffer, buf, len); ++ line->tail = line->buffer + len; ++ } ++ ++ return(len); ++} ++ ++static int flush_buffer(struct line *line) ++{ ++ int n, count; ++ ++ if((line->buffer == NULL) || (line->head == line->tail)) return(1); ++ ++ if(line->tail < line->head){ ++ count = line->buffer + LINE_BUFSIZE - line->head; ++ n = write_chan(&line->chan_list, line->head, count, ++ line->driver->write_irq); ++ if(n < 0) return(n); ++ if(n == count) line->head = line->buffer; ++ else { ++ line->head += n; ++ return(0); ++ } ++ } ++ ++ count = line->tail - line->head; ++ n = write_chan(&line->chan_list, line->head, count, ++ line->driver->write_irq); ++ if(n < 0) return(n); ++ ++ line->head += n; ++ return(line->head == line->tail); ++} ++ ++int line_write(struct line *lines, struct tty_struct *tty, int from_user, ++ const char *buf, int len) ++{ ++ struct line *line; ++ char *new; ++ unsigned long flags; ++ int n, err, i, ret = 0; ++ ++ if(tty->stopped) return 0; ++ ++ if(from_user){ ++ new = kmalloc(len, GFP_KERNEL); ++ if(new == NULL) ++ return(0); ++ n = copy_from_user(new, buf, len); ++ buf = new; ++ if(n == len){ ++ len = -EFAULT; ++ goto out_free; ++ } ++ ++ len -= n; ++ } ++ ++ i = minor(tty->device) - tty->driver.minor_start; ++ line = &lines[i]; ++ ++ down(&line->sem); ++ if(line->head != line->tail){ ++ local_irq_save(flags); ++ ret += buffer_data(line, buf, len); ++ err = flush_buffer(line); ++ local_irq_restore(flags); ++ if(err <= 0) ++ goto out_up; ++ } ++ else { ++ n = write_chan(&line->chan_list, buf, len, ++ line->driver->write_irq); ++ if(n < 0){ ++ ret = n; ++ goto out_up; ++ } ++ ++ len -= n; ++ ret += n; ++ if(len > 0) ++ ret += buffer_data(line, buf + n, len); ++ } ++ out_up: ++ up(&line->sem); ++ ++ out_free: ++ if(from_user) ++ kfree(buf); ++ return(ret); ++} ++ ++static void line_write_interrupt(int irq, void *data, struct pt_regs *unused) ++{ ++ struct line *dev = data; ++ struct tty_struct *tty = dev->tty; ++ int err; ++ ++ err = flush_buffer(dev); ++ if(err == 0) return; ++ else if(err < 0){ ++ dev->head = dev->buffer; ++ dev->tail = dev->buffer; ++ } ++ ++ if(tty == NULL) return; ++ ++ if(test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags) && ++ (tty->ldisc.write_wakeup != NULL)) ++ (tty->ldisc.write_wakeup)(tty); ++ ++ /* BLOCKING mode ++ * In blocking mode, everything sleeps on tty->write_wait. ++ * Sleeping in the console driver would break non-blocking ++ * writes. ++ */ ++ ++ if (waitqueue_active(&tty->write_wait)) ++ wake_up_interruptible(&tty->write_wait); ++ ++} ++ ++int line_setup_irq(int fd, int input, int output, void *data) ++{ ++ struct line *line = data; ++ struct line_driver *driver = line->driver; ++ int err = 0, flags = SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM; ++ ++ if(input) err = um_request_irq(driver->read_irq, fd, IRQ_READ, ++ line_interrupt, flags, ++ driver->read_irq_name, line); ++ if(err) return(err); ++ if(output) err = um_request_irq(driver->write_irq, fd, IRQ_WRITE, ++ line_write_interrupt, flags, ++ driver->write_irq_name, line); ++ line->have_irq = 1; ++ return(err); ++} ++ ++void line_disable(struct line *line, int current_irq) ++{ ++ if(!line->have_irq) return; ++ ++ if(line->driver->read_irq == current_irq) ++ free_irq_later(line->driver->read_irq, line); ++ else ++ free_irq(line->driver->read_irq, line); ++ ++ if(line->driver->write_irq == current_irq) ++ free_irq_later(line->driver->write_irq, line); ++ else ++ free_irq(line->driver->write_irq, line); ++ ++ line->have_irq = 0; ++} ++ ++int line_open(struct line *lines, struct tty_struct *tty, ++ struct chan_opts *opts) ++{ ++ struct line *line; ++ int n, err = 0; ++ ++ if(tty == NULL) n = 0; ++ else n = minor(tty->device) - tty->driver.minor_start; ++ line = &lines[n]; ++ ++ down(&line->sem); ++ if(line->count == 0){ ++ if(!line->valid){ ++ err = -ENODEV; ++ goto out; ++ } ++ if(list_empty(&line->chan_list)){ ++ err = parse_chan_pair(line->init_str, &line->chan_list, ++ line->init_pri, n, opts); ++ if(err) goto out; ++ err = open_chan(&line->chan_list); ++ if(err) goto out; ++ } ++ enable_chan(&line->chan_list, line); ++ INIT_TQUEUE(&line->task, line_timer_cb, line); ++ } ++ ++ if(!line->sigio){ ++ chan_enable_winch(&line->chan_list, line); ++ line->sigio = 1; ++ } ++ ++ /* This is outside the if because the initial console is opened ++ * with tty == NULL ++ */ ++ line->tty = tty; ++ ++ if(tty != NULL){ ++ tty->driver_data = line; ++ chan_window_size(&line->chan_list, &tty->winsize.ws_row, ++ &tty->winsize.ws_col); ++ } ++ ++ line->count++; ++ out: ++ up(&line->sem); ++ return(err); ++} ++ ++void line_close(struct line *lines, struct tty_struct *tty) ++{ ++ struct line *line; ++ int n; ++ ++ if(tty == NULL) n = 0; ++ else n = minor(tty->device) - tty->driver.minor_start; ++ line = &lines[n]; ++ ++ down(&line->sem); ++ line->count--; ++ ++ /* I don't like this, but I can't think of anything better. What's ++ * going on is that the tty is in the process of being closed for ++ * the last time. Its count hasn't been dropped yet, so it's still ++ * at 1. This may happen when line->count != 0 because of the initial ++ * console open (without a tty) bumping it up to 1. ++ */ ++ if((line->tty != NULL) && (line->tty->count == 1)) ++ line->tty = NULL; ++ if(line->count == 0) ++ line_disable(line, -1); ++ up(&line->sem); ++} ++ ++void close_lines(struct line *lines, int nlines) ++{ ++ int i; ++ ++ for(i = 0; i < nlines; i++) ++ close_chan(&lines[i].chan_list); ++} ++ ++int line_setup(struct line *lines, int num, char *init, int all_allowed) ++{ ++ int i, n; ++ char *end; ++ ++ if(*init == '=') n = -1; ++ else { ++ n = simple_strtoul(init, &end, 0); ++ if(*end != '='){ ++ printk(KERN_ERR "line_setup failed to parse \"%s\"\n", ++ init); ++ return(0); ++ } ++ init = end; ++ } ++ init++; ++ if((n >= 0) && (n >= num)){ ++ printk("line_setup - %d out of range ((0 ... %d) allowed)\n", ++ n, num); ++ return(0); ++ } ++ else if(n >= 0){ ++ if(lines[n].count > 0){ ++ printk("line_setup - device %d is open\n", n); ++ return(0); ++ } ++ if(lines[n].init_pri <= INIT_ONE){ ++ lines[n].init_pri = INIT_ONE; ++ if(!strcmp(init, "none")) lines[n].valid = 0; ++ else { ++ lines[n].init_str = init; ++ lines[n].valid = 1; ++ } ++ } ++ } ++ else if(!all_allowed){ ++ printk("line_setup - can't configure all devices from " ++ "mconsole\n"); ++ return(0); ++ } ++ else { ++ for(i = 0; i < num; i++){ ++ if(lines[i].init_pri <= INIT_ALL){ ++ lines[i].init_pri = INIT_ALL; ++ if(!strcmp(init, "none")) lines[i].valid = 0; ++ else { ++ lines[i].init_str = init; ++ lines[i].valid = 1; ++ } ++ } ++ } ++ } ++ return(1); ++} ++ ++int line_config(struct line *lines, int num, char *str) ++{ ++ char *new = uml_strdup(str); ++ ++ if(new == NULL){ ++ printk("line_config - uml_strdup failed\n"); ++ return(-ENOMEM); ++ } ++ return(!line_setup(lines, num, new, 0)); ++} ++ ++int line_get_config(char *name, struct line *lines, int num, char *str, ++ int size, char **error_out) ++{ ++ struct line *line; ++ char *end; ++ int dev, n = 0; ++ ++ dev = simple_strtoul(name, &end, 0); ++ if((*end != '\0') || (end == name)){ ++ *error_out = "line_get_config failed to parse device number"; ++ return(0); ++ } ++ ++ if((dev < 0) || (dev >= num)){ ++ *error_out = "device number of of range"; ++ return(0); ++ } ++ ++ line = &lines[dev]; ++ ++ down(&line->sem); ++ if(!line->valid) ++ CONFIG_CHUNK(str, size, n, "none", 1); ++ else if(line->count == 0) ++ CONFIG_CHUNK(str, size, n, line->init_str, 1); ++ else n = chan_config_string(&line->chan_list, str, size, error_out); ++ up(&line->sem); ++ ++ return(n); ++} ++ ++int line_remove(struct line *lines, int num, char *str) ++{ ++ char config[sizeof("conxxxx=none\0")]; ++ ++ sprintf(config, "%s=none", str); ++ return(!line_setup(lines, num, config, 0)); ++} ++ ++static int line_write_room(struct tty_struct *tty) ++{ ++ struct line *dev = tty->driver_data; ++ ++ return(write_room(dev)); ++} ++ ++void line_register_devfs(struct lines *set, struct line_driver *line_driver, ++ struct tty_driver *driver, struct line *lines, ++ int nlines) ++{ ++ int err, i, n; ++ char *from, *to; ++ ++ driver->driver_name = line_driver->name; ++ driver->name = line_driver->devfs_name; ++ driver->major = line_driver->major; ++ driver->minor_start = line_driver->minor_start; ++ driver->type = line_driver->type; ++ driver->subtype = line_driver->subtype; ++ driver->magic = TTY_DRIVER_MAGIC; ++ driver->flags = TTY_DRIVER_REAL_RAW; ++ ++ n = set->num; ++ driver->num = n; ++ driver->table = kmalloc(n * sizeof(driver->table[0]), GFP_KERNEL); ++ driver->termios = kmalloc(n * sizeof(driver->termios[0]), GFP_KERNEL); ++ driver->termios_locked = kmalloc(n * sizeof(driver->termios_locked[0]), ++ GFP_KERNEL); ++ if((driver->table == NULL) || (driver->termios == NULL) || ++ (driver->termios_locked == NULL)) ++ panic("Failed to allocate driver table"); ++ ++ memset(driver->table, 0, n * sizeof(driver->table[0])); ++ memset(driver->termios, 0, n * sizeof(driver->termios[0])); ++ memset(driver->termios_locked, 0, ++ n * sizeof(driver->termios_locked[0])); ++ ++ driver->write_room = line_write_room; ++ driver->init_termios = tty_std_termios; ++ ++ if (tty_register_driver(driver)) ++ panic("line_register_devfs : Couldn't register driver\n"); ++ ++ from = line_driver->symlink_from; ++ to = line_driver->symlink_to; ++ err = devfs_mk_symlink(NULL, from, 0, to, NULL, NULL); ++ if(err) printk("Symlink creation from /dev/%s to /dev/%s " ++ "returned %d\n", from, to, err); ++ ++ for(i = 0; i < nlines; i++){ ++ if(!lines[i].valid) ++ tty_unregister_devfs(driver, driver->minor_start + i); ++ } ++ ++ mconsole_register_dev(&line_driver->mc); ++} ++ ++void lines_init(struct line *lines, int nlines) ++{ ++ struct line *line; ++ int i; ++ ++ for(i = 0; i < nlines; i++){ ++ line = &lines[i]; ++ INIT_LIST_HEAD(&line->chan_list); ++ sema_init(&line->sem, 1); ++ if(line->init_str != NULL){ ++ line->init_str = uml_strdup(line->init_str); ++ if(line->init_str == NULL) ++ printk("lines_init - uml_strdup returned " ++ "NULL\n"); ++ } ++ } ++} ++ ++struct winch { ++ struct list_head list; ++ int fd; ++ int tty_fd; ++ int pid; ++ struct line *line; ++}; ++ ++void winch_interrupt(int irq, void *data, struct pt_regs *unused) ++{ ++ struct winch *winch = data; ++ struct tty_struct *tty; ++ int err; ++ char c; ++ ++ if(winch->fd != -1){ ++ err = generic_read(winch->fd, &c, NULL); ++ if(err < 0){ ++ if(err != -EAGAIN){ ++ printk("winch_interrupt : read failed, " ++ "errno = %d\n", -err); ++ printk("fd %d is losing SIGWINCH support\n", ++ winch->tty_fd); ++ return; ++ } ++ goto out; ++ } ++ } ++ tty = winch->line->tty; ++ if(tty != NULL){ ++ chan_window_size(&winch->line->chan_list, ++ &tty->winsize.ws_row, ++ &tty->winsize.ws_col); ++ kill_pg(tty->pgrp, SIGWINCH, 1); ++ } ++ out: ++ if(winch->fd != -1) ++ reactivate_fd(winch->fd, WINCH_IRQ); ++} ++ ++DECLARE_MUTEX(winch_handler_sem); ++LIST_HEAD(winch_handlers); ++ ++void register_winch_irq(int fd, int tty_fd, int pid, void *line) ++{ ++ struct winch *winch; ++ ++ down(&winch_handler_sem); ++ winch = kmalloc(sizeof(*winch), GFP_KERNEL); ++ if(winch == NULL){ ++ printk("register_winch_irq - kmalloc failed\n"); ++ goto out; ++ } ++ *winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list), ++ .fd = fd, ++ .tty_fd = tty_fd, ++ .pid = pid, ++ .line = line }); ++ list_add(&winch->list, &winch_handlers); ++ if(um_request_irq(WINCH_IRQ, fd, IRQ_READ, winch_interrupt, ++ SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, ++ "winch", winch) < 0) ++ printk("register_winch_irq - failed to register IRQ\n"); ++ out: ++ up(&winch_handler_sem); ++} ++ ++static void winch_cleanup(void) ++{ ++ struct list_head *ele; ++ struct winch *winch; ++ ++ list_for_each(ele, &winch_handlers){ ++ winch = list_entry(ele, struct winch, list); ++ if(winch->fd != -1){ ++ deactivate_fd(winch->fd, WINCH_IRQ); ++ os_close_file(winch->fd); ++ } ++ if(winch->pid != -1) ++ os_kill_process(winch->pid, 1); ++ } ++} ++ ++__uml_exitcall(winch_cleanup); ++ ++char *add_xterm_umid(char *base) ++{ ++ char *umid, *title; ++ int len; ++ ++ umid = get_umid(1); ++ if(umid == NULL) return(base); ++ ++ len = strlen(base) + strlen(" ()") + strlen(umid) + 1; ++ title = kmalloc(len, GFP_KERNEL); ++ if(title == NULL){ ++ printk("Failed to allocate buffer for xterm title\n"); ++ return(base); ++ } ++ ++ strncpy(title, base, len); ++ len -= strlen(title); ++ snprintf(&title[strlen(title)], len, " (%s)", umid); ++ return(title); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/Makefile um/arch/um/drivers/Makefile +--- orig/arch/um/drivers/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/Makefile 2003-11-08 09:58:54.000000000 -0500 +@@ -0,0 +1,97 @@ ++# ++# Copyright (C) 2000, 2002, 2003 Jeff Dike (jdike@karaya.com) ++# Licensed under the GPL ++# ++ ++O_TARGET := built-in.o ++ ++CHAN_OBJS := chan_kern.o chan_user.o line.o ++ ++list-multi := slip.o slirp.o daemon.o mcast.o mconsole.o net.o ubd.o \ ++ hostaudio.o pcap.o port.o harddog.o ++ ++slip-objs := slip_kern.o slip_user.o ++slirp-objs := slirp_kern.o slirp_user.o ++daemon-objs := daemon_kern.o daemon_user.o ++mcast-objs := mcast_kern.o mcast_user.o ++pcap-objs := pcap_kern.o pcap_user.o ++pcap-libs := -lpcap -L/usr/lib ++net-objs := net_kern.o net_user.o ++mconsole-objs := mconsole_kern.o mconsole_user.o ++hostaudio-objs := hostaudio_kern.o hostaudio_user.o ++ubd-objs := ubd_kern.o ubd_user.o ++port-objs := port_kern.o port_user.o ++harddog-objs := harddog_kern.o harddog_user.o ++ ++export-objs := mconsole_kern.o ++ ++obj-y = ++obj-$(CONFIG_SSL) += ssl.o ++obj-$(CONFIG_UML_NET_SLIP) += slip.o ++obj-$(CONFIG_UML_NET_SLIRP) += slirp.o ++obj-$(CONFIG_UML_NET_DAEMON) += daemon.o ++obj-$(CONFIG_UML_NET_MCAST) += mcast.o ++obj-$(CONFIG_UML_NET_PCAP) += pcap.o ++obj-$(CONFIG_UML_NET) += net.o ++obj-$(CONFIG_MCONSOLE) += mconsole.o ++obj-$(CONFIG_MMAPPER) += mmapper_kern.o ++obj-$(CONFIG_BLK_DEV_UBD) += ubd.o ++obj-$(CONFIG_HOSTAUDIO) += hostaudio.o ++obj-$(CONFIG_FD_CHAN) += fd.o ++obj-$(CONFIG_NULL_CHAN) += null.o ++obj-$(CONFIG_PORT_CHAN) += port.o ++obj-$(CONFIG_PTY_CHAN) += pty.o ++obj-$(CONFIG_TTY_CHAN) += tty.o ++obj-$(CONFIG_XTERM_CHAN) += xterm.o xterm_kern.o ++obj-$(CONFIG_UML_WATCHDOG) += harddog.o ++obj-$(CONFIG_COW) += cow_kern.o ++obj-$(CONFIG_COW_COMMON) += cow_user.o ++ ++CFLAGS_pcap_user.o = -I/usr/include/pcap ++ ++obj-y += stdio_console.o $(CHAN_OBJS) ++ ++USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y) $(obj-m)),$($(f)-objs)) ++ ++USER_OBJS = $(filter %_user.o,$(obj-y) $(obj-m) $(USER_SINGLE_OBJS)) fd.o \ ++ null.o pty.o tty.o xterm.o ++ ++include $(TOPDIR)/Rules.make ++ ++$(USER_OBJS) : %.o: %.c ++ $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< ++ ++clean: ++ ++modules: ++ ++fastdep: ++ ++dep: ++ ++archmrproper: ++ ++daemon.o : $(daemon-objs) ++ ++slip.o : $(slip-objs) ++ ++slirp.o : $(slirp-objs) ++ ++mcast.o : $(mcast-objs) ++ ++pcap.o : $(pcap-objs) ++ ++mconsole.o : $(mconsole-objs) ++ ++net.o : $(net-objs) ++ ++hostaudio.o : $(hostaudio-objs) ++ ++ubd.o : $(ubd-objs) ++ ++port.o : $(port-objs) ++ ++harddog.o : $(harddog-objs) ++ ++$(list-multi) : # This doesn't work, but should : '%.o : $(%-objs)' ++ $(LD) -r -o $@ $($(patsubst %.o,%,$@)-objs) $($(patsubst %.o,%,$@)-libs) +diff -Naur -X ../exclude-files orig/arch/um/drivers/mcast.h um/arch/um/drivers/mcast.h +--- orig/arch/um/drivers/mcast.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/mcast.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "net_user.h" ++ ++struct mcast_data { ++ char *addr; ++ unsigned short port; ++ void *mcast_addr; ++ int ttl; ++ void *dev; ++}; ++ ++extern struct net_user_info mcast_user_info; ++ ++extern int mcast_user_write(int fd, void *buf, int len, ++ struct mcast_data *pri); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/mcast_kern.c um/arch/um/drivers/mcast_kern.c +--- orig/arch/um/drivers/mcast_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/mcast_kern.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,145 @@ ++/* ++ * user-mode-linux networking multicast transport ++ * Copyright (C) 2001 by Harald Welte ++ * ++ * based on the existing uml-networking code, which is ++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and ++ * James Leu (jleu@mindspring.net). ++ * Copyright (C) 2001 by various other people who didn't put their name here. ++ * ++ * Licensed under the GPL. ++ */ ++ ++#include "linux/kernel.h" ++#include "linux/init.h" ++#include "linux/netdevice.h" ++#include "linux/etherdevice.h" ++#include "linux/in.h" ++#include "linux/inet.h" ++#include "net_kern.h" ++#include "net_user.h" ++#include "mcast.h" ++ ++struct mcast_init { ++ char *addr; ++ int port; ++ int ttl; ++}; ++ ++void mcast_init(struct net_device *dev, void *data) ++{ ++ struct uml_net_private *pri; ++ struct mcast_data *dpri; ++ struct mcast_init *init = data; ++ ++ init_etherdev(dev, 0); ++ pri = dev->priv; ++ dpri = (struct mcast_data *) pri->user; ++ *dpri = ((struct mcast_data) ++ { .addr = init->addr, ++ .port = init->port, ++ .ttl = init->ttl, ++ .mcast_addr = NULL, ++ .dev = dev }); ++ printk("mcast backend "); ++ printk("multicast adddress: %s:%u, TTL:%u ", ++ dpri->addr, dpri->port, dpri->ttl); ++ ++ printk("\n"); ++} ++ ++static int mcast_read(int fd, struct sk_buff **skb, struct uml_net_private *lp) ++{ ++ *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER); ++ if(*skb == NULL) return(-ENOMEM); ++ return(net_recvfrom(fd, (*skb)->mac.raw, ++ (*skb)->dev->mtu + ETH_HEADER_OTHER)); ++} ++ ++static int mcast_write(int fd, struct sk_buff **skb, ++ struct uml_net_private *lp) ++{ ++ return mcast_user_write(fd, (*skb)->data, (*skb)->len, ++ (struct mcast_data *) &lp->user); ++} ++ ++static struct net_kern_info mcast_kern_info = { ++ .init = mcast_init, ++ .protocol = eth_protocol, ++ .read = mcast_read, ++ .write = mcast_write, ++}; ++ ++int mcast_setup(char *str, char **mac_out, void *data) ++{ ++ struct mcast_init *init = data; ++ char *port_str = NULL, *ttl_str = NULL, *remain; ++ char *last; ++ int n; ++ ++ *init = ((struct mcast_init) ++ { .addr = "239.192.168.1", ++ .port = 1102, ++ .ttl = 1 }); ++ ++ remain = split_if_spec(str, mac_out, &init->addr, &port_str, &ttl_str, ++ NULL); ++ if(remain != NULL){ ++ printk(KERN_ERR "mcast_setup - Extra garbage on " ++ "specification : '%s'\n", remain); ++ return(0); ++ } ++ ++ if(port_str != NULL){ ++ n = simple_strtoul(port_str, &last, 10); ++ if((*last != '\0') || (last == port_str)){ ++ printk(KERN_ERR "mcast_setup - Bad port : '%s'\n", ++ port_str); ++ return(0); ++ } ++ init->port = htons(n); ++ } ++ ++ if(ttl_str != NULL){ ++ init->ttl = simple_strtoul(ttl_str, &last, 10); ++ if((*last != '\0') || (last == ttl_str)){ ++ printk(KERN_ERR "mcast_setup - Bad ttl : '%s'\n", ++ ttl_str); ++ return(0); ++ } ++ } ++ ++ printk(KERN_INFO "Configured mcast device: %s:%u-%u\n", init->addr, ++ init->port, init->ttl); ++ ++ return(1); ++} ++ ++static struct transport mcast_transport = { ++ .list = LIST_HEAD_INIT(mcast_transport.list), ++ .name = "mcast", ++ .setup = mcast_setup, ++ .user = &mcast_user_info, ++ .kern = &mcast_kern_info, ++ .private_size = sizeof(struct mcast_data), ++ .setup_size = sizeof(struct mcast_init), ++}; ++ ++static int register_mcast(void) ++{ ++ register_transport(&mcast_transport); ++ return(1); ++} ++ ++__initcall(register_mcast); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/mcast_user.c um/arch/um/drivers/mcast_user.c +--- orig/arch/um/drivers/mcast_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/mcast_user.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,177 @@ ++/* ++ * user-mode-linux networking multicast transport ++ * Copyright (C) 2001 by Harald Welte ++ * ++ * 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: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/mconsole_kern.c um/arch/um/drivers/mconsole_kern.c +--- orig/arch/um/drivers/mconsole_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/mconsole_kern.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,561 @@ ++/* ++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) ++ * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/kernel.h" ++#include "linux/slab.h" ++#include "linux/init.h" ++#include "linux/notifier.h" ++#include "linux/reboot.h" ++#include "linux/utsname.h" ++#include "linux/ctype.h" ++#include "linux/interrupt.h" ++#include "linux/sysrq.h" ++#include "linux/tqueue.h" ++#include "linux/module.h" ++#include "linux/file.h" ++#include "linux/fs.h" ++#include "linux/proc_fs.h" ++#include "asm/irq.h" ++#include "asm/uaccess.h" ++#include "user_util.h" ++#include "kern_util.h" ++#include "kern.h" ++#include "mconsole.h" ++#include "mconsole_kern.h" ++#include "irq_user.h" ++#include "init.h" ++#include "os.h" ++#include "umid.h" ++#include "irq_kern.h" ++ ++static int do_unlink_socket(struct notifier_block *notifier, ++ unsigned long what, void *data) ++{ ++ return(mconsole_unlink_socket()); ++} ++ ++ ++static struct notifier_block reboot_notifier = { ++ .notifier_call = do_unlink_socket, ++ .priority = 0, ++}; ++ ++/* Safe without explicit locking for now. Tasklets provide their own ++ * locking, and the interrupt handler is safe because it can't interrupt ++ * itself and it can only happen on CPU 0. ++ */ ++ ++LIST_HEAD(mc_requests); ++ ++void mc_task_proc(void *unused) ++{ ++ struct mconsole_entry *req; ++ unsigned long flags; ++ int done; ++ ++ do { ++ save_flags(flags); ++ req = list_entry(mc_requests.next, struct mconsole_entry, ++ list); ++ list_del(&req->list); ++ done = list_empty(&mc_requests); ++ restore_flags(flags); ++ req->request.cmd->handler(&req->request); ++ kfree(req); ++ } while(!done); ++} ++ ++struct tq_struct mconsole_task = { ++ .routine = mc_task_proc, ++ .data = NULL ++}; ++ ++void mconsole_interrupt(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ int fd; ++ struct mconsole_entry *new; ++ struct mc_request req; ++ ++ fd = (int) dev_id; ++ while (mconsole_get_request(fd, &req)){ ++ if(req.cmd->context == MCONSOLE_INTR) ++ (*req.cmd->handler)(&req); ++ else { ++ new = kmalloc(sizeof(*new), GFP_ATOMIC); ++ if(new == NULL) ++ mconsole_reply(&req, "Out of memory", 1, 0); ++ else { ++ new->request = req; ++ list_add(&new->list, &mc_requests); ++ } ++ } ++ } ++ if(!list_empty(&mc_requests)) schedule_task(&mconsole_task); ++ reactivate_fd(fd, MCONSOLE_IRQ); ++} ++ ++void mconsole_version(struct mc_request *req) ++{ ++ char version[256]; ++ ++ sprintf(version, "%s %s %s %s %s", system_utsname.sysname, ++ system_utsname.nodename, system_utsname.release, ++ system_utsname.version, system_utsname.machine); ++ mconsole_reply(req, version, 0, 0); ++} ++ ++void mconsole_log(struct mc_request *req) ++{ ++ int len; ++ char *ptr = req->request.data; ++ ++ ptr += strlen("log"); ++ while(isspace(*ptr)) ptr++; ++ ++ 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++; ++ ++ handle_sysrq(*ptr, ¤t->thread.regs, NULL, NULL); ++ mconsole_reply(req, "", 0, 0); ++} ++#else ++void mconsole_sysrq(struct mc_request *req) ++{ ++ mconsole_reply(req, "Sysrq not compiled in", 1, 0); ++} ++#endif ++ ++/* 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: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/mconsole_user.c um/arch/um/drivers/mconsole_user.c +--- orig/arch/um/drivers/mconsole_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/mconsole_user.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,215 @@ ++/* ++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) ++ * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com) ++ * Licensed under the GPL ++ */ ++ ++#include ++#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: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/mmapper_kern.c um/arch/um/drivers/mmapper_kern.c +--- orig/arch/um/drivers/mmapper_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/mmapper_kern.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,151 @@ ++/* ++ * arch/um/drivers/mmapper_kern.c ++ * ++ * BRIEF MODULE DESCRIPTION ++ * ++ * Copyright (C) 2000 RidgeRun, Inc. ++ * Author: RidgeRun, Inc. ++ * Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com ++ * ++ */ ++#include ++#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: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/net_kern.c um/arch/um/drivers/net_kern.c +--- orig/arch/um/drivers/net_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/net_kern.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,872 @@ ++/* ++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and ++ * James Leu (jleu@mindspring.net). ++ * Copyright (C) 2001 by various other people who didn't put their name here. ++ * Licensed under the GPL. ++ */ ++ ++#include "linux/config.h" ++#include "linux/kernel.h" ++#include "linux/netdevice.h" ++#include "linux/rtnetlink.h" ++#include "linux/skbuff.h" ++#include "linux/socket.h" ++#include "linux/spinlock.h" ++#include "linux/module.h" ++#include "linux/init.h" ++#include "linux/etherdevice.h" ++#include "linux/list.h" ++#include "linux/inetdevice.h" ++#include "linux/ctype.h" ++#include "linux/bootmem.h" ++#include "user_util.h" ++#include "kern_util.h" ++#include "net_kern.h" ++#include "net_user.h" ++#include "mconsole_kern.h" ++#include "init.h" ++#include "irq_user.h" ++#include "irq_kern.h" ++ ++static spinlock_t opened_lock = SPIN_LOCK_UNLOCKED; ++LIST_HEAD(opened); ++ ++static int uml_net_rx(struct net_device *dev) ++{ ++ struct uml_net_private *lp = dev->priv; ++ int pkt_len; ++ struct sk_buff *skb; ++ ++ /* If we can't allocate memory, try again next round. */ ++ skb = dev_alloc_skb(dev->mtu); ++ if (skb == NULL) { ++ lp->stats.rx_dropped++; ++ return 0; ++ } ++ ++ skb->dev = dev; ++ skb_put(skb, dev->mtu); ++ skb->mac.raw = skb->data; ++ pkt_len = (*lp->read)(lp->fd, &skb, lp); ++ ++ if (pkt_len > 0) { ++ skb_trim(skb, pkt_len); ++ skb->protocol = (*lp->protocol)(skb); ++ netif_rx(skb); ++ ++ lp->stats.rx_bytes += skb->len; ++ lp->stats.rx_packets++; ++ return pkt_len; ++ } ++ ++ kfree_skb(skb); ++ return pkt_len; ++} ++ ++void uml_net_interrupt(int irq, void *dev_id, struct pt_regs *regs) ++{ ++ struct net_device *dev = dev_id; ++ struct uml_net_private *lp = dev->priv; ++ int err; ++ ++ if(!netif_running(dev)) ++ return; ++ ++ spin_lock(&lp->lock); ++ while((err = uml_net_rx(dev)) > 0) ; ++ if(err < 0) { ++ printk(KERN_ERR ++ "Device '%s' read returned %d, shutting it down\n", ++ dev->name, err); ++ dev_close(dev); ++ goto out; ++ } ++ reactivate_fd(lp->fd, UM_ETH_IRQ); ++ ++ out: ++ spin_unlock(&lp->lock); ++} ++ ++static int uml_net_open(struct net_device *dev) ++{ ++ struct uml_net_private *lp = dev->priv; ++ char addr[sizeof("255.255.255.255\0")]; ++ int err; ++ ++ spin_lock(&lp->lock); ++ ++ if(lp->fd >= 0){ ++ err = -ENXIO; ++ goto out; ++ } ++ ++ if(!lp->have_mac){ ++ dev_ip_addr(dev, addr, &lp->mac[2]); ++ set_ether_mac(dev, lp->mac); ++ } ++ ++ lp->fd = (*lp->open)(&lp->user); ++ if(lp->fd < 0){ ++ err = lp->fd; ++ goto out; ++ } ++ ++ err = um_request_irq(dev->irq, lp->fd, IRQ_READ, uml_net_interrupt, ++ SA_INTERRUPT | SA_SHIRQ, dev->name, dev); ++ if(err != 0){ ++ printk(KERN_ERR "uml_net_open: failed to get irq(%d)\n", err); ++ if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user); ++ lp->fd = -1; ++ err = -ENETUNREACH; ++ } ++ ++ lp->tl.data = (unsigned long) &lp->user; ++ netif_start_queue(dev); ++ ++ spin_lock(&opened_lock); ++ list_add(&lp->list, &opened); ++ spin_unlock(&opened_lock); ++ MOD_INC_USE_COUNT; ++ out: ++ spin_unlock(&lp->lock); ++ return(err); ++} ++ ++static int uml_net_close(struct net_device *dev) ++{ ++ struct uml_net_private *lp = dev->priv; ++ ++ netif_stop_queue(dev); ++ spin_lock(&lp->lock); ++ ++ free_irq(dev->irq, dev); ++ if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user); ++ lp->fd = -1; ++ spin_lock(&opened_lock); ++ list_del(&lp->list); ++ spin_unlock(&opened_lock); ++ ++ MOD_DEC_USE_COUNT; ++ spin_unlock(&lp->lock); ++ return 0; ++} ++ ++static int uml_net_start_xmit(struct sk_buff *skb, struct net_device *dev) ++{ ++ struct uml_net_private *lp = dev->priv; ++ unsigned long flags; ++ int len; ++ ++ netif_stop_queue(dev); ++ ++ spin_lock_irqsave(&lp->lock, flags); ++ ++ len = (*lp->write)(lp->fd, &skb, lp); ++ ++ if(len == skb->len) { ++ lp->stats.tx_packets++; ++ lp->stats.tx_bytes += skb->len; ++ dev->trans_start = jiffies; ++ netif_start_queue(dev); ++ ++ /* this is normally done in the interrupt when tx finishes */ ++ netif_wake_queue(dev); ++ } ++ else if(len == 0){ ++ netif_start_queue(dev); ++ lp->stats.tx_dropped++; ++ } ++ else { ++ netif_start_queue(dev); ++ printk(KERN_ERR "uml_net_start_xmit: failed(%d)\n", len); ++ } ++ ++ spin_unlock_irqrestore(&lp->lock, flags); ++ ++ dev_kfree_skb(skb); ++ ++ return 0; ++} ++ ++static struct net_device_stats *uml_net_get_stats(struct net_device *dev) ++{ ++ struct uml_net_private *lp = dev->priv; ++ return &lp->stats; ++} ++ ++static void uml_net_set_multicast_list(struct net_device *dev) ++{ ++ if (dev->flags & IFF_PROMISC) return; ++ else if (dev->mc_count) dev->flags |= IFF_ALLMULTI; ++ else dev->flags &= ~IFF_ALLMULTI; ++} ++ ++static void uml_net_tx_timeout(struct net_device *dev) ++{ ++ dev->trans_start = jiffies; ++ netif_wake_queue(dev); ++} ++ ++static int uml_net_set_mac(struct net_device *dev, void *addr) ++{ ++ struct uml_net_private *lp = dev->priv; ++ struct sockaddr *hwaddr = addr; ++ ++ spin_lock(&lp->lock); ++ memcpy(dev->dev_addr, hwaddr->sa_data, ETH_ALEN); ++ spin_unlock(&lp->lock); ++ ++ return(0); ++} ++ ++static int uml_net_change_mtu(struct net_device *dev, int new_mtu) ++{ ++ struct uml_net_private *lp = dev->priv; ++ int err = 0; ++ ++ spin_lock(&lp->lock); ++ ++ new_mtu = (*lp->set_mtu)(new_mtu, &lp->user); ++ if(new_mtu < 0){ ++ err = new_mtu; ++ goto out; ++ } ++ ++ dev->mtu = new_mtu; ++ ++ out: ++ spin_unlock(&lp->lock); ++ return err; ++} ++ ++static int uml_net_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd) ++{ ++ return(-EINVAL); ++} ++ ++void uml_net_user_timer_expire(unsigned long _conn) ++{ ++#ifdef undef ++ struct connection *conn = (struct connection *)_conn; ++ ++ dprintk(KERN_INFO "uml_net_user_timer_expire [%p]\n", conn); ++ do_connect(conn); ++#endif ++} ++ ++/* ++ * default do nothing hard header packet routines for struct net_device init. ++ * real ethernet transports will overwrite with real routines. ++ */ ++static int uml_net_hard_header(struct sk_buff *skb, struct net_device *dev, ++ unsigned short type, void *daddr, void *saddr, unsigned len) ++{ ++ return(0); /* no change */ ++} ++ ++static int uml_net_rebuild_header(struct sk_buff *skb) ++{ ++ return(0); /* ignore */ ++} ++ ++static int uml_net_header_cache(struct neighbour *neigh, struct hh_cache *hh) ++{ ++ return(-1); /* fail */ ++} ++ ++static void uml_net_header_cache_update(struct hh_cache *hh, ++ struct net_device *dev, unsigned char * haddr) ++{ ++ /* ignore */ ++} ++ ++static int uml_net_header_parse(struct sk_buff *skb, unsigned char *haddr) ++{ ++ return(0); /* nothing */ ++} ++ ++static spinlock_t devices_lock = SPIN_LOCK_UNLOCKED; ++static struct list_head devices = LIST_HEAD_INIT(devices); ++ ++static int eth_configure(int n, void *init, char *mac, ++ struct transport *transport) ++{ ++ struct uml_net *device; ++ struct net_device *dev; ++ struct uml_net_private *lp; ++ int save, err, size; ++ ++ size = transport->private_size + sizeof(struct uml_net_private) + ++ sizeof(((struct uml_net_private *) 0)->user); ++ ++ device = kmalloc(sizeof(*device), GFP_KERNEL); ++ if(device == NULL){ ++ printk(KERN_ERR "eth_configure failed to allocate uml_net\n"); ++ return(1); ++ } ++ ++ *device = ((struct uml_net) { .list = LIST_HEAD_INIT(device->list), ++ .dev = NULL, ++ .index = n, ++ .mac = { [ 0 ... 5 ] = 0 }, ++ .have_mac = 0 }); ++ ++ spin_lock(&devices_lock); ++ list_add(&device->list, &devices); ++ spin_unlock(&devices_lock); ++ ++ if(setup_etheraddr(mac, device->mac)) ++ device->have_mac = 1; ++ ++ printk(KERN_INFO "Netdevice %d ", n); ++ if(device->have_mac) printk("(%02x:%02x:%02x:%02x:%02x:%02x) ", ++ device->mac[0], device->mac[1], ++ device->mac[2], device->mac[3], ++ device->mac[4], device->mac[5]); ++ printk(": "); ++ dev = kmalloc(sizeof(*dev) + size, GFP_KERNEL); ++ if(dev == NULL){ ++ printk(KERN_ERR "eth_configure: failed to allocate device\n"); ++ return(1); ++ } ++ memset(dev, 0, sizeof(*dev) + size); ++ ++ snprintf(dev->name, sizeof(dev->name), "eth%d", n); ++ dev->priv = (void *) &dev[1]; ++ device->dev = dev; ++ ++ dev->hard_header = uml_net_hard_header; ++ dev->rebuild_header = uml_net_rebuild_header; ++ dev->hard_header_cache = uml_net_header_cache; ++ dev->header_cache_update= uml_net_header_cache_update; ++ dev->hard_header_parse = uml_net_header_parse; ++ ++ (*transport->kern->init)(dev, init); ++ ++ dev->mtu = transport->user->max_packet; ++ dev->open = uml_net_open; ++ dev->hard_start_xmit = uml_net_start_xmit; ++ dev->stop = uml_net_close; ++ dev->get_stats = uml_net_get_stats; ++ dev->set_multicast_list = uml_net_set_multicast_list; ++ dev->tx_timeout = uml_net_tx_timeout; ++ dev->set_mac_address = uml_net_set_mac; ++ dev->change_mtu = uml_net_change_mtu; ++ dev->do_ioctl = uml_net_ioctl; ++ dev->watchdog_timeo = (HZ >> 1); ++ dev->irq = UM_ETH_IRQ; ++ ++ rtnl_lock(); ++ err = register_netdevice(dev); ++ rtnl_unlock(); ++ if(err) ++ return(1); ++ lp = dev->priv; ++ ++ /* lp.user is the first four bytes of the transport data, which ++ * has already been initialized. This structure assignment will ++ * overwrite that, so we make sure that .user gets overwritten with ++ * what it already has. ++ */ ++ save = lp->user[0]; ++ *lp = ((struct uml_net_private) ++ { .list = LIST_HEAD_INIT(lp->list), ++ .lock = SPIN_LOCK_UNLOCKED, ++ .dev = dev, ++ .fd = -1, ++ .mac = { 0xfe, 0xfd, 0x0, 0x0, 0x0, 0x0}, ++ .have_mac = device->have_mac, ++ .protocol = transport->kern->protocol, ++ .open = transport->user->open, ++ .close = transport->user->close, ++ .remove = transport->user->remove, ++ .read = transport->kern->read, ++ .write = transport->kern->write, ++ .add_address = transport->user->add_address, ++ .delete_address = transport->user->delete_address, ++ .set_mtu = transport->user->set_mtu, ++ .user = { save } }); ++ init_timer(&lp->tl); ++ lp->tl.function = uml_net_user_timer_expire; ++ memset(&lp->stats, 0, sizeof(lp->stats)); ++ if(lp->have_mac) memcpy(lp->mac, device->mac, sizeof(lp->mac)); ++ ++ if(transport->user->init) ++ (*transport->user->init)(&lp->user, dev); ++ ++ if(device->have_mac) ++ set_ether_mac(dev, device->mac); ++ return(0); ++} ++ ++static struct uml_net *find_device(int n) ++{ ++ struct uml_net *device; ++ struct list_head *ele; ++ ++ spin_lock(&devices_lock); ++ list_for_each(ele, &devices){ ++ device = list_entry(ele, struct uml_net, list); ++ if(device->index == n) ++ goto out; ++ } ++ device = NULL; ++ out: ++ spin_unlock(&devices_lock); ++ return(device); ++} ++ ++static int eth_parse(char *str, int *index_out, char **str_out) ++{ ++ char *end; ++ int n; ++ ++ n = simple_strtoul(str, &end, 0); ++ if(end == str){ ++ printk(KERN_ERR "eth_setup: Failed to parse '%s'\n", str); ++ return(1); ++ } ++ if(n < 0){ ++ printk(KERN_ERR "eth_setup: device %d is negative\n", n); ++ return(1); ++ } ++ str = end; ++ if(*str != '='){ ++ printk(KERN_ERR ++ "eth_setup: expected '=' after device number\n"); ++ return(1); ++ } ++ str++; ++ if(find_device(n)){ ++ printk(KERN_ERR "eth_setup: Device %d already configured\n", ++ n); ++ return(1); ++ } ++ if(index_out) *index_out = n; ++ *str_out = str; ++ return(0); ++} ++ ++struct eth_init { ++ struct list_head list; ++ char *init; ++ int index; ++}; ++ ++/* Filled in at boot time. Will need locking if the transports become ++ * modular. ++ */ ++struct list_head transports = LIST_HEAD_INIT(transports); ++ ++/* Filled in during early boot */ ++struct list_head eth_cmd_line = LIST_HEAD_INIT(eth_cmd_line); ++ ++static int check_transport(struct transport *transport, char *eth, int n, ++ void **init_out, char **mac_out) ++{ ++ int len; ++ ++ len = strlen(transport->name); ++ if(strncmp(eth, transport->name, len)) ++ return(0); ++ ++ eth += len; ++ if(*eth == ',') ++ eth++; ++ else if(*eth != '\0') ++ return(0); ++ ++ *init_out = kmalloc(transport->setup_size, GFP_KERNEL); ++ if(*init_out == NULL) ++ return(1); ++ ++ if(!transport->setup(eth, mac_out, *init_out)){ ++ kfree(*init_out); ++ *init_out = NULL; ++ } ++ return(1); ++} ++ ++void register_transport(struct transport *new) ++{ ++ struct list_head *ele, *next; ++ struct eth_init *eth; ++ void *init; ++ char *mac = NULL; ++ int match; ++ ++ list_add(&new->list, &transports); ++ ++ list_for_each_safe(ele, next, ð_cmd_line){ ++ eth = list_entry(ele, struct eth_init, list); ++ match = check_transport(new, eth->init, eth->index, &init, ++ &mac); ++ if(!match) ++ continue; ++ else if(init != NULL){ ++ eth_configure(eth->index, init, mac, new); ++ kfree(init); ++ } ++ list_del(ð->list); ++ } ++} ++ ++static int eth_setup_common(char *str, int index) ++{ ++ struct list_head *ele; ++ struct transport *transport; ++ void *init; ++ char *mac = NULL; ++ ++ list_for_each(ele, &transports){ ++ transport = list_entry(ele, struct transport, list); ++ if(!check_transport(transport, str, index, &init, &mac)) ++ continue; ++ if(init != NULL){ ++ eth_configure(index, init, mac, transport); ++ kfree(init); ++ } ++ return(1); ++ } ++ return(0); ++} ++ ++static int eth_setup(char *str) ++{ ++ struct eth_init *new; ++ int n, err; ++ ++ err = eth_parse(str, &n, &str); ++ if(err) return(1); ++ ++ new = alloc_bootmem(sizeof(new)); ++ if(new == NULL){ ++ printk("eth_init : alloc_bootmem failed\n"); ++ return(1); ++ } ++ *new = ((struct eth_init) { .list = LIST_HEAD_INIT(new->list), ++ .index = n, ++ .init = str }); ++ list_add_tail(&new->list, ð_cmd_line); ++ return(1); ++} ++ ++__setup("eth", eth_setup); ++__uml_help(eth_setup, ++"eth[0-9]+=,\n" ++" Configure a network device.\n\n" ++); ++ ++static int eth_init(void) ++{ ++ struct list_head *ele, *next; ++ struct eth_init *eth; ++ ++ list_for_each_safe(ele, next, ð_cmd_line){ ++ eth = list_entry(ele, struct eth_init, list); ++ ++ if(eth_setup_common(eth->init, eth->index)) ++ list_del(ð->list); ++ } ++ ++ return(1); ++} ++ ++__initcall(eth_init); ++ ++static int net_config(char *str) ++{ ++ int n, err; ++ ++ err = eth_parse(str, &n, &str); ++ if(err) return(err); ++ ++ str = uml_strdup(str); ++ if(str == NULL){ ++ printk(KERN_ERR "net_config failed to strdup string\n"); ++ return(-1); ++ } ++ err = !eth_setup_common(str, n); ++ if(err) ++ kfree(str); ++ return(err); ++} ++ ++static int net_remove(char *str) ++{ ++ struct uml_net *device; ++ struct net_device *dev; ++ struct uml_net_private *lp; ++ char *end; ++ int n; ++ ++ n = simple_strtoul(str, &end, 0); ++ if((*end != '\0') || (end == str)) ++ return(-1); ++ ++ device = find_device(n); ++ if(device == NULL) ++ return(0); ++ ++ dev = device->dev; ++ lp = dev->priv; ++ if(lp->fd > 0) return(-1); ++ if(lp->remove != NULL) (*lp->remove)(&lp->user); ++ unregister_netdev(dev); ++ ++ list_del(&device->list); ++ kfree(device); ++ return(0); ++} ++ ++static struct mc_device net_mc = { ++ .name = "eth", ++ .config = net_config, ++ .get_config = NULL, ++ .remove = net_remove, ++}; ++ ++static int uml_inetaddr_event(struct notifier_block *this, unsigned long event, ++ void *ptr) ++{ ++ struct in_ifaddr *ifa = ptr; ++ u32 addr = ifa->ifa_address; ++ u32 netmask = ifa->ifa_mask; ++ struct net_device *dev = ifa->ifa_dev->dev; ++ struct uml_net_private *lp; ++ void (*proc)(unsigned char *, unsigned char *, void *); ++ unsigned char addr_buf[4], netmask_buf[4]; ++ ++ if(dev->open != uml_net_open) return(NOTIFY_DONE); ++ ++ lp = dev->priv; ++ ++ proc = NULL; ++ switch (event){ ++ case NETDEV_UP: ++ proc = lp->add_address; ++ break; ++ case NETDEV_DOWN: ++ proc = lp->delete_address; ++ break; ++ } ++ if(proc != NULL){ ++ addr_buf[0] = addr & 0xff; ++ addr_buf[1] = (addr >> 8) & 0xff; ++ addr_buf[2] = (addr >> 16) & 0xff; ++ addr_buf[3] = addr >> 24; ++ netmask_buf[0] = netmask & 0xff; ++ netmask_buf[1] = (netmask >> 8) & 0xff; ++ netmask_buf[2] = (netmask >> 16) & 0xff; ++ netmask_buf[3] = netmask >> 24; ++ (*proc)(addr_buf, netmask_buf, &lp->user); ++ } ++ return(NOTIFY_DONE); ++} ++ ++struct notifier_block uml_inetaddr_notifier = { ++ .notifier_call = uml_inetaddr_event, ++}; ++ ++static int uml_net_init(void) ++{ ++ struct list_head *ele; ++ struct uml_net_private *lp; ++ struct in_device *ip; ++ struct in_ifaddr *in; ++ ++ mconsole_register_dev(&net_mc); ++ register_inetaddr_notifier(¨_inetaddr_notifier); ++ ++ /* Devices may have been opened already, so the uml_inetaddr_notifier ++ * didn't get a chance to run for them. This fakes it so that ++ * addresses which have already been set up get handled properly. ++ */ ++ list_for_each(ele, &opened){ ++ lp = list_entry(ele, struct uml_net_private, list); ++ ip = lp->dev->ip_ptr; ++ if(ip == NULL) continue; ++ in = ip->ifa_list; ++ while(in != NULL){ ++ uml_inetaddr_event(NULL, NETDEV_UP, in); ++ in = in->ifa_next; ++ } ++ } ++ ++ return(0); ++} ++ ++__initcall(uml_net_init); ++ ++static void close_devices(void) ++{ ++ struct list_head *ele; ++ struct uml_net_private *lp; ++ ++ list_for_each(ele, &opened){ ++ lp = list_entry(ele, struct uml_net_private, list); ++ if(lp->close != NULL) (*lp->close)(lp->fd, &lp->user); ++ if(lp->remove != NULL) (*lp->remove)(&lp->user); ++ } ++} ++ ++__uml_exitcall(close_devices); ++ ++int setup_etheraddr(char *str, unsigned char *addr) ++{ ++ char *end; ++ int i; ++ ++ if(str == NULL) ++ return(0); ++ for(i=0;i<6;i++){ ++ addr[i] = simple_strtoul(str, &end, 16); ++ if((end == str) || ++ ((*end != ':') && (*end != ',') && (*end != '\0'))){ ++ printk(KERN_ERR ++ "setup_etheraddr: failed to parse '%s' " ++ "as an ethernet address\n", str); ++ return(0); ++ } ++ str = end + 1; ++ } ++ if(addr[0] & 1){ ++ printk(KERN_ERR ++ "Attempt to assign a broadcast ethernet address to a " ++ "device disallowed\n"); ++ return(0); ++ } ++ return(1); ++} ++ ++void dev_ip_addr(void *d, char *buf, char *bin_buf) ++{ ++ struct net_device *dev = d; ++ struct in_device *ip = dev->ip_ptr; ++ struct in_ifaddr *in; ++ u32 addr; ++ ++ if((ip == NULL) || ((in = ip->ifa_list) == NULL)){ ++ printk(KERN_WARNING "dev_ip_addr - device not assigned an " ++ "IP address\n"); ++ return; ++ } ++ addr = in->ifa_address; ++ sprintf(buf, "%d.%d.%d.%d", addr & 0xff, (addr >> 8) & 0xff, ++ (addr >> 16) & 0xff, addr >> 24); ++ if(bin_buf){ ++ bin_buf[0] = addr & 0xff; ++ bin_buf[1] = (addr >> 8) & 0xff; ++ bin_buf[2] = (addr >> 16) & 0xff; ++ bin_buf[3] = addr >> 24; ++ } ++} ++ ++void set_ether_mac(void *d, unsigned char *addr) ++{ ++ struct net_device *dev = d; ++ ++ memcpy(dev->dev_addr, addr, ETH_ALEN); ++} ++ ++struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra) ++{ ++ if((skb != NULL) && (skb_tailroom(skb) < extra)){ ++ struct sk_buff *skb2; ++ ++ skb2 = skb_copy_expand(skb, 0, extra, GFP_ATOMIC); ++ dev_kfree_skb(skb); ++ skb = skb2; ++ } ++ if(skb != NULL) skb_put(skb, extra); ++ return(skb); ++} ++ ++void iter_addresses(void *d, void (*cb)(unsigned char *, unsigned char *, ++ void *), ++ void *arg) ++{ ++ struct net_device *dev = d; ++ struct in_device *ip = dev->ip_ptr; ++ struct in_ifaddr *in; ++ unsigned char address[4], netmask[4]; ++ ++ if(ip == NULL) return; ++ in = ip->ifa_list; ++ while(in != NULL){ ++ address[0] = in->ifa_address & 0xff; ++ address[1] = (in->ifa_address >> 8) & 0xff; ++ address[2] = (in->ifa_address >> 16) & 0xff; ++ address[3] = in->ifa_address >> 24; ++ netmask[0] = in->ifa_mask & 0xff; ++ netmask[1] = (in->ifa_mask >> 8) & 0xff; ++ netmask[2] = (in->ifa_mask >> 16) & 0xff; ++ netmask[3] = in->ifa_mask >> 24; ++ (*cb)(address, netmask, arg); ++ in = in->ifa_next; ++ } ++} ++ ++int dev_netmask(void *d, void *m) ++{ ++ struct net_device *dev = d; ++ struct in_device *ip = dev->ip_ptr; ++ struct in_ifaddr *in; ++ __u32 *mask_out = m; ++ ++ if(ip == NULL) ++ return(1); ++ ++ in = ip->ifa_list; ++ if(in == NULL) ++ return(1); ++ ++ *mask_out = in->ifa_mask; ++ return(0); ++} ++ ++void *get_output_buffer(int *len_out) ++{ ++ void *ret; ++ ++ ret = (void *) __get_free_pages(GFP_KERNEL, 0); ++ if(ret) *len_out = PAGE_SIZE; ++ else *len_out = 0; ++ return(ret); ++} ++ ++void free_output_buffer(void *buffer) ++{ ++ free_pages((unsigned long) buffer, 0); ++} ++ ++int tap_setup_common(char *str, char *type, char **dev_name, char **mac_out, ++ char **gate_addr) ++{ ++ char *remain; ++ ++ remain = split_if_spec(str, dev_name, mac_out, gate_addr, NULL); ++ if(remain != NULL){ ++ printk("tap_setup_common - Extra garbage on specification : " ++ "'%s'\n", remain); ++ return(1); ++ } ++ ++ return(0); ++} ++ ++unsigned short eth_protocol(struct sk_buff *skb) ++{ ++ return(eth_type_trans(skb, skb->dev)); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/net_user.c um/arch/um/drivers/net_user.c +--- orig/arch/um/drivers/net_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/net_user.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,252 @@ ++/* ++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include ++#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); ++ ++ os_close_file(fds[1]); ++ read_output(fds[0], output, output_len); ++ waitpid(pid, NULL, 0); ++ return(pid); ++} ++ ++static void change(char *dev, char *what, unsigned char *addr, ++ unsigned char *netmask) ++{ ++ char addr_buf[sizeof("255.255.255.255\0")]; ++ char netmask_buf[sizeof("255.255.255.255\0")]; ++ char version[sizeof("nnnnn\0")]; ++ char *argv[] = { "uml_net", version, what, dev, addr_buf, ++ netmask_buf, NULL }; ++ char *output; ++ int output_len, pid; ++ ++ sprintf(version, "%d", UML_NET_VERSION); ++ sprintf(addr_buf, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]); ++ sprintf(netmask_buf, "%d.%d.%d.%d", netmask[0], netmask[1], ++ netmask[2], netmask[3]); ++ ++ output_len = page_size(); ++ output = um_kmalloc(output_len); ++ if(output == NULL) ++ printk("change : failed to allocate output buffer\n"); ++ ++ pid = change_tramp(argv, output, output_len); ++ if(pid < 0) return; ++ ++ if(output != NULL){ ++ printk("%s", output); ++ kfree(output); ++ } ++} ++ ++void open_addr(unsigned char *addr, unsigned char *netmask, void *arg) ++{ ++ change(arg, "add", addr, netmask); ++} ++ ++void close_addr(unsigned char *addr, unsigned char *netmask, void *arg) ++{ ++ change(arg, "del", addr, netmask); ++} ++ ++char *split_if_spec(char *str, ...) ++{ ++ char **arg, *end; ++ va_list ap; ++ ++ va_start(ap, str); ++ while((arg = va_arg(ap, char **)) != NULL){ ++ if(*str == '\0') ++ return(NULL); ++ end = strchr(str, ','); ++ if(end != str) ++ *arg = str; ++ if(end == NULL) ++ return(NULL); ++ *end++ = '\0'; ++ str = end; ++ } ++ va_end(ap); ++ return(str); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/null.c um/arch/um/drivers/null.c +--- orig/arch/um/drivers/null.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/null.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,55 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include ++#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: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/pcap_kern.c um/arch/um/drivers/pcap_kern.c +--- orig/arch/um/drivers/pcap_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/pcap_kern.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,127 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike ++ * Licensed under the GPL. ++ */ ++ ++#include "linux/init.h" ++#include "linux/netdevice.h" ++#include "linux/etherdevice.h" ++#include "net_kern.h" ++#include "net_user.h" ++#include "pcap_user.h" ++ ++struct pcap_init { ++ char *host_if; ++ int promisc; ++ int optimize; ++ char *filter; ++}; ++ ++void pcap_init(struct net_device *dev, void *data) ++{ ++ struct uml_net_private *pri; ++ struct pcap_data *ppri; ++ struct pcap_init *init = data; ++ ++ init_etherdev(dev, 0); ++ pri = dev->priv; ++ ppri = (struct pcap_data *) pri->user; ++ *ppri = ((struct pcap_data) ++ { .host_if = init->host_if, ++ .promisc = init->promisc, ++ .optimize = init->optimize, ++ .filter = init->filter, ++ .compiled = NULL, ++ .pcap = NULL }); ++} ++ ++static int pcap_read(int fd, struct sk_buff **skb, ++ struct uml_net_private *lp) ++{ ++ *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER); ++ if(*skb == NULL) return(-ENOMEM); ++ return(pcap_user_read(fd, (*skb)->mac.raw, ++ (*skb)->dev->mtu + ETH_HEADER_OTHER, ++ (struct pcap_data *) &lp->user)); ++} ++ ++static int pcap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp) ++{ ++ return(-EPERM); ++} ++ ++static struct net_kern_info pcap_kern_info = { ++ .init = pcap_init, ++ .protocol = eth_protocol, ++ .read = pcap_read, ++ .write = pcap_write, ++}; ++ ++int pcap_setup(char *str, char **mac_out, void *data) ++{ ++ struct pcap_init *init = data; ++ char *remain, *host_if = NULL, *options[2] = { NULL, NULL }; ++ int i; ++ ++ *init = ((struct pcap_init) ++ { .host_if = "eth0", ++ .promisc = 1, ++ .optimize = 0, ++ .filter = NULL }); ++ ++ remain = split_if_spec(str, &host_if, &init->filter, ++ &options[0], &options[1], NULL); ++ if(remain != NULL){ ++ printk(KERN_ERR "pcap_setup - Extra garbage on " ++ "specification : '%s'\n", remain); ++ return(0); ++ } ++ ++ if(host_if != NULL) ++ init->host_if = host_if; ++ ++ for(i = 0; i < sizeof(options)/sizeof(options[0]); i++){ ++ if(options[i] == NULL) ++ continue; ++ if(!strcmp(options[i], "promisc")) ++ init->promisc = 1; ++ else if(!strcmp(options[i], "nopromisc")) ++ init->promisc = 0; ++ else if(!strcmp(options[i], "optimize")) ++ init->optimize = 1; ++ else if(!strcmp(options[i], "nooptimize")) ++ init->optimize = 0; ++ else printk("pcap_setup : bad option - '%s'\n", options[i]); ++ } ++ ++ return(1); ++} ++ ++static struct transport pcap_transport = { ++ .list = LIST_HEAD_INIT(pcap_transport.list), ++ .name = "pcap", ++ .setup = pcap_setup, ++ .user = &pcap_user_info, ++ .kern = &pcap_kern_info, ++ .private_size = sizeof(struct pcap_data), ++ .setup_size = sizeof(struct pcap_init), ++}; ++ ++static int register_pcap(void) ++{ ++ register_transport(&pcap_transport); ++ return(1); ++} ++ ++__initcall(register_pcap); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/pcap_user.c um/arch/um/drivers/pcap_user.c +--- orig/arch/um/drivers/pcap_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/pcap_user.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,143 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike ++ * 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: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/pcap_user.h um/arch/um/drivers/pcap_user.h +--- orig/arch/um/drivers/pcap_user.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/pcap_user.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "net_user.h" ++ ++struct pcap_data { ++ char *host_if; ++ int promisc; ++ int optimize; ++ char *filter; ++ void *compiled; ++ void *pcap; ++ void *dev; ++}; ++ ++extern struct net_user_info pcap_user_info; ++ ++extern int pcap_user_read(int fd, void *buf, int len, struct pcap_data *pri); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/port.h um/arch/um/drivers/port.h +--- orig/arch/um/drivers/port.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/port.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __PORT_H__ ++#define __PORT_H__ ++ ++extern void *port_data(int port); ++extern int port_wait(void *data); ++extern void port_kern_close(void *d); ++extern int port_connection(int fd, int *socket_out, int *pid_out); ++extern int port_listen_fd(int port); ++extern void port_read(int fd, void *data); ++extern void port_kern_free(void *d); ++extern int port_rcv_fd(int fd); ++extern void port_remove_dev(void *d); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/port_kern.c um/arch/um/drivers/port_kern.c +--- orig/arch/um/drivers/port_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/port_kern.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,303 @@ ++/* ++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/list.h" ++#include "linux/sched.h" ++#include "linux/slab.h" ++#include "linux/irq.h" ++#include "linux/spinlock.h" ++#include "linux/errno.h" ++#include "asm/semaphore.h" ++#include "asm/errno.h" ++#include "kern_util.h" ++#include "kern.h" ++#include "irq_user.h" ++#include "irq_kern.h" ++#include "port.h" ++#include "init.h" ++#include "os.h" ++ ++struct port_list { ++ struct list_head list; ++ int has_connection; ++ struct semaphore sem; ++ int port; ++ int fd; ++ spinlock_t lock; ++ struct list_head pending; ++ struct list_head connections; ++}; ++ ++struct port_dev { ++ struct port_list *port; ++ int helper_pid; ++ int telnetd_pid; ++}; ++ ++struct connection { ++ struct list_head list; ++ int fd; ++ int helper_pid; ++ int socket[2]; ++ int telnetd_pid; ++ struct port_list *port; ++}; ++ ++static void pipe_interrupt(int irq, void *data, struct pt_regs *regs) ++{ ++ struct connection *conn = data; ++ int fd; ++ ++ fd = os_rcv_fd(conn->socket[0], &conn->helper_pid); ++ if(fd < 0){ ++ if(fd == -EAGAIN) ++ return; ++ ++ printk(KERN_ERR "pipe_interrupt : os_rcv_fd returned %d\n", ++ -fd); ++ os_close_file(conn->fd); ++ } ++ ++ list_del(&conn->list); ++ ++ conn->fd = fd; ++ list_add(&conn->list, &conn->port->connections); ++ ++ up(&conn->port->sem); ++} ++ ++static int port_accept(struct port_list *port) ++{ ++ struct connection *conn; ++ int fd, socket[2], pid, ret = 0; ++ ++ fd = port_connection(port->fd, socket, &pid); ++ if(fd < 0){ ++ if(fd != -EAGAIN) ++ printk(KERN_ERR "port_accept : port_connection " ++ "returned %d\n", -fd); ++ goto out; ++ } ++ ++ conn = kmalloc(sizeof(*conn), GFP_ATOMIC); ++ if(conn == NULL){ ++ printk(KERN_ERR "port_accept : failed to allocate " ++ "connection\n"); ++ goto out_close; ++ } ++ *conn = ((struct connection) ++ { .list = LIST_HEAD_INIT(conn->list), ++ .fd = fd, ++ .socket = { socket[0], socket[1] }, ++ .telnetd_pid = pid, ++ .port = port }); ++ ++ if(um_request_irq(TELNETD_IRQ, socket[0], IRQ_READ, pipe_interrupt, ++ SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, ++ "telnetd", conn)){ ++ printk(KERN_ERR "port_accept : failed to get IRQ for " ++ "telnetd\n"); ++ goto out_free; ++ } ++ ++ list_add(&conn->list, &port->pending); ++ return(1); ++ ++ out_free: ++ kfree(conn); ++ out_close: ++ os_close_file(fd); ++ if(pid != -1) ++ os_kill_process(pid, 1); ++ out: ++ return(ret); ++} ++ ++DECLARE_MUTEX(ports_sem); ++struct list_head ports = LIST_HEAD_INIT(ports); ++ ++void port_task_proc(void *unused) ++{ ++ struct port_list *port; ++ struct list_head *ele; ++ unsigned long flags; ++ ++ save_flags(flags); ++ list_for_each(ele, &ports){ ++ port = list_entry(ele, struct port_list, list); ++ if(!port->has_connection) ++ continue; ++ reactivate_fd(port->fd, ACCEPT_IRQ); ++ while(port_accept(port)) ; ++ port->has_connection = 0; ++ } ++ restore_flags(flags); ++} ++ ++struct tq_struct port_task = { ++ .routine = port_task_proc, ++ .data = NULL ++}; ++ ++static void port_interrupt(int irq, void *data, struct pt_regs *regs) ++{ ++ struct port_list *port = data; ++ ++ port->has_connection = 1; ++ schedule_task(&port_task); ++} ++ ++void *port_data(int port_num) ++{ ++ struct list_head *ele; ++ struct port_list *port; ++ struct port_dev *dev = NULL; ++ int fd; ++ ++ down(&ports_sem); ++ list_for_each(ele, &ports){ ++ port = list_entry(ele, struct port_list, list); ++ if(port->port == port_num) goto found; ++ } ++ port = kmalloc(sizeof(struct port_list), GFP_KERNEL); ++ if(port == NULL){ ++ printk(KERN_ERR "Allocation of port list failed\n"); ++ goto out; ++ } ++ ++ fd = port_listen_fd(port_num); ++ if(fd < 0){ ++ printk(KERN_ERR "binding to port %d failed, errno = %d\n", ++ port_num, -fd); ++ goto out_free; ++ } ++ if(um_request_irq(ACCEPT_IRQ, fd, IRQ_READ, port_interrupt, ++ SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, "port", ++ port)){ ++ printk(KERN_ERR "Failed to get IRQ for port %d\n", port_num); ++ goto out_close; ++ } ++ ++ *port = ((struct port_list) ++ { .list = LIST_HEAD_INIT(port->list), ++ .has_connection = 0, ++ .sem = __SEMAPHORE_INITIALIZER(port->sem, ++ 0), ++ .lock = SPIN_LOCK_UNLOCKED, ++ .port = port_num, ++ .fd = fd, ++ .pending = LIST_HEAD_INIT(port->pending), ++ .connections = LIST_HEAD_INIT(port->connections) }); ++ list_add(&port->list, &ports); ++ ++ found: ++ dev = kmalloc(sizeof(struct port_dev), GFP_KERNEL); ++ if(dev == NULL){ ++ printk(KERN_ERR "Allocation of port device entry failed\n"); ++ goto out; ++ } ++ ++ *dev = ((struct port_dev) { .port = port, ++ .helper_pid = -1, ++ .telnetd_pid = -1 }); ++ goto out; ++ ++ out_free: ++ kfree(port); ++ out_close: ++ os_close_file(fd); ++ out: ++ up(&ports_sem); ++ return(dev); ++} ++ ++int port_wait(void *data) ++{ ++ struct port_dev *dev = data; ++ struct connection *conn; ++ struct port_list *port = dev->port; ++ int fd; ++ ++ while(1){ ++ if(down_interruptible(&port->sem)) ++ return(-ERESTARTSYS); ++ ++ spin_lock(&port->lock); ++ ++ conn = list_entry(port->connections.next, struct connection, ++ list); ++ list_del(&conn->list); ++ spin_unlock(&port->lock); ++ ++ os_shutdown_socket(conn->socket[0], 1, 1); ++ os_close_file(conn->socket[0]); ++ os_shutdown_socket(conn->socket[1], 1, 1); ++ os_close_file(conn->socket[1]); ++ ++ /* This is done here because freeing an IRQ can't be done ++ * within the IRQ handler. So, pipe_interrupt always ups ++ * the semaphore regardless of whether it got a successful ++ * connection. Then we loop here throwing out failed ++ * connections until a good one is found. ++ */ ++ free_irq(TELNETD_IRQ, conn); ++ ++ if(conn->fd >= 0) break; ++ os_close_file(conn->fd); ++ kfree(conn); ++ } ++ ++ fd = conn->fd; ++ dev->helper_pid = conn->helper_pid; ++ dev->telnetd_pid = conn->telnetd_pid; ++ kfree(conn); ++ ++ return(fd); ++} ++ ++void port_remove_dev(void *d) ++{ ++ struct port_dev *dev = d; ++ ++ if(dev->helper_pid != -1) ++ os_kill_process(dev->helper_pid, 0); ++ if(dev->telnetd_pid != -1) ++ os_kill_process(dev->telnetd_pid, 1); ++ dev->helper_pid = -1; ++ dev->telnetd_pid = -1; ++} ++ ++void port_kern_free(void *d) ++{ ++ struct port_dev *dev = d; ++ ++ port_remove_dev(dev); ++ kfree(dev); ++} ++ ++static void free_port(void) ++{ ++ struct list_head *ele; ++ struct port_list *port; ++ ++ list_for_each(ele, &ports){ ++ port = list_entry(ele, struct port_list, list); ++ free_irq_by_fd(port->fd); ++ os_close_file(port->fd); ++ } ++} ++ ++__uml_exitcall(free_port); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/port_user.c um/arch/um/drivers/port_user.c +--- orig/arch/um/drivers/port_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/port_user.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,213 @@ ++/* ++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include ++#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; ++ ++ fd = port_wait(data->kernel_data); ++ if((fd >= 0) && data->raw){ ++ tcgetattr(fd, &data->tt); ++ raw(fd, 0); ++ } ++ *dev_out = data->dev; ++ return(fd); ++} ++ ++void port_close(int fd, void *d) ++{ ++ struct port_chan *data = d; ++ ++ port_remove_dev(data->kernel_data); ++ os_close_file(fd); ++} ++ ++int port_console_write(int fd, const char *buf, int n, void *d) ++{ ++ struct port_chan *data = d; ++ ++ return(generic_console_write(fd, buf, n, &data->tt)); ++} ++ ++struct chan_ops port_ops = { ++ .type = "port", ++ .init = port_init, ++ .open = port_open, ++ .close = port_close, ++ .read = generic_read, ++ .write = generic_write, ++ .console_write = port_console_write, ++ .window_size = generic_window_size, ++ .free = port_free, ++ .winch = 1, ++}; ++ ++int port_listen_fd(int port) ++{ ++ struct sockaddr_in addr; ++ int fd, err; ++ ++ fd = socket(PF_INET, SOCK_STREAM, 0); ++ if(fd == -1) ++ return(-errno); ++ ++ addr.sin_family = AF_INET; ++ addr.sin_port = htons(port); ++ addr.sin_addr.s_addr = htonl(INADDR_ANY); ++ if(bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0){ ++ err = -errno; ++ goto out; ++ } ++ ++ if(listen(fd, 1) < 0){ ++ err = -errno; ++ goto out; ++ } ++ ++ err = os_set_fd_block(fd, 0); ++ if(err < 0) ++ goto out; ++ ++ return(fd); ++ out: ++ os_close_file(fd); ++ return(err); ++} ++ ++struct port_pre_exec_data { ++ int sock_fd; ++ int pipe_fd; ++}; ++ ++void port_pre_exec(void *arg) ++{ ++ struct port_pre_exec_data *data = arg; ++ ++ dup2(data->sock_fd, 0); ++ dup2(data->sock_fd, 1); ++ dup2(data->sock_fd, 2); ++ os_close_file(data->sock_fd); ++ dup2(data->pipe_fd, 3); ++ os_shutdown_socket(3, 1, 0); ++ os_close_file(data->pipe_fd); ++} ++ ++int port_connection(int fd, int *socket, int *pid_out) ++{ ++ int new, err; ++ char *argv[] = { "/usr/sbin/in.telnetd", "-L", ++ "/usr/lib/uml/port-helper", NULL }; ++ struct port_pre_exec_data data; ++ ++ new = os_accept_connection(fd); ++ if(new < 0) ++ return(new); ++ ++ err = os_pipe(socket, 0, 0); ++ if(err < 0) ++ goto out_close; ++ ++ data = ((struct port_pre_exec_data) ++ { .sock_fd = new, ++ .pipe_fd = socket[1] }); ++ ++ err = run_helper(port_pre_exec, &data, argv, NULL); ++ if(err < 0) ++ goto out_shutdown; ++ ++ *pid_out = err; ++ return(new); ++ ++ out_shutdown: ++ os_shutdown_socket(socket[0], 1, 1); ++ os_close_file(socket[0]); ++ os_shutdown_socket(socket[1], 1, 1); ++ os_close_file(socket[1]); ++ out_close: ++ os_close_file(new); ++ return(err); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/pty.c um/arch/um/drivers/pty.c +--- orig/arch/um/drivers/pty.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/pty.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,148 @@ ++/* ++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include ++#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; ++ ++ fd = get_pty(); ++ if(fd < 0){ ++ printk("open_pts : Failed to open pts\n"); ++ return(-errno); ++ } ++ if(data->raw){ ++ tcgetattr(fd, &data->tt); ++ raw(fd, 0); ++ } ++ ++ dev = ptsname(fd); ++ sprintf(data->dev_name, "%s", dev); ++ *dev_out = data->dev_name; ++ if(data->announce) (*data->announce)(dev, data->dev); ++ return(fd); ++} ++ ++int getmaster(char *line) ++{ ++ char *pty, *bank, *cp; ++ int master, err; ++ ++ pty = &line[strlen("/dev/ptyp")]; ++ for (bank = "pqrs"; *bank; bank++) { ++ line[strlen("/dev/pty")] = *bank; ++ *pty = '0'; ++ if (os_stat_file(line, NULL) < 0) ++ break; ++ for (cp = "0123456789abcdef"; *cp; cp++) { ++ *pty = *cp; ++ master = os_open_file(line, of_rdwr(OPENFLAGS()), 0); ++ if (master >= 0) { ++ char *tp = &line[strlen("/dev/")]; ++ ++ /* verify slave side is usable */ ++ *tp = 't'; ++ err = os_access(line, OS_ACC_RW_OK); ++ *tp = 'p'; ++ if(err == 0) return(master); ++ (void) os_close_file(master); ++ } ++ } ++ } ++ return(-1); ++} ++ ++int pty_open(int input, int output, int primary, void *d, char **dev_out) ++{ ++ struct pty_chan *data = d; ++ int fd; ++ char dev[sizeof("/dev/ptyxx\0")] = "/dev/ptyxx"; ++ ++ fd = getmaster(dev); ++ if(fd < 0) return(-errno); ++ ++ if(data->raw) raw(fd, 0); ++ if(data->announce) (*data->announce)(dev, data->dev); ++ ++ sprintf(data->dev_name, "%s", dev); ++ *dev_out = data->dev_name; ++ return(fd); ++} ++ ++int pty_console_write(int fd, const char *buf, int n, void *d) ++{ ++ struct pty_chan *data = d; ++ ++ return(generic_console_write(fd, buf, n, &data->tt)); ++} ++ ++struct chan_ops pty_ops = { ++ .type = "pty", ++ .init = pty_chan_init, ++ .open = pty_open, ++ .close = generic_close, ++ .read = generic_read, ++ .write = generic_write, ++ .console_write = pty_console_write, ++ .window_size = generic_window_size, ++ .free = generic_free, ++ .winch = 0, ++}; ++ ++struct chan_ops pts_ops = { ++ .type = "pts", ++ .init = pty_chan_init, ++ .open = pts_open, ++ .close = generic_close, ++ .read = generic_read, ++ .write = generic_write, ++ .console_write = pty_console_write, ++ .window_size = generic_window_size, ++ .free = generic_free, ++ .winch = 0, ++}; ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/slip.h um/arch/um/drivers/slip.h +--- orig/arch/um/drivers/slip.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/slip.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,39 @@ ++#ifndef __UM_SLIP_H ++#define __UM_SLIP_H ++ ++#define BUF_SIZE 1500 ++ /* two bytes each for a (pathological) max packet of escaped chars + * ++ * terminating END char + initial END char */ ++#define ENC_BUF_SIZE (2 * BUF_SIZE + 2) ++ ++struct slip_data { ++ void *dev; ++ char name[sizeof("slnnnnn\0")]; ++ char *addr; ++ char *gate_addr; ++ int slave; ++ char ibuf[ENC_BUF_SIZE]; ++ char obuf[ENC_BUF_SIZE]; ++ int more; /* more data: do not read fd until ibuf has been drained */ ++ int pos; ++ int esc; ++}; ++ ++extern struct net_user_info slip_user_info; ++ ++extern int set_umn_addr(int fd, char *addr, char *ptp_addr); ++extern int slip_user_read(int fd, void *buf, int len, struct slip_data *pri); ++extern int slip_user_write(int fd, void *buf, int len, struct slip_data *pri); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/slip_kern.c um/arch/um/drivers/slip_kern.c +--- orig/arch/um/drivers/slip_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/slip_kern.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,109 @@ ++#include "linux/config.h" ++#include "linux/kernel.h" ++#include "linux/stddef.h" ++#include "linux/init.h" ++#include "linux/netdevice.h" ++#include "linux/if_arp.h" ++#include "net_kern.h" ++#include "net_user.h" ++#include "kern.h" ++#include "slip.h" ++ ++struct slip_init { ++ char *gate_addr; ++}; ++ ++void slip_init(struct net_device *dev, void *data) ++{ ++ struct uml_net_private *private; ++ struct slip_data *spri; ++ struct slip_init *init = data; ++ ++ private = dev->priv; ++ spri = (struct slip_data *) private->user; ++ *spri = ((struct slip_data) ++ { .name = { '\0' }, ++ .addr = NULL, ++ .gate_addr = init->gate_addr, ++ .slave = -1, ++ .ibuf = { '\0' }, ++ .obuf = { '\0' }, ++ .pos = 0, ++ .esc = 0, ++ .dev = dev }); ++ ++ dev->init = NULL; ++ dev->hard_header_len = 0; ++ dev->addr_len = 4; ++ dev->type = ARPHRD_ETHER; ++ dev->tx_queue_len = 256; ++ dev->flags = IFF_NOARP; ++ printk("SLIP backend - SLIP IP = %s\n", spri->gate_addr); ++} ++ ++static unsigned short slip_protocol(struct sk_buff *skbuff) ++{ ++ return(htons(ETH_P_IP)); ++} ++ ++static int slip_read(int fd, struct sk_buff **skb, ++ struct uml_net_private *lp) ++{ ++ return(slip_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu, ++ (struct slip_data *) &lp->user)); ++} ++ ++static int slip_write(int fd, struct sk_buff **skb, ++ struct uml_net_private *lp) ++{ ++ return(slip_user_write(fd, (*skb)->data, (*skb)->len, ++ (struct slip_data *) &lp->user)); ++} ++ ++struct net_kern_info slip_kern_info = { ++ .init = slip_init, ++ .protocol = slip_protocol, ++ .read = slip_read, ++ .write = slip_write, ++}; ++ ++static int slip_setup(char *str, char **mac_out, void *data) ++{ ++ struct slip_init *init = data; ++ ++ *init = ((struct slip_init) ++ { .gate_addr = NULL }); ++ ++ if(str[0] != '\0') ++ init->gate_addr = str; ++ return(1); ++} ++ ++static struct transport slip_transport = { ++ .list = LIST_HEAD_INIT(slip_transport.list), ++ .name = "slip", ++ .setup = slip_setup, ++ .user = &slip_user_info, ++ .kern = &slip_kern_info, ++ .private_size = sizeof(struct slip_data), ++ .setup_size = sizeof(struct slip_init), ++}; ++ ++static int register_slip(void) ++{ ++ register_transport(&slip_transport); ++ return(1); ++} ++ ++__initcall(register_slip); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/slip_proto.h um/arch/um/drivers/slip_proto.h +--- orig/arch/um/drivers/slip_proto.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/slip_proto.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,93 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UM_SLIP_PROTO_H__ ++#define __UM_SLIP_PROTO_H__ ++ ++/* SLIP protocol characters. */ ++#define SLIP_END 0300 /* indicates end of frame */ ++#define SLIP_ESC 0333 /* indicates byte stuffing */ ++#define SLIP_ESC_END 0334 /* ESC ESC_END means END 'data' */ ++#define SLIP_ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */ ++ ++static inline int slip_unesc(unsigned char c,char *buf,int *pos, int *esc) ++{ ++ int ret; ++ ++ switch(c){ ++ case SLIP_END: ++ *esc = 0; ++ ret=*pos; ++ *pos=0; ++ return(ret); ++ case SLIP_ESC: ++ *esc = 1; ++ return(0); ++ case SLIP_ESC_ESC: ++ if(*esc){ ++ *esc = 0; ++ c = SLIP_ESC; ++ } ++ break; ++ case SLIP_ESC_END: ++ if(*esc){ ++ *esc = 0; ++ c = SLIP_END; ++ } ++ break; ++ } ++ buf[(*pos)++] = c; ++ return(0); ++} ++ ++static inline int slip_esc(unsigned char *s, unsigned char *d, int len) ++{ ++ unsigned char *ptr = d; ++ unsigned char c; ++ ++ /* ++ * Send an initial END character to flush out any ++ * data that may have accumulated in the receiver ++ * due to line noise. ++ */ ++ ++ *ptr++ = SLIP_END; ++ ++ /* ++ * For each byte in the packet, send the appropriate ++ * character sequence, according to the SLIP protocol. ++ */ ++ ++ while (len-- > 0) { ++ switch(c = *s++) { ++ case SLIP_END: ++ *ptr++ = SLIP_ESC; ++ *ptr++ = SLIP_ESC_END; ++ break; ++ case SLIP_ESC: ++ *ptr++ = SLIP_ESC; ++ *ptr++ = SLIP_ESC_ESC; ++ break; ++ default: ++ *ptr++ = c; ++ break; ++ } ++ } ++ *ptr++ = SLIP_END; ++ return (ptr - d); ++} ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/slip_user.c um/arch/um/drivers/slip_user.c +--- orig/arch/um/drivers/slip_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/slip_user.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,274 @@ ++#include ++#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); ++ } ++ if(waitpid(pid, &status, 0) < 0) err = errno; ++ else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)){ ++ printk("'%s' didn't exit with status 0\n", argv[0]); ++ err = -EINVAL; ++ } ++ } ++ return(err); ++} ++ ++static int slip_open(void *data) ++{ ++ struct slip_data *pri = data; ++ char version_buf[sizeof("nnnnn\0")]; ++ char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")]; ++ char *argv[] = { "uml_net", version_buf, "slip", "up", gate_buf, ++ NULL }; ++ int sfd, mfd, err; ++ ++ mfd = get_pty(); ++ if(mfd < 0){ ++ printk("umn : Failed to open pty, err = %d\n", -mfd); ++ return(mfd); ++ } ++ sfd = os_open_file(ptsname(mfd), of_rdwr(OPENFLAGS()), 0); ++ if(sfd < 0){ ++ printk("Couldn't open tty for slip line, err = %d\n", -sfd); ++ return(sfd); ++ } ++ if(set_up_tty(sfd)) return(-1); ++ pri->slave = sfd; ++ pri->pos = 0; ++ pri->esc = 0; ++ if(pri->gate_addr != NULL){ ++ sprintf(version_buf, "%d", UML_NET_VERSION); ++ strcpy(gate_buf, pri->gate_addr); ++ ++ err = slip_tramp(argv, sfd); ++ ++ if(err < 0){ ++ printk("slip_tramp failed - err = %d\n", -err); ++ return(err); ++ } ++ err = os_get_ifname(pri->slave, pri->name); ++ if(err < 0){ ++ printk("get_ifname failed, err = %d\n", -err); ++ return(err); ++ } ++ iter_addresses(pri->dev, open_addr, pri->name); ++ } ++ else { ++ err = os_set_slip(sfd); ++ if(err < 0){ ++ printk("Failed to set slip discipline encapsulation - " ++ "err = %d\n", -err); ++ return(err); ++ } ++ } ++ return(mfd); ++} ++ ++static void slip_close(int fd, void *data) ++{ ++ struct slip_data *pri = data; ++ char version_buf[sizeof("nnnnn\0")]; ++ char *argv[] = { "uml_net", version_buf, "slip", "down", pri->name, ++ NULL }; ++ int err; ++ ++ if(pri->gate_addr != NULL) ++ iter_addresses(pri->dev, close_addr, pri->name); ++ ++ sprintf(version_buf, "%d", UML_NET_VERSION); ++ ++ err = slip_tramp(argv, -1); ++ ++ if(err != 0) ++ printk("slip_tramp failed - errno = %d\n", -err); ++ os_close_file(fd); ++ os_close_file(pri->slave); ++ pri->slave = -1; ++} ++ ++int slip_user_read(int fd, void *buf, int len, struct slip_data *pri) ++{ ++ int i, n, size, start; ++ ++ if(pri->more>0) { ++ i = 0; ++ while(i < pri->more) { ++ size = slip_unesc(pri->ibuf[i++], ++ pri->ibuf, &pri->pos, &pri->esc); ++ if(size){ ++ memcpy(buf, pri->ibuf, size); ++ memmove(pri->ibuf, &pri->ibuf[i], pri->more-i); ++ pri->more=pri->more-i; ++ return(size); ++ } ++ } ++ pri->more=0; ++ } ++ ++ n = net_read(fd, &pri->ibuf[pri->pos], sizeof(pri->ibuf) - pri->pos); ++ if(n <= 0) return(n); ++ ++ start = pri->pos; ++ for(i = 0; i < n; i++){ ++ size = slip_unesc(pri->ibuf[start + i], ++ pri->ibuf, &pri->pos, &pri->esc); ++ if(size){ ++ memcpy(buf, pri->ibuf, size); ++ memmove(pri->ibuf, &pri->ibuf[start+i+1], n-(i+1)); ++ pri->more=n-(i+1); ++ return(size); ++ } ++ } ++ return(0); ++} ++ ++int slip_user_write(int fd, void *buf, int len, struct slip_data *pri) ++{ ++ int actual, n; ++ ++ actual = slip_esc(buf, pri->obuf, len); ++ n = net_write(fd, pri->obuf, actual); ++ if(n < 0) return(n); ++ else return(len); ++} ++ ++static int slip_set_mtu(int mtu, void *data) ++{ ++ return(mtu); ++} ++ ++static void slip_add_addr(unsigned char *addr, unsigned char *netmask, ++ void *data) ++{ ++ struct slip_data *pri = data; ++ ++ if(pri->slave < 0) return; ++ open_addr(addr, netmask, pri->name); ++} ++ ++static void slip_del_addr(unsigned char *addr, unsigned char *netmask, ++ void *data) ++{ ++ struct slip_data *pri = data; ++ ++ if(pri->slave < 0) return; ++ close_addr(addr, netmask, pri->name); ++} ++ ++struct net_user_info slip_user_info = { ++ .init = slip_user_init, ++ .open = slip_open, ++ .close = slip_close, ++ .remove = NULL, ++ .set_mtu = slip_set_mtu, ++ .add_address = slip_add_addr, ++ .delete_address = slip_del_addr, ++ .max_packet = BUF_SIZE ++}; ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/slirp.h um/arch/um/drivers/slirp.h +--- orig/arch/um/drivers/slirp.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/slirp.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,51 @@ ++#ifndef __UM_SLIRP_H ++#define __UM_SLIRP_H ++ ++#define BUF_SIZE 1500 ++ /* two bytes each for a (pathological) max packet of escaped chars + * ++ * terminating END char + initial END char */ ++#define ENC_BUF_SIZE (2 * BUF_SIZE + 2) ++ ++#define SLIRP_MAX_ARGS 100 ++/* ++ * XXX this next definition is here because I don't understand why this ++ * initializer doesn't work in slirp_kern.c: ++ * ++ * argv : { init->argv[ 0 ... SLIRP_MAX_ARGS-1 ] }, ++ * ++ * or why I can't typecast like this: ++ * ++ * argv : (char* [SLIRP_MAX_ARGS])(init->argv), ++ */ ++struct arg_list_dummy_wrapper { char *argv[SLIRP_MAX_ARGS]; }; ++ ++struct slirp_data { ++ void *dev; ++ struct arg_list_dummy_wrapper argw; ++ int pid; ++ int slave; ++ char ibuf[ENC_BUF_SIZE]; ++ char obuf[ENC_BUF_SIZE]; ++ int more; /* more data: do not read fd until ibuf has been drained */ ++ int pos; ++ int esc; ++}; ++ ++extern struct net_user_info slirp_user_info; ++ ++extern int set_umn_addr(int fd, char *addr, char *ptp_addr); ++extern int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri); ++extern int slirp_user_write(int fd, void *buf, int len, struct slirp_data *pri); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/slirp_kern.c um/arch/um/drivers/slirp_kern.c +--- orig/arch/um/drivers/slirp_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/slirp_kern.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,132 @@ ++#include "linux/kernel.h" ++#include "linux/stddef.h" ++#include "linux/init.h" ++#include "linux/netdevice.h" ++#include "linux/if_arp.h" ++#include "net_kern.h" ++#include "net_user.h" ++#include "kern.h" ++#include "slirp.h" ++ ++struct slirp_init { ++ struct arg_list_dummy_wrapper argw; /* XXX should be simpler... */ ++}; ++ ++void slirp_init(struct net_device *dev, void *data) ++{ ++ struct uml_net_private *private; ++ struct slirp_data *spri; ++ struct slirp_init *init = data; ++ int i; ++ ++ private = dev->priv; ++ spri = (struct slirp_data *) private->user; ++ *spri = ((struct slirp_data) ++ { .argw = init->argw, ++ .pid = -1, ++ .slave = -1, ++ .ibuf = { '\0' }, ++ .obuf = { '\0' }, ++ .pos = 0, ++ .esc = 0, ++ .dev = dev }); ++ ++ dev->init = NULL; ++ dev->hard_header_len = 0; ++ dev->addr_len = 4; ++ dev->type = ARPHRD_ETHER; ++ dev->tx_queue_len = 256; ++ dev->flags = IFF_NOARP; ++ printk("SLIRP backend - command line:"); ++ for(i=0;spri->argw.argv[i]!=NULL;i++) { ++ printk(" '%s'",spri->argw.argv[i]); ++ } ++ printk("\n"); ++} ++ ++static unsigned short slirp_protocol(struct sk_buff *skbuff) ++{ ++ return(htons(ETH_P_IP)); ++} ++ ++static int slirp_read(int fd, struct sk_buff **skb, ++ struct uml_net_private *lp) ++{ ++ return(slirp_user_read(fd, (*skb)->mac.raw, (*skb)->dev->mtu, ++ (struct slirp_data *) &lp->user)); ++} ++ ++static int slirp_write(int fd, struct sk_buff **skb, ++ struct uml_net_private *lp) ++{ ++ return(slirp_user_write(fd, (*skb)->data, (*skb)->len, ++ (struct slirp_data *) &lp->user)); ++} ++ ++struct net_kern_info slirp_kern_info = { ++ .init = slirp_init, ++ .protocol = slirp_protocol, ++ .read = slirp_read, ++ .write = slirp_write, ++}; ++ ++static int slirp_setup(char *str, char **mac_out, void *data) ++{ ++ struct slirp_init *init = data; ++ int i=0; ++ ++ *init = ((struct slirp_init) ++ { argw : { { "slirp", NULL } } }); ++ ++ str = split_if_spec(str, mac_out, NULL); ++ ++ if(str == NULL) { /* no command line given after MAC addr */ ++ return(1); ++ } ++ ++ do { ++ if(i>=SLIRP_MAX_ARGS-1) { ++ printk("slirp_setup: truncating slirp arguments\n"); ++ break; ++ } ++ init->argw.argv[i++] = str; ++ while(*str && *str!=',') { ++ if(*str=='_') *str=' '; ++ str++; ++ } ++ if(*str!=',') ++ break; ++ *str++='\0'; ++ } while(1); ++ init->argw.argv[i]=NULL; ++ return(1); ++} ++ ++static struct transport slirp_transport = { ++ .list = LIST_HEAD_INIT(slirp_transport.list), ++ .name = "slirp", ++ .setup = slirp_setup, ++ .user = &slirp_user_info, ++ .kern = &slirp_kern_info, ++ .private_size = sizeof(struct slirp_data), ++ .setup_size = sizeof(struct slirp_init), ++}; ++ ++static int register_slirp(void) ++{ ++ register_transport(&slirp_transport); ++ return(1); ++} ++ ++__initcall(register_slirp); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/slirp_user.c um/arch/um/drivers/slirp_user.c +--- orig/arch/um/drivers/slirp_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/slirp_user.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,201 @@ ++#include ++#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 ++ ++ err = waitpid(pri->pid, &status, WNOHANG); ++ if(err<0) { ++ printk("slirp_close: waitpid returned %d\n", errno); ++ return; ++ } ++ ++ if(err==0) { ++ printk("slirp_close: process %d has not exited\n"); ++ return; ++ } ++ ++ pri->pid = -1; ++} ++ ++int slirp_user_read(int fd, void *buf, int len, struct slirp_data *pri) ++{ ++ int i, n, size, start; ++ ++ if(pri->more>0) { ++ i = 0; ++ while(i < pri->more) { ++ size = slip_unesc(pri->ibuf[i++], ++ pri->ibuf,&pri->pos,&pri->esc); ++ if(size){ ++ memcpy(buf, pri->ibuf, size); ++ memmove(pri->ibuf, &pri->ibuf[i], pri->more-i); ++ pri->more=pri->more-i; ++ return(size); ++ } ++ } ++ pri->more=0; ++ } ++ ++ n = net_read(fd, &pri->ibuf[pri->pos], sizeof(pri->ibuf) - pri->pos); ++ if(n <= 0) return(n); ++ ++ start = pri->pos; ++ for(i = 0; i < n; i++){ ++ size = slip_unesc(pri->ibuf[start + i], ++ pri->ibuf,&pri->pos,&pri->esc); ++ if(size){ ++ memcpy(buf, pri->ibuf, size); ++ memmove(pri->ibuf, &pri->ibuf[start+i+1], n-(i+1)); ++ pri->more=n-(i+1); ++ return(size); ++ } ++ } ++ return(0); ++} ++ ++int slirp_user_write(int fd, void *buf, int len, struct slirp_data *pri) ++{ ++ int actual, n; ++ ++ actual = slip_esc(buf, pri->obuf, len); ++ n = net_write(fd, pri->obuf, actual); ++ if(n < 0) return(n); ++ else return(len); ++} ++ ++static int slirp_set_mtu(int mtu, void *data) ++{ ++ return(mtu); ++} ++ ++struct net_user_info slirp_user_info = { ++ .init = slirp_user_init, ++ .open = slirp_open, ++ .close = slirp_close, ++ .remove = NULL, ++ .set_mtu = slirp_set_mtu, ++ .add_address = NULL, ++ .delete_address = NULL, ++ .max_packet = BUF_SIZE ++}; ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/ssl.c um/arch/um/drivers/ssl.c +--- orig/arch/um/drivers/ssl.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/ssl.c 2003-11-08 02:57:02.000000000 -0500 +@@ -0,0 +1,306 @@ ++/* ++ * 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) ++{ ++#if 0 /* This is the 2.5 implementation */ ++static struct tty_driver *ssl_console_device(struct console *c, int *index) ++ *index = c->index; ++ return ssl_driver; ++#endif ++ ++ return mk_kdev(TTY_MAJOR, c->index); ++} ++ ++static int ssl_console_setup(struct console *co, char *options) ++{ ++ return(0); ++} ++ ++static struct console ssl_cons = { ++ name: "ttyS", ++ write: ssl_console_write, ++ device: ssl_console_device, ++ setup: ssl_console_setup, ++ flags: CON_PRINTBUFFER, ++ index: -1, ++}; ++ ++int ssl_init(void) ++{ ++ char *new_title; ++ ++ printk(KERN_INFO "Initializing software serial port version %d\n", ++ ssl_version); ++ ++ line_register_devfs(&lines, &driver, &ssl_driver, serial_lines, ++ sizeof(serial_lines)/sizeof(serial_lines[0])); ++ ++ lines_init(serial_lines, sizeof(serial_lines)/sizeof(serial_lines[0])); ++ ++ new_title = add_xterm_umid(opts.xterm_title); ++ if(new_title != NULL) opts.xterm_title = new_title; ++ ++ register_console(&ssl_cons); ++ ssl_init_done = 1; ++ return(0); ++} ++ ++__initcall(ssl_init); ++ ++static int ssl_chan_setup(char *str) ++{ ++ return(line_setup(serial_lines, ++ sizeof(serial_lines)/sizeof(serial_lines[0]), ++ str, 1)); ++} ++ ++__setup("ssl", ssl_chan_setup); ++__channel_help(ssl_chan_setup, "ssl"); ++ ++static void ssl_exit(void) ++{ ++ if(!ssl_init_done) return; ++ close_lines(serial_lines, ++ sizeof(serial_lines)/sizeof(serial_lines[0])); ++} ++ ++__uml_exitcall(ssl_exit); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/ssl.h um/arch/um/drivers/ssl.h +--- orig/arch/um/drivers/ssl.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/ssl.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,23 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __SSL_H__ ++#define __SSL_H__ ++ ++extern int ssl_read(int fd, int line); ++extern void ssl_receive_char(int line, char ch); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/stdio_console.c um/arch/um/drivers/stdio_console.c +--- orig/arch/um/drivers/stdio_console.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/stdio_console.c 2003-11-07 03:03:03.000000000 -0500 +@@ -0,0 +1,258 @@ ++/* ++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/config.h" ++#include "linux/posix_types.h" ++#include "linux/tty.h" ++#include "linux/tty_flip.h" ++#include "linux/types.h" ++#include "linux/major.h" ++#include "linux/kdev_t.h" ++#include "linux/console.h" ++#include "linux/string.h" ++#include "linux/sched.h" ++#include "linux/list.h" ++#include "linux/init.h" ++#include "linux/interrupt.h" ++#include "linux/slab.h" ++#include "asm/current.h" ++#include "asm/softirq.h" ++#include "asm/hardirq.h" ++#include "asm/irq.h" ++#include "stdio_console.h" ++#include "line.h" ++#include "chan_kern.h" ++#include "user_util.h" ++#include "kern_util.h" ++#include "irq_user.h" ++#include "mconsole_kern.h" ++#include "init.h" ++#include "2_5compat.h" ++ ++#define MAX_TTYS (8) ++ ++/* Referenced only by tty_driver below - presumably it's locked correctly ++ * by the tty driver. ++ */ ++ ++static struct tty_driver console_driver; ++ ++static int console_refcount = 0; ++ ++static struct chan_ops init_console_ops = { ++ .type = "you shouldn't see this", ++ .init = NULL, ++ .open = NULL, ++ .close = NULL, ++ .read = NULL, ++ .write = NULL, ++ .console_write = generic_write, ++ .window_size = NULL, ++ .free = NULL, ++ .winch = 0, ++}; ++ ++static struct chan init_console_chan = { ++ .list = { }, ++ .primary = 1, ++ .input = 0, ++ .output = 1, ++ .opened = 1, ++ .fd = 1, ++ .pri = INIT_STATIC, ++ .ops = &init_console_ops, ++ .data = NULL ++}; ++ ++void stdio_announce(char *dev_name, int dev) ++{ ++ printk(KERN_INFO "Virtual console %d assigned device '%s'\n", dev, ++ dev_name); ++} ++ ++static struct chan_opts opts = { ++ .announce = stdio_announce, ++ .xterm_title = "Virtual Console #%d", ++ .raw = 1, ++ .tramp_stack = 0, ++ .in_kernel = 1, ++}; ++ ++static int con_config(char *str); ++static int con_get_config(char *dev, char *str, int size, char **error_out); ++static int con_remove(char *str); ++ ++static struct line_driver driver = { ++ .name = "UML console", ++ .devfs_name = "vc/%d", ++ .major = TTY_MAJOR, ++ .minor_start = 0, ++ .type = TTY_DRIVER_TYPE_CONSOLE, ++ .subtype = SYSTEM_TYPE_CONSOLE, ++ .read_irq = CONSOLE_IRQ, ++ .read_irq_name = "console", ++ .write_irq = CONSOLE_WRITE_IRQ, ++ .write_irq_name = "console-write", ++ .symlink_from = "ttys", ++ .symlink_to = "vc", ++ .mc = { ++ .name = "con", ++ .config = con_config, ++ .get_config = con_get_config, ++ .remove = con_remove, ++ }, ++}; ++ ++static struct lines console_lines = LINES_INIT(MAX_TTYS); ++ ++/* The array is initialized by line_init, which is an initcall. The ++ * individual elements are protected by individual semaphores. ++ */ ++struct line vts[MAX_TTYS] = { LINE_INIT(CONFIG_CON_ZERO_CHAN, &driver), ++ [ 1 ... MAX_TTYS - 1 ] = ++ LINE_INIT(CONFIG_CON_CHAN, &driver) }; ++ ++static int con_config(char *str) ++{ ++ return(line_config(vts, sizeof(vts)/sizeof(vts[0]), str)); ++} ++ ++static int con_get_config(char *dev, char *str, int size, char **error_out) ++{ ++ return(line_get_config(dev, vts, sizeof(vts)/sizeof(vts[0]), str, ++ size, error_out)); ++} ++ ++static int con_remove(char *str) ++{ ++ return(line_remove(vts, sizeof(vts)/sizeof(vts[0]), str)); ++} ++ ++static int open_console(struct tty_struct *tty) ++{ ++ return(line_open(vts, tty, &opts)); ++} ++ ++static int con_open(struct tty_struct *tty, struct file *filp) ++{ ++ return(open_console(tty)); ++} ++ ++static void con_close(struct tty_struct *tty, struct file *filp) ++{ ++ line_close(vts, tty); ++} ++ ++static int con_write(struct tty_struct *tty, int from_user, ++ const unsigned char *buf, int count) ++{ ++ return(line_write(vts, tty, from_user, buf, count)); ++} ++ ++static void set_termios(struct tty_struct *tty, struct termios * old) ++{ ++} ++ ++static int chars_in_buffer(struct tty_struct *tty) ++{ ++ return(0); ++} ++ ++static int con_init_done = 0; ++ ++int stdio_init(void) ++{ ++ char *new_title; ++ ++ printk(KERN_INFO "Initializing stdio console driver\n"); ++ ++ line_register_devfs(&console_lines, &driver, &console_driver, vts, ++ sizeof(vts)/sizeof(vts[0])); ++ ++ lines_init(vts, sizeof(vts)/sizeof(vts[0])); ++ ++ new_title = add_xterm_umid(opts.xterm_title); ++ if(new_title != NULL) opts.xterm_title = new_title; ++ ++ open_console(NULL); ++ con_init_done = 1; ++ return(0); ++} ++ ++__initcall(stdio_init); ++ ++static void console_write(struct console *console, const char *string, ++ unsigned len) ++{ ++ struct line *line = &vts[console->index]; ++ ++ if(con_init_done) ++ down(&line->sem); ++ console_write_chan(&line->chan_list, string, len); ++ if(con_init_done) ++ up(&line->sem); ++} ++ ++static struct tty_driver console_driver = { ++ .refcount = &console_refcount, ++ .open = con_open, ++ .close = con_close, ++ .write = con_write, ++ .chars_in_buffer = chars_in_buffer, ++ .set_termios = set_termios ++}; ++ ++static kdev_t console_device(struct console *c) ++{ ++ return mk_kdev(TTY_MAJOR, c->index); ++} ++ ++static int console_setup(struct console *co, char *options) ++{ ++ return(0); ++} ++ ++static struct console stdiocons = { ++ name: "tty", ++ write: console_write, ++ device: console_device, ++ setup: console_setup, ++ flags: CON_PRINTBUFFER, ++ index: -1, ++}; ++ ++void stdio_console_init(void) ++{ ++ INIT_LIST_HEAD(&vts[0].chan_list); ++ list_add(&init_console_chan.list, &vts[0].chan_list); ++ register_console(&stdiocons); ++} ++ ++static int console_chan_setup(char *str) ++{ ++ return(line_setup(vts, sizeof(vts)/sizeof(vts[0]), str, 1)); ++} ++ ++__setup("con", console_chan_setup); ++__channel_help(console_chan_setup, "con"); ++ ++static void console_exit(void) ++{ ++ if(!con_init_done) return; ++ close_lines(vts, sizeof(vts)/sizeof(vts[0])); ++} ++ ++__uml_exitcall(console_exit); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/stdio_console.h um/arch/um/drivers/stdio_console.h +--- orig/arch/um/drivers/stdio_console.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/stdio_console.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,21 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __STDIO_CONSOLE_H ++#define __STDIO_CONSOLE_H ++ ++extern void save_console_flags(void); ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/tty.c um/arch/um/drivers/tty.c +--- orig/arch/um/drivers/tty.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/tty.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,86 @@ ++/* ++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include ++#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; ++ ++ fd = os_open_file(data->dev, of_set_rw(OPENFLAGS(), input, output), 0); ++ if(fd < 0) return(fd); ++ if(data->raw){ ++ tcgetattr(fd, &data->tt); ++ raw(fd, 0); ++ } ++ ++ *dev_out = data->dev; ++ return(fd); ++} ++ ++int tty_console_write(int fd, const char *buf, int n, void *d) ++{ ++ struct tty_chan *data = d; ++ ++ return(generic_console_write(fd, buf, n, &data->tt)); ++} ++ ++struct chan_ops tty_ops = { ++ .type = "tty", ++ .init = tty_chan_init, ++ .open = tty_open, ++ .close = generic_close, ++ .read = generic_read, ++ .write = generic_write, ++ .console_write = tty_console_write, ++ .window_size = generic_window_size, ++ .free = generic_free, ++ .winch = 0, ++}; ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/ubd_kern.c um/arch/um/drivers/ubd_kern.c +--- orig/arch/um/drivers/ubd_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/ubd_kern.c 2003-12-17 10:48:17.000000000 -0500 +@@ -0,0 +1,1390 @@ ++/* ++ * 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); ++ if(dev->cow.file != NULL) { ++ os_close_file(dev->cow.fd); ++ vfree(dev->cow.bitmap); ++ dev->cow.bitmap = NULL; ++ } ++} ++ ++static int ubd_open_dev(struct ubd *dev) ++{ ++ struct openflags flags; ++ char **back_ptr; ++ int err, create_cow, *create_ptr; ++ ++ dev->openflags = dev->boot_openflags; ++ create_cow = 0; ++ create_ptr = (dev->cow.file != NULL) ? &create_cow : NULL; ++ back_ptr = dev->no_cow ? NULL : &dev->cow.file; ++ dev->fd = open_ubd_file(dev->file, &dev->openflags, back_ptr, ++ &dev->cow.bitmap_offset, &dev->cow.bitmap_len, ++ &dev->cow.data_offset, create_ptr); ++ ++ if((dev->fd == -ENOENT) && create_cow){ ++ dev->fd = create_cow_file(dev->file, dev->cow.file, ++ dev->openflags, 1 << 9, PAGE_SIZE, ++ &dev->cow.bitmap_offset, ++ &dev->cow.bitmap_len, ++ &dev->cow.data_offset); ++ if(dev->fd >= 0){ ++ printk(KERN_INFO "Creating \"%s\" as COW file for " ++ "\"%s\"\n", dev->file, dev->cow.file); ++ } ++ } ++ ++ if(dev->fd < 0) return(dev->fd); ++ ++ if(dev->cow.file != NULL){ ++ err = -ENOMEM; ++ dev->cow.bitmap = (void *) vmalloc(dev->cow.bitmap_len); ++ if(dev->cow.bitmap == NULL){ ++ printk(KERN_ERR "Failed to vmalloc COW bitmap\n"); ++ goto error; ++ } ++ flush_tlb_kernel_vm(); ++ ++ err = read_cow_bitmap(dev->fd, dev->cow.bitmap, ++ dev->cow.bitmap_offset, ++ dev->cow.bitmap_len); ++ if(err < 0) goto error; ++ ++ flags = dev->openflags; ++ flags.w = 0; ++ err = open_ubd_file(dev->cow.file, &flags, NULL, NULL, NULL, ++ NULL, NULL); ++ if(err < 0) goto error; ++ dev->cow.fd = err; ++ } ++ return(0); ++ error: ++ os_close_file(dev->fd); ++ return(err); ++} ++ ++static int ubd_file_size(struct ubd *dev, __u64 *size_out) ++{ ++ char *file; ++ ++ file = dev->cow.file ? dev->cow.file : dev->file; ++ return(os_file_size(file, size_out)); ++} ++ ++static int ubd_open(struct inode *inode, struct file *filp) ++{ ++ struct ubd *dev; ++ int n, offset, err = 0; ++ ++ n = DEVICE_NR(inode->i_rdev); ++ dev = &ubd_dev[n]; ++ if(n >= MAX_DEV) ++ return -ENODEV; ++ ++ spin_lock(&ubd_lock); ++ offset = n << UBD_SHIFT; ++ ++ if(dev->count == 0){ ++ err = ubd_open_dev(dev); ++ if(err){ ++ printk(KERN_ERR "ubd%d: Can't open \"%s\": " ++ "errno = %d\n", n, dev->file, -err); ++ goto out; ++ } ++ err = ubd_file_size(dev, &dev->size); ++ if(err < 0) ++ goto out; ++ sizes[offset] = dev->size / BLOCK_SIZE; ++ ubd_part[offset].nr_sects = dev->size / hardsect_sizes[offset]; ++ } ++ dev->count++; ++ if((filp->f_mode & FMODE_WRITE) && !dev->openflags.w){ ++ if(--dev->count == 0) ubd_close(dev); ++ err = -EROFS; ++ } ++ out: ++ spin_unlock(&ubd_lock); ++ return(err); ++} ++ ++static int ubd_release(struct inode * inode, struct file * file) ++{ ++ int n, offset; ++ ++ n = DEVICE_NR(inode->i_rdev); ++ offset = n << UBD_SHIFT; ++ if(n >= MAX_DEV) ++ return -ENODEV; ++ ++ spin_lock(&ubd_lock); ++ if(--ubd_dev[n].count == 0) ++ ubd_close(&ubd_dev[n]); ++ spin_unlock(&ubd_lock); ++ ++ return(0); ++} ++ ++static void cowify_bitmap(__u64 io_offset, int length, unsigned long *cow_mask, ++ __u64 *cow_offset, unsigned long *bitmap, ++ __u64 bitmap_offset, unsigned long *bitmap_words, ++ __u64 bitmap_len) ++{ ++ __u64 sector = io_offset >> 9; ++ int i, update_bitmap = 0; ++ ++ for(i = 0; i < length >> 9; i++){ ++ if(cow_mask != NULL) ++ ubd_set_bit(i, (unsigned char *) cow_mask); ++ if(ubd_test_bit(sector + i, (unsigned char *) bitmap)) ++ continue; ++ ++ update_bitmap = 1; ++ ubd_set_bit(sector + i, (unsigned char *) bitmap); ++ } ++ ++ if(!update_bitmap) ++ return; ++ ++ *cow_offset = sector / (sizeof(unsigned long) * 8); ++ ++ /* This takes care of the case where we're exactly at the end of the ++ * device, and *cow_offset + 1 is off the end. So, just back it up ++ * by one word. Thanks to Lynn Kerby for the fix and James McMechan ++ * for the original diagnosis. ++ */ ++ if(*cow_offset == ((bitmap_len + sizeof(unsigned long) - 1) / ++ sizeof(unsigned long) - 1)) ++ (*cow_offset)--; ++ ++ bitmap_words[0] = bitmap[*cow_offset]; ++ bitmap_words[1] = bitmap[*cow_offset + 1]; ++ ++ *cow_offset *= sizeof(unsigned long); ++ *cow_offset += bitmap_offset; ++} ++ ++static void cowify_req(struct io_thread_req *req, unsigned long *bitmap, ++ __u64 bitmap_offset, __u64 bitmap_len) ++{ ++ __u64 sector = req->offset >> 9; ++ int i; ++ ++ if(req->length > (sizeof(req->sector_mask) * 8) << 9) ++ panic("Operation too long"); ++ ++ if(req->op == UBD_READ) { ++ for(i = 0; i < req->length >> 9; i++){ ++ if(ubd_test_bit(sector + i, (unsigned char *) bitmap)){ ++ ubd_set_bit(i, (unsigned char *) ++ &req->sector_mask); ++ } ++ } ++ } ++ else cowify_bitmap(req->offset, req->length, &req->sector_mask, ++ &req->cow_offset, bitmap, bitmap_offset, ++ req->bitmap_words, bitmap_len); ++} ++ ++static int mmap_fd(struct request *req, struct ubd *dev, __u64 offset) ++{ ++ __u64 sector; ++ unsigned char *bitmap; ++ int bit, i; ++ ++ /* mmap must have been requested on the command line */ ++ if(!ubd_do_mmap) ++ return(-1); ++ ++ /* The buffer must be page aligned */ ++ if(((unsigned long) req->buffer % UBD_MMAP_BLOCK_SIZE) != 0) ++ return(-1); ++ ++ /* The request must be a page long */ ++ if((req->current_nr_sectors << 9) != PAGE_SIZE) ++ return(-1); ++ ++ if(dev->cow.file == NULL) ++ return(dev->fd); ++ ++ sector = offset >> 9; ++ bitmap = (unsigned char *) dev->cow.bitmap; ++ bit = ubd_test_bit(sector, bitmap); ++ ++ for(i = 1; i < req->current_nr_sectors; i++){ ++ if(ubd_test_bit(sector + i, bitmap) != bit) ++ return(-1); ++ } ++ ++ if(bit || (req->cmd == WRITE)) ++ offset += dev->cow.data_offset; ++ ++ /* The data on disk must be page aligned */ ++ if((offset % UBD_MMAP_BLOCK_SIZE) != 0) ++ return(-1); ++ ++ return(bit ? dev->fd : dev->cow.fd); ++} ++ ++static int prepare_mmap_request(struct ubd *dev, int fd, __u64 offset, ++ struct request *req, ++ struct io_thread_req *io_req) ++{ ++ int err; ++ ++ if(req->cmd == WRITE){ ++ /* Writes are almost no-ops since the new data is already in the ++ * host page cache ++ */ ++ dev->map_writes++; ++ if(dev->cow.file != NULL) ++ cowify_bitmap(io_req->offset, io_req->length, ++ &io_req->sector_mask, &io_req->cow_offset, ++ dev->cow.bitmap, dev->cow.bitmap_offset, ++ io_req->bitmap_words, ++ dev->cow.bitmap_len); ++ } ++ else { ++ int w; ++ ++ if((dev->cow.file != NULL) && (fd == dev->cow.fd)) ++ w = 0; ++ else w = dev->openflags.w; ++ ++ if((dev->cow.file != NULL) && (fd == dev->fd)) ++ offset += dev->cow.data_offset; ++ ++ err = physmem_subst_mapping(req->buffer, fd, offset, w); ++ if(err){ ++ printk("physmem_subst_mapping failed, err = %d\n", ++ -err); ++ return(1); ++ } ++ dev->map_reads++; ++ } ++ io_req->op = UBD_MMAP; ++ io_req->buffer = req->buffer; ++ return(0); ++} ++ ++static int prepare_request(struct request *req, struct io_thread_req *io_req) ++{ ++ struct ubd *dev; ++ __u64 offset; ++ int minor, n, len, fd; ++ ++ if(req->rq_status == RQ_INACTIVE) return(1); ++ ++ minor = MINOR(req->rq_dev); ++ n = minor >> UBD_SHIFT; ++ dev = &ubd_dev[n]; ++ ++ if(IS_WRITE(req) && !dev->openflags.w){ ++ printk("Write attempted on readonly ubd device %d\n", n); ++ end_request(0); ++ return(1); ++ } ++ ++ req->sector += ubd_part[minor].start_sect; ++ offset = ((__u64) req->sector) << 9; ++ len = req->current_nr_sectors << 9; ++ ++ io_req->fds[0] = (dev->cow.file != NULL) ? dev->cow.fd : dev->fd; ++ io_req->fds[1] = dev->fd; ++ io_req->map_fd = -1; ++ io_req->cow_offset = -1; ++ io_req->offset = offset; ++ io_req->length = len; ++ io_req->error = 0; ++ io_req->sector_mask = 0; ++ ++ fd = mmap_fd(req, dev, io_req->offset); ++ if(fd > 0){ ++ /* If mmapping is otherwise OK, but the first access to the ++ * page is a write, then it's not mapped in yet. So we have ++ * to write the data to disk first, then we can map the disk ++ * page in and continue normally from there. ++ */ ++ if((req->cmd == WRITE) && !is_remapped(req->buffer)){ ++ io_req->map_fd = dev->fd; ++ io_req->map_offset = io_req->offset + ++ dev->cow.data_offset; ++ dev->write_maps++; ++ } ++ else return(prepare_mmap_request(dev, fd, io_req->offset, req, ++ io_req)); ++ } ++ ++ if(req->cmd == READ) ++ dev->nomap_reads++; ++ else dev->nomap_writes++; ++ ++ io_req->op = (req->cmd == READ) ? UBD_READ : UBD_WRITE; ++ io_req->offsets[0] = 0; ++ io_req->offsets[1] = dev->cow.data_offset; ++ io_req->buffer = req->buffer; ++ io_req->sectorsize = 1 << 9; ++ ++ if(dev->cow.file != NULL) ++ cowify_req(io_req, dev->cow.bitmap, dev->cow.bitmap_offset, ++ dev->cow.bitmap_len); ++ return(0); ++} ++ ++static void do_ubd_request(request_queue_t *q) ++{ ++ struct io_thread_req io_req; ++ struct request *req; ++ int err, n; ++ ++ if(thread_fd == -1){ ++ while(!list_empty(&q->queue_head)){ ++ req = blkdev_entry_next_request(&q->queue_head); ++ err = prepare_request(req, &io_req); ++ if(!err){ ++ do_io(&io_req); ++ ubd_finish(io_req.error); ++ } ++ } ++ } ++ else { ++ if(DEVICE_INTR || list_empty(&q->queue_head)) return; ++ req = blkdev_entry_next_request(&q->queue_head); ++ err = prepare_request(req, &io_req); ++ if(!err){ ++ SET_INTR(ubd_handler); ++ n = write_ubd_fs(thread_fd, (char *) &io_req, ++ sizeof(io_req)); ++ if(n != sizeof(io_req)) ++ printk("write to io thread failed, " ++ "errno = %d\n", -n); ++ } ++ } ++} ++ ++static int ubd_ioctl(struct inode * inode, struct file * file, ++ unsigned int cmd, unsigned long arg) ++{ ++ struct hd_geometry *loc = (struct hd_geometry *) arg; ++ struct ubd *dev; ++ int n, minor, err; ++ struct hd_driveid ubd_id = { ++ .cyls = 0, ++ .heads = 128, ++ .sectors = 32, ++ }; ++ ++ if(!inode) return(-EINVAL); ++ minor = MINOR(inode->i_rdev); ++ n = minor >> UBD_SHIFT; ++ if(n >= MAX_DEV) ++ return(-EINVAL); ++ dev = &ubd_dev[n]; ++ switch (cmd) { ++ struct hd_geometry g; ++ struct cdrom_volctrl volume; ++ case HDIO_GETGEO: ++ if(!loc) return(-EINVAL); ++ g.heads = 128; ++ g.sectors = 32; ++ g.cylinders = dev->size / (128 * 32 * hardsect_sizes[minor]); ++ g.start = ubd_part[minor].start_sect; ++ return(copy_to_user(loc, &g, sizeof(g)) ? -EFAULT : 0); ++ case BLKGETSIZE: /* Return device size */ ++ if(!arg) return(-EINVAL); ++ err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); ++ if(err) ++ return(err); ++ put_user(ubd_part[minor].nr_sects, (long *) arg); ++ return(0); ++ case BLKRRPART: /* Re-read partition tables */ ++ return(ubd_revalidate(inode->i_rdev)); ++ ++ case HDIO_SET_UNMASKINTR: ++ if(!capable(CAP_SYS_ADMIN)) return(-EACCES); ++ if((arg > 1) || (minor & 0x3F)) return(-EINVAL); ++ return(0); ++ ++ case HDIO_GET_UNMASKINTR: ++ if(!arg) return(-EINVAL); ++ err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); ++ if(err) ++ return(err); ++ return(0); ++ ++ case HDIO_GET_MULTCOUNT: ++ if(!arg) return(-EINVAL); ++ err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); ++ if(err) ++ return(err); ++ return(0); ++ ++ case HDIO_SET_MULTCOUNT: ++ if(!capable(CAP_SYS_ADMIN)) return(-EACCES); ++ if(MINOR(inode->i_rdev) & 0x3F) return(-EINVAL); ++ return(0); ++ ++ case HDIO_GET_IDENTITY: ++ ubd_id.cyls = dev->size / (128 * 32 * hardsect_sizes[minor]); ++ if(copy_to_user((char *) arg, (char *) &ubd_id, ++ sizeof(ubd_id))) ++ return(-EFAULT); ++ return(0); ++ ++ case CDROMVOLREAD: ++ if(copy_from_user(&volume, (char *) arg, sizeof(volume))) ++ return(-EFAULT); ++ volume.channel0 = 255; ++ volume.channel1 = 255; ++ volume.channel2 = 255; ++ volume.channel3 = 255; ++ if(copy_to_user((char *) arg, &volume, sizeof(volume))) ++ return(-EFAULT); ++ return(0); ++ ++ default: ++ return blk_ioctl(inode->i_rdev, cmd, arg); ++ } ++} ++ ++static int ubd_revalidate1(kdev_t rdev) ++{ ++ int i, n, offset, err = 0, pcount = 1 << UBD_SHIFT; ++ struct ubd *dev; ++ struct hd_struct *part; ++ ++ n = DEVICE_NR(rdev); ++ offset = n << UBD_SHIFT; ++ dev = &ubd_dev[n]; ++ ++ part = &ubd_part[offset]; ++ ++ /* clear all old partition counts */ ++ for(i = 1; i < pcount; i++) { ++ part[i].start_sect = 0; ++ part[i].nr_sects = 0; ++ } ++ ++ /* If it already has been opened we can check the partitions ++ * directly ++ */ ++ if(dev->count){ ++ part->start_sect = 0; ++ register_disk(&ubd_gendisk, MKDEV(MAJOR_NR, offset), pcount, ++ &ubd_blops, part->nr_sects); ++ } ++ else if(dev->file){ ++ err = ubd_open_dev(dev); ++ if(err){ ++ printk(KERN_ERR "unable to open %s for validation\n", ++ dev->file); ++ goto out; ++ } ++ ++ /* have to recompute sizes since we opened it */ ++ err = ubd_file_size(dev, &dev->size); ++ if(err < 0) { ++ ubd_close(dev); ++ goto out; ++ } ++ part->start_sect = 0; ++ part->nr_sects = dev->size / hardsect_sizes[offset]; ++ register_disk(&ubd_gendisk, MKDEV(MAJOR_NR, offset), pcount, ++ &ubd_blops, part->nr_sects); ++ ++ /* we are done so close it */ ++ ubd_close(dev); ++ } ++ else err = -ENODEV; ++ out: ++ return(err); ++} ++ ++static int ubd_revalidate(kdev_t rdev) ++{ ++ int err; ++ ++ spin_lock(&ubd_lock); ++ err = ubd_revalidate1(rdev); ++ spin_unlock(&ubd_lock); ++ return(err); ++} ++ ++static int ubd_check_remapped(int fd, unsigned long address, int is_write, ++ __u64 offset) ++{ ++ __u64 bitmap_offset; ++ unsigned long new_bitmap[2]; ++ int i, err, n; ++ ++ /* If it's not a write access, we can't do anything about it */ ++ if(!is_write) ++ return(0); ++ ++ /* We have a write */ ++ for(i = 0; i < sizeof(ubd_dev) / sizeof(ubd_dev[0]); i++){ ++ struct ubd *dev = &ubd_dev[i]; ++ ++ if((dev->fd != fd) && (dev->cow.fd != fd)) ++ continue; ++ ++ /* It's a write to a ubd device */ ++ ++ if(!dev->openflags.w){ ++ /* It's a write access on a read-only device - probably ++ * shouldn't happen. If the kernel is trying to change ++ * something with no intention of writing it back out, ++ * then this message will clue us in that this needs ++ * fixing ++ */ ++ printk("Write access to mapped page from readonly ubd " ++ "device %d\n", i); ++ return(0); ++ } ++ ++ /* It's a write to a writeable ubd device - it must be COWed ++ * because, otherwise, the page would have been mapped in ++ * writeable ++ */ ++ ++ if(!dev->cow.file) ++ panic("Write fault on writeable non-COW ubd device %d", ++ i); ++ ++ /* It should also be an access to the backing file since the ++ * COW pages should be mapped in read-write ++ */ ++ ++ if(fd == dev->fd) ++ panic("Write fault on a backing page of ubd " ++ "device %d\n", i); ++ ++ /* So, we do the write, copying the backing data to the COW ++ * file... ++ */ ++ ++ err = os_seek_file(dev->fd, offset + dev->cow.data_offset); ++ if(err < 0) ++ panic("Couldn't seek to %lld in COW file of ubd " ++ "device %d, err = %d", ++ offset + dev->cow.data_offset, i, -err); ++ ++ n = os_write_file(dev->fd, (void *) address, PAGE_SIZE); ++ if(n != PAGE_SIZE) ++ panic("Couldn't copy data to COW file of ubd " ++ "device %d, err = %d", i, -n); ++ ++ /* ... updating the COW bitmap... */ ++ ++ cowify_bitmap(offset, PAGE_SIZE, NULL, &bitmap_offset, ++ dev->cow.bitmap, dev->cow.bitmap_offset, ++ new_bitmap, dev->cow.bitmap_len); ++ ++ err = os_seek_file(dev->fd, bitmap_offset); ++ if(err < 0) ++ panic("Couldn't seek to %lld in COW file of ubd " ++ "device %d, err = %d", bitmap_offset, i, -err); ++ ++ n = os_write_file(dev->fd, new_bitmap, sizeof(new_bitmap)); ++ if(n != sizeof(new_bitmap)) ++ panic("Couldn't update bitmap of ubd device %d, " ++ "err = %d", i, -n); ++ ++ /* Maybe we can map the COW page in, and maybe we can't. If ++ * it is a pre-V3 COW file, we can't, since the alignment will ++ * be wrong. If it is a V3 or later COW file which has been ++ * moved to a system with a larger page size, then maybe we ++ * can't, depending on the exact location of the page. ++ */ ++ ++ offset += dev->cow.data_offset; ++ ++ /* Remove the remapping, putting the original anonymous page ++ * back. If the COW file can be mapped in, that is done. ++ * Otherwise, the COW page is read in. ++ */ ++ ++ if(!physmem_remove_mapping((void *) address)) ++ panic("Address 0x%lx not remapped by ubd device %d", ++ address, i); ++ if((offset % UBD_MMAP_BLOCK_SIZE) == 0) ++ physmem_subst_mapping((void *) address, dev->fd, ++ offset, 1); ++ else { ++ err = os_seek_file(dev->fd, offset); ++ if(err < 0) ++ panic("Couldn't seek to %lld in COW file of " ++ "ubd device %d, err = %d", offset, i, ++ -err); ++ ++ n = os_read_file(dev->fd, (void *) address, PAGE_SIZE); ++ if(n != PAGE_SIZE) ++ panic("Failed to read page from offset %llx of " ++ "COW file of ubd device %d, err = %d", ++ offset, i, -n); ++ } ++ ++ return(1); ++ } ++ ++ /* It's not a write on a ubd device */ ++ return(0); ++} ++ ++static struct remapper ubd_remapper = { ++ .list = LIST_HEAD_INIT(ubd_remapper.list), ++ .proc = ubd_check_remapped, ++}; ++ ++static int ubd_remapper_setup(void) ++{ ++ if(ubd_do_mmap) ++ register_remapper(&ubd_remapper); ++ ++ return(0); ++} ++ ++__initcall(ubd_remapper_setup); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/ubd_user.c um/arch/um/drivers/ubd_user.c +--- orig/arch/um/drivers/ubd_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/ubd_user.c 2003-11-08 07:57:49.000000000 -0500 +@@ -0,0 +1,378 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Copyright (C) 2001 Ridgerun,Inc (glonnon@ridgerun.com) ++ * Licensed under the GPL ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#include "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_dev == buf2.ust_dev) && (buf1.ust_ino == buf2.ust_ino)) ++ return(1); ++ ++ printk("Backing file mismatch - \"%s\" requested,\n" ++ "\"%s\" specified in COW header of \"%s\"\n", ++ from_cmdline, from_cow, cow); ++ return(0); ++} ++ ++static int backing_file_mismatch(char *file, __u64 size, time_t mtime) ++{ ++ unsigned long modtime; ++ long long actual; ++ int err; ++ ++ err = os_file_modtime(file, &modtime); ++ if(err < 0){ ++ printk("Failed to get modification time of backing file " ++ "\"%s\", err = %d\n", file, -err); ++ return(err); ++ } ++ ++ err = os_file_size(file, &actual); ++ if(err < 0){ ++ printk("Failed to get size of backing file \"%s\", " ++ "err = %d\n", file, -err); ++ return(err); ++ } ++ ++ if(actual != size){ ++ printk("Size mismatch (%ld vs %ld) of COW header vs backing " ++ "file\n", size, actual); ++ return(-EINVAL); ++ } ++ if(modtime != mtime){ ++ printk("mtime mismatch (%ld vs %ld) of COW header vs backing " ++ "file\n", mtime, modtime); ++ return(-EINVAL); ++ } ++ return(0); ++} ++ ++int read_cow_bitmap(int fd, void *buf, int offset, int len) ++{ ++ int err; ++ ++ err = os_seek_file(fd, offset); ++ if(err < 0) ++ return(err); ++ ++ err = os_read_file(fd, buf, len); ++ if(err < 0) ++ return(err); ++ ++ return(0); ++} ++ ++int open_ubd_file(char *file, struct openflags *openflags, ++ char **backing_file_out, int *bitmap_offset_out, ++ unsigned long *bitmap_len_out, int *data_offset_out, ++ int *create_cow_out) ++{ ++ time_t mtime; ++ __u64 size; ++ __u32 version, align; ++ char *backing_file; ++ int fd, err, sectorsize, same, mode = 0644; ++ ++ fd = os_open_file(file, *openflags, mode); ++ if(fd < 0){ ++ if((fd == -ENOENT) && (create_cow_out != NULL)) ++ *create_cow_out = 1; ++ if(!openflags->w || ++ ((errno != EROFS) && (errno != EACCES))) return(-errno); ++ openflags->w = 0; ++ fd = os_open_file(file, *openflags, mode); ++ if(fd < 0) ++ return(fd); ++ } ++ ++ err = os_lock_file(fd, openflags->w); ++ if(err < 0){ ++ printk("Failed to lock '%s', err = %d\n", file, -err); ++ goto out_close; ++ } ++ ++ if(backing_file_out == NULL) return(fd); ++ ++ err = read_cow_header(file_reader, &fd, &version, &backing_file, &mtime, ++ &size, §orsize, &align, bitmap_offset_out); ++ if(err && (*backing_file_out != NULL)){ ++ printk("Failed to read COW header from COW file \"%s\", " ++ "errno = %d\n", file, -err); ++ goto out_close; ++ } ++ if(err) return(fd); ++ ++ if(backing_file_out == NULL) return(fd); ++ ++ same = same_backing_files(*backing_file_out, backing_file, file); ++ ++ if(!same && !backing_file_mismatch(*backing_file_out, size, mtime)){ ++ printk("Switching backing file to '%s'\n", *backing_file_out); ++ err = write_cow_header(file, fd, *backing_file_out, ++ sectorsize, align, &size); ++ if(err){ ++ printk("Switch failed, errno = %d\n", -err); ++ return(err); ++ } ++ } ++ else { ++ *backing_file_out = backing_file; ++ err = backing_file_mismatch(*backing_file_out, size, mtime); ++ if(err) goto out_close; ++ } ++ ++ cow_sizes(version, size, sectorsize, align, *bitmap_offset_out, ++ bitmap_len_out, data_offset_out); ++ ++ return(fd); ++ out_close: ++ os_close_file(fd); ++ return(err); ++} ++ ++int create_cow_file(char *cow_file, char *backing_file, struct openflags flags, ++ int sectorsize, int alignment, int *bitmap_offset_out, ++ unsigned long *bitmap_len_out, int *data_offset_out) ++{ ++ int err, fd; ++ ++ flags.c = 1; ++ fd = open_ubd_file(cow_file, &flags, NULL, NULL, NULL, NULL, NULL); ++ if(fd < 0){ ++ err = fd; ++ printk("Open of COW file '%s' failed, errno = %d\n", cow_file, ++ -err); ++ goto out; ++ } ++ ++ err = init_cow_file(fd, cow_file, backing_file, sectorsize, alignment, ++ bitmap_offset_out, bitmap_len_out, ++ data_offset_out); ++ if(!err) ++ return(fd); ++ ++ os_close_file(fd); ++ out: ++ return(err); ++} ++ ++/* XXX Just trivial wrappers around os_read_file and os_write_file */ ++int read_ubd_fs(int fd, void *buffer, int len) ++{ ++ return(os_read_file(fd, buffer, len)); ++} ++ ++int write_ubd_fs(int fd, char *buffer, int len) ++{ ++ return(os_write_file(fd, buffer, len)); ++} ++ ++static int update_bitmap(struct io_thread_req *req) ++{ ++ int n; ++ ++ if(req->cow_offset == -1) ++ return(0); ++ ++ n = os_seek_file(req->fds[1], req->cow_offset); ++ if(n < 0){ ++ printk("do_io - bitmap lseek failed : err = %d\n", -n); ++ return(1); ++ } ++ ++ n = os_write_file(req->fds[1], &req->bitmap_words, ++ sizeof(req->bitmap_words)); ++ if(n != sizeof(req->bitmap_words)){ ++ printk("do_io - bitmap update failed, err = %d fd = %d\n", -n, ++ req->fds[1]); ++ return(1); ++ } ++ ++ return(0); ++} ++ ++void do_io(struct io_thread_req *req) ++{ ++ char *buf; ++ unsigned long len; ++ int n, nsectors, start, end, bit; ++ int err; ++ __u64 off; ++ ++ if(req->op == UBD_MMAP){ ++ /* Touch the page to force the host to do any necessary IO to ++ * get it into memory ++ */ ++ n = *((volatile int *) req->buffer); ++ req->error = update_bitmap(req); ++ return; ++ } ++ ++ nsectors = req->length / req->sectorsize; ++ start = 0; ++ do { ++ bit = ubd_test_bit(start, (unsigned char *) &req->sector_mask); ++ end = start; ++ while((end < nsectors) && ++ (ubd_test_bit(end, (unsigned char *) ++ &req->sector_mask) == bit)) ++ end++; ++ ++ off = req->offset + req->offsets[bit] + ++ start * req->sectorsize; ++ len = (end - start) * req->sectorsize; ++ buf = &req->buffer[start * req->sectorsize]; ++ ++ err = os_seek_file(req->fds[bit], off); ++ if(err < 0){ ++ printk("do_io - lseek failed : err = %d\n", -err); ++ req->error = 1; ++ return; ++ } ++ if(req->op == UBD_READ){ ++ n = 0; ++ do { ++ buf = &buf[n]; ++ len -= n; ++ n = os_read_file(req->fds[bit], buf, len); ++ if (n < 0) { ++ printk("do_io - read failed, err = %d " ++ "fd = %d\n", -n, req->fds[bit]); ++ req->error = 1; ++ return; ++ } ++ } while((n < len) && (n != 0)); ++ if (n < len) memset(&buf[n], 0, len - n); ++ } ++ else { ++ n = os_write_file(req->fds[bit], buf, len); ++ if(n != len){ ++ printk("do_io - write failed err = %d " ++ "fd = %d\n", -n, req->fds[bit]); ++ req->error = 1; ++ return; ++ } ++ } ++ ++ start = end; ++ } while(start < nsectors); ++ ++ req->error = update_bitmap(req); ++} ++ ++/* Changed in start_io_thread, which is serialized by being called only ++ * from ubd_init, which is an initcall. ++ */ ++int kernel_fd = -1; ++ ++/* Only changed by the io thread */ ++int io_count = 0; ++ ++int io_thread(void *arg) ++{ ++ struct io_thread_req req; ++ int n; ++ ++ signal(SIGWINCH, SIG_IGN); ++ while(1){ ++ n = os_read_file(kernel_fd, &req, sizeof(req)); ++ if(n != sizeof(req)){ ++ if(n < 0) ++ printk("io_thread - read failed, fd = %d, " ++ "err = %d\n", kernel_fd, -n); ++ else { ++ printk("io_thread - short read, fd = %d, " ++ "length = %d\n", kernel_fd, n); ++ } ++ continue; ++ } ++ io_count++; ++ do_io(&req); ++ n = os_write_file(kernel_fd, &req, sizeof(req)); ++ if(n != sizeof(req)) ++ printk("io_thread - write failed, fd = %d, err = %d\n", ++ kernel_fd, -n); ++ } ++} ++ ++int start_io_thread(unsigned long sp, int *fd_out) ++{ ++ int pid, fds[2], err; ++ ++ err = os_pipe(fds, 1, 1); ++ if(err < 0){ ++ printk("start_io_thread - os_pipe failed, err = %d\n", -err); ++ goto out; ++ } ++ ++ kernel_fd = fds[0]; ++ *fd_out = fds[1]; ++ ++ pid = clone(io_thread, (void *) sp, CLONE_FILES | CLONE_VM | SIGCHLD, ++ NULL); ++ if(pid < 0){ ++ printk("start_io_thread - clone failed : errno = %d\n", errno); ++ goto out_close; ++ } ++ ++ return(pid); ++ ++ out_close: ++ os_close_file(fds[0]); ++ os_close_file(fds[1]); ++ kernel_fd = -1; ++ *fd_out = -1; ++ out: ++ return(err); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/xterm.c um/arch/um/drivers/xterm.c +--- orig/arch/um/drivers/xterm.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/xterm.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,201 @@ ++/* ++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include ++#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" ++); ++ ++int xterm_open(int input, int output, int primary, void *d, char **dev_out) ++{ ++ struct xterm_chan *data = d; ++ unsigned long stack; ++ int pid, fd, new, err; ++ char title[256], file[] = "/tmp/xterm-pipeXXXXXX"; ++ char *argv[] = { terminal_emulator, title_switch, title, exec_switch, ++ "/usr/lib/uml/port-helper", "-uml-socket", ++ file, NULL }; ++ ++ if(os_access(argv[4], OS_ACC_X_OK) < 0) ++ argv[4] = "port-helper"; ++ ++ fd = mkstemp(file); ++ if(fd < 0){ ++ printk("xterm_open : mkstemp failed, errno = %d\n", errno); ++ return(-errno); ++ } ++ ++ if(unlink(file)){ ++ printk("xterm_open : unlink failed, errno = %d\n", errno); ++ return(-errno); ++ } ++ os_close_file(fd); ++ ++ fd = os_create_unix_socket(file, sizeof(file), 1); ++ if(fd < 0){ ++ printk("xterm_open : create_unix_socket failed, errno = %d\n", ++ -fd); ++ return(fd); ++ } ++ ++ sprintf(title, data->title, data->device); ++ stack = data->stack; ++ pid = run_helper(NULL, NULL, argv, &stack); ++ if(pid < 0){ ++ printk("xterm_open : run_helper failed, errno = %d\n", -pid); ++ return(pid); ++ } ++ ++ if(data->stack == 0) free_stack(stack, 0); ++ ++ if(data->direct_rcv) ++ new = os_rcv_fd(fd, &data->helper_pid); ++ else { ++ err = os_set_fd_block(fd, 0); ++ if(err < 0){ ++ printk("xterm_open : failed to set descriptor " ++ "non-blocking, err = %d\n", -err); ++ return(err); ++ } ++ new = xterm_fd(fd, &data->helper_pid); ++ } ++ if(new < 0){ ++ printk("xterm_open : os_rcv_fd failed, err = %d\n", -new); ++ goto out; ++ } ++ ++ tcgetattr(new, &data->tt); ++ if(data->raw) raw(new, 0); ++ ++ data->pid = pid; ++ *dev_out = NULL; ++ out: ++ unlink(file); ++ return(new); ++} ++ ++void xterm_close(int fd, void *d) ++{ ++ struct xterm_chan *data = d; ++ ++ if(data->pid != -1) ++ os_kill_process(data->pid, 1); ++ data->pid = -1; ++ if(data->helper_pid != -1) ++ os_kill_process(data->helper_pid, 0); ++ data->helper_pid = -1; ++ os_close_file(fd); ++} ++ ++void xterm_free(void *d) ++{ ++ free(d); ++} ++ ++int xterm_console_write(int fd, const char *buf, int n, void *d) ++{ ++ struct xterm_chan *data = d; ++ ++ return(generic_console_write(fd, buf, n, &data->tt)); ++} ++ ++struct chan_ops xterm_ops = { ++ .type = "xterm", ++ .init = xterm_init, ++ .open = xterm_open, ++ .close = xterm_close, ++ .read = generic_read, ++ .write = generic_write, ++ .console_write = xterm_console_write, ++ .window_size = generic_window_size, ++ .free = xterm_free, ++ .winch = 1, ++}; ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/xterm.h um/arch/um/drivers/xterm.h +--- orig/arch/um/drivers/xterm.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/xterm.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,22 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __XTERM_H__ ++#define __XTERM_H__ ++ ++extern int xterm_fd(int socket, int *pid_out); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/drivers/xterm_kern.c um/arch/um/drivers/xterm_kern.c +--- orig/arch/um/drivers/xterm_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/drivers/xterm_kern.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,82 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/errno.h" ++#include "linux/slab.h" ++#include "asm/semaphore.h" ++#include "asm/irq.h" ++#include "irq_user.h" ++#include "irq_kern.h" ++#include "kern_util.h" ++#include "os.h" ++#include "xterm.h" ++ ++struct xterm_wait { ++ struct semaphore sem; ++ int fd; ++ int pid; ++ int new_fd; ++}; ++ ++static void xterm_interrupt(int irq, void *data, struct pt_regs *regs) ++{ ++ struct xterm_wait *xterm = data; ++ int fd; ++ ++ fd = os_rcv_fd(xterm->fd, &xterm->pid); ++ if(fd == -EAGAIN) ++ return; ++ ++ xterm->new_fd = fd; ++ up(&xterm->sem); ++} ++ ++int xterm_fd(int socket, int *pid_out) ++{ ++ struct xterm_wait *data; ++ int err, ret; ++ ++ data = kmalloc(sizeof(*data), GFP_KERNEL); ++ if(data == NULL){ ++ printk(KERN_ERR "xterm_fd : failed to allocate xterm_wait\n"); ++ return(-ENOMEM); ++ } ++ *data = ((struct xterm_wait) ++ { .sem = __SEMAPHORE_INITIALIZER(data->sem, 0), ++ .fd = socket, ++ .pid = -1, ++ .new_fd = -1 }); ++ ++ err = um_request_irq(XTERM_IRQ, socket, IRQ_READ, xterm_interrupt, ++ SA_INTERRUPT | SA_SHIRQ | SA_SAMPLE_RANDOM, ++ "xterm", data); ++ if(err){ ++ printk(KERN_ERR "xterm_fd : failed to get IRQ for xterm, " ++ "err = %d\n", err); ++ ret = err; ++ goto out; ++ } ++ down(&data->sem); ++ ++ free_irq(XTERM_IRQ, data); ++ ++ ret = data->new_fd; ++ *pid_out = data->pid; ++ out: ++ kfree(data); ++ ++ return(ret); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/dyn_link.ld.in um/arch/um/dyn_link.ld.in +--- orig/arch/um/dyn_link.ld.in 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/dyn_link.ld.in 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,172 @@ ++OUTPUT_FORMAT("ELF_FORMAT") ++OUTPUT_ARCH(ELF_ARCH) ++ENTRY(_start) ++SEARCH_DIR("/usr/local/i686-pc-linux-gnu/lib"); SEARCH_DIR("/usr/local/lib"); SEARCH_DIR("/lib"); SEARCH_DIR("/usr/lib"); ++/* Do we need any of these for elf? ++ __DYNAMIC = 0; */ ++SECTIONS ++{ ++ . = START() + SIZEOF_HEADERS; ++ .interp : { *(.interp) } ++ . = ALIGN(4096); ++ __binary_start = .; ++ . = ALIGN(4096); /* Init code and data */ ++ _stext = .; ++ __init_begin = .; ++ .text.init : { *(.text.init) } ++ ++ . = ALIGN(4096); ++ ++ /* Read-only sections, merged into text segment: */ ++ .hash : { *(.hash) } ++ .dynsym : { *(.dynsym) } ++ .dynstr : { *(.dynstr) } ++ .gnu.version : { *(.gnu.version) } ++ .gnu.version_d : { *(.gnu.version_d) } ++ .gnu.version_r : { *(.gnu.version_r) } ++ .rel.init : { *(.rel.init) } ++ .rela.init : { *(.rela.init) } ++ .rel.text : { *(.rel.text .rel.text.* .rel.gnu.linkonce.t.*) } ++ .rela.text : { *(.rela.text .rela.text.* .rela.gnu.linkonce.t.*) } ++ .rel.fini : { *(.rel.fini) } ++ .rela.fini : { *(.rela.fini) } ++ .rel.rodata : { *(.rel.rodata .rel.rodata.* .rel.gnu.linkonce.r.*) } ++ .rela.rodata : { *(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*) } ++ .rel.data : { *(.rel.data .rel.data.* .rel.gnu.linkonce.d.*) } ++ .rela.data : { *(.rela.data .rela.data.* .rela.gnu.linkonce.d.*) } ++ .rel.tdata : { *(.rel.tdata .rel.tdata.* .rel.gnu.linkonce.td.*) } ++ .rela.tdata : { *(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*) } ++ .rel.tbss : { *(.rel.tbss .rel.tbss.* .rel.gnu.linkonce.tb.*) } ++ .rela.tbss : { *(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*) } ++ .rel.ctors : { *(.rel.ctors) } ++ .rela.ctors : { *(.rela.ctors) } ++ .rel.dtors : { *(.rel.dtors) } ++ .rela.dtors : { *(.rela.dtors) } ++ .rel.got : { *(.rel.got) } ++ .rela.got : { *(.rela.got) } ++ .rel.bss : { *(.rel.bss .rel.bss.* .rel.gnu.linkonce.b.*) } ++ .rela.bss : { *(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*) } ++ .rel.plt : { *(.rel.plt) } ++ .rela.plt : { *(.rela.plt) } ++ .init : { ++ KEEP (*(.init)) ++ } =0x90909090 ++ .plt : { *(.plt) } ++ .text : { ++ *(.text .stub .text.* .gnu.linkonce.t.*) ++ /* .gnu.warning sections are handled specially by elf32.em. */ ++ *(.gnu.warning) ++ } =0x90909090 ++ .fini : { ++ KEEP (*(.fini)) ++ } =0x90909090 ++ ++ PROVIDE (__etext = .); ++ PROVIDE (_etext = .); ++ PROVIDE (etext = .); ++ .rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) } ++ .rodata1 : { *(.rodata1) } ++ .eh_frame_hdr : { *(.eh_frame_hdr) } ++ ++ ++ . = ALIGN(4096); ++ PROVIDE (_sdata = .); ++ ++include(`arch/um/common.ld.in') ++ ++ /* Ensure the __preinit_array_start label is properly aligned. We ++ could instead move the label definition inside the section, but ++ the linker would then create the section even if it turns out to ++ be empty, which isn't pretty. */ ++ . = ALIGN(32 / 8); ++ .preinit_array : { *(.preinit_array) } ++ .init_array : { *(.init_array) } ++ .fini_array : { *(.fini_array) } ++ .data : { ++ . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ ++ *(.data.init_task) ++ *(.data .data.* .gnu.linkonce.d.*) ++ SORT(CONSTRUCTORS) ++ } ++ .data1 : { *(.data1) } ++ .tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) } ++ .tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) } ++ .eh_frame : { KEEP (*(.eh_frame)) } ++ .gcc_except_table : { *(.gcc_except_table) } ++ .dynamic : { *(.dynamic) } ++ .ctors : { ++ /* gcc uses crtbegin.o to find the start of ++ the constructors, so we make sure it is ++ first. Because this is a wildcard, it ++ doesn't matter if the user does not ++ actually link against crtbegin.o; the ++ linker won't look for a file to match a ++ wildcard. The wildcard also means that it ++ doesn't matter which directory crtbegin.o ++ is in. */ ++ KEEP (*crtbegin.o(.ctors)) ++ /* We don't want to include the .ctor section from ++ from the crtend.o file until after the sorted ctors. ++ The .ctor section from the crtend file contains the ++ end of ctors marker and it must be last */ ++ KEEP (*(EXCLUDE_FILE (*crtend.o ) .ctors)) ++ KEEP (*(SORT(.ctors.*))) ++ KEEP (*(.ctors)) ++ } ++ .dtors : { ++ KEEP (*crtbegin.o(.dtors)) ++ KEEP (*(EXCLUDE_FILE (*crtend.o ) .dtors)) ++ KEEP (*(SORT(.dtors.*))) ++ KEEP (*(.dtors)) ++ } ++ .jcr : { KEEP (*(.jcr)) } ++ .got : { *(.got.plt) *(.got) } ++ _edata = .; ++ PROVIDE (edata = .); ++ __bss_start = .; ++ .bss : { ++ *(.dynbss) ++ *(.bss .bss.* .gnu.linkonce.b.*) ++ *(COMMON) ++ /* Align here to ensure that the .bss section occupies space up to ++ _end. Align after .bss to ensure correct alignment even if the ++ .bss section disappears because there are no input sections. */ ++ . = ALIGN(32 / 8); ++ . = ALIGN(32 / 8); ++ } ++ _end = .; ++ PROVIDE (end = .); ++ /* Stabs debugging sections. */ ++ .stab 0 : { *(.stab) } ++ .stabstr 0 : { *(.stabstr) } ++ .stab.excl 0 : { *(.stab.excl) } ++ .stab.exclstr 0 : { *(.stab.exclstr) } ++ .stab.index 0 : { *(.stab.index) } ++ .stab.indexstr 0 : { *(.stab.indexstr) } ++ .comment 0 : { *(.comment) } ++ /* DWARF debug sections. ++ Symbols in the DWARF debugging sections are relative to the beginning ++ of the section so we begin them at 0. */ ++ /* DWARF 1 */ ++ .debug 0 : { *(.debug) } ++ .line 0 : { *(.line) } ++ /* GNU DWARF 1 extensions */ ++ .debug_srcinfo 0 : { *(.debug_srcinfo) } ++ .debug_sfnames 0 : { *(.debug_sfnames) } ++ /* DWARF 1.1 and DWARF 2 */ ++ .debug_aranges 0 : { *(.debug_aranges) } ++ .debug_pubnames 0 : { *(.debug_pubnames) } ++ /* DWARF 2 */ ++ .debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) } ++ .debug_abbrev 0 : { *(.debug_abbrev) } ++ .debug_line 0 : { *(.debug_line) } ++ .debug_frame 0 : { *(.debug_frame) } ++ .debug_str 0 : { *(.debug_str) } ++ .debug_loc 0 : { *(.debug_loc) } ++ .debug_macinfo 0 : { *(.debug_macinfo) } ++ /* SGI/MIPS DWARF 2 extensions */ ++ .debug_weaknames 0 : { *(.debug_weaknames) } ++ .debug_funcnames 0 : { *(.debug_funcnames) } ++ .debug_typenames 0 : { *(.debug_typenames) } ++ .debug_varnames 0 : { *(.debug_varnames) } ++} +diff -Naur -X ../exclude-files orig/arch/um/fs/hostfs/hostfs.h um/arch/um/fs/hostfs/hostfs.h +--- orig/arch/um/fs/hostfs/hostfs.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/fs/hostfs/hostfs.h 2003-12-17 10:52:50.000000000 -0500 +@@ -0,0 +1,69 @@ ++#ifndef __UM_FS_HOSTFS ++#define __UM_FS_HOSTFS ++ ++#include "os.h" ++ ++/* These are exactly the same definitions as in fs.h, but the names are ++ * changed so that this file can be included in both kernel and user files. ++ */ ++ ++#define HOSTFS_ATTR_MODE 1 ++#define HOSTFS_ATTR_UID 2 ++#define HOSTFS_ATTR_GID 4 ++#define HOSTFS_ATTR_SIZE 8 ++#define HOSTFS_ATTR_ATIME 16 ++#define HOSTFS_ATTR_MTIME 32 ++#define HOSTFS_ATTR_CTIME 64 ++#define HOSTFS_ATTR_ATIME_SET 128 ++#define HOSTFS_ATTR_MTIME_SET 256 ++#define HOSTFS_ATTR_FORCE 512 /* Not a change, but a change it */ ++#define HOSTFS_ATTR_ATTR_FLAG 1024 ++ ++struct hostfs_iattr { ++ unsigned int ia_valid; ++ mode_t ia_mode; ++ uid_t ia_uid; ++ gid_t ia_gid; ++ loff_t ia_size; ++ time_t ia_atime; ++ time_t ia_mtime; ++ time_t ia_ctime; ++ unsigned int ia_attr_flags; ++}; ++ ++extern int stat_file(const char *path, int *dev_out, ++ unsigned long long *inode_out, int *mode_out, ++ int *nlink_out, int *uid_out, int *gid_out, ++ unsigned long long *size_out, unsigned long *atime_out, ++ unsigned long *mtime_out, unsigned long *ctime_out, ++ int *blksize_out, unsigned long long *blocks_out); ++extern int access_file(char *path, int r, int w, int x); ++extern int open_file(char *path, int r, int w, int append); ++extern int file_type(const char *path, int *rdev); ++extern void *open_dir(char *path, int *err_out); ++extern char *read_dir(void *stream, unsigned long long *pos, ++ unsigned long long *ino_out, int *len_out); ++extern void close_file(void *stream); ++extern void close_dir(void *stream); ++extern int read_file(int fd, unsigned long long *offset, char *buf, int len); ++extern int write_file(int fd, unsigned long long *offset, const char *buf, ++ int len); ++extern int lseek_file(int fd, long long offset, int whence); ++extern int file_create(char *name, int ur, int uw, int ux, int gr, ++ int gw, int gx, int or, int ow, int ox); ++extern int set_attr(const char *file, struct hostfs_iattr *attrs); ++extern int make_symlink(const char *from, const char *to); ++extern int unlink_file(const char *file); ++extern int do_mkdir(const char *file, int mode); ++extern int do_rmdir(const char *file); ++extern int do_mknod(const char *file, int mode, int dev); ++extern int link_file(const char *from, const char *to); ++extern int do_readlink(char *file, char *buf, int size); ++extern int rename_file(char *from, char *to); ++extern int do_statfs(char *root, long *bsize_out, long long *blocks_out, ++ long long *bfree_out, long long *bavail_out, ++ long long *files_out, long long *ffree_out, ++ void *fsid_out, int fsid_size, long *namelen_out, ++ long *spare_out); ++ ++#endif +diff -Naur -X ../exclude-files orig/arch/um/fs/hostfs/hostfs_kern.c um/arch/um/fs/hostfs/hostfs_kern.c +--- orig/arch/um/fs/hostfs/hostfs_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/fs/hostfs/hostfs_kern.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,965 @@ ++/* ++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) ++ * Licensed under the GPL ++ */ ++ ++#include <linux/stddef.h> ++#include <linux/fs.h> ++#include <linux/version.h> ++#include <linux/module.h> ++#include <linux/init.h> ++#include <linux/slab.h> ++#include <linux/pagemap.h> ++#include <linux/blkdev.h> ++#include <asm/uaccess.h> ++#include "hostfs.h" ++#include "kern_util.h" ++#include "kern.h" ++#include "user_util.h" ++#include "2_5compat.h" ++#include "init.h" ++ ++#define file_hostfs_i(file) (&(file)->f_dentry->d_inode->u.hostfs_i) ++ ++int hostfs_d_delete(struct dentry *dentry) ++{ ++ return(1); ++} ++ ++struct dentry_operations hostfs_dentry_ops = { ++ .d_delete = hostfs_d_delete, ++}; ++ ++#define DEFAULT_ROOT "/" ++ ++/* Changed in hostfs_args before the kernel starts running */ ++static char *jail_dir = NULL; ++static int append = 0; ++ ++#define HOSTFS_SUPER_MAGIC 0x00c0ffee ++ ++static struct inode_operations hostfs_iops; ++static struct inode_operations hostfs_dir_iops; ++static struct address_space_operations hostfs_link_aops; ++ ++static int __init hostfs_args(char *options, int *add) ++{ ++ char *ptr; ++ ++ ptr = strchr(options, ','); ++ if(ptr != NULL) ++ *ptr++ = '\0'; ++ if(*options != '\0') ++ jail_dir = options; ++ ++ options = ptr; ++ while(options){ ++ ptr = strchr(options, ','); ++ if(ptr != NULL) ++ *ptr++ = '\0'; ++ if(*options != '\0'){ ++ if(!strcmp(options, "append")) ++ append = 1; ++ else printf("hostfs_args - unsupported option - %s\n", ++ options); ++ } ++ options = ptr; ++ } ++ return(0); ++} ++ ++__uml_setup("hostfs=", hostfs_args, ++"hostfs=<root dir>,<flags>,...\n" ++" This is used to set hostfs parameters. The root directory argument\n" ++" is used to confine all hostfs mounts to within the specified directory\n" ++" tree on the host. If this isn't specified, then a user inside UML can\n" ++" mount anything on the host that's accessible to the user that's running\n" ++" it.\n" ++" The only flag currently supported is 'append', which specifies that all\n" ++" files opened by hostfs will be opened in append mode.\n\n" ++); ++ ++static char *dentry_name(struct dentry *dentry, int extra) ++{ ++ struct dentry *parent; ++ char *root, *name; ++ int len; ++ ++ len = 0; ++ parent = dentry; ++ while(parent->d_parent != parent){ ++ len += parent->d_name.len + 1; ++ parent = parent->d_parent; ++ } ++ ++ root = parent->d_inode->u.hostfs_i.host_filename; ++ len += strlen(root); ++ name = kmalloc(len + extra + 1, GFP_KERNEL); ++ if(name == NULL) return(NULL); ++ ++ name[len] = '\0'; ++ parent = dentry; ++ while(parent->d_parent != parent){ ++ len -= parent->d_name.len + 1; ++ name[len] = '/'; ++ strncpy(&name[len + 1], parent->d_name.name, ++ parent->d_name.len); ++ parent = parent->d_parent; ++ } ++ strncpy(name, root, strlen(root)); ++ return(name); ++} ++ ++static char *inode_name(struct inode *ino, int extra) ++{ ++ struct dentry *dentry; ++ ++ dentry = list_entry(ino->i_dentry.next, struct dentry, d_alias); ++ return(dentry_name(dentry, extra)); ++} ++ ++static int read_name(struct inode *ino, char *name) ++{ ++ /* The non-int inode fields are copied into ints by stat_file and ++ * then copied into the inode because passing the actual pointers ++ * in and having them treated as int * breaks on big-endian machines ++ */ ++ int err; ++ int i_dev, i_mode, i_nlink, i_blksize; ++ unsigned long long i_size; ++ unsigned long long i_ino; ++ unsigned long long i_blocks; ++ err = stat_file(name, &i_dev, &i_ino, &i_mode, &i_nlink, ++ &ino->i_uid, &ino->i_gid, &i_size, &ino->i_atime, ++ &ino->i_mtime, &ino->i_ctime, &i_blksize, &i_blocks); ++ if(err) return(err); ++ ino->i_ino = i_ino; ++ ino->i_dev = i_dev; ++ ino->i_mode = i_mode; ++ ino->i_nlink = i_nlink; ++ ino->i_size = i_size; ++ ino->i_blksize = i_blksize; ++ ino->i_blocks = i_blocks; ++ if(kdev_same(ino->i_sb->s_dev, ROOT_DEV) && (ino->i_uid == getuid())) ++ ino->i_uid = 0; ++ return(0); ++} ++ ++static char *follow_link(char *link) ++{ ++ int len, n; ++ char *name, *resolved, *end; ++ ++ len = 64; ++ while(1){ ++ n = -ENOMEM; ++ name = kmalloc(len, GFP_KERNEL); ++ if(name == NULL) ++ goto out; ++ ++ n = do_readlink(link, name, len); ++ if(n < len) ++ break; ++ len *= 2; ++ kfree(name); ++ } ++ if(n < 0) ++ goto out_free; ++ ++ if(*name == '/') ++ return(name); ++ ++ end = strrchr(link, '/'); ++ if(end == NULL) ++ return(name); ++ ++ *(end + 1) = '\0'; ++ len = strlen(link) + strlen(name) + 1; ++ ++ resolved = kmalloc(len, GFP_KERNEL); ++ if(resolved == NULL){ ++ n = -ENOMEM; ++ goto out_free; ++ } ++ ++ sprintf(resolved, "%s%s", link, name); ++ kfree(name); ++ kfree(link); ++ return(resolved); ++ ++ out_free: ++ kfree(name); ++ out: ++ return(ERR_PTR(n)); ++} ++ ++static int read_inode(struct inode *ino) ++{ ++ char *name; ++ int err; ++ ++ err = -ENOMEM; ++ name = inode_name(ino, 0); ++ if(name == NULL) ++ goto out; ++ ++ if(file_type(name, NULL) == OS_TYPE_SYMLINK){ ++ name = follow_link(name); ++ if(IS_ERR(name)){ ++ err = PTR_ERR(name); ++ goto out; ++ } ++ } ++ ++ err = read_name(ino, name); ++ kfree(name); ++ out: ++ return(err); ++} ++ ++void hostfs_delete_inode(struct inode *ino) ++{ ++ if(ino->u.hostfs_i.host_filename) ++ kfree(ino->u.hostfs_i.host_filename); ++ ino->u.hostfs_i.host_filename = NULL; ++ ++ if(ino->u.hostfs_i.fd != -1) ++ close_file(&ino->u.hostfs_i.fd); ++ ++ ino->u.hostfs_i.mode = 0; ++ clear_inode(ino); ++} ++ ++int hostfs_statfs(struct super_block *sb, struct statfs *sf) ++{ ++ /* do_statfs uses struct statfs64 internally, but the linux kernel ++ * struct statfs still has 32-bit versions for most of these fields, ++ * so we convert them here ++ */ ++ int err; ++ long long f_blocks; ++ long long f_bfree; ++ long long f_bavail; ++ long long f_files; ++ long long f_ffree; ++ ++ err = do_statfs(sb->s_root->d_inode->u.hostfs_i.host_filename, ++ &sf->f_bsize, &f_blocks, &f_bfree, &f_bavail, &f_files, ++ &f_ffree, &sf->f_fsid, sizeof(sf->f_fsid), ++ &sf->f_namelen, sf->f_spare); ++ if(err) return(err); ++ sf->f_blocks = f_blocks; ++ sf->f_bfree = f_bfree; ++ sf->f_bavail = f_bavail; ++ sf->f_files = f_files; ++ sf->f_ffree = f_ffree; ++ sf->f_type = HOSTFS_SUPER_MAGIC; ++ return(0); ++} ++ ++static struct super_operations hostfs_sbops = { ++ .put_inode = force_delete, ++ .delete_inode = hostfs_delete_inode, ++ .statfs = hostfs_statfs, ++}; ++ ++int hostfs_readdir(struct file *file, void *ent, filldir_t filldir) ++{ ++ void *dir; ++ char *name; ++ unsigned long long next, ino; ++ int error, len; ++ ++ name = dentry_name(file->f_dentry, 0); ++ if(name == NULL) return(-ENOMEM); ++ dir = open_dir(name, &error); ++ kfree(name); ++ if(dir == NULL) return(-error); ++ next = file->f_pos; ++ while((name = read_dir(dir, &next, &ino, &len)) != NULL){ ++ error = (*filldir)(ent, name, len, file->f_pos, ++ ino, DT_UNKNOWN); ++ if(error) break; ++ file->f_pos = next; ++ } ++ close_dir(dir); ++ return(0); ++} ++ ++int hostfs_file_open(struct inode *ino, struct file *file) ++{ ++ char *name; ++ int mode = 0, r = 0, w = 0, fd; ++ ++ mode = file->f_mode & (FMODE_READ | FMODE_WRITE); ++ if((mode & ino->u.hostfs_i.mode) == mode) ++ return(0); ++ ++ /* The file may already have been opened, but with the wrong access, ++ * so this resets things and reopens the file with the new access. ++ */ ++ if(ino->u.hostfs_i.fd != -1){ ++ close_file(&ino->u.hostfs_i.fd); ++ ino->u.hostfs_i.fd = -1; ++ } ++ ++ ino->u.hostfs_i.mode |= mode; ++ if(ino->u.hostfs_i.mode & FMODE_READ) ++ r = 1; ++ if(ino->u.hostfs_i.mode & FMODE_WRITE) ++ w = 1; ++ if(w) ++ r = 1; ++ ++ name = dentry_name(file->f_dentry, 0); ++ if(name == NULL) ++ return(-ENOMEM); ++ ++ fd = open_file(name, r, w, append); ++ kfree(name); ++ if(fd < 0) return(fd); ++ file_hostfs_i(file)->fd = fd; ++ ++ return(0); ++} ++ ++int hostfs_dir_open(struct inode *ino, struct file *file) ++{ ++ return(0); ++} ++ ++int hostfs_dir_release(struct inode *ino, struct file *file) ++{ ++ return(0); ++} ++ ++int hostfs_fsync(struct file *file, struct dentry *dentry, int datasync) ++{ ++ return(0); ++} ++ ++static struct file_operations hostfs_file_fops = { ++ .owner = NULL, ++ .read = generic_file_read, ++ .write = generic_file_write, ++ .mmap = generic_file_mmap, ++ .open = hostfs_file_open, ++ .release = NULL, ++ .fsync = hostfs_fsync, ++}; ++ ++static struct file_operations hostfs_dir_fops = { ++ .owner = NULL, ++ .readdir = hostfs_readdir, ++ .open = hostfs_dir_open, ++ .release = hostfs_dir_release, ++ .fsync = hostfs_fsync, ++}; ++ ++int hostfs_writepage(struct page *page) ++{ ++ struct address_space *mapping = page->mapping; ++ struct inode *inode = mapping->host; ++ char *buffer; ++ unsigned long long base; ++ int count = PAGE_CACHE_SIZE; ++ int end_index = inode->i_size >> PAGE_CACHE_SHIFT; ++ int err; ++ ++ if (page->index >= end_index) ++ count = inode->i_size & (PAGE_CACHE_SIZE-1); ++ ++ buffer = kmap(page); ++ base = ((unsigned long long) page->index) << PAGE_CACHE_SHIFT; ++ ++ err = write_file(inode->u.hostfs_i.fd, &base, buffer, count); ++ if(err != count){ ++ ClearPageUptodate(page); ++ goto out; ++ } ++ ++ if (base > inode->i_size) ++ inode->i_size = base; ++ ++ if (PageError(page)) ++ ClearPageError(page); ++ err = 0; ++ ++ out: ++ kunmap(page); ++ ++ UnlockPage(page); ++ return err; ++} ++ ++int hostfs_readpage(struct file *file, struct page *page) ++{ ++ char *buffer; ++ long long start; ++ int err = 0; ++ ++ start = (long long) page->index << PAGE_CACHE_SHIFT; ++ buffer = kmap(page); ++ err = read_file(file_hostfs_i(file)->fd, &start, buffer, ++ PAGE_CACHE_SIZE); ++ if(err < 0) goto out; ++ ++ memset(&buffer[err], 0, PAGE_CACHE_SIZE - err); ++ ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ if (PageError(page)) ClearPageError(page); ++ err = 0; ++ out: ++ kunmap(page); ++ UnlockPage(page); ++ return(err); ++} ++ ++int hostfs_prepare_write(struct file *file, struct page *page, ++ unsigned int from, unsigned int to) ++{ ++ char *buffer; ++ long long start, tmp; ++ int err; ++ ++ start = (long long) page->index << PAGE_CACHE_SHIFT; ++ buffer = kmap(page); ++ if(from != 0){ ++ tmp = start; ++ err = read_file(file_hostfs_i(file)->fd, &tmp, buffer, ++ from); ++ if(err < 0) goto out; ++ } ++ if(to != PAGE_CACHE_SIZE){ ++ start += to; ++ err = read_file(file_hostfs_i(file)->fd, &start, buffer + to, ++ PAGE_CACHE_SIZE - to); ++ if(err < 0) goto out; ++ } ++ err = 0; ++ out: ++ kunmap(page); ++ return(err); ++} ++ ++int hostfs_commit_write(struct file *file, struct page *page, unsigned from, ++ unsigned to) ++{ ++ struct address_space *mapping = page->mapping; ++ struct inode *inode = mapping->host; ++ char *buffer; ++ long long start; ++ int err = 0; ++ ++ start = (long long) (page->index << PAGE_CACHE_SHIFT) + from; ++ buffer = kmap(page); ++ err = write_file(file_hostfs_i(file)->fd, &start, buffer + from, ++ to - from); ++ if(err > 0) err = 0; ++ if(!err && (start > inode->i_size)) ++ inode->i_size = start; ++ ++ kunmap(page); ++ return(err); ++} ++ ++static struct address_space_operations hostfs_aops = { ++ .writepage = hostfs_writepage, ++ .readpage = hostfs_readpage, ++/* .set_page_dirty = __set_page_dirty_nobuffers, */ ++ .prepare_write = hostfs_prepare_write, ++ .commit_write = hostfs_commit_write ++}; ++ ++static struct inode *get_inode(struct super_block *sb, struct dentry *dentry, ++ int *error) ++{ ++ struct inode *inode; ++ char *name; ++ int type, err = -ENOMEM, rdev; ++ ++ inode = new_inode(sb); ++ if(inode == NULL) ++ goto out; ++ ++ inode->u.hostfs_i.host_filename = NULL; ++ inode->u.hostfs_i.fd = -1; ++ inode->u.hostfs_i.mode = 0; ++ insert_inode_hash(inode); ++ if(dentry){ ++ name = dentry_name(dentry, 0); ++ if(name == NULL){ ++ err = -ENOMEM; ++ goto out_put; ++ } ++ type = file_type(name, &rdev); ++ kfree(name); ++ } ++ else type = OS_TYPE_DIR; ++ inode->i_sb = sb; ++ ++ err = 0; ++ if(type == OS_TYPE_SYMLINK) ++ inode->i_op = &page_symlink_inode_operations; ++ else if(type == OS_TYPE_DIR) ++ inode->i_op = &hostfs_dir_iops; ++ else inode->i_op = &hostfs_iops; ++ ++ if(type == OS_TYPE_DIR) inode->i_fop = &hostfs_dir_fops; ++ else inode->i_fop = &hostfs_file_fops; ++ ++ if(type == OS_TYPE_SYMLINK) ++ inode->i_mapping->a_ops = &hostfs_link_aops; ++ else inode->i_mapping->a_ops = &hostfs_aops; ++ ++ switch (type) { ++ case OS_TYPE_CHARDEV: ++ init_special_inode(inode, S_IFCHR, rdev); ++ break; ++ case OS_TYPE_BLOCKDEV: ++ init_special_inode(inode, S_IFBLK, rdev); ++ break; ++ case OS_TYPE_FIFO: ++ init_special_inode(inode, S_IFIFO, 0); ++ break; ++ case OS_TYPE_SOCK: ++ init_special_inode(inode, S_IFSOCK, 0); ++ break; ++ } ++ ++ if(error) *error = err; ++ return(inode); ++ out_put: ++ make_bad_inode(inode); ++ iput(inode); ++ out: ++ if(error) *error = err; ++ return(NULL); ++} ++ ++int hostfs_create(struct inode *dir, struct dentry *dentry, int mode) ++{ ++ struct inode *inode; ++ char *name; ++ int error, fd; ++ ++ inode = get_inode(dir->i_sb, dentry, &error); ++ if(error) return(error); ++ name = dentry_name(dentry, 0); ++ if(name == NULL){ ++ iput(inode); ++ return(-ENOMEM); ++ } ++ fd = file_create(name, ++ mode & S_IRUSR, mode & S_IWUSR, mode & S_IXUSR, ++ mode & S_IRGRP, mode & S_IWGRP, mode & S_IXGRP, ++ mode & S_IROTH, mode & S_IWOTH, mode & S_IXOTH); ++ if(fd < 0) ++ error = fd; ++ else error = read_name(inode, name); ++ ++ kfree(name); ++ if(error){ ++ iput(inode); ++ return(error); ++ } ++ inode->u.hostfs_i.fd = fd; ++ inode->u.hostfs_i.mode = FMODE_READ | FMODE_WRITE; ++ d_instantiate(dentry, inode); ++ return(0); ++} ++ ++struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry) ++{ ++ struct inode *inode; ++ char *name; ++ int error; ++ ++ inode = get_inode(ino->i_sb, dentry, &error); ++ if(error != 0) return(ERR_PTR(error)); ++ name = dentry_name(dentry, 0); ++ if(name == NULL) return(ERR_PTR(-ENOMEM)); ++ error = read_name(inode, name); ++ kfree(name); ++ if(error){ ++ iput(inode); ++ if(error == -ENOENT) inode = NULL; ++ else return(ERR_PTR(error)); ++ } ++ d_add(dentry, inode); ++ dentry->d_op = &hostfs_dentry_ops; ++ return(NULL); ++} ++ ++static char *inode_dentry_name(struct inode *ino, struct dentry *dentry) ++{ ++ char *file; ++ int len; ++ ++ file = inode_name(ino, dentry->d_name.len + 1); ++ if(file == NULL) return(NULL); ++ strcat(file, "/"); ++ len = strlen(file); ++ strncat(file, dentry->d_name.name, dentry->d_name.len); ++ file[len + dentry->d_name.len] = '\0'; ++ return(file); ++} ++ ++int hostfs_link(struct dentry *to, struct inode *ino, struct dentry *from) ++{ ++ char *from_name, *to_name; ++ int err; ++ ++ from_name = inode_dentry_name(ino, from); ++ if(from_name == NULL) ++ return(-ENOMEM); ++ to_name = dentry_name(to, 0); ++ if(to_name == NULL){ ++ kfree(from_name); ++ return(-ENOMEM); ++ } ++ err = link_file(to_name, from_name); ++ kfree(from_name); ++ kfree(to_name); ++ return(err); ++} ++ ++int hostfs_unlink(struct inode *ino, struct dentry *dentry) ++{ ++ char *file; ++ int err; ++ ++ file = inode_dentry_name(ino, dentry); ++ if(file == NULL) return(-ENOMEM); ++ if(append) ++ return(-EPERM); ++ ++ err = unlink_file(file); ++ kfree(file); ++ return(err); ++} ++ ++int hostfs_symlink(struct inode *ino, struct dentry *dentry, const char *to) ++{ ++ char *file; ++ int err; ++ ++ file = inode_dentry_name(ino, dentry); ++ if(file == NULL) return(-ENOMEM); ++ err = make_symlink(file, to); ++ kfree(file); ++ return(err); ++} ++ ++int hostfs_mkdir(struct inode *ino, struct dentry *dentry, int mode) ++{ ++ char *file; ++ int err; ++ ++ file = inode_dentry_name(ino, dentry); ++ if(file == NULL) return(-ENOMEM); ++ err = do_mkdir(file, mode); ++ kfree(file); ++ return(err); ++} ++ ++int hostfs_rmdir(struct inode *ino, struct dentry *dentry) ++{ ++ char *file; ++ int err; ++ ++ file = inode_dentry_name(ino, dentry); ++ if(file == NULL) return(-ENOMEM); ++ err = do_rmdir(file); ++ kfree(file); ++ return(err); ++} ++ ++int hostfs_mknod(struct inode *dir, struct dentry *dentry, int mode, int dev) ++{ ++ struct inode *inode; ++ char *name; ++ int error; ++ ++ inode = get_inode(dir->i_sb, dentry, &error); ++ if(error) return(error); ++ name = dentry_name(dentry, 0); ++ if(name == NULL){ ++ iput(inode); ++ return(-ENOMEM); ++ } ++ init_special_inode(inode, mode, dev); ++ error = do_mknod(name, mode, dev); ++ if(!error) error = read_name(inode, name); ++ kfree(name); ++ if(error){ ++ iput(inode); ++ return(error); ++ } ++ d_instantiate(dentry, inode); ++ return(0); ++} ++ ++int hostfs_rename(struct inode *from_ino, struct dentry *from, ++ struct inode *to_ino, struct dentry *to) ++{ ++ char *from_name, *to_name; ++ int err; ++ ++ from_name = inode_dentry_name(from_ino, from); ++ if(from_name == NULL) ++ return(-ENOMEM); ++ to_name = inode_dentry_name(to_ino, to); ++ if(to_name == NULL){ ++ kfree(from_name); ++ return(-ENOMEM); ++ } ++ err = rename_file(from_name, to_name); ++ kfree(from_name); ++ kfree(to_name); ++ return(err); ++} ++ ++void hostfs_truncate(struct inode *ino) ++{ ++ not_implemented(); ++} ++ ++int hostfs_permission(struct inode *ino, int desired) ++{ ++ char *name; ++ int r = 0, w = 0, x = 0, err; ++ ++ if(desired & MAY_READ) r = 1; ++ if(desired & MAY_WRITE) w = 1; ++ if(desired & MAY_EXEC) x = 1; ++ name = inode_name(ino, 0); ++ if(name == NULL) return(-ENOMEM); ++ err = access_file(name, r, w, x); ++ kfree(name); ++ if(!err) err = vfs_permission(ino, desired); ++ return(err); ++} ++ ++int hostfs_setattr(struct dentry *dentry, struct iattr *attr) ++{ ++ struct hostfs_iattr attrs; ++ char *name; ++ int err; ++ ++ if(append) ++ attr->ia_valid &= ~ATTR_SIZE; ++ ++ attrs.ia_valid = 0; ++ if(attr->ia_valid & ATTR_MODE){ ++ attrs.ia_valid |= HOSTFS_ATTR_MODE; ++ attrs.ia_mode = attr->ia_mode; ++ } ++ if(attr->ia_valid & ATTR_UID){ ++ if(kdev_same(dentry->d_inode->i_sb->s_dev, ROOT_DEV) && ++ (attr->ia_uid == 0)) ++ attr->ia_uid = getuid(); ++ attrs.ia_valid |= HOSTFS_ATTR_UID; ++ attrs.ia_uid = attr->ia_uid; ++ } ++ if(attr->ia_valid & ATTR_GID){ ++ if(kdev_same(dentry->d_inode->i_sb->s_dev, ROOT_DEV) && ++ (attr->ia_gid == 0)) ++ attr->ia_gid = getuid(); ++ attrs.ia_valid |= HOSTFS_ATTR_GID; ++ attrs.ia_gid = attr->ia_gid; ++ } ++ if(attr->ia_valid & ATTR_SIZE){ ++ attrs.ia_valid |= HOSTFS_ATTR_SIZE; ++ attrs.ia_size = attr->ia_size; ++ } ++ if(attr->ia_valid & ATTR_ATIME){ ++ attrs.ia_valid |= HOSTFS_ATTR_ATIME; ++ attrs.ia_atime = attr->ia_atime; ++ } ++ if(attr->ia_valid & ATTR_MTIME){ ++ attrs.ia_valid |= HOSTFS_ATTR_MTIME; ++ attrs.ia_mtime = attr->ia_mtime; ++ } ++ if(attr->ia_valid & ATTR_CTIME){ ++ attrs.ia_valid |= HOSTFS_ATTR_CTIME; ++ attrs.ia_ctime = attr->ia_ctime; ++ } ++ if(attr->ia_valid & ATTR_ATIME_SET){ ++ attrs.ia_valid |= HOSTFS_ATTR_ATIME_SET; ++ } ++ if(attr->ia_valid & ATTR_MTIME_SET){ ++ attrs.ia_valid |= HOSTFS_ATTR_MTIME_SET; ++ } ++ name = dentry_name(dentry, 0); ++ if(name == NULL) return(-ENOMEM); ++ err = set_attr(name, &attrs); ++ kfree(name); ++ if(err) ++ return(err); ++ ++ return(inode_setattr(dentry->d_inode, attr)); ++} ++ ++int hostfs_getattr(struct dentry *dentry, struct iattr *attr) ++{ ++ not_implemented(); ++ return(-EINVAL); ++} ++ ++static struct inode_operations hostfs_iops = { ++ .create = hostfs_create, ++ .link = hostfs_link, ++ .unlink = hostfs_unlink, ++ .symlink = hostfs_symlink, ++ .mkdir = hostfs_mkdir, ++ .rmdir = hostfs_rmdir, ++ .mknod = hostfs_mknod, ++ .rename = hostfs_rename, ++ .truncate = hostfs_truncate, ++ .permission = hostfs_permission, ++ .setattr = hostfs_setattr, ++ .getattr = hostfs_getattr, ++}; ++ ++static struct inode_operations hostfs_dir_iops = { ++ .create = hostfs_create, ++ .lookup = hostfs_lookup, ++ .link = hostfs_link, ++ .unlink = hostfs_unlink, ++ .symlink = hostfs_symlink, ++ .mkdir = hostfs_mkdir, ++ .rmdir = hostfs_rmdir, ++ .mknod = hostfs_mknod, ++ .rename = hostfs_rename, ++ .truncate = hostfs_truncate, ++ .permission = hostfs_permission, ++ .setattr = hostfs_setattr, ++ .getattr = hostfs_getattr, ++}; ++ ++int hostfs_link_readpage(struct file *file, struct page *page) ++{ ++ char *buffer, *name; ++ long long start; ++ int err; ++ ++ start = page->index << PAGE_CACHE_SHIFT; ++ buffer = kmap(page); ++ name = inode_name(page->mapping->host, 0); ++ if(name == NULL) return(-ENOMEM); ++ err = do_readlink(name, buffer, PAGE_CACHE_SIZE); ++ kfree(name); ++ if(err == PAGE_CACHE_SIZE) ++ err = -E2BIG; ++ else if(err > 0){ ++ flush_dcache_page(page); ++ SetPageUptodate(page); ++ if (PageError(page)) ClearPageError(page); ++ err = 0; ++ } ++ kunmap(page); ++ UnlockPage(page); ++ return(err); ++} ++ ++static struct address_space_operations hostfs_link_aops = { ++ .readpage = hostfs_link_readpage, ++}; ++ ++static char *get_root(char *mount_arg) ++{ ++ char *root, *slash = ""; ++ int len = 0; ++ ++ if(jail_dir != NULL){ ++ len += strlen(jail_dir); ++ if((*jail_dir == '\0') || ++ (jail_dir[strlen(jail_dir) - 1] != '/')) ++ slash = "/"; ++ len += strlen(slash); ++ } ++ ++ if((mount_arg == NULL) || (*mount_arg == '\0')) ++ mount_arg = DEFAULT_ROOT; ++ ++ len += strlen(mount_arg) + 1; ++ ++ root = kmalloc(len, GFP_KERNEL); ++ if(root == NULL) ++ return(NULL); ++ ++ if(jail_dir != NULL) ++ sprintf(root, "%s%s%s", jail_dir, slash, mount_arg); ++ else ++ strcpy(root, mount_arg); ++ ++ return(root); ++} ++ ++struct super_block *hostfs_read_super(struct super_block *sb, void *data, ++ int silent) ++{ ++ struct inode *root_inode; ++ char *root_dir; ++ ++ sb->s_blocksize = 1024; ++ sb->s_blocksize_bits = 10; ++ sb->s_magic = HOSTFS_SUPER_MAGIC; ++ sb->s_op = &hostfs_sbops; ++ ++ root_inode = get_inode(sb, NULL, NULL); ++ if(root_inode == NULL) ++ goto out; ++ ++ root_dir = get_root(data); ++ if(root_dir == NULL) ++ goto out_put; ++ ++ root_inode->u.hostfs_i.host_filename = root_dir; ++ sb->s_root = d_alloc_root(root_inode); ++ if(sb->s_root == NULL) ++ goto out_free; ++ ++ if(read_inode(root_inode)) ++ goto out_dput; ++ return(sb); ++ ++ out_dput: ++ dput(sb->s_root); ++ out_free: ++ kfree(root_dir); ++ out_put: ++ make_bad_inode(root_inode); ++ iput(root_inode); ++ out: ++ return(NULL); ++} ++ ++DECLARE_FSTYPE(hostfs_type, "hostfs", hostfs_read_super, 0); ++ ++static int __init init_hostfs(void) ++{ ++ return(register_filesystem(&hostfs_type)); ++} ++ ++static void __exit exit_hostfs(void) ++{ ++ unregister_filesystem(&hostfs_type); ++} ++ ++module_init(init_hostfs) ++module_exit(exit_hostfs) ++MODULE_LICENSE("GPL"); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/fs/hostfs/hostfs_user.c um/arch/um/fs/hostfs/hostfs_user.c +--- orig/arch/um/fs/hostfs/hostfs_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/fs/hostfs/hostfs_user.c 2003-11-14 08:51:20.000000000 -0500 +@@ -0,0 +1,359 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <unistd.h> ++#include <stdio.h> ++#include <fcntl.h> ++#include <dirent.h> ++#include <errno.h> ++#include <utime.h> ++#include <string.h> ++#include <sys/stat.h> ++#include <sys/time.h> ++#include <sys/vfs.h> ++#include "hostfs.h" ++#include "kern_util.h" ++#include "user.h" ++ ++int stat_file(const char *path, int *dev_out, unsigned long long *inode_out, ++ int *mode_out, int *nlink_out, int *uid_out, int *gid_out, ++ unsigned long long *size_out, unsigned long *atime_out, ++ unsigned long *mtime_out, unsigned long *ctime_out, ++ int *blksize_out, unsigned long long *blocks_out) ++{ ++ struct stat64 buf; ++ ++ if(lstat64(path, &buf) < 0) ++ return(-errno); ++ if(dev_out != NULL) *dev_out = buf.st_dev; ++ ++ /* See the Makefile for why STAT64_INO_FIELD is passed in ++ * by the build ++ */ ++ if(inode_out != NULL) *inode_out = buf.STAT64_INO_FIELD; ++ if(mode_out != NULL) *mode_out = buf.st_mode; ++ if(nlink_out != NULL) *nlink_out = buf.st_nlink; ++ if(uid_out != NULL) *uid_out = buf.st_uid; ++ if(gid_out != NULL) *gid_out = buf.st_gid; ++ if(size_out != NULL) *size_out = buf.st_size; ++ if(atime_out != NULL) *atime_out = buf.st_atime; ++ if(mtime_out != NULL) *mtime_out = buf.st_mtime; ++ if(ctime_out != NULL) *ctime_out = buf.st_ctime; ++ if(blksize_out != NULL) *blksize_out = buf.st_blksize; ++ if(blocks_out != NULL) *blocks_out = buf.st_blocks; ++ return(0); ++} ++ ++int file_type(const char *path, int *rdev) ++{ ++ struct stat64 buf; ++ ++ if(lstat64(path, &buf) < 0) ++ return(-errno); ++ if(rdev != NULL) ++ *rdev = buf.st_rdev; ++ ++ if(S_ISDIR(buf.st_mode)) return(OS_TYPE_DIR); ++ else if(S_ISLNK(buf.st_mode)) return(OS_TYPE_SYMLINK); ++ else if(S_ISCHR(buf.st_mode)) return(OS_TYPE_CHARDEV); ++ else if(S_ISBLK(buf.st_mode)) return(OS_TYPE_BLOCKDEV); ++ else if(S_ISFIFO(buf.st_mode))return(OS_TYPE_FIFO); ++ else if(S_ISSOCK(buf.st_mode))return(OS_TYPE_SOCK); ++ else return(OS_TYPE_FILE); ++} ++ ++int access_file(char *path, int r, int w, int x) ++{ ++ int mode = 0; ++ ++ if(r) mode = R_OK; ++ if(w) mode |= W_OK; ++ if(x) mode |= X_OK; ++ if(access(path, mode) != 0) return(-errno); ++ else return(0); ++} ++ ++int open_file(char *path, int r, int w, int append) ++{ ++ int mode = 0, fd; ++ ++ if(r && !w) ++ mode = O_RDONLY; ++ else if(!r && w) ++ mode = O_WRONLY; ++ else if(r && w) ++ mode = O_RDWR; ++ else panic("Impossible mode in open_file"); ++ ++ if(append) ++ mode |= O_APPEND; ++ fd = open64(path, mode); ++ if(fd < 0) return(-errno); ++ else return(fd); ++} ++ ++void *open_dir(char *path, int *err_out) ++{ ++ DIR *dir; ++ ++ dir = opendir(path); ++ *err_out = errno; ++ if(dir == NULL) return(NULL); ++ return(dir); ++} ++ ++char *read_dir(void *stream, unsigned long long *pos, ++ unsigned long long *ino_out, int *len_out) ++{ ++ DIR *dir = stream; ++ struct dirent *ent; ++ ++ seekdir(dir, *pos); ++ ent = readdir(dir); ++ if(ent == NULL) return(NULL); ++ *len_out = strlen(ent->d_name); ++ *ino_out = ent->d_ino; ++ *pos = telldir(dir); ++ return(ent->d_name); ++} ++ ++int read_file(int fd, unsigned long long *offset, char *buf, int len) ++{ ++ int n, err; ++ ++ err = os_seek_file(fd, *offset); ++ if(err) ++ return(err); ++ ++ n = os_read_file(fd, buf, len); ++ if(n < 0) ++ return(n); ++ ++ *offset += n; ++ return(n); ++} ++ ++int write_file(int fd, unsigned long long *offset, const char *buf, int len) ++{ ++ int n, err; ++ ++ err = os_seek_file(fd, *offset); ++ if(err) ++ return(err); ++ ++ n = os_write_file(fd, buf, len); ++ if(n < 0) ++ return(n); ++ ++ *offset += n; ++ return(n); ++} ++ ++int lseek_file(int fd, long long offset, int whence) ++{ ++ int ret; ++ ++ ret = lseek64(fd, offset, whence); ++ if(ret < 0) return(-errno); ++ return(0); ++} ++ ++void close_file(void *stream) ++{ ++ close(*((int *) stream)); ++} ++ ++void close_dir(void *stream) ++{ ++ closedir(stream); ++} ++ ++int file_create(char *name, int ur, int uw, int ux, int gr, ++ int gw, int gx, int or, int ow, int ox) ++{ ++ int mode, fd; ++ ++ mode = 0; ++ mode |= ur ? S_IRUSR : 0; ++ mode |= uw ? S_IWUSR : 0; ++ mode |= ux ? S_IXUSR : 0; ++ mode |= gr ? S_IRGRP : 0; ++ mode |= gw ? S_IWGRP : 0; ++ mode |= gx ? S_IXGRP : 0; ++ mode |= or ? S_IROTH : 0; ++ mode |= ow ? S_IWOTH : 0; ++ mode |= ox ? S_IXOTH : 0; ++ fd = open64(name, O_CREAT | O_RDWR, mode); ++ if(fd < 0) ++ return(-errno); ++ return(fd); ++} ++ ++int set_attr(const char *file, struct hostfs_iattr *attrs) ++{ ++ struct utimbuf buf; ++ int err, ma; ++ ++ if(attrs->ia_valid & HOSTFS_ATTR_MODE){ ++ if(chmod(file, attrs->ia_mode) != 0) return(-errno); ++ } ++ if(attrs->ia_valid & HOSTFS_ATTR_UID){ ++ if(chown(file, attrs->ia_uid, -1)) return(-errno); ++ } ++ if(attrs->ia_valid & HOSTFS_ATTR_GID){ ++ if(chown(file, -1, attrs->ia_gid)) return(-errno); ++ } ++ if(attrs->ia_valid & HOSTFS_ATTR_SIZE){ ++ if(truncate(file, attrs->ia_size)) return(-errno); ++ } ++ ma = HOSTFS_ATTR_ATIME_SET | HOSTFS_ATTR_MTIME_SET; ++ if((attrs->ia_valid & ma) == ma){ ++ buf.actime = attrs->ia_atime; ++ buf.modtime = attrs->ia_mtime; ++ if(utime(file, &buf) != 0) return(-errno); ++ } ++ else { ++ if(attrs->ia_valid & HOSTFS_ATTR_ATIME_SET){ ++ err = stat_file(file, NULL, NULL, NULL, NULL, NULL, ++ NULL, NULL, NULL, &buf.modtime, NULL, ++ NULL, NULL); ++ if(err != 0) return(err); ++ buf.actime = attrs->ia_atime; ++ if(utime(file, &buf) != 0) return(-errno); ++ } ++ if(attrs->ia_valid & HOSTFS_ATTR_MTIME_SET){ ++ err = stat_file(file, NULL, NULL, NULL, NULL, NULL, ++ NULL, NULL, &buf.actime, NULL, NULL, ++ NULL, NULL); ++ if(err != 0) return(err); ++ buf.modtime = attrs->ia_mtime; ++ if(utime(file, &buf) != 0) return(-errno); ++ } ++ } ++ if(attrs->ia_valid & HOSTFS_ATTR_CTIME) ; ++ if(attrs->ia_valid & (HOSTFS_ATTR_ATIME | HOSTFS_ATTR_MTIME)){ ++ err = stat_file(file, NULL, NULL, NULL, NULL, NULL, ++ NULL, NULL, &attrs->ia_atime, &attrs->ia_mtime, ++ NULL, NULL, NULL); ++ if(err != 0) return(err); ++ } ++ return(0); ++} ++ ++int make_symlink(const char *from, const char *to) ++{ ++ int err; ++ ++ err = symlink(to, from); ++ if(err) return(-errno); ++ return(0); ++} ++ ++int unlink_file(const char *file) ++{ ++ int err; ++ ++ err = unlink(file); ++ if(err) return(-errno); ++ return(0); ++} ++ ++int do_mkdir(const char *file, int mode) ++{ ++ int err; ++ ++ err = mkdir(file, mode); ++ if(err) return(-errno); ++ return(0); ++} ++ ++int do_rmdir(const char *file) ++{ ++ int err; ++ ++ err = rmdir(file); ++ if(err) return(-errno); ++ return(0); ++} ++ ++int do_mknod(const char *file, int mode, int dev) ++{ ++ int err; ++ ++ err = mknod(file, mode, dev); ++ if(err) return(-errno); ++ return(0); ++} ++ ++int link_file(const char *to, const char *from) ++{ ++ int err; ++ ++ err = link(to, from); ++ if(err) return(-errno); ++ return(0); ++} ++ ++int do_readlink(char *file, char *buf, int size) ++{ ++ int n; ++ ++ n = readlink(file, buf, size); ++ if(n < 0) ++ return(-errno); ++ if(n < size) ++ buf[n] = '\0'; ++ return(n); ++} ++ ++int rename_file(char *from, char *to) ++{ ++ int err; ++ ++ err = rename(from, to); ++ if(err < 0) return(-errno); ++ return(0); ++} ++ ++int do_statfs(char *root, long *bsize_out, long long *blocks_out, ++ long long *bfree_out, long long *bavail_out, ++ long long *files_out, long long *ffree_out, ++ void *fsid_out, int fsid_size, long *namelen_out, ++ long *spare_out) ++{ ++ struct statfs64 buf; ++ int err; ++ ++ err = statfs64(root, &buf); ++ if(err < 0) return(-errno); ++ *bsize_out = buf.f_bsize; ++ *blocks_out = buf.f_blocks; ++ *bfree_out = buf.f_bfree; ++ *bavail_out = buf.f_bavail; ++ *files_out = buf.f_files; ++ *ffree_out = buf.f_ffree; ++ memcpy(fsid_out, &buf.f_fsid, ++ sizeof(buf.f_fsid) > fsid_size ? fsid_size : ++ sizeof(buf.f_fsid)); ++ *namelen_out = buf.f_namelen; ++ spare_out[0] = buf.f_spare[0]; ++ spare_out[1] = buf.f_spare[1]; ++ spare_out[2] = buf.f_spare[2]; ++ spare_out[3] = buf.f_spare[3]; ++ spare_out[4] = buf.f_spare[4]; ++ spare_out[5] = buf.f_spare[5]; ++ return(0); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/fs/hostfs/Makefile um/arch/um/fs/hostfs/Makefile +--- orig/arch/um/fs/hostfs/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/fs/hostfs/Makefile 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,24 @@ ++# ++# Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++# Licensed under the GPL ++# ++ ++# struct stat64 changed the inode field name between 2.2 and 2.4 from st_ino ++# to __st_ino. It stayed in the same place, so as long as the correct name ++# is used, hostfs compiled on 2.2 should work on 2.4 and vice versa. ++ ++STAT64_INO_FIELD := $(shell grep -q __st_ino /usr/include/bits/stat.h && \ ++ echo __)st_ino ++ ++USER_CFLAGS := $(USER_CFLAGS) -DSTAT64_INO_FIELD=$(STAT64_INO_FIELD) ++ ++O_TARGET := hostfs.o ++obj-y = hostfs_kern.o hostfs_user.o ++obj-m = $(O_TARGET) ++ ++USER_OBJS = $(filter %_user.o,$(obj-y)) ++ ++include $(TOPDIR)/Rules.make ++ ++$(USER_OBJS) : %.o: %.c ++ $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< +diff -Naur -X ../exclude-files orig/arch/um/fs/hppfs/hppfs_kern.c um/arch/um/fs/hppfs/hppfs_kern.c +--- orig/arch/um/fs/hppfs/hppfs_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/fs/hppfs/hppfs_kern.c 2003-11-08 09:42:49.000000000 -0500 +@@ -0,0 +1,727 @@ ++/* ++ * 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(!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; ++ ++ 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; ++ ++ proc_file->f_pos = file->f_pos; ++ err = (*readdir)(proc_file, &dirent, hppfs_filldir); ++ file->f_pos = proc_file->f_pos; ++ ++ return(err); ++} ++ ++static int hppfs_fsync(struct file *file, struct dentry *dentry, int datasync) ++{ ++ return(0); ++} ++ ++static struct file_operations hppfs_file_fops = { ++ .owner = NULL, ++ .llseek = hppfs_llseek, ++ .read = hppfs_read, ++ .write = hppfs_write, ++ .open = hppfs_open, ++}; ++ ++static struct file_operations hppfs_dir_fops = { ++ .owner = NULL, ++ .readdir = hppfs_readdir, ++ .open = hppfs_dir_open, ++ .fsync = hppfs_fsync, ++}; ++ ++static int hppfs_statfs(struct super_block *sb, struct statfs *sf) ++{ ++ sf->f_blocks = 0; ++ sf->f_bfree = 0; ++ sf->f_bavail = 0; ++ sf->f_files = 0; ++ sf->f_ffree = 0; ++ sf->f_type = HPPFS_SUPER_MAGIC; ++ return(0); ++} ++ ++static struct super_operations hppfs_sbops = { ++ .put_inode = force_delete, ++ .delete_inode = NULL, ++ .statfs = hppfs_statfs, ++}; ++ ++static int hppfs_readlink(struct dentry *dentry, char *buffer, int buflen) ++{ ++ struct file proc_file; ++ struct dentry *proc_dentry; ++ int (*readlink)(struct dentry *, char *, int); ++ int err, n; ++ ++ proc_dentry = dentry->d_inode->u.hppfs_i.proc_dentry; ++ err = init_private_file(&proc_file, proc_dentry, FMODE_READ); ++ if(err) ++ return(err); ++ ++ readlink = proc_dentry->d_inode->i_op->readlink; ++ n = (*readlink)(proc_dentry, buffer, buflen); ++ ++ if(proc_file.f_op->release) ++ (*proc_file.f_op->release)(proc_dentry->d_inode, &proc_file); ++ ++ return(n); ++} ++ ++static 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; ++ n = (*follow_link)(proc_dentry, nd); ++ ++ if(proc_file.f_op->release) ++ (*proc_file.f_op->release)(proc_dentry->d_inode, &proc_file); ++ ++ return(n); ++} ++ ++static struct inode_operations hppfs_link_iops = { ++ .readlink = hppfs_readlink, ++ .follow_link = hppfs_follow_link, ++}; ++ ++static void read_inode(struct inode *ino) ++{ ++ struct inode *proc_ino; ++ ++ proc_ino = ino->u.hppfs_i.proc_dentry->d_inode; ++ ino->i_uid = proc_ino->i_uid; ++ ino->i_gid = proc_ino->i_gid; ++ ino->i_atime = proc_ino->i_atime; ++ ino->i_mtime = proc_ino->i_mtime; ++ ino->i_ctime = proc_ino->i_ctime; ++ ino->i_ino = proc_ino->i_ino; ++ ino->i_dev = proc_ino->i_dev; ++ ino->i_mode = proc_ino->i_mode; ++ ino->i_nlink = proc_ino->i_nlink; ++ ino->i_size = proc_ino->i_size; ++ ino->i_blksize = proc_ino->i_blksize; ++ ino->i_blocks = proc_ino->i_blocks; ++} ++ ++static struct inode *get_inode(struct super_block *sb, struct dentry *dentry, ++ int *error) ++{ ++ struct inode *inode; ++ int err = -ENOMEM; ++ ++ inode = new_inode(sb); ++ if(inode == NULL) ++ goto out; ++ ++ insert_inode_hash(inode); ++ if(S_ISDIR(dentry->d_inode->i_mode)){ ++ inode->i_op = &hppfs_dir_iops; ++ inode->i_fop = &hppfs_dir_fops; ++ } ++ else if(S_ISLNK(dentry->d_inode->i_mode)){ ++ inode->i_op = &hppfs_link_iops; ++ inode->i_fop = &hppfs_file_fops; ++ } ++ else { ++ inode->i_op = &hppfs_file_iops; ++ inode->i_fop = &hppfs_file_fops; ++ } ++ ++ inode->i_sb = sb; ++ inode->u.hppfs_i.proc_dentry = dentry; ++ ++ read_inode(inode); ++ err = 0; ++ ++ if(error) *error = err; ++ return(inode); ++ out: ++ if(error) *error = err; ++ return(NULL); ++} ++ ++static struct super_block *hppfs_read_super(struct super_block *sb, void *d, ++ int silent) ++{ ++ struct inode *root_inode; ++ struct file_system_type *procfs; ++ struct super_block *proc_sb; ++ ++ procfs = get_fs_type("proc"); ++ if(procfs == NULL) ++ goto out; ++ ++ if(list_empty(&procfs->fs_supers)) ++ goto out; ++ ++ proc_sb = list_entry(procfs->fs_supers.next, struct super_block, ++ s_instances); ++ ++ sb->s_blocksize = 1024; ++ sb->s_blocksize_bits = 10; ++ sb->s_magic = HPPFS_SUPER_MAGIC; ++ sb->s_op = &hppfs_sbops; ++ ++ dget(proc_sb->s_root); ++ root_inode = get_inode(sb, proc_sb->s_root, NULL); ++ if(root_inode == NULL) ++ goto out_dput; ++ ++ sb->s_root = d_alloc_root(root_inode); ++ if(sb->s_root == NULL) ++ goto out_put; ++ ++ return(sb); ++ ++ out_put: ++ iput(root_inode); ++ out_dput: ++ dput(proc_sb->s_root); ++ out: ++ return(NULL); ++} ++ ++DECLARE_FSTYPE(hppfs_type, "hppfs", hppfs_read_super, 0); ++ ++static int __init init_hppfs(void) ++{ ++ return(register_filesystem(&hppfs_type)); ++} ++ ++static void __exit exit_hppfs(void) ++{ ++ unregister_filesystem(&hppfs_type); ++} ++ ++module_init(init_hppfs) ++module_exit(exit_hppfs) ++MODULE_LICENSE("GPL"); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/fs/hppfs/Makefile um/arch/um/fs/hppfs/Makefile +--- orig/arch/um/fs/hppfs/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/fs/hppfs/Makefile 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,10 @@ ++O_TARGET := hppfs.o ++obj-y = hppfs_kern.o #hppfs_user.o ++obj-m = $(O_TARGET) ++ ++CFLAGS_hppfs_kern.o := $(CFLAGS) ++#CFLAGS_hppfs_user.o := $(USER_CFLAGS) ++ ++override CFLAGS = ++ ++include $(TOPDIR)/Rules.make +diff -Naur -X ../exclude-files orig/arch/um/fs/Makefile um/arch/um/fs/Makefile +--- orig/arch/um/fs/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/fs/Makefile 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,23 @@ ++# ++# Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++# Licensed under the GPL ++# ++ ++O_TARGET := built-in.o ++ ++subdir-y = ++subdir-m = ++ ++subdir-$(CONFIG_HOSTFS) += hostfs ++subdir-$(CONFIG_HPPFS) += hppfs ++ ++obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o)) ++obj-m += $(join $(subdir-m),$(subdir-m:%=/%.o)) ++ ++include $(TOPDIR)/Rules.make ++ ++dep: ++ ++clean: ++ ++archmrproper: +diff -Naur -X ../exclude-files orig/arch/um/include/2_5compat.h um/arch/um/include/2_5compat.h +--- orig/arch/um/include/2_5compat.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/2_5compat.h 2003-11-07 02:49:26.000000000 -0500 +@@ -0,0 +1,33 @@ ++/* ++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __2_5_COMPAT_H__ ++#define __2_5_COMPAT_H__ ++ ++#include "linux/version.h" ++ ++#define INIT_ELV(queue, elv) elevator_init(elv, ELV_NOOP) ++ ++#define ELV_NOOP ELEVATOR_NOOP ++ ++#define INIT_HARDSECT(arr, maj, sizes) arr[maj] = sizes ++ ++#define IS_WRITE(req) ((req)->cmd == WRITE) ++ ++#define SET_PRI(task) \ ++ do { (task)->nice = 20; (task)->counter = -100; } while(0); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/chan_kern.h um/arch/um/include/chan_kern.h +--- orig/arch/um/include/chan_kern.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/chan_kern.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,56 @@ ++/* ++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __CHAN_KERN_H__ ++#define __CHAN_KERN_H__ ++ ++#include "linux/tty.h" ++#include "linux/list.h" ++#include "chan_user.h" ++ ++struct chan { ++ struct list_head list; ++ char *dev; ++ unsigned int primary:1; ++ unsigned int input:1; ++ unsigned int output:1; ++ unsigned int opened:1; ++ int fd; ++ enum chan_init_pri pri; ++ struct chan_ops *ops; ++ void *data; ++}; ++ ++extern void chan_interrupt(struct list_head *chans, struct tq_struct *task, ++ struct tty_struct *tty, int irq, void *dev); ++extern int parse_chan_pair(char *str, struct list_head *chans, int pri, ++ int device, struct chan_opts *opts); ++extern int open_chan(struct list_head *chans); ++extern int write_chan(struct list_head *chans, const char *buf, int len, ++ int write_irq); ++extern int console_write_chan(struct list_head *chans, const char *buf, ++ int len); ++extern void close_chan(struct list_head *chans); ++extern void chan_enable_winch(struct list_head *chans, void *line); ++extern void enable_chan(struct list_head *chans, void *data); ++extern int chan_window_size(struct list_head *chans, ++ unsigned short *rows_out, ++ unsigned short *cols_out); ++extern int chan_out_fd(struct list_head *chans); ++extern int chan_config_string(struct list_head *chans, char *str, int size, ++ char **error_out); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/chan_user.h um/arch/um/include/chan_user.h +--- orig/arch/um/include/chan_user.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/chan_user.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,66 @@ ++/* ++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __CHAN_USER_H__ ++#define __CHAN_USER_H__ ++ ++#include "init.h" ++ ++struct chan_opts { ++ void (*announce)(char *dev_name, int dev); ++ char *xterm_title; ++ int raw; ++ unsigned long tramp_stack; ++ int in_kernel; ++}; ++ ++enum chan_init_pri { INIT_STATIC, INIT_ALL, INIT_ONE }; ++ ++struct chan_ops { ++ char *type; ++ void *(*init)(char *, int, struct chan_opts *); ++ int (*open)(int, int, int, void *, char **); ++ void (*close)(int, void *); ++ int (*read)(int, char *, void *); ++ int (*write)(int, const char *, int, void *); ++ int (*console_write)(int, const char *, int, void *); ++ int (*window_size)(int, void *, unsigned short *, unsigned short *); ++ void (*free)(void *); ++ int winch; ++}; ++ ++extern struct chan_ops fd_ops, null_ops, port_ops, pts_ops, pty_ops, tty_ops, ++ xterm_ops; ++ ++extern void generic_close(int fd, void *unused); ++extern int generic_read(int fd, char *c_out, void *unused); ++extern int generic_write(int fd, const char *buf, int n, void *unused); ++extern int generic_console_write(int fd, const char *buf, int n, void *state); ++extern int generic_window_size(int fd, void *unused, unsigned short *rows_out, ++ unsigned short *cols_out); ++extern void generic_free(void *data); ++ ++extern void register_winch(int fd, void *device_data); ++extern void register_winch_irq(int fd, int tty_fd, int pid, void *line); ++ ++#define __channel_help(fn, prefix) \ ++__uml_help(fn, prefix "[0-9]*=<channel description>\n" \ ++" Attach a console or serial line to a host channel. See\n" \ ++" http://user-mode-linux.sourceforge.net/input.html for a complete\n" \ ++" description of this switch.\n\n" \ ++); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/choose-mode.h um/arch/um/include/choose-mode.h +--- orig/arch/um/include/choose-mode.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/choose-mode.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,35 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __CHOOSE_MODE_H__ ++#define __CHOOSE_MODE_H__ ++ ++#include "uml-config.h" ++ ++#if defined(UML_CONFIG_MODE_TT) && defined(UML_CONFIG_MODE_SKAS) ++#define CHOOSE_MODE(tt, skas) (mode_tt ? (tt) : (skas)) ++ ++#elif defined(UML_CONFIG_MODE_SKAS) ++#define CHOOSE_MODE(tt, skas) (skas) ++ ++#elif defined(UML_CONFIG_MODE_TT) ++#define CHOOSE_MODE(tt, skas) (tt) ++#endif ++ ++#define CHOOSE_MODE_PROC(tt, skas, args...) \ ++ CHOOSE_MODE(tt(args), skas(args)) ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/frame.h um/arch/um/include/frame.h +--- orig/arch/um/include/frame.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/frame.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,53 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __FRAME_H_ ++#define __FRAME_H_ ++ ++#include "sysdep/frame.h" ++ ++struct frame_common { ++ void *data; ++ int len; ++ int sig_index; ++ int sr_index; ++ int sr_relative; ++ int sp_index; ++ struct arch_frame_data arch; ++}; ++ ++struct sc_frame { ++ struct frame_common common; ++ int sc_index; ++}; ++ ++extern struct sc_frame signal_frame_sc; ++ ++extern struct sc_frame signal_frame_sc_sr; ++ ++struct si_frame { ++ struct frame_common common; ++ int sip_index; ++ int si_index; ++ int ucp_index; ++ int uc_index; ++}; ++ ++extern struct si_frame signal_frame_si; ++ ++extern void capture_signal_stack(void); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/frame_kern.h um/arch/um/include/frame_kern.h +--- orig/arch/um/include/frame_kern.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/frame_kern.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __FRAME_KERN_H_ ++#define __FRAME_KERN_H_ ++ ++#include "frame.h" ++#include "sysdep/frame_kern.h" ++ ++extern int setup_signal_stack_sc(unsigned long stack_top, int sig, ++ unsigned long handler, ++ void (*restorer)(void), ++ struct pt_regs *regs, ++ sigset_t *mask); ++extern int setup_signal_stack_si(unsigned long stack_top, int sig, ++ unsigned long handler, ++ void (*restorer)(void), ++ struct pt_regs *regs, siginfo_t *info, ++ sigset_t *mask); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/frame_user.h um/arch/um/include/frame_user.h +--- orig/arch/um/include/frame_user.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/frame_user.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,23 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __FRAME_USER_H_ ++#define __FRAME_USER_H_ ++ ++#include "sysdep/frame_user.h" ++#include "frame.h" ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/helper.h um/arch/um/include/helper.h +--- orig/arch/um/include/helper.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/helper.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,27 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __HELPER_H__ ++#define __HELPER_H__ ++ ++extern int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, ++ unsigned long *stack_out); ++extern int run_helper_thread(int (*proc)(void *), void *arg, ++ unsigned int flags, unsigned long *stack_out, ++ int stack_order); ++extern int helper_wait(int pid); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/hostaudio.h um/arch/um/include/hostaudio.h +--- orig/arch/um/include/hostaudio.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/hostaudio.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (C) 2002 Steve Schmidtke ++ * Licensed under the GPL ++ */ ++ ++#ifndef HOSTAUDIO_H ++#define HOSTAUDIO_H ++ ++#define HOSTAUDIO_DEV_DSP "/dev/sound/dsp" ++#define HOSTAUDIO_DEV_MIXER "/dev/sound/mixer" ++ ++struct hostaudio_state { ++ int fd; ++}; ++ ++struct hostmixer_state { ++ int fd; ++}; ++ ++/* UML user-side protoypes */ ++extern ssize_t hostaudio_read_user(struct hostaudio_state *state, char *buffer, ++ size_t count, loff_t *ppos); ++extern ssize_t hostaudio_write_user(struct hostaudio_state *state, ++ const char *buffer, size_t count, ++ loff_t *ppos); ++extern int hostaudio_ioctl_user(struct hostaudio_state *state, ++ unsigned int cmd, unsigned long arg); ++extern int hostaudio_open_user(struct hostaudio_state *state, int r, int w, ++ char *dsp); ++extern int hostaudio_release_user(struct hostaudio_state *state); ++extern int hostmixer_ioctl_mixdev_user(struct hostmixer_state *state, ++ unsigned int cmd, unsigned long arg); ++extern int hostmixer_open_mixdev_user(struct hostmixer_state *state, int r, ++ int w, char *mixer); ++extern int hostmixer_release_mixdev_user(struct hostmixer_state *state); ++ ++#endif /* HOSTAUDIO_H */ ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/init.h um/arch/um/include/init.h +--- orig/arch/um/include/init.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/init.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,114 @@ ++#ifndef _LINUX_UML_INIT_H ++#define _LINUX_UML_INIT_H ++ ++/* These macros are used to mark some functions or ++ * initialized data (doesn't apply to uninitialized data) ++ * as `initialization' functions. The kernel can take this ++ * as hint that the function is used only during the initialization ++ * phase and free up used memory resources after ++ * ++ * Usage: ++ * For functions: ++ * ++ * You should add __init immediately before the function name, like: ++ * ++ * static void __init initme(int x, int y) ++ * { ++ * extern int z; z = x * y; ++ * } ++ * ++ * If the function has a prototype somewhere, you can also add ++ * __init between closing brace of the prototype and semicolon: ++ * ++ * extern int initialize_foobar_device(int, int, int) __init; ++ * ++ * For initialized data: ++ * You should insert __initdata between the variable name and equal ++ * sign followed by value, e.g.: ++ * ++ * static int init_variable __initdata = 0; ++ * static char linux_logo[] __initdata = { 0x32, 0x36, ... }; ++ * ++ * Don't forget to initialize data not at file scope, i.e. within a function, ++ * as gcc otherwise puts the data into the bss section and not into the init ++ * section. ++ * ++ * Also note, that this data cannot be "const". ++ */ ++ ++#ifndef _LINUX_INIT_H ++typedef int (*initcall_t)(void); ++typedef void (*exitcall_t)(void); ++ ++#define __init __attribute__ ((__section__ (".text.init"))) ++#define __exit __attribute__ ((unused, __section__(".text.exit"))) ++#define __initdata __attribute__ ((__section__ (".data.init"))) ++ ++#endif ++ ++#ifndef MODULE ++struct uml_param { ++ const char *str; ++ int (*setup_func)(char *, int *); ++}; ++ ++extern initcall_t __uml_initcall_start, __uml_initcall_end; ++extern initcall_t __uml_postsetup_start, __uml_postsetup_end; ++extern const char *__uml_help_start, *__uml_help_end; ++#endif ++ ++#define __uml_initcall(fn) \ ++ static initcall_t __uml_initcall_##fn __uml_init_call = fn ++ ++#define __uml_exitcall(fn) \ ++ static exitcall_t __uml_exitcall_##fn __uml_exit_call = fn ++ ++extern struct uml_param __uml_setup_start, __uml_setup_end; ++ ++#define __uml_postsetup(fn) \ ++ static initcall_t __uml_postsetup_##fn __uml_postsetup_call = fn ++ ++#define __non_empty_string(dummyname,string) \ ++ struct __uml_non_empty_string_struct_##dummyname \ ++ { \ ++ char _string[sizeof(string)-2]; \ ++ } ++ ++#ifndef MODULE ++#define __uml_setup(str, fn, help...) \ ++ __non_empty_string(fn ##_setup, str); \ ++ __uml_help(fn, help); \ ++ static char __uml_setup_str_##fn[] __initdata = str; \ ++ static struct uml_param __uml_setup_##fn __uml_init_setup = { __uml_setup_str_##fn, fn } ++#else ++#define __uml_setup(str, fn, help...) \ ++ ++#endif ++ ++#define __uml_help(fn, help...) \ ++ __non_empty_string(fn ##__help, help); \ ++ static char __uml_help_str_##fn[] __initdata = help; \ ++ static const char *__uml_help_##fn __uml_setup_help = __uml_help_str_##fn ++ ++/* ++ * Mark functions and data as being only used at initialization ++ * or exit time. ++ */ ++#define __uml_init_setup __attribute__ ((unused,__section__ (".uml.setup.init"))) ++#define __uml_setup_help __attribute__ ((unused,__section__ (".uml.help.init"))) ++#define __uml_init_call __attribute__ ((unused,__section__ (".uml.initcall.init"))) ++#define __uml_postsetup_call __attribute__ ((unused,__section__ (".uml.postsetup.init"))) ++#define __uml_exit_call __attribute__ ((unused,__section__ (".uml.exitcall.exit"))) ++ ++#endif /* _LINUX_UML_INIT_H */ ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/initrd.h um/arch/um/include/initrd.h +--- orig/arch/um/include/initrd.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/initrd.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,22 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __INITRD_USER_H__ ++#define __INITRD_USER_H__ ++ ++extern int load_initrd(char *filename, void *buf, int size); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/irq_kern.h um/arch/um/include/irq_kern.h +--- orig/arch/um/include/irq_kern.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/irq_kern.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,27 @@ ++/* ++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __IRQ_KERN_H__ ++#define __IRQ_KERN_H__ ++ ++#include "linux/interrupt.h" ++ ++extern int um_request_irq(unsigned int irq, int fd, int type, ++ void (*handler)(int, void *, struct pt_regs *), ++ unsigned long irqflags, const char * devname, ++ void *dev_id); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/irq_user.h um/arch/um/include/irq_user.h +--- orig/arch/um/include/irq_user.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/irq_user.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,35 @@ ++/* ++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __IRQ_USER_H__ ++#define __IRQ_USER_H__ ++ ++enum { IRQ_READ, IRQ_WRITE }; ++ ++extern void sigio_handler(int sig, union uml_pt_regs *regs); ++extern int activate_fd(int irq, int fd, int type, void *dev_id); ++extern void free_irq_by_irq_and_dev(int irq, void *dev_id); ++extern void free_irq_by_fd(int fd); ++extern void reactivate_fd(int fd, int irqnum); ++extern void deactivate_fd(int fd, int irqnum); ++extern void forward_interrupts(int pid); ++extern void init_irq_signals(int on_sigstack); ++extern void forward_ipi(int fd, int pid); ++extern void free_irq_later(int irq, void *dev_id); ++extern int activate_ipi(int fd, int pid); ++extern unsigned long irq_lock(void); ++extern void irq_unlock(unsigned long flags); ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/kern.h um/arch/um/include/kern.h +--- orig/arch/um/include/kern.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/kern.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __KERN_H__ ++#define __KERN_H__ ++ ++/* These are all user-mode things which are convenient to call directly ++ * from kernel code and for which writing a wrapper is too much of a pain. ++ * The regular include files can't be included because this file is included ++ * only into kernel code, and user-space includes conflict with kernel ++ * includes. ++ */ ++ ++extern int errno; ++ ++extern int clone(int (*proc)(void *), void *sp, int flags, void *data); ++extern int sleep(int); ++extern int printf(char *fmt, ...); ++extern char *strerror(int errnum); ++extern char *ptsname(int __fd); ++extern int munmap(void *, int); ++extern void *sbrk(int increment); ++extern void *malloc(int size); ++extern void perror(char *err); ++extern int kill(int pid, int sig); ++extern int getuid(void); ++extern int pause(void); ++extern int write(int, const void *, int); ++extern int exit(int); ++extern int close(int); ++extern int read(unsigned int, char *, int); ++extern int pipe(int *); ++extern int sched_yield(void); ++extern int ptrace(int op, int pid, long addr, long data); ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/kern_util.h um/arch/um/include/kern_util.h +--- orig/arch/um/include/kern_util.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/kern_util.h 2003-11-10 00:58:10.000000000 -0500 +@@ -0,0 +1,123 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __KERN_UTIL_H__ ++#define __KERN_UTIL_H__ ++ ++#include "sysdep/ptrace.h" ++ ++extern int ncpus; ++extern char *linux_prog; ++extern char *gdb_init; ++extern int kmalloc_ok; ++extern int timer_irq_inited; ++extern int jail; ++extern int nsyscalls; ++ ++#define UML_ROUND_DOWN(addr) ((void *)(((unsigned long) addr) & PAGE_MASK)) ++#define UML_ROUND_UP(addr) \ ++ UML_ROUND_DOWN(((unsigned long) addr) + PAGE_SIZE - 1) ++ ++extern int kernel_fork(unsigned long flags, int (*fn)(void *), void * arg); ++extern unsigned long stack_sp(unsigned long page); ++extern int kernel_thread_proc(void *data); ++extern void syscall_segv(int sig); ++extern int current_pid(void); ++extern unsigned long alloc_stack(int order, int atomic); ++extern int do_signal(int error); ++extern int is_stack_fault(unsigned long sp); ++extern unsigned long segv(unsigned long address, unsigned long ip, ++ int is_write, int is_user, void *sc); ++extern unsigned long handle_page_fault(unsigned long address, unsigned long ip, ++ int is_write, int is_user, ++ int *code_out); ++extern void syscall_ready(void); ++extern int segv_syscall(void); ++extern void kern_finish_exec(void *task, int new_pid, unsigned long stack); ++extern int page_size(void); ++extern int page_mask(void); ++extern int need_finish_fork(void); ++extern void free_stack(unsigned long stack, int order); ++extern void add_input_request(int op, void (*proc)(int), void *arg); ++extern int sys_execve(char *file, char **argv, char **env); ++extern char *current_cmd(void); ++extern void timer_handler(int sig, union uml_pt_regs *regs); ++extern int set_signals(int enable); ++extern void force_sigbus(void); ++extern int pid_to_processor_id(int pid); ++extern void block_signals(void); ++extern void unblock_signals(void); ++extern void deliver_signals(void *t); ++extern int next_syscall_index(int max); ++extern int next_trap_index(int max); ++extern void cpu_idle(void); ++extern void finish_fork(void); ++extern void paging_init(void); ++extern void init_flush_vm(void); ++extern void *syscall_sp(void *t); ++extern void syscall_trace(void); ++extern int hz(void); ++extern void idle_timer(void); ++extern unsigned int do_IRQ(int irq, union uml_pt_regs *regs); ++extern int external_pid(void *t); ++extern void boot_timer_handler(int sig); ++extern void interrupt_end(void); ++extern void initial_thread_cb(void (*proc)(void *), void *arg); ++extern int debugger_signal(int status, int pid); ++extern void debugger_parent_signal(int status, int pid); ++extern void child_signal(int pid, int status); ++extern int init_ptrace_proxy(int idle_pid, int startup, int stop); ++extern int init_parent_proxy(int pid); ++extern void check_stack_overflow(void *ptr); ++extern void relay_signal(int sig, union uml_pt_regs *regs); ++extern void not_implemented(void); ++extern int user_context(unsigned long sp); ++extern void timer_irq(union uml_pt_regs *regs); ++extern void unprotect_stack(unsigned long stack); ++extern void do_uml_exitcalls(void); ++extern int attach_debugger(int idle_pid, int pid, int stop); ++extern void bad_segv(unsigned long address, unsigned long ip, int is_write); ++extern int config_gdb(char *str); ++extern int remove_gdb(void); ++extern char *uml_strdup(char *string); ++extern void unprotect_kernel_mem(void); ++extern void protect_kernel_mem(void); ++extern void set_kmem_end(unsigned long); ++extern void uml_cleanup(void); ++extern void set_current(void *t); ++extern void lock_signalled_task(void *t); ++extern void IPI_handler(int cpu); ++extern int jail_setup(char *line, int *add); ++extern void *get_init_task(void); ++extern int clear_user_proc(void *buf, int size); ++extern int copy_to_user_proc(void *to, void *from, int size); ++extern int copy_from_user_proc(void *to, void *from, int size); ++extern int strlen_user_proc(char *str); ++extern void bus_handler(int sig, union uml_pt_regs *regs); ++extern void winch(int sig, union uml_pt_regs *regs); ++extern long execute_syscall(void *r); ++extern int smp_sigio_handler(void); ++extern void *get_current(void); ++extern struct task_struct *get_task(int pid, int require); ++extern void machine_halt(void); ++extern int is_syscall(unsigned long addr); ++extern void arch_switch(void); ++extern void free_irq(unsigned int, void *); ++extern int um_in_interrupt(void); ++extern int cpu(void); ++extern unsigned long long time_stamp(void); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/line.h um/arch/um/include/line.h +--- orig/arch/um/include/line.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/line.h 2003-11-07 02:25:37.000000000 -0500 +@@ -0,0 +1,103 @@ ++/* ++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __LINE_H__ ++#define __LINE_H__ ++ ++#include "linux/list.h" ++#include "linux/tqueue.h" ++#include "linux/tty.h" ++#include "asm/semaphore.h" ++#include "chan_user.h" ++#include "mconsole_kern.h" ++ ++struct line_driver { ++ char *name; ++ char *devfs_name; ++ short major; ++ short minor_start; ++ short type; ++ short subtype; ++ int read_irq; ++ char *read_irq_name; ++ int write_irq; ++ char *write_irq_name; ++ char *symlink_from; ++ char *symlink_to; ++ struct mc_device mc; ++}; ++ ++struct line { ++ char *init_str; ++ int init_pri; ++ struct list_head chan_list; ++ int valid; ++ int count; ++ struct tty_struct *tty; ++ struct semaphore sem; ++ char *buffer; ++ char *head; ++ char *tail; ++ int sigio; ++ struct tq_struct task; ++ struct line_driver *driver; ++ int have_irq; ++}; ++ ++#define LINE_INIT(str, d) \ ++ { init_str : str, \ ++ init_pri : INIT_STATIC, \ ++ chan_list : { }, \ ++ valid : 1, \ ++ count : 0, \ ++ tty : NULL, \ ++ sem : { }, \ ++ buffer : NULL, \ ++ head : NULL, \ ++ tail : NULL, \ ++ sigio : 0, \ ++ driver : d, \ ++ have_irq : 0 } ++ ++struct lines { ++ int num; ++}; ++ ++#define LINES_INIT(n) { num : n } ++ ++extern void line_close(struct line *lines, struct tty_struct *tty); ++extern int line_open(struct line *lines, struct tty_struct *tty, ++ struct chan_opts *opts); ++extern int line_setup(struct line *lines, int num, char *init, ++ int all_allowed); ++extern int line_write(struct line *line, struct tty_struct *tty, int from_user, ++ const char *buf, int len); ++extern char *add_xterm_umid(char *base); ++extern int line_setup_irq(int fd, int input, int output, void *data); ++extern void line_close_chan(struct line *line); ++extern void line_disable(struct line *line, int current_irq); ++extern void line_register_devfs(struct lines *set, ++ struct line_driver *line_driver, ++ struct tty_driver *driver, struct line *lines, ++ int nlines); ++extern void lines_init(struct line *lines, int nlines); ++extern void close_lines(struct line *lines, int nlines); ++extern int line_config(struct line *lines, int num, char *str); ++extern int line_remove(struct line *lines, int num, char *str); ++extern int line_get_config(char *dev, struct line *lines, int num, char *str, ++ int size, char **error_out); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/Makefile um/arch/um/include/Makefile +--- orig/arch/um/include/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/Makefile 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,7 @@ ++all : sc.h ++ ++sc.h : ../util/mk_sc ++ ../util/mk_sc > $@ ++ ++../util/mk_sc : ++ $(MAKE) -C ../util mk_sc +diff -Naur -X ../exclude-files orig/arch/um/include/mconsole.h um/arch/um/include/mconsole.h +--- orig/arch/um/include/mconsole.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/mconsole.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,103 @@ ++/* ++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) ++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __MCONSOLE_H__ ++#define __MCONSOLE_H__ ++ ++#ifndef __KERNEL__ ++#include <stdint.h> ++#define u32 uint32_t ++#endif ++ ++#define MCONSOLE_MAGIC (0xcafebabe) ++#define MCONSOLE_MAX_DATA (512) ++#define MCONSOLE_VERSION 2 ++ ++struct mconsole_request { ++ u32 magic; ++ u32 version; ++ u32 len; ++ char data[MCONSOLE_MAX_DATA]; ++}; ++ ++struct mconsole_reply { ++ u32 err; ++ u32 more; ++ u32 len; ++ char data[MCONSOLE_MAX_DATA]; ++}; ++ ++struct mconsole_notify { ++ u32 magic; ++ u32 version; ++ enum { MCONSOLE_SOCKET, MCONSOLE_PANIC, MCONSOLE_HANG, ++ MCONSOLE_USER_NOTIFY } type; ++ u32 len; ++ char data[MCONSOLE_MAX_DATA]; ++}; ++ ++struct mc_request; ++ ++enum mc_context { MCONSOLE_INTR, MCONSOLE_PROC }; ++ ++struct mconsole_command ++{ ++ char *command; ++ void (*handler)(struct mc_request *req); ++ enum mc_context context; ++}; ++ ++struct mc_request ++{ ++ int len; ++ int as_interrupt; ++ ++ int originating_fd; ++ int originlen; ++ unsigned char origin[128]; /* sockaddr_un */ ++ ++ struct mconsole_request request; ++ struct mconsole_command *cmd; ++}; ++ ++extern char mconsole_socket_name[]; ++ ++extern int mconsole_unlink_socket(void); ++extern int mconsole_reply(struct mc_request *req, char *reply, int err, ++ int more); ++ ++extern void mconsole_version(struct mc_request *req); ++extern void mconsole_help(struct mc_request *req); ++extern void mconsole_halt(struct mc_request *req); ++extern void mconsole_reboot(struct mc_request *req); ++extern void mconsole_config(struct mc_request *req); ++extern void mconsole_remove(struct mc_request *req); ++extern void mconsole_sysrq(struct mc_request *req); ++extern void mconsole_cad(struct mc_request *req); ++extern void mconsole_stop(struct mc_request *req); ++extern void mconsole_go(struct mc_request *req); ++extern void mconsole_log(struct mc_request *req); ++extern void mconsole_proc(struct mc_request *req); ++ ++extern int mconsole_get_request(int fd, struct mc_request *req); ++extern int mconsole_notify(char *sock_name, int type, const void *data, ++ int len); ++extern char *mconsole_notify_socket(void); ++extern void lock_notify(void); ++extern void unlock_notify(void); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/mconsole_kern.h um/arch/um/include/mconsole_kern.h +--- orig/arch/um/include/mconsole_kern.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/mconsole_kern.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,62 @@ ++/* ++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __MCONSOLE_KERN_H__ ++#define __MCONSOLE_KERN_H__ ++ ++#include "linux/config.h" ++#include "linux/list.h" ++#include "mconsole.h" ++ ++struct mconsole_entry { ++ struct list_head list; ++ struct mc_request request; ++}; ++ ++struct mc_device { ++ struct list_head list; ++ char *name; ++ int (*config)(char *); ++ int (*get_config)(char *, char *, int, char **); ++ int (*remove)(char *); ++}; ++ ++#define CONFIG_CHUNK(str, size, current, chunk, end) \ ++do { \ ++ current += strlen(chunk); \ ++ if(current >= size) \ ++ str = NULL; \ ++ if(str != NULL){ \ ++ strcpy(str, chunk); \ ++ str += strlen(chunk); \ ++ } \ ++ if(end) \ ++ current++; \ ++} while(0) ++ ++#ifdef CONFIG_MCONSOLE ++ ++extern void mconsole_register_dev(struct mc_device *new); ++ ++#else ++ ++static inline void mconsole_register_dev(struct mc_device *new) ++{ ++} ++ ++#endif ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/mem.h um/arch/um/include/mem.h +--- orig/arch/um/include/mem.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/mem.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (C) 2002, 2003 Jeff Dike (jdike@addtoit.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __MEM_H__ ++#define __MEM_H__ ++ ++#include "linux/types.h" ++ ++extern void set_kmem_end(unsigned long new); ++extern int phys_mapping(unsigned long phys, __u64 *offset_out); ++extern int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w); ++extern int is_remapped(void *virt); ++extern int physmem_remove_mapping(void *virt); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/mem_kern.h um/arch/um/include/mem_kern.h +--- orig/arch/um/include/mem_kern.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/mem_kern.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (C) 2003 Jeff Dike (jdike@addtoit.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __MEM_KERN_H__ ++#define __MEM_KERN_H__ ++ ++#include "linux/list.h" ++#include "linux/types.h" ++ ++struct remapper { ++ struct list_head list; ++ int (*proc)(int, unsigned long, int, __u64); ++}; ++ ++extern void register_remapper(struct remapper *info); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/mem_user.h um/arch/um/include/mem_user.h +--- orig/arch/um/include/mem_user.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/mem_user.h 2003-12-14 11:16:03.000000000 -0500 +@@ -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 void check_devanon(void); ++extern int init_mem_user(void); ++extern int create_mem_file(unsigned long len); ++extern void setup_memory(void *entry); ++extern unsigned long find_iomem(char *driver, unsigned long *len_out); ++extern int init_maps(unsigned long physmem, unsigned long iomem, ++ unsigned long highmem); ++extern unsigned long get_vm(unsigned long len); ++extern void setup_physmem(unsigned long start, unsigned long usable, ++ unsigned long len, unsigned long highmem); ++extern void add_iomem(char *name, int fd, unsigned long size); ++extern unsigned long phys_offset(unsigned long phys); ++extern void unmap_physmem(void); ++extern void map_memory(unsigned long virt, unsigned long phys, ++ unsigned long len, int r, int w, int x); ++extern int protect_memory(unsigned long addr, unsigned long len, ++ int r, int w, int x, int must_succeed); ++extern unsigned long get_kmem_end(void); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/mode.h um/arch/um/include/mode.h +--- orig/arch/um/include/mode.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/mode.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __MODE_H__ ++#define __MODE_H__ ++ ++#include "uml-config.h" ++ ++#ifdef UML_CONFIG_MODE_TT ++#include "../kernel/tt/include/mode.h" ++#endif ++ ++#ifdef UML_CONFIG_MODE_SKAS ++#include "../kernel/skas/include/mode.h" ++#endif ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/mode_kern.h um/arch/um/include/mode_kern.h +--- orig/arch/um/include/mode_kern.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/mode_kern.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __MODE_KERN_H__ ++#define __MODE_KERN_H__ ++ ++#include "linux/config.h" ++ ++#ifdef CONFIG_MODE_TT ++#include "../kernel/tt/include/mode_kern.h" ++#endif ++ ++#ifdef CONFIG_MODE_SKAS ++#include "../kernel/skas/include/mode_kern.h" ++#endif ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/net_kern.h um/arch/um/include/net_kern.h +--- orig/arch/um/include/net_kern.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/net_kern.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,81 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UM_NET_KERN_H ++#define __UM_NET_KERN_H ++ ++#include "linux/netdevice.h" ++#include "linux/skbuff.h" ++#include "linux/socket.h" ++#include "linux/list.h" ++ ++struct uml_net { ++ struct list_head list; ++ struct net_device *dev; ++ int index; ++ unsigned char mac[ETH_ALEN]; ++ int have_mac; ++}; ++ ++struct uml_net_private { ++ struct list_head list; ++ spinlock_t lock; ++ struct net_device *dev; ++ struct timer_list tl; ++ struct net_device_stats stats; ++ int fd; ++ unsigned char mac[ETH_ALEN]; ++ int have_mac; ++ unsigned short (*protocol)(struct sk_buff *); ++ int (*open)(void *); ++ void (*close)(int, void *); ++ void (*remove)(void *); ++ int (*read)(int, struct sk_buff **skb, struct uml_net_private *); ++ int (*write)(int, struct sk_buff **skb, struct uml_net_private *); ++ ++ void (*add_address)(unsigned char *, unsigned char *, void *); ++ void (*delete_address)(unsigned char *, unsigned char *, void *); ++ int (*set_mtu)(int mtu, void *); ++ int user[1]; ++}; ++ ++struct net_kern_info { ++ void (*init)(struct net_device *, void *); ++ unsigned short (*protocol)(struct sk_buff *); ++ int (*read)(int, struct sk_buff **skb, struct uml_net_private *); ++ int (*write)(int, struct sk_buff **skb, struct uml_net_private *); ++}; ++ ++struct transport { ++ struct list_head list; ++ char *name; ++ int (*setup)(char *, char **, void *); ++ struct net_user_info *user; ++ struct net_kern_info *kern; ++ int private_size; ++ int setup_size; ++}; ++ ++extern struct net_device *ether_init(int); ++extern unsigned short ether_protocol(struct sk_buff *); ++extern int setup_etheraddr(char *str, unsigned char *addr); ++extern struct sk_buff *ether_adjust_skb(struct sk_buff *skb, int extra); ++extern int tap_setup_common(char *str, char *type, char **dev_name, ++ char **mac_out, char **gate_addr); ++extern void register_transport(struct transport *new); ++extern unsigned short eth_protocol(struct sk_buff *skb); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/net_user.h um/arch/um/include/net_user.h +--- orig/arch/um/include/net_user.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/net_user.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,66 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UM_NET_USER_H__ ++#define __UM_NET_USER_H__ ++ ++#define ETH_ADDR_LEN (6) ++#define ETH_HEADER_ETHERTAP (16) ++#define ETH_HEADER_OTHER (14) ++#define ETH_MAX_PACKET (1500) ++ ++#define UML_NET_VERSION (4) ++ ++struct net_user_info { ++ void (*init)(void *, void *); ++ int (*open)(void *); ++ void (*close)(int, void *); ++ void (*remove)(void *); ++ int (*set_mtu)(int mtu, void *); ++ void (*add_address)(unsigned char *, unsigned char *, void *); ++ void (*delete_address)(unsigned char *, unsigned char *, void *); ++ int max_packet; ++}; ++ ++extern void ether_user_init(void *data, void *dev); ++extern void dev_ip_addr(void *d, char *buf, char *bin_buf); ++extern void set_ether_mac(void *d, unsigned char *addr); ++extern void iter_addresses(void *d, void (*cb)(unsigned char *, ++ unsigned char *, void *), ++ void *arg); ++ ++extern void *get_output_buffer(int *len_out); ++extern void free_output_buffer(void *buffer); ++ ++extern int tap_open_common(void *dev, char *gate_addr); ++extern void tap_check_ips(char *gate_addr, char *eth_addr); ++ ++extern void read_output(int fd, char *output_out, int len); ++ ++extern int net_read(int fd, void *buf, int len); ++extern int net_recvfrom(int fd, void *buf, int len); ++extern int net_write(int fd, void *buf, int len); ++extern int net_send(int fd, void *buf, int len); ++extern int net_sendto(int fd, void *buf, int len, void *to, int sock_len); ++ ++extern void open_addr(unsigned char *addr, unsigned char *netmask, void *arg); ++extern void close_addr(unsigned char *addr, unsigned char *netmask, void *arg); ++ ++extern char *split_if_spec(char *str, ...); ++ ++extern int dev_netmask(void *d, void *m); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/os.h um/arch/um/include/os.h +--- orig/arch/um/include/os.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/os.h 2003-12-17 10:48:12.000000000 -0500 +@@ -0,0 +1,180 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __OS_H__ ++#define __OS_H__ ++ ++#include "asm/types.h" ++#include "../os/include/file.h" ++ ++#define OS_TYPE_FILE 1 ++#define OS_TYPE_DIR 2 ++#define OS_TYPE_SYMLINK 3 ++#define OS_TYPE_CHARDEV 4 ++#define OS_TYPE_BLOCKDEV 5 ++#define OS_TYPE_FIFO 6 ++#define OS_TYPE_SOCK 7 ++ ++/* os_access() flags */ ++#define OS_ACC_F_OK 0 /* Test for existence. */ ++#define OS_ACC_X_OK 1 /* Test for execute permission. */ ++#define OS_ACC_W_OK 2 /* Test for write permission. */ ++#define OS_ACC_R_OK 4 /* Test for read permission. */ ++#define OS_ACC_RW_OK (OS_ACC_W_OK | OS_ACC_R_OK) /* Test for RW permission */ ++ ++/* ++ * types taken from stat_file() in hostfs_user.c ++ * (if they are wrong here, they are wrong there...). ++ */ ++struct uml_stat { ++ int ust_dev; /* device */ ++ unsigned long long ust_ino; /* inode */ ++ int ust_mode; /* protection */ ++ int ust_nlink; /* number of hard links */ ++ int ust_uid; /* user ID of owner */ ++ int ust_gid; /* group ID of owner */ ++ unsigned long long ust_size; /* total size, in bytes */ ++ int ust_blksize; /* blocksize for filesystem I/O */ ++ unsigned long long ust_blocks; /* number of blocks allocated */ ++ unsigned long ust_atime; /* time of last access */ ++ unsigned long ust_mtime; /* time of last modification */ ++ unsigned long ust_ctime; /* time of last change */ ++}; ++ ++struct openflags { ++ unsigned int r : 1; ++ unsigned int w : 1; ++ unsigned int s : 1; /* O_SYNC */ ++ unsigned int c : 1; /* O_CREAT */ ++ unsigned int t : 1; /* O_TRUNC */ ++ unsigned int a : 1; /* O_APPEND */ ++ unsigned int e : 1; /* O_EXCL */ ++ unsigned int cl : 1; /* FD_CLOEXEC */ ++}; ++ ++#define OPENFLAGS() ((struct openflags) { .r = 0, .w = 0, .s = 0, .c = 0, \ ++ .t = 0, .a = 0, .e = 0, .cl = 0 }) ++ ++static inline struct openflags of_read(struct openflags flags) ++{ ++ flags.r = 1; ++ return(flags); ++} ++ ++static inline struct openflags of_write(struct openflags flags) ++{ ++ flags.w = 1; ++ return(flags); ++} ++ ++static inline struct openflags of_rdwr(struct openflags flags) ++{ ++ return(of_read(of_write(flags))); ++} ++ ++static inline struct openflags of_set_rw(struct openflags flags, int r, int w) ++{ ++ flags.r = r; ++ flags.w = w; ++ return(flags); ++} ++ ++static inline struct openflags of_sync(struct openflags flags) ++{ ++ flags.s = 1; ++ return(flags); ++} ++ ++static inline struct openflags of_create(struct openflags flags) ++{ ++ flags.c = 1; ++ return(flags); ++} ++ ++static inline struct openflags of_trunc(struct openflags flags) ++{ ++ flags.t = 1; ++ return(flags); ++} ++ ++static inline struct openflags of_append(struct openflags flags) ++{ ++ flags.a = 1; ++ return(flags); ++} ++ ++static inline struct openflags of_excl(struct openflags flags) ++{ ++ flags.e = 1; ++ return(flags); ++} ++ ++static inline struct openflags of_cloexec(struct openflags flags) ++{ ++ flags.cl = 1; ++ return(flags); ++} ++ ++extern int os_stat_file(const char *file_name, struct uml_stat *buf); ++extern int os_stat_fd(const int fd, struct uml_stat *buf); ++extern int os_access(const char *file, int mode); ++extern void os_print_error(int error, const char* str); ++extern int os_get_exec_close(int fd, int *close_on_exec); ++extern int os_set_exec_close(int fd, int close_on_exec); ++extern int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg); ++extern int os_window_size(int fd, int *rows, int *cols); ++extern int os_new_tty_pgrp(int fd, int pid); ++extern int os_get_ifname(int fd, char *namebuf); ++extern int os_set_slip(int fd); ++extern int os_set_owner(int fd, int pid); ++extern int os_sigio_async(int master, int slave); ++extern int os_mode_fd(int fd, int mode); ++ ++extern int os_seek_file(int fd, __u64 offset); ++extern int os_open_file(char *file, struct openflags flags, int mode); ++extern int os_read_file(int fd, void *buf, int len); ++extern int os_write_file(int fd, const void *buf, int count); ++extern int os_file_size(char *file, long long *size_out); ++extern int os_file_modtime(char *file, unsigned long *modtime); ++extern int os_pipe(int *fd, int stream, int close_on_exec); ++extern int os_set_fd_async(int fd, int owner); ++extern int os_set_fd_block(int fd, int blocking); ++extern int os_accept_connection(int fd); ++extern int os_create_unix_socket(char *file, int len, int close_on_exec); ++extern int os_shutdown_socket(int fd, int r, int w); ++extern void os_close_file(int fd); ++extern int os_rcv_fd(int fd, int *helper_pid_out); ++extern int create_unix_socket(char *file, int len, int close_on_exec); ++extern int os_connect_socket(char *name); ++extern int os_file_type(char *file); ++extern int os_file_mode(char *file, struct openflags *mode_out); ++extern int os_lock_file(int fd, int excl); ++ ++extern unsigned long os_process_pc(int pid); ++extern int os_process_parent(int pid); ++extern void os_stop_process(int pid); ++extern void os_kill_process(int pid, int reap_child); ++extern void os_usr1_process(int pid); ++extern int os_getpid(void); ++ ++extern int os_map_memory(void *virt, int fd, unsigned long long off, ++ unsigned long len, int r, int w, int x); ++extern int os_protect_memory(void *addr, unsigned long len, ++ int r, int w, int x); ++extern int os_unmap_memory(void *addr, int len); ++extern void os_flush_stdout(void); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/process.h um/arch/um/include/process.h +--- orig/arch/um/include/process.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/process.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,25 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __PROCESS_H__ ++#define __PROCESS_H__ ++ ++#include <asm/sigcontext.h> ++ ++extern void sig_handler(int sig, struct sigcontext sc); ++extern void alarm_handler(int sig, struct sigcontext sc); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/ptrace_user.h um/arch/um/include/ptrace_user.h +--- orig/arch/um/include/ptrace_user.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/ptrace_user.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,18 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __PTRACE_USER_H__ ++#define __PTRACE_USER_H__ ++ ++#include "sysdep/ptrace_user.h" ++ ++extern int ptrace_getregs(long pid, unsigned long *regs_out); ++extern int ptrace_setregs(long pid, unsigned long *regs_in); ++extern int ptrace_getfpregs(long pid, unsigned long *regs_out); ++extern void arch_enter_kernel(void *task, int pid); ++extern void arch_leave_kernel(void *task, int pid); ++extern void ptrace_pokeuser(unsigned long addr, unsigned long data); ++ ++#endif +diff -Naur -X ../exclude-files orig/arch/um/include/sigcontext.h um/arch/um/include/sigcontext.h +--- orig/arch/um/include/sigcontext.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/sigcontext.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,25 @@ ++/* ++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UML_SIGCONTEXT_H__ ++#define __UML_SIGCONTEXT_H__ ++ ++#include "sysdep/sigcontext.h" ++ ++extern int sc_size(void *data); ++extern void sc_to_sc(void *to_ptr, void *from_ptr); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/sigio.h um/arch/um/include/sigio.h +--- orig/arch/um/include/sigio.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/sigio.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __SIGIO_H__ ++#define __SIGIO_H__ ++ ++extern int write_sigio_irq(int fd); ++extern int register_sigio_fd(int fd); ++extern int read_sigio_fd(int fd); ++extern int add_sigio_fd(int fd, int read); ++extern int ignore_sigio_fd(int fd); ++extern void sigio_lock(void); ++extern void sigio_unlock(void); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/signal_kern.h um/arch/um/include/signal_kern.h +--- orig/arch/um/include/signal_kern.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/signal_kern.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,22 @@ ++/* ++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __SIGNAL_KERN_H__ ++#define __SIGNAL_KERN_H__ ++ ++extern int have_signals(void *t); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/signal_user.h um/arch/um/include/signal_user.h +--- orig/arch/um/include/signal_user.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/signal_user.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,26 @@ ++/* ++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __SIGNAL_USER_H__ ++#define __SIGNAL_USER_H__ ++ ++extern int signal_stack_size; ++ ++extern int change_sig(int signal, int on); ++extern void set_sigstack(void *stack, int size); ++extern void set_handler(int sig, void (*handler)(int), int flags, ...); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/skas_ptrace.h um/arch/um/include/skas_ptrace.h +--- orig/arch/um/include/skas_ptrace.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/skas_ptrace.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,36 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __SKAS_PTRACE_H ++#define __SKAS_PTRACE_H ++ ++struct ptrace_faultinfo { ++ int is_write; ++ unsigned long addr; ++}; ++ ++struct ptrace_ldt { ++ int func; ++ void *ptr; ++ unsigned long bytecount; ++}; ++ ++#define PTRACE_FAULTINFO 52 ++#define PTRACE_SIGPENDING 53 ++#define PTRACE_LDT 54 ++#define PTRACE_SWITCH_MM 55 ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/syscall_user.h um/arch/um/include/syscall_user.h +--- orig/arch/um/include/syscall_user.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/syscall_user.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,23 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __SYSCALL_USER_H ++#define __SYSCALL_USER_H ++ ++extern int record_syscall_start(int syscall); ++extern void record_syscall_end(int index, int result); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-i386/checksum.h um/arch/um/include/sysdep-i386/checksum.h +--- orig/arch/um/include/sysdep-i386/checksum.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/sysdep-i386/checksum.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,217 @@ ++/* ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UM_SYSDEP_CHECKSUM_H ++#define __UM_SYSDEP_CHECKSUM_H ++ ++#include "linux/string.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 exeption occurs. ++ * ++ * these functions should go away after some time. ++ */ ++ ++#define csum_partial_copy_fromuser csum_partial_copy_from_user ++unsigned int csum_partial_copy( const char *src, char *dst, int len, int sum); ++ ++/* ++ * This is a version of ip_compute_csum() optimized for IP headers, ++ * which always checksum on 4 octet boundaries. ++ * ++ * By Jorge Cwik <jorge@laser.satlink.net>, adapted for linux by ++ * Arnt Gulbrandsen. ++ */ ++static inline unsigned short ip_fast_csum(unsigned char * iph, ++ unsigned int ihl) ++{ ++ unsigned int sum; ++ ++ __asm__ __volatile__( ++ "movl (%1), %0 ;\n" ++ "subl $4, %2 ;\n" ++ "jbe 2f ;\n" ++ "addl 4(%1), %0 ;\n" ++ "adcl 8(%1), %0 ;\n" ++ "adcl 12(%1), %0 ;\n" ++"1: adcl 16(%1), %0 ;\n" ++ "lea 4(%1), %1 ;\n" ++ "decl %2 ;\n" ++ "jne 1b ;\n" ++ "adcl $0, %0 ;\n" ++ "movl %0, %2 ;\n" ++ "shrl $16, %0 ;\n" ++ "addw %w2, %w0 ;\n" ++ "adcl $0, %0 ;\n" ++ "notl %0 ;\n" ++"2: ;\n" ++ /* Since the input registers which are loaded with iph and ipl ++ are modified, we must also specify them as outputs, or gcc ++ will assume they contain their original values. */ ++ : "=r" (sum), "=r" (iph), "=r" (ihl) ++ : "1" (iph), "2" (ihl)); ++ return(sum); ++} ++ ++/* ++ * Fold a partial checksum ++ */ ++ ++static inline unsigned int csum_fold(unsigned int sum) ++{ ++ __asm__( ++ "addl %1, %0 ;\n" ++ "adcl $0xffff, %0 ;\n" ++ : "=r" (sum) ++ : "r" (sum << 16), "0" (sum & 0xffff0000) ++ ); ++ return (~sum) >> 16; ++} ++ ++static inline unsigned long csum_tcpudp_nofold(unsigned long saddr, ++ unsigned long daddr, ++ unsigned short len, ++ unsigned short proto, ++ unsigned int sum) ++{ ++ __asm__( ++ "addl %1, %0 ;\n" ++ "adcl %2, %0 ;\n" ++ "adcl %3, %0 ;\n" ++ "adcl $0, %0 ;\n" ++ : "=r" (sum) ++ : "g" (daddr), "g"(saddr), "g"((ntohs(len)<<16)+proto*256), "0"(sum)); ++ return sum; ++} ++ ++/* ++ * computes the checksum of the TCP/UDP pseudo-header ++ * returns a 16-bit checksum, already complemented ++ */ ++static inline unsigned short int csum_tcpudp_magic(unsigned long saddr, ++ unsigned long daddr, ++ unsigned short len, ++ unsigned short proto, ++ unsigned int sum) ++{ ++ return csum_fold(csum_tcpudp_nofold(saddr,daddr,len,proto,sum)); ++} ++ ++/* ++ * this routine is used for miscellaneous IP-like checksums, mainly ++ * in icmp.c ++ */ ++ ++static inline unsigned short ip_compute_csum(unsigned char * buff, int len) ++{ ++ return csum_fold (csum_partial(buff, len, 0)); ++} ++ ++#define _HAVE_ARCH_IPV6_CSUM ++static __inline__ unsigned short int csum_ipv6_magic(struct in6_addr *saddr, ++ struct in6_addr *daddr, ++ __u32 len, ++ unsigned short proto, ++ unsigned int sum) ++{ ++ __asm__( ++ "addl 0(%1), %0 ;\n" ++ "adcl 4(%1), %0 ;\n" ++ "adcl 8(%1), %0 ;\n" ++ "adcl 12(%1), %0 ;\n" ++ "adcl 0(%2), %0 ;\n" ++ "adcl 4(%2), %0 ;\n" ++ "adcl 8(%2), %0 ;\n" ++ "adcl 12(%2), %0 ;\n" ++ "adcl %3, %0 ;\n" ++ "adcl %4, %0 ;\n" ++ "adcl $0, %0 ;\n" ++ : "=&r" (sum) ++ : "r" (saddr), "r" (daddr), ++ "r"(htonl(len)), "r"(htonl(proto)), "0"(sum)); ++ ++ return csum_fold(sum); ++} ++ ++/* ++ * Copy and checksum to user ++ */ ++#define HAVE_CSUM_COPY_USER ++static __inline__ unsigned int csum_and_copy_to_user(const char *src, ++ char *dst, int len, ++ int sum, int *err_ptr) ++{ ++ if (access_ok(VERIFY_WRITE, dst, len)) ++ return(csum_partial_copy_to(src, dst, len, sum, err_ptr)); ++ ++ if (len) ++ *err_ptr = -EFAULT; ++ ++ return -1; /* invalid checksum */ ++} ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-i386/frame.h um/arch/um/include/sysdep-i386/frame.h +--- orig/arch/um/include/sysdep-i386/frame.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/sysdep-i386/frame.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,29 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __FRAME_I386_H ++#define __FRAME_I386_H ++ ++struct arch_frame_data_raw { ++ unsigned long fp_start; ++ unsigned long sr; ++}; ++ ++struct arch_frame_data { ++ int fpstate_size; ++}; ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-i386/frame_kern.h um/arch/um/include/sysdep-i386/frame_kern.h +--- orig/arch/um/include/sysdep-i386/frame_kern.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/sysdep-i386/frame_kern.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,69 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __FRAME_KERN_I386_H ++#define __FRAME_KERN_I386_H ++ ++/* This is called from sys_sigreturn. It takes the sp at the point of the ++ * sigreturn system call and returns the address of the sigcontext struct ++ * on the stack. ++ */ ++ ++static inline void *sp_to_sc(unsigned long sp) ++{ ++ return((void *) sp); ++} ++ ++static inline void *sp_to_uc(unsigned long sp) ++{ ++ unsigned long uc; ++ ++ uc = sp + signal_frame_si.uc_index - ++ signal_frame_si.common.sp_index - 4; ++ return((void *) uc); ++} ++ ++static inline void *sp_to_rt_sc(unsigned long sp) ++{ ++ unsigned long sc; ++ ++ sc = sp - signal_frame_si.common.sp_index + ++ signal_frame_si.common.len - 4; ++ return((void *) sc); ++} ++ ++static inline void *sp_to_mask(unsigned long sp) ++{ ++ unsigned long mask; ++ ++ mask = sp - signal_frame_sc.common.sp_index + ++ signal_frame_sc.common.len - 8; ++ return((void *) mask); ++} ++ ++extern int sc_size(void *data); ++ ++static inline void *sp_to_rt_mask(unsigned long sp) ++{ ++ unsigned long mask; ++ ++ mask = sp - signal_frame_si.common.sp_index + ++ signal_frame_si.common.len + ++ sc_size(&signal_frame_si.common.arch) - 4; ++ return((void *) mask); ++} ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-i386/frame_user.h um/arch/um/include/sysdep-i386/frame_user.h +--- orig/arch/um/include/sysdep-i386/frame_user.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/sysdep-i386/frame_user.h 2003-10-21 03:26:06.000000000 -0400 +@@ -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). ++ */ ++ ++static inline unsigned long frame_restorer(void) ++{ ++ unsigned long *fp; ++ ++ fp = __builtin_frame_address(0); ++ return((unsigned long) (fp + 1)); ++} ++ ++/* Similarly, this returns the value of sp when the handler was first ++ * entered. This is used to calculate the proper sp when delivering ++ * signals. ++ */ ++ ++static inline unsigned long frame_sp(void) ++{ ++ unsigned long *fp; ++ ++ fp = __builtin_frame_address(0); ++ return((unsigned long) (fp + 1)); ++} ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-i386/ptrace.h um/arch/um/include/sysdep-i386/ptrace.h +--- orig/arch/um/include/sysdep-i386/ptrace.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/sysdep-i386/ptrace.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,193 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __SYSDEP_I386_PTRACE_H ++#define __SYSDEP_I386_PTRACE_H ++ ++#include "uml-config.h" ++ ++#ifdef UML_CONFIG_MODE_TT ++#include "ptrace-tt.h" ++#endif ++ ++#ifdef UML_CONFIG_MODE_SKAS ++#include "ptrace-skas.h" ++#endif ++ ++#include "choose-mode.h" ++ ++union uml_pt_regs { ++#ifdef UML_CONFIG_MODE_TT ++ struct tt_regs { ++ long syscall; ++ void *sc; ++ } tt; ++#endif ++#ifdef UML_CONFIG_MODE_SKAS ++ struct skas_regs { ++ unsigned long regs[HOST_FRAME_SIZE]; ++ unsigned long fp[HOST_FP_SIZE]; ++ unsigned long xfp[HOST_XFP_SIZE]; ++ unsigned long fault_addr; ++ unsigned long fault_type; ++ unsigned long trap_type; ++ long syscall; ++ int is_user; ++ } skas; ++#endif ++}; ++ ++#define EMPTY_UML_PT_REGS { } ++ ++extern int mode_tt; ++ ++#define UPT_SC(r) ((r)->tt.sc) ++#define UPT_IP(r) \ ++ CHOOSE_MODE(SC_IP(UPT_SC(r)), REGS_IP((r)->skas.regs)) ++#define UPT_SP(r) \ ++ CHOOSE_MODE(SC_SP(UPT_SC(r)), REGS_SP((r)->skas.regs)) ++#define UPT_EFLAGS(r) \ ++ CHOOSE_MODE(SC_EFLAGS(UPT_SC(r)), REGS_EFLAGS((r)->skas.regs)) ++#define UPT_EAX(r) \ ++ CHOOSE_MODE(SC_EAX(UPT_SC(r)), REGS_EAX((r)->skas.regs)) ++#define UPT_EBX(r) \ ++ CHOOSE_MODE(SC_EBX(UPT_SC(r)), REGS_EBX((r)->skas.regs)) ++#define UPT_ECX(r) \ ++ CHOOSE_MODE(SC_ECX(UPT_SC(r)), REGS_ECX((r)->skas.regs)) ++#define UPT_EDX(r) \ ++ CHOOSE_MODE(SC_EDX(UPT_SC(r)), REGS_EDX((r)->skas.regs)) ++#define UPT_ESI(r) \ ++ CHOOSE_MODE(SC_ESI(UPT_SC(r)), REGS_ESI((r)->skas.regs)) ++#define UPT_EDI(r) \ ++ CHOOSE_MODE(SC_EDI(UPT_SC(r)), REGS_EDI((r)->skas.regs)) ++#define UPT_EBP(r) \ ++ CHOOSE_MODE(SC_EBP(UPT_SC(r)), REGS_EBP((r)->skas.regs)) ++#define UPT_ORIG_EAX(r) \ ++ CHOOSE_MODE((r)->tt.syscall, (r)->skas.syscall) ++#define UPT_CS(r) \ ++ CHOOSE_MODE(SC_CS(UPT_SC(r)), REGS_CS((r)->skas.regs)) ++#define UPT_SS(r) \ ++ CHOOSE_MODE(SC_SS(UPT_SC(r)), REGS_SS((r)->skas.regs)) ++#define UPT_DS(r) \ ++ CHOOSE_MODE(SC_DS(UPT_SC(r)), REGS_DS((r)->skas.regs)) ++#define UPT_ES(r) \ ++ CHOOSE_MODE(SC_ES(UPT_SC(r)), REGS_ES((r)->skas.regs)) ++#define UPT_FS(r) \ ++ CHOOSE_MODE(SC_FS(UPT_SC(r)), REGS_FS((r)->skas.regs)) ++#define UPT_GS(r) \ ++ CHOOSE_MODE(SC_GS(UPT_SC(r)), REGS_GS((r)->skas.regs)) ++ ++#define UPT_SYSCALL_ARG1(r) UPT_EBX(r) ++#define UPT_SYSCALL_ARG2(r) UPT_ECX(r) ++#define UPT_SYSCALL_ARG3(r) UPT_EDX(r) ++#define UPT_SYSCALL_ARG4(r) UPT_ESI(r) ++#define UPT_SYSCALL_ARG5(r) UPT_EDI(r) ++#define UPT_SYSCALL_ARG6(r) UPT_EBP(r) ++ ++extern int user_context(unsigned long sp); ++ ++#define UPT_IS_USER(r) \ ++ CHOOSE_MODE(user_context(UPT_SP(r)), (r)->skas.is_user) ++ ++struct syscall_args { ++ unsigned long args[6]; ++}; ++ ++#define SYSCALL_ARGS(r) ((struct syscall_args) \ ++ { .args = { UPT_SYSCALL_ARG1(r), \ ++ UPT_SYSCALL_ARG2(r), \ ++ UPT_SYSCALL_ARG3(r), \ ++ UPT_SYSCALL_ARG4(r), \ ++ UPT_SYSCALL_ARG5(r), \ ++ UPT_SYSCALL_ARG6(r) } } ) ++ ++#define UPT_REG(regs, reg) \ ++ ({ unsigned long val; \ ++ switch(reg){ \ ++ case EIP: val = UPT_IP(regs); break; \ ++ case UESP: val = UPT_SP(regs); break; \ ++ case EAX: val = UPT_EAX(regs); break; \ ++ case EBX: val = UPT_EBX(regs); break; \ ++ case ECX: val = UPT_ECX(regs); break; \ ++ case EDX: val = UPT_EDX(regs); break; \ ++ case ESI: val = UPT_ESI(regs); break; \ ++ case EDI: val = UPT_EDI(regs); break; \ ++ case EBP: val = UPT_EBP(regs); break; \ ++ case ORIG_EAX: val = UPT_ORIG_EAX(regs); break; \ ++ case CS: val = UPT_CS(regs); break; \ ++ case SS: val = UPT_SS(regs); break; \ ++ case DS: val = UPT_DS(regs); break; \ ++ case ES: val = UPT_ES(regs); break; \ ++ case FS: val = UPT_FS(regs); break; \ ++ case GS: val = UPT_GS(regs); break; \ ++ case EFL: val = UPT_EFLAGS(regs); break; \ ++ default : \ ++ panic("Bad register in UPT_REG : %d\n", reg); \ ++ val = -1; \ ++ } \ ++ val; \ ++ }) ++ ++ ++#define UPT_SET(regs, reg, val) \ ++ do { \ ++ switch(reg){ \ ++ case EIP: UPT_IP(regs) = val; break; \ ++ case UESP: UPT_SP(regs) = val; break; \ ++ case EAX: UPT_EAX(regs) = val; break; \ ++ case EBX: UPT_EBX(regs) = val; break; \ ++ case ECX: UPT_ECX(regs) = val; break; \ ++ case EDX: UPT_EDX(regs) = val; break; \ ++ case ESI: UPT_ESI(regs) = val; break; \ ++ case EDI: UPT_EDI(regs) = val; break; \ ++ case EBP: UPT_EBP(regs) = val; break; \ ++ case ORIG_EAX: UPT_ORIG_EAX(regs) = val; break; \ ++ case CS: UPT_CS(regs) = val; break; \ ++ case SS: UPT_SS(regs) = val; break; \ ++ case DS: UPT_DS(regs) = val; break; \ ++ case ES: UPT_ES(regs) = val; break; \ ++ case FS: UPT_FS(regs) = val; break; \ ++ case GS: UPT_GS(regs) = val; break; \ ++ case EFL: UPT_EFLAGS(regs) = val; break; \ ++ default : \ ++ panic("Bad register in UPT_SET : %d\n", reg); \ ++ break; \ ++ } \ ++ } while (0) ++ ++#define UPT_SET_SYSCALL_RETURN(r, res) \ ++ CHOOSE_MODE(SC_SET_SYSCALL_RETURN(UPT_SC(r), (res)), \ ++ REGS_SET_SYSCALL_RETURN((r)->skas.regs, (res))) ++ ++#define UPT_RESTART_SYSCALL(r) \ ++ CHOOSE_MODE(SC_RESTART_SYSCALL(UPT_SC(r)), \ ++ REGS_RESTART_SYSCALL((r)->skas.regs)) ++ ++#define UPT_ORIG_SYSCALL(r) UPT_EAX(r) ++#define UPT_SYSCALL_NR(r) UPT_ORIG_EAX(r) ++#define UPT_SYSCALL_RET(r) UPT_EAX(r) ++ ++#define UPT_SEGV_IS_FIXABLE(r) \ ++ CHOOSE_MODE(SC_SEGV_IS_FIXABLE(UPT_SC(r)), \ ++ REGS_SEGV_IS_FIXABLE(&r->skas)) ++ ++#define UPT_FAULT_ADDR(r) \ ++ CHOOSE_MODE(SC_FAULT_ADDR(UPT_SC(r)), REGS_FAULT_ADDR(&r->skas)) ++ ++#define UPT_FAULT_WRITE(r) \ ++ CHOOSE_MODE(SC_FAULT_WRITE(UPT_SC(r)), REGS_FAULT_WRITE(&r->skas)) ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-i386/ptrace_user.h um/arch/um/include/sysdep-i386/ptrace_user.h +--- orig/arch/um/include/sysdep-i386/ptrace_user.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/sysdep-i386/ptrace_user.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,62 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __SYSDEP_I386_PTRACE_USER_H__ ++#define __SYSDEP_I386_PTRACE_USER_H__ ++ ++#include <asm/ptrace.h> ++ ++#define PT_OFFSET(r) ((r) * sizeof(long)) ++ ++#define PT_SYSCALL_NR(regs) ((regs)[ORIG_EAX]) ++#define PT_SYSCALL_NR_OFFSET PT_OFFSET(ORIG_EAX) ++ ++#define PT_SYSCALL_ARG1_OFFSET PT_OFFSET(EBX) ++#define PT_SYSCALL_ARG2_OFFSET PT_OFFSET(ECX) ++#define PT_SYSCALL_ARG3_OFFSET PT_OFFSET(EDX) ++#define PT_SYSCALL_ARG4_OFFSET PT_OFFSET(ESI) ++#define PT_SYSCALL_ARG5_OFFSET PT_OFFSET(EDI) ++ ++#define PT_SYSCALL_RET_OFFSET PT_OFFSET(EAX) ++ ++#define PT_IP_OFFSET PT_OFFSET(EIP) ++#define PT_IP(regs) ((regs)[EIP]) ++#define PT_SP(regs) ((regs)[UESP]) ++ ++#ifndef FRAME_SIZE ++#define FRAME_SIZE (17) ++#endif ++#define FRAME_SIZE_OFFSET (FRAME_SIZE * sizeof(unsigned long)) ++ ++#define FP_FRAME_SIZE (27) ++#define FPX_FRAME_SIZE (128) ++ ++#ifdef PTRACE_GETREGS ++#define UM_HAVE_GETREGS ++#endif ++ ++#ifdef PTRACE_SETREGS ++#define UM_HAVE_SETREGS ++#endif ++ ++#ifdef PTRACE_GETFPREGS ++#define UM_HAVE_GETFPREGS ++#endif ++ ++#ifdef PTRACE_SETFPREGS ++#define UM_HAVE_SETFPREGS ++#endif ++ ++#ifdef PTRACE_GETFPXREGS ++#define UM_HAVE_GETFPXREGS ++#endif ++ ++#ifdef PTRACE_SETFPXREGS ++#define UM_HAVE_SETFPXREGS ++#endif ++ ++extern void update_debugregs(int seq); ++ ++#endif +diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-i386/sigcontext.h um/arch/um/include/sysdep-i386/sigcontext.h +--- orig/arch/um/include/sysdep-i386/sigcontext.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/sysdep-i386/sigcontext.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,49 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __SYS_SIGCONTEXT_I386_H ++#define __SYS_SIGCONTEXT_I386_H ++ ++#include "sc.h" ++ ++#define IP_RESTART_SYSCALL(ip) ((ip) -= 2) ++ ++#define SC_RESTART_SYSCALL(sc) IP_RESTART_SYSCALL(SC_IP(sc)) ++#define SC_SET_SYSCALL_RETURN(sc, result) SC_EAX(sc) = (result) ++ ++#define SC_FAULT_ADDR(sc) SC_CR2(sc) ++#define SC_FAULT_TYPE(sc) SC_ERR(sc) ++ ++#define FAULT_WRITE(err) (err & 2) ++#define TO_SC_ERR(is_write) ((is_write) ? 2 : 0) ++ ++#define SC_FAULT_WRITE(sc) (FAULT_WRITE(SC_ERR(sc))) ++ ++#define SC_TRAP_TYPE(sc) SC_TRAPNO(sc) ++ ++/* ptrace expects that, at the start of a system call, %eax contains ++ * -ENOSYS, so this makes it so. ++ */ ++#define SC_START_SYSCALL(sc) do SC_EAX(sc) = -ENOSYS; while(0) ++ ++/* This is Page Fault */ ++#define SEGV_IS_FIXABLE(trap) (trap == 14) ++ ++#define SC_SEGV_IS_FIXABLE(sc) (SEGV_IS_FIXABLE(SC_TRAPNO(sc))) ++ ++extern unsigned long *sc_sigmask(void *sc_ptr); ++extern int sc_get_fpregs(unsigned long buf, void *sc_ptr); ++ ++#endif ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-i386/syscalls.h um/arch/um/include/sysdep-i386/syscalls.h +--- orig/arch/um/include/sysdep-i386/syscalls.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/sysdep-i386/syscalls.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,61 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "asm/unistd.h" ++#include "sysdep/ptrace.h" ++ ++typedef long syscall_handler_t(struct pt_regs); ++ ++#define EXECUTE_SYSCALL(syscall, regs) \ ++ ((long (*)(struct syscall_args)) (*sys_call_table[syscall]))(SYSCALL_ARGS(®s->regs)) ++ ++extern syscall_handler_t sys_modify_ldt; ++extern syscall_handler_t old_mmap_i386; ++extern syscall_handler_t old_select; ++extern syscall_handler_t sys_ni_syscall; ++ ++#define ARCH_SYSCALLS \ ++ [ __NR_mmap ] = old_mmap_i386, \ ++ [ __NR_select ] = old_select, \ ++ [ __NR_vm86old ] = sys_ni_syscall, \ ++ [ __NR_modify_ldt ] = sys_modify_ldt, \ ++ [ __NR_lchown32 ] = sys_lchown, \ ++ [ __NR_getuid32 ] = sys_getuid, \ ++ [ __NR_getgid32 ] = sys_getgid, \ ++ [ __NR_geteuid32 ] = sys_geteuid, \ ++ [ __NR_getegid32 ] = sys_getegid, \ ++ [ __NR_setreuid32 ] = sys_setreuid, \ ++ [ __NR_setregid32 ] = sys_setregid, \ ++ [ __NR_getgroups32 ] = sys_getgroups, \ ++ [ __NR_setgroups32 ] = sys_setgroups, \ ++ [ __NR_fchown32 ] = sys_fchown, \ ++ [ __NR_setresuid32 ] = sys_setresuid, \ ++ [ __NR_getresuid32 ] = sys_getresuid, \ ++ [ __NR_setresgid32 ] = sys_setresgid, \ ++ [ __NR_getresgid32 ] = sys_getresgid, \ ++ [ __NR_chown32 ] = sys_chown, \ ++ [ __NR_setuid32 ] = sys_setuid, \ ++ [ __NR_setgid32 ] = sys_setgid, \ ++ [ __NR_setfsuid32 ] = sys_setfsuid, \ ++ [ __NR_setfsgid32 ] = sys_setfsgid, \ ++ [ __NR_pivot_root ] = sys_pivot_root, \ ++ [ __NR_mincore ] = sys_mincore, \ ++ [ __NR_madvise ] = sys_madvise, \ ++ [ 222 ] = sys_ni_syscall, ++ ++/* 222 doesn't yet have a name in include/asm-i386/unistd.h */ ++ ++#define LAST_ARCH_SYSCALL 222 ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-ia64/ptrace.h um/arch/um/include/sysdep-ia64/ptrace.h +--- orig/arch/um/include/sysdep-ia64/ptrace.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/sysdep-ia64/ptrace.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,26 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __SYSDEP_IA64_PTRACE_H ++#define __SYSDEP_IA64_PTRACE_H ++ ++struct sys_pt_regs { ++ int foo; ++}; ++ ++#define EMPTY_REGS { 0 } ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-ia64/sigcontext.h um/arch/um/include/sysdep-ia64/sigcontext.h +--- orig/arch/um/include/sysdep-ia64/sigcontext.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/sysdep-ia64/sigcontext.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,20 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __SYSDEP_IA64_SIGCONTEXT_H ++#define __SYSDEP_IA64_SIGCONTEXT_H ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-ia64/syscalls.h um/arch/um/include/sysdep-ia64/syscalls.h +--- orig/arch/um/include/sysdep-ia64/syscalls.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/sysdep-ia64/syscalls.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,20 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __SYSDEP_IA64_SYSCALLS_H ++#define __SYSDEP_IA64_SYSCALLS_H ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-ppc/ptrace.h um/arch/um/include/sysdep-ppc/ptrace.h +--- orig/arch/um/include/sysdep-ppc/ptrace.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/sysdep-ppc/ptrace.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,104 @@ ++/* ++ * Licensed under the GPL ++ */ ++ ++#ifndef __SYS_PTRACE_PPC_H ++#define __SYS_PTRACE_PPC_H ++ ++#include "linux/config.h" ++#include "linux/types.h" ++ ++/* the following taken from <asm-ppc/ptrace.h> */ ++ ++#ifdef CONFIG_PPC64 ++#define PPC_REG unsigned long /*long*/ ++#else ++#define PPC_REG unsigned long ++#endif ++struct sys_pt_regs_s { ++ PPC_REG gpr[32]; ++ PPC_REG nip; ++ PPC_REG msr; ++ PPC_REG orig_gpr3; /* Used for restarting system calls */ ++ PPC_REG ctr; ++ PPC_REG link; ++ PPC_REG xer; ++ PPC_REG ccr; ++ PPC_REG mq; /* 601 only (not used at present) */ ++ /* Used on APUS to hold IPL value. */ ++ PPC_REG trap; /* Reason for being here */ ++ PPC_REG dar; /* Fault registers */ ++ PPC_REG dsisr; ++ PPC_REG result; /* Result of a system call */ ++}; ++ ++#define NUM_REGS (sizeof(struct sys_pt_regs_s) / sizeof(PPC_REG)) ++ ++struct sys_pt_regs { ++ PPC_REG regs[sizeof(struct sys_pt_regs_s) / sizeof(PPC_REG)]; ++}; ++ ++#define UM_MAX_REG (PT_FPR0) ++#define UM_MAX_REG_OFFSET (UM_MAX_REG * sizeof(PPC_REG)) ++ ++#define EMPTY_REGS { { [ 0 ... NUM_REGS - 1] = 0 } } ++ ++#define UM_REG(r, n) ((r)->regs[n]) ++ ++#define UM_SYSCALL_RET(r) UM_REG(r, PT_R3) ++#define UM_SP(r) UM_REG(r, PT_R1) ++#define UM_IP(r) UM_REG(r, PT_NIP) ++#define UM_ELF_ZERO(r) UM_REG(r, PT_FPSCR) ++#define UM_SYSCALL_NR(r) UM_REG(r, PT_R0) ++#define UM_SYSCALL_ARG1(r) UM_REG(r, PT_ORIG_R3) ++#define UM_SYSCALL_ARG2(r) UM_REG(r, PT_R4) ++#define UM_SYSCALL_ARG3(r) UM_REG(r, PT_R5) ++#define UM_SYSCALL_ARG4(r) UM_REG(r, PT_R6) ++#define UM_SYSCALL_ARG5(r) UM_REG(r, PT_R7) ++#define UM_SYSCALL_ARG6(r) UM_REG(r, PT_R8) ++ ++#define UM_SYSCALL_NR_OFFSET (PT_R0 * sizeof(PPC_REG)) ++#define UM_SYSCALL_RET_OFFSET (PT_R3 * sizeof(PPC_REG)) ++#define UM_SYSCALL_ARG1_OFFSET (PT_R3 * sizeof(PPC_REG)) ++#define UM_SYSCALL_ARG2_OFFSET (PT_R4 * sizeof(PPC_REG)) ++#define UM_SYSCALL_ARG3_OFFSET (PT_R5 * sizeof(PPC_REG)) ++#define UM_SYSCALL_ARG4_OFFSET (PT_R6 * sizeof(PPC_REG)) ++#define UM_SYSCALL_ARG5_OFFSET (PT_R7 * sizeof(PPC_REG)) ++#define UM_SYSCALL_ARG6_OFFSET (PT_R8 * sizeof(PPC_REG)) ++#define UM_SP_OFFSET (PT_R1 * sizeof(PPC_REG)) ++#define UM_IP_OFFSET (PT_NIP * sizeof(PPC_REG)) ++#define UM_ELF_ZERO_OFFSET (PT_R3 * sizeof(PPC_REG)) ++ ++#define UM_SET_SYSCALL_RETURN(_regs, result) \ ++do { \ ++ if (result < 0) { \ ++ (_regs)->regs[PT_CCR] |= 0x10000000; \ ++ UM_SYSCALL_RET((_regs)) = -result; \ ++ } else { \ ++ UM_SYSCALL_RET((_regs)) = result; \ ++ } \ ++} while(0) ++ ++extern void shove_aux_table(unsigned long sp); ++#define UM_FIX_EXEC_STACK(sp) shove_aux_table(sp); ++ ++/* These aren't actually defined. The undefs are just to make sure ++ * everyone's clear on the concept. ++ */ ++#undef UML_HAVE_GETREGS ++#undef UML_HAVE_GETFPREGS ++#undef UML_HAVE_SETREGS ++#undef UML_HAVE_SETFPREGS ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-ppc/sigcontext.h um/arch/um/include/sysdep-ppc/sigcontext.h +--- orig/arch/um/include/sysdep-ppc/sigcontext.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/sysdep-ppc/sigcontext.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,62 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __SYS_SIGCONTEXT_PPC_H ++#define __SYS_SIGCONTEXT_PPC_H ++ ++#define DSISR_WRITE 0x02000000 ++ ++#define SC_FAULT_ADDR(sc) ({ \ ++ struct sigcontext *_sc = (sc); \ ++ long retval = -1; \ ++ switch (_sc->regs->trap) { \ ++ case 0x300: \ ++ /* data exception */ \ ++ retval = _sc->regs->dar; \ ++ break; \ ++ case 0x400: \ ++ /* instruction exception */ \ ++ retval = _sc->regs->nip; \ ++ break; \ ++ default: \ ++ panic("SC_FAULT_ADDR: unhandled trap type\n"); \ ++ } \ ++ retval; \ ++ }) ++ ++#define SC_FAULT_WRITE(sc) ({ \ ++ struct sigcontext *_sc = (sc); \ ++ long retval = -1; \ ++ switch (_sc->regs->trap) { \ ++ case 0x300: \ ++ /* data exception */ \ ++ retval = !!(_sc->regs->dsisr & DSISR_WRITE); \ ++ break; \ ++ case 0x400: \ ++ /* instruction exception: not a write */ \ ++ retval = 0; \ ++ break; \ ++ default: \ ++ panic("SC_FAULT_ADDR: unhandled trap type\n"); \ ++ } \ ++ retval; \ ++ }) ++ ++#define SC_IP(sc) ((sc)->regs->nip) ++#define SC_SP(sc) ((sc)->regs->gpr[1]) ++#define SEGV_IS_FIXABLE(sc) (1) ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/sysdep-ppc/syscalls.h um/arch/um/include/sysdep-ppc/syscalls.h +--- orig/arch/um/include/sysdep-ppc/syscalls.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/sysdep-ppc/syscalls.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,50 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++typedef long syscall_handler_t(unsigned long arg1, unsigned long arg2, ++ unsigned long arg3, unsigned long arg4, ++ unsigned long arg5, unsigned long arg6); ++ ++#define EXECUTE_SYSCALL(syscall, regs) \ ++ (*sys_call_table[syscall])(UM_SYSCALL_ARG1(®s), \ ++ UM_SYSCALL_ARG2(®s), \ ++ UM_SYSCALL_ARG3(®s), \ ++ UM_SYSCALL_ARG4(®s), \ ++ UM_SYSCALL_ARG5(®s), \ ++ UM_SYSCALL_ARG6(®s)) ++ ++extern syscall_handler_t sys_mincore; ++extern syscall_handler_t sys_madvise; ++ ++/* old_mmap needs the correct prototype since syscall_kern.c includes ++ * this file. ++ */ ++int old_mmap(unsigned long addr, unsigned long len, ++ unsigned long prot, unsigned long flags, ++ unsigned long fd, unsigned long offset); ++ ++#define ARCH_SYSCALLS \ ++ [ __NR_modify_ldt ] = sys_ni_syscall, \ ++ [ __NR_pciconfig_read ] = sys_ni_syscall, \ ++ [ __NR_pciconfig_write ] = sys_ni_syscall, \ ++ [ __NR_pciconfig_iobase ] = sys_ni_syscall, \ ++ [ __NR_pivot_root ] = sys_ni_syscall, \ ++ [ __NR_multiplexer ] = sys_ni_syscall, \ ++ [ __NR_mmap ] = old_mmap, \ ++ [ __NR_madvise ] = sys_madvise, \ ++ [ __NR_mincore ] = sys_mincore, ++ ++#define LAST_ARCH_SYSCALL __NR_mincore ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/sysrq.h um/arch/um/include/sysrq.h +--- orig/arch/um/include/sysrq.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/sysrq.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_SYSRQ_H ++#define __UM_SYSRQ_H ++ ++extern void show_trace(unsigned long *stack); ++ ++#endif +diff -Naur -X ../exclude-files orig/arch/um/include/tempfile.h um/arch/um/include/tempfile.h +--- orig/arch/um/include/tempfile.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/tempfile.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,21 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __TEMPFILE_H__ ++#define __TEMPFILE_H__ ++ ++extern int make_tempfile(const char *template, char **tempname, int do_unlink); ++ ++#endif ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/time_user.h um/arch/um/include/time_user.h +--- orig/arch/um/include/time_user.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/time_user.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,17 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __TIME_USER_H__ ++#define __TIME_USER_H__ ++ ++extern void timer(void); ++extern void switch_timers(int to_real); ++extern void set_interval(int timer_type); ++extern void idle_sleep(int secs); ++extern void enable_timer(void); ++extern unsigned long time_lock(void); ++extern void time_unlock(unsigned long); ++ ++#endif +diff -Naur -X ../exclude-files orig/arch/um/include/tlb.h um/arch/um/include/tlb.h +--- orig/arch/um/include/tlb.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/tlb.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,23 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __TLB_H__ ++#define __TLB_H__ ++ ++extern void mprotect_kernel_vm(int w); ++extern void force_flush_all(void); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/ubd_user.h um/arch/um/include/ubd_user.h +--- orig/arch/um/include/ubd_user.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/ubd_user.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,79 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Copyright (C) 2001 RidgeRun, Inc (glonnon@ridgerun.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UM_UBD_USER_H ++#define __UM_UBD_USER_H ++ ++#include "os.h" ++ ++enum ubd_req { UBD_READ, UBD_WRITE, UBD_MMAP }; ++ ++struct io_thread_req { ++ enum ubd_req op; ++ int fds[2]; ++ unsigned long offsets[2]; ++ unsigned long long offset; ++ unsigned long length; ++ char *buffer; ++ int sectorsize; ++ unsigned long sector_mask; ++ unsigned long long cow_offset; ++ unsigned long bitmap_words[2]; ++ int map_fd; ++ unsigned long long map_offset; ++ int error; ++}; ++ ++extern int open_ubd_file(char *file, struct openflags *openflags, ++ char **backing_file_out, int *bitmap_offset_out, ++ unsigned long *bitmap_len_out, int *data_offset_out, ++ int *create_cow_out); ++extern int create_cow_file(char *cow_file, char *backing_file, ++ struct openflags flags, int sectorsize, ++ int alignment, int *bitmap_offset_out, ++ unsigned long *bitmap_len_out, ++ int *data_offset_out); ++extern int read_cow_bitmap(int fd, void *buf, int offset, int len); ++extern int read_ubd_fs(int fd, void *buffer, int len); ++extern int write_ubd_fs(int fd, char *buffer, int len); ++extern int start_io_thread(unsigned long sp, int *fds_out); ++extern void do_io(struct io_thread_req *req); ++ ++static inline int ubd_test_bit(__u64 bit, unsigned char *data) ++{ ++ __u64 n; ++ int bits, off; ++ ++ bits = sizeof(data[0]) * 8; ++ n = bit / bits; ++ off = bit % bits; ++ return((data[n] & (1 << off)) != 0); ++} ++ ++static inline void ubd_set_bit(__u64 bit, unsigned char *data) ++{ ++ __u64 n; ++ int bits, off; ++ ++ bits = sizeof(data[0]) * 8; ++ n = bit / bits; ++ off = bit % bits; ++ data[n] |= (1 << off); ++} ++ ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/umid.h um/arch/um/include/umid.h +--- orig/arch/um/include/umid.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/umid.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,22 @@ ++/* ++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UMID_H__ ++#define __UMID_H__ ++ ++extern int umid_file_name(char *name, char *buf, int len); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/uml_uaccess.h um/arch/um/include/uml_uaccess.h +--- orig/arch/um/include/uml_uaccess.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/uml_uaccess.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UML_UACCESS_H__ ++#define __UML_UACCESS_H__ ++ ++extern int __do_copy_to_user(void *to, const void *from, int n, ++ void **fault_addr, void **fault_catcher); ++extern unsigned long __do_user_copy(void *to, const void *from, int n, ++ void **fault_addr, void **fault_catcher, ++ void (*op)(void *to, const void *from, ++ int n), int *faulted_out); ++void __do_copy(void *to, const void *from, int n); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/um_mmu.h um/arch/um/include/um_mmu.h +--- orig/arch/um/include/um_mmu.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/um_mmu.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,40 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __ARCH_UM_MMU_H ++#define __ARCH_UM_MMU_H ++ ++#include "linux/config.h" ++#include "choose-mode.h" ++ ++#ifdef CONFIG_MODE_TT ++#include "../kernel/tt/include/mmu.h" ++#endif ++ ++#ifdef CONFIG_MODE_SKAS ++#include "../kernel/skas/include/mmu.h" ++#endif ++ ++typedef union { ++#ifdef CONFIG_MODE_TT ++ struct mmu_context_tt tt; ++#endif ++#ifdef CONFIG_MODE_SKAS ++ struct mmu_context_skas skas; ++#endif ++} mm_context_t; ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/umn.h um/arch/um/include/umn.h +--- orig/arch/um/include/umn.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/umn.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,27 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UMN_H ++#define __UMN_H ++ ++extern int open_umn_tty(int *slave_out, int *slipno_out); ++extern void close_umn_tty(int master, int slave); ++extern int umn_send_packet(int fd, void *data, int len); ++extern int set_umn_addr(int fd, char *addr, char *ptp_addr); ++extern void slip_unesc(unsigned char s); ++extern void umn_read(int fd); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/um_uaccess.h um/arch/um/include/um_uaccess.h +--- orig/arch/um/include/um_uaccess.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/um_uaccess.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,124 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __ARCH_UM_UACCESS_H ++#define __ARCH_UM_UACCESS_H ++ ++#include "linux/config.h" ++#include "choose-mode.h" ++ ++#ifdef CONFIG_MODE_TT ++#include "../kernel/tt/include/uaccess.h" ++#endif ++ ++#ifdef CONFIG_MODE_SKAS ++#include "../kernel/skas/include/uaccess.h" ++#endif ++ ++#define access_ok(type, addr, size) \ ++ CHOOSE_MODE_PROC(access_ok_tt, access_ok_skas, type, addr, size) ++ ++static inline int verify_area(int type, const void * addr, unsigned long size) ++{ ++ return(CHOOSE_MODE_PROC(verify_area_tt, verify_area_skas, type, addr, ++ size)); ++} ++ ++static inline int copy_from_user(void *to, const void *from, int n) ++{ ++ return(CHOOSE_MODE_PROC(copy_from_user_tt, copy_from_user_skas, to, ++ from, n)); ++} ++ ++static inline int copy_to_user(void *to, const void *from, int n) ++{ ++ return(CHOOSE_MODE_PROC(copy_to_user_tt, copy_to_user_skas, to, ++ from, n)); ++} ++ ++/* ++ * strncpy_from_user: - Copy a NUL terminated string from userspace. ++ * @dst: Destination address, in kernel space. This buffer must be at ++ * least @count bytes long. ++ * @src: Source address, in user space. ++ * @count: Maximum number of bytes to copy, including the trailing NUL. ++ * ++ * Copies a NUL-terminated string from userspace to kernel space. ++ * ++ * On success, returns the length of the string (not including the trailing ++ * NUL). ++ * ++ * If access to userspace fails, returns -EFAULT (some data may have been ++ * copied). ++ * ++ * If @count is smaller than the length of the string, copies @count bytes ++ * and returns @count. ++ */ ++ ++static inline int strncpy_from_user(char *dst, const char *src, int count) ++{ ++ return(CHOOSE_MODE_PROC(strncpy_from_user_tt, strncpy_from_user_skas, ++ dst, src, count)); ++} ++ ++/* ++ * __clear_user: - Zero a block of memory in user space, with less checking. ++ * @to: Destination address, in user space. ++ * @n: Number of bytes to zero. ++ * ++ * Zero a block of memory in user space. Caller must check ++ * the specified block with access_ok() before calling this function. ++ * ++ * Returns number of bytes that could not be cleared. ++ * On success, this will be zero. ++ */ ++static inline int __clear_user(void *mem, int len) ++{ ++ return(CHOOSE_MODE_PROC(__clear_user_tt, __clear_user_skas, mem, len)); ++} ++ ++/* ++ * clear_user: - Zero a block of memory in user space. ++ * @to: Destination address, in user space. ++ * @n: Number of bytes to zero. ++ * ++ * Zero a block of memory in user space. ++ * ++ * Returns number of bytes that could not be cleared. ++ * On success, this will be zero. ++ */ ++static inline int clear_user(void *mem, int len) ++{ ++ return(CHOOSE_MODE_PROC(clear_user_tt, clear_user_skas, mem, len)); ++} ++ ++/* ++ * strlen_user: - Get the size of a string in user space. ++ * @str: The string to measure. ++ * @n: The maximum valid length ++ * ++ * Get the size of a NUL-terminated string in user space. ++ * ++ * Returns the size of the string INCLUDING the terminating NUL. ++ * On exception, returns 0. ++ * If the string is too long, returns a value greater than @n. ++ */ ++static inline int strnlen_user(const void *str, int len) ++{ ++ return(CHOOSE_MODE_PROC(strnlen_user_tt, strnlen_user_skas, str, len)); ++} ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/user.h um/arch/um/include/user.h +--- orig/arch/um/include/user.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/user.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,29 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __USER_H__ ++#define __USER_H__ ++ ++extern void panic(const char *fmt, ...); ++extern int printk(const char *fmt, ...); ++extern void schedule(void); ++extern void *um_kmalloc(int size); ++extern void *um_kmalloc_atomic(int size); ++extern void kfree(void *ptr); ++extern int in_aton(char *str); ++extern int open_gdb_chan(void); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/include/user_util.h um/arch/um/include/user_util.h +--- orig/arch/um/include/user_util.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/include/user_util.h 2003-11-09 11:36:31.000000000 -0500 +@@ -0,0 +1,103 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __USER_UTIL_H__ ++#define __USER_UTIL_H__ ++ ++#include "sysdep/ptrace.h" ++ ++extern int mode_tt; ++ ++extern int grantpt(int __fd); ++extern int unlockpt(int __fd); ++extern char *ptsname(int __fd); ++ ++struct cpu_task { ++ int pid; ++ void *task; ++}; ++ ++extern struct cpu_task cpu_tasks[]; ++ ++struct signal_info { ++ void (*handler)(int, union uml_pt_regs *); ++ int is_irq; ++}; ++ ++extern struct signal_info sig_info[]; ++ ++extern unsigned long low_physmem; ++extern unsigned long high_physmem; ++extern unsigned long uml_physmem; ++extern unsigned long uml_reserved; ++extern unsigned long end_vm; ++extern unsigned long start_vm; ++extern unsigned long highmem; ++ ++extern char host_info[]; ++ ++extern char saved_command_line[]; ++extern char command_line[]; ++ ++extern char *tempdir; ++ ++extern unsigned long _stext, _etext, _sdata, _edata, __bss_start, _end; ++extern unsigned long _unprotected_end; ++extern unsigned long brk_start; ++ ++extern int pty_output_sigio; ++extern int pty_close_sigio; ++ ++extern void stop(void); ++extern void stack_protections(unsigned long address); ++extern void task_protections(unsigned long address); ++extern int wait_for_stop(int pid, int sig, int cont_type, void *relay); ++extern void *add_signal_handler(int sig, void (*handler)(int)); ++extern int start_fork_tramp(void *arg, unsigned long temp_stack, ++ int clone_flags, int (*tramp)(void *)); ++extern int linux_main(int argc, char **argv); ++extern void set_cmdline(char *cmd); ++extern void input_cb(void (*proc)(void *), void *arg, int arg_len); ++extern int get_pty(void); ++extern void *um_kmalloc(int size); ++extern int raw(int fd, int complain); ++extern int switcheroo(int fd, int prot, void *from, void *to, int size); ++extern void setup_machinename(char *machine_out); ++extern void setup_hostinfo(void); ++extern void add_arg(char *cmd_line, char *arg); ++extern void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)); ++extern void init_new_thread_signals(int altstack); ++extern void do_exec(int old_pid, int new_pid); ++extern void tracer_panic(char *msg, ...); ++extern char *get_umid(int only_if_set); ++extern void do_longjmp(void *p, int val); ++extern void suspend_new_thread(int fd); ++extern int detach(int pid, int sig); ++extern int attach(int pid); ++extern void kill_child_dead(int pid); ++extern int cont(int pid); ++extern void check_ptrace(void); ++extern void check_sigio(void); ++extern int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr); ++extern void write_sigio_workaround(void); ++extern void arch_check_bugs(void); ++extern int cpu_feature(char *what, char *buf, int len); ++extern int arch_handle_signal(int sig, union uml_pt_regs *regs); ++extern int arch_fixup(unsigned long address, void *sc_ptr); ++extern int can_do_skas(void); ++extern void arch_init_thread(void); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/checksum.c um/arch/um/kernel/checksum.c +--- orig/arch/um/kernel/checksum.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/checksum.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,42 @@ ++#include "asm/uaccess.h" ++#include "linux/errno.h" ++ ++extern unsigned int arch_csum_partial(const char *buff, int len, int sum); ++ ++extern unsigned int csum_partial(char *buff, int len, int sum) ++{ ++ return(arch_csum_partial(buff, len, sum)); ++} ++ ++unsigned int csum_partial_copy_to(const char *src, char *dst, int len, ++ int sum, int *err_ptr) ++{ ++ if(copy_to_user(dst, src, len)){ ++ *err_ptr = -EFAULT; ++ return(-1); ++ } ++ ++ return(arch_csum_partial(src, len, sum)); ++} ++ ++unsigned int csum_partial_copy_from(const char *src, char *dst, int len, ++ int sum, int *err_ptr) ++{ ++ if(copy_from_user(dst, src, len)){ ++ *err_ptr = -EFAULT; ++ return(-1); ++ } ++ ++ return(arch_csum_partial(dst, len, sum)); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/config.c.in um/arch/um/kernel/config.c.in +--- orig/arch/um/kernel/config.c.in 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/config.c.in 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,32 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include "init.h" ++ ++static __initdata char *config = "CONFIG"; ++ ++static int __init print_config(char *line, int *add) ++{ ++ printf("%s", config); ++ exit(0); ++} ++ ++__uml_setup("--showconfig", print_config, ++"--showconfig\n" ++" Prints the config file that this UML binary was generated from.\n\n" ++); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/exec_kern.c um/arch/um/kernel/exec_kern.c +--- orig/arch/um/kernel/exec_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/exec_kern.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,86 @@ ++/* ++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/slab.h" ++#include "linux/smp_lock.h" ++#include "asm/ptrace.h" ++#include "asm/pgtable.h" ++#include "asm/pgalloc.h" ++#include "asm/uaccess.h" ++#include "user_util.h" ++#include "kern_util.h" ++#include "mem_user.h" ++#include "kern.h" ++#include "irq_user.h" ++#include "tlb.h" ++#include "2_5compat.h" ++#include "os.h" ++#include "time_user.h" ++#include "choose-mode.h" ++#include "mode_kern.h" ++ ++void flush_thread(void) ++{ ++ CHOOSE_MODE(flush_thread_tt(), flush_thread_skas()); ++} ++ ++void start_thread(struct pt_regs *regs, unsigned long eip, unsigned long esp) ++{ ++ CHOOSE_MODE_PROC(start_thread_tt, start_thread_skas, regs, eip, esp); ++} ++ ++extern void log_exec(char **argv, void *tty); ++ ++static int execve1(char *file, char **argv, char **env) ++{ ++ int error; ++ ++#ifdef CONFIG_TTY_LOG ++ log_exec(argv, current->tty); ++#endif ++ error = do_execve(file, argv, env, ¤t->thread.regs); ++ if (error == 0){ ++ current->ptrace &= ~PT_DTRACE; ++ set_cmdline(current_cmd()); ++ } ++ return(error); ++} ++ ++int um_execve(char *file, char **argv, char **env) ++{ ++ int err; ++ ++ err = execve1(file, argv, env); ++ if(!err) ++ do_longjmp(current->thread.exec_buf, 1); ++ return(err); ++} ++ ++int sys_execve(char *file, char **argv, char **env) ++{ ++ int error; ++ char *filename; ++ ++ lock_kernel(); ++ filename = getname((char *) file); ++ error = PTR_ERR(filename); ++ if (IS_ERR(filename)) goto out; ++ error = execve1(filename, argv, env); ++ putname(filename); ++ out: ++ unlock_kernel(); ++ return(error); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/exitcode.c um/arch/um/kernel/exitcode.c +--- orig/arch/um/kernel/exitcode.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/exitcode.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,73 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/init.h" ++#include "linux/ctype.h" ++#include "linux/proc_fs.h" ++#include "asm/uaccess.h" ++ ++/* If read and write race, the read will still atomically read a valid ++ * value. ++ */ ++int uml_exitcode = 0; ++ ++static int read_proc_exitcode(char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ int len; ++ ++ len = sprintf(page, "%d\n", uml_exitcode); ++ len -= off; ++ if(len <= off+count) *eof = 1; ++ *start = page + off; ++ if(len > count) len = count; ++ if(len < 0) len = 0; ++ return(len); ++} ++ ++static int write_proc_exitcode(struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ char *end, buf[sizeof("nnnnn\0")]; ++ int tmp; ++ ++ if(copy_from_user(buf, buffer, count)) ++ return(-EFAULT); ++ tmp = simple_strtol(buf, &end, 0); ++ if((*end != '\0') && !isspace(*end)) ++ return(-EINVAL); ++ uml_exitcode = tmp; ++ return(count); ++} ++ ++static int make_proc_exitcode(void) ++{ ++ struct proc_dir_entry *ent; ++ ++ ent = create_proc_entry("exitcode", 0600, &proc_root); ++ if(ent == NULL){ ++ printk("make_proc_exitcode : Failed to register " ++ "/proc/exitcode\n"); ++ return(0); ++ } ++ ++ ent->read_proc = read_proc_exitcode; ++ ent->write_proc = write_proc_exitcode; ++ ++ return(0); ++} ++ ++__initcall(make_proc_exitcode); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/frame.c um/arch/um/kernel/frame.c +--- orig/arch/um/kernel/frame.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/frame.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,341 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <unistd.h> ++#include <string.h> ++#include <signal.h> ++#include <wait.h> ++#include <sched.h> ++#include <errno.h> ++#include <sys/ptrace.h> ++#include <sys/syscall.h> ++#include <sys/mman.h> ++#include <asm/page.h> ++#include <asm/ptrace.h> ++#include <asm/sigcontext.h> ++#include "sysdep/ptrace.h" ++#include "sysdep/sigcontext.h" ++#include "frame_user.h" ++#include "kern_util.h" ++#include "ptrace_user.h" ++#include "os.h" ++ ++static int capture_stack(int (*child)(void *arg), void *arg, void *sp, ++ unsigned long top, void **data_out) ++{ ++ unsigned long regs[FRAME_SIZE]; ++ int pid, status, n, len; ++ ++ /* Start the child as a thread */ ++ pid = clone(child, sp, CLONE_VM | SIGCHLD, arg); ++ if(pid < 0){ ++ printf("capture_stack : clone failed - errno = %d\n", errno); ++ exit(1); ++ } ++ ++ /* Wait for it to stop itself and continue it with a SIGUSR1 to force ++ * it into the signal handler. ++ */ ++ n = waitpid(pid, &status, WUNTRACED); ++ if(n < 0){ ++ printf("capture_stack : waitpid failed - errno = %d\n", errno); ++ exit(1); ++ } ++ if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)){ ++ fprintf(stderr, "capture_stack : Expected SIGSTOP, " ++ "got status = 0x%x\n", status); ++ exit(1); ++ } ++ if(ptrace(PTRACE_CONT, pid, 0, SIGUSR1) < 0){ ++ printf("capture_stack : PTRACE_CONT failed - errno = %d\n", ++ errno); ++ exit(1); ++ } ++ ++ /* Wait for it to stop itself again and grab its registers again. ++ * At this point, the handler has stuffed the addresses of ++ * sig, sc, and SA_RESTORER in raw. ++ */ ++ n = waitpid(pid, &status, WUNTRACED); ++ if(n < 0){ ++ printf("capture_stack : waitpid failed - errno = %d\n", errno); ++ exit(1); ++ } ++ if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)){ ++ fprintf(stderr, "capture_stack : Expected SIGSTOP, " ++ "got status = 0x%x\n", status); ++ exit(1); ++ } ++ if(ptrace(PTRACE_GETREGS, pid, 0, regs) < 0){ ++ printf("capture_stack : PTRACE_GETREGS failed - errno = %d\n", ++ errno); ++ exit(1); ++ } ++ ++ /* It has outlived its usefulness, so continue it so it can exit */ ++ if(ptrace(PTRACE_CONT, pid, 0, 0) < 0){ ++ printf("capture_stack : PTRACE_CONT failed - errno = %d\n", ++ errno); ++ exit(1); ++ } ++ if(waitpid(pid, &status, 0) < 0){ ++ printf("capture_stack : waitpid failed - errno = %d\n", errno); ++ exit(1); ++ } ++ if(!WIFSIGNALED(status) || (WTERMSIG(status) != 9)){ ++ printf("capture_stack : Expected exit signal 9, " ++ "got status = 0x%x\n", status); ++ exit(1); ++ } ++ ++ /* The frame that we want is the top of the signal stack */ ++ ++ len = top - PT_SP(regs); ++ *data_out = malloc(len); ++ if(*data_out == NULL){ ++ printf("capture_stack : malloc failed - errno = %d\n", errno); ++ exit(1); ++ } ++ memcpy(*data_out, (void *) PT_SP(regs), len); ++ ++ return(len); ++} ++ ++struct common_raw { ++ void *stack; ++ int size; ++ unsigned long sig; ++ unsigned long sr; ++ unsigned long sp; ++ struct arch_frame_data_raw arch; ++}; ++ ++#define SA_RESTORER (0x04000000) ++ ++typedef unsigned long old_sigset_t; ++ ++struct old_sigaction { ++ __sighandler_t handler; ++ old_sigset_t sa_mask; ++ unsigned long sa_flags; ++ void (*sa_restorer)(void); ++}; ++ ++static void child_common(struct common_raw *common, sighandler_t handler, ++ int restorer, int flags) ++{ ++ stack_t ss = ((stack_t) { .ss_sp = common->stack, ++ .ss_flags = 0, ++ .ss_size = common->size }); ++ int err; ++ ++ if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){ ++ printf("PTRACE_TRACEME failed, errno = %d\n", errno); ++ } ++ if(sigaltstack(&ss, NULL) < 0){ ++ printf("sigaltstack failed - errno = %d\n", errno); ++ kill(getpid(), SIGKILL); ++ } ++ ++ if(restorer){ ++ struct sigaction sa; ++ ++ sa.sa_handler = handler; ++ sigemptyset(&sa.sa_mask); ++ sa.sa_flags = SA_ONSTACK | flags; ++ err = sigaction(SIGUSR1, &sa, NULL); ++ } ++ else { ++ struct old_sigaction sa; ++ ++ sa.handler = handler; ++ sa.sa_mask = 0; ++ sa.sa_flags = (SA_ONSTACK | flags) & ~SA_RESTORER; ++ err = syscall(__NR_sigaction, SIGUSR1, &sa, NULL); ++ } ++ ++ if(err < 0){ ++ printf("sigaction failed - errno = %d\n", errno); ++ kill(getpid(), SIGKILL); ++ } ++ ++ os_stop_process(os_getpid()); ++} ++ ++/* Changed only during early boot */ ++struct sc_frame signal_frame_sc; ++ ++struct sc_frame signal_frame_sc_sr; ++ ++struct sc_frame_raw { ++ struct common_raw common; ++ unsigned long sc; ++ int restorer; ++}; ++ ++/* Changed only during early boot */ ++static struct sc_frame_raw *raw_sc = NULL; ++ ++static void sc_handler(int sig, struct sigcontext sc) ++{ ++ raw_sc->common.sig = (unsigned long) &sig; ++ raw_sc->common.sr = frame_restorer(); ++ raw_sc->common.sp = frame_sp(); ++ raw_sc->sc = (unsigned long) ≻ ++ setup_arch_frame_raw(&raw_sc->common.arch, &sc + 1, raw_sc->common.sr); ++ ++ os_stop_process(os_getpid()); ++ kill(getpid(), SIGKILL); ++} ++ ++static int sc_child(void *arg) ++{ ++ raw_sc = arg; ++ child_common(&raw_sc->common, (sighandler_t) sc_handler, ++ raw_sc->restorer, 0); ++ return(-1); ++} ++ ++/* Changed only during early boot */ ++struct si_frame signal_frame_si; ++ ++struct si_frame_raw { ++ struct common_raw common; ++ unsigned long sip; ++ unsigned long si; ++ unsigned long ucp; ++ unsigned long uc; ++}; ++ ++/* Changed only during early boot */ ++static struct si_frame_raw *raw_si = NULL; ++ ++static void si_handler(int sig, siginfo_t *si, struct ucontext *ucontext) ++{ ++ raw_si->common.sig = (unsigned long) &sig; ++ raw_si->common.sr = frame_restorer(); ++ raw_si->common.sp = frame_sp(); ++ raw_si->sip = (unsigned long) &si; ++ raw_si->si = (unsigned long) si; ++ raw_si->ucp = (unsigned long) &ucontext; ++ raw_si->uc = (unsigned long) ucontext; ++ setup_arch_frame_raw(&raw_si->common.arch, ++ ucontext->uc_mcontext.fpregs, raw_si->common.sr); ++ ++ os_stop_process(os_getpid()); ++ kill(getpid(), SIGKILL); ++} ++ ++static int si_child(void *arg) ++{ ++ raw_si = arg; ++ child_common(&raw_si->common, (sighandler_t) si_handler, 1, ++ SA_SIGINFO); ++ return(-1); ++} ++ ++static int relative_sr(unsigned long sr, int sr_index, void *stack, ++ void *framep) ++{ ++ unsigned long *srp = (unsigned long *) sr; ++ unsigned long frame = (unsigned long) framep; ++ ++ if((*srp & PAGE_MASK) == (unsigned long) stack){ ++ *srp -= sr; ++ *((unsigned long *) (frame + sr_index)) = *srp; ++ return(1); ++ } ++ else return(0); ++} ++ ++static unsigned long capture_stack_common(int (*proc)(void *), void *arg, ++ struct common_raw *common_in, ++ void *top, void *sigstack, ++ int stack_len, ++ struct frame_common *common_out) ++{ ++ unsigned long sig_top = (unsigned long) sigstack + stack_len, base; ++ ++ common_in->stack = (void *) sigstack; ++ common_in->size = stack_len; ++ common_out->len = capture_stack(proc, arg, top, sig_top, ++ &common_out->data); ++ base = sig_top - common_out->len; ++ common_out->sig_index = common_in->sig - base; ++ common_out->sp_index = common_in->sp - base; ++ common_out->sr_index = common_in->sr - base; ++ common_out->sr_relative = relative_sr(common_in->sr, ++ common_out->sr_index, sigstack, ++ common_out->data); ++ return(base); ++} ++ ++void capture_signal_stack(void) ++{ ++ struct sc_frame_raw raw_sc; ++ struct si_frame_raw raw_si; ++ void *stack, *sigstack; ++ unsigned long top, base; ++ ++ stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, ++ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ++ sigstack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, ++ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ++ if((stack == MAP_FAILED) || (sigstack == MAP_FAILED)){ ++ printf("capture_signal_stack : mmap failed - errno = %d\n", ++ errno); ++ exit(1); ++ } ++ ++ top = (unsigned long) stack + PAGE_SIZE - sizeof(void *); ++ ++ /* Get the sigcontext, no sigrestorer layout */ ++ raw_sc.restorer = 0; ++ base = capture_stack_common(sc_child, &raw_sc, &raw_sc.common, ++ (void *) top, sigstack, PAGE_SIZE, ++ &signal_frame_sc.common); ++ ++ signal_frame_sc.sc_index = raw_sc.sc - base; ++ setup_arch_frame(&raw_sc.common.arch, &signal_frame_sc.common.arch); ++ ++ /* Ditto for the sigcontext, sigrestorer layout */ ++ raw_sc.restorer = 1; ++ base = capture_stack_common(sc_child, &raw_sc, &raw_sc.common, ++ (void *) top, sigstack, PAGE_SIZE, ++ &signal_frame_sc_sr.common); ++ signal_frame_sc_sr.sc_index = raw_sc.sc - base; ++ setup_arch_frame(&raw_sc.common.arch, &signal_frame_sc_sr.common.arch); ++ ++ /* And the siginfo layout */ ++ ++ base = capture_stack_common(si_child, &raw_si, &raw_si.common, ++ (void *) top, sigstack, PAGE_SIZE, ++ &signal_frame_si.common); ++ signal_frame_si.sip_index = raw_si.sip - base; ++ signal_frame_si.si_index = raw_si.si - base; ++ signal_frame_si.ucp_index = raw_si.ucp - base; ++ signal_frame_si.uc_index = raw_si.uc - base; ++ setup_arch_frame(&raw_si.common.arch, &signal_frame_si.common.arch); ++ ++ if((munmap(stack, PAGE_SIZE) < 0) || ++ (munmap(sigstack, PAGE_SIZE) < 0)){ ++ printf("capture_signal_stack : munmap failed - errno = %d\n", ++ errno); ++ exit(1); ++ } ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/frame_kern.c um/arch/um/kernel/frame_kern.c +--- orig/arch/um/kernel/frame_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/frame_kern.c 2003-11-19 03:32:43.000000000 -0500 +@@ -0,0 +1,174 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "asm/ptrace.h" ++#include "asm/uaccess.h" ++#include "asm/signal.h" ++#include "asm/uaccess.h" ++#include "asm/ucontext.h" ++#include "frame_kern.h" ++#include "sigcontext.h" ++#include "sysdep/ptrace.h" ++#include "choose-mode.h" ++#include "mode.h" ++ ++int copy_siginfo_to_user(siginfo_t *to, siginfo_t *from) ++{ ++ if (!access_ok (VERIFY_WRITE, to, sizeof(siginfo_t))) ++ return -EFAULT; ++ if (from->si_code < 0) ++ return __copy_to_user(to, from, sizeof(siginfo_t)); ++ else { ++ int err; ++ ++ /* If you change siginfo_t structure, please be sure ++ this code is fixed accordingly. ++ It should never copy any pad contained in the structure ++ to avoid security leaks, but must copy the generic ++ 3 ints plus the relevant union member. */ ++ err = __put_user(from->si_signo, &to->si_signo); ++ err |= __put_user(from->si_errno, &to->si_errno); ++ err |= __put_user((short)from->si_code, &to->si_code); ++ /* First 32bits of unions are always present. */ ++ err |= __put_user(from->si_pid, &to->si_pid); ++ switch (from->si_code >> 16) { ++ case __SI_FAULT >> 16: ++ break; ++ case __SI_CHLD >> 16: ++ err |= __put_user(from->si_utime, &to->si_utime); ++ err |= __put_user(from->si_stime, &to->si_stime); ++ err |= __put_user(from->si_status, &to->si_status); ++ default: ++ err |= __put_user(from->si_uid, &to->si_uid); ++ break; ++ } ++ return err; ++ } ++} ++ ++static int copy_restorer(void (*restorer)(void), unsigned long start, ++ unsigned long sr_index, int sr_relative) ++{ ++ unsigned long sr; ++ ++ if(sr_relative){ ++ sr = (unsigned long) restorer; ++ sr += start + sr_index; ++ restorer = (void (*)(void)) sr; ++ } ++ ++ return(copy_to_user((void *) (start + sr_index), &restorer, ++ sizeof(restorer))); ++} ++ ++extern int userspace_pid[]; ++ ++static int copy_sc_to_user(void *to, void *fp, struct pt_regs *from, ++ struct arch_frame_data *arch) ++{ ++ return(CHOOSE_MODE(copy_sc_to_user_tt(to, fp, UPT_SC(&from->regs), ++ arch), ++ copy_sc_to_user_skas(userspace_pid[0], to, fp, ++ &from->regs, ++ current->thread.cr2, ++ current->thread.err))); ++} ++ ++static int copy_ucontext_to_user(struct ucontext *uc, void *fp, sigset_t *set, ++ unsigned long sp) ++{ ++ int err = 0; ++ ++ err |= put_user(current->sas_ss_sp, &uc->uc_stack.ss_sp); ++ err |= put_user(sas_ss_flags(sp), &uc->uc_stack.ss_flags); ++ err |= put_user(current->sas_ss_size, &uc->uc_stack.ss_size); ++ err |= copy_sc_to_user(&uc->uc_mcontext, fp, ¤t->thread.regs, ++ &signal_frame_si.common.arch); ++ err |= copy_to_user(&uc->uc_sigmask, set, sizeof(*set)); ++ return(err); ++} ++ ++int setup_signal_stack_si(unsigned long stack_top, int sig, ++ unsigned long handler, void (*restorer)(void), ++ struct pt_regs *regs, siginfo_t *info, ++ sigset_t *mask) ++{ ++ unsigned long start; ++ void *sip, *ucp, *fp; ++ ++ start = stack_top - signal_frame_si.common.len; ++ sip = (void *) (start + signal_frame_si.si_index); ++ ucp = (void *) (start + signal_frame_si.uc_index); ++ fp = (void *) (((unsigned long) ucp) + sizeof(struct ucontext)); ++ ++ if(restorer == NULL) ++ panic("setup_signal_stack_si - no restorer"); ++ ++ if(copy_to_user((void *) start, signal_frame_si.common.data, ++ signal_frame_si.common.len) || ++ copy_to_user((void *) (start + signal_frame_si.common.sig_index), ++ &sig, sizeof(sig)) || ++ copy_siginfo_to_user(sip, info) || ++ copy_to_user((void *) (start + signal_frame_si.sip_index), &sip, ++ sizeof(sip)) || ++ copy_ucontext_to_user(ucp, fp, mask, PT_REGS_SP(regs)) || ++ copy_to_user((void *) (start + signal_frame_si.ucp_index), &ucp, ++ sizeof(ucp)) || ++ copy_restorer(restorer, start, signal_frame_si.common.sr_index, ++ signal_frame_si.common.sr_relative)) ++ return(1); ++ ++ PT_REGS_IP(regs) = handler; ++ PT_REGS_SP(regs) = start + signal_frame_si.common.sp_index; ++ return(0); ++} ++ ++int setup_signal_stack_sc(unsigned long stack_top, int sig, ++ unsigned long handler, void (*restorer)(void), ++ struct pt_regs *regs, sigset_t *mask) ++{ ++ struct frame_common *frame = &signal_frame_sc_sr.common; ++ void *user_sc; ++ int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long); ++ unsigned long sigs, sr; ++ unsigned long start = stack_top - frame->len - sig_size; ++ ++ user_sc = (void *) (start + signal_frame_sc_sr.sc_index); ++ if(restorer == NULL){ ++ frame = &signal_frame_sc.common; ++ user_sc = (void *) (start + signal_frame_sc.sc_index); ++ sr = (unsigned long) frame->data; ++ sr += frame->sr_index; ++ sr = *((unsigned long *) sr); ++ restorer = ((void (*)(void)) sr); ++ } ++ ++ sigs = start + frame->len; ++ if(copy_to_user((void *) start, frame->data, frame->len) || ++ copy_to_user((void *) (start + frame->sig_index), &sig, ++ sizeof(sig)) || ++ copy_sc_to_user(user_sc, NULL, regs, ++ &signal_frame_sc.common.arch) || ++ copy_to_user(sc_sigmask(user_sc), mask, sizeof(mask->sig[0])) || ++ copy_to_user((void *) sigs, &mask->sig[1], sig_size) || ++ copy_restorer(restorer, start, frame->sr_index, frame->sr_relative)) ++ return(1); ++ ++ PT_REGS_IP(regs) = handler; ++ PT_REGS_SP(regs) = start + frame->sp_index; ++ ++ return(0); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/gmon_syms.c um/arch/um/kernel/gmon_syms.c +--- orig/arch/um/kernel/gmon_syms.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/gmon_syms.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,20 @@ ++/* ++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/module.h" ++ ++extern void __bb_init_func(void *); ++EXPORT_SYMBOL(__bb_init_func); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/gprof_syms.c um/arch/um/kernel/gprof_syms.c +--- orig/arch/um/kernel/gprof_syms.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/gprof_syms.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,20 @@ ++/* ++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/module.h" ++ ++extern void mcount(void); ++EXPORT_SYMBOL(mcount); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/helper.c um/arch/um/kernel/helper.c +--- orig/arch/um/kernel/helper.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/helper.c 2003-11-08 07:41:30.000000000 -0500 +@@ -0,0 +1,170 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <unistd.h> ++#include <errno.h> ++#include <sched.h> ++#include <sys/signal.h> ++#include <sys/wait.h> ++#include "user.h" ++#include "kern_util.h" ++#include "os.h" ++ ++struct helper_data { ++ void (*pre_exec)(void*); ++ void *pre_data; ++ char **argv; ++ int fd; ++}; ++ ++/* Debugging aid, changed only from gdb */ ++int helper_pause = 0; ++ ++static void helper_hup(int sig) ++{ ++} ++ ++static int helper_child(void *arg) ++{ ++ struct helper_data *data = arg; ++ char **argv = data->argv; ++ int errval; ++ ++ if(helper_pause){ ++ signal(SIGHUP, helper_hup); ++ pause(); ++ } ++ if(data->pre_exec != NULL) ++ (*data->pre_exec)(data->pre_data); ++ execvp(argv[0], argv); ++ errval = errno; ++ printk("execvp of '%s' failed - errno = %d\n", argv[0], errno); ++ os_write_file(data->fd, &errval, sizeof(errval)); ++ os_kill_process(os_getpid(), 0); ++ return(0); ++} ++ ++/* XXX The alloc_stack here breaks if this is called in the tracing thread */ ++ ++int run_helper(void (*pre_exec)(void *), void *pre_data, char **argv, ++ unsigned long *stack_out) ++{ ++ struct helper_data data; ++ unsigned long stack, sp; ++ int pid, fds[2], err, n; ++ ++ if((stack_out != NULL) && (*stack_out != 0)) ++ stack = *stack_out; ++ else stack = alloc_stack(0, um_in_interrupt()); ++ if(stack == 0) ++ return(-ENOMEM); ++ ++ err = os_pipe(fds, 1, 0); ++ if(err < 0){ ++ printk("run_helper : pipe failed, err = %d\n", -err); ++ goto out_free; ++ } ++ ++ err = os_set_exec_close(fds[1], 1); ++ if(err < 0){ ++ printk("run_helper : setting FD_CLOEXEC failed, err = %d\n", ++ -err); ++ goto out_close; ++ } ++ ++ sp = stack + page_size() - sizeof(void *); ++ data.pre_exec = pre_exec; ++ data.pre_data = pre_data; ++ data.argv = argv; ++ data.fd = fds[1]; ++ pid = clone(helper_child, (void *) sp, CLONE_VM | SIGCHLD, &data); ++ if(pid < 0){ ++ printk("run_helper : clone failed, errno = %d\n", errno); ++ err = -errno; ++ goto out_close; ++ } ++ ++ os_close_file(fds[1]); ++ n = os_read_file(fds[0], &err, sizeof(err)); ++ if(n < 0){ ++ printk("run_helper : read on pipe failed, err = %d\n", -n); ++ err = n; ++ goto out_kill; ++ } ++ else if(n != 0){ ++ waitpid(pid, NULL, 0); ++ pid = -errno; ++ } ++ ++ if(stack_out == NULL) free_stack(stack, 0); ++ else *stack_out = stack; ++ return(pid); ++ ++ out_kill: ++ os_kill_process(pid, 1); ++ out_close: ++ os_close_file(fds[0]); ++ os_close_file(fds[1]); ++ out_free: ++ free_stack(stack, 0); ++ return(err); ++} ++ ++int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags, ++ unsigned long *stack_out, int stack_order) ++{ ++ unsigned long stack, sp; ++ int pid, status; ++ ++ stack = alloc_stack(stack_order, um_in_interrupt()); ++ if(stack == 0) return(-ENOMEM); ++ ++ sp = stack + (page_size() << stack_order) - sizeof(void *); ++ pid = clone(proc, (void *) sp, flags | SIGCHLD, arg); ++ if(pid < 0){ ++ printk("run_helper_thread : clone failed, errno = %d\n", ++ errno); ++ return(-errno); ++ } ++ if(stack_out == NULL){ ++ pid = waitpid(pid, &status, 0); ++ if(pid < 0){ ++ printk("run_helper_thread - wait failed, errno = %d\n", ++ errno); ++ pid = -errno; ++ } ++ if(!WIFEXITED(status) || (WEXITSTATUS(status) != 0)) ++ printk("run_helper_thread - thread returned status " ++ "0x%x\n", status); ++ free_stack(stack, stack_order); ++ } ++ else *stack_out = stack; ++ return(pid); ++} ++ ++int helper_wait(int pid, int block) ++{ ++ int ret; ++ ++ ret = waitpid(pid, NULL, WNOHANG); ++ if(ret < 0){ ++ printk("helper_wait : waitpid failed, errno = %d\n", errno); ++ return(-errno); ++ } ++ return(ret); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/initrd_kern.c um/arch/um/kernel/initrd_kern.c +--- orig/arch/um/kernel/initrd_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/initrd_kern.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,59 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/init.h" ++#include "linux/bootmem.h" ++#include "linux/blk.h" ++#include "asm/types.h" ++#include "user_util.h" ++#include "kern_util.h" ++#include "initrd.h" ++#include "init.h" ++#include "os.h" ++ ++/* Changed by uml_initrd_setup, which is a setup */ ++static char *initrd __initdata = NULL; ++ ++static int __init read_initrd(void) ++{ ++ void *area; ++ long long size; ++ int err; ++ ++ if(initrd == NULL) return 0; ++ err = os_file_size(initrd, &size); ++ if(err) return 0; ++ area = alloc_bootmem(size); ++ if(area == NULL) return 0; ++ if(load_initrd(initrd, area, size) == -1) return 0; ++ initrd_start = (unsigned long) area; ++ initrd_end = initrd_start + size; ++ return 0; ++} ++ ++__uml_postsetup(read_initrd); ++ ++static int __init uml_initrd_setup(char *line, int *add) ++{ ++ initrd = line; ++ return 0; ++} ++ ++__uml_setup("initrd=", uml_initrd_setup, ++"initrd=<initrd image>\n" ++" This is used to boot UML from an initrd image. The argument is the\n" ++" name of the file containing the image.\n\n" ++); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/initrd_user.c um/arch/um/kernel/initrd_user.c +--- orig/arch/um/kernel/initrd_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/initrd_user.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,44 @@ ++/* ++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <unistd.h> ++#include <sys/types.h> ++#include <sys/stat.h> ++#include <errno.h> ++ ++#include "user_util.h" ++#include "kern_util.h" ++#include "user.h" ++#include "initrd.h" ++#include "os.h" ++ ++int load_initrd(char *filename, void *buf, int size) ++{ ++ int fd, n; ++ ++ fd = os_open_file(filename, of_read(OPENFLAGS()), 0); ++ if(fd < 0){ ++ printk("Opening '%s' failed - err = %d\n", filename, -fd); ++ return(-1); ++ } ++ n = os_read_file(fd, buf, size); ++ if(n != size){ ++ printk("Read of %d bytes from '%s' failed, err = %d\n", size, ++ filename, -n); ++ return(-1); ++ } ++ return(0); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/init_task.c um/arch/um/kernel/init_task.c +--- orig/arch/um/kernel/init_task.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/init_task.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,61 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/config.h" ++#include "linux/mm.h" ++#include "linux/sched.h" ++#include "linux/version.h" ++#include "asm/uaccess.h" ++#include "asm/pgtable.h" ++#include "user_util.h" ++#include "mem_user.h" ++ ++static struct fs_struct init_fs = INIT_FS; ++static struct files_struct init_files = INIT_FILES; ++static struct signal_struct init_signals = INIT_SIGNALS; ++struct mm_struct init_mm = INIT_MM(init_mm); ++ ++/* ++ * Initial task structure. ++ * ++ * We need to make sure that this is 16384-byte aligned due to the ++ * way process stacks are handled. This is done by having a special ++ * "init_task" linker map entry.. ++ */ ++ ++union task_union init_task_union ++__attribute__((__section__(".data.init_task"))) = ++{ INIT_TASK(init_task_union.task) }; ++ ++struct task_struct *alloc_task_struct(void) ++{ ++ return((struct task_struct *) ++ __get_free_pages(GFP_KERNEL, CONFIG_KERNEL_STACK_ORDER)); ++} ++ ++void unprotect_stack(unsigned long stack) ++{ ++ protect_memory(stack, (1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE, ++ 1, 1, 0, 1); ++} ++ ++void free_task_struct(struct task_struct *task) ++{ ++ /* free_pages decrements the page counter and only actually frees ++ * the pages if they are now not accessed by anything. ++ */ ++ free_pages((unsigned long) task, CONFIG_KERNEL_STACK_ORDER); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/irq.c um/arch/um/kernel/irq.c +--- orig/arch/um/kernel/irq.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/irq.c 2003-12-16 22:45:27.000000000 -0500 +@@ -0,0 +1,840 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ * Derived (i.e. mostly copied) from arch/i386/kernel/irq.c: ++ * Copyright (C) 1992, 1998 Linus Torvalds, Ingo Molnar ++ */ ++ ++#include "linux/config.h" ++#include "linux/kernel.h" ++#include "linux/smp.h" ++#include "linux/irq.h" ++#include "linux/kernel_stat.h" ++#include "linux/interrupt.h" ++#include "linux/random.h" ++#include "linux/slab.h" ++#include "linux/file.h" ++#include "linux/proc_fs.h" ++#include "linux/init.h" ++#include "linux/seq_file.h" ++#include "asm/irq.h" ++#include "asm/hw_irq.h" ++#include "asm/hardirq.h" ++#include "asm/atomic.h" ++#include "asm/signal.h" ++#include "asm/system.h" ++#include "asm/errno.h" ++#include "asm/uaccess.h" ++#include "user_util.h" ++#include "kern_util.h" ++#include "irq_user.h" ++#include "irq_kern.h" ++ ++static void register_irq_proc (unsigned int irq); ++ ++irq_desc_t irq_desc[NR_IRQS] __cacheline_aligned = ++ { [0 ... NR_IRQS-1] = { 0, &no_irq_type, NULL, 0, SPIN_LOCK_UNLOCKED}}; ++ ++/* ++ * Generic no controller code ++ */ ++ ++static void enable_none(unsigned int irq) { } ++static unsigned int startup_none(unsigned int irq) { return 0; } ++static void disable_none(unsigned int irq) { } ++static void ack_none(unsigned int irq) ++{ ++/* ++ * 'what should we do if we get a hw irq event on an illegal vector'. ++ * each architecture has to answer this themselves, it doesnt deserve ++ * a generic callback i think. ++ */ ++#if CONFIG_X86 ++ printk(KERN_ERR "unexpected IRQ trap at vector %02x\n", irq); ++#ifdef CONFIG_X86_LOCAL_APIC ++ /* ++ * Currently unexpected vectors happen only on SMP and APIC. ++ * We _must_ ack these because every local APIC has only N ++ * irq slots per priority level, and a 'hanging, unacked' IRQ ++ * holds up an irq slot - in excessive cases (when multiple ++ * unexpected vectors occur) that might lock up the APIC ++ * completely. ++ */ ++ ack_APIC_irq(); ++#endif ++#endif ++} ++ ++/* startup is the same as "enable", shutdown is same as "disable" */ ++#define shutdown_none disable_none ++#define end_none enable_none ++ ++struct hw_interrupt_type no_irq_type = { ++ "none", ++ startup_none, ++ shutdown_none, ++ enable_none, ++ disable_none, ++ ack_none, ++ end_none ++}; ++ ++/* ++ * Generic, controller-independent functions: ++ */ ++ ++int get_irq_list(char *buf) ++{ ++ int i, j; ++ unsigned long flags; ++ struct irqaction * action; ++ char *p = buf; ++ ++ p += sprintf(p, " "); ++ for (j=0; j<smp_num_cpus; j++) ++ p += sprintf(p, "CPU%d ",j); ++ *p++ = '\n'; ++ ++ for (i = 0 ; i < NR_IRQS ; i++) { ++ spin_lock_irqsave(&irq_desc[i].lock, flags); ++ action = irq_desc[i].action; ++ if (!action) ++ goto end; ++ p += sprintf(p, "%3d: ",i); ++#ifndef CONFIG_SMP ++ p += sprintf(p, "%10u ", kstat_irqs(i)); ++#else ++ for (j = 0; j < smp_num_cpus; j++) ++ p += sprintf(p, "%10u ", ++ kstat.irqs[cpu_logical_map(j)][i]); ++#endif ++ p += sprintf(p, " %14s", irq_desc[i].handler->typename); ++ p += sprintf(p, " %s", action->name); ++ ++ for (action=action->next; action; action = action->next) ++ p += sprintf(p, ", %s", action->name); ++ *p++ = '\n'; ++ end: ++ spin_unlock_irqrestore(&irq_desc[i].lock, flags); ++ } ++ p += sprintf(p, "\n"); ++#ifdef notdef ++#if CONFIG_SMP ++ p += sprintf(p, "LOC: "); ++ for (j = 0; j < smp_num_cpus; j++) ++ p += sprintf(p, "%10u ", ++ apic_timer_irqs[cpu_logical_map(j)]); ++ p += sprintf(p, "\n"); ++#endif ++#endif ++ p += sprintf(p, "ERR: %10lu\n", 0L); ++ return p - buf; ++} ++ ++/* ++ * This should really return information about whether ++ * we should do bottom half handling etc. Right now we ++ * end up _always_ checking the bottom half, which is a ++ * waste of time and is not what some drivers would ++ * prefer. ++ */ ++int handle_IRQ_event(unsigned int irq, struct pt_regs * regs, ++ struct irqaction * action) ++{ ++ int status; ++ int cpu = smp_processor_id(); ++ ++ irq_enter(cpu, irq); ++ ++ status = 1; /* Force the "do bottom halves" bit */ ++ ++ if (!(action->flags & SA_INTERRUPT)) ++ __sti(); ++ ++ do { ++ status |= action->flags; ++ action->handler(irq, action->dev_id, regs); ++ action = action->next; ++ } while (action); ++ if (status & SA_SAMPLE_RANDOM) ++ add_interrupt_randomness(irq); ++ __cli(); ++ ++ irq_exit(cpu, irq); ++ ++ return status; ++} ++ ++/* ++ * Generic enable/disable code: this just calls ++ * down into the PIC-specific version for the actual ++ * hardware disable after having gotten the irq ++ * controller lock. ++ */ ++ ++/** ++ * disable_irq_nosync - disable an irq without waiting ++ * @irq: Interrupt to disable ++ * ++ * Disable the selected interrupt line. Disables of an interrupt ++ * stack. Unlike disable_irq(), this function does not ensure existing ++ * instances of the IRQ handler have completed before returning. ++ * ++ * This function may be called from IRQ context. ++ */ ++ ++void inline disable_irq_nosync(unsigned int irq) ++{ ++ irq_desc_t *desc = irq_desc + irq; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&desc->lock, flags); ++ if (!desc->depth++) { ++ desc->status |= IRQ_DISABLED; ++ desc->handler->disable(irq); ++ } ++ spin_unlock_irqrestore(&desc->lock, flags); ++} ++ ++/** ++ * disable_irq - disable an irq and wait for completion ++ * @irq: Interrupt to disable ++ * ++ * Disable the selected interrupt line. Disables of an interrupt ++ * stack. That is for two disables you need two enables. This ++ * function waits for any pending IRQ handlers for this interrupt ++ * to complete before returning. If you use this function while ++ * holding a resource the IRQ handler may need you will deadlock. ++ * ++ * This function may be called - with care - from IRQ context. ++ */ ++ ++void disable_irq(unsigned int irq) ++{ ++ disable_irq_nosync(irq); ++ ++ if (!local_irq_count(smp_processor_id())) { ++ do { ++ barrier(); ++ } while (irq_desc[irq].status & IRQ_INPROGRESS); ++ } ++} ++ ++/** ++ * enable_irq - enable interrupt handling on an irq ++ * @irq: Interrupt to enable ++ * ++ * Re-enables the processing of interrupts on this IRQ line ++ * providing no disable_irq calls are now in effect. ++ * ++ * This function may be called from IRQ context. ++ */ ++ ++void enable_irq(unsigned int irq) ++{ ++ irq_desc_t *desc = irq_desc + irq; ++ unsigned long flags; ++ ++ spin_lock_irqsave(&desc->lock, flags); ++ switch (desc->depth) { ++ case 1: { ++ unsigned int status = desc->status & ~IRQ_DISABLED; ++ desc->status = status; ++ if ((status & (IRQ_PENDING | IRQ_REPLAY)) == IRQ_PENDING) { ++ desc->status = status | IRQ_REPLAY; ++ hw_resend_irq(desc->handler,irq); ++ } ++ desc->handler->enable(irq); ++ /* fall-through */ ++ } ++ default: ++ desc->depth--; ++ break; ++ case 0: ++ printk(KERN_ERR "enable_irq() unbalanced from %p\n", ++ __builtin_return_address(0)); ++ } ++ spin_unlock_irqrestore(&desc->lock, flags); ++} ++ ++/* ++ * do_IRQ handles all normal device IRQ's (the special ++ * SMP cross-CPU interrupts have their own specific ++ * handlers). ++ */ ++unsigned int do_IRQ(int irq, union uml_pt_regs *regs) ++{ ++ /* ++ * 0 return value means that this irq is already being ++ * handled by some other CPU. (or is disabled) ++ */ ++ int cpu = smp_processor_id(); ++ irq_desc_t *desc = irq_desc + irq; ++ struct irqaction * action; ++ unsigned int status; ++ ++ kstat.irqs[cpu][irq]++; ++ spin_lock(&desc->lock); ++ desc->handler->ack(irq); ++ /* ++ REPLAY is when Linux resends an IRQ that was dropped earlier ++ WAITING is used by probe to mark irqs that are being tested ++ */ ++ status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); ++ status |= IRQ_PENDING; /* we _want_ to handle it */ ++ ++ /* ++ * If the IRQ is disabled for whatever reason, we cannot ++ * use the action we have. ++ */ ++ action = NULL; ++ if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { ++ action = desc->action; ++ status &= ~IRQ_PENDING; /* we commit to handling */ ++ status |= IRQ_INPROGRESS; /* we are handling it */ ++ } ++ desc->status = status; ++ ++ /* ++ * If there is no IRQ handler or it was disabled, exit early. ++ Since we set PENDING, if another processor is handling ++ a different instance of this same irq, the other processor ++ will take care of it. ++ */ ++ if (!action) ++ goto out; ++ ++ /* ++ * Edge triggered interrupts need to remember ++ * pending events. ++ * This applies to any hw interrupts that allow a second ++ * instance of the same irq to arrive while we are in do_IRQ ++ * or in the handler. But the code here only handles the _second_ ++ * instance of the irq, not the third or fourth. So it is mostly ++ * useful for irq hardware that does not mask cleanly in an ++ * SMP environment. ++ */ ++ for (;;) { ++ spin_unlock(&desc->lock); ++ handle_IRQ_event(irq, (struct pt_regs *) regs, action); ++ spin_lock(&desc->lock); ++ ++ if (!(desc->status & IRQ_PENDING)) ++ break; ++ desc->status &= ~IRQ_PENDING; ++ } ++ desc->status &= ~IRQ_INPROGRESS; ++out: ++ /* ++ * The ->end() handler has to deal with interrupts which got ++ * disabled while the handler was running. ++ */ ++ desc->handler->end(irq); ++ spin_unlock(&desc->lock); ++ ++ if (softirq_pending(cpu)) ++ do_softirq(); ++ return 1; ++} ++ ++/** ++ * request_irq - allocate an interrupt line ++ * @irq: Interrupt line to allocate ++ * @handler: Function to be called when the IRQ occurs ++ * @irqflags: Interrupt type flags ++ * @devname: An ascii name for the claiming device ++ * @dev_id: A cookie passed back to the handler function ++ * ++ * This call allocates interrupt resources and enables the ++ * interrupt line and IRQ handling. From the point this ++ * call is made your handler function may be invoked. Since ++ * your handler function must clear any interrupt the board ++ * raises, you must take care both to initialise your hardware ++ * and to set up the interrupt handler in the right order. ++ * ++ * Dev_id must be globally unique. Normally the address of the ++ * device data structure is used as the cookie. Since the handler ++ * receives this value it makes sense to use it. ++ * ++ * If your interrupt is shared you must pass a non NULL dev_id ++ * as this is required when freeing the interrupt. ++ * ++ * Flags: ++ * ++ * SA_SHIRQ Interrupt is shared ++ * ++ * SA_INTERRUPT Disable local interrupts while processing ++ * ++ * SA_SAMPLE_RANDOM The interrupt can be used for entropy ++ * ++ */ ++ ++int request_irq(unsigned int irq, ++ void (*handler)(int, void *, struct pt_regs *), ++ unsigned long irqflags, ++ const char * devname, ++ void *dev_id) ++{ ++ int retval; ++ struct irqaction * action; ++ ++#if 1 ++ /* ++ * Sanity-check: shared interrupts should REALLY pass in ++ * a real dev-ID, otherwise we'll have trouble later trying ++ * to figure out which interrupt is which (messes up the ++ * interrupt freeing logic etc). ++ */ ++ if (irqflags & SA_SHIRQ) { ++ if (!dev_id) ++ printk(KERN_ERR "Bad boy: %s (at 0x%x) called us " ++ "without a dev_id!\n", devname, (&irq)[-1]); ++ } ++#endif ++ ++ if (irq >= NR_IRQS) ++ return -EINVAL; ++ if (!handler) ++ return -EINVAL; ++ ++ action = (struct irqaction *) ++ kmalloc(sizeof(struct irqaction), GFP_KERNEL); ++ if (!action) ++ return -ENOMEM; ++ ++ action->handler = handler; ++ action->flags = irqflags; ++ action->mask = 0; ++ action->name = devname; ++ action->next = NULL; ++ action->dev_id = dev_id; ++ ++ retval = setup_irq(irq, action); ++ if (retval) ++ kfree(action); ++ return retval; ++} ++ ++int um_request_irq(unsigned int irq, int fd, int type, ++ void (*handler)(int, void *, struct pt_regs *), ++ unsigned long irqflags, const char * devname, ++ void *dev_id) ++{ ++ int err; ++ ++ err = request_irq(irq, handler, irqflags, devname, dev_id); ++ if(err) ++ return(err); ++ ++ if(fd != -1) ++ err = activate_fd(irq, fd, type, dev_id); ++ return(err); ++} ++ ++/* this was setup_x86_irq but it seems pretty generic */ ++int setup_irq(unsigned int irq, struct irqaction * new) ++{ ++ int shared = 0; ++ unsigned long flags; ++ struct irqaction *old, **p; ++ irq_desc_t *desc = irq_desc + irq; ++ ++ /* ++ * Some drivers like serial.c use request_irq() heavily, ++ * so we have to be careful not to interfere with a ++ * running system. ++ */ ++ if (new->flags & SA_SAMPLE_RANDOM) { ++ /* ++ * This function might sleep, we want to call it first, ++ * outside of the atomic block. ++ * Yes, this might clear the entropy pool if the wrong ++ * driver is attempted to be loaded, without actually ++ * installing a new handler, but is this really a problem, ++ * only the sysadmin is able to do this. ++ */ ++ rand_initialize_irq(irq); ++ } ++ ++ /* ++ * The following block of code has to be executed atomically ++ */ ++ spin_lock_irqsave(&desc->lock,flags); ++ p = &desc->action; ++ old = *p; ++ if (old != NULL) { ++ /* Can't share interrupts unless both agree to */ ++ if (!(old->flags & new->flags & SA_SHIRQ)) { ++ spin_unlock_irqrestore(&desc->lock,flags); ++ return -EBUSY; ++ } ++ ++ /* add new interrupt at end of irq queue */ ++ do { ++ p = &old->next; ++ old = *p; ++ } while (old); ++ shared = 1; ++ } ++ ++ *p = new; ++ ++ if (!shared) { ++ desc->depth = 0; ++ desc->status &= ~IRQ_DISABLED; ++ desc->handler->startup(irq); ++ } ++ spin_unlock_irqrestore(&desc->lock,flags); ++ ++ register_irq_proc(irq); ++ return 0; ++} ++ ++/** ++ * free_irq - free an interrupt ++ * @irq: Interrupt line to free ++ * @dev_id: Device identity to free ++ * ++ * Remove an interrupt handler. The handler is removed and if the ++ * interrupt line is no longer in use by any driver it is disabled. ++ * On a shared IRQ the caller must ensure the interrupt is disabled ++ * on the card it drives before calling this function. The function ++ * does not return until any executing interrupts for this IRQ ++ * have completed. ++ * ++ * This function may be called from interrupt context. ++ * ++ * Bugs: Attempting to free an irq in a handler for the same irq hangs ++ * the machine. ++ */ ++ ++void free_irq(unsigned int irq, void *dev_id) ++{ ++ irq_desc_t *desc; ++ struct irqaction **p; ++ unsigned long flags; ++ ++ if (irq >= NR_IRQS) ++ return; ++ ++ desc = irq_desc + irq; ++ spin_lock_irqsave(&desc->lock,flags); ++ p = &desc->action; ++ for (;;) { ++ struct irqaction * action = *p; ++ if (action) { ++ struct irqaction **pp = p; ++ p = &action->next; ++ if (action->dev_id != dev_id) ++ continue; ++ ++ /* Found it - now remove it from the list of entries */ ++ *pp = action->next; ++ if (!desc->action) { ++ desc->status |= IRQ_DISABLED; ++ desc->handler->shutdown(irq); ++ } ++ free_irq_by_irq_and_dev(irq, dev_id); ++ spin_unlock_irqrestore(&desc->lock,flags); ++ ++#ifdef CONFIG_SMP ++ /* Wait to make sure it's not being used on another CPU */ ++ while (desc->status & IRQ_INPROGRESS) ++ barrier(); ++#endif ++ kfree(action); ++ return; ++ } ++ printk(KERN_ERR "Trying to free free IRQ%d\n",irq); ++ spin_unlock_irqrestore(&desc->lock,flags); ++ return; ++ } ++} ++ ++/* These are initialized by sysctl_init, which is called from init/main.c */ ++static struct proc_dir_entry * root_irq_dir; ++static struct proc_dir_entry * irq_dir [NR_IRQS]; ++static struct proc_dir_entry * smp_affinity_entry [NR_IRQS]; ++ ++/* These are read and written as longs, so a read won't see a partial write ++ * even during a race. ++ */ ++static unsigned long irq_affinity [NR_IRQS] = { [0 ... NR_IRQS-1] = ~0UL }; ++ ++#define HEX_DIGITS 8 ++ ++static int irq_affinity_read_proc (char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ if (count < HEX_DIGITS+1) ++ return -EINVAL; ++ return sprintf (page, "%08lx\n", irq_affinity[(long)data]); ++} ++ ++static unsigned int parse_hex_value (const char *buffer, ++ unsigned long count, unsigned long *ret) ++{ ++ unsigned char hexnum [HEX_DIGITS]; ++ unsigned long value; ++ int i; ++ ++ if (!count) ++ return -EINVAL; ++ if (count > HEX_DIGITS) ++ count = HEX_DIGITS; ++ if (copy_from_user(hexnum, buffer, count)) ++ return -EFAULT; ++ ++ /* ++ * Parse the first HEX_DIGITS characters as a hex string, any non-hex ++ * char is end-of-string. '00e1', 'e1', '00E1', 'E1' are all the same. ++ */ ++ value = 0; ++ ++ for (i = 0; i < count; i++) { ++ unsigned int c = hexnum[i]; ++ ++ switch (c) { ++ case '0' ... '9': c -= '0'; break; ++ case 'a' ... 'f': c -= 'a'-10; break; ++ case 'A' ... 'F': c -= 'A'-10; break; ++ default: ++ goto out; ++ } ++ value = (value << 4) | c; ++ } ++out: ++ *ret = value; ++ return 0; ++} ++ ++static int irq_affinity_write_proc (struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ int irq = (long) data, full_count = count, err; ++ unsigned long new_value; ++ ++ if (!irq_desc[irq].handler->set_affinity) ++ return -EIO; ++ ++ err = parse_hex_value(buffer, count, &new_value); ++ ++#if CONFIG_SMP ++ /* ++ * Do not allow disabling IRQs completely - it's a too easy ++ * way to make the system unusable accidentally :-) At least ++ * one online CPU still has to be targeted. ++ */ ++ if (!(new_value & cpu_online_map)) ++ return -EINVAL; ++#endif ++ ++ irq_affinity[irq] = new_value; ++ irq_desc[irq].handler->set_affinity(irq, new_value); ++ ++ return full_count; ++} ++ ++static int prof_cpu_mask_read_proc (char *page, char **start, off_t off, ++ int count, int *eof, void *data) ++{ ++ unsigned long *mask = (unsigned long *) data; ++ if (count < HEX_DIGITS+1) ++ return -EINVAL; ++ return sprintf (page, "%08lx\n", *mask); ++} ++ ++static int prof_cpu_mask_write_proc (struct file *file, const char *buffer, ++ unsigned long count, void *data) ++{ ++ unsigned long *mask = (unsigned long *) data, full_count = count, err; ++ unsigned long new_value; ++ ++ err = parse_hex_value(buffer, count, &new_value); ++ if (err) ++ return err; ++ ++ *mask = new_value; ++ return full_count; ++} ++ ++#define MAX_NAMELEN 10 ++ ++static void register_irq_proc (unsigned int irq) ++{ ++ struct proc_dir_entry *entry; ++ char name [MAX_NAMELEN]; ++ ++ if (!root_irq_dir || (irq_desc[irq].handler == &no_irq_type) || ++ irq_dir[irq]) ++ return; ++ ++ memset(name, 0, MAX_NAMELEN); ++ sprintf(name, "%d", irq); ++ ++ /* create /proc/irq/1234 */ ++ irq_dir[irq] = proc_mkdir(name, root_irq_dir); ++ ++ /* create /proc/irq/1234/smp_affinity */ ++ entry = create_proc_entry("smp_affinity", 0600, irq_dir[irq]); ++ ++ entry->nlink = 1; ++ entry->data = (void *)(long)irq; ++ entry->read_proc = irq_affinity_read_proc; ++ entry->write_proc = irq_affinity_write_proc; ++ ++ smp_affinity_entry[irq] = entry; ++} ++ ++/* Read and written as a long */ ++unsigned long prof_cpu_mask = -1; ++ ++void __init init_irq_proc (void) ++{ ++ struct proc_dir_entry *entry; ++ int i; ++ ++ /* create /proc/irq */ ++ root_irq_dir = proc_mkdir("irq", 0); ++ ++ /* create /proc/irq/prof_cpu_mask */ ++ entry = create_proc_entry("prof_cpu_mask", 0600, root_irq_dir); ++ ++ entry->nlink = 1; ++ entry->data = (void *)&prof_cpu_mask; ++ entry->read_proc = prof_cpu_mask_read_proc; ++ entry->write_proc = prof_cpu_mask_write_proc; ++ ++ /* ++ * Create entries for all existing IRQs. ++ */ ++ for (i = 0; i < NR_IRQS; i++) ++ register_irq_proc(i); ++} ++ ++static spinlock_t irq_spinlock = SPIN_LOCK_UNLOCKED; ++ ++unsigned long irq_lock(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&irq_spinlock, flags); ++ return(flags); ++} ++ ++void irq_unlock(unsigned long flags) ++{ ++ spin_unlock_irqrestore(&irq_spinlock, flags); ++} ++ ++unsigned long probe_irq_on(void) ++{ ++ return(0); ++} ++ ++int probe_irq_off(unsigned long val) ++{ ++ return(0); ++} ++ ++static unsigned int startup_SIGIO_irq(unsigned int irq) ++{ ++ return(0); ++} ++ ++static void shutdown_SIGIO_irq(unsigned int irq) ++{ ++} ++ ++static void enable_SIGIO_irq(unsigned int irq) ++{ ++} ++ ++static void disable_SIGIO_irq(unsigned int irq) ++{ ++} ++ ++static void mask_and_ack_SIGIO(unsigned int irq) ++{ ++} ++ ++static void end_SIGIO_irq(unsigned int irq) ++{ ++} ++ ++static unsigned int startup_SIGVTALRM_irq(unsigned int irq) ++{ ++ return(0); ++} ++ ++static void shutdown_SIGVTALRM_irq(unsigned int irq) ++{ ++} ++ ++static void enable_SIGVTALRM_irq(unsigned int irq) ++{ ++} ++ ++static void disable_SIGVTALRM_irq(unsigned int irq) ++{ ++} ++ ++static void mask_and_ack_SIGVTALRM(unsigned int irq) ++{ ++} ++ ++static void end_SIGVTALRM_irq(unsigned int irq) ++{ ++} ++ ++static struct hw_interrupt_type SIGIO_irq_type = { ++ "SIGIO", ++ startup_SIGIO_irq, ++ shutdown_SIGIO_irq, ++ enable_SIGIO_irq, ++ disable_SIGIO_irq, ++ mask_and_ack_SIGIO, ++ end_SIGIO_irq, ++ NULL ++}; ++ ++static struct hw_interrupt_type SIGVTALRM_irq_type = { ++ "SIGVTALRM", ++ startup_SIGVTALRM_irq, ++ shutdown_SIGVTALRM_irq, ++ enable_SIGVTALRM_irq, ++ disable_SIGVTALRM_irq, ++ mask_and_ack_SIGVTALRM, ++ end_SIGVTALRM_irq, ++ NULL ++}; ++ ++void __init init_IRQ(void) ++{ ++ int i; ++ ++ irq_desc[TIMER_IRQ].status = IRQ_DISABLED; ++ irq_desc[TIMER_IRQ].action = 0; ++ irq_desc[TIMER_IRQ].depth = 1; ++ irq_desc[TIMER_IRQ].handler = &SIGVTALRM_irq_type; ++ enable_irq(TIMER_IRQ); ++ for(i=1;i<NR_IRQS;i++){ ++ irq_desc[i].status = IRQ_DISABLED; ++ irq_desc[i].action = 0; ++ irq_desc[i].depth = 1; ++ irq_desc[i].handler = &SIGIO_irq_type; ++ enable_irq(i); ++ } ++ init_irq_signals(0); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/irq_user.c um/arch/um/kernel/irq_user.c +--- orig/arch/um/kernel/irq_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/irq_user.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,424 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdlib.h> ++#include <unistd.h> ++#include <errno.h> ++#include <signal.h> ++#include <string.h> ++#include <sys/poll.h> ++#include <sys/types.h> ++#include <sys/time.h> ++#include "user_util.h" ++#include "kern_util.h" ++#include "user.h" ++#include "process.h" ++#include "signal_user.h" ++#include "sigio.h" ++#include "irq_user.h" ++#include "os.h" ++ ++struct irq_fd { ++ struct irq_fd *next; ++ void *id; ++ int fd; ++ int type; ++ int irq; ++ int pid; ++ int events; ++ int current_events; ++ int freed; ++}; ++ ++static struct irq_fd *active_fds = NULL; ++static struct irq_fd **last_irq_ptr = &active_fds; ++ ++static struct pollfd *pollfds = NULL; ++static int pollfds_num = 0; ++static int pollfds_size = 0; ++ ++extern int io_count, intr_count; ++ ++void sigio_handler(int sig, union uml_pt_regs *regs) ++{ ++ struct irq_fd *irq_fd, *next; ++ int i, n; ++ ++ if(smp_sigio_handler()) return; ++ while(1){ ++ n = poll(pollfds, pollfds_num, 0); ++ if(n < 0){ ++ if(errno == EINTR) continue; ++ printk("sigio_handler : poll returned %d, " ++ "errno = %d\n", n, errno); ++ break; ++ } ++ if(n == 0) break; ++ ++ irq_fd = active_fds; ++ for(i = 0; i < pollfds_num; i++){ ++ if(pollfds[i].revents != 0){ ++ irq_fd->current_events = pollfds[i].revents; ++ pollfds[i].fd = -1; ++ } ++ irq_fd = irq_fd->next; ++ } ++ ++ for(irq_fd = active_fds; irq_fd != NULL; irq_fd = next){ ++ next = irq_fd->next; ++ if(irq_fd->current_events != 0){ ++ irq_fd->current_events = 0; ++ do_IRQ(irq_fd->irq, regs); ++ ++ /* This is here because the next irq may be ++ * freed in the handler. If a console goes ++ * away, both the read and write irqs will be ++ * freed. After do_IRQ, ->next will point to ++ * a good IRQ. ++ * Irqs can't be freed inside their handlers, ++ * so the next best thing is to have them ++ * marked as needing freeing, so that they ++ * can be freed here. ++ */ ++ next = irq_fd->next; ++ if(irq_fd->freed) ++ free_irq(irq_fd->irq, irq_fd->id); ++ } ++ } ++ } ++} ++ ++int activate_ipi(int fd, int pid) ++{ ++ return(os_set_fd_async(fd, pid)); ++} ++ ++static void maybe_sigio_broken(int fd, int type) ++{ ++ if(isatty(fd)){ ++ if((type == IRQ_WRITE) && !pty_output_sigio){ ++ write_sigio_workaround(); ++ add_sigio_fd(fd, 0); ++ } ++ else if((type == IRQ_READ) && !pty_close_sigio){ ++ write_sigio_workaround(); ++ add_sigio_fd(fd, 1); ++ } ++ } ++} ++ ++int activate_fd(int irq, int fd, int type, void *dev_id) ++{ ++ struct pollfd *tmp_pfd; ++ struct irq_fd *new_fd, *irq_fd; ++ unsigned long flags; ++ int pid, events, err, n, size; ++ ++ pid = os_getpid(); ++ err = os_set_fd_async(fd, pid); ++ if(err < 0) ++ goto out; ++ ++ new_fd = um_kmalloc(sizeof(*new_fd)); ++ err = -ENOMEM; ++ if(new_fd == NULL) ++ goto out; ++ ++ if(type == IRQ_READ) events = POLLIN | POLLPRI; ++ else events = POLLOUT; ++ *new_fd = ((struct irq_fd) { .next = NULL, ++ .id = dev_id, ++ .fd = fd, ++ .type = type, ++ .irq = irq, ++ .pid = pid, ++ .events = events, ++ .current_events = 0, ++ .freed = 0 } ); ++ ++ /* Critical section - locked by a spinlock because this stuff can ++ * be changed from interrupt handlers. The stuff above is done ++ * outside the lock because it allocates memory. ++ */ ++ ++ /* Actually, it only looks like it can be called from interrupt ++ * context. The culprit is reactivate_fd, which calls ++ * maybe_sigio_broken, which calls write_sigio_workaround, ++ * which calls activate_fd. However, write_sigio_workaround should ++ * only be called once, at boot time. That would make it clear that ++ * this is called only from process context, and can be locked with ++ * a semaphore. ++ */ ++ flags = irq_lock(); ++ for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){ ++ if((irq_fd->fd == fd) && (irq_fd->type == type)){ ++ printk("Registering fd %d twice\n", fd); ++ printk("Irqs : %d, %d\n", irq_fd->irq, irq); ++ printk("Ids : 0x%x, 0x%x\n", irq_fd->id, dev_id); ++ goto out_unlock; ++ } ++ } ++ ++ n = pollfds_num; ++ if(n == pollfds_size){ ++ while(1){ ++ /* Here we have to drop the lock in order to call ++ * kmalloc, which might sleep. If something else ++ * came in and changed the pollfds array, we free ++ * the buffer and try again. ++ */ ++ irq_unlock(flags); ++ size = (pollfds_num + 1) * sizeof(pollfds[0]); ++ tmp_pfd = um_kmalloc(size); ++ flags = irq_lock(); ++ if(tmp_pfd == NULL) ++ goto out_unlock; ++ if(n == pollfds_size) ++ break; ++ kfree(tmp_pfd); ++ } ++ if(pollfds != NULL){ ++ memcpy(tmp_pfd, pollfds, ++ sizeof(pollfds[0]) * pollfds_size); ++ kfree(pollfds); ++ } ++ pollfds = tmp_pfd; ++ pollfds_size++; ++ } ++ ++ if(type == IRQ_WRITE) ++ fd = -1; ++ ++ pollfds[pollfds_num] = ((struct pollfd) { .fd = fd, ++ .events = events, ++ .revents = 0 }); ++ pollfds_num++; ++ ++ *last_irq_ptr = new_fd; ++ last_irq_ptr = &new_fd->next; ++ ++ irq_unlock(flags); ++ ++ /* This calls activate_fd, so it has to be outside the critical ++ * section. ++ */ ++ maybe_sigio_broken(fd, type); ++ ++ return(0); ++ ++ out_unlock: ++ irq_unlock(flags); ++ kfree(new_fd); ++ out: ++ return(err); ++} ++ ++static void free_irq_by_cb(int (*test)(struct irq_fd *, void *), void *arg) ++{ ++ struct irq_fd **prev; ++ unsigned long flags; ++ int i = 0; ++ ++ flags = irq_lock(); ++ prev = &active_fds; ++ while(*prev != NULL){ ++ if((*test)(*prev, arg)){ ++ struct irq_fd *old_fd = *prev; ++ if((pollfds[i].fd != -1) && ++ (pollfds[i].fd != (*prev)->fd)){ ++ printk("free_irq_by_cb - mismatch between " ++ "active_fds and pollfds, fd %d vs %d\n", ++ (*prev)->fd, pollfds[i].fd); ++ goto out; ++ } ++ memcpy(&pollfds[i], &pollfds[i + 1], ++ (pollfds_num - i - 1) * sizeof(pollfds[0])); ++ pollfds_num--; ++ if(last_irq_ptr == &old_fd->next) ++ last_irq_ptr = prev; ++ *prev = (*prev)->next; ++ if(old_fd->type == IRQ_WRITE) ++ ignore_sigio_fd(old_fd->fd); ++ kfree(old_fd); ++ continue; ++ } ++ prev = &(*prev)->next; ++ i++; ++ } ++ out: ++ irq_unlock(flags); ++} ++ ++struct irq_and_dev { ++ int irq; ++ void *dev; ++}; ++ ++static int same_irq_and_dev(struct irq_fd *irq, void *d) ++{ ++ struct irq_and_dev *data = d; ++ ++ return((irq->irq == data->irq) && (irq->id == data->dev)); ++} ++ ++void free_irq_by_irq_and_dev(int irq, void *dev) ++{ ++ struct irq_and_dev data = ((struct irq_and_dev) { .irq = irq, ++ .dev = dev }); ++ ++ free_irq_by_cb(same_irq_and_dev, &data); ++} ++ ++static int same_fd(struct irq_fd *irq, void *fd) ++{ ++ return(irq->fd == *((int *) fd)); ++} ++ ++void free_irq_by_fd(int fd) ++{ ++ free_irq_by_cb(same_fd, &fd); ++} ++ ++static struct irq_fd *find_irq_by_fd(int fd, int irqnum, int *index_out) ++{ ++ struct irq_fd *irq; ++ int i = 0; ++ ++ for(irq=active_fds; irq != NULL; irq = irq->next){ ++ if((irq->fd == fd) && (irq->irq == irqnum)) break; ++ i++; ++ } ++ if(irq == NULL){ ++ printk("find_irq_by_fd doesn't have descriptor %d\n", fd); ++ goto out; ++ } ++ if((pollfds[i].fd != -1) && (pollfds[i].fd != fd)){ ++ printk("find_irq_by_fd - mismatch between active_fds and " ++ "pollfds, fd %d vs %d, need %d\n", irq->fd, ++ pollfds[i].fd, fd); ++ irq = NULL; ++ goto out; ++ } ++ *index_out = i; ++ out: ++ return(irq); ++} ++ ++void free_irq_later(int irq, void *dev_id) ++{ ++ struct irq_fd *irq_fd; ++ unsigned long flags; ++ ++ flags = irq_lock(); ++ for(irq_fd = active_fds; irq_fd != NULL; irq_fd = irq_fd->next){ ++ if((irq_fd->irq == irq) && (irq_fd->id == dev_id)) ++ break; ++ } ++ if(irq_fd == NULL){ ++ printk("free_irq_later found no irq, irq = %d, " ++ "dev_id = 0x%p\n", irq, dev_id); ++ goto out; ++ } ++ irq_fd->freed = 1; ++ out: ++ irq_unlock(flags); ++} ++ ++void reactivate_fd(int fd, int irqnum) ++{ ++ struct irq_fd *irq; ++ unsigned long flags; ++ int i; ++ ++ flags = irq_lock(); ++ irq = find_irq_by_fd(fd, irqnum, &i); ++ if(irq == NULL){ ++ irq_unlock(flags); ++ return; ++ } ++ ++ pollfds[i].fd = irq->fd; ++ ++ irq_unlock(flags); ++ ++ /* This calls activate_fd, so it has to be outside the critical ++ * section. ++ */ ++ maybe_sigio_broken(fd, irq->type); ++} ++ ++void deactivate_fd(int fd, int irqnum) ++{ ++ struct irq_fd *irq; ++ unsigned long flags; ++ int i; ++ ++ flags = irq_lock(); ++ irq = find_irq_by_fd(fd, irqnum, &i); ++ if(irq == NULL) ++ goto out; ++ pollfds[i].fd = -1; ++ out: ++ irq_unlock(flags); ++} ++ ++void forward_ipi(int fd, int pid) ++{ ++ int err; ++ ++ err = os_set_owner(fd, pid); ++ if(err < 0) ++ printk("forward_ipi: set_owner failed, fd = %d, me = %d, " ++ "target = %d, err = %d\n", fd, os_getpid(), pid, -err); ++} ++ ++void forward_interrupts(int pid) ++{ ++ struct irq_fd *irq; ++ unsigned long flags; ++ int err; ++ ++ flags = irq_lock(); ++ for(irq=active_fds;irq != NULL;irq = irq->next){ ++ err = os_set_owner(irq->fd, pid); ++ if(err < 0){ ++ /* XXX Just remove the irq rather than ++ * print out an infinite stream of these ++ */ ++ printk("Failed to forward %d to pid %d, err = %d\n", ++ irq->fd, pid, -err); ++ } ++ ++ irq->pid = pid; ++ } ++ irq_unlock(flags); ++} ++ ++void init_irq_signals(int on_sigstack) ++{ ++ __sighandler_t h; ++ int flags; ++ ++ flags = on_sigstack ? SA_ONSTACK : 0; ++ if(timer_irq_inited) h = (__sighandler_t) alarm_handler; ++ else h = boot_timer_handler; ++ ++ set_handler(SIGVTALRM, h, flags | SA_RESTART, ++ SIGUSR1, SIGIO, SIGWINCH, SIGALRM, -1); ++ set_handler(SIGIO, (__sighandler_t) sig_handler, flags | SA_RESTART, ++ SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); ++ signal(SIGWINCH, SIG_IGN); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/ksyms.c um/arch/um/kernel/ksyms.c +--- orig/arch/um/kernel/ksyms.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/ksyms.c 2003-12-17 03:22:37.000000000 -0500 +@@ -0,0 +1,119 @@ ++/* ++ * Copyright (C) 2001 - 2003 Jeff Dike (jdike@addtoit.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/config.h" ++#include "linux/module.h" ++#include "linux/string.h" ++#include "linux/smp_lock.h" ++#include "linux/spinlock.h" ++#include "asm/current.h" ++#include "asm/delay.h" ++#include "asm/processor.h" ++#include "asm/unistd.h" ++#include "asm/pgalloc.h" ++#include "asm/pgtable.h" ++#include "asm/page.h" ++#include "kern_util.h" ++#include "user_util.h" ++#include "os.h" ++#include "helper.h" ++ ++EXPORT_SYMBOL(stop); ++EXPORT_SYMBOL(strtok); ++EXPORT_SYMBOL(uml_physmem); ++EXPORT_SYMBOL(set_signals); ++EXPORT_SYMBOL(get_signals); ++EXPORT_SYMBOL(kernel_thread); ++EXPORT_SYMBOL(__const_udelay); ++EXPORT_SYMBOL(__udelay); ++EXPORT_SYMBOL(sys_waitpid); ++EXPORT_SYMBOL(task_size); ++EXPORT_SYMBOL(flush_tlb_range); ++EXPORT_SYMBOL(host_task_size); ++EXPORT_SYMBOL(arch_validate); ++EXPORT_SYMBOL(get_kmem_end); ++ ++EXPORT_SYMBOL(high_physmem); ++EXPORT_SYMBOL(empty_zero_page); ++EXPORT_SYMBOL(um_virt_to_phys); ++EXPORT_SYMBOL(__virt_to_page); ++EXPORT_SYMBOL(to_phys); ++EXPORT_SYMBOL(to_virt); ++EXPORT_SYMBOL(mode_tt); ++EXPORT_SYMBOL(handle_page_fault); ++ ++#ifdef CONFIG_MODE_TT ++EXPORT_SYMBOL(copy_from_user_tt); ++EXPORT_SYMBOL(copy_to_user_tt); ++#endif ++ ++#ifdef CONFIG_MODE_SKAS ++EXPORT_SYMBOL(copy_to_user_skas); ++EXPORT_SYMBOL(copy_from_user_skas); ++#endif ++ ++EXPORT_SYMBOL(os_stat_fd); ++EXPORT_SYMBOL(os_stat_file); ++EXPORT_SYMBOL(os_access); ++EXPORT_SYMBOL(os_print_error); ++EXPORT_SYMBOL(os_get_exec_close); ++EXPORT_SYMBOL(os_set_exec_close); ++EXPORT_SYMBOL(os_getpid); ++EXPORT_SYMBOL(os_open_file); ++EXPORT_SYMBOL(os_read_file); ++EXPORT_SYMBOL(os_write_file); ++EXPORT_SYMBOL(os_seek_file); ++EXPORT_SYMBOL(os_lock_file); ++EXPORT_SYMBOL(os_pipe); ++EXPORT_SYMBOL(os_file_type); ++EXPORT_SYMBOL(os_file_mode); ++EXPORT_SYMBOL(os_file_size); ++EXPORT_SYMBOL(os_flush_stdout); ++EXPORT_SYMBOL(os_close_file); ++EXPORT_SYMBOL(os_set_fd_async); ++EXPORT_SYMBOL(os_set_fd_block); ++EXPORT_SYMBOL(helper_wait); ++EXPORT_SYMBOL(os_shutdown_socket); ++EXPORT_SYMBOL(os_create_unix_socket); ++EXPORT_SYMBOL(os_connect_socket); ++EXPORT_SYMBOL(os_accept_connection); ++EXPORT_SYMBOL(os_rcv_fd); ++EXPORT_SYMBOL(run_helper); ++EXPORT_SYMBOL(start_thread); ++EXPORT_SYMBOL(dump_thread); ++ ++/* This is here because UML expands open to sys_open, not to a system ++ * call instruction. ++ */ ++EXPORT_SYMBOL(sys_open); ++EXPORT_SYMBOL(sys_lseek); ++EXPORT_SYMBOL(sys_read); ++EXPORT_SYMBOL(sys_wait4); ++ ++#ifdef CONFIG_SMP ++ ++/* required for SMP */ ++ ++extern void FASTCALL( __write_lock_failed(rwlock_t *rw)); ++EXPORT_SYMBOL_NOVERS(__write_lock_failed); ++ ++extern void FASTCALL( __read_lock_failed(rwlock_t *rw)); ++EXPORT_SYMBOL_NOVERS(__read_lock_failed); ++ ++EXPORT_SYMBOL(kernel_flag_cacheline); ++EXPORT_SYMBOL(smp_num_cpus); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/Makefile um/arch/um/kernel/Makefile +--- orig/arch/um/kernel/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/Makefile 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,73 @@ ++# ++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++# Licensed under the GPL ++# ++ ++O_TARGET = built-in.o ++ ++obj-y = config.o checksum.o exec_kern.o exitcode.o frame_kern.o frame.o \ ++ helper.o init_task.o irq.o irq_user.o ksyms.o mem.o mem_user.o \ ++ physmem.o process.o process_kern.o ptrace.o reboot.o resource.o \ ++ sigio_user.o sigio_kern.o signal_kern.o signal_user.o smp.o \ ++ syscall_kern.o syscall_user.o sysrq.o sys_call_table.o tempfile.o \ ++ time.o time_kern.o tlb.o trap_kern.o trap_user.o uaccess_user.o \ ++ um_arch.o umid.o user_syms.o user_util.o ++ ++obj-$(CONFIG_BLK_DEV_INITRD) += initrd_kern.o initrd_user.o ++obj-$(CONFIG_GPROF) += gprof_syms.o ++obj-$(CONFIG_GCOV) += gmon_syms.o ++obj-$(CONFIG_TTY_LOG) += tty_log.o ++ ++subdir-$(CONFIG_MODE_TT) += tt ++subdir-$(CONFIG_MODE_SKAS) += skas ++ ++user-objs-$(CONFIG_TTY_LOG) += tty_log.o ++ ++obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o)) ++ ++# user_syms.o not included here because Rules.make has its own ideas about ++# building anything in export-objs ++ ++USER_OBJS = $(filter %_user.o,$(obj-y)) $(user-objs-y) config.o helper.o \ ++ process.o tempfile.o time.o umid.o user_util.o ++ ++DMODULES-$(CONFIG_MODULES) = -D__CONFIG_MODULES__ ++DMODVERSIONS-$(CONFIG_MODVERSIONS) = -D__CONFIG_MODVERSIONS__ ++ ++export-objs-$(CONFIG_GPROF) += gprof_syms.o ++export-objs-$(CONFIG_GCOV) += gmon_syms.o ++ ++export-objs = ksyms.o process_kern.o signal_kern.o user_syms.o $(export-objs-y) ++ ++CFLAGS_user_syms.o = -D__AUTOCONF_INCLUDED__ $(DMODULES-y) $(DMODVERSIONS-y) \ ++ -I/usr/include -I../include ++ ++CFLAGS_frame.o := $(patsubst -fomit-frame-pointer,,$(USER_CFLAGS)) ++ ++include $(TOPDIR)/Rules.make ++ ++$(USER_OBJS) : %.o: %.c ++ $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< ++ ++# This has to be separate because it needs be compiled with frame pointers ++# regardless of how the rest of the kernel is built. ++ ++frame.o: frame.c ++ $(CC) $(CFLAGS_$@) -c -o $@ $< ++ ++QUOTE = 'my $$config=`cat $(TOPDIR)/.config`; $$config =~ s/"/\\"/g ; $$config =~ s/\n/\\n"\n"/g ; while(<STDIN>) { $$_ =~ s/CONFIG/$$config/; print $$_ }' ++ ++config.c : config.c.in $(TOPDIR)/.config ++ $(PERL) -e $(QUOTE) < config.c.in > $@ ++ ++clean: ++ $(RM) config.c ++ for dir in $(subdir-y) ; do $(MAKE) -C $$dir clean; done ++ ++modules: ++ ++fastdep: ++ ++dep: ++ ++archmrproper: clean +diff -Naur -X ../exclude-files orig/arch/um/kernel/mem.c um/arch/um/kernel/mem.c +--- orig/arch/um/kernel/mem.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/mem.c 2003-11-13 23:26:35.000000000 -0500 +@@ -0,0 +1,336 @@ ++/* ++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/stddef.h" ++#include "linux/kernel.h" ++#include "linux/mm.h" ++#include "linux/bootmem.h" ++#include "linux/highmem.h" ++#include "asm/page.h" ++#include "asm/fixmap.h" ++#include "asm/pgalloc.h" ++#include "user_util.h" ++#include "kern_util.h" ++#include "kern.h" ++#include "mem_user.h" ++#include "uml_uaccess.h" ++#include "os.h" ++ ++extern char __binary_start; ++ ++/* Changed during early boot */ ++unsigned long *empty_zero_page = NULL; ++unsigned long *empty_bad_page = NULL; ++pgd_t swapper_pg_dir[1024]; ++unsigned long highmem; ++int kmalloc_ok = 0; ++ ++static unsigned long brk_end; ++static unsigned long totalram_pages = 0; ++ ++void unmap_physmem(void) ++{ ++ os_unmap_memory((void *) brk_end, uml_reserved - brk_end); ++} ++ ++static void map_cb(void *unused) ++{ ++ map_memory(brk_end, __pa(brk_end), uml_reserved - brk_end, 1, 1, 0); ++} ++ ++#ifdef CONFIG_HIGHMEM ++static void setup_highmem(unsigned long highmem_start, ++ unsigned long highmem_len) ++{ ++ struct page *page; ++ unsigned long highmem_pfn; ++ int i; ++ ++ highmem_start_page = virt_to_page(highmem_start); ++ ++ highmem_pfn = __pa(highmem_start) >> PAGE_SHIFT; ++ for(i = 0; i < highmem_len >> PAGE_SHIFT; i++){ ++ page = &mem_map[highmem_pfn + i]; ++ ClearPageReserved(page); ++ set_bit(PG_highmem, &page->flags); ++ atomic_set(&page->count, 1); ++ __free_page(page); ++ } ++} ++#endif ++ ++void mem_init(void) ++{ ++ unsigned long start; ++ ++ /* clear the zero-page */ ++ memset((void *) empty_zero_page, 0, PAGE_SIZE); ++ ++ /* Map in the area just after the brk now that kmalloc is about ++ * to be turned on. ++ */ ++ brk_end = (unsigned long) UML_ROUND_UP(sbrk(0)); ++ map_cb(NULL); ++ initial_thread_cb(map_cb, NULL); ++ free_bootmem(__pa(brk_end), uml_reserved - brk_end); ++ uml_reserved = brk_end; ++ ++ /* Fill in any hole at the start of the binary */ ++ start = (unsigned long) &__binary_start; ++ if(uml_physmem != start){ ++ map_memory(uml_physmem, __pa(uml_physmem), start - uml_physmem, ++ 1, 1, 0); ++ } ++ ++ /* this will put all low memory onto the freelists */ ++ totalram_pages = free_all_bootmem(); ++ totalram_pages += highmem >> PAGE_SHIFT; ++ num_physpages = totalram_pages; ++ printk(KERN_INFO "Memory: %luk available\n", ++ (unsigned long) nr_free_pages() << (PAGE_SHIFT-10)); ++ kmalloc_ok = 1; ++ ++#ifdef CONFIG_HIGHMEM ++ setup_highmem(end_iomem, highmem); ++#endif ++} ++ ++static void __init fixrange_init(unsigned long start, unsigned long end, ++ pgd_t *pgd_base) ++{ ++ pgd_t *pgd; ++ pmd_t *pmd; ++ pte_t *pte; ++ int i, j; ++ unsigned long vaddr; ++ ++ vaddr = start; ++ i = __pgd_offset(vaddr); ++ j = __pmd_offset(vaddr); ++ pgd = pgd_base + i; ++ ++ for ( ; (i < PTRS_PER_PGD) && (vaddr < end); pgd++, i++) { ++ pmd = (pmd_t *)pgd; ++ for (; (j < PTRS_PER_PMD) && (vaddr != end); pmd++, j++) { ++ if (pmd_none(*pmd)) { ++ pte = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); ++ set_pmd(pmd, __pmd(_KERNPG_TABLE + ++ (unsigned long) __pa(pte))); ++ if (pte != pte_offset(pmd, 0)) ++ BUG(); ++ } ++ vaddr += PMD_SIZE; ++ } ++ j = 0; ++ } ++} ++ ++#if CONFIG_HIGHMEM ++pte_t *kmap_pte; ++pgprot_t kmap_prot; ++ ++#define kmap_get_fixmap_pte(vaddr) \ ++ pte_offset(pmd_offset(pgd_offset_k(vaddr), (vaddr)), (vaddr)) ++ ++void __init kmap_init(void) ++{ ++ unsigned long kmap_vstart; ++ ++ /* cache the first kmap pte */ ++ kmap_vstart = __fix_to_virt(FIX_KMAP_BEGIN); ++ kmap_pte = kmap_get_fixmap_pte(kmap_vstart); ++ ++ kmap_prot = PAGE_KERNEL; ++} ++ ++static void init_highmem(void) ++{ ++ pgd_t *pgd; ++ pmd_t *pmd; ++ pte_t *pte; ++ unsigned long vaddr; ++ ++ /* ++ * Permanent kmaps: ++ */ ++ vaddr = PKMAP_BASE; ++ fixrange_init(vaddr, vaddr + PAGE_SIZE*LAST_PKMAP, swapper_pg_dir); ++ ++ pgd = swapper_pg_dir + __pgd_offset(vaddr); ++ pmd = pmd_offset(pgd, vaddr); ++ pte = pte_offset(pmd, vaddr); ++ pkmap_page_table = pte; ++ ++ kmap_init(); ++} ++ ++#endif /* CONFIG_HIGHMEM */ ++ ++void paging_init(void) ++{ ++ unsigned long zones_size[MAX_NR_ZONES], vaddr; ++ int i; ++ ++ empty_zero_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE); ++ empty_bad_page = (unsigned long *) alloc_bootmem_low_pages(PAGE_SIZE); ++ for(i=0;i<sizeof(zones_size)/sizeof(zones_size[0]);i++) ++ zones_size[i] = 0; ++ zones_size[0] = (end_iomem >> PAGE_SHIFT) - (uml_physmem >> PAGE_SHIFT); ++ zones_size[2] = highmem >> PAGE_SHIFT; ++ free_area_init(zones_size); ++ ++ /* ++ * Fixed mappings, only the page table structure has to be ++ * created - mappings will be set by set_fixmap(): ++ */ ++ vaddr = __fix_to_virt(__end_of_fixed_addresses - 1) & PMD_MASK; ++ fixrange_init(vaddr, FIXADDR_TOP, swapper_pg_dir); ++ ++#if CONFIG_HIGHMEM ++ init_highmem(); ++#endif ++} ++ ++struct page *arch_validate(struct page *page, int mask, int order) ++{ ++ unsigned long addr, zero = 0; ++ int i; ++ ++ again: ++ if(page == NULL) return(page); ++ if(PageHighMem(page)) return(page); ++ ++ addr = (unsigned long) page_address(page); ++ for(i = 0; i < (1 << order); i++){ ++ current->thread.fault_addr = (void *) addr; ++ if(__do_copy_to_user((void *) addr, &zero, ++ sizeof(zero), ++ ¤t->thread.fault_addr, ++ ¤t->thread.fault_catcher)){ ++ if(!(mask & __GFP_WAIT)) return(NULL); ++ else break; ++ } ++ addr += PAGE_SIZE; ++ } ++ if(i == (1 << order)) return(page); ++ page = _alloc_pages(mask, order); ++ goto again; ++} ++ ++/* This can't do anything because nothing in the kernel image can be freed ++ * since it's not in kernel physical memory. ++ */ ++ ++void free_initmem(void) ++{ ++} ++ ++#ifdef CONFIG_BLK_DEV_INITRD ++ ++void free_initrd_mem(unsigned long start, unsigned long end) ++{ ++ if (start < end) ++ printk ("Freeing initrd memory: %ldk freed\n", ++ (end - start) >> 10); ++ for (; start < end; start += PAGE_SIZE) { ++ ClearPageReserved(virt_to_page(start)); ++ set_page_count(virt_to_page(start), 1); ++ free_page(start); ++ totalram_pages++; ++ } ++} ++ ++#endif ++ ++int do_check_pgt_cache(int low, int high) ++{ ++ int freed = 0; ++ if(pgtable_cache_size > high) { ++ do { ++ if (pgd_quicklist) { ++ free_pgd_slow(get_pgd_fast()); ++ freed++; ++ } ++ if (pmd_quicklist) { ++ pmd_free_slow(pmd_alloc_one_fast(NULL, 0)); ++ freed++; ++ } ++ if (pte_quicklist) { ++ pte_free_slow(pte_alloc_one_fast(NULL, 0)); ++ freed++; ++ } ++ } while(pgtable_cache_size > low); ++ } ++ return freed; ++} ++ ++void show_mem(void) ++{ ++ int i, total = 0, reserved = 0; ++ int shared = 0, cached = 0; ++ int highmem = 0; ++ ++ printk("Mem-info:\n"); ++ show_free_areas(); ++ printk("Free swap: %6dkB\n", nr_swap_pages<<(PAGE_SHIFT-10)); ++ i = max_mapnr; ++ while(i-- > 0) { ++ total++; ++ if(PageHighMem(mem_map + i)) ++ highmem++; ++ if(PageReserved(mem_map + i)) ++ reserved++; ++ else if(PageSwapCache(mem_map + i)) ++ cached++; ++ else if(page_count(mem_map + i)) ++ shared += page_count(mem_map + i) - 1; ++ } ++ printk("%d pages of RAM\n", total); ++ printk("%d pages of HIGHMEM\n", highmem); ++ printk("%d reserved pages\n", reserved); ++ printk("%d pages shared\n", shared); ++ printk("%d pages swap cached\n", cached); ++ printk("%ld pages in page table cache\n", pgtable_cache_size); ++ show_buffers(); ++} ++ ++/* Changed by meminfo_compat, which is a setup */ ++static int meminfo_22 = 0; ++ ++static int meminfo_compat(char *str) ++{ ++ meminfo_22 = 1; ++ return(1); ++} ++ ++__setup("22_meminfo", meminfo_compat); ++ ++void si_meminfo(struct sysinfo *val) ++{ ++ val->totalram = totalram_pages; ++ val->sharedram = 0; ++ val->freeram = nr_free_pages(); ++ val->bufferram = atomic_read(&buffermem_pages); ++ val->totalhigh = highmem >> PAGE_SHIFT; ++ val->freehigh = nr_free_highpages(); ++ val->mem_unit = PAGE_SIZE; ++ if(meminfo_22){ ++ val->freeram <<= PAGE_SHIFT; ++ val->bufferram <<= PAGE_SHIFT; ++ val->totalram <<= PAGE_SHIFT; ++ val->sharedram <<= PAGE_SHIFT; ++ } ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/mem_user.c um/arch/um/kernel/mem_user.c +--- orig/arch/um/kernel/mem_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/mem_user.c 2003-12-14 11:30:57.000000000 -0500 +@@ -0,0 +1,217 @@ ++/* ++ * arch/um/kernel/mem_user.c ++ * ++ * BRIEF MODULE DESCRIPTION ++ * user side memory routines for supporting IO memory inside user mode linux ++ * ++ * Copyright (C) 2001 RidgeRun, Inc. ++ * Author: RidgeRun, Inc. ++ * Greg Lonnon glonnon@ridgerun.com or info@ridgerun.com ++ * ++ * This program is free software; you can redistribute it and/or modify it ++ * under the terms of the GNU General Public License as published by the ++ * Free Software Foundation; either version 2 of the License, or (at your ++ * option) any later version. ++ * ++ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED ++ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF ++ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN ++ * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, ++ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT ++ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF ++ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ++ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ++ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF ++ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ++ * ++ * You should have received a copy of the GNU General Public License along ++ * with this program; if not, write to the Free Software Foundation, Inc., ++ * 675 Mass Ave, Cambridge, MA 02139, USA. ++ */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <stddef.h> ++#include <stdarg.h> ++#include <unistd.h> ++#include <errno.h> ++#include <string.h> ++#include <fcntl.h> ++#include <sys/types.h> ++#include <sys/mman.h> ++#include "kern_util.h" ++#include "user.h" ++#include "user_util.h" ++#include "mem_user.h" ++#include "init.h" ++#include "os.h" ++#include "tempfile.h" ++#include "kern_constants.h" ++ ++extern struct mem_region physmem_region; ++ ++#define TEMPNAME_TEMPLATE "vm_file-XXXXXX" ++ ++static int create_tmp_file(unsigned long len) ++{ ++ int fd, err; ++ char zero; ++ ++ fd = make_tempfile(TEMPNAME_TEMPLATE, NULL, 1); ++ if(fd < 0) { ++ os_print_error(fd, "make_tempfile"); ++ exit(1); ++ } ++ ++ err = os_mode_fd(fd, 0777); ++ if(err < 0){ ++ os_print_error(err, "os_mode_fd"); ++ exit(1); ++ } ++ err = os_seek_file(fd, len); ++ if(err < 0){ ++ os_print_error(err, "os_seek_file"); ++ exit(1); ++ } ++ zero = 0; ++ err = os_write_file(fd, &zero, 1); ++ if(err != 1){ ++ os_print_error(err, "os_write_file"); ++ exit(1); ++ } ++ ++ return(fd); ++} ++ ++static int have_devanon = 0; ++ ++void check_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; ++ } ++ ++ printk("OK\n"); ++ have_devanon = 1; ++} ++ ++static int create_anon_file(unsigned long len) ++{ ++ void *addr; ++ int fd; ++ ++ fd = open("/dev/anon", O_RDWR); ++ if(fd < 0) { ++ os_print_error(fd, "opening /dev/anon"); ++ exit(1); ++ } ++ ++ addr = mmap(NULL, len, PROT_READ | PROT_WRITE , MAP_PRIVATE, fd, 0); ++ if(addr == MAP_FAILED){ ++ os_print_error((int) addr, "mapping physmem file"); ++ exit(1); ++ } ++ munmap(addr, len); ++ ++ return(fd); ++} ++ ++int create_mem_file(unsigned long len) ++{ ++ int err, fd; ++ ++ if(have_devanon) ++ fd = create_anon_file(len); ++ else fd = create_tmp_file(len); ++ ++ err = os_set_exec_close(fd, 1); ++ if(err < 0) ++ os_print_error(err, "exec_close"); ++ return(fd); ++} ++ ++struct iomem_region *iomem_regions = NULL; ++int iomem_size = 0; ++ ++static int __init parse_iomem(char *str, int *add) ++{ ++ struct iomem_region *new; ++ struct uml_stat buf; ++ char *file, *driver; ++ int fd, err; ++ ++ driver = str; ++ file = strchr(str,','); ++ if(file == NULL){ ++ printf("parse_iomem : failed to parse iomem\n"); ++ goto out; ++ } ++ *file = '\0'; ++ file++; ++ fd = os_open_file(file, of_rdwr(OPENFLAGS()), 0); ++ if(fd < 0){ ++ os_print_error(fd, "parse_iomem - Couldn't open io file"); ++ goto out; ++ } ++ err = os_stat_fd(fd, &buf); ++ if(err < 0){ ++ os_print_error(err, "parse_iomem - cannot stat_fd file"); ++ goto out_close; ++ } ++ ++ new = malloc(sizeof(*new)); ++ if(new == NULL){ ++ perror("Couldn't allocate iomem_region struct"); ++ goto out_close; ++ } ++ ++ *new = ((struct iomem_region) { .next = iomem_regions, ++ .driver = driver, ++ .fd = fd, ++ .size = buf.ust_size, ++ .phys = 0, ++ .virt = 0 }); ++ iomem_regions = new; ++ iomem_size += new->size + UM_KERN_PAGE_SIZE; ++ ++ return(0); ++ out_close: ++ os_close_file(fd); ++ out: ++ return(1); ++} ++ ++__uml_setup("iomem=", parse_iomem, ++"iomem=<name>,<file>\n" ++" Configure <file> as an IO memory region named <name>.\n\n" ++); ++ ++int protect_memory(unsigned long addr, unsigned long len, int r, int w, int x, ++ int must_succeed) ++{ ++ int err; ++ ++ err = os_protect_memory((void *) addr, len, r, w, x); ++ if(err < 0){ ++ if(must_succeed) ++ panic("protect failed, err = %d", -err); ++ else return(err); ++ } ++ return(0); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/mprot.h um/arch/um/kernel/mprot.h +--- orig/arch/um/kernel/mprot.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/mprot.h 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __MPROT_H__ ++#define __MPROT_H__ ++ ++extern void no_access(unsigned long addr, unsigned int len); ++ ++#endif +diff -Naur -X ../exclude-files orig/arch/um/kernel/physmem.c um/arch/um/kernel/physmem.c +--- orig/arch/um/kernel/physmem.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/physmem.c 2003-11-14 02:59:20.000000000 -0500 +@@ -0,0 +1,349 @@ ++/* ++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/mm.h" ++#include "linux/ghash.h" ++#include "linux/slab.h" ++#include "linux/vmalloc.h" ++#include "linux/bootmem.h" ++#include "asm/types.h" ++#include "asm/pgtable.h" ++#include "kern_util.h" ++#include "user_util.h" ++#include "mode_kern.h" ++#include "mem.h" ++#include "mem_user.h" ++#include "os.h" ++#include "kern.h" ++#include "init.h" ++ ++#define PHYS_HASHSIZE (8192) ++ ++struct phys_desc; ++ ++DEF_HASH_STRUCTS(virtmem, PHYS_HASHSIZE, struct phys_desc); ++ ++struct phys_desc { ++ struct virtmem_ptrs virt_ptrs; ++ int fd; ++ __u64 offset; ++ void *virt; ++ unsigned long phys; ++}; ++ ++struct virtmem_table virtmem_hash; ++ ++static int virt_cmp(void *virt1, void *virt2) ++{ ++ return(virt1 != virt2); ++} ++ ++static int virt_hash(void *virt) ++{ ++ unsigned long addr = ((unsigned long) virt) >> PAGE_SHIFT; ++ return(addr % PHYS_HASHSIZE); ++} ++ ++DEF_HASH(static, virtmem, struct phys_desc, virt_ptrs, void *, virt, virt_cmp, ++ virt_hash); ++ ++int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w) ++{ ++ struct phys_desc *desc; ++ unsigned long phys; ++ int err; ++ ++ virt = (void *) ((unsigned long) virt & PAGE_MASK); ++ err = os_map_memory(virt, fd, offset, PAGE_SIZE, 1, w, 0); ++ if(err) ++ goto out; ++ ++ phys = __pa(virt); ++ if(find_virtmem_hash(&virtmem_hash, virt) != NULL) ++ panic("Address 0x%p is already substituted\n", virt); ++ ++ err = -ENOMEM; ++ desc = kmalloc(sizeof(*desc), GFP_ATOMIC); ++ if(desc == NULL) ++ goto out; ++ ++ *desc = ((struct phys_desc) { .virt_ptrs = { NULL, NULL }, ++ .fd = fd, ++ .offset = offset, ++ .virt = virt, ++ .phys = __pa(virt) }); ++ insert_virtmem_hash(&virtmem_hash, desc); ++ err = 0; ++ out: ++ return(err); ++} ++ ++static int physmem_fd = -1; ++ ++int physmem_remove_mapping(void *virt) ++{ ++ struct phys_desc *desc; ++ int err; ++ ++ virt = (void *) ((unsigned long) virt & PAGE_MASK); ++ desc = find_virtmem_hash(&virtmem_hash, virt); ++ if(desc == NULL) ++ return(0); ++ ++ remove_virtmem_hash(&virtmem_hash, desc); ++ 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); ++ return(1); ++} ++ ++void arch_free_page(struct page *page, int order) ++{ ++ void *virt; ++ int i; ++ ++ for(i = 0; i < 1 << order; i++){ ++ virt = __va(page_to_phys(page + i)); ++ physmem_remove_mapping(virt); ++ } ++} ++ ++int is_remapped(void *virt) ++{ ++ return(find_virtmem_hash(&virtmem_hash, virt) != NULL); ++} ++ ++/* Changed during early boot */ ++unsigned long high_physmem; ++ ++extern unsigned long physmem_size; ++ ++void *to_virt(unsigned long phys) ++{ ++ return((void *) uml_physmem + phys); ++} ++ ++unsigned long to_phys(void *virt) ++{ ++ return(((unsigned long) virt) - uml_physmem); ++} ++ ++int init_maps(unsigned long physmem, unsigned long iomem, unsigned long highmem) ++{ ++ struct page *p, *map; ++ unsigned long phys_len, phys_pages, highmem_len, highmem_pages; ++ unsigned long iomem_len, iomem_pages, total_len, total_pages; ++ int i; ++ ++ phys_pages = physmem >> PAGE_SHIFT; ++ phys_len = phys_pages * sizeof(struct page); ++ ++ iomem_pages = iomem >> PAGE_SHIFT; ++ iomem_len = iomem_pages * sizeof(struct page); ++ ++ highmem_pages = highmem >> PAGE_SHIFT; ++ highmem_len = highmem_pages * sizeof(struct page); ++ ++ total_pages = phys_pages + iomem_pages + highmem_pages; ++ total_len = phys_len + iomem_pages + highmem_len; ++ ++ if(kmalloc_ok){ ++ map = kmalloc(total_len, GFP_KERNEL); ++ if(map == NULL) ++ map = vmalloc(total_len); ++ } ++ else map = alloc_bootmem_low_pages(total_len); ++ ++ if(map == NULL) ++ return(-ENOMEM); ++ ++ for(i = 0; i < total_pages; i++){ ++ p = &map[i]; ++ set_page_count(p, 0); ++ SetPageReserved(p); ++ INIT_LIST_HEAD(&p->list); ++ } ++ ++ mem_map = map; ++ max_mapnr = total_pages; ++ return(0); ++} ++ ++struct page *phys_to_page(const unsigned long phys) ++{ ++ return(&mem_map[phys >> PAGE_SHIFT]); ++} ++ ++struct page *__virt_to_page(const unsigned long virt) ++{ ++ return(&mem_map[__pa(virt) >> PAGE_SHIFT]); ++} ++ ++unsigned long page_to_phys(struct page *page) ++{ ++ return((page - mem_map) << PAGE_SHIFT); ++} ++ ++pte_t mk_pte(struct page *page, pgprot_t pgprot) ++{ ++ pte_t pte; ++ ++ pte_val(pte) = page_to_phys(page) + pgprot_val(pgprot); ++ if(pte_present(pte)) pte_mknewprot(pte_mknewpage(pte)); ++ return(pte); ++} ++ ++/* Changed during early boot */ ++static unsigned long kmem_top = 0; ++ ++unsigned long get_kmem_end(void) ++{ ++ if(kmem_top == 0) ++ kmem_top = CHOOSE_MODE(kmem_end_tt, kmem_end_skas); ++ return(kmem_top); ++} ++ ++void map_memory(unsigned long virt, unsigned long phys, unsigned long len, ++ int r, int w, int x) ++{ ++ __u64 offset; ++ int fd, err; ++ ++ fd = phys_mapping(phys, &offset); ++ err = os_map_memory((void *) virt, fd, offset, len, r, w, x); ++ if(err) ++ panic("map_memory(0x%lx, %d, 0x%llx, %ld, %d, %d, %d) failed, " ++ "err = %d\n", virt, fd, offset, len, r, w, x, err); ++} ++ ++#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) ++ ++void setup_physmem(unsigned long start, unsigned long reserve_end, ++ unsigned long len, unsigned long highmem) ++{ ++ unsigned long reserve = reserve_end - start; ++ int pfn = PFN_UP(__pa(reserve_end)); ++ int delta = (len - reserve) >> PAGE_SHIFT; ++ int err, offset, bootmap_size; ++ ++ physmem_fd = create_mem_file(len + highmem); ++ ++ offset = uml_reserved - uml_physmem; ++ err = os_map_memory((void *) uml_reserved, physmem_fd, offset, ++ len - offset, 1, 1, 0); ++ if(err < 0){ ++ os_print_error(err, "Mapping memory"); ++ exit(1); ++ } ++ ++ bootmap_size = init_bootmem(pfn, pfn + delta); ++ free_bootmem(__pa(reserve_end) + bootmap_size, ++ len - bootmap_size - reserve); ++} ++ ++int phys_mapping(unsigned long phys, __u64 *offset_out) ++{ ++ struct phys_desc *desc = find_virtmem_hash(&virtmem_hash, ++ __va(phys & PAGE_MASK)); ++ int fd = -1; ++ ++ if(desc != NULL){ ++ fd = desc->fd; ++ *offset_out = desc->offset; ++ } ++ else if(phys < physmem_size){ ++ fd = physmem_fd; ++ *offset_out = phys; ++ } ++ else if(phys < __pa(end_iomem)){ ++ struct iomem_region *region = iomem_regions; ++ ++ while(region != NULL){ ++ if((phys >= region->phys) && ++ (phys < region->phys + region->size)){ ++ fd = region->fd; ++ *offset_out = phys - region->phys; ++ break; ++ } ++ region = region->next; ++ } ++ } ++ else if(phys < __pa(end_iomem) + highmem){ ++ fd = physmem_fd; ++ *offset_out = phys - iomem_size; ++ } ++ ++ return(fd); ++} ++ ++static int __init uml_mem_setup(char *line, int *add) ++{ ++ char *retptr; ++ physmem_size = memparse(line,&retptr); ++ return 0; ++} ++__uml_setup("mem=", uml_mem_setup, ++"mem=<Amount of desired ram>\n" ++" This controls how much \"physical\" memory the kernel allocates\n" ++" for the system. The size is specified as a number followed by\n" ++" one of 'k', 'K', 'm', 'M', which have the obvious meanings.\n" ++" This is not related to the amount of memory in the host. It can\n" ++" be more, and the excess, if it's ever used, will just be swapped out.\n" ++" Example: mem=64M\n\n" ++); ++ ++unsigned long find_iomem(char *driver, unsigned long *len_out) ++{ ++ struct iomem_region *region = iomem_regions; ++ ++ while(region != NULL){ ++ if(!strcmp(region->driver, driver)){ ++ *len_out = region->size; ++ return(region->virt); ++ } ++ } ++ ++ return(0); ++} ++ ++int setup_iomem(void) ++{ ++ struct iomem_region *region = iomem_regions; ++ unsigned long iomem_start = high_physmem + PAGE_SIZE; ++ int err; ++ ++ while(region != NULL){ ++ err = os_map_memory((void *) iomem_start, region->fd, 0, ++ region->size, 1, 1, 0); ++ if(err) ++ printk("Mapping iomem region for driver '%s' failed, " ++ "errno = %d\n", region->driver, -err); ++ else { ++ region->virt = iomem_start; ++ region->phys = __pa(region->virt); ++ } ++ ++ iomem_start += region->size + PAGE_SIZE; ++ region = region->next; ++ } ++ ++ return(0); ++} ++ ++__initcall(setup_iomem); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/process.c um/arch/um/kernel/process.c +--- orig/arch/um/kernel/process.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/process.c 2003-11-07 02:09:21.000000000 -0500 +@@ -0,0 +1,288 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdio.h> ++#include <unistd.h> ++#include <signal.h> ++#include <sched.h> ++#include <errno.h> ++#include <stdarg.h> ++#include <stdlib.h> ++#include <setjmp.h> ++#include <sys/time.h> ++#include <sys/ptrace.h> ++#include <sys/wait.h> ++#include <sys/mman.h> ++#include <asm/ptrace.h> ++#include <asm/sigcontext.h> ++#include <asm/unistd.h> ++#include <asm/page.h> ++#include "user_util.h" ++#include "kern_util.h" ++#include "user.h" ++#include "process.h" ++#include "signal_kern.h" ++#include "signal_user.h" ++#include "sysdep/ptrace.h" ++#include "sysdep/sigcontext.h" ++#include "irq_user.h" ++#include "ptrace_user.h" ++#include "time_user.h" ++#include "init.h" ++#include "os.h" ++#include "uml-config.h" ++#include "choose-mode.h" ++#include "mode.h" ++#ifdef UML_CONFIG_MODE_SKAS ++#include "skas.h" ++#include "skas_ptrace.h" ++#endif ++ ++void init_new_thread_stack(void *sig_stack, void (*usr1_handler)(int)) ++{ ++ int flags = 0, pages; ++ ++ if(sig_stack != NULL){ ++ pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER) - 2; ++ set_sigstack(sig_stack, pages * page_size()); ++ flags = SA_ONSTACK; ++ } ++ if(usr1_handler) set_handler(SIGUSR1, usr1_handler, flags, -1); ++} ++ ++void init_new_thread_signals(int altstack) ++{ ++ int flags = altstack ? SA_ONSTACK : 0; ++ ++ /* NODEFER is set here because SEGV isn't turned back on when the ++ * handler is ready to receive signals. This causes any segfault ++ * during a copy_user to kill the process because the fault is blocked. ++ */ ++ set_handler(SIGSEGV, (__sighandler_t) sig_handler, flags | SA_NODEFER, ++ SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); ++ set_handler(SIGTRAP, (__sighandler_t) sig_handler, flags, ++ SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); ++ set_handler(SIGFPE, (__sighandler_t) sig_handler, flags, ++ SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); ++ set_handler(SIGILL, (__sighandler_t) sig_handler, flags, ++ SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); ++ set_handler(SIGBUS, (__sighandler_t) sig_handler, flags, ++ SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); ++ set_handler(SIGWINCH, (__sighandler_t) sig_handler, flags, ++ SIGUSR1, SIGIO, SIGWINCH, SIGALRM, SIGVTALRM, -1); ++ set_handler(SIGUSR2, (__sighandler_t) sig_handler, ++ SA_NOMASK | flags, -1); ++ signal(SIGHUP, SIG_IGN); ++ ++ init_irq_signals(altstack); ++} ++ ++struct tramp { ++ int (*tramp)(void *); ++ void *tramp_data; ++ unsigned long temp_stack; ++ int flags; ++ int pid; ++}; ++ ++/* See above for why sigkill is here */ ++ ++int sigkill = SIGKILL; ++ ++int outer_tramp(void *arg) ++{ ++ struct tramp *t; ++ int sig = sigkill; ++ ++ t = arg; ++ t->pid = clone(t->tramp, (void *) t->temp_stack + page_size()/2, ++ t->flags, t->tramp_data); ++ if(t->pid > 0) wait_for_stop(t->pid, SIGSTOP, PTRACE_CONT, NULL); ++ kill(os_getpid(), sig); ++ _exit(0); ++} ++ ++int start_fork_tramp(void *thread_arg, unsigned long temp_stack, ++ int clone_flags, int (*tramp)(void *)) ++{ ++ struct tramp arg; ++ unsigned long sp; ++ int new_pid, status, err; ++ ++ /* The trampoline will run on the temporary stack */ ++ sp = stack_sp(temp_stack); ++ ++ clone_flags |= CLONE_FILES | SIGCHLD; ++ ++ arg.tramp = tramp; ++ arg.tramp_data = thread_arg; ++ arg.temp_stack = temp_stack; ++ arg.flags = clone_flags; ++ ++ /* Start the process and wait for it to kill itself */ ++ new_pid = clone(outer_tramp, (void *) sp, clone_flags, &arg); ++ if(new_pid < 0) return(-errno); ++ while(((err = waitpid(new_pid, &status, 0)) < 0) && (errno == EINTR)) ; ++ if(err < 0) panic("Waiting for outer trampoline failed - errno = %d", ++ errno); ++ if(!WIFSIGNALED(status) || (WTERMSIG(status) != SIGKILL)) ++ panic("outer trampoline didn't exit with SIGKILL"); ++ ++ return(arg.pid); ++} ++ ++void suspend_new_thread(int fd) ++{ ++ char c; ++ ++ os_stop_process(os_getpid()); ++ ++ if(os_read_file(fd, &c, sizeof(c)) != sizeof(c)) ++ panic("read failed in suspend_new_thread"); ++} ++ ++static int ptrace_child(void *arg) ++{ ++ int pid = os_getpid(); ++ ++ if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){ ++ perror("ptrace"); ++ os_kill_process(pid, 0); ++ } ++ os_stop_process(pid); ++ _exit(os_getpid() == pid); ++} ++ ++static int start_ptraced_child(void **stack_out) ++{ ++ void *stack; ++ unsigned long sp; ++ int pid, n, status; ++ ++ stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, ++ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ++ if(stack == MAP_FAILED) ++ panic("check_ptrace : mmap failed, errno = %d", errno); ++ sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *); ++ pid = clone(ptrace_child, (void *) sp, SIGCHLD, NULL); ++ if(pid < 0) ++ panic("check_ptrace : clone failed, errno = %d", errno); ++ n = waitpid(pid, &status, WUNTRACED); ++ if(n < 0) ++ panic("check_ptrace : wait failed, errno = %d", errno); ++ if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) ++ panic("check_ptrace : expected SIGSTOP, got status = %d", ++ status); ++ ++ *stack_out = stack; ++ return(pid); ++} ++ ++static void stop_ptraced_child(int pid, void *stack, int exitcode) ++{ ++ int status, n; ++ ++ if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) ++ panic("check_ptrace : ptrace failed, errno = %d", errno); ++ n = waitpid(pid, &status, 0); ++ if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) ++ panic("check_ptrace : child exited with status 0x%x", status); ++ ++ if(munmap(stack, PAGE_SIZE) < 0) ++ panic("check_ptrace : munmap failed, errno = %d", errno); ++} ++ ++void __init check_ptrace(void) ++{ ++ void *stack; ++ int pid, syscall, n, status; ++ ++ printk("Checking that ptrace can change system call numbers..."); ++ pid = start_ptraced_child(&stack); ++ ++ while(1){ ++ if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) ++ panic("check_ptrace : ptrace failed, errno = %d", ++ errno); ++ n = waitpid(pid, &status, WUNTRACED); ++ if(n < 0) ++ panic("check_ptrace : wait failed, errno = %d", errno); ++ if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) ++ panic("check_ptrace : expected SIGTRAP, " ++ "got status = %d", status); ++ ++ syscall = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET, ++ 0); ++ if(syscall == __NR_getpid){ ++ n = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, ++ __NR_getppid); ++ if(n < 0) ++ panic("check_ptrace : failed to modify system " ++ "call, errno = %d", errno); ++ break; ++ } ++ } ++ stop_ptraced_child(pid, stack, 0); ++ printk("OK\n"); ++} ++ ++int run_kernel_thread(int (*fn)(void *), void *arg, void **jmp_ptr) ++{ ++ jmp_buf buf; ++ int n; ++ ++ *jmp_ptr = &buf; ++ n = sigsetjmp(buf, 1); ++ if(n != 0) ++ return(n); ++ (*fn)(arg); ++ return(0); ++} ++ ++int can_do_skas(void) ++{ ++#ifdef UML_CONFIG_MODE_SKAS ++ struct ptrace_faultinfo fi; ++ void *stack; ++ int pid, n, ret = 1; ++ ++ printf("Checking for the skas3 patch in the host..."); ++ pid = start_ptraced_child(&stack); ++ ++ n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi); ++ if(n < 0){ ++ if(errno == EIO) ++ printf("not found\n"); ++ else printf("No (unexpected errno - %d)\n", errno); ++ ret = 0; ++ } ++ else printf("found\n"); ++ ++ init_registers(pid); ++ stop_ptraced_child(pid, stack, 1); ++ ++ printf("Checking for /proc/mm..."); ++ if(os_access("/proc/mm", OS_ACC_W_OK) < 0){ ++ printf("not found\n"); ++ ret = 0; ++ } ++ else printf("found\n"); ++ ++ return(ret); ++#else ++ return(0); ++#endif ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/process_kern.c um/arch/um/kernel/process_kern.c +--- orig/arch/um/kernel/process_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/process_kern.c 2003-11-08 08:37:04.000000000 -0500 +@@ -0,0 +1,396 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/config.h" ++#include "linux/kernel.h" ++#include "linux/sched.h" ++#include "linux/interrupt.h" ++#include "linux/mm.h" ++#include "linux/slab.h" ++#include "linux/utsname.h" ++#include "linux/fs.h" ++#include "linux/utime.h" ++#include "linux/smp_lock.h" ++#include "linux/module.h" ++#include "linux/init.h" ++#include "linux/capability.h" ++#include "asm/unistd.h" ++#include "asm/mman.h" ++#include "asm/segment.h" ++#include "asm/stat.h" ++#include "asm/pgtable.h" ++#include "asm/processor.h" ++#include "asm/pgalloc.h" ++#include "asm/spinlock.h" ++#include "asm/uaccess.h" ++#include "asm/user.h" ++#include "user_util.h" ++#include "kern_util.h" ++#include "kern.h" ++#include "signal_kern.h" ++#include "signal_user.h" ++#include "init.h" ++#include "irq_user.h" ++#include "mem_user.h" ++#include "time_user.h" ++#include "tlb.h" ++#include "frame_kern.h" ++#include "sigcontext.h" ++#include "2_5compat.h" ++#include "os.h" ++#include "mode.h" ++#include "mode_kern.h" ++#include "choose-mode.h" ++ ++/* This is a per-cpu array. A processor only modifies its entry and it only ++ * cares about its entry, so it's OK if another processor is modifying its ++ * entry. ++ */ ++struct cpu_task cpu_tasks[NR_CPUS] = { [0 ... NR_CPUS - 1] = { -1, NULL } }; ++ ++struct task_struct *get_task(int pid, int require) ++{ ++ struct task_struct *ret; ++ ++ read_lock(&tasklist_lock); ++ ret = find_task_by_pid(pid); ++ read_unlock(&tasklist_lock); ++ ++ if(require && (ret == NULL)) panic("get_task couldn't find a task\n"); ++ return(ret); ++} ++ ++int external_pid(void *t) ++{ ++ struct task_struct *task = t ? t : current; ++ ++ return(CHOOSE_MODE_PROC(external_pid_tt, external_pid_skas, task)); ++} ++ ++int pid_to_processor_id(int pid) ++{ ++ int i; ++ ++ for(i = 0; i < smp_num_cpus; i++){ ++ if(cpu_tasks[i].pid == pid) return(i); ++ } ++ return(-1); ++} ++ ++void free_stack(unsigned long stack, int order) ++{ ++ free_pages(stack, order); ++} ++ ++unsigned long alloc_stack(int order, int atomic) ++{ ++ unsigned long page; ++ int flags = GFP_KERNEL; ++ ++ if(atomic) flags |= GFP_ATOMIC; ++ page = __get_free_pages(flags, order); ++ if(page == 0) ++ return(0); ++ stack_protections(page); ++ return(page); ++} ++ ++int arch_kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) ++{ ++ int pid; ++ ++ current->thread.request.u.thread.proc = fn; ++ current->thread.request.u.thread.arg = arg; ++ pid = do_fork(CLONE_VM | flags, 0, NULL, 0); ++#if 0 /* CLONE_UNTRACED for 2.6 */ ++ pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0, NULL, 0); ++#endif ++ if(pid < 0) ++ panic("do_fork failed in kernel_thread, errno = %d", pid); ++ return(pid); ++} ++ ++void switch_mm(struct mm_struct *prev, struct mm_struct *next, ++ struct task_struct *tsk, unsigned cpu) ++{ ++ if (prev != next) ++ clear_bit(cpu, &prev->cpu_vm_mask); ++ set_bit(cpu, &next->cpu_vm_mask); ++} ++ ++void set_current(void *t) ++{ ++ struct task_struct *task = t; ++ ++ cpu_tasks[task->processor] = ((struct cpu_task) ++ { external_pid(task), task }); ++} ++ ++void *_switch_to(void *prev, void *next) ++{ ++ return(CHOOSE_MODE(_switch_to_tt(prev, next), ++ _switch_to_skas(prev, next))); ++} ++ ++void interrupt_end(void) ++{ ++ if(current->need_resched) schedule(); ++ if(current->sigpending != 0) do_signal(0); ++} ++ ++void release_thread(struct task_struct *task) ++{ ++ CHOOSE_MODE(release_thread_tt(task), release_thread_skas(task)); ++} ++ ++void exit_thread(void) ++{ ++ CHOOSE_MODE(exit_thread_tt(), exit_thread_skas()); ++ unprotect_stack((unsigned long) current); ++} ++ ++void *get_current(void) ++{ ++ return(current); ++} ++ ++int copy_thread(int nr, unsigned long clone_flags, unsigned long sp, ++ unsigned long stack_top, struct task_struct * p, ++ struct pt_regs *regs) ++{ ++ p->thread = (struct thread_struct) INIT_THREAD; ++ p->thread.kernel_stack = (unsigned long) p + 2 * PAGE_SIZE; ++ ++ return(CHOOSE_MODE_PROC(copy_thread_tt, copy_thread_skas, nr, ++ clone_flags, sp, stack_top, p, regs)); ++} ++ ++void initial_thread_cb(void (*proc)(void *), void *arg) ++{ ++ int save_kmalloc_ok = kmalloc_ok; ++ ++ kmalloc_ok = 0; ++ CHOOSE_MODE_PROC(initial_thread_cb_tt, initial_thread_cb_skas, proc, ++ arg); ++ kmalloc_ok = save_kmalloc_ok; ++} ++ ++unsigned long stack_sp(unsigned long page) ++{ ++ return(page + PAGE_SIZE - sizeof(void *)); ++} ++ ++int current_pid(void) ++{ ++ return(current->pid); ++} ++ ++void cpu_idle(void) ++{ ++ CHOOSE_MODE(init_idle_tt(), init_idle_skas()); ++ ++ atomic_inc(&init_mm.mm_count); ++ current->mm = &init_mm; ++ current->active_mm = &init_mm; ++ ++ while(1){ ++ /* endless idle loop with no priority at all */ ++ SET_PRI(current); ++ ++ /* ++ * although we are an idle CPU, we do not want to ++ * get into the scheduler unnecessarily. ++ */ ++ if (current->need_resched) { ++ schedule(); ++ check_pgt_cache(); ++ } ++ idle_sleep(10); ++ } ++} ++ ++int page_size(void) ++{ ++ return(PAGE_SIZE); ++} ++ ++int page_mask(void) ++{ ++ return(PAGE_MASK); ++} ++ ++void *um_virt_to_phys(struct task_struct *task, unsigned long addr, ++ pte_t *pte_out) ++{ ++ pgd_t *pgd; ++ pmd_t *pmd; ++ pte_t *pte; ++ ++ if(task->mm == NULL) ++ return(ERR_PTR(-EINVAL)); ++ pgd = pgd_offset(task->mm, addr); ++ pmd = pmd_offset(pgd, addr); ++ if(!pmd_present(*pmd)) ++ return(ERR_PTR(-EINVAL)); ++ pte = pte_offset(pmd, addr); ++ if(!pte_present(*pte)) ++ return(ERR_PTR(-EINVAL)); ++ if(pte_out != NULL) ++ *pte_out = *pte; ++ return((void *) (pte_val(*pte) & PAGE_MASK) + (addr & ~PAGE_MASK)); ++} ++ ++char *current_cmd(void) ++{ ++#if defined(CONFIG_SMP) || defined(CONFIG_HIGHMEM) ++ return("(Unknown)"); ++#else ++ void *addr = um_virt_to_phys(current, current->mm->arg_start, NULL); ++ return IS_ERR(addr) ? "(Unknown)": __va((unsigned long) addr); ++#endif ++} ++ ++void force_sigbus(void) ++{ ++ printk(KERN_ERR "Killing pid %d because of a lack of memory\n", ++ current->pid); ++ lock_kernel(); ++ sigaddset(¤t->pending.signal, SIGBUS); ++ recalc_sigpending(current); ++ current->flags |= PF_SIGNALED; ++ do_exit(SIGBUS | 0x80); ++} ++ ++void dump_thread(struct pt_regs *regs, struct user *u) ++{ ++} ++ ++void enable_hlt(void) ++{ ++ panic("enable_hlt"); ++} ++ ++void disable_hlt(void) ++{ ++ panic("disable_hlt"); ++} ++ ++extern int signal_frame_size; ++ ++void *um_kmalloc(int size) ++{ ++ return(kmalloc(size, GFP_KERNEL)); ++} ++ ++void *um_kmalloc_atomic(int size) ++{ ++ return(kmalloc(size, GFP_ATOMIC)); ++} ++ ++unsigned long get_fault_addr(void) ++{ ++ return((unsigned long) current->thread.fault_addr); ++} ++ ++EXPORT_SYMBOL(get_fault_addr); ++ ++void not_implemented(void) ++{ ++ printk(KERN_DEBUG "Something isn't implemented in here\n"); ++} ++ ++EXPORT_SYMBOL(not_implemented); ++ ++int user_context(unsigned long sp) ++{ ++ unsigned long stack; ++ ++ stack = sp & (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER); ++ stack += 2 * PAGE_SIZE; ++ return(stack != current->thread.kernel_stack); ++} ++ ++extern void remove_umid_dir(void); ++ ++__uml_exitcall(remove_umid_dir); ++ ++extern exitcall_t __uml_exitcall_begin, __uml_exitcall_end; ++ ++void do_uml_exitcalls(void) ++{ ++ exitcall_t *call; ++ ++ call = &__uml_exitcall_end; ++ while (--call >= &__uml_exitcall_begin) ++ (*call)(); ++} ++ ++char *uml_strdup(char *string) ++{ ++ char *new; ++ ++ new = kmalloc(strlen(string) + 1, GFP_KERNEL); ++ if(new == NULL) return(NULL); ++ strcpy(new, string); ++ return(new); ++} ++ ++void *get_init_task(void) ++{ ++ return(&init_task_union.task); ++} ++ ++int copy_to_user_proc(void *to, void *from, int size) ++{ ++ return(copy_to_user(to, from, size)); ++} ++ ++int copy_from_user_proc(void *to, void *from, int size) ++{ ++ return(copy_from_user(to, from, size)); ++} ++ ++int clear_user_proc(void *buf, int size) ++{ ++ return(clear_user(buf, size)); ++} ++ ++int strlen_user_proc(char *str) ++{ ++ return(strlen_user(str)); ++} ++ ++int smp_sigio_handler(void) ++{ ++#ifdef CONFIG_SMP ++ int cpu = current->processor; ++ ++ IPI_handler(cpu); ++ if(cpu != 0) ++ return(1); ++#endif ++ return(0); ++} ++ ++int um_in_interrupt(void) ++{ ++ return(in_interrupt()); ++} ++ ++int cpu(void) ++{ ++ return(current->processor); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/ptrace.c um/arch/um/kernel/ptrace.c +--- orig/arch/um/kernel/ptrace.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/ptrace.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,325 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/sched.h" ++#include "linux/mm.h" ++#include "linux/errno.h" ++#include "linux/smp_lock.h" ++#ifdef CONFIG_PROC_MM ++#include "linux/proc_mm.h" ++#endif ++#include "asm/ptrace.h" ++#include "asm/uaccess.h" ++#include "kern_util.h" ++#include "ptrace_user.h" ++ ++/* ++ * Called by kernel/ptrace.c when detaching.. ++ */ ++void ptrace_disable(struct task_struct *child) ++{ ++} ++ ++extern long do_mmap2(struct task_struct *task, unsigned long addr, ++ unsigned long len, unsigned long prot, ++ unsigned long flags, unsigned long fd, ++ unsigned long pgoff); ++ ++int sys_ptrace(long request, long pid, long addr, long data) ++{ ++ struct task_struct *child; ++ int i, ret; ++ ++ lock_kernel(); ++ ret = -EPERM; ++ if (request == PTRACE_TRACEME) { ++ /* are we already being traced? */ ++ if (current->ptrace & PT_PTRACED) ++ goto out; ++ /* set the ptrace bit in the process flags. */ ++ current->ptrace |= PT_PTRACED; ++ ret = 0; ++ goto out; ++ } ++ ret = -ESRCH; ++ read_lock(&tasklist_lock); ++ child = find_task_by_pid(pid); ++ if (child) ++ get_task_struct(child); ++ read_unlock(&tasklist_lock); ++ if (!child) ++ goto out; ++ ++ ret = -EPERM; ++ if (pid == 1) /* you may not mess with init */ ++ goto out_tsk; ++ ++ if (request == PTRACE_ATTACH) { ++ ret = ptrace_attach(child); ++ goto out_tsk; ++ } ++ ++ ret = ptrace_check_attach(child, request == PTRACE_KILL); ++ if (ret < 0) ++ goto out_tsk; ++ ++ switch (request) { ++ /* when I and D space are separate, these will need to be fixed. */ ++ case PTRACE_PEEKTEXT: /* read word at location addr. */ ++ case PTRACE_PEEKDATA: { ++ unsigned long tmp; ++ int copied; ++ ++ ret = -EIO; ++ copied = access_process_vm(child, addr, &tmp, sizeof(tmp), 0); ++ if (copied != sizeof(tmp)) ++ break; ++ ret = put_user(tmp,(unsigned long *) data); ++ break; ++ } ++ ++ /* read the word at location addr in the USER area. */ ++ case PTRACE_PEEKUSR: { ++ unsigned long tmp; ++ ++ ret = -EIO; ++ if ((addr & 3) || addr < 0) ++ break; ++ ++ tmp = 0; /* Default return condition */ ++ if(addr < FRAME_SIZE_OFFSET){ ++ tmp = getreg(child, addr); ++ } ++ else if((addr >= offsetof(struct user, u_debugreg[0])) && ++ (addr <= offsetof(struct user, u_debugreg[7]))){ ++ addr -= offsetof(struct user, u_debugreg[0]); ++ addr = addr >> 2; ++ tmp = child->thread.arch.debugregs[addr]; ++ } ++ ret = put_user(tmp, (unsigned long *) data); ++ break; ++ } ++ ++ /* when I and D space are separate, this will have to be fixed. */ ++ case PTRACE_POKETEXT: /* write the word at location addr. */ ++ case PTRACE_POKEDATA: ++ ret = -EIO; ++ if (access_process_vm(child, addr, &data, sizeof(data), ++ 1) != sizeof(data)) ++ break; ++ ret = 0; ++ break; ++ ++ case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ ++ ret = -EIO; ++ if ((addr & 3) || addr < 0) ++ break; ++ ++ if (addr < FRAME_SIZE_OFFSET) { ++ ret = putreg(child, addr, data); ++ break; ++ } ++ else if((addr >= offsetof(struct user, u_debugreg[0])) && ++ (addr <= offsetof(struct user, u_debugreg[7]))){ ++ addr -= offsetof(struct user, u_debugreg[0]); ++ addr = addr >> 2; ++ if((addr == 4) || (addr == 5)) break; ++ child->thread.arch.debugregs[addr] = data; ++ ret = 0; ++ } ++ ++ break; ++ ++ case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */ ++ case PTRACE_CONT: { /* restart after signal. */ ++ ret = -EIO; ++ if ((unsigned long) data > _NSIG) ++ break; ++ if (request == PTRACE_SYSCALL) ++ child->ptrace |= PT_TRACESYS; ++ else ++ child->ptrace &= ~PT_TRACESYS; ++ child->exit_code = data; ++ wake_up_process(child); ++ ret = 0; ++ break; ++ } ++ ++/* ++ * make the child exit. Best I can do is send it a sigkill. ++ * perhaps it should be put in the status that it wants to ++ * exit. ++ */ ++ case PTRACE_KILL: { ++ ret = 0; ++ if (child->state == TASK_ZOMBIE) /* already dead */ ++ break; ++ child->exit_code = SIGKILL; ++ wake_up_process(child); ++ break; ++ } ++ ++ case PTRACE_SINGLESTEP: { /* set the trap flag. */ ++ ret = -EIO; ++ if ((unsigned long) data > _NSIG) ++ break; ++ child->ptrace &= ~PT_TRACESYS; ++ child->ptrace |= PT_DTRACE; ++ child->exit_code = data; ++ /* give it a chance to run. */ ++ wake_up_process(child); ++ ret = 0; ++ break; ++ } ++ ++ case PTRACE_DETACH: ++ /* detach a process that was attached. */ ++ ret = ptrace_detach(child, data); ++ break; ++ ++#ifdef PTRACE_GETREGS ++ case PTRACE_GETREGS: { /* Get all gp regs from the child. */ ++ if (!access_ok(VERIFY_WRITE, (unsigned long *)data, ++ FRAME_SIZE_OFFSET)) { ++ ret = -EIO; ++ break; ++ } ++ for ( i = 0; i < FRAME_SIZE_OFFSET; i += sizeof(long) ) { ++ __put_user(getreg(child, i), (unsigned long *) data); ++ data += sizeof(long); ++ } ++ ret = 0; ++ break; ++ } ++#endif ++#ifdef PTRACE_SETREGS ++ case PTRACE_SETREGS: { /* Set all gp regs in the child. */ ++ unsigned long tmp = 0; ++ if (!access_ok(VERIFY_READ, (unsigned *)data, ++ FRAME_SIZE_OFFSET)) { ++ ret = -EIO; ++ break; ++ } ++ for ( i = 0; i < FRAME_SIZE_OFFSET; i += sizeof(long) ) { ++ __get_user(tmp, (unsigned long *) data); ++ putreg(child, i, tmp); ++ data += sizeof(long); ++ } ++ ret = 0; ++ break; ++ } ++#endif ++#ifdef PTRACE_GETFPREGS ++ case PTRACE_GETFPREGS: /* Get the child FPU state. */ ++ ret = get_fpregs(data, child); ++ break; ++#endif ++#ifdef PTRACE_SETFPREGS ++ case PTRACE_SETFPREGS: /* Set the child FPU state. */ ++ ret = set_fpregs(data, child); ++ break; ++#endif ++#ifdef PTRACE_GETFPXREGS ++ case PTRACE_GETFPXREGS: /* Get the child FPU state. */ ++ ret = get_fpxregs(data, child); ++ break; ++#endif ++#ifdef PTRACE_SETFPXREGS ++ case PTRACE_SETFPXREGS: /* Set the child FPU state. */ ++ ret = set_fpxregs(data, child); ++ break; ++#endif ++ case PTRACE_FAULTINFO: { ++ struct ptrace_faultinfo fault; ++ ++ fault = ((struct ptrace_faultinfo) ++ { .is_write = child->thread.err, ++ .addr = child->thread.cr2 }); ++ ret = copy_to_user((unsigned long *) data, &fault, ++ sizeof(fault)); ++ if(ret) ++ break; ++ break; ++ } ++ case PTRACE_SIGPENDING: ++ ret = copy_to_user((unsigned long *) data, ++ &child->pending.signal, ++ sizeof(child->pending.signal)); ++ break; ++ ++ case PTRACE_LDT: { ++ struct ptrace_ldt ldt; ++ ++ if(copy_from_user(&ldt, (unsigned long *) data, ++ sizeof(ldt))){ ++ ret = -EIO; ++ break; ++ } ++ ++ /* This one is confusing, so just punt and return -EIO for ++ * now ++ */ ++ ret = -EIO; ++ break; ++ } ++#ifdef CONFIG_PROC_MM ++ case PTRACE_SWITCH_MM: { ++ struct mm_struct *old = child->mm; ++ struct mm_struct *new = proc_mm_get_mm(data); ++ ++ if(IS_ERR(new)){ ++ ret = PTR_ERR(new); ++ break; ++ } ++ ++ atomic_inc(&new->mm_users); ++ child->mm = new; ++ child->active_mm = new; ++ mmput(old); ++ ret = 0; ++ break; ++ } ++#endif ++ default: ++ ret = -EIO; ++ break; ++ } ++ out_tsk: ++ free_task_struct(child); ++ out: ++ unlock_kernel(); ++ return ret; ++} ++ ++void syscall_trace(void) ++{ ++ if ((current->ptrace & (PT_PTRACED|PT_TRACESYS)) ++ != (PT_PTRACED|PT_TRACESYS)) ++ return; ++ current->exit_code = SIGTRAP; ++ current->state = TASK_STOPPED; ++ notify_parent(current, SIGCHLD); ++ schedule(); ++ /* ++ * this isn't the same as continuing with a signal, but it will do ++ * for normal use. strace only continues with a signal if the ++ * stopping signal is not SIGTRAP. -brl ++ */ ++ if (current->exit_code) { ++ send_sig(current->exit_code, current, 1); ++ current->exit_code = 0; ++ } ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/reboot.c um/arch/um/kernel/reboot.c +--- orig/arch/um/kernel/reboot.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/reboot.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,73 @@ ++/* ++ * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/sched.h" ++#include "user_util.h" ++#include "kern_util.h" ++#include "kern.h" ++#include "os.h" ++#include "mode.h" ++#include "choose-mode.h" ++ ++#ifdef CONFIG_SMP ++static void kill_idlers(int me) ++{ ++#ifdef CONFIG_MODE_TT ++ struct task_struct *p; ++ int i; ++ ++ for(i = 0; i < sizeof(init_tasks)/sizeof(init_tasks[0]); i++){ ++ p = init_tasks[i]; ++ if((p != NULL) && (p->thread.mode.tt.extern_pid != me) && ++ (p->thread.mode.tt.extern_pid != -1)) ++ os_kill_process(p->thread.mode.tt.extern_pid, 0); ++ } ++#endif ++} ++#endif ++ ++static void kill_off_processes(void) ++{ ++ CHOOSE_MODE(kill_off_processes_tt(), kill_off_processes_skas()); ++#ifdef CONFIG_SMP ++ kill_idlers(os_getpid()); ++#endif ++} ++ ++void uml_cleanup(void) ++{ ++ kill_off_processes(); ++ do_uml_exitcalls(); ++} ++ ++void machine_restart(char * __unused) ++{ ++ do_uml_exitcalls(); ++ kill_off_processes(); ++ CHOOSE_MODE(reboot_tt(), reboot_skas()); ++} ++ ++void machine_power_off(void) ++{ ++ do_uml_exitcalls(); ++ kill_off_processes(); ++ CHOOSE_MODE(halt_tt(), halt_skas()); ++} ++ ++void machine_halt(void) ++{ ++ machine_power_off(); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/resource.c um/arch/um/kernel/resource.c +--- orig/arch/um/kernel/resource.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/resource.c 2003-10-21 03:26:06.000000000 -0400 +@@ -0,0 +1,23 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/pci.h" ++ ++unsigned long resource_fixup(struct pci_dev * dev, struct resource * res, ++ unsigned long start, unsigned long size) ++{ ++ return start; ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/sigio_kern.c um/arch/um/kernel/sigio_kern.c +--- orig/arch/um/kernel/sigio_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/sigio_kern.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,57 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/kernel.h" ++#include "linux/list.h" ++#include "linux/slab.h" ++#include "asm/irq.h" ++#include "init.h" ++#include "sigio.h" ++#include "irq_user.h" ++#include "irq_kern.h" ++ ++/* Protected by sigio_lock() called from write_sigio_workaround */ ++static int sigio_irq_fd = -1; ++ ++void sigio_interrupt(int irq, void *data, struct pt_regs *unused) ++{ ++ read_sigio_fd(sigio_irq_fd); ++ reactivate_fd(sigio_irq_fd, SIGIO_WRITE_IRQ); ++} ++ ++int write_sigio_irq(int fd) ++{ ++ if(um_request_irq(SIGIO_WRITE_IRQ, fd, IRQ_READ, sigio_interrupt, ++ SA_INTERRUPT | SA_SAMPLE_RANDOM, "write sigio", ++ NULL)){ ++ printk("write_sigio_irq : um_request_irq failed\n"); ++ return(-1); ++ } ++ sigio_irq_fd = fd; ++ return(0); ++} ++ ++static spinlock_t sigio_spinlock = SPIN_LOCK_UNLOCKED; ++ ++void sigio_lock(void) ++{ ++ spin_lock(&sigio_spinlock); ++} ++ ++void sigio_unlock(void) ++{ ++ spin_unlock(&sigio_spinlock); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/sigio_user.c um/arch/um/kernel/sigio_user.c +--- orig/arch/um/kernel/sigio_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/sigio_user.c 2003-11-07 01:41:13.000000000 -0500 +@@ -0,0 +1,438 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <unistd.h> ++#include <stdlib.h> ++#include <termios.h> ++#include <pty.h> ++#include <signal.h> ++#include <errno.h> ++#include <string.h> ++#include <sched.h> ++#include <sys/socket.h> ++#include <sys/poll.h> ++#include "init.h" ++#include "user.h" ++#include "kern_util.h" ++#include "sigio.h" ++#include "helper.h" ++#include "os.h" ++ ++/* Changed during early boot */ ++int pty_output_sigio = 0; ++int pty_close_sigio = 0; ++ ++/* Used as a flag during SIGIO testing early in boot */ ++static volatile int got_sigio = 0; ++ ++void __init handler(int sig) ++{ ++ got_sigio = 1; ++} ++ ++struct openpty_arg { ++ int master; ++ int slave; ++ int err; ++}; ++ ++static void openpty_cb(void *arg) ++{ ++ struct openpty_arg *info = arg; ++ ++ info->err = 0; ++ if(openpty(&info->master, &info->slave, NULL, NULL, NULL)) ++ info->err = -errno; ++} ++ ++void __init check_one_sigio(void (*proc)(int, int)) ++{ ++ struct sigaction old, new; ++ struct termios tt; ++ struct openpty_arg pty = { .master = -1, .slave = -1 }; ++ int master, slave, err; ++ ++ initial_thread_cb(openpty_cb, &pty); ++ if(pty.err){ ++ printk("openpty failed, errno = %d\n", -pty.err); ++ return; ++ } ++ ++ master = pty.master; ++ slave = pty.slave; ++ ++ if((master == -1) || (slave == -1)){ ++ printk("openpty failed to allocate a pty\n"); ++ return; ++ } ++ ++ /* XXX These can fail with EINTR */ ++ if(tcgetattr(master, &tt) < 0) ++ panic("check_sigio : tcgetattr failed, errno = %d\n", errno); ++ cfmakeraw(&tt); ++ if(tcsetattr(master, TCSADRAIN, &tt) < 0) ++ panic("check_sigio : tcsetattr failed, errno = %d\n", errno); ++ ++ err = os_sigio_async(master, slave); ++ if(err < 0) ++ panic("tty_fds : sigio_async failed, err = %d\n", -err); ++ ++ if(sigaction(SIGIO, NULL, &old) < 0) ++ panic("check_sigio : sigaction 1 failed, errno = %d\n", errno); ++ new = old; ++ new.sa_handler = handler; ++ if(sigaction(SIGIO, &new, NULL) < 0) ++ panic("check_sigio : sigaction 2 failed, errno = %d\n", errno); ++ ++ got_sigio = 0; ++ (*proc)(master, slave); ++ ++ os_close_file(master); ++ os_close_file(slave); ++ ++ if(sigaction(SIGIO, &old, NULL) < 0) ++ panic("check_sigio : sigaction 3 failed, errno = %d\n", errno); ++} ++ ++static void tty_output(int master, int slave) ++{ ++ int n; ++ char buf[512]; ++ ++ printk("Checking that host ptys support output SIGIO..."); ++ ++ memset(buf, 0, sizeof(buf)); ++ ++ while(os_write_file(master, buf, sizeof(buf)) > 0) ; ++ if(errno != EAGAIN) ++ panic("check_sigio : write failed, errno = %d\n", errno); ++ while(((n = os_read_file(slave, buf, sizeof(buf))) > 0) && !got_sigio) ; ++ ++ if(got_sigio){ ++ printk("Yes\n"); ++ pty_output_sigio = 1; ++ } ++ else if(n == -EAGAIN) printk("No, enabling workaround\n"); ++ else panic("check_sigio : read failed, err = %d\n", n); ++} ++ ++static void tty_close(int master, int slave) ++{ ++ printk("Checking that host ptys support SIGIO on close..."); ++ ++ os_close_file(slave); ++ if(got_sigio){ ++ printk("Yes\n"); ++ pty_close_sigio = 1; ++ } ++ else printk("No, enabling workaround\n"); ++} ++ ++void __init check_sigio(void) ++{ ++ if((os_access("/dev/ptmx", OS_ACC_R_OK) < 0) && ++ (os_access("/dev/ptyp0", OS_ACC_R_OK) < 0)){ ++ printk("No pseudo-terminals available - skipping pty SIGIO " ++ "check\n"); ++ return; ++ } ++ check_one_sigio(tty_output); ++ check_one_sigio(tty_close); ++} ++ ++/* Protected by sigio_lock(), also used by sigio_cleanup, which is an ++ * exitcall. ++ */ ++static int write_sigio_pid = -1; ++ ++/* These arrays are initialized before the sigio thread is started, and ++ * the descriptors closed after it is killed. So, it can't see them change. ++ * On the UML side, they are changed under the sigio_lock. ++ */ ++static int write_sigio_fds[2] = { -1, -1 }; ++static int sigio_private[2] = { -1, -1 }; ++ ++struct pollfds { ++ struct pollfd *poll; ++ int size; ++ int used; ++}; ++ ++/* Protected by sigio_lock(). Used by the sigio thread, but the UML thread ++ * synchronizes with it. ++ */ ++struct pollfds current_poll = { ++ .poll = NULL, ++ .size = 0, ++ .used = 0 ++}; ++ ++struct pollfds next_poll = { ++ .poll = NULL, ++ .size = 0, ++ .used = 0 ++}; ++ ++static int write_sigio_thread(void *unused) ++{ ++ struct pollfds *fds, tmp; ++ struct pollfd *p; ++ int i, n, respond_fd; ++ char c; ++ ++ fds = ¤t_poll; ++ while(1){ ++ n = poll(fds->poll, fds->used, -1); ++ if(n < 0){ ++ if(errno == EINTR) continue; ++ printk("write_sigio_thread : poll returned %d, " ++ "errno = %d\n", n, errno); ++ } ++ for(i = 0; i < fds->used; i++){ ++ p = &fds->poll[i]; ++ if(p->revents == 0) continue; ++ if(p->fd == sigio_private[1]){ ++ n = os_read_file(sigio_private[1], &c, sizeof(c)); ++ if(n != sizeof(c)) ++ printk("write_sigio_thread : " ++ "read failed, err = %d\n", -n); ++ tmp = current_poll; ++ current_poll = next_poll; ++ next_poll = tmp; ++ respond_fd = sigio_private[1]; ++ } ++ else { ++ respond_fd = write_sigio_fds[1]; ++ fds->used--; ++ memmove(&fds->poll[i], &fds->poll[i + 1], ++ (fds->used - i) * sizeof(*fds->poll)); ++ } ++ ++ n = os_write_file(respond_fd, &c, sizeof(c)); ++ if(n != sizeof(c)) ++ printk("write_sigio_thread : write failed, " ++ "err = %d\n", -n); ++ } ++ } ++} ++ ++static int need_poll(int n) ++{ ++ if(n <= next_poll.size){ ++ next_poll.used = n; ++ return(0); ++ } ++ if(next_poll.poll != NULL) kfree(next_poll.poll); ++ next_poll.poll = um_kmalloc_atomic(n * sizeof(struct pollfd)); ++ if(next_poll.poll == NULL){ ++ printk("need_poll : failed to allocate new pollfds\n"); ++ next_poll.size = 0; ++ next_poll.used = 0; ++ return(-1); ++ } ++ next_poll.size = n; ++ next_poll.used = n; ++ return(0); ++} ++ ++static void update_thread(void) ++{ ++ unsigned long flags; ++ int n; ++ char c; ++ ++ flags = set_signals(0); ++ n = os_write_file(sigio_private[0], &c, sizeof(c)); ++ if(n != sizeof(c)){ ++ printk("update_thread : write failed, err = %d\n", -n); ++ goto fail; ++ } ++ ++ n = os_read_file(sigio_private[0], &c, sizeof(c)); ++ if(n != sizeof(c)){ ++ printk("update_thread : read failed, err = %d\n", -n); ++ goto fail; ++ } ++ ++ set_signals(flags); ++ return; ++ fail: ++ sigio_lock(); ++ if(write_sigio_pid != -1) ++ os_kill_process(write_sigio_pid, 1); ++ write_sigio_pid = -1; ++ os_close_file(sigio_private[0]); ++ os_close_file(sigio_private[1]); ++ os_close_file(write_sigio_fds[0]); ++ os_close_file(write_sigio_fds[1]); ++ sigio_unlock(); ++ set_signals(flags); ++} ++ ++int add_sigio_fd(int fd, int read) ++{ ++ int err = 0, i, n, events; ++ ++ sigio_lock(); ++ for(i = 0; i < current_poll.used; i++){ ++ if(current_poll.poll[i].fd == fd) ++ goto out; ++ } ++ ++ n = current_poll.used + 1; ++ err = need_poll(n); ++ if(err) ++ goto out; ++ ++ for(i = 0; i < current_poll.used; i++) ++ next_poll.poll[i] = current_poll.poll[i]; ++ ++ if(read) events = POLLIN; ++ else events = POLLOUT; ++ ++ next_poll.poll[n - 1] = ((struct pollfd) { .fd = fd, ++ .events = events, ++ .revents = 0 }); ++ update_thread(); ++ out: ++ sigio_unlock(); ++ return(err); ++} ++ ++int ignore_sigio_fd(int fd) ++{ ++ struct pollfd *p; ++ int err = 0, i, n = 0; ++ ++ sigio_lock(); ++ for(i = 0; i < current_poll.used; i++){ ++ if(current_poll.poll[i].fd == fd) break; ++ } ++ if(i == current_poll.used) ++ goto out; ++ ++ err = need_poll(current_poll.used - 1); ++ if(err) ++ goto out; ++ ++ for(i = 0; i < current_poll.used; i++){ ++ p = ¤t_poll.poll[i]; ++ if(p->fd != fd) next_poll.poll[n++] = current_poll.poll[i]; ++ } ++ if(n == i){ ++ printk("ignore_sigio_fd : fd %d not found\n", fd); ++ err = -1; ++ goto out; ++ } ++ ++ update_thread(); ++ out: ++ sigio_unlock(); ++ return(err); ++} ++ ++static int setup_initial_poll(int fd) ++{ ++ struct pollfd *p; ++ ++ p = um_kmalloc(sizeof(struct pollfd)); ++ if(p == NULL){ ++ printk("setup_initial_poll : failed to allocate poll\n"); ++ return(-1); ++ } ++ *p = ((struct pollfd) { .fd = fd, ++ .events = POLLIN, ++ .revents = 0 }); ++ current_poll = ((struct pollfds) { .poll = p, ++ .used = 1, ++ .size = 1 }); ++ return(0); ++} ++ ++void write_sigio_workaround(void) ++{ ++ unsigned long stack; ++ int err; ++ ++ sigio_lock(); ++ if(write_sigio_pid != -1) ++ goto out; ++ ++ err = os_pipe(write_sigio_fds, 1, 1); ++ if(err < 0){ ++ printk("write_sigio_workaround - os_pipe 1 failed, " ++ "err = %d\n", -err); ++ goto out; ++ } ++ err = os_pipe(sigio_private, 1, 1); ++ if(err < 0){ ++ printk("write_sigio_workaround - os_pipe 2 failed, " ++ "err = %d\n", -err); ++ goto out_close1; ++ } ++ if(setup_initial_poll(sigio_private[1])) ++ goto out_close2; ++ ++ write_sigio_pid = run_helper_thread(write_sigio_thread, NULL, ++ CLONE_FILES | CLONE_VM, &stack, 0); ++ ++ if(write_sigio_pid < 0) goto out_close2; ++ ++ if(write_sigio_irq(write_sigio_fds[0])) ++ goto out_kill; ++ ++ out: ++ sigio_unlock(); ++ return; ++ ++ out_kill: ++ os_kill_process(write_sigio_pid, 1); ++ write_sigio_pid = -1; ++ out_close2: ++ os_close_file(sigio_private[0]); ++ os_close_file(sigio_private[1]); ++ out_close1: ++ os_close_file(write_sigio_fds[0]); ++ os_close_file(write_sigio_fds[1]); ++ sigio_unlock(); ++} ++ ++int read_sigio_fd(int fd) ++{ ++ int n; ++ char c; ++ ++ n = os_read_file(fd, &c, sizeof(c)); ++ if(n != sizeof(c)){ ++ if(n < 0) { ++ printk("read_sigio_fd - read failed, err = %d\n", -n); ++ return(n); ++ } ++ else { ++ printk("read_sigio_fd - short read, bytes = %d\n", n); ++ return(-EIO); ++ } ++ } ++ return(n); ++} ++ ++static void sigio_cleanup(void) ++{ ++ if(write_sigio_pid != -1) ++ os_kill_process(write_sigio_pid, 1); ++} ++ ++__uml_exitcall(sigio_cleanup); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/signal_kern.c um/arch/um/kernel/signal_kern.c +--- orig/arch/um/kernel/signal_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/signal_kern.c 2003-11-19 03:50:58.000000000 -0500 +@@ -0,0 +1,369 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/config.h" ++#include "linux/stddef.h" ++#include "linux/sys.h" ++#include "linux/sched.h" ++#include "linux/wait.h" ++#include "linux/kernel.h" ++#include "linux/smp_lock.h" ++#include "linux/module.h" ++#include "linux/slab.h" ++#include "asm/signal.h" ++#include "asm/uaccess.h" ++#include "asm/ucontext.h" ++#include "user_util.h" ++#include "kern_util.h" ++#include "signal_kern.h" ++#include "signal_user.h" ++#include "kern.h" ++#include "frame_kern.h" ++#include "sigcontext.h" ++#include "mode.h" ++ ++EXPORT_SYMBOL(block_signals); ++EXPORT_SYMBOL(unblock_signals); ++ ++static void force_segv(int sig) ++{ ++ if(sig == SIGSEGV){ ++ struct k_sigaction *ka; ++ ++ ka = ¤t->sig->action[SIGSEGV - 1]; ++ ka->sa.sa_handler = SIG_DFL; ++ } ++ force_sig(SIGSEGV, current); ++} ++ ++#define _S(nr) (1<<((nr)-1)) ++ ++#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) ++ ++/* ++ * OK, we're invoking a handler ++ */ ++static int handle_signal(struct pt_regs *regs, unsigned long signr, ++ struct k_sigaction *ka, siginfo_t *info, ++ sigset_t *oldset, int error) ++{ ++ __sighandler_t handler; ++ void (*restorer)(void); ++ unsigned long sp; ++ sigset_t save; ++ int err, ret; ++ ++ ret = 0; ++ switch(error){ ++ case -ERESTARTNOHAND: ++ ret = -EINTR; ++ break; ++ ++ case -ERESTARTSYS: ++ if (!(ka->sa.sa_flags & SA_RESTART)) { ++ ret = -EINTR; ++ break; ++ } ++ /* fallthrough */ ++ case -ERESTARTNOINTR: ++ PT_REGS_RESTART_SYSCALL(regs); ++ PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs); ++ ++ /* This is because of the UM_SET_SYSCALL_RETURN and the fact ++ * that on i386 the system call number and return value are ++ * in the same register. When the system call restarts, %eax ++ * had better have the system call number in it. Since the ++ * return value doesn't matter (except that it shouldn't be ++ * -ERESTART*), we'll stick the system call number there. ++ */ ++ ret = PT_REGS_SYSCALL_NR(regs); ++ break; ++ } ++ ++ handler = ka->sa.sa_handler; ++ save = *oldset; ++ ++ if (ka->sa.sa_flags & SA_ONESHOT) ++ ka->sa.sa_handler = SIG_DFL; ++ ++ if (!(ka->sa.sa_flags & SA_NODEFER)) { ++ spin_lock_irq(¤t->sigmask_lock); ++ sigorsets(¤t->blocked, ¤t->blocked, ++ &ka->sa.sa_mask); ++ sigaddset(¤t->blocked, signr); ++ recalc_sigpending(current); ++ spin_unlock_irq(¤t->sigmask_lock); ++ } ++ ++ sp = PT_REGS_SP(regs); ++ ++ if((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags(sp) == 0)) ++ sp = current->sas_ss_sp + current->sas_ss_size; ++ ++ if(error != 0) PT_REGS_SET_SYSCALL_RETURN(regs, ret); ++ ++ if (ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer; ++ else restorer = NULL; ++ ++ if(ka->sa.sa_flags & SA_SIGINFO) ++ err = setup_signal_stack_si(sp, signr, (unsigned long) handler, ++ restorer, regs, info, &save); ++ else ++ err = setup_signal_stack_sc(sp, signr, (unsigned long) handler, ++ restorer, regs, &save); ++ if(err) goto segv; ++ ++ return(0); ++ segv: ++ force_segv(signr); ++ return(1); ++} ++ ++/* ++ * Note that 'init' is a special process: it doesn't get signals it doesn't ++ * want to handle. Thus you cannot kill init even with a SIGKILL even by ++ * mistake. ++ */ ++ ++static int kern_do_signal(struct pt_regs *regs, sigset_t *oldset, int error) ++{ ++ siginfo_t info; ++ struct k_sigaction *ka; ++ int err; ++ ++ if (!oldset) ++ oldset = ¤t->blocked; ++ ++ for (;;) { ++ unsigned long signr; ++ ++ spin_lock_irq(¤t->sigmask_lock); ++ signr = dequeue_signal(¤t->blocked, &info); ++ spin_unlock_irq(¤t->sigmask_lock); ++ ++ if (!signr) ++ break; ++ ++ if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { ++ /* Let the debugger run. */ ++ current->exit_code = signr; ++ current->state = TASK_STOPPED; ++ notify_parent(current, SIGCHLD); ++ schedule(); ++ ++ /* We're back. Did the debugger cancel the sig? */ ++ signr = current->exit_code; ++ if (!signr) ++ continue; ++ current->exit_code = 0; ++ ++ /* The debugger continued. Ignore SIGSTOP. */ ++ if (signr == SIGSTOP) ++ continue; ++ ++ /* Update the siginfo structure. Is this good? */ ++ if (signr != info.si_signo) { ++ info.si_signo = signr; ++ info.si_errno = 0; ++ info.si_code = SI_USER; ++ info.si_pid = current->p_pptr->pid; ++ info.si_uid = current->p_pptr->uid; ++ } ++ ++ /* If the (new) signal is now blocked, requeue it. */ ++ if (sigismember(¤t->blocked, signr)) { ++ send_sig_info(signr, &info, current); ++ continue; ++ } ++ } ++ ++ ka = ¤t->sig->action[signr-1]; ++ if (ka->sa.sa_handler == SIG_IGN) { ++ if (signr != SIGCHLD) ++ continue; ++ /* Check for SIGCHLD: it's special. */ ++ while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) ++ /* nothing */; ++ continue; ++ } ++ ++ if (ka->sa.sa_handler == SIG_DFL) { ++ int exit_code = signr; ++ ++ /* Init gets no signals it doesn't want. */ ++ if (current->pid == 1) ++ continue; ++ ++ switch (signr) { ++ case SIGCONT: case SIGCHLD: case SIGWINCH: case SIGURG: ++ continue; ++ ++ case SIGTSTP: case SIGTTIN: case SIGTTOU: ++ if (is_orphaned_pgrp(current->pgrp)) ++ continue; ++ /* FALLTHRU */ ++ ++ case SIGSTOP: { ++ struct signal_struct *sig; ++ current->state = TASK_STOPPED; ++ current->exit_code = signr; ++ sig = current->p_pptr->sig; ++ if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) ++ notify_parent(current, SIGCHLD); ++ schedule(); ++ continue; ++ } ++ case SIGQUIT: case SIGILL: case SIGTRAP: ++ case SIGABRT: case SIGFPE: case SIGSEGV: ++ case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: ++ if (do_coredump(signr, ¤t->thread.regs)) ++ exit_code |= 0x80; ++ /* FALLTHRU */ ++ ++ default: ++ sig_exit(signr, exit_code, &info); ++ /* NOTREACHED */ ++ } ++ } ++ ++ /* Whee! Actually deliver the signal. */ ++ err = handle_signal(regs, signr, ka, &info, oldset, error); ++ if(!err) return(1); ++ } ++ ++ /* Did we come from a system call? */ ++ if(PT_REGS_SYSCALL_NR(regs) >= 0){ ++ /* Restart the system call - no handlers present */ ++ if(PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOHAND || ++ PT_REGS_SYSCALL_RET(regs) == -ERESTARTSYS || ++ PT_REGS_SYSCALL_RET(regs) == -ERESTARTNOINTR){ ++ PT_REGS_ORIG_SYSCALL(regs) = PT_REGS_SYSCALL_NR(regs); ++ PT_REGS_RESTART_SYSCALL(regs); ++ } ++ } ++ ++ /* This closes a way to execute a system call on the host. If ++ * you set a breakpoint on a system call instruction and singlestep ++ * from it, the tracing thread used to PTRACE_SINGLESTEP the process ++ * rather than PTRACE_SYSCALL it, allowing the system call to execute ++ * on the host. The tracing thread will check this flag and ++ * PTRACE_SYSCALL if necessary. ++ */ ++ if((current->ptrace & PT_DTRACE) && ++ is_syscall(PT_REGS_IP(¤t->thread.regs))) ++ (void) CHOOSE_MODE(current->thread.mode.tt.singlestep_syscall = 1, 0); ++ ++ return(0); ++} ++ ++int do_signal(int error) ++{ ++ return(kern_do_signal(¤t->thread.regs, NULL, error)); ++} ++ ++/* ++ * Atomically swap in the new signal mask, and wait for a signal. ++ */ ++int sys_sigsuspend(int history0, int history1, old_sigset_t mask) ++{ ++ sigset_t saveset; ++ ++ mask &= _BLOCKABLE; ++ spin_lock_irq(¤t->sigmask_lock); ++ saveset = current->blocked; ++ siginitset(¤t->blocked, mask); ++ recalc_sigpending(current); ++ spin_unlock_irq(¤t->sigmask_lock); ++ ++ while (1) { ++ current->state = TASK_INTERRUPTIBLE; ++ schedule(); ++ if(kern_do_signal(¤t->thread.regs, &saveset, -EINTR)) ++ return(-EINTR); ++ } ++} ++ ++int sys_rt_sigsuspend(sigset_t *unewset, size_t sigsetsize) ++{ ++ sigset_t saveset, newset; ++ ++ /* XXX: Don't preclude handling different sized sigset_t's. */ ++ if (sigsetsize != sizeof(sigset_t)) ++ return -EINVAL; ++ ++ if (copy_from_user(&newset, unewset, sizeof(newset))) ++ return -EFAULT; ++ sigdelsetmask(&newset, ~_BLOCKABLE); ++ ++ spin_lock_irq(¤t->sigmask_lock); ++ saveset = current->blocked; ++ current->blocked = newset; ++ recalc_sigpending(current); ++ spin_unlock_irq(¤t->sigmask_lock); ++ ++ while (1) { ++ current->state = TASK_INTERRUPTIBLE; ++ schedule(); ++ if (kern_do_signal(¤t->thread.regs, &saveset, -EINTR)) ++ return(-EINTR); ++ } ++} ++ ++extern int userspace_pid[]; ++ ++static int copy_sc_from_user(struct pt_regs *to, void *from, ++ struct arch_frame_data *arch) ++{ ++ int ret; ++ ++ ret = CHOOSE_MODE(copy_sc_from_user_tt(UPT_SC(&to->regs), from, arch), ++ copy_sc_from_user_skas(userspace_pid[0], ++ &to->regs, from)); ++ return(ret); ++} ++ ++int sys_sigreturn(struct pt_regs regs) ++{ ++ void *sc = sp_to_sc(PT_REGS_SP(¤t->thread.regs)); ++ void *mask = sp_to_mask(PT_REGS_SP(¤t->thread.regs)); ++ int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long); ++ ++ spin_lock_irq(¤t->sigmask_lock); ++ copy_from_user(¤t->blocked.sig[0], sc_sigmask(sc), ++ sizeof(current->blocked.sig[0])); ++ copy_from_user(¤t->blocked.sig[1], mask, sig_size); ++ sigdelsetmask(¤t->blocked, ~_BLOCKABLE); ++ recalc_sigpending(current); ++ spin_unlock_irq(¤t->sigmask_lock); ++ copy_sc_from_user(¤t->thread.regs, sc, ++ &signal_frame_sc.common.arch); ++ return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); ++} ++ ++int sys_rt_sigreturn(struct pt_regs regs) ++{ ++ struct ucontext *uc = sp_to_uc(PT_REGS_SP(¤t->thread.regs)); ++ int sig_size = _NSIG_WORDS * sizeof(unsigned long); ++ ++ spin_lock_irq(¤t->sigmask_lock); ++ copy_from_user(¤t->blocked, &uc->uc_sigmask, sig_size); ++ sigdelsetmask(¤t->blocked, ~_BLOCKABLE); ++ recalc_sigpending(current); ++ spin_unlock_irq(¤t->sigmask_lock); ++ copy_sc_from_user(¤t->thread.regs, &uc->uc_mcontext, ++ &signal_frame_si.common.arch); ++ return(PT_REGS_SYSCALL_RET(¤t->thread.regs)); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/signal_user.c um/arch/um/kernel/signal_user.c +--- orig/arch/um/kernel/signal_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/signal_user.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,142 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdio.h> ++#include <unistd.h> ++#include <stdlib.h> ++#include <signal.h> ++#include <errno.h> ++#include <stdarg.h> ++#include <string.h> ++#include <sys/mman.h> ++#include "user_util.h" ++#include "kern_util.h" ++#include "user.h" ++#include "signal_user.h" ++#include "signal_kern.h" ++#include "sysdep/sigcontext.h" ++#include "sigcontext.h" ++ ++void set_sigstack(void *sig_stack, int size) ++{ ++ stack_t stack = ((stack_t) { .ss_flags = 0, ++ .ss_sp = (__ptr_t) sig_stack, ++ .ss_size = size - sizeof(void *) }); ++ ++ if(sigaltstack(&stack, NULL) != 0) ++ panic("enabling signal stack failed, errno = %d\n", errno); ++} ++ ++void set_handler(int sig, void (*handler)(int), int flags, ...) ++{ ++ struct sigaction action; ++ va_list ap; ++ int mask; ++ ++ va_start(ap, flags); ++ action.sa_handler = handler; ++ sigemptyset(&action.sa_mask); ++ while((mask = va_arg(ap, int)) != -1){ ++ sigaddset(&action.sa_mask, mask); ++ } ++ action.sa_flags = flags; ++ action.sa_restorer = NULL; ++ if(sigaction(sig, &action, NULL) < 0) ++ panic("sigaction failed"); ++} ++ ++int change_sig(int signal, int on) ++{ ++ sigset_t sigset, old; ++ ++ sigemptyset(&sigset); ++ sigaddset(&sigset, signal); ++ sigprocmask(on ? SIG_UNBLOCK : SIG_BLOCK, &sigset, &old); ++ return(!sigismember(&old, signal)); ++} ++ ++static void change_signals(int type) ++{ ++ sigset_t mask; ++ ++ sigemptyset(&mask); ++ sigaddset(&mask, SIGVTALRM); ++ sigaddset(&mask, SIGALRM); ++ sigaddset(&mask, SIGIO); ++ sigaddset(&mask, SIGPROF); ++ if(sigprocmask(type, &mask, NULL) < 0) ++ panic("Failed to change signal mask - errno = %d", errno); ++} ++ ++void block_signals(void) ++{ ++ change_signals(SIG_BLOCK); ++} ++ ++void unblock_signals(void) ++{ ++ change_signals(SIG_UNBLOCK); ++} ++ ++#define SIGIO_BIT 0 ++#define SIGVTALRM_BIT 1 ++ ++static int enable_mask(sigset_t *mask) ++{ ++ int sigs; ++ ++ sigs = sigismember(mask, SIGIO) ? 0 : 1 << SIGIO_BIT; ++ sigs |= sigismember(mask, SIGVTALRM) ? 0 : 1 << SIGVTALRM_BIT; ++ sigs |= sigismember(mask, SIGALRM) ? 0 : 1 << SIGVTALRM_BIT; ++ return(sigs); ++} ++ ++int get_signals(void) ++{ ++ sigset_t mask; ++ ++ if(sigprocmask(SIG_SETMASK, NULL, &mask) < 0) ++ panic("Failed to get signal mask"); ++ return(enable_mask(&mask)); ++} ++ ++int set_signals(int enable) ++{ ++ sigset_t mask; ++ int ret; ++ ++ sigemptyset(&mask); ++ if(enable & (1 << SIGIO_BIT)) ++ sigaddset(&mask, SIGIO); ++ if(enable & (1 << SIGVTALRM_BIT)){ ++ sigaddset(&mask, SIGVTALRM); ++ sigaddset(&mask, SIGALRM); ++ } ++ if(sigprocmask(SIG_UNBLOCK, &mask, &mask) < 0) ++ panic("Failed to enable signals"); ++ ret = enable_mask(&mask); ++ sigemptyset(&mask); ++ if((enable & (1 << SIGIO_BIT)) == 0) ++ sigaddset(&mask, SIGIO); ++ if((enable & (1 << SIGVTALRM_BIT)) == 0){ ++ sigaddset(&mask, SIGVTALRM); ++ sigaddset(&mask, SIGALRM); ++ } ++ if(sigprocmask(SIG_BLOCK, &mask, NULL) < 0) ++ panic("Failed to block signals"); ++ ++ return(ret); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/exec_kern.c um/arch/um/kernel/skas/exec_kern.c +--- orig/arch/um/kernel/skas/exec_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/exec_kern.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,41 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/kernel.h" ++#include "asm/current.h" ++#include "asm/page.h" ++#include "asm/signal.h" ++#include "asm/ptrace.h" ++#include "asm/uaccess.h" ++#include "asm/mmu_context.h" ++#include "tlb.h" ++#include "skas.h" ++#include "mmu.h" ++#include "os.h" ++ ++void flush_thread_skas(void) ++{ ++ force_flush_all(); ++ switch_mm_skas(current->mm->context.skas.mm_fd); ++} ++ ++void start_thread_skas(struct pt_regs *regs, unsigned long eip, ++ unsigned long esp) ++{ ++ set_fs(USER_DS); ++ PT_REGS_IP(regs) = eip; ++ PT_REGS_SP(regs) = esp; ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/exec_user.c um/arch/um/kernel/skas/exec_user.c +--- orig/arch/um/kernel/skas/exec_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/exec_user.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,61 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdlib.h> ++#include <errno.h> ++#include <signal.h> ++#include <sched.h> ++#include <sys/wait.h> ++#include <sys/ptrace.h> ++#include "user.h" ++#include "kern_util.h" ++#include "os.h" ++#include "time_user.h" ++ ++static int user_thread_tramp(void *arg) ++{ ++ if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) ++ panic("user_thread_tramp - PTRACE_TRACEME failed, " ++ "errno = %d\n", errno); ++ enable_timer(); ++ os_stop_process(os_getpid()); ++ return(0); ++} ++ ++int user_thread(unsigned long stack, int flags) ++{ ++ int pid, status; ++ ++ pid = clone(user_thread_tramp, (void *) stack_sp(stack), ++ flags | CLONE_FILES | SIGCHLD, NULL); ++ if(pid < 0){ ++ printk("user_thread - clone failed, errno = %d\n", errno); ++ return(pid); ++ } ++ ++ if(waitpid(pid, &status, WUNTRACED) < 0){ ++ printk("user_thread - waitpid failed, errno = %d\n", errno); ++ return(-errno); ++ } ++ ++ if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)){ ++ printk("user_thread - trampoline didn't stop, status = %d\n", ++ status); ++ return(-EINVAL); ++ } ++ ++ return(pid); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/include/mmu.h um/arch/um/kernel/skas/include/mmu.h +--- orig/arch/um/kernel/skas/include/mmu.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/include/mmu.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,27 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __SKAS_MMU_H ++#define __SKAS_MMU_H ++ ++#include "linux/list.h" ++#include "linux/spinlock.h" ++ ++struct mmu_context_skas { ++ int mm_fd; ++}; ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/include/mode.h um/arch/um/kernel/skas/include/mode.h +--- orig/arch/um/kernel/skas/include/mode.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/include/mode.h 2003-11-19 03:27:36.000000000 -0500 +@@ -0,0 +1,37 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __MODE_SKAS_H__ ++#define __MODE_SKAS_H__ ++ ++extern unsigned long exec_regs[]; ++extern unsigned long exec_fp_regs[]; ++extern unsigned long exec_fpx_regs[]; ++extern int have_fpx_regs; ++ ++extern void user_time_init_skas(void); ++extern int copy_sc_from_user_skas(int pid, union uml_pt_regs *regs, ++ void *from_ptr); ++extern int copy_sc_to_user_skas(int pid, void *to_ptr, void *fp, ++ union uml_pt_regs *regs, ++ unsigned long fault_addr, int fault_type); ++extern void sig_handler_common_skas(int sig, void *sc_ptr); ++extern void halt_skas(void); ++extern void reboot_skas(void); ++extern void kill_off_processes_skas(void); ++extern int is_skas_winch(int pid, int fd, void *data); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/include/mode_kern.h um/arch/um/kernel/skas/include/mode_kern.h +--- orig/arch/um/kernel/skas/include/mode_kern.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/include/mode_kern.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,51 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __SKAS_MODE_KERN_H__ ++#define __SKAS_MODE_KERN_H__ ++ ++#include "linux/sched.h" ++#include "asm/page.h" ++#include "asm/ptrace.h" ++ ++extern void flush_thread_skas(void); ++extern void *_switch_to_skas(void *prev, void *next); ++extern void start_thread_skas(struct pt_regs *regs, unsigned long eip, ++ unsigned long esp); ++extern int copy_thread_skas(int nr, unsigned long clone_flags, ++ unsigned long sp, unsigned long stack_top, ++ struct task_struct *p, struct pt_regs *regs); ++extern void release_thread_skas(struct task_struct *task); ++extern void exit_thread_skas(void); ++extern void initial_thread_cb_skas(void (*proc)(void *), void *arg); ++extern void init_idle_skas(void); ++extern void flush_tlb_kernel_vm_skas(void); ++extern void __flush_tlb_one_skas(unsigned long addr); ++extern void flush_tlb_range_skas(struct mm_struct *mm, unsigned long start, ++ unsigned long end); ++extern void flush_tlb_mm_skas(struct mm_struct *mm); ++extern void force_flush_all_skas(void); ++extern long execute_syscall_skas(void *r); ++extern void before_mem_skas(unsigned long unused); ++extern unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, ++ unsigned long *task_size_out); ++extern int start_uml_skas(void); ++extern int external_pid_skas(struct task_struct *task); ++extern int thread_pid_skas(struct thread_struct *thread); ++ ++#define kmem_end_skas (host_task_size - 1024 * 1024) ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/include/proc_mm.h um/arch/um/kernel/skas/include/proc_mm.h +--- orig/arch/um/kernel/skas/include/proc_mm.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/include/proc_mm.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,55 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __SKAS_PROC_MM_H ++#define __SKAS_PROC_MM_H ++ ++#define MM_MMAP 54 ++#define MM_MUNMAP 55 ++#define MM_MPROTECT 56 ++#define MM_COPY_SEGMENTS 57 ++ ++struct mm_mmap { ++ unsigned long addr; ++ unsigned long len; ++ unsigned long prot; ++ unsigned long flags; ++ unsigned long fd; ++ unsigned long offset; ++}; ++ ++struct mm_munmap { ++ unsigned long addr; ++ unsigned long len; ++}; ++ ++struct mm_mprotect { ++ unsigned long addr; ++ unsigned long len; ++ unsigned int prot; ++}; ++ ++struct proc_mm_op { ++ int op; ++ union { ++ struct mm_mmap mmap; ++ struct mm_munmap munmap; ++ struct mm_mprotect mprotect; ++ int copy_segments; ++ } u; ++}; ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/include/ptrace-skas.h um/arch/um/kernel/skas/include/ptrace-skas.h +--- orig/arch/um/kernel/skas/include/ptrace-skas.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/include/ptrace-skas.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,57 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __PTRACE_SKAS_H ++#define __PTRACE_SKAS_H ++ ++#include "uml-config.h" ++ ++#ifdef UML_CONFIG_MODE_SKAS ++ ++#include "skas_ptregs.h" ++ ++#define HOST_FRAME_SIZE 17 ++ ++#define REGS_IP(r) ((r)[HOST_IP]) ++#define REGS_SP(r) ((r)[HOST_SP]) ++#define REGS_EFLAGS(r) ((r)[HOST_EFLAGS]) ++#define REGS_EAX(r) ((r)[HOST_EAX]) ++#define REGS_EBX(r) ((r)[HOST_EBX]) ++#define REGS_ECX(r) ((r)[HOST_ECX]) ++#define REGS_EDX(r) ((r)[HOST_EDX]) ++#define REGS_ESI(r) ((r)[HOST_ESI]) ++#define REGS_EDI(r) ((r)[HOST_EDI]) ++#define REGS_EBP(r) ((r)[HOST_EBP]) ++#define REGS_CS(r) ((r)[HOST_CS]) ++#define REGS_SS(r) ((r)[HOST_SS]) ++#define REGS_DS(r) ((r)[HOST_DS]) ++#define REGS_ES(r) ((r)[HOST_ES]) ++#define REGS_FS(r) ((r)[HOST_FS]) ++#define REGS_GS(r) ((r)[HOST_GS]) ++ ++#define REGS_SET_SYSCALL_RETURN(r, res) REGS_EAX(r) = (res) ++ ++#define REGS_RESTART_SYSCALL(r) IP_RESTART_SYSCALL(REGS_IP(r)) ++ ++#define REGS_SEGV_IS_FIXABLE(r) SEGV_IS_FIXABLE((r)->trap_type) ++ ++#define REGS_FAULT_ADDR(r) ((r)->fault_addr) ++ ++#define REGS_FAULT_WRITE(r) FAULT_WRITE((r)->fault_type) ++ ++#endif ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/include/skas.h um/arch/um/kernel/skas/include/skas.h +--- orig/arch/um/kernel/skas/include/skas.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/include/skas.h 2003-11-19 03:00:51.000000000 -0500 +@@ -0,0 +1,49 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __SKAS_H ++#define __SKAS_H ++ ++#include "sysdep/ptrace.h" ++ ++extern int userspace_pid[]; ++ ++extern void switch_threads(void *me, void *next); ++extern void thread_wait(void *sw, void *fb); ++extern void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, ++ void (*handler)(int)); ++extern int start_idle_thread(void *stack, void *switch_buf_ptr, ++ void **fork_buf_ptr); ++extern int user_thread(unsigned long stack, int flags); ++extern void userspace(union uml_pt_regs *regs); ++extern void new_thread_proc(void *stack, void (*handler)(int sig)); ++extern void remove_sigstack(void); ++extern void new_thread_handler(int sig); ++extern void handle_syscall(union uml_pt_regs *regs); ++extern void map(int fd, unsigned long virt, unsigned long phys, ++ unsigned long len, int r, int w, int x); ++extern int unmap(int fd, void *addr, int len); ++extern int protect(int fd, unsigned long addr, unsigned long len, ++ int r, int w, int x, int must_succeed); ++extern void user_signal(int sig, union uml_pt_regs *regs); ++extern int singlestepping_skas(void); ++extern int new_mm(int from); ++extern void save_registers(union uml_pt_regs *regs); ++extern void restore_registers(union uml_pt_regs *regs); ++extern void start_userspace(int cpu); ++extern void init_registers(int pid); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/include/uaccess.h um/arch/um/kernel/skas/include/uaccess.h +--- orig/arch/um/kernel/skas/include/uaccess.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/include/uaccess.h 2003-12-17 01:19:45.000000000 -0500 +@@ -0,0 +1,38 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __SKAS_UACCESS_H ++#define __SKAS_UACCESS_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); ++} ++ ++#endif ++ ++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); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/Makefile um/arch/um/kernel/skas/Makefile +--- orig/arch/um/kernel/skas/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/Makefile 2003-11-11 06:36:12.000000000 -0500 +@@ -0,0 +1,31 @@ ++# ++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++# Licensed under the GPL ++# ++ ++O_TARGET = skas.o ++ ++obj-y = exec_kern.o exec_user.o mem.o mem_user.o mmu.o process.o \ ++ process_kern.o syscall_kern.o syscall_user.o time.o tlb.o trap_user.o \ ++ uaccess.o ++ ++subdir-y = sys-$(SUBARCH) ++ ++obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o)) ++ ++USER_OBJS = $(filter %_user.o,$(obj-y)) process.o time.o ++ ++include $(TOPDIR)/Rules.make ++ ++include/skas_ptregs.h : util/mk_ptregs ++ util/mk_ptregs > $@ ++ ++util/mk_ptregs : ++ $(MAKE) -C util ++ ++$(USER_OBJS) : %.o: %.c ++ $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< ++ ++clean : ++ $(MAKE) -C util clean ++ $(RM) -f include/skas_ptregs.h +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/mem.c um/arch/um/kernel/skas/mem.c +--- orig/arch/um/kernel/skas/mem.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/mem.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/config.h" ++#include "linux/mm.h" ++#include "mem_user.h" ++ ++unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, ++ unsigned long *task_size_out) ++{ ++ /* Round up to the nearest 4M */ ++ unsigned long top = ROUND_4M((unsigned long) &arg); ++ ++ *host_size_out = top; ++ *task_size_out = top; ++ return(((unsigned long) set_task_sizes_skas) & ~0xffffff); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/mem_user.c um/arch/um/kernel/skas/mem_user.c +--- orig/arch/um/kernel/skas/mem_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/mem_user.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,105 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <errno.h> ++#include <sys/mman.h> ++#include <sys/ptrace.h> ++#include "mem_user.h" ++#include "mem.h" ++#include "user.h" ++#include "os.h" ++#include "proc_mm.h" ++ ++void map(int fd, unsigned long virt, unsigned long phys, unsigned long len, ++ int r, int w, int x) ++{ ++ struct proc_mm_op map; ++ __u64 offset; ++ int prot, n, phys_fd; ++ ++ prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | ++ (x ? PROT_EXEC : 0); ++ phys_fd = phys_mapping(phys, &offset); ++ ++ map = ((struct proc_mm_op) { .op = MM_MMAP, ++ .u = ++ { .mmap = ++ { .addr = virt, ++ .len = len, ++ .prot = prot, ++ .flags = MAP_SHARED | ++ MAP_FIXED, ++ .fd = phys_fd, ++ .offset = offset ++ } } } ); ++ n = os_write_file(fd, &map, sizeof(map)); ++ if(n != sizeof(map)) ++ printk("map : /proc/mm map failed, err = %d\n", -n); ++} ++ ++int unmap(int fd, void *addr, int len) ++{ ++ struct proc_mm_op unmap; ++ int n; ++ ++ unmap = ((struct proc_mm_op) { .op = MM_MUNMAP, ++ .u = ++ { .munmap = ++ { .addr = (unsigned long) addr, ++ .len = len } } } ); ++ n = os_write_file(fd, &unmap, sizeof(unmap)); ++ if(n != sizeof(unmap)) { ++ if(n < 0) ++ return(n); ++ else if(n > 0) ++ return(-EIO); ++ } ++ ++ return(0); ++} ++ ++int protect(int fd, unsigned long addr, unsigned long len, int r, int w, ++ int x, int must_succeed) ++{ ++ struct proc_mm_op protect; ++ int prot, n; ++ ++ prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | ++ (x ? PROT_EXEC : 0); ++ ++ protect = ((struct proc_mm_op) { .op = MM_MPROTECT, ++ .u = ++ { .mprotect = ++ { .addr = (unsigned long) addr, ++ .len = len, ++ .prot = prot } } } ); ++ ++ n = os_write_file(fd, &protect, sizeof(protect)); ++ if(n != sizeof(protect)) { ++ if(n == 0) return(0); ++ ++ if(must_succeed) ++ panic("protect failed, err = %d", -n); ++ ++ return(-EIO); ++ } ++ ++ return(0); ++} ++ ++void before_mem_skas(unsigned long unused) ++{ ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/mmu.c um/arch/um/kernel/skas/mmu.c +--- orig/arch/um/kernel/skas/mmu.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/mmu.c 2003-11-15 22:25:20.000000000 -0500 +@@ -0,0 +1,46 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/list.h" ++#include "linux/spinlock.h" ++#include "linux/slab.h" ++#include "asm/segment.h" ++#include "asm/mmu.h" ++#include "os.h" ++#include "skas.h" ++ ++int init_new_context_skas(struct task_struct *task, struct mm_struct *mm) ++{ ++ int from; ++ ++ if((current->mm != NULL) && (current->mm != &init_mm)) ++ from = current->mm->context.skas.mm_fd; ++ else from = -1; ++ ++ mm->context.skas.mm_fd = new_mm(from); ++ if(mm->context.skas.mm_fd < 0){ ++ printk("init_new_context_skas - new_mm failed, errno = %d\n", ++ mm->context.skas.mm_fd); ++ return(mm->context.skas.mm_fd); ++ } ++ ++ return(0); ++} ++ ++void destroy_context_skas(struct mm_struct *mm) ++{ ++ os_close_file(mm->context.skas.mm_fd); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/process.c um/arch/um/kernel/skas/process.c +--- orig/arch/um/kernel/skas/process.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/process.c 2003-11-19 03:00:01.000000000 -0500 +@@ -0,0 +1,417 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdlib.h> ++#include <unistd.h> ++#include <errno.h> ++#include <signal.h> ++#include <setjmp.h> ++#include <sched.h> ++#include <sys/wait.h> ++#include <sys/ptrace.h> ++#include <sys/mman.h> ++#include <sys/user.h> ++#include <asm/unistd.h> ++#include "user.h" ++#include "ptrace_user.h" ++#include "time_user.h" ++#include "sysdep/ptrace.h" ++#include "user_util.h" ++#include "kern_util.h" ++#include "skas.h" ++#include "sysdep/sigcontext.h" ++#include "os.h" ++#include "proc_mm.h" ++#include "skas_ptrace.h" ++#include "chan_user.h" ++ ++int is_skas_winch(int pid, int fd, void *data) ++{ ++ if(pid != getpid()) ++ return(0); ++ ++ register_winch_irq(-1, fd, -1, data); ++ return(1); ++} ++ ++/* These are set once at boot time and not changed thereafter */ ++ ++unsigned long exec_regs[FRAME_SIZE]; ++unsigned long exec_fp_regs[HOST_FP_SIZE]; ++unsigned long exec_fpx_regs[HOST_XFP_SIZE]; ++int have_fpx_regs = 1; ++ ++static void handle_segv(int pid) ++{ ++ struct ptrace_faultinfo fault; ++ int err; ++ ++ err = ptrace(PTRACE_FAULTINFO, pid, 0, &fault); ++ if(err) ++ panic("handle_segv - PTRACE_FAULTINFO failed, errno = %d\n", ++ errno); ++ ++ segv(fault.addr, 0, FAULT_WRITE(fault.is_write), 1, NULL); ++} ++ ++static void handle_trap(int pid, union uml_pt_regs *regs) ++{ ++ int err, syscall_nr, status; ++ ++ syscall_nr = PT_SYSCALL_NR(regs->skas.regs); ++ UPT_SYSCALL_NR(regs) = syscall_nr; ++ if(syscall_nr < 1){ ++ relay_signal(SIGTRAP, regs); ++ return; ++ } ++ ++ err = ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_getpid); ++ if(err < 0) ++ panic("handle_trap - nullifying syscall failed errno = %d\n", ++ errno); ++ ++ err = ptrace(PTRACE_SYSCALL, pid, 0, 0); ++ if(err < 0) ++ panic("handle_trap - continuing to end of syscall failed, " ++ "errno = %d\n", errno); ++ ++ err = waitpid(pid, &status, WUNTRACED); ++ if((err < 0) || !WIFSTOPPED(status) || (WSTOPSIG(status) != SIGTRAP)) ++ panic("handle_trap - failed to wait at end of syscall, " ++ "errno = %d, status = %d\n", errno, status); ++ ++ handle_syscall(regs); ++} ++ ++static int userspace_tramp(void *arg) ++{ ++ init_new_thread_signals(0); ++ enable_timer(); ++ ptrace(PTRACE_TRACEME, 0, 0, 0); ++ os_stop_process(os_getpid()); ++ return(0); ++} ++ ++/* Each element set once, and only accessed by a single processor anyway */ ++#define NR_CPUS 1 ++int userspace_pid[NR_CPUS]; ++ ++void start_userspace(int cpu) ++{ ++ void *stack; ++ unsigned long sp; ++ int pid, status, n; ++ ++ stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, ++ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); ++ if(stack == MAP_FAILED) ++ panic("start_userspace : mmap failed, errno = %d", errno); ++ sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *); ++ ++ pid = clone(userspace_tramp, (void *) sp, ++ CLONE_FILES | CLONE_VM | SIGCHLD, NULL); ++ if(pid < 0) ++ panic("start_userspace : clone failed, errno = %d", errno); ++ ++ do { ++ n = waitpid(pid, &status, WUNTRACED); ++ if(n < 0) ++ panic("start_userspace : wait failed, errno = %d", ++ errno); ++ } while(WIFSTOPPED(status) && (WSTOPSIG(status) == SIGVTALRM)); ++ ++ if(!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP)) ++ panic("start_userspace : expected SIGSTOP, got status = %d", ++ status); ++ ++ if(munmap(stack, PAGE_SIZE) < 0) ++ panic("start_userspace : munmap failed, errno = %d\n", errno); ++ ++ userspace_pid[cpu] = pid; ++} ++ ++void userspace(union uml_pt_regs *regs) ++{ ++ int err, status, op, pid = userspace_pid[0]; ++ ++ restore_registers(regs); ++ ++ err = ptrace(PTRACE_SYSCALL, pid, 0, 0); ++ if(err) ++ panic("userspace - PTRACE_SYSCALL failed, errno = %d\n", ++ errno); ++ while(1){ ++ err = waitpid(pid, &status, WUNTRACED); ++ if(err < 0) ++ panic("userspace - waitpid failed, errno = %d\n", ++ errno); ++ ++ regs->skas.is_user = 1; ++ save_registers(regs); ++ ++ if(WIFSTOPPED(status)){ ++ switch(WSTOPSIG(status)){ ++ case SIGSEGV: ++ handle_segv(pid); ++ break; ++ case SIGTRAP: ++ handle_trap(pid, regs); ++ break; ++ case SIGIO: ++ case SIGVTALRM: ++ case SIGILL: ++ case SIGBUS: ++ case SIGFPE: ++ case SIGWINCH: ++ user_signal(WSTOPSIG(status), regs); ++ break; ++ default: ++ printk("userspace - child stopped with signal " ++ "%d\n", WSTOPSIG(status)); ++ } ++ interrupt_end(); ++ } ++ ++ restore_registers(regs); ++ ++ op = singlestepping_skas() ? PTRACE_SINGLESTEP : ++ PTRACE_SYSCALL; ++ err = ptrace(op, pid, 0, 0); ++ if(err) ++ panic("userspace - PTRACE_SYSCALL failed, " ++ "errno = %d\n", errno); ++ } ++} ++ ++void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, ++ void (*handler)(int)) ++{ ++ jmp_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) ++{ ++ jmp_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) ++{ ++ jmp_buf my_buf, **me_ptr = me, *next_buf = next; ++ ++ *me_ptr = &my_buf; ++ if(sigsetjmp(my_buf, 1) == 0) ++ siglongjmp(*next_buf, 1); ++} ++ ++static jmp_buf initial_jmpbuf; ++ ++/* XXX Make these percpu */ ++static void (*cb_proc)(void *arg); ++static void *cb_arg; ++static jmp_buf *cb_back; ++ ++int start_idle_thread(void *stack, void *switch_buf_ptr, void **fork_buf_ptr) ++{ ++ jmp_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) ++{ ++ jmp_buf here; ++ ++ cb_proc = proc; ++ cb_arg = arg; ++ cb_back = &here; ++ ++ block_signals(); ++ if(sigsetjmp(here, 1) == 0) ++ siglongjmp(initial_jmpbuf, 2); ++ unblock_signals(); ++ ++ cb_proc = NULL; ++ cb_arg = NULL; ++ cb_back = NULL; ++} ++ ++void halt_skas(void) ++{ ++ block_signals(); ++ siglongjmp(initial_jmpbuf, 3); ++} ++ ++void reboot_skas(void) ++{ ++ block_signals(); ++ siglongjmp(initial_jmpbuf, 4); ++} ++ ++int new_mm(int from) ++{ ++ struct proc_mm_op copy; ++ int n, fd = os_open_file("/proc/mm", ++ of_cloexec(of_write(OPENFLAGS())), 0); ++ ++ if(fd < 0) ++ return(fd); ++ ++ if(from != -1){ ++ copy = ((struct proc_mm_op) { .op = MM_COPY_SEGMENTS, ++ .u = ++ { .copy_segments = from } } ); ++ n = os_write_file(fd, ©, sizeof(copy)); ++ if(n != sizeof(copy)) ++ printk("new_mm : /proc/mm copy_segments failed, " ++ "err = %d\n", -n); ++ } ++ ++ return(fd); ++} ++ ++void switch_mm_skas(int mm_fd) ++{ ++ int err; ++ ++#warning need cpu pid in switch_mm_skas ++ err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, mm_fd); ++ if(err) ++ panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n", ++ errno); ++} ++ ++void kill_off_processes_skas(void) ++{ ++#warning need to loop over userspace_pids in kill_off_processes_skas ++ os_kill_process(userspace_pid[0], 1); ++} ++ ++void init_registers(int pid) ++{ ++ int err; ++ ++ if(ptrace(PTRACE_GETREGS, pid, 0, exec_regs) < 0) ++ panic("check_ptrace : PTRACE_GETREGS failed, errno = %d", ++ errno); ++ ++ err = ptrace(PTRACE_GETFPXREGS, pid, 0, exec_fpx_regs); ++ if(!err) ++ return; ++ ++ have_fpx_regs = 0; ++ if(errno != EIO) ++ panic("check_ptrace : PTRACE_GETFPXREGS failed, errno = %d", ++ errno); ++ ++ err = ptrace(PTRACE_GETFPREGS, pid, 0, exec_fp_regs); ++ if(err) ++ panic("check_ptrace : PTRACE_GETFPREGS failed, errno = %d", ++ errno); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/process_kern.c um/arch/um/kernel/skas/process_kern.c +--- orig/arch/um/kernel/skas/process_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/process_kern.c 2003-11-19 03:18:25.000000000 -0500 +@@ -0,0 +1,196 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/sched.h" ++#include "linux/slab.h" ++#include "kern_util.h" ++#include "time_user.h" ++#include "signal_user.h" ++#include "skas.h" ++#include "os.h" ++#include "user_util.h" ++#include "tlb.h" ++#include "frame.h" ++#include "kern.h" ++#include "mode.h" ++ ++int singlestepping_skas(void) ++{ ++ int ret = current->ptrace & PT_DTRACE; ++ ++ current->ptrace &= ~PT_DTRACE; ++ return(ret); ++} ++ ++void *_switch_to_skas(void *prev, void *next) ++{ ++ struct task_struct *from, *to; ++ ++ from = prev; ++ to = next; ++ ++ /* XXX need to check runqueues[cpu].idle */ ++ if(current->pid == 0) ++ switch_timers(0); ++ ++ to->thread.prev_sched = from; ++ set_current(to); ++ ++ switch_threads(&from->thread.mode.skas.switch_buf, ++ to->thread.mode.skas.switch_buf); ++ ++ if(current->pid == 0) ++ switch_timers(1); ++ ++ return(current->thread.prev_sched); ++} ++ ++extern void schedule_tail(struct task_struct *prev); ++ ++void new_thread_handler(int sig) ++{ ++ int (*fn)(void *), n; ++ void *arg; ++ ++ fn = current->thread.request.u.thread.proc; ++ arg = current->thread.request.u.thread.arg; ++ change_sig(SIGUSR1, 1); ++ thread_wait(¤t->thread.mode.skas.switch_buf, ++ current->thread.mode.skas.fork_buf); ++ ++ if(current->thread.prev_sched != NULL) ++ schedule_tail(current->thread.prev_sched); ++ current->thread.prev_sched = NULL; ++ ++ /* The return value is 1 if the kernel thread execs a process, ++ * 0 if it just exits ++ */ ++ n = run_kernel_thread(fn, arg, ¤t->thread.exec_buf); ++ if(n == 1) ++ userspace(¤t->thread.regs.regs); ++ else do_exit(0); ++} ++ ++void new_thread_proc(void *stack, void (*handler)(int sig)) ++{ ++ init_new_thread_stack(stack, handler); ++ os_usr1_process(os_getpid()); ++} ++ ++void release_thread_skas(struct task_struct *task) ++{ ++} ++ ++void exit_thread_skas(void) ++{ ++} ++ ++void fork_handler(int sig) ++{ ++ change_sig(SIGUSR1, 1); ++ thread_wait(¤t->thread.mode.skas.switch_buf, ++ current->thread.mode.skas.fork_buf); ++ ++ force_flush_all(); ++ if(current->thread.prev_sched != NULL) ++ schedule_tail(current->thread.prev_sched); ++ current->thread.prev_sched = NULL; ++ unblock_signals(); ++ ++ userspace(¤t->thread.regs.regs); ++} ++ ++int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp, ++ unsigned long stack_top, struct task_struct * p, ++ struct pt_regs *regs) ++{ ++ void (*handler)(int); ++ ++ if(current->thread.forking){ ++ memcpy(&p->thread.regs.regs.skas, ++ ¤t->thread.regs.regs.skas, ++ sizeof(p->thread.regs.regs.skas)); ++ REGS_SET_SYSCALL_RETURN(p->thread.regs.regs.skas.regs, 0); ++ if(sp != 0) REGS_SP(p->thread.regs.regs.skas.regs) = sp; ++ ++ handler = fork_handler; ++ } ++ else { ++ memcpy(p->thread.regs.regs.skas.regs, exec_regs, ++ sizeof(p->thread.regs.regs.skas.regs)); ++ memcpy(p->thread.regs.regs.skas.fp, exec_fp_regs, ++ sizeof(p->thread.regs.regs.skas.fp)); ++ memcpy(p->thread.regs.regs.skas.xfp, exec_fpx_regs, ++ sizeof(p->thread.regs.regs.skas.xfp)); ++ p->thread.request.u.thread = current->thread.request.u.thread; ++ handler = new_thread_handler; ++ } ++ ++ new_thread((void *) p->thread.kernel_stack, ++ &p->thread.mode.skas.switch_buf, ++ &p->thread.mode.skas.fork_buf, handler); ++ return(0); ++} ++ ++void init_idle_skas(void) ++{ ++ cpu_tasks[current->processor].pid = os_getpid(); ++} ++ ++extern void start_kernel(void); ++ ++static int start_kernel_proc(void *unused) ++{ ++ int pid; ++ ++ block_signals(); ++ pid = os_getpid(); ++ ++ cpu_tasks[0].pid = pid; ++ cpu_tasks[0].task = current; ++#ifdef CONFIG_SMP ++ cpu_online_map = 1; ++#endif ++ start_kernel(); ++ return(0); ++} ++ ++int start_uml_skas(void) ++{ ++ start_userspace(0); ++ capture_signal_stack(); ++ idle_timer(); ++ ++ init_new_thread_signals(1); ++ ++ init_task.thread.request.u.thread.proc = start_kernel_proc; ++ init_task.thread.request.u.thread.arg = NULL; ++ return(start_idle_thread((void *) init_task.thread.kernel_stack, ++ &init_task.thread.mode.skas.switch_buf, ++ &init_task.thread.mode.skas.fork_buf)); ++} ++ ++int external_pid_skas(struct task_struct *task) ++{ ++#warning Need to look up userspace_pid by cpu ++ return(userspace_pid[0]); ++} ++ ++int thread_pid_skas(struct thread_struct *thread) ++{ ++#warning Need to look up userspace_pid by cpu ++ return(userspace_pid[0]); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/syscall_kern.c um/arch/um/kernel/skas/syscall_kern.c +--- orig/arch/um/kernel/skas/syscall_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/syscall_kern.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,42 @@ ++/* ++ * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/sys.h" ++#include "asm/errno.h" ++#include "asm/unistd.h" ++#include "asm/ptrace.h" ++#include "asm/current.h" ++#include "sysdep/syscalls.h" ++#include "kern_util.h" ++ ++extern syscall_handler_t *sys_call_table[]; ++ ++long execute_syscall_skas(void *r) ++{ ++ struct pt_regs *regs = r; ++ long res; ++ int syscall; ++ ++ current->thread.nsyscalls++; ++ nsyscalls++; ++ syscall = UPT_SYSCALL_NR(®s->regs); ++ ++ if((syscall >= NR_syscalls) || (syscall < 0)) ++ res = -ENOSYS; ++ else res = EXECUTE_SYSCALL(syscall, regs); ++ ++ return(res); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/syscall_user.c um/arch/um/kernel/skas/syscall_user.c +--- orig/arch/um/kernel/skas/syscall_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/syscall_user.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,46 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdlib.h> ++#include <signal.h> ++#include "kern_util.h" ++#include "syscall_user.h" ++#include "sysdep/ptrace.h" ++#include "sysdep/sigcontext.h" ++ ++/* XXX Bogus */ ++#define ERESTARTSYS 512 ++#define ERESTARTNOINTR 513 ++#define ERESTARTNOHAND 514 ++ ++void handle_syscall(union uml_pt_regs *regs) ++{ ++ long result; ++ int index; ++ ++ index = record_syscall_start(UPT_SYSCALL_NR(regs)); ++ ++ syscall_trace(); ++ result = execute_syscall(regs); ++ ++ REGS_SET_SYSCALL_RETURN(regs->skas.regs, result); ++ if((result == -ERESTARTNOHAND) || (result == -ERESTARTSYS) || ++ (result == -ERESTARTNOINTR)) ++ do_signal(result); ++ ++ syscall_trace(); ++ record_syscall_end(index, result); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/sys-i386/Makefile um/arch/um/kernel/skas/sys-i386/Makefile +--- orig/arch/um/kernel/skas/sys-i386/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/sys-i386/Makefile 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,17 @@ ++# ++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++# Licensed under the GPL ++# ++ ++O_TARGET = sys-i386.o ++ ++obj-y = sigcontext.o ++ ++USER_OBJS = sigcontext.o ++ ++include $(TOPDIR)/Rules.make ++ ++$(USER_OBJS) : %.o: %.c ++ $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< ++ ++clean : +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/sys-i386/sigcontext.c um/arch/um/kernel/skas/sys-i386/sigcontext.c +--- orig/arch/um/kernel/skas/sys-i386/sigcontext.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/sys-i386/sigcontext.c 2003-11-19 03:27:43.000000000 -0500 +@@ -0,0 +1,114 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <errno.h> ++#include <asm/sigcontext.h> ++#include <sys/ptrace.h> ++#include <linux/ptrace.h> ++#include "sysdep/ptrace.h" ++#include "sysdep/ptrace_user.h" ++#include "kern_util.h" ++#include "user.h" ++#include "sigcontext.h" ++#include "mode.h" ++ ++int copy_sc_from_user_skas(int pid, union uml_pt_regs *regs, void *from_ptr) ++{ ++ struct sigcontext sc, *from = from_ptr; ++ unsigned long fpregs[FP_FRAME_SIZE]; ++ int err; ++ ++ err = copy_from_user_proc(&sc, from, sizeof(sc)); ++ err |= copy_from_user_proc(fpregs, sc.fpstate, sizeof(fpregs)); ++ if(err) ++ return(err); ++ ++ regs->skas.regs[GS] = sc.gs; ++ regs->skas.regs[FS] = sc.fs; ++ regs->skas.regs[ES] = sc.es; ++ regs->skas.regs[DS] = sc.ds; ++ regs->skas.regs[EDI] = sc.edi; ++ regs->skas.regs[ESI] = sc.esi; ++ regs->skas.regs[EBP] = sc.ebp; ++ regs->skas.regs[UESP] = sc.esp; ++ regs->skas.regs[EBX] = sc.ebx; ++ regs->skas.regs[EDX] = sc.edx; ++ regs->skas.regs[ECX] = sc.ecx; ++ regs->skas.regs[EAX] = sc.eax; ++ regs->skas.regs[EIP] = sc.eip; ++ regs->skas.regs[CS] = sc.cs; ++ regs->skas.regs[EFL] = sc.eflags; ++ regs->skas.regs[SS] = sc.ss; ++ regs->skas.fault_addr = sc.cr2; ++ regs->skas.fault_type = FAULT_WRITE(sc.err); ++ regs->skas.trap_type = sc.trapno; ++ ++ err = ptrace(PTRACE_SETFPREGS, pid, 0, fpregs); ++ if(err < 0){ ++ printk("copy_sc_to_user - PTRACE_SETFPREGS failed, " ++ "errno = %d\n", errno); ++ return(1); ++ } ++ ++ return(0); ++} ++ ++int copy_sc_to_user_skas(int pid, void *to_ptr, void *fp, ++ union uml_pt_regs *regs, unsigned long fault_addr, ++ int fault_type) ++{ ++ struct sigcontext sc, *to = to_ptr; ++ struct _fpstate *to_fp; ++ unsigned long fpregs[FP_FRAME_SIZE]; ++ int err; ++ ++ sc.gs = regs->skas.regs[GS]; ++ sc.fs = regs->skas.regs[FS]; ++ sc.es = regs->skas.regs[ES]; ++ sc.ds = regs->skas.regs[DS]; ++ sc.edi = regs->skas.regs[EDI]; ++ sc.esi = regs->skas.regs[ESI]; ++ sc.ebp = regs->skas.regs[EBP]; ++ sc.esp = regs->skas.regs[UESP]; ++ sc.ebx = regs->skas.regs[EBX]; ++ sc.edx = regs->skas.regs[EDX]; ++ sc.ecx = regs->skas.regs[ECX]; ++ sc.eax = regs->skas.regs[EAX]; ++ sc.eip = regs->skas.regs[EIP]; ++ sc.cs = regs->skas.regs[CS]; ++ sc.eflags = regs->skas.regs[EFL]; ++ sc.esp_at_signal = regs->skas.regs[UESP]; ++ sc.ss = regs->skas.regs[SS]; ++ sc.cr2 = fault_addr; ++ sc.err = TO_SC_ERR(fault_type); ++ sc.trapno = regs->skas.trap_type; ++ ++ err = ptrace(PTRACE_GETFPREGS, pid, 0, fpregs); ++ if(err < 0){ ++ printk("copy_sc_to_user - PTRACE_GETFPREGS failed, " ++ "errno = %d\n", errno); ++ return(1); ++ } ++ to_fp = (struct _fpstate *) ++ (fp ? (unsigned long) fp : ((unsigned long) to + sizeof(*to))); ++ sc.fpstate = to_fp; ++ ++ if(err) ++ return(err); ++ ++ return(copy_to_user_proc(to, &sc, sizeof(sc)) || ++ copy_to_user_proc(to_fp, fpregs, sizeof(fpregs))); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/time.c um/arch/um/kernel/skas/time.c +--- orig/arch/um/kernel/skas/time.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/time.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,30 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <sys/signal.h> ++#include <sys/time.h> ++#include "time_user.h" ++#include "process.h" ++#include "user.h" ++ ++void user_time_init_skas(void) ++{ ++ if(signal(SIGALRM, (__sighandler_t) alarm_handler) == SIG_ERR) ++ panic("Couldn't set SIGALRM handler"); ++ if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR) ++ panic("Couldn't set SIGVTALRM handler"); ++ set_interval(ITIMER_VIRTUAL); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/tlb.c um/arch/um/kernel/skas/tlb.c +--- orig/arch/um/kernel/skas/tlb.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/tlb.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,153 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/stddef.h" ++#include "linux/sched.h" ++#include "asm/page.h" ++#include "asm/pgtable.h" ++#include "asm/mmu.h" ++#include "user_util.h" ++#include "mem_user.h" ++#include "skas.h" ++#include "os.h" ++ ++static void fix_range(struct mm_struct *mm, unsigned long start_addr, ++ unsigned long end_addr, int force) ++{ ++ pgd_t *npgd; ++ pmd_t *npmd; ++ pte_t *npte; ++ unsigned long addr; ++ int r, w, x, err, fd; ++ ++ if(mm == NULL) return; ++ fd = mm->context.skas.mm_fd; ++ for(addr = start_addr; addr < end_addr;){ ++ npgd = pgd_offset(mm, addr); ++ npmd = pmd_offset(npgd, addr); ++ if(pmd_present(*npmd)){ ++ npte = pte_offset(npmd, addr); ++ r = pte_read(*npte); ++ w = pte_write(*npte); ++ x = pte_exec(*npte); ++ if(!pte_dirty(*npte)) w = 0; ++ if(!pte_young(*npte)){ ++ r = 0; ++ w = 0; ++ } ++ if(force || pte_newpage(*npte)){ ++ err = unmap(fd, (void *) addr, PAGE_SIZE); ++ if(err < 0) ++ panic("munmap failed, errno = %d\n", ++ -err); ++ if(pte_present(*npte)) ++ map(fd, addr, ++ pte_val(*npte) & PAGE_MASK, ++ PAGE_SIZE, r, w, x); ++ } ++ else if(pte_newprot(*npte)){ ++ protect(fd, addr, PAGE_SIZE, r, w, x, 1); ++ } ++ *npte = pte_mkuptodate(*npte); ++ addr += PAGE_SIZE; ++ } ++ else { ++ if(force || pmd_newpage(*npmd)){ ++ err = unmap(fd, (void *) addr, PMD_SIZE); ++ if(err < 0) ++ panic("munmap failed, errno = %d\n", ++ -err); ++ pmd_mkuptodate(*npmd); ++ } ++ addr += PMD_SIZE; ++ } ++ } ++} ++ ++static void flush_kernel_vm_range(unsigned long start, unsigned long end) ++{ ++ struct mm_struct *mm; ++ pgd_t *pgd; ++ pmd_t *pmd; ++ pte_t *pte; ++ unsigned long addr; ++ int updated = 0, err; ++ ++ mm = &init_mm; ++ for(addr = start_vm; addr < end_vm;){ ++ pgd = pgd_offset(mm, addr); ++ pmd = pmd_offset(pgd, addr); ++ if(pmd_present(*pmd)){ ++ pte = pte_offset(pmd, addr); ++ if(!pte_present(*pte) || pte_newpage(*pte)){ ++ updated = 1; ++ err = os_unmap_memory((void *) addr, ++ PAGE_SIZE); ++ if(err < 0) ++ panic("munmap failed, errno = %d\n", ++ -err); ++ if(pte_present(*pte)) ++ map_memory(addr, ++ pte_val(*pte) & PAGE_MASK, ++ PAGE_SIZE, 1, 1, 1); ++ } ++ else if(pte_newprot(*pte)){ ++ updated = 1; ++ protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1); ++ } ++ addr += PAGE_SIZE; ++ } ++ else { ++ if(pmd_newpage(*pmd)){ ++ updated = 1; ++ err = os_unmap_memory((void *) addr, PMD_SIZE); ++ if(err < 0) ++ panic("munmap failed, errno = %d\n", ++ -err); ++ } ++ addr += PMD_SIZE; ++ } ++ } ++} ++ ++void flush_tlb_kernel_vm_skas(void) ++{ ++ flush_kernel_vm_range(start_vm, end_vm); ++} ++ ++void __flush_tlb_one_skas(unsigned long addr) ++{ ++ flush_kernel_vm_range(addr, addr + PAGE_SIZE); ++} ++ ++void flush_tlb_range_skas(struct mm_struct *mm, unsigned long start, ++ unsigned long end) ++{ ++ if(mm == NULL) ++ flush_kernel_vm_range(start, end); ++ else fix_range(mm, start, end, 0); ++} ++ ++void flush_tlb_mm_skas(struct mm_struct *mm) ++{ ++ flush_tlb_kernel_vm_skas(); ++ fix_range(mm, 0, host_task_size, 0); ++} ++ ++void force_flush_all_skas(void) ++{ ++ fix_range(current->mm, 0, host_task_size, 1); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/trap_user.c um/arch/um/kernel/skas/trap_user.c +--- orig/arch/um/kernel/skas/trap_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/trap_user.c 2003-12-14 11:17:37.000000000 -0500 +@@ -0,0 +1,63 @@ ++/* ++ * 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; ++ ++ r = &TASK_REGS(get_current())->skas; ++ 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; ++} ++ ++extern int missed_ticks[]; ++ ++void user_signal(int sig, union uml_pt_regs *regs) ++{ ++ struct signal_info *info; ++ ++ regs->skas.is_user = 1; ++ regs->skas.fault_addr = 0; ++ regs->skas.fault_type = 0; ++ regs->skas.trap_type = 0; ++ info = &sig_info[sig]; ++ (*info->handler)(sig, regs); ++ ++ unblock_signals(); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/uaccess.c um/arch/um/kernel/skas/uaccess.c +--- orig/arch/um/kernel/skas/uaccess.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/uaccess.c 2003-11-11 11:11:26.000000000 -0500 +@@ -0,0 +1,217 @@ ++/* ++ * Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/stddef.h" ++#include "linux/kernel.h" ++#include "linux/string.h" ++#include "linux/fs.h" ++#include "linux/highmem.h" ++#include "asm/page.h" ++#include "asm/pgtable.h" ++#include "asm/uaccess.h" ++#include "kern_util.h" ++ ++extern void *um_virt_to_phys(struct task_struct *task, unsigned long addr, ++ pte_t *pte_out); ++ ++static unsigned long maybe_map(unsigned long virt, int is_write) ++{ ++ pte_t pte; ++ ++ void *phys = um_virt_to_phys(current, virt, &pte); ++ int dummy_code; ++ ++ if(IS_ERR(phys) || (is_write && !pte_write(pte))){ ++ if(!handle_page_fault(virt, 0, is_write, 0, &dummy_code)) ++ return(0); ++ phys = um_virt_to_phys(current, virt, NULL); ++ } ++ return((unsigned long) phys); ++} ++ ++static int do_op(unsigned long addr, int len, int is_write, ++ int (*op)(unsigned long addr, int len, void *arg), void *arg) ++{ ++ struct page *page; ++ int n; ++ ++ addr = maybe_map(addr, is_write); ++ if(addr == -1) ++ return(-1); ++ ++ page = phys_to_page(addr); ++ addr = (unsigned long) kmap(page) + (addr & ~PAGE_MASK); ++ n = (*op)(addr, len, arg); ++ kunmap(page); ++ ++ return(n); ++} ++ ++static int buffer_op(unsigned long addr, int len, int is_write, ++ int (*op)(unsigned long addr, int len, void *arg), ++ void *arg) ++{ ++ int size = min(PAGE_ALIGN(addr) - addr, (unsigned long) len); ++ int remain = len, n; ++ ++ n = do_op(addr, size, is_write, op, arg); ++ if(n != 0) ++ return(n < 0 ? remain : 0); ++ ++ addr += size; ++ remain -= size; ++ if(remain == 0) ++ return(0); ++ ++ while(addr < ((addr + remain) & PAGE_MASK)){ ++ n = do_op(addr, PAGE_SIZE, is_write, op, arg); ++ if(n != 0) ++ return(n < 0 ? remain : 0); ++ ++ addr += PAGE_SIZE; ++ remain -= PAGE_SIZE; ++ } ++ if(remain == 0) ++ return(0); ++ ++ n = do_op(addr, remain, is_write, op, arg); ++ if(n != 0) ++ return(n < 0 ? remain : 0); ++ return(0); ++} ++ ++static int copy_chunk_from_user(unsigned long from, int len, void *arg) ++{ ++ unsigned long *to_ptr = arg, to = *to_ptr; ++ ++ memcpy((void *) to, (void *) from, len); ++ *to_ptr += len; ++ return(0); ++} ++ ++int copy_from_user_skas(void *to, const void *from, int n) ++{ ++ if(segment_eq(get_fs(), KERNEL_DS)){ ++ memcpy(to, from, n); ++ return(0); ++ } ++ ++ return(access_ok_skas(VERIFY_READ, from, n) ? ++ buffer_op((unsigned long) from, n, 0, copy_chunk_from_user, &to): ++ n); ++} ++ ++static int copy_chunk_to_user(unsigned long to, int len, void *arg) ++{ ++ unsigned long *from_ptr = arg, from = *from_ptr; ++ ++ memcpy((void *) to, (void *) from, len); ++ *from_ptr += len; ++ return(0); ++} ++ ++int copy_to_user_skas(void *to, const void *from, int n) ++{ ++ if(segment_eq(get_fs(), KERNEL_DS)){ ++ memcpy(to, from, n); ++ return(0); ++ } ++ ++ return(access_ok_skas(VERIFY_WRITE, to, n) ? ++ buffer_op((unsigned long) to, n, 1, copy_chunk_to_user, &from) : ++ n); ++} ++ ++static int strncpy_chunk_from_user(unsigned long from, int len, void *arg) ++{ ++ char **to_ptr = arg, *to = *to_ptr; ++ int n; ++ ++ strncpy(to, (void *) from, len); ++ n = strnlen(to, len); ++ *to_ptr += n; ++ ++ if(n < len) ++ return(1); ++ return(0); ++} ++ ++int strncpy_from_user_skas(char *dst, const char *src, int count) ++{ ++ int n; ++ char *ptr = dst; ++ ++ if(segment_eq(get_fs(), KERNEL_DS)){ ++ strncpy(dst, src, count); ++ return(strnlen(dst, count)); ++ } ++ ++ if(!access_ok_skas(VERIFY_READ, src, 1)) ++ return(-EFAULT); ++ ++ n = buffer_op((unsigned long) src, count, 0, strncpy_chunk_from_user, ++ &ptr); ++ if(n != 0) ++ return(-EFAULT); ++ return(strnlen(dst, count)); ++} ++ ++static int clear_chunk(unsigned long addr, int len, void *unused) ++{ ++ memset((void *) addr, 0, len); ++ return(0); ++} ++ ++int __clear_user_skas(void *mem, int len) ++{ ++ return(buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL)); ++} ++ ++int clear_user_skas(void *mem, int len) ++{ ++ if(segment_eq(get_fs(), KERNEL_DS)){ ++ memset(mem, 0, len); ++ return(0); ++ } ++ ++ return(access_ok_skas(VERIFY_WRITE, mem, len) ? ++ buffer_op((unsigned long) mem, len, 1, clear_chunk, NULL) : len); ++} ++ ++static int strnlen_chunk(unsigned long str, int len, void *arg) ++{ ++ int *len_ptr = arg, n; ++ ++ n = strnlen((void *) str, len); ++ *len_ptr += n; ++ ++ if(n < len) ++ return(1); ++ return(0); ++} ++ ++int strnlen_user_skas(const void *str, int len) ++{ ++ int count = 0, n; ++ ++ if(segment_eq(get_fs(), KERNEL_DS)) ++ return(strnlen(str, len) + 1); ++ ++ n = buffer_op((unsigned long) str, len, 0, strnlen_chunk, &count); ++ if(n == 0) ++ return(count + 1); ++ return(-EFAULT); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/util/Makefile um/arch/um/kernel/skas/util/Makefile +--- orig/arch/um/kernel/skas/util/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/util/Makefile 2003-11-08 02:52:22.000000000 -0500 +@@ -0,0 +1,10 @@ ++all: mk_ptregs ++ ++mk_ptregs : mk_ptregs.o ++ $(HOSTCC) -o mk_ptregs mk_ptregs.o ++ ++mk_ptregs.o : mk_ptregs.c ++ $(HOSTCC) -c $< ++ ++clean : ++ $(RM) -f mk_ptregs *.o *~ +diff -Naur -X ../exclude-files orig/arch/um/kernel/skas/util/mk_ptregs.c um/arch/um/kernel/skas/util/mk_ptregs.c +--- orig/arch/um/kernel/skas/util/mk_ptregs.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/skas/util/mk_ptregs.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,50 @@ ++#include <asm/ptrace.h> ++#include <asm/user.h> ++ ++#define PRINT_REG(name, val) printf("#define HOST_%s %d\n", (name), (val)) ++ ++int main(int argc, char **argv) ++{ ++ printf("/* Automatically generated by " ++ "arch/um/kernel/skas/util/mk_ptregs */\n"); ++ printf("\n"); ++ printf("#ifndef __SKAS_PT_REGS_\n"); ++ printf("#define __SKAS_PT_REGS_\n"); ++ printf("\n"); ++ printf("#define HOST_FRAME_SIZE %d\n", FRAME_SIZE); ++ printf("#define HOST_FP_SIZE %d\n", ++ sizeof(struct user_i387_struct) / sizeof(unsigned long)); ++ printf("#define HOST_XFP_SIZE %d\n", ++ sizeof(struct user_fxsr_struct) / sizeof(unsigned long)); ++ ++ PRINT_REG("IP", EIP); ++ PRINT_REG("SP", UESP); ++ PRINT_REG("EFLAGS", EFL); ++ PRINT_REG("EAX", EAX); ++ PRINT_REG("EBX", EBX); ++ PRINT_REG("ECX", ECX); ++ PRINT_REG("EDX", EDX); ++ PRINT_REG("ESI", ESI); ++ PRINT_REG("EDI", EDI); ++ PRINT_REG("EBP", EBP); ++ PRINT_REG("CS", CS); ++ PRINT_REG("SS", SS); ++ PRINT_REG("DS", DS); ++ PRINT_REG("FS", FS); ++ PRINT_REG("ES", ES); ++ PRINT_REG("GS", GS); ++ printf("\n"); ++ printf("#endif\n"); ++ return(0); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/smp.c um/arch/um/kernel/smp.c +--- orig/arch/um/kernel/smp.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/smp.c 2003-11-15 02:59:25.000000000 -0500 +@@ -0,0 +1,328 @@ ++/* ++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/config.h" ++ ++#ifdef CONFIG_SMP ++ ++#include "linux/sched.h" ++#include "linux/threads.h" ++#include "linux/interrupt.h" ++#include "asm/smp.h" ++#include "asm/processor.h" ++#include "asm/spinlock.h" ++#include "asm/softirq.h" ++#include "asm/hardirq.h" ++#include "asm/tlb.h" ++#include "user_util.h" ++#include "kern_util.h" ++#include "irq_user.h" ++#include "kern.h" ++#include "os.h" ++ ++/* Total count of live CPUs, set by smp_boot_cpus */ ++int smp_num_cpus = 1; ++ ++/* The 'big kernel lock' */ ++spinlock_cacheline_t kernel_flag_cacheline = {SPIN_LOCK_UNLOCKED}; ++ ++/* Per CPU bogomips and other parameters */ ++ ++/* The only piece used here is the ipi pipe, which is set before SMP is ++ * started and never changed. ++ */ ++struct cpuinfo_um cpu_data[NR_CPUS]; ++ ++/* CPU online map, set by smp_boot_cpus */ ++unsigned long cpu_online_map; ++ ++atomic_t global_bh_count; ++ ++/* Set when the idlers are all forked */ ++int smp_threads_ready = 0; ++ ++/* Not used by UML */ ++unsigned char global_irq_holder = 0; ++unsigned volatile long global_irq_lock; ++ ++/* A statistic, can be a little off */ ++static int num_reschedules_sent = 0; ++ ++mmu_gather_t mmu_gathers[NR_CPUS]; ++ ++void smp_send_reschedule(int cpu) ++{ ++ os_write_file(cpu_data[cpu].ipi_pipe[1], "R", 1); ++ num_reschedules_sent++; ++} ++ ++static void show(char * str) ++{ ++ int cpu = smp_processor_id(); ++ ++ printk(KERN_INFO "\n%s, CPU %d:\n", str, cpu); ++} ++ ++#define MAXCOUNT 100000000 ++ ++static inline void wait_on_bh(void) ++{ ++ int count = MAXCOUNT; ++ do { ++ if (!--count) { ++ show("wait_on_bh"); ++ count = ~0; ++ } ++ /* nothing .. wait for the other bh's to go away */ ++ } while (atomic_read(&global_bh_count) != 0); ++} ++ ++/* ++ * This is called when we want to synchronize with ++ * bottom half handlers. We need to wait until ++ * no other CPU is executing any bottom half handler. ++ * ++ * Don't wait if we're already running in an interrupt ++ * context or are inside a bh handler. ++ */ ++void synchronize_bh(void) ++{ ++ if (atomic_read(&global_bh_count) && !in_interrupt()) ++ wait_on_bh(); ++} ++ ++void smp_send_stop(void) ++{ ++ int i; ++ ++ printk(KERN_INFO "Stopping all CPUs..."); ++ for(i = 0; i < ncpus; i++){ ++ if(i == current->processor) ++ continue; ++ os_write_file(cpu_data[i].ipi_pipe[1], "S", 1); ++ } ++ printk("done\n"); ++} ++ ++ ++static atomic_t smp_commenced = ATOMIC_INIT(0); ++static volatile unsigned long smp_callin_map = 0; ++ ++void smp_commence(void) ++{ ++ printk("All CPUs are go!\n"); ++ ++ wmb(); ++ atomic_set(&smp_commenced, 1); ++} ++ ++static int idle_proc(void *unused) ++{ ++ int cpu, err; ++ ++ set_current(current); ++ del_from_runqueue(current); ++ unhash_process(current); ++ ++ cpu = current->processor; ++ err = os_pipe(cpu_data[cpu].ipi_pipe, 1, 1); ++ if(err < 0) ++ panic("CPU#%d failed to create IPI pipe, err = %d", cpu, -err); ++ ++ activate_ipi(cpu_data[cpu].ipi_pipe[0], ++ current->thread.mode.tt.extern_pid); ++ ++ wmb(); ++ if (test_and_set_bit(current->processor, &smp_callin_map)) { ++ printk("huh, CPU#%d already present??\n", current->processor); ++ BUG(); ++ } ++ ++ while (!atomic_read(&smp_commenced)) ++ cpu_relax(); ++ ++ init_idle(); ++ cpu_idle(); ++ return(0); ++} ++ ++static int idle_thread(int (*fn)(void *), int cpu) ++{ ++ struct task_struct *new_task; ++ int pid; ++ unsigned char c; ++ ++ current->thread.request.u.thread.proc = fn; ++ current->thread.request.u.thread.arg = NULL; ++ pid = do_fork(CLONE_VM | CLONE_PID, 0, NULL, 0); ++ if(pid < 0) ++ panic("do_fork failed in idle_thread"); ++ new_task = get_task(pid, 1); ++ ++ cpu_tasks[cpu] = ((struct cpu_task) ++ { .pid = new_task->thread.mode.tt.extern_pid, ++ .task = new_task } ); ++ init_tasks[cpu] = new_task; ++ new_task->processor = cpu; ++ new_task->cpus_allowed = 1 << cpu; ++ new_task->cpus_runnable = new_task->cpus_allowed; ++ CHOOSE_MODE(os_write_file(new_task->thread.mode.tt.switch_pipe[1], &c, ++ sizeof(c)), ++ ({ panic("skas mode doesn't support SMP"); })); ++ return(new_task->thread.mode.tt.extern_pid); ++} ++ ++void smp_boot_cpus(void) ++{ ++ int err; ++ ++ set_bit(0, &cpu_online_map); ++ set_bit(0, &smp_callin_map); ++ ++ err = os_pipe(cpu_data[0].ipi_pipe, 1, 1); ++ if(err < 0) ++ panic("CPU#0 failed to create IPI pipe, err = %d", -err); ++ ++ activate_ipi(cpu_data[0].ipi_pipe[0], ++ current->thread.mode.tt.extern_pid); ++ ++ if(ncpus < 1){ ++ printk(KERN_INFO "ncpus set to 1\n"); ++ ncpus = 1; ++ } ++ else if(ncpus > NR_CPUS){ ++ printk(KERN_INFO ++ "ncpus can't be greater than NR_CPUS, set to %d\n", ++ NR_CPUS); ++ ncpus = NR_CPUS; ++ } ++ ++ if(ncpus > 1){ ++ int i, pid; ++ ++ printk(KERN_INFO "Starting up other processors:\n"); ++ for(i=1;i<ncpus;i++){ ++ int waittime; ++ ++ /* Do this early, for hard_smp_processor_id() */ ++ cpu_tasks[i].pid = -1; ++ set_bit(i, &cpu_online_map); ++ smp_num_cpus++; ++ ++ pid = idle_thread(idle_proc, i); ++ printk(KERN_INFO "\t#%d - idle thread pid = %d.. ", ++ i, pid); ++ ++ waittime = 200000000; ++ while (waittime-- && !test_bit(i, &smp_callin_map)) ++ cpu_relax(); ++ ++ if (test_bit(i, &smp_callin_map)) ++ printk("online\n"); ++ else { ++ printk("failed\n"); ++ clear_bit(i, &cpu_online_map); ++ } ++ } ++ } ++} ++ ++int setup_profiling_timer(unsigned int multiplier) ++{ ++ printk(KERN_INFO "setup_profiling_timer\n"); ++ return(0); ++} ++ ++void smp_call_function_slave(int cpu); ++ ++void IPI_handler(int cpu) ++{ ++ unsigned char c; ++ int fd; ++ ++ fd = cpu_data[cpu].ipi_pipe[0]; ++ while (os_read_file(fd, &c, 1) == 1) { ++ switch (c) { ++ case 'C': ++ smp_call_function_slave(cpu); ++ break; ++ ++ case 'R': ++ current->need_resched = 1; ++ break; ++ ++ case 'S': ++ printk("CPU#%d stopping\n", cpu); ++ while(1) ++ pause(); ++ break; ++ ++ default: ++ printk("CPU#%d received unknown IPI [%c]!\n", cpu, c); ++ break; ++ } ++ } ++} ++ ++int hard_smp_processor_id(void) ++{ ++ return(pid_to_processor_id(os_getpid())); ++} ++ ++static spinlock_t call_lock = SPIN_LOCK_UNLOCKED; ++static atomic_t scf_started; ++static atomic_t scf_finished; ++static void (*func)(void *info); ++static void *info; ++ ++void smp_call_function_slave(int cpu) ++{ ++ atomic_inc(&scf_started); ++ (*func)(info); ++ atomic_inc(&scf_finished); ++} ++ ++int smp_call_function(void (*_func)(void *info), void *_info, int nonatomic, ++ int wait) ++{ ++ int cpus = smp_num_cpus - 1; ++ int i; ++ ++ if (!cpus) ++ return 0; ++ ++ spin_lock_bh(&call_lock); ++ atomic_set(&scf_started, 0); ++ atomic_set(&scf_finished, 0); ++ func = _func; ++ info = _info; ++ ++ for (i=0;i<NR_CPUS;i++) ++ if (i != current->processor && test_bit(i, &cpu_online_map)) ++ os_write_file(cpu_data[i].ipi_pipe[1], "C", 1); ++ ++ while (atomic_read(&scf_started) != cpus) ++ barrier(); ++ ++ if (wait) ++ while (atomic_read(&scf_finished) != cpus) ++ barrier(); ++ ++ spin_unlock_bh(&call_lock); ++ return 0; ++} ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/syscall_kern.c um/arch/um/kernel/syscall_kern.c +--- orig/arch/um/kernel/syscall_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/syscall_kern.c 2003-11-07 01:41:13.000000000 -0500 +@@ -0,0 +1,343 @@ ++/* ++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/sched.h" ++#include "linux/file.h" ++#include "linux/smp_lock.h" ++#include "linux/mm.h" ++#include "linux/utsname.h" ++#include "linux/msg.h" ++#include "linux/shm.h" ++#include "linux/sys.h" ++#include "linux/unistd.h" ++#include "linux/slab.h" ++#include "linux/utime.h" ++#include "asm/mman.h" ++#include "asm/uaccess.h" ++#include "asm/ipc.h" ++#include "kern_util.h" ++#include "user_util.h" ++#include "sysdep/syscalls.h" ++#include "mode_kern.h" ++#include "choose-mode.h" ++ ++/* Unlocked, I don't care if this is a bit off */ ++int nsyscalls = 0; ++ ++long um_mount(char * dev_name, char * dir_name, char * type, ++ unsigned long new_flags, void * data) ++{ ++ if(type == NULL) type = ""; ++ return(sys_mount(dev_name, dir_name, type, new_flags, data)); ++} ++ ++long sys_fork(void) ++{ ++ long ret; ++ ++ current->thread.forking = 1; ++ ret = do_fork(SIGCHLD, 0, NULL, 0); ++ current->thread.forking = 0; ++ return(ret); ++} ++ ++long sys_clone(unsigned long clone_flags, unsigned long newsp) ++{ ++ long ret; ++ ++ current->thread.forking = 1; ++ ret = do_fork(clone_flags, newsp, NULL, 0); ++ current->thread.forking = 0; ++ return(ret); ++} ++ ++long sys_vfork(void) ++{ ++ long ret; ++ ++ current->thread.forking = 1; ++ ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0); ++ current->thread.forking = 0; ++ return(ret); ++} ++ ++/* common code for old and new mmaps */ ++long do_mmap2(struct mm_struct *mm, unsigned long addr, unsigned long len, ++ unsigned long prot, unsigned long flags, unsigned long fd, ++ unsigned long pgoff) ++{ ++ int error = -EBADF; ++ struct file * file = NULL; ++ ++ flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE); ++ if (!(flags & MAP_ANONYMOUS)) { ++ file = fget(fd); ++ if (!file) ++ goto out; ++ } ++ ++ down_write(&mm->mmap_sem); ++ error = do_mmap_pgoff(mm, file, addr, len, prot, flags, pgoff); ++ up_write(&mm->mmap_sem); ++ ++ if (file) ++ fput(file); ++ out: ++ return error; ++} ++ ++long sys_mmap2(unsigned long addr, unsigned long len, ++ unsigned long prot, unsigned long flags, ++ unsigned long fd, unsigned long pgoff) ++{ ++ return do_mmap2(current->mm, addr, len, prot, flags, fd, pgoff); ++} ++ ++/* ++ * Perform the select(nd, in, out, ex, tv) and mmap() system ++ * calls. Linux/i386 didn't use to be able to handle more than ++ * 4 system call parameters, so these system calls used a memory ++ * block for parameter passing.. ++ */ ++ ++struct mmap_arg_struct { ++ unsigned long addr; ++ unsigned long len; ++ unsigned long prot; ++ unsigned long flags; ++ unsigned long fd; ++ unsigned long offset; ++}; ++ ++int old_mmap(unsigned long addr, unsigned long len, ++ unsigned long prot, unsigned long flags, ++ unsigned long fd, unsigned long offset) ++{ ++ int err = -EINVAL; ++ if (offset & ~PAGE_MASK) ++ goto out; ++ ++ err = do_mmap2(current->mm, addr, len, prot, flags, fd, ++ offset >> PAGE_SHIFT); ++ out: ++ return err; ++} ++/* ++ * sys_pipe() is the normal C calling standard for creating ++ * a pipe. It's not the way unix traditionally does this, though. ++ */ ++int sys_pipe(unsigned long * fildes) ++{ ++ int fd[2]; ++ int error; ++ ++ error = do_pipe(fd); ++ if (!error) { ++ if (copy_to_user(fildes, fd, sizeof(fd))) ++ error = -EFAULT; ++ } ++ return error; ++} ++ ++int sys_pause(void) ++{ ++ current->state = TASK_INTERRUPTIBLE; ++ schedule(); ++ return -ERESTARTNOHAND; ++} ++ ++int sys_sigaction(int sig, const struct old_sigaction *act, ++ struct old_sigaction *oact) ++{ ++ struct k_sigaction new_ka, old_ka; ++ int ret; ++ ++ if (act) { ++ old_sigset_t mask; ++ if (verify_area(VERIFY_READ, act, sizeof(*act)) || ++ __get_user(new_ka.sa.sa_handler, &act->sa_handler) || ++ __get_user(new_ka.sa.sa_restorer, &act->sa_restorer)) ++ return -EFAULT; ++ __get_user(new_ka.sa.sa_flags, &act->sa_flags); ++ __get_user(mask, &act->sa_mask); ++ siginitset(&new_ka.sa.sa_mask, mask); ++ } ++ ++ ret = do_sigaction(sig, act ? &new_ka : NULL, oact ? &old_ka : NULL); ++ ++ if (!ret && oact) { ++ if (verify_area(VERIFY_WRITE, oact, sizeof(*oact)) || ++ __put_user(old_ka.sa.sa_handler, &oact->sa_handler) || ++ __put_user(old_ka.sa.sa_restorer, &oact->sa_restorer)) ++ return -EFAULT; ++ __put_user(old_ka.sa.sa_flags, &oact->sa_flags); ++ __put_user(old_ka.sa.sa_mask.sig[0], &oact->sa_mask); ++ } ++ ++ return ret; ++} ++ ++/* ++ * sys_ipc() is the de-multiplexer for the SysV IPC calls.. ++ * ++ * This is really horribly ugly. ++ */ ++int sys_ipc (uint call, int first, int second, ++ int third, void *ptr, long fifth) ++{ ++ int version, ret; ++ ++ version = call >> 16; /* hack for backward compatibility */ ++ call &= 0xffff; ++ ++ switch (call) { ++ case SEMOP: ++ return sys_semop (first, (struct sembuf *)ptr, second); ++ case SEMGET: ++ return sys_semget (first, second, third); ++ case SEMCTL: { ++ union semun fourth; ++ if (!ptr) ++ return -EINVAL; ++ if (get_user(fourth.__pad, (void **) ptr)) ++ return -EFAULT; ++ return sys_semctl (first, second, third, fourth); ++ } ++ ++ case MSGSND: ++ return sys_msgsnd (first, (struct msgbuf *) ptr, ++ second, third); ++ case MSGRCV: ++ switch (version) { ++ case 0: { ++ struct ipc_kludge tmp; ++ if (!ptr) ++ return -EINVAL; ++ ++ if (copy_from_user(&tmp, ++ (struct ipc_kludge *) ptr, ++ sizeof (tmp))) ++ return -EFAULT; ++ return sys_msgrcv (first, tmp.msgp, second, ++ tmp.msgtyp, third); ++ } ++ default: ++ panic("msgrcv with version != 0"); ++ return sys_msgrcv (first, ++ (struct msgbuf *) ptr, ++ second, fifth, third); ++ } ++ case MSGGET: ++ return sys_msgget ((key_t) first, second); ++ case MSGCTL: ++ return sys_msgctl (first, second, (struct msqid_ds *) ptr); ++ ++ case SHMAT: ++ switch (version) { ++ default: { ++ ulong raddr; ++ ret = sys_shmat (first, (char *) ptr, second, &raddr); ++ if (ret) ++ return ret; ++ return put_user (raddr, (ulong *) third); ++ } ++ case 1: /* iBCS2 emulator entry point */ ++ if (!segment_eq(get_fs(), get_ds())) ++ return -EINVAL; ++ return sys_shmat (first, (char *) ptr, second, (ulong *) third); ++ } ++ case SHMDT: ++ return sys_shmdt ((char *)ptr); ++ case SHMGET: ++ return sys_shmget (first, second, third); ++ case SHMCTL: ++ return sys_shmctl (first, second, ++ (struct shmid_ds *) ptr); ++ default: ++ return -EINVAL; ++ } ++} ++ ++int sys_uname(struct old_utsname * name) ++{ ++ int err; ++ if (!name) ++ return -EFAULT; ++ down_read(&uts_sem); ++ err=copy_to_user(name, &system_utsname, sizeof (*name)); ++ up_read(&uts_sem); ++ return err?-EFAULT:0; ++} ++ ++int sys_olduname(struct oldold_utsname * name) ++{ ++ int error; ++ ++ if (!name) ++ return -EFAULT; ++ if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) ++ return -EFAULT; ++ ++ down_read(&uts_sem); ++ ++ error = __copy_to_user(&name->sysname,&system_utsname.sysname, ++ __OLD_UTS_LEN); ++ error |= __put_user(0,name->sysname+__OLD_UTS_LEN); ++ error |= __copy_to_user(&name->nodename,&system_utsname.nodename, ++ __OLD_UTS_LEN); ++ error |= __put_user(0,name->nodename+__OLD_UTS_LEN); ++ error |= __copy_to_user(&name->release,&system_utsname.release, ++ __OLD_UTS_LEN); ++ error |= __put_user(0,name->release+__OLD_UTS_LEN); ++ error |= __copy_to_user(&name->version,&system_utsname.version, ++ __OLD_UTS_LEN); ++ error |= __put_user(0,name->version+__OLD_UTS_LEN); ++ error |= __copy_to_user(&name->machine,&system_utsname.machine, ++ __OLD_UTS_LEN); ++ error |= __put_user(0,name->machine+__OLD_UTS_LEN); ++ ++ up_read(&uts_sem); ++ ++ error = error ? -EFAULT : 0; ++ ++ return error; ++} ++ ++int sys_sigaltstack(const stack_t *uss, stack_t *uoss) ++{ ++ return(do_sigaltstack(uss, uoss, PT_REGS_SP(¤t->thread.regs))); ++} ++ ++long execute_syscall(void *r) ++{ ++ return(CHOOSE_MODE_PROC(execute_syscall_tt, execute_syscall_skas, r)); ++} ++ ++spinlock_t syscall_lock = SPIN_LOCK_UNLOCKED; ++ ++static int syscall_index = 0; ++ ++int next_syscall_index(int limit) ++{ ++ int ret; ++ ++ spin_lock(&syscall_lock); ++ ret = syscall_index; ++ if(++syscall_index == limit) ++ syscall_index = 0; ++ spin_unlock(&syscall_lock); ++ return(ret); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/sys_call_table.c um/arch/um/kernel/sys_call_table.c +--- orig/arch/um/kernel/sys_call_table.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/sys_call_table.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,496 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/unistd.h" ++#include "linux/version.h" ++#include "linux/sys.h" ++#include "asm/signal.h" ++#include "sysdep/syscalls.h" ++#include "kern_util.h" ++ ++extern syscall_handler_t sys_ni_syscall; ++extern syscall_handler_t sys_exit; ++extern syscall_handler_t sys_fork; ++extern syscall_handler_t sys_creat; ++extern syscall_handler_t sys_link; ++extern syscall_handler_t sys_unlink; ++extern syscall_handler_t sys_chdir; ++extern syscall_handler_t sys_mknod; ++extern syscall_handler_t sys_chmod; ++extern syscall_handler_t sys_lchown16; ++extern syscall_handler_t sys_ni_syscall; ++extern syscall_handler_t sys_stat; ++extern syscall_handler_t sys_getpid; ++extern syscall_handler_t sys_oldumount; ++extern syscall_handler_t sys_setuid16; ++extern syscall_handler_t sys_getuid16; ++extern syscall_handler_t sys_ptrace; ++extern syscall_handler_t sys_alarm; ++extern syscall_handler_t sys_fstat; ++extern syscall_handler_t sys_pause; ++extern syscall_handler_t sys_utime; ++extern syscall_handler_t sys_ni_syscall; ++extern syscall_handler_t sys_ni_syscall; ++extern syscall_handler_t sys_access; ++extern syscall_handler_t sys_nice; ++extern syscall_handler_t sys_ni_syscall; ++extern syscall_handler_t sys_sync; ++extern syscall_handler_t sys_kill; ++extern syscall_handler_t sys_rename; ++extern syscall_handler_t sys_mkdir; ++extern syscall_handler_t sys_rmdir; ++extern syscall_handler_t sys_pipe; ++extern syscall_handler_t sys_times; ++extern syscall_handler_t sys_ni_syscall; ++extern syscall_handler_t sys_brk; ++extern syscall_handler_t sys_setgid16; ++extern syscall_handler_t sys_getgid16; ++extern syscall_handler_t sys_signal; ++extern syscall_handler_t sys_geteuid16; ++extern syscall_handler_t sys_getegid16; ++extern syscall_handler_t sys_acct; ++extern syscall_handler_t sys_umount; ++extern syscall_handler_t sys_ni_syscall; ++extern syscall_handler_t sys_ioctl; ++extern syscall_handler_t sys_fcntl; ++extern syscall_handler_t sys_ni_syscall; ++extern syscall_handler_t sys_setpgid; ++extern syscall_handler_t sys_ni_syscall; ++extern syscall_handler_t sys_olduname; ++extern syscall_handler_t sys_umask; ++extern syscall_handler_t sys_chroot; ++extern syscall_handler_t sys_ustat; ++extern syscall_handler_t sys_dup2; ++extern syscall_handler_t sys_getppid; ++extern syscall_handler_t sys_getpgrp; ++extern syscall_handler_t sys_sigaction; ++extern syscall_handler_t sys_sgetmask; ++extern syscall_handler_t sys_ssetmask; ++extern syscall_handler_t sys_setreuid16; ++extern syscall_handler_t sys_setregid16; ++extern syscall_handler_t sys_sigsuspend; ++extern syscall_handler_t sys_sigpending; ++extern syscall_handler_t sys_sethostname; ++extern syscall_handler_t sys_setrlimit; ++extern syscall_handler_t sys_old_getrlimit; ++extern syscall_handler_t sys_getrusage; ++extern syscall_handler_t sys_gettimeofday; ++extern syscall_handler_t sys_settimeofday; ++extern syscall_handler_t sys_getgroups16; ++extern syscall_handler_t sys_setgroups16; ++extern syscall_handler_t sys_symlink; ++extern syscall_handler_t sys_lstat; ++extern syscall_handler_t sys_readlink; ++extern syscall_handler_t sys_uselib; ++extern syscall_handler_t sys_swapon; ++extern syscall_handler_t sys_reboot; ++extern syscall_handler_t old_readdir; ++extern syscall_handler_t sys_munmap; ++extern syscall_handler_t sys_truncate; ++extern syscall_handler_t sys_ftruncate; ++extern syscall_handler_t sys_fchmod; ++extern syscall_handler_t sys_fchown16; ++extern syscall_handler_t sys_getpriority; ++extern syscall_handler_t sys_setpriority; ++extern syscall_handler_t sys_ni_syscall; ++extern syscall_handler_t sys_statfs; ++extern syscall_handler_t sys_fstatfs; ++extern syscall_handler_t sys_ni_syscall; ++extern syscall_handler_t sys_socketcall; ++extern syscall_handler_t sys_syslog; ++extern syscall_handler_t sys_setitimer; ++extern syscall_handler_t sys_getitimer; ++extern syscall_handler_t sys_newstat; ++extern syscall_handler_t sys_newlstat; ++extern syscall_handler_t sys_newfstat; ++extern syscall_handler_t sys_uname; ++extern syscall_handler_t sys_ni_syscall; ++extern syscall_handler_t sys_vhangup; ++extern syscall_handler_t sys_ni_syscall; ++extern syscall_handler_t sys_ni_syscall; ++extern syscall_handler_t sys_swapoff; ++extern syscall_handler_t sys_sysinfo; ++extern syscall_handler_t sys_ipc; ++extern syscall_handler_t sys_fsync; ++extern syscall_handler_t sys_sigreturn; ++extern syscall_handler_t sys_rt_sigreturn; ++extern syscall_handler_t sys_clone; ++extern syscall_handler_t sys_setdomainname; ++extern syscall_handler_t sys_newuname; ++extern syscall_handler_t sys_ni_syscall; ++extern syscall_handler_t sys_adjtimex; ++extern syscall_handler_t sys_mprotect; ++extern syscall_handler_t sys_sigprocmask; ++extern syscall_handler_t sys_create_module; ++extern syscall_handler_t sys_init_module; ++extern syscall_handler_t sys_delete_module; ++extern syscall_handler_t sys_get_kernel_syms; ++extern syscall_handler_t sys_quotactl; ++extern syscall_handler_t sys_getpgid; ++extern syscall_handler_t sys_fchdir; ++extern syscall_handler_t sys_bdflush; ++extern syscall_handler_t sys_sysfs; ++extern syscall_handler_t sys_personality; ++extern syscall_handler_t sys_ni_syscall; ++extern syscall_handler_t sys_setfsuid16; ++extern syscall_handler_t sys_setfsgid16; ++extern syscall_handler_t sys_llseek; ++extern syscall_handler_t sys_getdents; ++extern syscall_handler_t sys_flock; ++extern syscall_handler_t sys_msync; ++extern syscall_handler_t sys_readv; ++extern syscall_handler_t sys_writev; ++extern syscall_handler_t sys_getsid; ++extern syscall_handler_t sys_fdatasync; ++extern syscall_handler_t sys_sysctl; ++extern syscall_handler_t sys_mlock; ++extern syscall_handler_t sys_munlock; ++extern syscall_handler_t sys_mlockall; ++extern syscall_handler_t sys_munlockall; ++extern syscall_handler_t sys_sched_setparam; ++extern syscall_handler_t sys_sched_getparam; ++extern syscall_handler_t sys_sched_setscheduler; ++extern syscall_handler_t sys_sched_getscheduler; ++extern syscall_handler_t sys_sched_get_priority_max; ++extern syscall_handler_t sys_sched_get_priority_min; ++extern syscall_handler_t sys_sched_rr_get_interval; ++extern syscall_handler_t sys_nanosleep; ++extern syscall_handler_t sys_mremap; ++extern syscall_handler_t sys_setresuid16; ++extern syscall_handler_t sys_getresuid16; ++extern syscall_handler_t sys_ni_syscall; ++extern syscall_handler_t sys_query_module; ++extern syscall_handler_t sys_poll; ++extern syscall_handler_t sys_nfsservctl; ++extern syscall_handler_t sys_setresgid16; ++extern syscall_handler_t sys_getresgid16; ++extern syscall_handler_t sys_prctl; ++extern syscall_handler_t sys_ni_syscall; ++extern syscall_handler_t sys_rt_sigaction; ++extern syscall_handler_t sys_rt_sigprocmask; ++extern syscall_handler_t sys_rt_sigpending; ++extern syscall_handler_t sys_rt_sigtimedwait; ++extern syscall_handler_t sys_rt_sigqueueinfo; ++extern syscall_handler_t sys_rt_sigsuspend; ++extern syscall_handler_t sys_pread; ++extern syscall_handler_t sys_pwrite; ++extern syscall_handler_t sys_chown16; ++extern syscall_handler_t sys_getcwd; ++extern syscall_handler_t sys_capget; ++extern syscall_handler_t sys_capset; ++extern syscall_handler_t sys_sigaltstack; ++extern syscall_handler_t sys_sendfile; ++extern syscall_handler_t sys_ni_syscall; ++extern syscall_handler_t sys_ni_syscall; ++extern syscall_handler_t sys_vfork; ++extern syscall_handler_t sys_getrlimit; ++extern syscall_handler_t sys_mmap2; ++extern syscall_handler_t sys_truncate64; ++extern syscall_handler_t sys_ftruncate64; ++extern syscall_handler_t sys_stat64; ++extern syscall_handler_t sys_lstat64; ++extern syscall_handler_t sys_fstat64; ++extern syscall_handler_t sys_lchown; ++extern syscall_handler_t sys_getuid; ++extern syscall_handler_t sys_getgid; ++extern syscall_handler_t sys_geteuid; ++extern syscall_handler_t sys_getegid; ++extern syscall_handler_t sys_setreuid; ++extern syscall_handler_t sys_setregid; ++extern syscall_handler_t sys_getgroups; ++extern syscall_handler_t sys_setgroups; ++extern syscall_handler_t sys_fchown; ++extern syscall_handler_t sys_setresuid; ++extern syscall_handler_t sys_getresuid; ++extern syscall_handler_t sys_setresgid; ++extern syscall_handler_t sys_getresgid; ++extern syscall_handler_t sys_chown; ++extern syscall_handler_t sys_setuid; ++extern syscall_handler_t sys_setgid; ++extern syscall_handler_t sys_setfsuid; ++extern syscall_handler_t sys_setfsgid; ++extern syscall_handler_t sys_pivot_root; ++extern syscall_handler_t sys_mincore; ++extern syscall_handler_t sys_madvise; ++extern syscall_handler_t sys_fcntl64; ++extern syscall_handler_t sys_getdents64; ++extern syscall_handler_t sys_gettid; ++extern syscall_handler_t sys_readahead; ++extern syscall_handler_t sys_tkill; ++extern syscall_handler_t sys_setxattr; ++extern syscall_handler_t sys_lsetxattr; ++extern syscall_handler_t sys_fsetxattr; ++extern syscall_handler_t sys_getxattr; ++extern syscall_handler_t sys_lgetxattr; ++extern syscall_handler_t sys_fgetxattr; ++extern syscall_handler_t sys_listxattr; ++extern syscall_handler_t sys_llistxattr; ++extern syscall_handler_t sys_flistxattr; ++extern syscall_handler_t sys_removexattr; ++extern syscall_handler_t sys_lremovexattr; ++extern syscall_handler_t sys_fremovexattr; ++extern syscall_handler_t sys_sendfile64; ++ ++extern syscall_handler_t um_mount; ++extern syscall_handler_t um_time; ++extern syscall_handler_t um_stime; ++ ++#define LAST_GENERIC_SYSCALL __NR_exit_group ++ ++#if LAST_GENERIC_SYSCALL > LAST_ARCH_SYSCALL ++#define LAST_SYSCALL LAST_GENERIC_SYSCALL ++#else ++#define LAST_SYSCALL LAST_ARCH_SYSCALL ++#endif ++ ++syscall_handler_t *sys_call_table[] = { ++ [ 0 ] = sys_ni_syscall, ++ [ __NR_exit ] = sys_exit, ++ [ __NR_fork ] = sys_fork, ++ [ __NR_read ] = (syscall_handler_t *) sys_read, ++ [ __NR_write ] = (syscall_handler_t *) sys_write, ++ ++ /* These three are declared differently in asm/unistd.h */ ++ [ __NR_open ] = (syscall_handler_t *) sys_open, ++ [ __NR_close ] = (syscall_handler_t *) sys_close, ++ [ __NR_waitpid ] = (syscall_handler_t *) sys_waitpid, ++ [ __NR_creat ] = sys_creat, ++ [ __NR_link ] = sys_link, ++ [ __NR_unlink ] = sys_unlink, ++ ++ /* declared differently in kern_util.h */ ++ [ __NR_execve ] = (syscall_handler_t *) sys_execve, ++ [ __NR_chdir ] = sys_chdir, ++ [ __NR_time ] = um_time, ++ [ __NR_mknod ] = sys_mknod, ++ [ __NR_chmod ] = sys_chmod, ++ [ __NR_lchown ] = sys_lchown16, ++ [ __NR_break ] = sys_ni_syscall, ++ [ __NR_oldstat ] = sys_stat, ++ [ __NR_lseek ] = (syscall_handler_t *) sys_lseek, ++ [ __NR_getpid ] = sys_getpid, ++ [ __NR_mount ] = um_mount, ++ [ __NR_umount ] = sys_oldumount, ++ [ __NR_setuid ] = sys_setuid16, ++ [ __NR_getuid ] = sys_getuid16, ++ [ __NR_stime ] = um_stime, ++ [ __NR_ptrace ] = sys_ptrace, ++ [ __NR_alarm ] = sys_alarm, ++ [ __NR_oldfstat ] = sys_fstat, ++ [ __NR_pause ] = sys_pause, ++ [ __NR_utime ] = sys_utime, ++ [ __NR_stty ] = sys_ni_syscall, ++ [ __NR_gtty ] = sys_ni_syscall, ++ [ __NR_access ] = sys_access, ++ [ __NR_nice ] = sys_nice, ++ [ __NR_ftime ] = sys_ni_syscall, ++ [ __NR_sync ] = sys_sync, ++ [ __NR_kill ] = sys_kill, ++ [ __NR_rename ] = sys_rename, ++ [ __NR_mkdir ] = sys_mkdir, ++ [ __NR_rmdir ] = sys_rmdir, ++ ++ /* Declared differently in asm/unistd.h */ ++ [ __NR_dup ] = (syscall_handler_t *) sys_dup, ++ [ __NR_pipe ] = sys_pipe, ++ [ __NR_times ] = sys_times, ++ [ __NR_prof ] = sys_ni_syscall, ++ [ __NR_brk ] = sys_brk, ++ [ __NR_setgid ] = sys_setgid16, ++ [ __NR_getgid ] = sys_getgid16, ++ [ __NR_signal ] = sys_signal, ++ [ __NR_geteuid ] = sys_geteuid16, ++ [ __NR_getegid ] = sys_getegid16, ++ [ __NR_acct ] = sys_acct, ++ [ __NR_umount2 ] = sys_umount, ++ [ __NR_lock ] = sys_ni_syscall, ++ [ __NR_ioctl ] = sys_ioctl, ++ [ __NR_fcntl ] = sys_fcntl, ++ [ __NR_mpx ] = sys_ni_syscall, ++ [ __NR_setpgid ] = sys_setpgid, ++ [ __NR_ulimit ] = sys_ni_syscall, ++ [ __NR_oldolduname ] = sys_olduname, ++ [ __NR_umask ] = sys_umask, ++ [ __NR_chroot ] = sys_chroot, ++ [ __NR_ustat ] = sys_ustat, ++ [ __NR_dup2 ] = sys_dup2, ++ [ __NR_getppid ] = sys_getppid, ++ [ __NR_getpgrp ] = sys_getpgrp, ++ [ __NR_setsid ] = (syscall_handler_t *) sys_setsid, ++ [ __NR_sigaction ] = sys_sigaction, ++ [ __NR_sgetmask ] = sys_sgetmask, ++ [ __NR_ssetmask ] = sys_ssetmask, ++ [ __NR_setreuid ] = sys_setreuid16, ++ [ __NR_setregid ] = sys_setregid16, ++ [ __NR_sigsuspend ] = sys_sigsuspend, ++ [ __NR_sigpending ] = sys_sigpending, ++ [ __NR_sethostname ] = sys_sethostname, ++ [ __NR_setrlimit ] = sys_setrlimit, ++ [ __NR_getrlimit ] = sys_old_getrlimit, ++ [ __NR_getrusage ] = sys_getrusage, ++ [ __NR_gettimeofday ] = sys_gettimeofday, ++ [ __NR_settimeofday ] = sys_settimeofday, ++ [ __NR_getgroups ] = sys_getgroups16, ++ [ __NR_setgroups ] = sys_setgroups16, ++ [ __NR_symlink ] = sys_symlink, ++ [ __NR_oldlstat ] = sys_lstat, ++ [ __NR_readlink ] = sys_readlink, ++ [ __NR_uselib ] = sys_uselib, ++ [ __NR_swapon ] = sys_swapon, ++ [ __NR_reboot ] = sys_reboot, ++ [ __NR_readdir ] = old_readdir, ++ [ __NR_munmap ] = sys_munmap, ++ [ __NR_truncate ] = sys_truncate, ++ [ __NR_ftruncate ] = sys_ftruncate, ++ [ __NR_fchmod ] = sys_fchmod, ++ [ __NR_fchown ] = sys_fchown16, ++ [ __NR_getpriority ] = sys_getpriority, ++ [ __NR_setpriority ] = sys_setpriority, ++ [ __NR_profil ] = sys_ni_syscall, ++ [ __NR_statfs ] = sys_statfs, ++ [ __NR_fstatfs ] = sys_fstatfs, ++ [ __NR_ioperm ] = sys_ni_syscall, ++ [ __NR_socketcall ] = sys_socketcall, ++ [ __NR_syslog ] = sys_syslog, ++ [ __NR_setitimer ] = sys_setitimer, ++ [ __NR_getitimer ] = sys_getitimer, ++ [ __NR_stat ] = sys_newstat, ++ [ __NR_lstat ] = sys_newlstat, ++ [ __NR_fstat ] = sys_newfstat, ++ [ __NR_olduname ] = sys_uname, ++ [ __NR_iopl ] = sys_ni_syscall, ++ [ __NR_vhangup ] = sys_vhangup, ++ [ __NR_idle ] = sys_ni_syscall, ++ [ __NR_wait4 ] = (syscall_handler_t *) sys_wait4, ++ [ __NR_swapoff ] = sys_swapoff, ++ [ __NR_sysinfo ] = sys_sysinfo, ++ [ __NR_ipc ] = sys_ipc, ++ [ __NR_fsync ] = sys_fsync, ++ [ __NR_sigreturn ] = sys_sigreturn, ++ [ __NR_clone ] = sys_clone, ++ [ __NR_setdomainname ] = sys_setdomainname, ++ [ __NR_uname ] = sys_newuname, ++ [ __NR_adjtimex ] = sys_adjtimex, ++ [ __NR_mprotect ] = sys_mprotect, ++ [ __NR_sigprocmask ] = sys_sigprocmask, ++ [ __NR_create_module ] = sys_create_module, ++ [ __NR_init_module ] = sys_init_module, ++ [ __NR_delete_module ] = sys_delete_module, ++ [ __NR_get_kernel_syms ] = sys_get_kernel_syms, ++ [ __NR_quotactl ] = sys_quotactl, ++ [ __NR_getpgid ] = sys_getpgid, ++ [ __NR_fchdir ] = sys_fchdir, ++ [ __NR_bdflush ] = sys_bdflush, ++ [ __NR_sysfs ] = sys_sysfs, ++ [ __NR_personality ] = sys_personality, ++ [ __NR_afs_syscall ] = sys_ni_syscall, ++ [ __NR_setfsuid ] = sys_setfsuid16, ++ [ __NR_setfsgid ] = sys_setfsgid16, ++ [ __NR__llseek ] = sys_llseek, ++ [ __NR_getdents ] = sys_getdents, ++ [ __NR__newselect ] = (syscall_handler_t *) sys_select, ++ [ __NR_flock ] = sys_flock, ++ [ __NR_msync ] = sys_msync, ++ [ __NR_readv ] = sys_readv, ++ [ __NR_writev ] = sys_writev, ++ [ __NR_getsid ] = sys_getsid, ++ [ __NR_fdatasync ] = sys_fdatasync, ++ [ __NR__sysctl ] = sys_sysctl, ++ [ __NR_mlock ] = sys_mlock, ++ [ __NR_munlock ] = sys_munlock, ++ [ __NR_mlockall ] = sys_mlockall, ++ [ __NR_munlockall ] = sys_munlockall, ++ [ __NR_sched_setparam ] = sys_sched_setparam, ++ [ __NR_sched_getparam ] = sys_sched_getparam, ++ [ __NR_sched_setscheduler ] = sys_sched_setscheduler, ++ [ __NR_sched_getscheduler ] = sys_sched_getscheduler, ++ [ __NR_sched_yield ] = (syscall_handler_t *) yield, ++ [ __NR_sched_get_priority_max ] = sys_sched_get_priority_max, ++ [ __NR_sched_get_priority_min ] = sys_sched_get_priority_min, ++ [ __NR_sched_rr_get_interval ] = sys_sched_rr_get_interval, ++ [ __NR_nanosleep ] = sys_nanosleep, ++ [ __NR_mremap ] = sys_mremap, ++ [ __NR_setresuid ] = sys_setresuid16, ++ [ __NR_getresuid ] = sys_getresuid16, ++ [ __NR_vm86 ] = sys_ni_syscall, ++ [ __NR_query_module ] = sys_query_module, ++ [ __NR_poll ] = sys_poll, ++ [ __NR_nfsservctl ] = sys_nfsservctl, ++ [ __NR_setresgid ] = sys_setresgid16, ++ [ __NR_getresgid ] = sys_getresgid16, ++ [ __NR_prctl ] = sys_prctl, ++ [ __NR_rt_sigreturn ] = sys_rt_sigreturn, ++ [ __NR_rt_sigaction ] = sys_rt_sigaction, ++ [ __NR_rt_sigprocmask ] = sys_rt_sigprocmask, ++ [ __NR_rt_sigpending ] = sys_rt_sigpending, ++ [ __NR_rt_sigtimedwait ] = sys_rt_sigtimedwait, ++ [ __NR_rt_sigqueueinfo ] = sys_rt_sigqueueinfo, ++ [ __NR_rt_sigsuspend ] = sys_rt_sigsuspend, ++ [ __NR_pread ] = sys_pread, ++ [ __NR_pwrite ] = sys_pwrite, ++ [ __NR_chown ] = sys_chown16, ++ [ __NR_getcwd ] = sys_getcwd, ++ [ __NR_capget ] = sys_capget, ++ [ __NR_capset ] = sys_capset, ++ [ __NR_sigaltstack ] = sys_sigaltstack, ++ [ __NR_sendfile ] = sys_sendfile, ++ [ __NR_getpmsg ] = sys_ni_syscall, ++ [ __NR_putpmsg ] = sys_ni_syscall, ++ [ __NR_vfork ] = sys_vfork, ++ [ __NR_ugetrlimit ] = sys_getrlimit, ++ [ __NR_mmap2 ] = sys_mmap2, ++ [ __NR_truncate64 ] = sys_truncate64, ++ [ __NR_ftruncate64 ] = sys_ftruncate64, ++ [ __NR_stat64 ] = sys_stat64, ++ [ __NR_lstat64 ] = sys_lstat64, ++ [ __NR_fstat64 ] = sys_fstat64, ++ [ __NR_fcntl64 ] = sys_fcntl64, ++ [ __NR_getdents64 ] = sys_getdents64, ++ [ __NR_security ] = sys_ni_syscall, ++ [ __NR_gettid ] = sys_gettid, ++ [ __NR_readahead ] = sys_readahead, ++ [ __NR_setxattr ] = sys_setxattr, ++ [ __NR_lsetxattr ] = sys_lsetxattr, ++ [ __NR_fsetxattr ] = sys_fsetxattr, ++ [ __NR_getxattr ] = sys_getxattr, ++ [ __NR_lgetxattr ] = sys_lgetxattr, ++ [ __NR_fgetxattr ] = sys_fgetxattr, ++ [ __NR_listxattr ] = sys_listxattr, ++ [ __NR_llistxattr ] = sys_llistxattr, ++ [ __NR_flistxattr ] = sys_flistxattr, ++ [ __NR_removexattr ] = sys_removexattr, ++ [ __NR_lremovexattr ] = sys_lremovexattr, ++ [ __NR_fremovexattr ] = sys_fremovexattr, ++ [ __NR_tkill ] = sys_tkill, ++ [ __NR_sendfile64 ] = sys_sendfile64, ++ [ __NR_futex ] = sys_ni_syscall, ++ [ __NR_sched_setaffinity ] = sys_ni_syscall, ++ [ __NR_sched_getaffinity ] = sys_ni_syscall, ++ [ __NR_set_thread_area ] = sys_ni_syscall, ++ [ __NR_get_thread_area ] = sys_ni_syscall, ++ [ __NR_io_setup ] = sys_ni_syscall, ++ [ __NR_io_destroy ] = sys_ni_syscall, ++ [ __NR_io_getevents ] = sys_ni_syscall, ++ [ __NR_io_submit ] = sys_ni_syscall, ++ [ __NR_io_cancel ] = sys_ni_syscall, ++ [ __NR_alloc_hugepages ] = sys_ni_syscall, ++ [ __NR_free_hugepages ] = sys_ni_syscall, ++ [ __NR_exit_group ] = sys_ni_syscall, ++ ++ ARCH_SYSCALLS ++ [ LAST_SYSCALL + 1 ... NR_syscalls ] = ++ (syscall_handler_t *) sys_ni_syscall ++}; ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/syscall_user.c um/arch/um/kernel/syscall_user.c +--- orig/arch/um/kernel/syscall_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/syscall_user.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdlib.h> ++#include <sys/time.h> ++#include "kern_util.h" ++#include "syscall_user.h" ++ ++struct { ++ int syscall; ++ int pid; ++ int result; ++ struct timeval start; ++ struct timeval end; ++} syscall_record[1024]; ++ ++int record_syscall_start(int syscall) ++{ ++ int max, index; ++ ++ max = sizeof(syscall_record)/sizeof(syscall_record[0]); ++ index = next_syscall_index(max); ++ ++ syscall_record[index].syscall = syscall; ++ syscall_record[index].pid = current_pid(); ++ syscall_record[index].result = 0xdeadbeef; ++ gettimeofday(&syscall_record[index].start, NULL); ++ return(index); ++} ++ ++void record_syscall_end(int index, int result) ++{ ++ syscall_record[index].result = result; ++ gettimeofday(&syscall_record[index].end, NULL); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/sysrq.c um/arch/um/kernel/sysrq.c +--- orig/arch/um/kernel/sysrq.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/sysrq.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,98 @@ ++/* ++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/sched.h" ++#include "linux/kernel.h" ++#include "linux/module.h" ++#include "asm/page.h" ++#include "asm/processor.h" ++#include "sysrq.h" ++#include "user_util.h" ++ ++ /* ++ * If the address is either in the .text section of the ++ * kernel, or in the vmalloc'ed module regions, it *may* ++ * be the address of a calling routine ++ */ ++ ++#ifdef CONFIG_MODULES ++ ++extern struct module *module_list; ++extern struct module kernel_module; ++ ++static inline int kernel_text_address(unsigned long addr) ++{ ++ int retval = 0; ++ struct module *mod; ++ ++ if (addr >= (unsigned long) &_stext && ++ addr <= (unsigned long) &_etext) ++ return 1; ++ ++ for (mod = module_list; mod != &kernel_module; mod = mod->next) { ++ /* mod_bound tests for addr being inside the vmalloc'ed ++ * module area. Of course it'd be better to test only ++ * for the .text subset... */ ++ if (mod_bound(addr, 0, mod)) { ++ retval = 1; ++ break; ++ } ++ } ++ ++ return retval; ++} ++ ++#else ++ ++static inline int kernel_text_address(unsigned long addr) ++{ ++ return (addr >= (unsigned long) &_stext && ++ addr <= (unsigned long) &_etext); ++} ++ ++#endif ++ ++void show_trace(unsigned long * stack) ++{ ++ int i; ++ unsigned long addr; ++ ++ if (!stack) ++ stack = (unsigned long*) &stack; ++ ++ printk("Call Trace: "); ++ i = 1; ++ while (((long) stack & (THREAD_SIZE-1)) != 0) { ++ addr = *stack++; ++ if (kernel_text_address(addr)) { ++ if (i && ((i % 6) == 0)) ++ printk("\n "); ++ printk("[<%08lx>] ", addr); ++ i++; ++ } ++ } ++ printk("\n"); ++} ++ ++void show_trace_task(struct task_struct *tsk) ++{ ++ unsigned long esp = PT_REGS_SP(&tsk->thread.regs); ++ ++ /* User space on another CPU? */ ++ if ((esp ^ (unsigned long)tsk) & (PAGE_MASK<<1)) ++ return; ++ show_trace((unsigned long *)esp); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tempfile.c um/arch/um/kernel/tempfile.c +--- orig/arch/um/kernel/tempfile.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tempfile.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,82 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <unistd.h> ++#include <string.h> ++#include <errno.h> ++#include <sys/param.h> ++#include "init.h" ++ ++/* Modified from create_mem_file and start_debugger */ ++static char *tempdir = NULL; ++ ++static void __init find_tempdir(void) ++{ ++ char *dirs[] = { "TMP", "TEMP", "TMPDIR", NULL }; ++ int i; ++ char *dir = NULL; ++ ++ if(tempdir != NULL) return; /* We've already been called */ ++ for(i = 0; dirs[i]; i++){ ++ dir = getenv(dirs[i]); ++ if((dir != NULL) && (*dir != '\0')) ++ break; ++ } ++ if((dir == NULL) || (*dir == '\0')) ++ dir = "/tmp"; ++ ++ tempdir = malloc(strlen(dir) + 2); ++ if(tempdir == NULL){ ++ fprintf(stderr, "Failed to malloc tempdir, " ++ "errno = %d\n", errno); ++ return; ++ } ++ strcpy(tempdir, dir); ++ strcat(tempdir, "/"); ++} ++ ++int make_tempfile(const char *template, char **out_tempname, int do_unlink) ++{ ++ char tempname[MAXPATHLEN]; ++ int fd; ++ ++ find_tempdir(); ++ if (*template != '/') ++ strcpy(tempname, tempdir); ++ else ++ *tempname = 0; ++ strcat(tempname, template); ++ fd = mkstemp(tempname); ++ if(fd < 0){ ++ fprintf(stderr, "open - cannot create %s: %s\n", tempname, ++ strerror(errno)); ++ return -1; ++ } ++ if(do_unlink && (unlink(tempname) < 0)){ ++ perror("unlink"); ++ return -1; ++ } ++ if(out_tempname){ ++ *out_tempname = strdup(tempname); ++ if(*out_tempname == NULL){ ++ perror("strdup"); ++ return -1; ++ } ++ } ++ return(fd); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/time.c um/arch/um/kernel/time.c +--- orig/arch/um/kernel/time.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/time.c 2003-12-17 01:08:27.000000000 -0500 +@@ -0,0 +1,164 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <unistd.h> ++#include <time.h> ++#include <sys/time.h> ++#include <signal.h> ++#include <errno.h> ++#include "user_util.h" ++#include "kern_util.h" ++#include "user.h" ++#include "process.h" ++#include "signal_user.h" ++#include "time_user.h" ++ ++extern struct timeval xtime; ++ ++struct timeval local_offset = { 0, 0 }; ++ ++void timer(void) ++{ ++ gettimeofday(&xtime, NULL); ++ timeradd(&xtime, &local_offset, &xtime); ++} ++ ++void set_interval(int timer_type) ++{ ++ int usec = 1000000/hz(); ++ struct itimerval interval = ((struct itimerval) { { 0, usec }, ++ { 0, usec } }); ++ ++ if(setitimer(timer_type, &interval, NULL) == -1) ++ panic("setitimer failed - errno = %d\n", errno); ++} ++ ++void enable_timer(void) ++{ ++ int usec = 1000000/hz(); ++ struct itimerval enable = ((struct itimerval) { { 0, usec }, ++ { 0, usec }}); ++ if(setitimer(ITIMER_VIRTUAL, &enable, NULL)) ++ printk("enable_timer - setitimer failed, errno = %d\n", ++ errno); ++} ++ ++void switch_timers(int to_real) ++{ ++ struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); ++ struct itimerval enable = ((struct itimerval) { { 0, 1000000/hz() }, ++ { 0, 1000000/hz() }}); ++ int old, new; ++ ++ if(to_real){ ++ old = ITIMER_VIRTUAL; ++ new = ITIMER_REAL; ++ } ++ else { ++ old = ITIMER_REAL; ++ new = ITIMER_VIRTUAL; ++ } ++ ++ if((setitimer(old, &disable, NULL) < 0) || ++ (setitimer(new, &enable, NULL))) ++ printk("switch_timers - setitimer failed, errno = %d\n", ++ errno); ++} ++ ++void idle_timer(void) ++{ ++ if(signal(SIGVTALRM, SIG_IGN) == SIG_ERR) ++ panic("Couldn't unset SIGVTALRM handler"); ++ ++ set_handler(SIGALRM, (__sighandler_t) alarm_handler, ++ SA_RESTART, SIGUSR1, SIGIO, SIGWINCH, SIGVTALRM, -1); ++ set_interval(ITIMER_REAL); ++} ++ ++static unsigned long long get_host_hz(void) ++{ ++ char mhzline[16], *end; ++ int ret, mult, mhz, rest, len; ++ ++ ret = cpu_feature("cpu MHz", mhzline, ++ sizeof(mhzline) / sizeof(mhzline[0])); ++ if(!ret) ++ panic ("Could not get host MHZ"); ++ ++ mhz = strtoul(mhzline, &end, 10); ++ ++ /* This business is to parse a floating point number without using ++ * floating types. ++ */ ++ ++ rest = 0; ++ mult = 0; ++ if(*end == '.'){ ++ end++; ++ len = strlen(end); ++ if(len < 6) ++ mult = 6 - len; ++ else if(len > 6) ++ end[6] = '\0'; ++ rest = strtoul(end, NULL, 10); ++ while(mult-- > 0) ++ rest *= 10; ++ } ++ ++ return(1000000 * mhz + rest); ++} ++ ++unsigned long long host_hz = 0; ++ ++void time_init(void) ++{ ++ host_hz = get_host_hz(); ++ if(signal(SIGVTALRM, boot_timer_handler) == SIG_ERR) ++ panic("Couldn't set SIGVTALRM handler"); ++ set_interval(ITIMER_VIRTUAL); ++} ++ ++void do_gettimeofday(struct timeval *tv) ++{ ++ unsigned long flags; ++ ++ flags = time_lock(); ++ gettimeofday(tv, NULL); ++ timeradd(tv, &local_offset, tv); ++ time_unlock(flags); ++} ++ ++void do_settimeofday(struct timeval *tv) ++{ ++ struct timeval now; ++ unsigned long flags; ++ ++ flags = time_lock(); ++ gettimeofday(&now, NULL); ++ timersub(tv, &now, &local_offset); ++ time_unlock(flags); ++} ++ ++void idle_sleep(int secs) ++{ ++ struct timespec ts; ++ ++ ts.tv_sec = secs; ++ ts.tv_nsec = 0; ++ nanosleep(&ts, NULL); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/time_kern.c um/arch/um/kernel/time_kern.c +--- orig/arch/um/kernel/time_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/time_kern.c 2003-12-17 01:07:51.000000000 -0500 +@@ -0,0 +1,205 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/kernel.h" ++#include "linux/unistd.h" ++#include "linux/stddef.h" ++#include "linux/spinlock.h" ++#include "linux/sched.h" ++#include "linux/interrupt.h" ++#include "linux/init.h" ++#include "linux/delay.h" ++#include "asm/irq.h" ++#include "asm/param.h" ++#include "asm/current.h" ++#include "kern_util.h" ++#include "user_util.h" ++#include "time_user.h" ++#include "mode.h" ++ ++extern rwlock_t xtime_lock; ++ ++int hz(void) ++{ ++ return(HZ); ++} ++ ++/* Changed at early boot */ ++int timer_irq_inited = 0; ++ ++/* missed_ticks will be modified after kernel memory has been ++ * write-protected, so this puts it in a section which will be left ++ * write-enabled. ++ */ ++int __attribute__ ((__section__ (".unprotected"))) missed_ticks[NR_CPUS]; ++ ++static int first_tick; ++static unsigned long long prev_tsc; ++static long long delta; /* Deviation per interval */ ++ ++extern unsigned long long host_hz; ++ ++void timer_irq(union uml_pt_regs *regs) ++{ ++ unsigned long long ticks = 0; ++ ++ if(!timer_irq_inited){ ++ /* This is to ensure that ticks don't pile up when ++ * the timer handler is suspended */ ++ first_tick = 0; ++ return; ++ } ++ ++ if(first_tick){ ++#if defined(CONFIG_UML_REAL_TIME_CLOCK) ++ unsigned long long tsc; ++ /* We've had 1 tick */ ++ tsc = time_stamp(); ++ ++ delta += tsc - prev_tsc; ++ prev_tsc = tsc; ++ ++ ticks += (delta * HZ) / host_hz; ++ delta -= (ticks * host_hz) / HZ; ++#else ++ ticks = 1; ++#endif ++ } ++ else { ++ prev_tsc = time_stamp(); ++ first_tick = 1; ++ } ++ ++ while(ticks > 0){ ++ do_IRQ(TIMER_IRQ, regs); ++ ticks--; ++ } ++} ++ ++void boot_timer_handler(int sig) ++{ ++ struct pt_regs regs; ++ ++ CHOOSE_MODE((void) ++ (UPT_SC(®s.regs) = (struct sigcontext *) (&sig + 1)), ++ (void) (regs.regs.skas.is_user = 0)); ++ do_timer(®s); ++} ++ ++void um_timer(int irq, void *dev, struct pt_regs *regs) ++{ ++ do_timer(regs); ++ write_lock(&xtime_lock); ++ vxtime_lock(); ++ timer(); ++ vxtime_unlock(); ++ write_unlock(&xtime_lock); ++} ++ ++long um_time(int * tloc) ++{ ++ struct timeval now; ++ ++ do_gettimeofday(&now); ++ if (tloc) { ++ if (put_user(now.tv_sec,tloc)) ++ now.tv_sec = -EFAULT; ++ } ++ return now.tv_sec; ++} ++ ++long um_stime(int * tptr) ++{ ++ int value; ++ struct timeval new; ++ ++ if (get_user(value, tptr)) ++ return -EFAULT; ++ new.tv_sec = value; ++ new.tv_usec = 0; ++ do_settimeofday(&new); ++ return 0; ++} ++ ++/* XXX Needs to be moved under sys-i386 */ ++void __delay(um_udelay_t time) ++{ ++ /* Stolen from the i386 __loop_delay */ ++ int d0; ++ __asm__ __volatile__( ++ "\tjmp 1f\n" ++ ".align 16\n" ++ "1:\tjmp 2f\n" ++ ".align 16\n" ++ "2:\tdecl %0\n\tjns 2b" ++ :"=&a" (d0) ++ :"0" (time)); ++} ++ ++void __udelay(um_udelay_t usecs) ++{ ++ int i, n; ++ ++ n = (loops_per_jiffy * HZ * usecs) / 1000000; ++ for(i=0;i<n;i++) ; ++} ++ ++void __const_udelay(um_udelay_t usecs) ++{ ++ int i, n; ++ ++ n = (loops_per_jiffy * HZ * usecs) / 1000000; ++ for(i=0;i<n;i++) ; ++} ++ ++void timer_handler(int sig, union uml_pt_regs *regs) ++{ ++#ifdef CONFIG_SMP ++ update_process_times(user_context(UPT_SP(regs))); ++#endif ++ if(current->processor == 0) ++ timer_irq(regs); ++} ++ ++static spinlock_t timer_spinlock = SPIN_LOCK_UNLOCKED; ++ ++unsigned long time_lock(void) ++{ ++ unsigned long flags; ++ ++ spin_lock_irqsave(&timer_spinlock, flags); ++ return(flags); ++} ++ ++void time_unlock(unsigned long flags) ++{ ++ spin_unlock_irqrestore(&timer_spinlock, flags); ++} ++ ++int __init timer_init(void) ++{ ++ int err; ++ ++ CHOOSE_MODE(user_time_init_tt(), user_time_init_skas()); ++ err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", NULL); ++ if(err != 0) ++ printk(KERN_ERR "timer_init : request_irq failed - " ++ "errno = %d\n", -err); ++ timer_irq_inited = 1; ++ return(0); ++} ++ ++__initcall(timer_init); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tlb.c um/arch/um/kernel/tlb.c +--- orig/arch/um/kernel/tlb.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tlb.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,80 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/mm.h" ++#include "asm/page.h" ++#include "asm/pgalloc.h" ++#include "choose-mode.h" ++#include "mode_kern.h" ++ ++void flush_tlb_page(struct vm_area_struct *vma, unsigned long address) ++{ ++ address &= PAGE_MASK; ++ flush_tlb_range(vma->vm_mm, address, address + PAGE_SIZE); ++} ++ ++void flush_tlb_all(void) ++{ ++ flush_tlb_mm(current->mm); ++} ++ ++void flush_tlb_kernel_vm(void) ++{ ++ CHOOSE_MODE(flush_tlb_kernel_vm_tt(), flush_tlb_kernel_vm_skas()); ++} ++ ++void __flush_tlb_one(unsigned long addr) ++{ ++ CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr); ++} ++ ++void flush_tlb_range(struct mm_struct *mm, unsigned long start, ++ unsigned long end) ++{ ++ CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, mm, start, ++ end); ++} ++ ++void flush_tlb_mm(struct mm_struct *mm) ++{ ++ CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm); ++} ++ ++void force_flush_all(void) ++{ ++ CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas()); ++} ++ ++ ++pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address) ++{ ++ return(pgd_offset(mm, address)); ++} ++ ++pmd_t *pmd_offset_proc(pgd_t *pgd, unsigned long address) ++{ ++ return(pmd_offset(pgd, address)); ++} ++ ++pte_t *pte_offset_proc(pmd_t *pmd, unsigned long address) ++{ ++ return(pte_offset(pmd, address)); ++} ++ ++pte_t *addr_pte(struct task_struct *task, unsigned long addr) ++{ ++ return(pte_offset(pmd_offset(pgd_offset(task->mm, addr), addr), addr)); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/trap_kern.c um/arch/um/kernel/trap_kern.c +--- orig/arch/um/kernel/trap_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/trap_kern.c 2003-12-14 11:18:05.000000000 -0500 +@@ -0,0 +1,220 @@ ++/* ++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/kernel.h" ++#include "linux/sched.h" ++#include "linux/mm.h" ++#include "linux/spinlock.h" ++#include "linux/config.h" ++#include "linux/init.h" ++#include "asm/semaphore.h" ++#include "asm/pgtable.h" ++#include "asm/pgalloc.h" ++#include "asm/a.out.h" ++#include "asm/current.h" ++#include "asm/irq.h" ++#include "user_util.h" ++#include "kern_util.h" ++#include "kern.h" ++#include "chan_kern.h" ++#include "mconsole_kern.h" ++#include "2_5compat.h" ++#include "mem.h" ++#include "mem_kern.h" ++ ++unsigned long handle_page_fault(unsigned long address, unsigned long ip, ++ int is_write, int is_user, int *code_out) ++{ ++ struct mm_struct *mm = current->mm; ++ struct vm_area_struct *vma; ++ pgd_t *pgd; ++ pmd_t *pmd; ++ pte_t *pte; ++ unsigned long page; ++ int handled = 0; ++ ++ *code_out = SEGV_MAPERR; ++ down_read(&mm->mmap_sem); ++ vma = find_vma(mm, address); ++ if(!vma) ++ goto out; ++ else if(vma->vm_start <= address) ++ goto good_area; ++ else if(!(vma->vm_flags & VM_GROWSDOWN)) ++ goto out; ++ else if(expand_stack(vma, address)) ++ goto out; ++ ++ good_area: ++ *code_out = SEGV_ACCERR; ++ if(is_write && !(vma->vm_flags & VM_WRITE)) ++ goto out; ++ page = address & PAGE_MASK; ++ if(page == (unsigned long) current + PAGE_SIZE) ++ panic("Kernel stack overflow"); ++ pgd = pgd_offset(mm, page); ++ pmd = pmd_offset(pgd, page); ++ do { ++ survive: ++ switch (handle_mm_fault(mm, vma, address, is_write)) { ++ case 1: ++ current->min_flt++; ++ break; ++ case 2: ++ current->maj_flt++; ++ break; ++ default: ++ if (current->pid == 1) { ++ up_read(&mm->mmap_sem); ++ yield(); ++ down_read(&mm->mmap_sem); ++ goto survive; ++ } ++ /* Fall through to bad area case */ ++ case 0: ++ goto out; ++ } ++ pte = pte_offset(pmd, page); ++ } while(!pte_present(*pte)); ++ handled = 1; ++ *pte = pte_mkyoung(*pte); ++ if(pte_write(*pte)) *pte = pte_mkdirty(*pte); ++ flush_tlb_page(vma, page); ++ out: ++ up_read(&mm->mmap_sem); ++ return(handled); ++} ++ ++LIST_HEAD(physmem_remappers); ++ ++void register_remapper(struct remapper *info) ++{ ++ list_add(&info->list, &physmem_remappers); ++} ++ ++static int check_remapped_addr(unsigned long address, int is_write) ++{ ++ struct remapper *remapper; ++ struct list_head *ele; ++ __u64 offset; ++ int fd; ++ ++ fd = phys_mapping(__pa(address), &offset); ++ if(fd == -1) ++ return(0); ++ ++ list_for_each(ele, &physmem_remappers){ ++ remapper = list_entry(ele, struct remapper, list); ++ if((*remapper->proc)(fd, address, is_write, offset)) ++ return(1); ++ } ++ ++ return(0); ++} ++ ++unsigned long segv(unsigned long address, unsigned long ip, int is_write, ++ int is_user, void *sc) ++{ ++ struct siginfo si; ++ void *catcher; ++ int handled; ++ ++ if(!is_user && (address >= start_vm) && (address < end_vm)){ ++ flush_tlb_kernel_vm(); ++ return(0); ++ } ++ else if(check_remapped_addr(address & PAGE_MASK, is_write)) ++ return(0); ++ else if(current->mm == NULL) ++ panic("Segfault with no mm"); ++ ++ handled = handle_page_fault(address, ip, is_write, is_user, ++ &si.si_code); ++ ++ catcher = current->thread.fault_catcher; ++ if(handled) ++ return(0); ++ else if(catcher != NULL){ ++ current->thread.fault_addr = (void *) address; ++ do_longjmp(catcher, 1); ++ } ++ else if(current->thread.fault_addr != NULL) ++ panic("fault_addr set but no fault catcher"); ++ else if(arch_fixup(ip, sc)) ++ return(0); ++ ++ if(!is_user) ++ panic("Kernel mode fault at addr 0x%lx, ip 0x%lx", ++ address, ip); ++ si.si_signo = SIGSEGV; ++ si.si_addr = (void *) address; ++ current->thread.cr2 = address; ++ current->thread.err = is_write; ++ force_sig_info(SIGSEGV, &si, current); ++ return(0); ++} ++ ++void bad_segv(unsigned long address, unsigned long ip, int is_write) ++{ ++ struct siginfo si; ++ ++ si.si_signo = SIGSEGV; ++ si.si_code = SEGV_ACCERR; ++ si.si_addr = (void *) address; ++ current->thread.cr2 = address; ++ current->thread.err = is_write; ++ force_sig_info(SIGSEGV, &si, current); ++} ++ ++void relay_signal(int sig, union uml_pt_regs *regs) ++{ ++ if(arch_handle_signal(sig, regs)) return; ++ if(!UPT_IS_USER(regs)) ++ panic("Kernel mode signal %d", sig); ++ force_sig(sig, current); ++} ++ ++void bus_handler(int sig, union uml_pt_regs *regs) ++{ ++ if(current->thread.fault_catcher != NULL) ++ do_longjmp(current->thread.fault_catcher, 1); ++ else relay_signal(sig, regs); ++} ++ ++void winch(int sig, union uml_pt_regs *regs) ++{ ++ do_IRQ(WINCH_IRQ, regs); ++} ++ ++void trap_init(void) ++{ ++} ++ ++spinlock_t trap_lock = SPIN_LOCK_UNLOCKED; ++ ++static int trap_index = 0; ++ ++int next_trap_index(int limit) ++{ ++ int ret; ++ ++ spin_lock(&trap_lock); ++ ret = trap_index; ++ if(++trap_index == limit) ++ trap_index = 0; ++ spin_unlock(&trap_lock); ++ return(ret); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/trap_user.c um/arch/um/kernel/trap_user.c +--- orig/arch/um/kernel/trap_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/trap_user.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,138 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdlib.h> ++#include <errno.h> ++#include <setjmp.h> ++#include <signal.h> ++#include <sys/time.h> ++#include <sys/ptrace.h> ++#include <sys/wait.h> ++#include <asm/page.h> ++#include <asm/unistd.h> ++#include <asm/ptrace.h> ++#include "init.h" ++#include "sysdep/ptrace.h" ++#include "sigcontext.h" ++#include "sysdep/sigcontext.h" ++#include "irq_user.h" ++#include "frame_user.h" ++#include "signal_user.h" ++#include "time_user.h" ++#include "task.h" ++#include "mode.h" ++#include "choose-mode.h" ++#include "kern_util.h" ++#include "user_util.h" ++#include "os.h" ++ ++void kill_child_dead(int pid) ++{ ++ kill(pid, SIGKILL); ++ kill(pid, SIGCONT); ++ while(waitpid(pid, NULL, 0) > 0) kill(pid, SIGCONT); ++} ++ ++/* Unlocked - don't care if this is a bit off */ ++int nsegfaults = 0; ++ ++struct { ++ unsigned long address; ++ int is_write; ++ int pid; ++ unsigned long sp; ++ int is_user; ++} segfault_record[1024]; ++ ++void segv_handler(int sig, union uml_pt_regs *regs) ++{ ++ int index, max; ++ ++ if(UPT_IS_USER(regs) && !UPT_SEGV_IS_FIXABLE(regs)){ ++ bad_segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), ++ UPT_FAULT_WRITE(regs)); ++ return; ++ } ++ max = sizeof(segfault_record)/sizeof(segfault_record[0]); ++ index = next_trap_index(max); ++ ++ nsegfaults++; ++ segfault_record[index].address = UPT_FAULT_ADDR(regs); ++ segfault_record[index].pid = os_getpid(); ++ segfault_record[index].is_write = UPT_FAULT_WRITE(regs); ++ segfault_record[index].sp = UPT_SP(regs); ++ segfault_record[index].is_user = UPT_IS_USER(regs); ++ segv(UPT_FAULT_ADDR(regs), UPT_IP(regs), UPT_FAULT_WRITE(regs), ++ UPT_IS_USER(regs), regs); ++} ++ ++void usr2_handler(int sig, union uml_pt_regs *regs) ++{ ++ CHOOSE_MODE(syscall_handler_tt(sig, regs), (void) 0); ++} ++ ++struct signal_info sig_info[] = { ++ [ SIGTRAP ] { .handler = relay_signal, ++ .is_irq = 0 }, ++ [ SIGFPE ] { .handler = relay_signal, ++ .is_irq = 0 }, ++ [ SIGILL ] { .handler = relay_signal, ++ .is_irq = 0 }, ++ [ SIGWINCH ] { .handler = winch, ++ .is_irq = 1 }, ++ [ SIGBUS ] { .handler = bus_handler, ++ .is_irq = 0 }, ++ [ SIGSEGV] { .handler = segv_handler, ++ .is_irq = 0 }, ++ [ SIGIO ] { .handler = sigio_handler, ++ .is_irq = 1 }, ++ [ SIGVTALRM ] { .handler = timer_handler, ++ .is_irq = 1 }, ++ [ SIGALRM ] { .handler = timer_handler, ++ .is_irq = 1 }, ++ [ SIGUSR2 ] { .handler = usr2_handler, ++ .is_irq = 0 }, ++}; ++ ++void sig_handler(int sig, struct sigcontext sc) ++{ ++ CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas, ++ sig, &sc); ++} ++ ++extern int timer_irq_inited, missed_ticks[]; ++ ++void alarm_handler(int sig, struct sigcontext sc) ++{ ++ if(!timer_irq_inited) return; ++ missed_ticks[cpu()]++; ++ ++ if(sig == SIGALRM) ++ switch_timers(0); ++ ++ CHOOSE_MODE_PROC(sig_handler_common_tt, sig_handler_common_skas, ++ sig, &sc); ++ ++ if(sig == SIGALRM) ++ switch_timers(1); ++} ++ ++void do_longjmp(void *b, int val) ++{ ++ jmp_buf *buf = b; ++ ++ siglongjmp(*buf, val); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/exec_kern.c um/arch/um/kernel/tt/exec_kern.c +--- orig/arch/um/kernel/tt/exec_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/exec_kern.c 2003-11-07 02:23:10.000000000 -0500 +@@ -0,0 +1,84 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/kernel.h" ++#include "linux/mm.h" ++#include "asm/signal.h" ++#include "asm/ptrace.h" ++#include "asm/uaccess.h" ++#include "asm/pgalloc.h" ++#include "user_util.h" ++#include "kern_util.h" ++#include "irq_user.h" ++#include "time_user.h" ++#include "mem_user.h" ++#include "os.h" ++#include "tlb.h" ++#include "mode.h" ++ ++static int exec_tramp(void *sig_stack) ++{ ++ init_new_thread_stack(sig_stack, NULL); ++ init_new_thread_signals(1); ++ os_stop_process(os_getpid()); ++ return(0); ++} ++ ++void flush_thread_tt(void) ++{ ++ unsigned long stack; ++ int new_pid; ++ ++ stack = alloc_stack(0, 0); ++ if(stack == 0){ ++ printk(KERN_ERR ++ "flush_thread : failed to allocate temporary stack\n"); ++ do_exit(SIGKILL); ++ } ++ ++ new_pid = start_fork_tramp((void *) current->thread.kernel_stack, ++ stack, 0, exec_tramp); ++ if(new_pid < 0){ ++ printk(KERN_ERR ++ "flush_thread : new thread failed, errno = %d\n", ++ -new_pid); ++ do_exit(SIGKILL); ++ } ++ ++ if(current->processor == 0) ++ forward_interrupts(new_pid); ++ current->thread.request.op = OP_EXEC; ++ current->thread.request.u.exec.pid = new_pid; ++ unprotect_stack((unsigned long) current); ++ os_usr1_process(os_getpid()); ++ ++ enable_timer(); ++ free_page(stack); ++ protect_memory(uml_reserved, high_physmem - uml_reserved, 1, 1, 0, 1); ++ task_protections((unsigned long) current); ++ force_flush_all(); ++ unblock_signals(); ++} ++ ++void start_thread_tt(struct pt_regs *regs, unsigned long eip, ++ unsigned long esp) ++{ ++ set_fs(USER_DS); ++ flush_tlb_mm(current->mm); ++ PT_REGS_IP(regs) = eip; ++ PT_REGS_SP(regs) = esp; ++ PT_FIX_EXEC_STACK(esp); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/exec_user.c um/arch/um/kernel/tt/exec_user.c +--- orig/arch/um/kernel/tt/exec_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/exec_user.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,49 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdio.h> ++#include <unistd.h> ++#include <stdlib.h> ++#include <sched.h> ++#include <errno.h> ++#include <sys/wait.h> ++#include <sys/ptrace.h> ++#include <signal.h> ++#include "user_util.h" ++#include "kern_util.h" ++#include "user.h" ++#include "ptrace_user.h" ++ ++void do_exec(int old_pid, int new_pid) ++{ ++ unsigned long regs[FRAME_SIZE]; ++ ++ if((ptrace(PTRACE_ATTACH, new_pid, 0, 0) < 0) || ++ (ptrace(PTRACE_CONT, new_pid, 0, 0) < 0) || ++ (waitpid(new_pid, 0, WUNTRACED) < 0)) ++ tracer_panic("do_exec failed to attach proc - errno = %d", ++ errno); ++ ++ if(ptrace_getregs(old_pid, regs) < 0) ++ tracer_panic("do_exec failed to get registers - errno = %d", ++ errno); ++ ++ kill(old_pid, SIGKILL); ++ ++ if(ptrace_setregs(new_pid, regs) < 0) ++ tracer_panic("do_exec failed to start new proc - errno = %d", ++ errno); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/gdb.c um/arch/um/kernel/tt/gdb.c +--- orig/arch/um/kernel/tt/gdb.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/gdb.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,278 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <errno.h> ++#include <string.h> ++#include <signal.h> ++#include <sys/ptrace.h> ++#include <sys/types.h> ++#include "uml-config.h" ++#include "kern_constants.h" ++#include "chan_user.h" ++#include "init.h" ++#include "user.h" ++#include "debug.h" ++#include "kern_util.h" ++#include "user_util.h" ++#include "tt.h" ++#include "sysdep/thread.h" ++ ++extern int debugger_pid; ++extern int debugger_fd; ++extern int debugger_parent; ++ ++int detach(int pid, int sig) ++{ ++ return(ptrace(PTRACE_DETACH, pid, 0, sig)); ++} ++ ++int attach(int pid) ++{ ++ int err; ++ ++ err = ptrace(PTRACE_ATTACH, pid, 0, 0); ++ if(err < 0) return(-errno); ++ else return(err); ++} ++ ++int cont(int pid) ++{ ++ return(ptrace(PTRACE_CONT, pid, 0, 0)); ++} ++ ++#ifdef UML_CONFIG_PT_PROXY ++ ++int debugger_signal(int status, pid_t pid) ++{ ++ return(debugger_proxy(status, pid)); ++} ++ ++void child_signal(pid_t pid, int status) ++{ ++ child_proxy(pid, status); ++} ++ ++static void gdb_announce(char *dev_name, int dev) ++{ ++ printf("gdb assigned device '%s'\n", dev_name); ++} ++ ++static struct chan_opts opts = { ++ .announce = gdb_announce, ++ .xterm_title = "UML kernel debugger", ++ .raw = 0, ++ .tramp_stack = 0, ++ .in_kernel = 0, ++}; ++ ++/* Accessed by the tracing thread, which automatically serializes access */ ++static void *xterm_data; ++static int xterm_fd; ++ ++extern void *xterm_init(char *, int, struct chan_opts *); ++extern int xterm_open(int, int, int, void *, char **); ++extern void xterm_close(int, void *); ++ ++int open_gdb_chan(void) ++{ ++ char stack[UM_KERN_PAGE_SIZE], *dummy; ++ ++ opts.tramp_stack = (unsigned long) stack; ++ xterm_data = xterm_init("", 0, &opts); ++ xterm_fd = xterm_open(1, 1, 1, xterm_data, &dummy); ++ return(xterm_fd); ++} ++ ++static void exit_debugger_cb(void *unused) ++{ ++ if(debugger_pid != -1){ ++ if(gdb_pid != -1){ ++ fake_child_exit(); ++ gdb_pid = -1; ++ } ++ else kill_child_dead(debugger_pid); ++ debugger_pid = -1; ++ if(debugger_parent != -1) ++ detach(debugger_parent, SIGINT); ++ } ++ if(xterm_data != NULL) xterm_close(xterm_fd, xterm_data); ++} ++ ++static void exit_debugger(void) ++{ ++ initial_thread_cb(exit_debugger_cb, NULL); ++} ++ ++__uml_exitcall(exit_debugger); ++ ++struct gdb_data { ++ char *str; ++ int err; ++}; ++ ++static void config_gdb_cb(void *arg) ++{ ++ struct gdb_data *data = arg; ++ void *task; ++ int pid; ++ ++ data->err = -1; ++ if(debugger_pid != -1) exit_debugger_cb(NULL); ++ if(!strncmp(data->str, "pid,", strlen("pid,"))){ ++ data->str += strlen("pid,"); ++ pid = strtoul(data->str, NULL, 0); ++ task = cpu_tasks[0].task; ++ debugger_pid = attach_debugger(TASK_EXTERN_PID(task), pid, 0); ++ if(debugger_pid != -1){ ++ data->err = 0; ++ gdb_pid = pid; ++ } ++ return; ++ } ++ data->err = 0; ++ debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd); ++ init_proxy(debugger_pid, 0, 0); ++} ++ ++int gdb_config(char *str) ++{ ++ struct gdb_data data; ++ ++ if(*str++ != '=') return(-1); ++ data.str = str; ++ initial_thread_cb(config_gdb_cb, &data); ++ return(data.err); ++} ++ ++void remove_gdb_cb(void *unused) ++{ ++ exit_debugger_cb(NULL); ++} ++ ++int gdb_remove(char *unused) ++{ ++ initial_thread_cb(remove_gdb_cb, NULL); ++ return(0); ++} ++ ++void signal_usr1(int sig) ++{ ++ if(debugger_pid != -1){ ++ printk(UM_KERN_ERR "The debugger is already running\n"); ++ return; ++ } ++ debugger_pid = start_debugger(linux_prog, 0, 0, &debugger_fd); ++ init_proxy(debugger_pid, 0, 0); ++} ++ ++int init_ptrace_proxy(int idle_pid, int startup, int stop) ++{ ++ int pid, status; ++ ++ pid = start_debugger(linux_prog, startup, stop, &debugger_fd); ++ status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL); ++ if(pid < 0){ ++ cont(idle_pid); ++ return(-1); ++ } ++ init_proxy(pid, 1, status); ++ return(pid); ++} ++ ++int attach_debugger(int idle_pid, int pid, int stop) ++{ ++ int status = 0, err; ++ ++ err = attach(pid); ++ if(err < 0){ ++ printf("Failed to attach pid %d, errno = %d\n", pid, -err); ++ return(-1); ++ } ++ if(stop) status = wait_for_stop(idle_pid, SIGSTOP, PTRACE_CONT, NULL); ++ init_proxy(pid, 1, status); ++ return(pid); ++} ++ ++#ifdef notdef /* Put this back in when it does something useful */ ++static int __init uml_gdb_init_setup(char *line, int *add) ++{ ++ gdb_init = uml_strdup(line); ++ return 0; ++} ++ ++__uml_setup("gdb=", uml_gdb_init_setup, ++"gdb=<channel description>\n\n" ++); ++#endif ++ ++static int __init uml_gdb_pid_setup(char *line, int *add) ++{ ++ gdb_pid = strtoul(line, NULL, 0); ++ *add = 0; ++ return 0; ++} ++ ++__uml_setup("gdb-pid=", uml_gdb_pid_setup, ++"gdb-pid=<pid>\n" ++" gdb-pid is used to attach an external debugger to UML. This may be\n" ++" an already-running gdb or a debugger-like process like strace.\n\n" ++); ++ ++#else ++ ++int debugger_signal(int status, pid_t pid){ return(0); } ++void child_signal(pid_t pid, int status){ } ++int init_ptrace_proxy(int idle_pid, int startup, int stop) ++{ ++ printk(UM_KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n"); ++ kill_child_dead(idle_pid); ++ exit(1); ++} ++ ++void signal_usr1(int sig) ++{ ++ printk(UM_KERN_ERR "debug requested when CONFIG_PT_PROXY is off\n"); ++} ++ ++int attach_debugger(int idle_pid, int pid, int stop) ++{ ++ printk(UM_KERN_ERR "attach_debugger called when CONFIG_PT_PROXY " ++ "is off\n"); ++ return(-1); ++} ++ ++int config_gdb(char *str) ++{ ++ return(-1); ++} ++ ++int remove_gdb(void) ++{ ++ return(-1); ++} ++ ++int init_parent_proxy(int pid) ++{ ++ return(-1); ++} ++ ++void debugger_parent_signal(int status, int pid) ++{ ++} ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/gdb_kern.c um/arch/um/kernel/tt/gdb_kern.c +--- orig/arch/um/kernel/tt/gdb_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/gdb_kern.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,40 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/init.h" ++#include "linux/config.h" ++#include "mconsole_kern.h" ++ ++#ifdef CONFIG_MCONSOLE ++ ++extern int gdb_config(char *str); ++extern int gdb_remove(char *unused); ++ ++static struct mc_device gdb_mc = { ++ .name = "gdb", ++ .config = gdb_config, ++ .remove = gdb_remove, ++}; ++ ++int gdb_mc_init(void) ++{ ++ mconsole_register_dev(&gdb_mc); ++ return(0); ++} ++ ++__initcall(gdb_mc_init); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/include/debug.h um/arch/um/kernel/tt/include/debug.h +--- orig/arch/um/kernel/tt/include/debug.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/include/debug.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,29 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) and ++ * Lars Brinkhoff. ++ * Licensed under the GPL ++ */ ++ ++#ifndef __DEBUG_H ++#define __DEBUG_H ++ ++extern int debugger_proxy(int status, pid_t pid); ++extern void child_proxy(pid_t pid, int status); ++extern void init_proxy (pid_t pid, int waiting, int status); ++extern int start_debugger(char *prog, int startup, int stop, int *debugger_fd); ++extern void fake_child_exit(void); ++extern int gdb_config(char *str); ++extern int gdb_remove(char *unused); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/include/mmu.h um/arch/um/kernel/tt/include/mmu.h +--- orig/arch/um/kernel/tt/include/mmu.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/include/mmu.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,23 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __TT_MMU_H ++#define __TT_MMU_H ++ ++struct mmu_context_tt { ++}; ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/include/mode.h um/arch/um/kernel/tt/include/mode.h +--- orig/arch/um/kernel/tt/include/mode.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/include/mode.h 2003-11-07 01:42:09.000000000 -0500 +@@ -0,0 +1,38 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __MODE_TT_H__ ++#define __MODE_TT_H__ ++ ++#include "sysdep/ptrace.h" ++ ++enum { OP_NONE, OP_EXEC, OP_FORK, OP_TRACE_ON, OP_REBOOT, OP_HALT, OP_CB }; ++ ++extern int tracing_pid; ++ ++extern int tracer(int (*init_proc)(void *), void *sp); ++extern void user_time_init_tt(void); ++extern int copy_sc_from_user_tt(void *to_ptr, void *from_ptr, void *data); ++extern int copy_sc_to_user_tt(void *to_ptr, void *fp, void *from_ptr, ++ void *data); ++extern void sig_handler_common_tt(int sig, void *sc); ++extern void syscall_handler_tt(int sig, union uml_pt_regs *regs); ++extern void reboot_tt(void); ++extern void halt_tt(void); ++extern int is_tracer_winch(int pid, int fd, void *data); ++extern void kill_off_processes_tt(void); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/include/mode_kern.h um/arch/um/kernel/tt/include/mode_kern.h +--- orig/arch/um/kernel/tt/include/mode_kern.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/include/mode_kern.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,52 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __TT_MODE_KERN_H__ ++#define __TT_MODE_KERN_H__ ++ ++#include "linux/sched.h" ++#include "asm/page.h" ++#include "asm/ptrace.h" ++#include "asm/uaccess.h" ++ ++extern void *_switch_to_tt(void *prev, void *next); ++extern void flush_thread_tt(void); ++extern void start_thread_tt(struct pt_regs *regs, unsigned long eip, ++ unsigned long esp); ++extern int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, ++ unsigned long stack_top, struct task_struct *p, ++ struct pt_regs *regs); ++extern void release_thread_tt(struct task_struct *task); ++extern void exit_thread_tt(void); ++extern void initial_thread_cb_tt(void (*proc)(void *), void *arg); ++extern void init_idle_tt(void); ++extern void flush_tlb_kernel_vm_tt(void); ++extern void __flush_tlb_one_tt(unsigned long addr); ++extern void flush_tlb_range_tt(struct mm_struct *mm, unsigned long start, ++ unsigned long end); ++extern void flush_tlb_mm_tt(struct mm_struct *mm); ++extern void force_flush_all_tt(void); ++extern long execute_syscall_tt(void *r); ++extern void before_mem_tt(unsigned long brk_start); ++extern unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out, ++ unsigned long *task_size_out); ++extern int start_uml_tt(void); ++extern int external_pid_tt(struct task_struct *task); ++extern int thread_pid_tt(struct thread_struct *thread); ++ ++#define kmem_end_tt (host_task_size - ABOVE_KMEM) ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/include/ptrace-tt.h um/arch/um/kernel/tt/include/ptrace-tt.h +--- orig/arch/um/kernel/tt/include/ptrace-tt.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/include/ptrace-tt.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,26 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __PTRACE_TT_H ++#define __PTRACE_TT_H ++ ++#include "uml-config.h" ++ ++#ifdef UML_CONFIG_MODE_TT ++#include "sysdep/sc.h" ++#endif ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/include/tt.h um/arch/um/kernel/tt/include/tt.h +--- orig/arch/um/kernel/tt/include/tt.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/include/tt.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,46 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __TT_H__ ++#define __TT_H__ ++ ++#include "sysdep/ptrace.h" ++ ++extern int gdb_pid; ++extern int debug; ++extern int debug_stop; ++extern int debug_trace; ++ ++extern int honeypot; ++ ++extern int fork_tramp(void *sig_stack); ++extern int do_proc_op(void *t, int proc_id); ++extern int tracer(int (*init_proc)(void *), void *sp); ++extern void attach_process(int pid); ++extern void tracer_panic(char *format, ...); ++extern void set_init_pid(int pid); ++extern int set_user_mode(void *task); ++extern void set_tracing(void *t, int tracing); ++extern int is_tracing(void *task); ++extern int singlestepping_tt(void *t); ++extern void clear_singlestep(void *t); ++extern void syscall_handler(int sig, union uml_pt_regs *regs); ++extern void exit_kernel(int pid, void *task); ++extern int do_syscall(void *task, int pid); ++extern int is_valid_pid(int pid); ++extern void remap_data(void *segment_start, void *segment_end, int w); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/include/uaccess.h um/arch/um/kernel/tt/include/uaccess.h +--- orig/arch/um/kernel/tt/include/uaccess.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/include/uaccess.h 2003-11-12 08:37:20.000000000 -0500 +@@ -0,0 +1,71 @@ ++/* ++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __TT_UACCESS_H ++#define __TT_UACCESS_H ++ ++#include "linux/string.h" ++#include "linux/sched.h" ++#include "asm/processor.h" ++#include "asm/errno.h" ++#include "asm/current.h" ++#include "asm/a.out.h" ++#include "uml_uaccess.h" ++ ++#define ABOVE_KMEM (16 * 1024 * 1024) ++ ++extern unsigned long end_vm; ++extern unsigned long uml_physmem; ++ ++#define under_task_size(addr, size) \ ++ (((unsigned long) (addr) < TASK_SIZE) && \ ++ (((unsigned long) (addr) + (size)) < TASK_SIZE)) ++ ++#define is_stack(addr, size) \ ++ (((unsigned long) (addr) < STACK_TOP) && \ ++ ((unsigned long) (addr) >= STACK_TOP - ABOVE_KMEM) && \ ++ (((unsigned long) (addr) + (size)) <= STACK_TOP)) ++ ++#define access_ok_tt(type, addr, size) \ ++ ((type == VERIFY_READ) || (segment_eq(get_fs(), KERNEL_DS)) || \ ++ (((unsigned long) (addr) <= ((unsigned long) (addr) + (size))) && \ ++ (under_task_size(addr, size) || is_stack(addr, size)))) ++ ++static inline int verify_area_tt(int type, const void * addr, ++ unsigned long size) ++{ ++ return(access_ok_tt(type, addr, size) ? 0 : -EFAULT); ++} ++ ++extern unsigned long get_fault_addr(void); ++ ++extern int __do_copy_from_user(void *to, const void *from, int n, ++ void **fault_addr, void **fault_catcher); ++extern int __do_strncpy_from_user(char *dst, const char *src, size_t n, ++ void **fault_addr, void **fault_catcher); ++extern int __do_clear_user(void *mem, size_t len, void **fault_addr, ++ void **fault_catcher); ++extern int __do_strnlen_user(const char *str, unsigned long n, ++ void **fault_addr, void **fault_catcher); ++ ++extern int copy_from_user_tt(void *to, const void *from, int n); ++extern int copy_to_user_tt(void *to, const void *from, int n); ++extern int strncpy_from_user_tt(char *dst, const char *src, int count); ++extern int __clear_user_tt(void *mem, int len); ++extern int clear_user_tt(void *mem, int len); ++extern int strnlen_user_tt(const void *str, int len); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/ksyms.c um/arch/um/kernel/tt/ksyms.c +--- orig/arch/um/kernel/tt/ksyms.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/ksyms.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/module.h" ++#include "asm/uaccess.h" ++#include "mode.h" ++ ++EXPORT_SYMBOL(__do_copy_from_user); ++EXPORT_SYMBOL(__do_copy_to_user); ++EXPORT_SYMBOL(__do_strncpy_from_user); ++EXPORT_SYMBOL(__do_strnlen_user); ++EXPORT_SYMBOL(__do_clear_user); ++ ++EXPORT_SYMBOL(tracing_pid); ++EXPORT_SYMBOL(honeypot); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/Makefile um/arch/um/kernel/tt/Makefile +--- orig/arch/um/kernel/tt/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/Makefile 2003-11-12 08:34:27.000000000 -0500 +@@ -0,0 +1,39 @@ ++# ++# Copyright (C) 2002 - 2003 Jeff Dike (jdike@addtoit.com) ++# Licensed under the GPL ++# ++ ++O_TARGET = tt.o ++ ++obj-y = exec_kern.o exec_user.o gdb.o ksyms.o mem.o mem_user.o process_kern.o \ ++ syscall_kern.o syscall_user.o time.o tlb.o tracer.o trap_user.o \ ++ uaccess.o uaccess_user.o ++ ++obj-$(CONFIG_PT_PROXY) += gdb_kern.o ++ ++subdir-y = sys-$(SUBARCH) ++subdir-$(CONFIG_PT_PROXY) += ptproxy ++ ++obj-y += $(join $(subdir-y),$(subdir-y:%=/%.o)) ++ ++export-objs = ksyms.o ++ ++USER_OBJS = $(filter %_user.o,$(obj-y)) gdb.o time.o tracer.o ++ ++UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS)) ++UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS)) ++ ++include $(TOPDIR)/Rules.make ++ ++$(USER_OBJS) : %.o: %.c ++ $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< ++ ++$(O_TARGET) : unmap_fin.o ++ ++unmap.o: unmap.c ++ $(CC) $(UNMAP_CFLAGS) -c -o $@ $< ++ ++unmap_fin.o : unmap.o ++ ld -r -o $@ $< -lc -L/usr/lib ++ ++clean : +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/mem.c um/arch/um/kernel/tt/mem.c +--- orig/arch/um/kernel/tt/mem.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/mem.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,51 @@ ++/* ++ * Copyright (C) 2002 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(brk_start), 1); ++} ++ ++#ifdef CONFIG_HOST_2G_2G ++#define TOP 0x80000000 ++#else ++#define TOP 0xc0000000 ++#endif ++ ++#define SIZE ((CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS) * 0x20000000) ++#define START (TOP - SIZE) ++ ++unsigned long set_task_sizes_tt(int arg, unsigned long *host_size_out, ++ unsigned long *task_size_out) ++{ ++ /* Round up to the nearest 4M */ ++ *host_size_out = ROUND_4M((unsigned long) &arg); ++ *task_size_out = START; ++ return(START); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/mem_user.c um/arch/um/kernel/tt/mem_user.c +--- orig/arch/um/kernel/tt/mem_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/mem_user.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,49 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdlib.h> ++#include <stdio.h> ++#include <unistd.h> ++#include <string.h> ++#include <errno.h> ++#include <sys/mman.h> ++#include "tt.h" ++#include "mem_user.h" ++#include "user_util.h" ++ ++void remap_data(void *segment_start, void *segment_end, int w) ++{ ++ void *addr; ++ unsigned long size; ++ int data, prot; ++ ++ if(w) prot = PROT_WRITE; ++ else prot = 0; ++ prot |= PROT_READ | PROT_EXEC; ++ size = (unsigned long) segment_end - ++ (unsigned long) segment_start; ++ data = create_mem_file(size); ++ addr = mmap(NULL, size, PROT_WRITE | PROT_READ, MAP_SHARED, data, 0); ++ if(addr == MAP_FAILED){ ++ perror("mapping new data segment"); ++ exit(1); ++ } ++ memcpy(addr, segment_start, size); ++ if(switcheroo(data, prot, addr, segment_start, size) < 0){ ++ printf("switcheroo failed\n"); ++ exit(1); ++ } ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/process_kern.c um/arch/um/kernel/tt/process_kern.c +--- orig/arch/um/kernel/tt/process_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/process_kern.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,537 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/sched.h" ++#include "linux/signal.h" ++#include "linux/kernel.h" ++#include "asm/system.h" ++#include "asm/pgalloc.h" ++#include "asm/ptrace.h" ++#include "irq_user.h" ++#include "signal_user.h" ++#include "kern_util.h" ++#include "user_util.h" ++#include "os.h" ++#include "kern.h" ++#include "sigcontext.h" ++#include "time_user.h" ++#include "mem_user.h" ++#include "tlb.h" ++#include "mode.h" ++#include "init.h" ++#include "tt.h" ++ ++void *_switch_to_tt(void *prev, void *next) ++{ ++ struct task_struct *from, *to; ++ unsigned long flags; ++ int err, vtalrm, alrm, prof, cpu; ++ char c; ++ /* jailing and SMP are incompatible, so this doesn't need to be ++ * made per-cpu ++ */ ++ static int reading; ++ ++ from = prev; ++ to = next; ++ ++ to->thread.prev_sched = from; ++ ++ cpu = from->processor; ++ if(cpu == 0) ++ forward_interrupts(to->thread.mode.tt.extern_pid); ++#ifdef CONFIG_SMP ++ forward_ipi(cpu_data[cpu].ipi_pipe[0], to->thread.mode.tt.extern_pid); ++#endif ++ local_irq_save(flags); ++ ++ vtalrm = change_sig(SIGVTALRM, 0); ++ alrm = change_sig(SIGALRM, 0); ++ prof = change_sig(SIGPROF, 0); ++ ++ c = 0; ++ set_current(to); ++ ++ reading = 0; ++ err = os_write_file(to->thread.mode.tt.switch_pipe[1], &c, sizeof(c)); ++ if(err != sizeof(c)) ++ panic("write of switch_pipe failed, err = %d", -err); ++ ++ reading = 1; ++ if(from->state == TASK_ZOMBIE) ++ os_kill_process(os_getpid(), 0); ++ ++ err = os_read_file(from->thread.mode.tt.switch_pipe[0], &c, sizeof(c)); ++ if(err != sizeof(c)) ++ panic("read of switch_pipe failed, errno = %d", -err); ++ ++ /* This works around a nasty race with 'jail'. If we are switching ++ * between two threads of a threaded app and the incoming process ++ * runs before the outgoing process reaches the read, and it makes ++ * it all the way out to userspace, then it will have write-protected ++ * the outgoing process stack. Then, when the outgoing process ++ * returns from the write, it will segfault because it can no longer ++ * write its own stack. So, in order to avoid that, the incoming ++ * thread sits in a loop yielding until 'reading' is set. This ++ * isn't entirely safe, since there may be a reschedule from a timer ++ * happening between setting 'reading' and sleeping in read. But, ++ * it should get a whole quantum in which to reach the read and sleep, ++ * which should be enough. ++ */ ++ ++ if(jail){ ++ while(!reading) sched_yield(); ++ } ++ ++ change_sig(SIGVTALRM, vtalrm); ++ change_sig(SIGALRM, alrm); ++ change_sig(SIGPROF, prof); ++ ++ arch_switch(); ++ ++ flush_tlb_all(); ++ local_irq_restore(flags); ++ ++ return(current->thread.prev_sched); ++} ++ ++void release_thread_tt(struct task_struct *task) ++{ ++ os_kill_process(task->thread.mode.tt.extern_pid, 0); ++} ++ ++void exit_thread_tt(void) ++{ ++ os_close_file(current->thread.mode.tt.switch_pipe[0]); ++ os_close_file(current->thread.mode.tt.switch_pipe[1]); ++} ++ ++extern void schedule_tail(struct task_struct *prev); ++ ++static void new_thread_handler(int sig) ++{ ++ unsigned long disable; ++ int (*fn)(void *); ++ void *arg; ++ ++ fn = current->thread.request.u.thread.proc; ++ arg = current->thread.request.u.thread.arg; ++ ++ UPT_SC(¤t->thread.regs.regs) = (void *) (&sig + 1); ++ disable = (1 << (SIGVTALRM - 1)) | (1 << (SIGALRM - 1)) | ++ (1 << (SIGIO - 1)) | (1 << (SIGPROF - 1)); ++ SC_SIGMASK(UPT_SC(¤t->thread.regs.regs)) &= ~disable; ++ ++ suspend_new_thread(current->thread.mode.tt.switch_pipe[0]); ++ ++ init_new_thread_signals(1); ++ enable_timer(); ++ free_page(current->thread.temp_stack); ++ set_cmdline("(kernel thread)"); ++ force_flush_all(); ++ ++ if(current->thread.prev_sched != NULL) ++ schedule_tail(current->thread.prev_sched); ++ current->thread.prev_sched = NULL; ++ ++ change_sig(SIGUSR1, 1); ++ change_sig(SIGVTALRM, 1); ++ change_sig(SIGPROF, 1); ++ sti(); ++ if(!run_kernel_thread(fn, arg, ¤t->thread.exec_buf)) ++ do_exit(0); ++} ++ ++static int new_thread_proc(void *stack) ++{ ++ /* cli is needed to block out signals until this thread is properly ++ * scheduled. Otherwise, the tracing thread will get mighty upset ++ * about any signals that arrive before that. ++ * This has the complication that it sets the saved signal mask in ++ * the sigcontext to block signals. This gets restored when this ++ * thread (or a descendant, since they get a copy of this sigcontext) ++ * returns to userspace. ++ * So, this is compensated for elsewhere. ++ * XXX There is still a small window until cli() actually finishes ++ * where signals are possible - shouldn't be a problem in practice ++ * since SIGIO hasn't been forwarded here yet, and the cli should ++ * finish before a SIGVTALRM has time to be delivered. ++ */ ++ cli(); ++ init_new_thread_stack(stack, new_thread_handler); ++ os_usr1_process(os_getpid()); ++ return(0); ++} ++ ++/* Signal masking - signals are blocked at the start of fork_tramp. They ++ * are re-enabled when finish_fork_handler is entered by fork_tramp hitting ++ * itself with a SIGUSR1. set_user_mode has to be run with SIGUSR1 off, ++ * so it is blocked before it's called. They are re-enabled on sigreturn ++ * despite the fact that they were blocked when the SIGUSR1 was issued because ++ * copy_thread copies the parent's sigcontext, including the signal mask ++ * onto the signal frame. ++ */ ++ ++static void finish_fork_handler(int sig) ++{ ++ UPT_SC(¤t->thread.regs.regs) = (void *) (&sig + 1); ++ suspend_new_thread(current->thread.mode.tt.switch_pipe[0]); ++ ++ init_new_thread_signals(1); ++ enable_timer(); ++ sti(); ++ force_flush_all(); ++ if(current->mm != current->p_pptr->mm) ++ protect_memory(uml_reserved, high_physmem - uml_reserved, 1, ++ 1, 0, 1); ++ task_protections((unsigned long) current); ++ ++ if(current->thread.prev_sched != NULL) ++ schedule_tail(current->thread.prev_sched); ++ current->thread.prev_sched = NULL; ++ ++ free_page(current->thread.temp_stack); ++ cli(); ++ change_sig(SIGUSR1, 0); ++ set_user_mode(current); ++} ++ ++int fork_tramp(void *stack) ++{ ++ cli(); ++ arch_init_thread(); ++ init_new_thread_stack(stack, finish_fork_handler); ++ os_usr1_process(os_getpid()); ++ return(0); ++} ++ ++int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp, ++ unsigned long stack_top, struct task_struct * p, ++ struct pt_regs *regs) ++{ ++ int (*tramp)(void *); ++ int new_pid, err; ++ unsigned long stack; ++ ++ if(current->thread.forking) ++ tramp = fork_tramp; ++ else { ++ tramp = new_thread_proc; ++ p->thread.request.u.thread = current->thread.request.u.thread; ++ } ++ ++ err = os_pipe(p->thread.mode.tt.switch_pipe, 1, 1); ++ if(err < 0){ ++ printk("copy_thread : pipe failed, err = %d\n", -err); ++ return(err); ++ } ++ ++ stack = alloc_stack(0, 0); ++ if(stack == 0){ ++ printk(KERN_ERR "copy_thread : failed to allocate " ++ "temporary stack\n"); ++ return(-ENOMEM); ++ } ++ ++ clone_flags &= CLONE_VM; ++ p->thread.temp_stack = stack; ++ new_pid = start_fork_tramp((void *) p->thread.kernel_stack, stack, ++ clone_flags, tramp); ++ if(new_pid < 0){ ++ printk(KERN_ERR "copy_thread : clone failed - errno = %d\n", ++ -new_pid); ++ return(new_pid); ++ } ++ ++ if(current->thread.forking){ ++ sc_to_sc(UPT_SC(&p->thread.regs.regs), ++ UPT_SC(¤t->thread.regs.regs)); ++ SC_SET_SYSCALL_RETURN(UPT_SC(&p->thread.regs.regs), 0); ++ if(sp != 0) SC_SP(UPT_SC(&p->thread.regs.regs)) = sp; ++ } ++ p->thread.mode.tt.extern_pid = new_pid; ++ ++ current->thread.request.op = OP_FORK; ++ current->thread.request.u.fork.pid = new_pid; ++ os_usr1_process(os_getpid()); ++ return(0); ++} ++ ++void reboot_tt(void) ++{ ++ current->thread.request.op = OP_REBOOT; ++ os_usr1_process(os_getpid()); ++ os_kill_process(os_getpid(), 0); ++} ++ ++void halt_tt(void) ++{ ++ current->thread.request.op = OP_HALT; ++ os_usr1_process(os_getpid()); ++ os_kill_process(os_getpid(), 0); ++} ++ ++void kill_off_processes_tt(void) ++{ ++ struct task_struct *p; ++ int me; ++ ++ me = os_getpid(); ++ for_each_task(p){ ++ int pid = p->thread.mode.tt.extern_pid; ++ if((pid != me) && (pid != -1)) ++ os_kill_process(p->thread.mode.tt.extern_pid, 0); ++ } ++ if((init_task.thread.mode.tt.extern_pid != me) && ++ (init_task.thread.mode.tt.extern_pid != -1)) ++ os_kill_process(init_task.thread.mode.tt.extern_pid, 0); ++} ++ ++void initial_thread_cb_tt(void (*proc)(void *), void *arg) ++{ ++ if(os_getpid() == tracing_pid){ ++ (*proc)(arg); ++ } ++ else { ++ current->thread.request.op = OP_CB; ++ current->thread.request.u.cb.proc = proc; ++ current->thread.request.u.cb.arg = arg; ++ os_usr1_process(os_getpid()); ++ } ++} ++ ++int do_proc_op(void *t, int proc_id) ++{ ++ struct task_struct *task; ++ struct thread_struct *thread; ++ int op, pid; ++ ++ task = t; ++ thread = &task->thread; ++ op = thread->request.op; ++ switch(op){ ++ case OP_NONE: ++ case OP_TRACE_ON: ++ break; ++ case OP_EXEC: ++ pid = thread->request.u.exec.pid; ++ do_exec(thread->mode.tt.extern_pid, pid); ++ thread->mode.tt.extern_pid = pid; ++ cpu_tasks[task->processor].pid = pid; ++ break; ++ case OP_FORK: ++ attach_process(thread->request.u.fork.pid); ++ break; ++ case OP_CB: ++ (*thread->request.u.cb.proc)(thread->request.u.cb.arg); ++ break; ++ case OP_REBOOT: ++ case OP_HALT: ++ break; ++ default: ++ tracer_panic("Bad op in do_proc_op"); ++ break; ++ } ++ thread->request.op = OP_NONE; ++ return(op); ++} ++ ++void init_idle_tt(void) ++{ ++ idle_timer(); ++} ++ ++/* Changed by jail_setup, which is a setup */ ++int jail = 0; ++ ++int __init jail_setup(char *line, int *add) ++{ ++ int ok = 1; ++ ++ if(jail) return(0); ++#ifdef CONFIG_SMP ++ printf("'jail' may not used used in a kernel with CONFIG_SMP " ++ "enabled\n"); ++ ok = 0; ++#endif ++#ifdef CONFIG_HOSTFS ++ printf("'jail' may not used used in a kernel with CONFIG_HOSTFS " ++ "enabled\n"); ++ ok = 0; ++#endif ++#ifdef CONFIG_MODULES ++ printf("'jail' may not used used in a kernel with CONFIG_MODULES " ++ "enabled\n"); ++ ok = 0; ++#endif ++ if(!ok) exit(1); ++ ++ /* CAP_SYS_RAWIO controls the ability to open /dev/mem and /dev/kmem. ++ * Removing it from the bounding set eliminates the ability of anything ++ * to acquire it, and thus read or write kernel memory. ++ */ ++ cap_lower(cap_bset, CAP_SYS_RAWIO); ++ jail = 1; ++ return(0); ++} ++ ++__uml_setup("jail", jail_setup, ++"jail\n" ++" Enables the protection of kernel memory from processes.\n\n" ++); ++ ++static void mprotect_kernel_mem(int w) ++{ ++ unsigned long start, end; ++ int pages; ++ ++ if(!jail || (current == &init_task)) return; ++ ++ pages = (1 << CONFIG_KERNEL_STACK_ORDER); ++ ++ start = (unsigned long) current + PAGE_SIZE; ++ end = (unsigned long) current + PAGE_SIZE * pages; ++ protect_memory(uml_reserved, start - uml_reserved, 1, w, 1, 1); ++ protect_memory(end, high_physmem - end, 1, w, 1, 1); ++ ++ start = (unsigned long) UML_ROUND_DOWN(&_stext); ++ end = (unsigned long) UML_ROUND_UP(&_etext); ++ protect_memory(start, end - start, 1, w, 1, 1); ++ ++ start = (unsigned long) UML_ROUND_DOWN(&_unprotected_end); ++ end = (unsigned long) UML_ROUND_UP(&_edata); ++ protect_memory(start, end - start, 1, w, 1, 1); ++ ++ start = (unsigned long) UML_ROUND_DOWN(&__bss_start); ++ end = (unsigned long) UML_ROUND_UP(brk_start); ++ protect_memory(start, end - start, 1, w, 1, 1); ++ ++ mprotect_kernel_vm(w); ++} ++ ++void unprotect_kernel_mem(void) ++{ ++ mprotect_kernel_mem(1); ++} ++ ++void protect_kernel_mem(void) ++{ ++ mprotect_kernel_mem(0); ++} ++ ++extern void start_kernel(void); ++ ++static int start_kernel_proc(void *unused) ++{ ++ int pid; ++ ++ block_signals(); ++ pid = os_getpid(); ++ ++ cpu_tasks[0].pid = pid; ++ cpu_tasks[0].task = current; ++#ifdef CONFIG_SMP ++ cpu_online_map = 1; ++#endif ++ if(debug) os_stop_process(pid); ++ start_kernel(); ++ return(0); ++} ++ ++void set_tracing(void *task, int tracing) ++{ ++ ((struct task_struct *) task)->thread.mode.tt.tracing = tracing; ++} ++ ++int is_tracing(void *t) ++{ ++ return (((struct task_struct *) t)->thread.mode.tt.tracing); ++} ++ ++int set_user_mode(void *t) ++{ ++ struct task_struct *task; ++ ++ task = t ? t : current; ++ if(task->thread.mode.tt.tracing) ++ return(1); ++ task->thread.request.op = OP_TRACE_ON; ++ os_usr1_process(os_getpid()); ++ return(0); ++} ++ ++void set_init_pid(int pid) ++{ ++ int err; ++ ++ init_task.thread.mode.tt.extern_pid = pid; ++ err = os_pipe(init_task.thread.mode.tt.switch_pipe, 1, 1); ++ if(err) ++ panic("Can't create switch pipe for init_task, errno = %d", ++ -err); ++} ++ ++int singlestepping_tt(void *t) ++{ ++ struct task_struct *task = t; ++ ++ if(task->thread.mode.tt.singlestep_syscall) ++ return(0); ++ return(task->ptrace & PT_DTRACE); ++} ++ ++void clear_singlestep(void *t) ++{ ++ struct task_struct *task = t; ++ ++ task->ptrace &= ~PT_DTRACE; ++} ++ ++int start_uml_tt(void) ++{ ++ void *sp; ++ int pages; ++ ++ pages = (1 << CONFIG_KERNEL_STACK_ORDER) - 2; ++ sp = (void *) init_task.thread.kernel_stack + pages * PAGE_SIZE - ++ sizeof(unsigned long); ++ return(tracer(start_kernel_proc, sp)); ++} ++ ++int external_pid_tt(struct task_struct *task) ++{ ++ return(task->thread.mode.tt.extern_pid); ++} ++ ++int thread_pid_tt(struct thread_struct *thread) ++{ ++ return(thread->mode.tt.extern_pid); ++} ++ ++int is_valid_pid(int pid) ++{ ++ struct task_struct *task; ++ ++ read_lock(&tasklist_lock); ++ for_each_task(task){ ++ if(task->thread.mode.tt.extern_pid == pid){ ++ read_unlock(&tasklist_lock); ++ return(1); ++ } ++ } ++ read_unlock(&tasklist_lock); ++ return(0); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/ptproxy/Makefile um/arch/um/kernel/tt/ptproxy/Makefile +--- orig/arch/um/kernel/tt/ptproxy/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/ptproxy/Makefile 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,12 @@ ++O_TARGET = ptproxy.o ++ ++obj-y = proxy.o ptrace.o sysdep.o wait.o ++ ++USER_OBJS = $(obj-y) ++ ++include $(TOPDIR)/Rules.make ++ ++$(USER_OBJS) : %.o: %.c ++ $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< ++ ++clean: +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/ptproxy/proxy.c um/arch/um/kernel/tt/ptproxy/proxy.c +--- orig/arch/um/kernel/tt/ptproxy/proxy.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/ptproxy/proxy.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,371 @@ ++/********************************************************************** ++proxy.c ++ ++Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing ++terms and conditions. ++ ++Jeff Dike (jdike@karaya.com) : Modified for integration into uml ++**********************************************************************/ ++ ++/* XXX This file shouldn't refer to CONFIG_* */ ++ ++#include <errno.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <unistd.h> ++#include <signal.h> ++#include <string.h> ++#include <termios.h> ++#include <sys/wait.h> ++#include <sys/types.h> ++#include <sys/ptrace.h> ++#include <sys/ioctl.h> ++#include <asm/unistd.h> ++ ++#include "ptproxy.h" ++#include "sysdep.h" ++#include "wait.h" ++ ++#include "user_util.h" ++#include "user.h" ++#include "os.h" ++#include "tempfile.h" ++ ++static int debugger_wait(debugger_state *debugger, int *status, int options, ++ int (*syscall)(debugger_state *debugger, pid_t child), ++ int (*normal_return)(debugger_state *debugger, ++ pid_t unused), ++ int (*wait_return)(debugger_state *debugger, ++ pid_t unused)) ++{ ++ if(debugger->real_wait){ ++ debugger->handle_trace = normal_return; ++ syscall_continue(debugger->pid); ++ debugger->real_wait = 0; ++ return(1); ++ } ++ debugger->wait_status_ptr = status; ++ debugger->wait_options = options; ++ if((debugger->debugee != NULL) && debugger->debugee->event){ ++ syscall_continue(debugger->pid); ++ wait_for_stop(debugger->pid, SIGTRAP, PTRACE_SYSCALL, ++ NULL); ++ (*wait_return)(debugger, -1); ++ return(0); ++ } ++ else if(debugger->wait_options & WNOHANG){ ++ syscall_cancel(debugger->pid, 0); ++ debugger->handle_trace = syscall; ++ return(0); ++ } ++ else { ++ syscall_pause(debugger->pid); ++ debugger->handle_trace = wait_return; ++ debugger->waiting = 1; ++ } ++ return(1); ++} ++ ++/* ++ * Handle debugger trap, i.e. syscall. ++ */ ++ ++int debugger_syscall(debugger_state *debugger, pid_t child) ++{ ++ long arg1, arg2, arg3, arg4, arg5, result; ++ int syscall, ret = 0; ++ ++ syscall = get_syscall(debugger->pid, &arg1, &arg2, &arg3, &arg4, ++ &arg5); ++ ++ switch(syscall){ ++ case __NR_execve: ++ /* execve never returns */ ++ debugger->handle_trace = debugger_syscall; ++ break; ++ ++ case __NR_ptrace: ++ if(debugger->debugee->pid != 0) arg2 = debugger->debugee->pid; ++ if(!debugger->debugee->in_context) ++ child = debugger->debugee->pid; ++ result = proxy_ptrace(debugger, arg1, arg2, arg3, arg4, child, ++ &ret); ++ syscall_cancel(debugger->pid, result); ++ debugger->handle_trace = debugger_syscall; ++ return(ret); ++ ++ case __NR_waitpid: ++ case __NR_wait4: ++ if(!debugger_wait(debugger, (int *) arg2, arg3, ++ debugger_syscall, debugger_normal_return, ++ proxy_wait_return)) ++ return(0); ++ break; ++ ++ case __NR_kill: ++ if(!debugger->debugee->in_context) ++ child = debugger->debugee->pid; ++ if(arg1 == debugger->debugee->pid){ ++ result = kill(child, arg2); ++ syscall_cancel(debugger->pid, result); ++ debugger->handle_trace = debugger_syscall; ++ return(0); ++ } ++ else debugger->handle_trace = debugger_normal_return; ++ break; ++ ++ default: ++ debugger->handle_trace = debugger_normal_return; ++ } ++ ++ syscall_continue(debugger->pid); ++ return(0); ++} ++ ++/* Used by the tracing thread */ ++static debugger_state parent; ++static int parent_syscall(debugger_state *debugger, int pid); ++ ++int init_parent_proxy(int pid) ++{ ++ parent = ((debugger_state) { .pid = pid, ++ .wait_options = 0, ++ .wait_status_ptr = NULL, ++ .waiting = 0, ++ .real_wait = 0, ++ .expecting_child = 0, ++ .handle_trace = parent_syscall, ++ .debugee = NULL } ); ++ return(0); ++} ++ ++int parent_normal_return(debugger_state *debugger, pid_t unused) ++{ ++ debugger->handle_trace = parent_syscall; ++ syscall_continue(debugger->pid); ++ return(0); ++} ++ ++static int parent_syscall(debugger_state *debugger, int pid) ++{ ++ long arg1, arg2, arg3, arg4, arg5; ++ int syscall; ++ ++ syscall = get_syscall(pid, &arg1, &arg2, &arg3, &arg4, &arg5); ++ ++ if((syscall == __NR_waitpid) || (syscall == __NR_wait4)){ ++ debugger_wait(&parent, (int *) arg2, arg3, parent_syscall, ++ parent_normal_return, parent_wait_return); ++ } ++ else ptrace(PTRACE_SYSCALL, pid, 0, 0); ++ return(0); ++} ++ ++int debugger_normal_return(debugger_state *debugger, pid_t unused) ++{ ++ debugger->handle_trace = debugger_syscall; ++ syscall_continue(debugger->pid); ++ return(0); ++} ++ ++void debugger_cancelled_return(debugger_state *debugger, int result) ++{ ++ debugger->handle_trace = debugger_syscall; ++ syscall_set_result(debugger->pid, result); ++ syscall_continue(debugger->pid); ++} ++ ++/* Used by the tracing thread */ ++static debugger_state debugger; ++static debugee_state debugee; ++ ++void init_proxy (pid_t debugger_pid, int stopped, int status) ++{ ++ debugger.pid = debugger_pid; ++ debugger.handle_trace = debugger_syscall; ++ debugger.debugee = &debugee; ++ debugger.waiting = 0; ++ debugger.real_wait = 0; ++ debugger.expecting_child = 0; ++ ++ debugee.pid = 0; ++ debugee.traced = 0; ++ debugee.stopped = stopped; ++ debugee.event = 0; ++ debugee.zombie = 0; ++ debugee.died = 0; ++ debugee.wait_status = status; ++ debugee.in_context = 1; ++} ++ ++int debugger_proxy(int status, int pid) ++{ ++ int ret = 0, sig; ++ ++ if(WIFSTOPPED(status)){ ++ sig = WSTOPSIG(status); ++ if (sig == SIGTRAP) ++ ret = (*debugger.handle_trace)(&debugger, pid); ++ ++ else if(sig == SIGCHLD){ ++ if(debugger.expecting_child){ ++ ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig); ++ debugger.expecting_child = 0; ++ } ++ else if(debugger.waiting) ++ real_wait_return(&debugger); ++ else { ++ ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig); ++ debugger.real_wait = 1; ++ } ++ } ++ else ptrace(PTRACE_SYSCALL, debugger.pid, 0, sig); ++ } ++ else if(WIFEXITED(status)){ ++ tracer_panic("debugger (pid %d) exited with status %d", ++ debugger.pid, WEXITSTATUS(status)); ++ } ++ else if(WIFSIGNALED(status)){ ++ tracer_panic("debugger (pid %d) exited with signal %d", ++ debugger.pid, WTERMSIG(status)); ++ } ++ else { ++ tracer_panic("proxy got unknown status (0x%x) on debugger " ++ "(pid %d)", status, debugger.pid); ++ } ++ return(ret); ++} ++ ++void child_proxy(pid_t pid, int status) ++{ ++ debugee.event = 1; ++ debugee.wait_status = status; ++ ++ if(WIFSTOPPED(status)){ ++ debugee.stopped = 1; ++ debugger.expecting_child = 1; ++ kill(debugger.pid, SIGCHLD); ++ } ++ else if(WIFEXITED(status) || WIFSIGNALED(status)){ ++ debugee.zombie = 1; ++ debugger.expecting_child = 1; ++ kill(debugger.pid, SIGCHLD); ++ } ++ else panic("proxy got unknown status (0x%x) on child (pid %d)", ++ status, pid); ++} ++ ++void debugger_parent_signal(int status, int pid) ++{ ++ int sig; ++ ++ if(WIFSTOPPED(status)){ ++ sig = WSTOPSIG(status); ++ if(sig == SIGTRAP) (*parent.handle_trace)(&parent, pid); ++ else ptrace(PTRACE_SYSCALL, pid, 0, sig); ++ } ++} ++ ++void fake_child_exit(void) ++{ ++ int status, pid; ++ ++ child_proxy(1, W_EXITCODE(0, 0)); ++ while(debugger.waiting == 1){ ++ pid = waitpid(debugger.pid, &status, WUNTRACED); ++ if(pid != debugger.pid){ ++ printk("fake_child_exit - waitpid failed, " ++ "errno = %d\n", errno); ++ return; ++ } ++ debugger_proxy(status, debugger.pid); ++ } ++ pid = waitpid(debugger.pid, &status, WUNTRACED); ++ if(pid != debugger.pid){ ++ printk("fake_child_exit - waitpid failed, " ++ "errno = %d\n", errno); ++ return; ++ } ++ if(ptrace(PTRACE_DETACH, debugger.pid, 0, SIGCONT) < 0) ++ printk("fake_child_exit - PTRACE_DETACH failed, errno = %d\n", ++ errno); ++} ++ ++char gdb_init_string[] = ++"att 1 \n\ ++b panic \n\ ++b stop \n\ ++handle SIGWINCH nostop noprint pass \n\ ++"; ++ ++int start_debugger(char *prog, int startup, int stop, int *fd_out) ++{ ++ int slave, child; ++ ++ slave = open_gdb_chan(); ++ child = fork(); ++ if(child == 0){ ++ char *tempname = NULL; ++ int fd; ++ ++ if(setsid() < 0) perror("setsid"); ++ if((dup2(slave, 0) < 0) || (dup2(slave, 1) < 0) || ++ (dup2(slave, 2) < 0)){ ++ printk("start_debugger : dup2 failed, errno = %d\n", ++ errno); ++ exit(1); ++ } ++ if(ioctl(0, TIOCSCTTY, 0) < 0){ ++ printk("start_debugger : TIOCSCTTY failed, " ++ "errno = %d\n", errno); ++ exit(1); ++ } ++ if(tcsetpgrp (1, os_getpid()) < 0){ ++ printk("start_debugger : tcsetpgrp failed, " ++ "errno = %d\n", errno); ++#ifdef notdef ++ exit(1); ++#endif ++ } ++ fd = make_tempfile("/tmp/gdb_init-XXXXXX", &tempname, 0); ++ if(fd < 0){ ++ printk("start_debugger : make_tempfile failed," ++ "err = %d\n", -fd); ++ exit(1); ++ } ++ os_write_file(fd, gdb_init_string, sizeof(gdb_init_string) - 1); ++ if(startup){ ++ if(stop){ ++ os_write_file(fd, "b start_kernel\n", ++ strlen("b start_kernel\n")); ++ } ++ os_write_file(fd, "c\n", strlen("c\n")); ++ } ++ if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0){ ++ printk("start_debugger : PTRACE_TRACEME failed, " ++ "errno = %d\n", errno); ++ exit(1); ++ } ++ execlp("gdb", "gdb", "--command", tempname, prog, NULL); ++ printk("start_debugger : exec of gdb failed, errno = %d\n", ++ errno); ++ } ++ if(child < 0){ ++ printk("start_debugger : fork for gdb failed, errno = %d\n", ++ errno); ++ return(-1); ++ } ++ *fd_out = slave; ++ return(child); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/ptproxy/ptproxy.h um/arch/um/kernel/tt/ptproxy/ptproxy.h +--- orig/arch/um/kernel/tt/ptproxy/ptproxy.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/ptproxy/ptproxy.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,61 @@ ++/********************************************************************** ++ptproxy.h ++ ++Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing ++terms and conditions. ++**********************************************************************/ ++ ++#ifndef __PTPROXY_H ++#define __PTPROXY_H ++ ++#include <sys/types.h> ++ ++typedef struct debugger debugger_state; ++typedef struct debugee debugee_state; ++ ++struct debugger ++{ ++ pid_t pid; ++ int wait_options; ++ int *wait_status_ptr; ++ unsigned int waiting : 1; ++ unsigned int real_wait : 1; ++ unsigned int expecting_child : 1; ++ int (*handle_trace) (debugger_state *, pid_t); ++ ++ debugee_state *debugee; ++}; ++ ++struct debugee ++{ ++ pid_t pid; ++ int wait_status; ++ unsigned int died : 1; ++ unsigned int event : 1; ++ unsigned int stopped : 1; ++ unsigned int trace_singlestep : 1; ++ unsigned int trace_syscall : 1; ++ unsigned int traced : 1; ++ unsigned int zombie : 1; ++ unsigned int in_context : 1; ++}; ++ ++extern int debugger_syscall(debugger_state *debugger, pid_t pid); ++extern int debugger_normal_return (debugger_state *debugger, pid_t unused); ++ ++extern long proxy_ptrace (struct debugger *, int, pid_t, long, long, pid_t, ++ int *strace_out); ++extern void debugger_cancelled_return(debugger_state *debugger, int result); ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/ptproxy/ptrace.c um/arch/um/kernel/tt/ptproxy/ptrace.c +--- orig/arch/um/kernel/tt/ptproxy/ptrace.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/ptproxy/ptrace.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,239 @@ ++/********************************************************************** ++ptrace.c ++ ++Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing ++terms and conditions. ++ ++Jeff Dike (jdike@karaya.com) : Modified for integration into uml ++**********************************************************************/ ++ ++#include <errno.h> ++#include <unistd.h> ++#include <signal.h> ++#include <sys/types.h> ++#include <sys/time.h> ++#include <sys/ptrace.h> ++#include <sys/wait.h> ++#include <asm/ptrace.h> ++ ++#include "ptproxy.h" ++#include "debug.h" ++#include "user_util.h" ++#include "kern_util.h" ++#include "ptrace_user.h" ++#include "tt.h" ++ ++long proxy_ptrace(struct debugger *debugger, int arg1, pid_t arg2, ++ long arg3, long arg4, pid_t child, int *ret) ++{ ++ sigset_t relay; ++ long result; ++ int status; ++ ++ *ret = 0; ++ if(debugger->debugee->died) return(-ESRCH); ++ ++ switch(arg1){ ++ case PTRACE_ATTACH: ++ if(debugger->debugee->traced) return(-EPERM); ++ ++ debugger->debugee->pid = arg2; ++ debugger->debugee->traced = 1; ++ ++ if(is_valid_pid(arg2) && (arg2 != child)){ ++ debugger->debugee->in_context = 0; ++ kill(arg2, SIGSTOP); ++ debugger->debugee->event = 1; ++ debugger->debugee->wait_status = W_STOPCODE(SIGSTOP); ++ } ++ else { ++ debugger->debugee->in_context = 1; ++ if(debugger->debugee->stopped) ++ child_proxy(child, W_STOPCODE(SIGSTOP)); ++ else kill(child, SIGSTOP); ++ } ++ ++ return(0); ++ ++ case PTRACE_DETACH: ++ if(!debugger->debugee->traced) return(-EPERM); ++ ++ debugger->debugee->traced = 0; ++ debugger->debugee->pid = 0; ++ if(!debugger->debugee->in_context) ++ kill(child, SIGCONT); ++ ++ return(0); ++ ++ case PTRACE_CONT: ++ if(!debugger->debugee->in_context) return(-EPERM); ++ *ret = PTRACE_CONT; ++ return(ptrace(PTRACE_CONT, child, arg3, arg4)); ++ ++#ifdef UM_HAVE_GETFPREGS ++ case PTRACE_GETFPREGS: ++ { ++ long regs[FP_FRAME_SIZE]; ++ int i, result; ++ ++ result = ptrace(PTRACE_GETFPREGS, child, 0, regs); ++ if(result == -1) return(-errno); ++ ++ for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) ++ ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i, ++ regs[i]); ++ return(result); ++ } ++#endif ++ ++#ifdef UM_HAVE_GETFPXREGS ++ case PTRACE_GETFPXREGS: ++ { ++ long regs[FPX_FRAME_SIZE]; ++ int i, result; ++ ++ result = ptrace(PTRACE_GETFPXREGS, child, 0, regs); ++ if(result == -1) return(-errno); ++ ++ for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) ++ ptrace(PTRACE_POKEDATA, debugger->pid, arg4 + 4 * i, ++ regs[i]); ++ return(result); ++ } ++#endif ++ ++#ifdef UM_HAVE_GETREGS ++ case PTRACE_GETREGS: ++ { ++ long regs[FRAME_SIZE]; ++ int i, result; ++ ++ result = ptrace(PTRACE_GETREGS, child, 0, regs); ++ if(result == -1) return(-errno); ++ ++ for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) ++ ptrace (PTRACE_POKEDATA, debugger->pid, ++ arg4 + 4 * i, regs[i]); ++ return(result); ++ } ++ break; ++#endif ++ ++ case PTRACE_KILL: ++ result = ptrace(PTRACE_KILL, child, arg3, arg4); ++ if(result == -1) return(-errno); ++ ++ return(result); ++ ++ case PTRACE_PEEKDATA: ++ case PTRACE_PEEKTEXT: ++ case PTRACE_PEEKUSER: ++ /* The value being read out could be -1, so we have to ++ * check errno to see if there's an error, and zero it ++ * beforehand so we're not faked out by an old error ++ */ ++ ++ errno = 0; ++ result = ptrace(arg1, child, arg3, 0); ++ if((result == -1) && (errno != 0)) return(-errno); ++ ++ result = ptrace(PTRACE_POKEDATA, debugger->pid, arg4, result); ++ if(result == -1) return(-errno); ++ ++ return(result); ++ ++ case PTRACE_POKEDATA: ++ case PTRACE_POKETEXT: ++ case PTRACE_POKEUSER: ++ result = ptrace(arg1, child, arg3, arg4); ++ if(result == -1) return(-errno); ++ ++ if(arg1 == PTRACE_POKEUSER) ptrace_pokeuser(arg3, arg4); ++ return(result); ++ ++#ifdef UM_HAVE_SETFPREGS ++ case PTRACE_SETFPREGS: ++ { ++ long regs[FP_FRAME_SIZE]; ++ int i; ++ ++ for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) ++ regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid, ++ arg4 + 4 * i, 0); ++ result = ptrace(PTRACE_SETFPREGS, child, 0, regs); ++ if(result == -1) return(-errno); ++ ++ return(result); ++ } ++#endif ++ ++#ifdef UM_HAVE_SETFPXREGS ++ case PTRACE_SETFPXREGS: ++ { ++ long regs[FPX_FRAME_SIZE]; ++ int i; ++ ++ for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) ++ regs[i] = ptrace (PTRACE_PEEKDATA, debugger->pid, ++ arg4 + 4 * i, 0); ++ result = ptrace(PTRACE_SETFPXREGS, child, 0, regs); ++ if(result == -1) return(-errno); ++ ++ return(result); ++ } ++#endif ++ ++#ifdef UM_HAVE_SETREGS ++ case PTRACE_SETREGS: ++ { ++ long regs[FRAME_SIZE]; ++ int i; ++ ++ for (i = 0; i < sizeof(regs)/sizeof(regs[0]); i++) ++ regs[i] = ptrace(PTRACE_PEEKDATA, debugger->pid, ++ arg4 + 4 * i, 0); ++ result = ptrace(PTRACE_SETREGS, child, 0, regs); ++ if(result == -1) return(-errno); ++ ++ return(result); ++ } ++#endif ++ ++ case PTRACE_SINGLESTEP: ++ if(!debugger->debugee->in_context) return(-EPERM); ++ sigemptyset(&relay); ++ sigaddset(&relay, SIGSEGV); ++ sigaddset(&relay, SIGILL); ++ sigaddset(&relay, SIGBUS); ++ result = ptrace(PTRACE_SINGLESTEP, child, arg3, arg4); ++ if(result == -1) return(-errno); ++ ++ status = wait_for_stop(child, SIGTRAP, PTRACE_SINGLESTEP, ++ &relay); ++ child_proxy(child, status); ++ return(result); ++ ++ case PTRACE_SYSCALL: ++ if(!debugger->debugee->in_context) return(-EPERM); ++ result = ptrace(PTRACE_SYSCALL, child, arg3, arg4); ++ if(result == -1) return(-errno); ++ ++ *ret = PTRACE_SYSCALL; ++ return(result); ++ ++ case PTRACE_TRACEME: ++ default: ++ return(-EINVAL); ++ } ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/ptproxy/sysdep.c um/arch/um/kernel/tt/ptproxy/sysdep.c +--- orig/arch/um/kernel/tt/ptproxy/sysdep.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/ptproxy/sysdep.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,72 @@ ++/********************************************************************** ++sysdep.c ++ ++Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing ++terms and conditions. ++**********************************************************************/ ++ ++#include <stdio.h> ++#include <string.h> ++#include <stdlib.h> ++#include <signal.h> ++#include <errno.h> ++#include <sys/types.h> ++#include <sys/ptrace.h> ++#include <asm/ptrace.h> ++#include <linux/unistd.h> ++#include "ptrace_user.h" ++#include "user_util.h" ++#include "user.h" ++ ++int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, long *arg4, ++ long *arg5) ++{ ++ *arg1 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG1_OFFSET, 0); ++ *arg2 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG2_OFFSET, 0); ++ *arg3 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG3_OFFSET, 0); ++ *arg4 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG4_OFFSET, 0); ++ *arg5 = ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_ARG5_OFFSET, 0); ++ return(ptrace(PTRACE_PEEKUSER, pid, PT_SYSCALL_NR_OFFSET, 0)); ++} ++ ++void syscall_cancel(pid_t pid, int result) ++{ ++ if((ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, ++ __NR_getpid) < 0) || ++ (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) || ++ (wait_for_stop(pid, SIGTRAP, PTRACE_SYSCALL, NULL) < 0) || ++ (ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, result) < 0) || ++ (ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)) ++ printk("ptproxy: couldn't cancel syscall: errno = %d\n", ++ errno); ++} ++ ++void syscall_set_result(pid_t pid, long result) ++{ ++ ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_RET_OFFSET, result); ++} ++ ++void syscall_continue(pid_t pid) ++{ ++ ptrace(PTRACE_SYSCALL, pid, 0, 0); ++} ++ ++int syscall_pause(pid_t pid) ++{ ++ if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, __NR_pause) < 0){ ++ printk("syscall_change - ptrace failed, errno = %d\n", errno); ++ return(-1); ++ } ++ return(0); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/ptproxy/sysdep.h um/arch/um/kernel/tt/ptproxy/sysdep.h +--- orig/arch/um/kernel/tt/ptproxy/sysdep.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/ptproxy/sysdep.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,25 @@ ++/********************************************************************** ++sysdep.h ++ ++Copyright (C) 1999 Lars Brinkhoff. ++Copyright (C) 2001 Jeff Dike (jdike@karaya.com) ++See the file COPYING for licensing terms and conditions. ++**********************************************************************/ ++ ++extern int get_syscall(pid_t pid, long *arg1, long *arg2, long *arg3, ++ long *arg4, long *arg5); ++extern void syscall_cancel (pid_t pid, long result); ++extern void syscall_set_result (pid_t pid, long result); ++extern void syscall_continue (pid_t pid); ++extern int syscall_pause(pid_t pid); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/ptproxy/wait.c um/arch/um/kernel/tt/ptproxy/wait.c +--- orig/arch/um/kernel/tt/ptproxy/wait.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/ptproxy/wait.c 2003-10-21 03:26:07.000000000 -0400 +@@ -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 = IP_RESTART_SYSCALL(ip); ++ ++ if(ptrace(PTRACE_POKEUSER, pid, PT_IP_OFFSET, ip) < 0) ++ tracer_panic("real_wait_return : Failed to restart system " ++ "call, errno = %d\n", errno); ++ ++ if((ptrace(PTRACE_SYSCALL, debugger->pid, 0, SIGCHLD) < 0) || ++ (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) || ++ (ptrace(PTRACE_SYSCALL, debugger->pid, 0, 0) < 0) || ++ debugger_normal_return(debugger, -1)) ++ tracer_panic("real_wait_return : gdb failed to wait, " ++ "errno = %d\n", errno); ++ return(0); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/ptproxy/wait.h um/arch/um/kernel/tt/ptproxy/wait.h +--- orig/arch/um/kernel/tt/ptproxy/wait.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/ptproxy/wait.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,15 @@ ++/********************************************************************** ++wait.h ++ ++Copyright (C) 1999 Lars Brinkhoff. See the file COPYING for licensing ++terms and conditions. ++**********************************************************************/ ++ ++#ifndef __PTPROXY_WAIT_H ++#define __PTPROXY_WAIT_H ++ ++extern int proxy_wait_return(struct debugger *debugger, pid_t unused); ++extern int real_wait_return(struct debugger *debugger); ++extern int parent_wait_return(struct debugger *debugger, pid_t unused); ++ ++#endif +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/syscall_kern.c um/arch/um/kernel/tt/syscall_kern.c +--- orig/arch/um/kernel/tt/syscall_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/syscall_kern.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,142 @@ ++/* ++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/types.h" ++#include "linux/utime.h" ++#include "linux/sys.h" ++#include "asm/unistd.h" ++#include "asm/ptrace.h" ++#include "asm/uaccess.h" ++#include "sysdep/syscalls.h" ++#include "kern_util.h" ++ ++static inline int check_area(void *ptr, int size) ++{ ++ return(verify_area(VERIFY_WRITE, ptr, size)); ++} ++ ++static int check_readlink(struct pt_regs *regs) ++{ ++ return(check_area((void *) UPT_SYSCALL_ARG1(®s->regs), ++ UPT_SYSCALL_ARG2(®s->regs))); ++} ++ ++static int check_utime(struct pt_regs *regs) ++{ ++ return(check_area((void *) UPT_SYSCALL_ARG1(®s->regs), ++ sizeof(struct utimbuf))); ++} ++ ++static int check_oldstat(struct pt_regs *regs) ++{ ++ return(check_area((void *) UPT_SYSCALL_ARG1(®s->regs), ++ sizeof(struct __old_kernel_stat))); ++} ++ ++static int check_stat(struct pt_regs *regs) ++{ ++ return(check_area((void *) UPT_SYSCALL_ARG1(®s->regs), ++ sizeof(struct stat))); ++} ++ ++static int check_stat64(struct pt_regs *regs) ++{ ++ return(check_area((void *) UPT_SYSCALL_ARG1(®s->regs), ++ sizeof(struct stat64))); ++} ++ ++struct bogus { ++ int kernel_ds; ++ int (*check_params)(struct pt_regs *); ++}; ++ ++struct bogus this_is_bogus[256] = { ++ [ __NR_mknod ] = { 1, NULL }, ++ [ __NR_mkdir ] = { 1, NULL }, ++ [ __NR_rmdir ] = { 1, NULL }, ++ [ __NR_unlink ] = { 1, NULL }, ++ [ __NR_symlink ] = { 1, NULL }, ++ [ __NR_link ] = { 1, NULL }, ++ [ __NR_rename ] = { 1, NULL }, ++ [ __NR_umount ] = { 1, NULL }, ++ [ __NR_mount ] = { 1, NULL }, ++ [ __NR_pivot_root ] = { 1, NULL }, ++ [ __NR_chdir ] = { 1, NULL }, ++ [ __NR_chroot ] = { 1, NULL }, ++ [ __NR_open ] = { 1, NULL }, ++ [ __NR_quotactl ] = { 1, NULL }, ++ [ __NR_sysfs ] = { 1, NULL }, ++ [ __NR_readlink ] = { 1, check_readlink }, ++ [ __NR_acct ] = { 1, NULL }, ++ [ __NR_execve ] = { 1, NULL }, ++ [ __NR_uselib ] = { 1, NULL }, ++ [ __NR_statfs ] = { 1, NULL }, ++ [ __NR_truncate ] = { 1, NULL }, ++ [ __NR_access ] = { 1, NULL }, ++ [ __NR_chmod ] = { 1, NULL }, ++ [ __NR_chown ] = { 1, NULL }, ++ [ __NR_lchown ] = { 1, NULL }, ++ [ __NR_utime ] = { 1, check_utime }, ++ [ __NR_oldlstat ] = { 1, check_oldstat }, ++ [ __NR_oldstat ] = { 1, check_oldstat }, ++ [ __NR_stat ] = { 1, check_stat }, ++ [ __NR_lstat ] = { 1, check_stat }, ++ [ __NR_stat64 ] = { 1, check_stat64 }, ++ [ __NR_lstat64 ] = { 1, check_stat64 }, ++ [ __NR_chown32 ] = { 1, NULL }, ++}; ++ ++/* sys_utimes */ ++ ++static int check_bogosity(struct pt_regs *regs) ++{ ++ struct bogus *bogon = &this_is_bogus[UPT_SYSCALL_NR(®s->regs)]; ++ ++ if(!bogon->kernel_ds) return(0); ++ if(bogon->check_params && (*bogon->check_params)(regs)) ++ return(-EFAULT); ++ set_fs(KERNEL_DS); ++ return(0); ++} ++ ++extern syscall_handler_t *sys_call_table[]; ++ ++long execute_syscall_tt(void *r) ++{ ++ struct pt_regs *regs = r; ++ long res; ++ int syscall; ++ ++ current->thread.nsyscalls++; ++ nsyscalls++; ++ syscall = UPT_SYSCALL_NR(®s->regs); ++ ++ if((syscall >= NR_syscalls) || (syscall < 0)) ++ res = -ENOSYS; ++ else if(honeypot && check_bogosity(regs)) ++ res = -EFAULT; ++ else res = EXECUTE_SYSCALL(syscall, regs); ++ ++ set_fs(USER_DS); ++ ++ if(current->thread.mode.tt.singlestep_syscall){ ++ current->thread.mode.tt.singlestep_syscall = 0; ++ current->ptrace &= ~PT_DTRACE; ++ force_sig(SIGTRAP, current); ++ } ++ ++ return(res); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/syscall_user.c um/arch/um/kernel/tt/syscall_user.c +--- orig/arch/um/kernel/tt/syscall_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/syscall_user.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,89 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <unistd.h> ++#include <signal.h> ++#include <errno.h> ++#include <sys/ptrace.h> ++#include <asm/unistd.h> ++#include "sysdep/ptrace.h" ++#include "sigcontext.h" ++#include "ptrace_user.h" ++#include "task.h" ++#include "user_util.h" ++#include "kern_util.h" ++#include "syscall_user.h" ++#include "tt.h" ++ ++/* XXX Bogus */ ++#define ERESTARTSYS 512 ++#define ERESTARTNOINTR 513 ++#define ERESTARTNOHAND 514 ++ ++void syscall_handler_tt(int sig, union uml_pt_regs *regs) ++{ ++ void *sc; ++ long result; ++ int index, syscall; ++ ++ syscall = UPT_SYSCALL_NR(regs); ++ sc = UPT_SC(regs); ++ SC_START_SYSCALL(sc); ++ ++ index = record_syscall_start(syscall); ++ syscall_trace(); ++ result = execute_syscall(regs); ++ ++ /* regs->sc may have changed while the system call ran (there may ++ * have been an interrupt or segfault), so it needs to be refreshed. ++ */ ++ UPT_SC(regs) = sc; ++ ++ SC_SET_SYSCALL_RETURN(sc, result); ++ if((result == -ERESTARTNOHAND) || (result == -ERESTARTSYS) || ++ (result == -ERESTARTNOINTR)) ++ do_signal(result); ++ ++ syscall_trace(); ++ record_syscall_end(index, result); ++} ++ ++int do_syscall(void *task, int pid) ++{ ++ unsigned long proc_regs[FRAME_SIZE]; ++ union uml_pt_regs *regs; ++ int syscall; ++ ++ if(ptrace_getregs(pid, proc_regs) < 0) ++ tracer_panic("Couldn't read registers"); ++ syscall = PT_SYSCALL_NR(proc_regs); ++ ++ regs = TASK_REGS(task); ++ UPT_SYSCALL_NR(regs) = syscall; ++ ++ if(syscall < 1) return(0); ++ ++ if((syscall != __NR_sigreturn) && ++ ((unsigned long *) PT_IP(proc_regs) >= &_stext) && ++ ((unsigned long *) PT_IP(proc_regs) <= &_etext)) ++ tracer_panic("I'm tracing myself and I can't get out"); ++ ++ if(ptrace(PTRACE_POKEUSER, pid, PT_SYSCALL_NR_OFFSET, ++ __NR_getpid) < 0) ++ tracer_panic("do_syscall : Nullifying syscall failed, " ++ "errno = %d", errno); ++ return(1); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/sys-i386/Makefile um/arch/um/kernel/tt/sys-i386/Makefile +--- orig/arch/um/kernel/tt/sys-i386/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/sys-i386/Makefile 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,17 @@ ++# ++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++# Licensed under the GPL ++# ++ ++O_TARGET = sys-i386.o ++ ++obj-y = sigcontext.o ++ ++USER_OBJS = sigcontext.o ++ ++include $(TOPDIR)/Rules.make ++ ++$(USER_OBJS) : %.o: %.c ++ $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< ++ ++clean : +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/sys-i386/sigcontext.c um/arch/um/kernel/tt/sys-i386/sigcontext.c +--- orig/arch/um/kernel/tt/sys-i386/sigcontext.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/sys-i386/sigcontext.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,60 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdlib.h> ++#include <asm/sigcontext.h> ++#include "kern_util.h" ++#include "sysdep/frame.h" ++ ++int copy_sc_from_user_tt(void *to_ptr, void *from_ptr, void *data) ++{ ++ struct arch_frame_data *arch = data; ++ struct sigcontext *to = to_ptr, *from = from_ptr; ++ struct _fpstate *to_fp, *from_fp; ++ unsigned long sigs; ++ int err; ++ ++ to_fp = to->fpstate; ++ from_fp = from->fpstate; ++ sigs = to->oldmask; ++ err = copy_from_user_proc(to, from, sizeof(*to)); ++ to->oldmask = sigs; ++ if(to_fp != NULL){ ++ err |= copy_from_user_proc(&to->fpstate, &to_fp, ++ sizeof(to->fpstate)); ++ err |= copy_from_user_proc(to_fp, from_fp, arch->fpstate_size); ++ } ++ return(err); ++} ++ ++int copy_sc_to_user_tt(void *to_ptr, void *fp, void *from_ptr, void *data) ++{ ++ struct arch_frame_data *arch = data; ++ struct sigcontext *to = to_ptr, *from = from_ptr; ++ struct _fpstate *to_fp, *from_fp; ++ int err; ++ ++ to_fp = (struct _fpstate *) ++ (fp ? (unsigned long) fp : ((unsigned long) to + sizeof(*to))); ++ from_fp = from->fpstate; ++ err = copy_to_user_proc(to, from, sizeof(*to)); ++ if(from_fp != NULL){ ++ err |= copy_to_user_proc(&to->fpstate, &to_fp, ++ sizeof(to->fpstate)); ++ err |= copy_to_user_proc(to_fp, from_fp, arch->fpstate_size); ++ } ++ return(err); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/time.c um/arch/um/kernel/tt/time.c +--- orig/arch/um/kernel/tt/time.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/time.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,28 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <signal.h> ++#include <sys/time.h> ++#include <time_user.h> ++#include "process.h" ++#include "user.h" ++ ++void user_time_init_tt(void) ++{ ++ if(signal(SIGVTALRM, (__sighandler_t) alarm_handler) == SIG_ERR) ++ panic("Couldn't set SIGVTALRM handler"); ++ set_interval(ITIMER_VIRTUAL); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/tlb.c um/arch/um/kernel/tt/tlb.c +--- orig/arch/um/kernel/tt/tlb.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/tlb.c 2003-11-13 00:40:57.000000000 -0500 +@@ -0,0 +1,220 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/stddef.h" ++#include "linux/kernel.h" ++#include "linux/sched.h" ++#include "asm/page.h" ++#include "asm/pgtable.h" ++#include "asm/uaccess.h" ++#include "user_util.h" ++#include "mem_user.h" ++#include "os.h" ++ ++static void fix_range(struct mm_struct *mm, unsigned long start_addr, ++ unsigned long end_addr, int force) ++{ ++ pgd_t *npgd; ++ pmd_t *npmd; ++ pte_t *npte; ++ unsigned long addr; ++ int r, w, x, err; ++ ++ if((current->thread.mode.tt.extern_pid != -1) && ++ (current->thread.mode.tt.extern_pid != os_getpid())) ++ panic("fix_range fixing wrong address space, current = 0x%p", ++ current); ++ if(mm == NULL) return; ++ for(addr=start_addr;addr<end_addr;){ ++ if(addr == TASK_SIZE){ ++ /* Skip over kernel text, kernel data, and physical ++ * memory, which don't have ptes, plus kernel virtual ++ * memory, which is flushed separately, and remap ++ * the process stack. The only way to get here is ++ * if (end_addr == STACK_TOP) > TASK_SIZE, which is ++ * only true in the honeypot case. ++ */ ++ addr = STACK_TOP - ABOVE_KMEM; ++ continue; ++ } ++ npgd = pgd_offset(mm, addr); ++ npmd = pmd_offset(npgd, addr); ++ if(pmd_present(*npmd)){ ++ npte = pte_offset(npmd, addr); ++ r = pte_read(*npte); ++ w = pte_write(*npte); ++ x = pte_exec(*npte); ++ if(!pte_dirty(*npte)) w = 0; ++ if(!pte_young(*npte)){ ++ r = 0; ++ w = 0; ++ } ++ if(force || pte_newpage(*npte)){ ++ err = os_unmap_memory((void *) addr, ++ PAGE_SIZE); ++ if(err < 0) ++ panic("munmap failed, errno = %d\n", ++ -err); ++ if(pte_present(*npte)) ++ map_memory(addr, ++ pte_val(*npte) & PAGE_MASK, ++ PAGE_SIZE, r, w, x); ++ } ++ else if(pte_newprot(*npte)){ ++ protect_memory(addr, PAGE_SIZE, r, w, x, 1); ++ } ++ *npte = pte_mkuptodate(*npte); ++ addr += PAGE_SIZE; ++ } ++ else { ++ if(force || pmd_newpage(*npmd)){ ++ err = os_unmap_memory((void *) addr, PMD_SIZE); ++ if(err < 0) ++ panic("munmap failed, errno = %d\n", ++ -err); ++ pmd_mkuptodate(*npmd); ++ } ++ addr += PMD_SIZE; ++ } ++ } ++} ++ ++atomic_t vmchange_seq = ATOMIC_INIT(1); ++ ++static void flush_kernel_vm_range(unsigned long start, unsigned long end, ++ int update_seq) ++{ ++ struct mm_struct *mm; ++ pgd_t *pgd; ++ pmd_t *pmd; ++ pte_t *pte; ++ unsigned long addr; ++ int updated = 0, err; ++ ++ mm = &init_mm; ++ for(addr = start; addr < end;){ ++ pgd = pgd_offset(mm, addr); ++ pmd = pmd_offset(pgd, addr); ++ if(pmd_present(*pmd)){ ++ pte = pte_offset(pmd, addr); ++ if(!pte_present(*pte) || pte_newpage(*pte)){ ++ updated = 1; ++ err = os_unmap_memory((void *) addr, ++ PAGE_SIZE); ++ if(err < 0) ++ panic("munmap failed, errno = %d\n", ++ -err); ++ if(pte_present(*pte)) ++ map_memory(addr, ++ pte_val(*pte) & PAGE_MASK, ++ PAGE_SIZE, 1, 1, 1); ++ } ++ else if(pte_newprot(*pte)){ ++ updated = 1; ++ protect_memory(addr, PAGE_SIZE, 1, 1, 1, 1); ++ } ++ addr += PAGE_SIZE; ++ } ++ else { ++ if(pmd_newpage(*pmd)){ ++ updated = 1; ++ err = os_unmap_memory((void *) addr, PMD_SIZE); ++ if(err < 0) ++ panic("munmap failed, errno = %d\n", ++ -err); ++ } ++ addr += PMD_SIZE; ++ } ++ } ++ if(updated && update_seq) atomic_inc(&vmchange_seq); ++} ++ ++static void protect_vm_page(unsigned long addr, int w, int must_succeed) ++{ ++ int err; ++ ++ err = protect_memory(addr, PAGE_SIZE, 1, w, 1, must_succeed); ++ if(err == 0) return; ++ else if((err == -EFAULT) || (err == -ENOMEM)){ ++ flush_kernel_vm_range(addr, addr + PAGE_SIZE, 1); ++ protect_vm_page(addr, w, 1); ++ } ++ else panic("protect_vm_page : protect failed, errno = %d\n", err); ++} ++ ++void mprotect_kernel_vm(int w) ++{ ++ struct mm_struct *mm; ++ pgd_t *pgd; ++ pmd_t *pmd; ++ pte_t *pte; ++ unsigned long addr; ++ ++ mm = &init_mm; ++ for(addr = start_vm; addr < end_vm;){ ++ pgd = pgd_offset(mm, addr); ++ pmd = pmd_offset(pgd, addr); ++ if(pmd_present(*pmd)){ ++ pte = pte_offset(pmd, addr); ++ if(pte_present(*pte)) protect_vm_page(addr, w, 0); ++ addr += PAGE_SIZE; ++ } ++ else addr += PMD_SIZE; ++ } ++} ++ ++void flush_tlb_kernel_vm_tt(void) ++{ ++ flush_kernel_vm_range(start_vm, end_vm, 1); ++} ++ ++void __flush_tlb_one_tt(unsigned long addr) ++{ ++ flush_kernel_vm_range(addr, addr + PAGE_SIZE, 1); ++} ++ ++void flush_tlb_range_tt(struct mm_struct *mm, unsigned long start, ++ unsigned long end) ++{ ++ if(mm != current->mm) return; ++ ++ /* Assumes that the range start ... end is entirely within ++ * either process memory or kernel vm ++ */ ++ if((start >= start_vm) && (start < end_vm)) ++ flush_kernel_vm_range(start, end, 1); ++ else fix_range(mm, start, end, 0); ++} ++ ++void flush_tlb_mm_tt(struct mm_struct *mm) ++{ ++ unsigned long seq; ++ ++ if(mm != current->mm) return; ++ ++ fix_range(mm, 0, STACK_TOP, 0); ++ ++ seq = atomic_read(&vmchange_seq); ++ if(current->thread.mode.tt.vm_seq == seq) return; ++ current->thread.mode.tt.vm_seq = seq; ++ flush_kernel_vm_range(start_vm, end_vm, 0); ++} ++ ++void force_flush_all_tt(void) ++{ ++ fix_range(current->mm, 0, STACK_TOP, 1); ++ flush_kernel_vm_range(start_vm, end_vm, 0); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/tracer.c um/arch/um/kernel/tt/tracer.c +--- orig/arch/um/kernel/tt/tracer.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/tracer.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,454 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <stdarg.h> ++#include <unistd.h> ++#include <signal.h> ++#include <errno.h> ++#include <sched.h> ++#include <string.h> ++#include <sys/mman.h> ++#include <sys/ptrace.h> ++#include <sys/time.h> ++#include <sys/wait.h> ++#include "user.h" ++#include "sysdep/ptrace.h" ++#include "sigcontext.h" ++#include "sysdep/sigcontext.h" ++#include "os.h" ++#include "signal_user.h" ++#include "user_util.h" ++#include "mem_user.h" ++#include "process.h" ++#include "kern_util.h" ++#include "frame.h" ++#include "chan_user.h" ++#include "ptrace_user.h" ++#include "mode.h" ++#include "tt.h" ++ ++static int tracer_winch[2]; ++ ++int is_tracer_winch(int pid, int fd, void *data) ++{ ++ if(pid != tracing_pid) ++ return(0); ++ ++ register_winch_irq(tracer_winch[0], fd, -1, data); ++ return(1); ++} ++ ++static void tracer_winch_handler(int sig) ++{ ++ int n; ++ char c = 1; ++ ++ n = os_write_file(tracer_winch[1], &c, sizeof(c)); ++ if(n != sizeof(c)) ++ printk("tracer_winch_handler - write failed, err = %d\n", -n); ++} ++ ++/* Called only by the tracing thread during initialization */ ++ ++static void setup_tracer_winch(void) ++{ ++ int err; ++ ++ err = os_pipe(tracer_winch, 1, 1); ++ if(err < 0){ ++ printk("setup_tracer_winch : os_pipe failed, err = %d\n", -err); ++ return; ++ } ++ signal(SIGWINCH, tracer_winch_handler); ++} ++ ++void attach_process(int pid) ++{ ++ if((ptrace(PTRACE_ATTACH, pid, 0, 0) < 0) || ++ (ptrace(PTRACE_CONT, pid, 0, 0) < 0)) ++ tracer_panic("OP_FORK failed to attach pid"); ++ wait_for_stop(pid, SIGSTOP, PTRACE_CONT, NULL); ++ if(ptrace(PTRACE_CONT, pid, 0, 0) < 0) ++ tracer_panic("OP_FORK failed to continue process"); ++} ++ ++void tracer_panic(char *format, ...) ++{ ++ va_list ap; ++ ++ va_start(ap, format); ++ vprintf(format, ap); ++ printf("\n"); ++ while(1) pause(); ++} ++ ++static void tracer_segv(int sig, struct sigcontext sc) ++{ ++ printf("Tracing thread segfault at address 0x%lx, ip 0x%lx\n", ++ SC_FAULT_ADDR(&sc), SC_IP(&sc)); ++ while(1) ++ pause(); ++} ++ ++/* Changed early in boot, and then only read */ ++int debug = 0; ++int debug_stop = 1; ++int debug_parent = 0; ++int honeypot = 0; ++ ++static int signal_tramp(void *arg) ++{ ++ int (*proc)(void *); ++ ++ if(honeypot && munmap((void *) (host_task_size - 0x10000000), ++ 0x10000000)) ++ panic("Unmapping stack failed"); ++ if(ptrace(PTRACE_TRACEME, 0, 0, 0) < 0) ++ panic("ptrace PTRACE_TRACEME failed"); ++ os_stop_process(os_getpid()); ++ change_sig(SIGWINCH, 0); ++ signal(SIGUSR1, SIG_IGN); ++ change_sig(SIGCHLD, 0); ++ signal(SIGSEGV, (__sighandler_t) sig_handler); ++ set_cmdline("(idle thread)"); ++ set_init_pid(os_getpid()); ++ proc = arg; ++ return((*proc)(NULL)); ++} ++ ++static void sleeping_process_signal(int pid, int sig) ++{ ++ switch(sig){ ++ /* These two result from UML being ^Z-ed and bg-ed. PTRACE_CONT is ++ * right because the process must be in the kernel already. ++ */ ++ case SIGCONT: ++ case SIGTSTP: ++ if(ptrace(PTRACE_CONT, pid, 0, sig) < 0) ++ tracer_panic("sleeping_process_signal : Failed to " ++ "continue pid %d, signal = %d, " ++ "errno = %d\n", pid, sig, errno); ++ break; ++ ++ /* This happens when the debugger (e.g. strace) is doing system call ++ * tracing on the kernel. During a context switch, the current task ++ * will be set to the incoming process and the outgoing process will ++ * hop into write and then read. Since it's not the current process ++ * any more, the trace of those will land here. So, we need to just ++ * PTRACE_SYSCALL it. ++ */ ++ case SIGTRAP: ++ if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0) ++ tracer_panic("sleeping_process_signal : Failed to " ++ "PTRACE_SYSCALL pid %d, errno = %d\n", ++ pid, errno); ++ break; ++ case SIGSTOP: ++ break; ++ default: ++ tracer_panic("sleeping process %d got unexpected " ++ "signal : %d\n", pid, sig); ++ break; ++ } ++} ++ ++/* Accessed only by the tracing thread */ ++int debugger_pid = -1; ++int debugger_parent = -1; ++int debugger_fd = -1; ++int gdb_pid = -1; ++ ++struct { ++ int pid; ++ int signal; ++ unsigned long addr; ++ struct timeval time; ++} signal_record[1024][32]; ++ ++int signal_index[32]; ++int nsignals = 0; ++int debug_trace = 0; ++extern int io_nsignals, io_count, intr_count; ++ ++extern void signal_usr1(int sig); ++ ++int tracing_pid = -1; ++ ++int tracer(int (*init_proc)(void *), void *sp) ++{ ++ void *task = NULL; ++ unsigned long eip = 0; ++ int status, pid = 0, sig = 0, cont_type, tracing = 0, op = 0; ++ int last_index, proc_id = 0, n, err, old_tracing = 0, strace = 0; ++ ++ capture_signal_stack(); ++ signal(SIGPIPE, SIG_IGN); ++ setup_tracer_winch(); ++ tracing_pid = os_getpid(); ++ printf("tracing thread pid = %d\n", tracing_pid); ++ ++ pid = clone(signal_tramp, sp, CLONE_FILES | SIGCHLD, init_proc); ++ n = waitpid(pid, &status, WUNTRACED); ++ if(n < 0){ ++ printf("waitpid on idle thread failed, errno = %d\n", errno); ++ exit(1); ++ } ++ if((ptrace(PTRACE_CONT, pid, 0, 0) < 0)){ ++ printf("Failed to continue idle thread, errno = %d\n", errno); ++ exit(1); ++ } ++ ++ signal(SIGSEGV, (sighandler_t) tracer_segv); ++ signal(SIGUSR1, signal_usr1); ++ if(debug_trace){ ++ printf("Tracing thread pausing to be attached\n"); ++ stop(); ++ } ++ if(debug){ ++ if(gdb_pid != -1) ++ debugger_pid = attach_debugger(pid, gdb_pid, 1); ++ else debugger_pid = init_ptrace_proxy(pid, 1, debug_stop); ++ if(debug_parent){ ++ debugger_parent = os_process_parent(debugger_pid); ++ init_parent_proxy(debugger_parent); ++ err = attach(debugger_parent); ++ if(err){ ++ printf("Failed to attach debugger parent %d, " ++ "errno = %d\n", debugger_parent, -err); ++ debugger_parent = -1; ++ } ++ else { ++ if(ptrace(PTRACE_SYSCALL, debugger_parent, ++ 0, 0) < 0){ ++ printf("Failed to continue debugger " ++ "parent, errno = %d\n", errno); ++ debugger_parent = -1; ++ } ++ } ++ } ++ } ++ set_cmdline("(tracing thread)"); ++ while(1){ ++ pid = waitpid(-1, &status, WUNTRACED); ++ if(pid <= 0){ ++ if(errno != ECHILD){ ++ printf("wait failed - errno = %d\n", errno); ++ } ++ continue; ++ } ++ if(pid == debugger_pid){ ++ int cont = 0; ++ ++ if(WIFEXITED(status) || WIFSIGNALED(status)) ++ debugger_pid = -1; ++ /* XXX Figure out how to deal with gdb and SMP */ ++ else cont = debugger_signal(status, cpu_tasks[0].pid); ++ if(cont == PTRACE_SYSCALL) strace = 1; ++ continue; ++ } ++ else if(pid == debugger_parent){ ++ debugger_parent_signal(status, pid); ++ continue; ++ } ++ nsignals++; ++ if(WIFEXITED(status)) ; ++#ifdef notdef ++ { ++ printf("Child %d exited with status %d\n", pid, ++ WEXITSTATUS(status)); ++ } ++#endif ++ else if(WIFSIGNALED(status)){ ++ sig = WTERMSIG(status); ++ if(sig != 9){ ++ printf("Child %d exited with signal %d\n", pid, ++ sig); ++ } ++ } ++ else if(WIFSTOPPED(status)){ ++ proc_id = pid_to_processor_id(pid); ++ sig = WSTOPSIG(status); ++ if(signal_index[proc_id] == 1024){ ++ signal_index[proc_id] = 0; ++ last_index = 1023; ++ } ++ else last_index = signal_index[proc_id] - 1; ++ if(((sig == SIGPROF) || (sig == SIGVTALRM) || ++ (sig == SIGALRM)) && ++ (signal_record[proc_id][last_index].signal == sig)&& ++ (signal_record[proc_id][last_index].pid == pid)) ++ signal_index[proc_id] = last_index; ++ signal_record[proc_id][signal_index[proc_id]].pid = pid; ++ gettimeofday(&signal_record[proc_id][signal_index[proc_id]].time, NULL); ++ eip = ptrace(PTRACE_PEEKUSER, pid, PT_IP_OFFSET, 0); ++ signal_record[proc_id][signal_index[proc_id]].addr = eip; ++ signal_record[proc_id][signal_index[proc_id]++].signal = sig; ++ ++ if(proc_id == -1){ ++ sleeping_process_signal(pid, sig); ++ continue; ++ } ++ ++ task = cpu_tasks[proc_id].task; ++ tracing = is_tracing(task); ++ old_tracing = tracing; ++ ++ switch(sig){ ++ case SIGUSR1: ++ sig = 0; ++ op = do_proc_op(task, proc_id); ++ switch(op){ ++ case OP_TRACE_ON: ++ arch_leave_kernel(task, pid); ++ tracing = 1; ++ break; ++ case OP_REBOOT: ++ case OP_HALT: ++ unmap_physmem(); ++ kmalloc_ok = 0; ++ ptrace(PTRACE_KILL, pid, 0, 0); ++ return(op == OP_REBOOT); ++ case OP_NONE: ++ printf("Detaching pid %d\n", pid); ++ detach(pid, SIGSTOP); ++ continue; ++ default: ++ break; ++ } ++ /* OP_EXEC switches host processes on us, ++ * we want to continue the new one. ++ */ ++ pid = cpu_tasks[proc_id].pid; ++ break; ++ case SIGTRAP: ++ if(!tracing && (debugger_pid != -1)){ ++ child_signal(pid, status); ++ continue; ++ } ++ tracing = 0; ++ if(do_syscall(task, pid)) sig = SIGUSR2; ++ else clear_singlestep(task); ++ break; ++ case SIGPROF: ++ if(tracing) sig = 0; ++ break; ++ case SIGCHLD: ++ case SIGHUP: ++ sig = 0; ++ break; ++ case SIGSEGV: ++ case SIGIO: ++ case SIGALRM: ++ case SIGVTALRM: ++ case SIGFPE: ++ case SIGBUS: ++ case SIGILL: ++ case SIGWINCH: ++ default: ++ tracing = 0; ++ break; ++ } ++ set_tracing(task, tracing); ++ ++ if(!tracing && old_tracing) ++ arch_enter_kernel(task, pid); ++ ++ if(!tracing && (debugger_pid != -1) && (sig != 0) && ++ (sig != SIGALRM) && (sig != SIGVTALRM) && ++ (sig != SIGSEGV) && (sig != SIGTRAP) && ++ (sig != SIGUSR2) && (sig != SIGIO) && ++ (sig != SIGFPE)){ ++ child_signal(pid, status); ++ continue; ++ } ++ ++ if(tracing){ ++ if(singlestepping_tt(task)) ++ cont_type = PTRACE_SINGLESTEP; ++ else cont_type = PTRACE_SYSCALL; ++ } ++ else cont_type = PTRACE_CONT; ++ ++ if((cont_type == PTRACE_CONT) && ++ (debugger_pid != -1) && strace) ++ cont_type = PTRACE_SYSCALL; ++ ++ if(ptrace(cont_type, pid, 0, sig) != 0){ ++ tracer_panic("ptrace failed to continue " ++ "process - errno = %d\n", ++ errno); ++ } ++ } ++ } ++ return(0); ++} ++ ++static int __init uml_debug_setup(char *line, int *add) ++{ ++ char *next; ++ ++ debug = 1; ++ *add = 0; ++ if(*line != '=') return(0); ++ line++; ++ ++ while(line != NULL){ ++ next = strchr(line, ','); ++ if(next) *next++ = '\0'; ++ ++ if(!strcmp(line, "go")) debug_stop = 0; ++ else if(!strcmp(line, "parent")) debug_parent = 1; ++ else printf("Unknown debug option : '%s'\n", line); ++ ++ line = next; ++ } ++ return(0); ++} ++ ++__uml_setup("debug", uml_debug_setup, ++"debug\n" ++" Starts up the kernel under the control of gdb. See the \n" ++" kernel debugging tutorial and the debugging session pages\n" ++" at http://user-mode-linux.sourceforge.net/ for more information.\n\n" ++); ++ ++static int __init uml_debugtrace_setup(char *line, int *add) ++{ ++ debug_trace = 1; ++ return 0; ++} ++__uml_setup("debugtrace", uml_debugtrace_setup, ++"debugtrace\n" ++" Causes the tracing thread to pause until it is attached by a\n" ++" debugger and continued. This is mostly for debugging crashes\n" ++" early during boot, and should be pretty much obsoleted by\n" ++" the debug switch.\n\n" ++); ++ ++static int __init uml_honeypot_setup(char *line, int *add) ++{ ++ jail_setup("", add); ++ honeypot = 1; ++ return 0; ++} ++__uml_setup("honeypot", uml_honeypot_setup, ++"honeypot\n" ++" This makes UML put process stacks in the same location as they are\n" ++" on the host, allowing expoits such as stack smashes to work against\n" ++" UML. This implies 'jail'.\n\n" ++); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/trap_user.c um/arch/um/kernel/tt/trap_user.c +--- orig/arch/um/kernel/tt/trap_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/trap_user.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,59 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdlib.h> ++#include <errno.h> ++#include <signal.h> ++#include <asm/sigcontext.h> ++#include "sysdep/ptrace.h" ++#include "signal_user.h" ++#include "user_util.h" ++#include "kern_util.h" ++#include "task.h" ++#include "tt.h" ++ ++void sig_handler_common_tt(int sig, void *sc_ptr) ++{ ++ struct sigcontext *sc = sc_ptr; ++ struct tt_regs save_regs, *r; ++ struct signal_info *info; ++ int save_errno = errno, is_user; ++ ++ unprotect_kernel_mem(); ++ ++ r = &TASK_REGS(get_current())->tt; ++ save_regs = *r; ++ is_user = user_context(SC_SP(sc)); ++ r->sc = sc; ++ if(sig != SIGUSR2) ++ r->syscall = -1; ++ ++ change_sig(SIGUSR1, 1); ++ info = &sig_info[sig]; ++ if(!info->is_irq) unblock_signals(); ++ ++ (*info->handler)(sig, (union uml_pt_regs *) r); ++ ++ if(is_user){ ++ interrupt_end(); ++ block_signals(); ++ change_sig(SIGUSR1, 0); ++ set_user_mode(NULL); ++ } ++ *r = save_regs; ++ errno = save_errno; ++ if(is_user) protect_kernel_mem(); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/uaccess.c um/arch/um/kernel/tt/uaccess.c +--- orig/arch/um/kernel/tt/uaccess.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/uaccess.c 2003-11-13 00:12:45.000000000 -0500 +@@ -0,0 +1,73 @@ ++/* ++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/sched.h" ++#include "asm/uaccess.h" ++ ++int copy_from_user_tt(void *to, const void *from, int n) ++{ ++ if(!access_ok_tt(VERIFY_READ, from, n)) ++ return(n); ++ ++ return(__do_copy_from_user(to, from, n, ¤t->thread.fault_addr, ++ ¤t->thread.fault_catcher)); ++} ++ ++int copy_to_user_tt(void *to, const void *from, int n) ++{ ++ if(!access_ok_tt(VERIFY_WRITE, to, n)) ++ return(n); ++ ++ return(__do_copy_to_user(to, from, n, ¤t->thread.fault_addr, ++ ¤t->thread.fault_catcher)); ++} ++ ++int strncpy_from_user_tt(char *dst, const char *src, int count) ++{ ++ int n; ++ ++ if(!access_ok_tt(VERIFY_READ, src, 1)) ++ return(-EFAULT); ++ ++ n = __do_strncpy_from_user(dst, src, count, ++ ¤t->thread.fault_addr, ++ ¤t->thread.fault_catcher); ++ if(n < 0) return(-EFAULT); ++ return(n); ++} ++ ++int __clear_user_tt(void *mem, int len) ++{ ++ return(__do_clear_user(mem, len, ++ ¤t->thread.fault_addr, ++ ¤t->thread.fault_catcher)); ++} ++ ++int clear_user_tt(void *mem, int len) ++{ ++ if(!access_ok_tt(VERIFY_WRITE, mem, len)) ++ return(len); ++ ++ return(__do_clear_user(mem, len, ¤t->thread.fault_addr, ++ ¤t->thread.fault_catcher)); ++} ++ ++int strnlen_user_tt(const void *str, int len) ++{ ++ return(__do_strnlen_user(str, len, ++ ¤t->thread.fault_addr, ++ ¤t->thread.fault_catcher)); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/uaccess_user.c um/arch/um/kernel/tt/uaccess_user.c +--- orig/arch/um/kernel/tt/uaccess_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/uaccess_user.c 2003-11-12 08:51:13.000000000 -0500 +@@ -0,0 +1,98 @@ ++/* ++ * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk) ++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <setjmp.h> ++#include <string.h> ++#include "user_util.h" ++#include "uml_uaccess.h" ++#include "task.h" ++#include "kern_util.h" ++ ++int __do_copy_from_user(void *to, const void *from, int n, ++ void **fault_addr, void **fault_catcher) ++{ ++ struct tt_regs save = TASK_REGS(get_current())->tt; ++ unsigned long fault; ++ int faulted; ++ ++ fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, ++ __do_copy, &faulted); ++ TASK_REGS(get_current())->tt = save; ++ ++ if(!faulted) return(0); ++ else return(n - (fault - (unsigned long) from)); ++} ++ ++static void __do_strncpy(void *dst, const void *src, int count) ++{ ++ strncpy(dst, src, count); ++} ++ ++int __do_strncpy_from_user(char *dst, const char *src, unsigned long count, ++ void **fault_addr, void **fault_catcher) ++{ ++ struct tt_regs save = TASK_REGS(get_current())->tt; ++ unsigned long fault; ++ int faulted; ++ ++ fault = __do_user_copy(dst, src, count, fault_addr, fault_catcher, ++ __do_strncpy, &faulted); ++ TASK_REGS(get_current())->tt = save; ++ ++ if(!faulted) return(strlen(dst)); ++ else return(-1); ++} ++ ++static void __do_clear(void *to, const void *from, int n) ++{ ++ memset(to, 0, n); ++} ++ ++int __do_clear_user(void *mem, unsigned long len, ++ void **fault_addr, void **fault_catcher) ++{ ++ struct tt_regs save = TASK_REGS(get_current())->tt; ++ unsigned long fault; ++ int faulted; ++ ++ fault = __do_user_copy(mem, NULL, len, fault_addr, fault_catcher, ++ __do_clear, &faulted); ++ TASK_REGS(get_current())->tt = save; ++ ++ if(!faulted) return(0); ++ else return(len - (fault - (unsigned long) mem)); ++} ++ ++int __do_strnlen_user(const char *str, unsigned long n, ++ void **fault_addr, void **fault_catcher) ++{ ++ struct tt_regs save = TASK_REGS(get_current())->tt; ++ int ret; ++ unsigned long *faddrp = (unsigned long *)fault_addr; ++ jmp_buf jbuf; ++ ++ *fault_catcher = &jbuf; ++ if(sigsetjmp(jbuf, 1) == 0) ++ ret = strlen(str) + 1; ++ else ret = *faddrp - (unsigned long) str; ++ ++ *fault_addr = NULL; ++ *fault_catcher = NULL; ++ ++ TASK_REGS(get_current())->tt = save; ++ return ret; ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tt/unmap.c um/arch/um/kernel/tt/unmap.c +--- orig/arch/um/kernel/tt/unmap.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tt/unmap.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,31 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <sys/mman.h> ++ ++int switcheroo(int fd, int prot, void *from, void *to, int size) ++{ ++ if(munmap(to, size) < 0){ ++ return(-1); ++ } ++ if(mmap(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) != to){ ++ return(-1); ++ } ++ if(munmap(from, size) < 0){ ++ return(-1); ++ } ++ return(0); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/tty_log.c um/arch/um/kernel/tty_log.c +--- orig/arch/um/kernel/tty_log.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/tty_log.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,228 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) and ++ * geoffrey hing <ghing@net.ohio-state.edu> ++ * Licensed under the GPL ++ */ ++ ++#include <errno.h> ++#include <string.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <unistd.h> ++#include <sys/time.h> ++#include "init.h" ++#include "user.h" ++#include "kern_util.h" ++#include "os.h" ++ ++#define TTY_LOG_DIR "./" ++ ++/* Set early in boot and then unchanged */ ++static char *tty_log_dir = TTY_LOG_DIR; ++static int tty_log_fd = -1; ++ ++#define TTY_LOG_OPEN 1 ++#define TTY_LOG_CLOSE 2 ++#define TTY_LOG_WRITE 3 ++#define TTY_LOG_EXEC 4 ++ ++#define TTY_READ 1 ++#define TTY_WRITE 2 ++ ++struct tty_log_buf { ++ int what; ++ unsigned long tty; ++ int len; ++ int direction; ++ unsigned long sec; ++ unsigned long usec; ++}; ++ ++int open_tty_log(void *tty, void *current_tty) ++{ ++ struct timeval tv; ++ struct tty_log_buf data; ++ char buf[strlen(tty_log_dir) + sizeof("01234567890-01234567\0")]; ++ int fd; ++ ++ gettimeofday(&tv, NULL); ++ if(tty_log_fd != -1){ ++ data = ((struct tty_log_buf) { .what = TTY_LOG_OPEN, ++ .tty = (unsigned long) tty, ++ .len = sizeof(current_tty), ++ .direction = 0, ++ .sec = tv.tv_sec, ++ .usec = tv.tv_usec } ); ++ os_write_file(tty_log_fd, &data, sizeof(data)); ++ os_write_file(tty_log_fd, ¤t_tty, data.len); ++ return(tty_log_fd); ++ } ++ ++ sprintf(buf, "%s/%0u-%0u", tty_log_dir, (unsigned int) tv.tv_sec, ++ (unsigned int) tv.tv_usec); ++ ++ fd = os_open_file(buf, of_append(of_create(of_rdwr(OPENFLAGS()))), ++ 0644); ++ if(fd < 0){ ++ printk("open_tty_log : couldn't open '%s', errno = %d\n", ++ buf, -fd); ++ } ++ return(fd); ++} ++ ++void close_tty_log(int fd, void *tty) ++{ ++ struct tty_log_buf data; ++ struct timeval tv; ++ ++ if(tty_log_fd != -1){ ++ gettimeofday(&tv, NULL); ++ data = ((struct tty_log_buf) { .what = TTY_LOG_CLOSE, ++ .tty = (unsigned long) tty, ++ .len = 0, ++ .direction = 0, ++ .sec = tv.tv_sec, ++ .usec = tv.tv_usec } ); ++ os_write_file(tty_log_fd, &data, sizeof(data)); ++ return; ++ } ++ os_close_file(fd); ++} ++ ++static int log_chunk(int fd, const char *buf, int len) ++{ ++ int total = 0, try, missed, n; ++ char chunk[64]; ++ ++ while(len > 0){ ++ try = (len > sizeof(chunk)) ? sizeof(chunk) : len; ++ missed = copy_from_user_proc(chunk, (char *) buf, try); ++ try -= missed; ++ n = os_write_file(fd, chunk, try); ++ if(n != try) { ++ if(n < 0) ++ return(n); ++ return(-EIO); ++ } ++ if(missed != 0) ++ return(-EFAULT); ++ ++ len -= try; ++ total += try; ++ buf += try; ++ } ++ ++ return(total); ++} ++ ++int write_tty_log(int fd, const char *buf, int len, void *tty, int is_read) ++{ ++ struct timeval tv; ++ struct tty_log_buf data; ++ int direction; ++ ++ if(fd == tty_log_fd){ ++ gettimeofday(&tv, NULL); ++ direction = is_read ? TTY_READ : TTY_WRITE; ++ data = ((struct tty_log_buf) { .what = TTY_LOG_WRITE, ++ .tty = (unsigned long) tty, ++ .len = len, ++ .direction = direction, ++ .sec = tv.tv_sec, ++ .usec = tv.tv_usec } ); ++ os_write_file(tty_log_fd, &data, sizeof(data)); ++ } ++ ++ return(log_chunk(fd, buf, len)); ++} ++ ++void log_exec(char **argv, void *tty) ++{ ++ struct timeval tv; ++ struct tty_log_buf data; ++ char **ptr,*arg; ++ int len; ++ ++ if(tty_log_fd == -1) return; ++ ++ gettimeofday(&tv, NULL); ++ ++ len = 0; ++ for(ptr = argv; ; ptr++){ ++ if(copy_from_user_proc(&arg, ptr, sizeof(arg))) ++ return; ++ if(arg == NULL) break; ++ len += strlen_user_proc(arg); ++ } ++ ++ data = ((struct tty_log_buf) { .what = TTY_LOG_EXEC, ++ .tty = (unsigned long) tty, ++ .len = len, ++ .direction = 0, ++ .sec = tv.tv_sec, ++ .usec = tv.tv_usec } ); ++ os_write_file(tty_log_fd, &data, sizeof(data)); ++ ++ for(ptr = argv; ; ptr++){ ++ if(copy_from_user_proc(&arg, ptr, sizeof(arg))) ++ return; ++ if(arg == NULL) break; ++ log_chunk(tty_log_fd, arg, strlen_user_proc(arg)); ++ } ++} ++ ++extern void register_tty_logger(int (*opener)(void *, void *), ++ int (*writer)(int, const char *, int, ++ void *, int), ++ void (*closer)(int, void *)); ++ ++static int register_logger(void) ++{ ++ register_tty_logger(open_tty_log, write_tty_log, close_tty_log); ++ return(0); ++} ++ ++__uml_initcall(register_logger); ++ ++static int __init set_tty_log_dir(char *name, int *add) ++{ ++ tty_log_dir = name; ++ return 0; ++} ++ ++__uml_setup("tty_log_dir=", set_tty_log_dir, ++"tty_log_dir=<directory>\n" ++" This is used to specify the directory where the logs of all pty\n" ++" data from this UML machine will be written.\n\n" ++); ++ ++static int __init set_tty_log_fd(char *name, int *add) ++{ ++ char *end; ++ ++ tty_log_fd = strtoul(name, &end, 0); ++ if((*end != '\0') || (end == name)){ ++ printf("set_tty_log_fd - strtoul failed on '%s'\n", name); ++ tty_log_fd = -1; ++ } ++ return 0; ++} ++ ++__uml_setup("tty_log_fd=", set_tty_log_fd, ++"tty_log_fd=<fd>\n" ++" This is used to specify a preconfigured file descriptor to which all\n" ++" tty data will be written. Preconfigure the descriptor with something\n" ++" like '10>tty_log tty_log_fd=10'.\n\n" ++); ++ ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/uaccess_user.c um/arch/um/kernel/uaccess_user.c +--- orig/arch/um/kernel/uaccess_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/uaccess_user.c 2003-10-21 03:26:07.000000000 -0400 +@@ -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; ++ ++ jmp_buf jbuf; ++ *fault_catcher = &jbuf; ++ if(sigsetjmp(jbuf, 1) == 0){ ++ (*op)(to, from, n); ++ ret = 0; ++ *faulted_out = 0; ++ } ++ else { ++ ret = *faddrp; ++ *faulted_out = 1; ++ } ++ *fault_addr = NULL; ++ *fault_catcher = NULL; ++ return ret; ++} ++ ++void __do_copy(void *to, const void *from, int n) ++{ ++ memcpy(to, from, n); ++} ++ ++ ++int __do_copy_to_user(void *to, const void *from, int n, ++ void **fault_addr, void **fault_catcher) ++{ ++ unsigned long fault; ++ int faulted; ++ ++ fault = __do_user_copy(to, from, n, fault_addr, fault_catcher, ++ __do_copy, &faulted); ++ if(!faulted) return(0); ++ else return(n - (fault - (unsigned long) to)); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/um_arch.c um/arch/um/kernel/um_arch.c +--- orig/arch/um/kernel/um_arch.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/um_arch.c 2003-12-14 11:19:59.000000000 -0500 +@@ -0,0 +1,432 @@ ++/* ++ * Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/config.h" ++#include "linux/kernel.h" ++#include "linux/sched.h" ++#include "linux/notifier.h" ++#include "linux/mm.h" ++#include "linux/types.h" ++#include "linux/tty.h" ++#include "linux/init.h" ++#include "linux/bootmem.h" ++#include "linux/spinlock.h" ++#include "linux/utsname.h" ++#include "linux/sysrq.h" ++#include "linux/seq_file.h" ++#include "linux/delay.h" ++#include "asm/page.h" ++#include "asm/pgtable.h" ++#include "asm/ptrace.h" ++#include "asm/elf.h" ++#include "asm/user.h" ++#include "ubd_user.h" ++#include "asm/current.h" ++#include "user_util.h" ++#include "kern_util.h" ++#include "kern.h" ++#include "mprot.h" ++#include "mem_user.h" ++#include "mem.h" ++#include "umid.h" ++#include "initrd.h" ++#include "init.h" ++#include "os.h" ++#include "choose-mode.h" ++#include "mode_kern.h" ++#include "mode.h" ++ ++#define DEFAULT_COMMAND_LINE "root=/dev/ubd0" ++ ++struct cpuinfo_um boot_cpu_data = { ++ .loops_per_jiffy = 0, ++ .pgd_quick = NULL, ++ .pmd_quick = NULL, ++ .pte_quick = NULL, ++ .pgtable_cache_sz = 0, ++ .ipi_pipe = { -1, -1 } ++}; ++ ++unsigned long thread_saved_pc(struct thread_struct *thread) ++{ ++ return(os_process_pc(CHOOSE_MODE_PROC(thread_pid_tt, thread_pid_skas, ++ thread))); ++} ++ ++static int show_cpuinfo(struct seq_file *m, void *v) ++{ ++ int index = 0; ++ ++#ifdef CONFIG_SMP ++ index = (struct cpuinfo_um *)v - cpu_data; ++ if (!(cpu_online_map & (1 << index))) ++ return 0; ++#endif ++ ++ seq_printf(m, "processor\t: %d\n", index); ++ seq_printf(m, "vendor_id\t: User Mode Linux\n"); ++ seq_printf(m, "model name\t: UML\n"); ++ seq_printf(m, "mode\t\t: %s\n", CHOOSE_MODE("tt", "skas")); ++ seq_printf(m, "host\t\t: %s\n", host_info); ++ seq_printf(m, "bogomips\t: %lu.%02lu\n\n", ++ loops_per_jiffy/(500000/HZ), ++ (loops_per_jiffy/(5000/HZ)) % 100); ++ ++ return(0); ++} ++ ++static void *c_start(struct seq_file *m, loff_t *pos) ++{ ++ return *pos < NR_CPUS ? cpu_data + *pos : NULL; ++} ++ ++static void *c_next(struct seq_file *m, void *v, loff_t *pos) ++{ ++ ++*pos; ++ return c_start(m, pos); ++} ++ ++static void c_stop(struct seq_file *m, void *v) ++{ ++} ++ ++struct seq_operations cpuinfo_op = { ++ .start = c_start, ++ .next = c_next, ++ .stop = c_stop, ++ .show = show_cpuinfo, ++}; ++ ++pte_t * __bad_pagetable(void) ++{ ++ panic("Someone should implement __bad_pagetable"); ++ return(NULL); ++} ++ ++/* Set in linux_main */ ++unsigned long host_task_size; ++unsigned long task_size; ++unsigned long uml_start; ++ ++/* Set in early boot */ ++unsigned long uml_physmem; ++unsigned long uml_reserved; ++unsigned long start_vm; ++unsigned long end_vm; ++int ncpus = 1; ++ ++#ifdef CONFIG_MODE_TT ++/* Pointer set in linux_main, the array itself is private to each thread, ++ * and changed at address space creation time so this poses no concurrency ++ * problems. ++ */ ++static char *argv1_begin = NULL; ++static char *argv1_end = NULL; ++#endif ++ ++/* Set in early boot */ ++static int have_root __initdata = 0; ++long physmem_size = 32 * 1024 * 1024; ++ ++void set_cmdline(char *cmd) ++{ ++#ifdef CONFIG_MODE_TT ++ char *umid, *ptr; ++ ++ if(CHOOSE_MODE(honeypot, 0)) return; ++ ++ umid = get_umid(1); ++ if(umid != NULL){ ++ snprintf(argv1_begin, ++ (argv1_end - argv1_begin) * sizeof(*ptr), ++ "(%s) ", umid); ++ ptr = &argv1_begin[strlen(argv1_begin)]; ++ } ++ else ptr = argv1_begin; ++ ++ snprintf(ptr, (argv1_end - ptr) * sizeof(*ptr), "[%s]", cmd); ++ memset(argv1_begin + strlen(argv1_begin), '\0', ++ argv1_end - argv1_begin - strlen(argv1_begin)); ++#endif ++} ++ ++static char *usage_string = ++"User Mode Linux v%s\n" ++" available at http://user-mode-linux.sourceforge.net/\n\n"; ++ ++static int __init uml_version_setup(char *line, int *add) ++{ ++ printf("%s\n", system_utsname.release); ++ exit(0); ++} ++ ++__uml_setup("--version", uml_version_setup, ++"--version\n" ++" Prints the version number of the kernel.\n\n" ++); ++ ++static int __init uml_root_setup(char *line, int *add) ++{ ++ have_root = 1; ++ return 0; ++} ++ ++__uml_setup("root=", uml_root_setup, ++"root=<file containing the root fs>\n" ++" This is actually used by the generic kernel in exactly the same\n" ++" way as in any other kernel. If you configure a number of block\n" ++" devices and want to boot off something other than ubd0, you \n" ++" would use something like:\n" ++" root=/dev/ubd5\n\n" ++); ++ ++#ifdef CONFIG_SMP ++static int __init uml_ncpus_setup(char *line, int *add) ++{ ++ if (!sscanf(line, "%d", &ncpus)) { ++ printf("Couldn't parse [%s]\n", line); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++__uml_setup("ncpus=", uml_ncpus_setup, ++"ncpus=<# of desired CPUs>\n" ++" This tells an SMP kernel how many virtual processors to start.\n\n" ++); ++#endif ++ ++int force_tt = 0; ++ ++#if defined(CONFIG_MODE_TT) && defined(CONFIG_MODE_SKAS) ++#define DEFAULT_TT 0 ++ ++static int __init mode_tt_setup(char *line, int *add) ++{ ++ force_tt = 1; ++ return(0); ++} ++ ++#else ++#ifdef CONFIG_MODE_SKAS ++ ++#define DEFAULT_TT 0 ++ ++static int __init mode_tt_setup(char *line, int *add) ++{ ++ printf("CONFIG_MODE_TT disabled - 'mode=tt' ignored\n"); ++ return(0); ++} ++ ++#else ++#ifdef CONFIG_MODE_TT ++ ++#define DEFAULT_TT 1 ++ ++static int __init mode_tt_setup(char *line, int *add) ++{ ++ printf("CONFIG_MODE_SKAS disabled - 'mode=tt' redundant\n"); ++ return(0); ++} ++ ++#else ++ ++#error Either CONFIG_MODE_TT or CONFIG_MODE_SKAS must be enabled ++ ++#endif ++#endif ++#endif ++ ++__uml_setup("mode=tt", mode_tt_setup, ++"mode=tt\n" ++" When both CONFIG_MODE_TT and CONFIG_MODE_SKAS are enabled, this option\n" ++" forces UML to run in tt (tracing thread) mode. It is not the default\n" ++" because it's slower and less secure than skas mode.\n\n" ++); ++ ++int mode_tt = DEFAULT_TT; ++ ++static int __init Usage(char *line, int *add) ++{ ++ const char **p; ++ ++ printf(usage_string, system_utsname.release); ++ p = &__uml_help_start; ++ while (p < &__uml_help_end) { ++ printf("%s", *p); ++ p++; ++ } ++ exit(0); ++} ++ ++__uml_setup("--help", Usage, ++"--help\n" ++" Prints this message.\n\n" ++); ++ ++static int __init uml_checksetup(char *line, int *add) ++{ ++ struct uml_param *p; ++ ++ p = &__uml_setup_start; ++ while(p < &__uml_setup_end) { ++ int n; ++ ++ n = strlen(p->str); ++ if(!strncmp(line, p->str, n)){ ++ if (p->setup_func(line + n, add)) return 1; ++ } ++ p++; ++ } ++ return 0; ++} ++ ++static void __init uml_postsetup(void) ++{ ++ initcall_t *p; ++ ++ p = &__uml_postsetup_start; ++ while(p < &__uml_postsetup_end){ ++ (*p)(); ++ p++; ++ } ++ return; ++} ++ ++/* Set during early boot */ ++unsigned long brk_start; ++unsigned long end_iomem; ++ ++#define MIN_VMALLOC (32 * 1024 * 1024) ++ ++int linux_main(int argc, char **argv) ++{ ++ unsigned long avail; ++ unsigned long virtmem_size, max_physmem; ++ unsigned int i, add; ++ ++ for (i = 1; i < argc; i++){ ++ if((i == 1) && (argv[i][0] == ' ')) continue; ++ add = 1; ++ uml_checksetup(argv[i], &add); ++ if(add) add_arg(saved_command_line, argv[i]); ++ } ++ if(have_root == 0) add_arg(saved_command_line, DEFAULT_COMMAND_LINE); ++ ++ mode_tt = force_tt ? 1 : !can_do_skas(); ++ uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0, ++ &host_task_size, &task_size); ++ ++ brk_start = (unsigned long) sbrk(0); ++ CHOOSE_MODE_PROC(before_mem_tt, before_mem_skas, brk_start); ++ ++ uml_physmem = uml_start; ++ ++ /* Reserve up to 4M after the current brk */ ++ uml_reserved = ROUND_4M(brk_start) + (1 << 22); ++ ++ setup_machinename(system_utsname.machine); ++ ++#ifdef CONFIG_MODE_TT ++ argv1_begin = argv[1]; ++ argv1_end = &argv[1][strlen(argv[1])]; ++#endif ++ ++ highmem = 0; ++ iomem_size = (iomem_size + PAGE_SIZE - 1) & PAGE_MASK; ++ max_physmem = get_kmem_end() - uml_physmem - iomem_size - MIN_VMALLOC; ++ ++ /* Zones have to begin on a 1 << MAX_ORDER page boundary, ++ * so this makes sure that's true for highmem ++ */ ++ max_physmem &= ~((1 << (PAGE_SHIFT + MAX_ORDER)) - 1); ++ if(physmem_size + iomem_size > max_physmem){ ++ highmem = physmem_size + iomem_size - max_physmem; ++ physmem_size -= highmem; ++#ifndef CONFIG_HIGHMEM ++ highmem = 0; ++ printf("CONFIG_HIGHMEM not enabled - physical memory shrunk " ++ "to %ld bytes\n", physmem_size); ++#endif ++ } ++ ++ high_physmem = uml_physmem + physmem_size; ++ end_iomem = high_physmem + iomem_size; ++ high_memory = (void *) end_iomem; ++ ++ start_vm = VMALLOC_START; ++ ++ setup_physmem(uml_physmem, uml_reserved, physmem_size, highmem); ++ if(init_maps(physmem_size, iomem_size, highmem)){ ++ printf("Failed to allocate mem_map for %ld bytes of physical " ++ "memory and %ld bytes of highmem\n", physmem_size, ++ highmem); ++ exit(1); ++ } ++ ++ virtmem_size = physmem_size; ++ avail = get_kmem_end() - start_vm; ++ if(physmem_size > avail) virtmem_size = avail; ++ end_vm = start_vm + virtmem_size; ++ ++ if(virtmem_size < physmem_size) ++ printf("Kernel virtual memory size shrunk to %ld bytes\n", ++ virtmem_size); ++ ++ uml_postsetup(); ++ ++ init_task.thread.kernel_stack = (unsigned long) &init_task + ++ 2 * PAGE_SIZE; ++ ++ task_protections((unsigned long) &init_task); ++ os_flush_stdout(); ++ ++ return(CHOOSE_MODE(start_uml_tt(), start_uml_skas())); ++} ++ ++static int panic_exit(struct notifier_block *self, unsigned long unused1, ++ void *unused2) ++{ ++#ifdef CONFIG_SYSRQ ++ handle_sysrq('p', ¤t->thread.regs, NULL, NULL); ++#endif ++ machine_halt(); ++ return(0); ++} ++ ++static struct notifier_block panic_exit_notifier = { ++ .notifier_call = panic_exit, ++ .next = NULL, ++ .priority = 0 ++}; ++ ++void __init setup_arch(char **cmdline_p) ++{ ++ notifier_chain_register(&panic_notifier_list, &panic_exit_notifier); ++ paging_init(); ++ strcpy(command_line, saved_command_line); ++ *cmdline_p = command_line; ++ setup_hostinfo(); ++} ++ ++void __init check_bugs(void) ++{ ++ arch_check_bugs(); ++ check_ptrace(); ++ check_sigio(); ++ check_devanon(); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/umid.c um/arch/um/kernel/umid.c +--- orig/arch/um/kernel/umid.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/umid.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,324 @@ ++/* ++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdio.h> ++#include <unistd.h> ++#include <errno.h> ++#include <string.h> ++#include <stdlib.h> ++#include <dirent.h> ++#include <signal.h> ++#include <sys/stat.h> ++#include <sys/param.h> ++#include "user.h" ++#include "umid.h" ++#include "init.h" ++#include "os.h" ++#include "user_util.h" ++#include "choose-mode.h" ++ ++#define UMID_LEN 64 ++#define UML_DIR "~/.uml/" ++ ++/* Changed by set_umid and make_umid, which are run early in boot */ ++static char umid[UMID_LEN] = { 0 }; ++ ++/* Changed by set_uml_dir and make_uml_dir, which are run early in boot */ ++static char *uml_dir = UML_DIR; ++ ++/* Changed by set_umid */ ++static int umid_is_random = 1; ++static int umid_inited = 0; ++ ++static int make_umid(int (*printer)(const char *fmt, ...)); ++ ++static int __init set_umid(char *name, int is_random, ++ int (*printer)(const char *fmt, ...)) ++{ ++ if(umid_inited){ ++ (*printer)("Unique machine name can't be set twice\n"); ++ return(-1); ++ } ++ ++ if(strlen(name) > UMID_LEN - 1) ++ (*printer)("Unique machine name is being truncated to %s " ++ "characters\n", UMID_LEN); ++ strncpy(umid, name, UMID_LEN - 1); ++ umid[UMID_LEN - 1] = '\0'; ++ ++ umid_is_random = is_random; ++ umid_inited = 1; ++ return 0; ++} ++ ++static int __init set_umid_arg(char *name, int *add) ++{ ++ return(set_umid(name, 0, printf)); ++} ++ ++__uml_setup("umid=", set_umid_arg, ++"umid=<name>\n" ++" This is used to assign a unique identity to this UML machine and\n" ++" is used for naming the pid file and management console socket.\n\n" ++); ++ ++int __init umid_file_name(char *name, char *buf, int len) ++{ ++ int n; ++ ++ if(!umid_inited && make_umid(printk)) return(-1); ++ ++ n = strlen(uml_dir) + strlen(umid) + strlen(name) + 1; ++ if(n > len){ ++ printk("umid_file_name : buffer too short\n"); ++ return(-1); ++ } ++ ++ sprintf(buf, "%s%s/%s", uml_dir, umid, name); ++ return(0); ++} ++ ++extern int tracing_pid; ++ ++static int __init create_pid_file(void) ++{ ++ char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")]; ++ char pid[sizeof("nnnnn\0")]; ++ int fd, n; ++ ++ if(umid_file_name("pid", file, sizeof(file))) return 0; ++ ++ fd = os_open_file(file, of_create(of_excl(of_rdwr(OPENFLAGS()))), ++ 0644); ++ if(fd < 0){ ++ printf("Open of machine pid file \"%s\" failed - " ++ "err = %d\n", file, -fd); ++ return 0; ++ } ++ ++ sprintf(pid, "%d\n", os_getpid()); ++ n = os_write_file(fd, pid, strlen(pid)); ++ if(n != strlen(pid)) ++ printf("Write of pid file failed - err = %d\n", -n); ++ os_close_file(fd); ++ return 0; ++} ++ ++static int actually_do_remove(char *dir) ++{ ++ DIR *directory; ++ struct dirent *ent; ++ int len; ++ char file[256]; ++ ++ directory = opendir(dir); ++ if(directory == NULL){ ++ printk("actually_do_remove : couldn't open directory '%s', " ++ "errno = %d\n", dir, errno); ++ return(1); ++ } ++ while((ent = readdir(directory)) != NULL){ ++ if(!strcmp(ent->d_name, ".") || !strcmp(ent->d_name, "..")) ++ continue; ++ len = strlen(dir) + sizeof("/") + strlen(ent->d_name) + 1; ++ if(len > sizeof(file)){ ++ printk("Not deleting '%s' from '%s' - name too long\n", ++ ent->d_name, dir); ++ continue; ++ } ++ sprintf(file, "%s/%s", dir, ent->d_name); ++ if(unlink(file) < 0){ ++ printk("actually_do_remove : couldn't remove '%s' " ++ "from '%s', errno = %d\n", ent->d_name, dir, ++ errno); ++ return(1); ++ } ++ } ++ if(rmdir(dir) < 0){ ++ printk("actually_do_remove : couldn't rmdir '%s', " ++ "errno = %d\n", dir, errno); ++ return(1); ++ } ++ return(0); ++} ++ ++void remove_umid_dir(void) ++{ ++ char dir[strlen(uml_dir) + UMID_LEN + 1]; ++ if(!umid_inited) return; ++ ++ sprintf(dir, "%s%s", uml_dir, umid); ++ actually_do_remove(dir); ++} ++ ++char *get_umid(int only_if_set) ++{ ++ if(only_if_set && umid_is_random) return(NULL); ++ return(umid); ++} ++ ++int not_dead_yet(char *dir) ++{ ++ char file[strlen(uml_dir) + UMID_LEN + sizeof("/pid\0")]; ++ char pid[sizeof("nnnnn\0")], *end; ++ int dead, fd, p, n; ++ ++ sprintf(file, "%s/pid", dir); ++ dead = 0; ++ fd = os_open_file(file, of_read(OPENFLAGS()), 0); ++ if(fd < 0){ ++ if(fd != -ENOENT){ ++ printk("not_dead_yet : couldn't open pid file '%s', " ++ "err = %d\n", file, -fd); ++ return(1); ++ } ++ dead = 1; ++ } ++ if(fd > 0){ ++ n = os_read_file(fd, pid, sizeof(pid)); ++ if(n < 0){ ++ printk("not_dead_yet : couldn't read pid file '%s', " ++ "err = %d\n", file, -n); ++ return(1); ++ } ++ p = strtoul(pid, &end, 0); ++ if(end == pid){ ++ printk("not_dead_yet : couldn't parse pid file '%s', " ++ "errno = %d\n", file, errno); ++ dead = 1; ++ } ++ if(((kill(p, 0) < 0) && (errno == ESRCH)) || ++ (p == CHOOSE_MODE(tracing_pid, os_getpid()))) ++ dead = 1; ++ } ++ if(!dead) return(1); ++ return(actually_do_remove(dir)); ++} ++ ++static int __init set_uml_dir(char *name, int *add) ++{ ++ if((strlen(name) > 0) && (name[strlen(name) - 1] != '/')){ ++ uml_dir = malloc(strlen(name) + 1); ++ if(uml_dir == NULL){ ++ printf("Failed to malloc uml_dir - error = %d\n", ++ errno); ++ uml_dir = name; ++ return(0); ++ } ++ sprintf(uml_dir, "%s/", name); ++ } ++ else uml_dir = name; ++ return 0; ++} ++ ++static int __init make_uml_dir(void) ++{ ++ char dir[MAXPATHLEN + 1] = { '\0' }; ++ int len; ++ ++ if(*uml_dir == '~'){ ++ char *home = getenv("HOME"); ++ ++ if(home == NULL){ ++ printf("make_uml_dir : no value in environment for " ++ "$HOME\n"); ++ exit(1); ++ } ++ strncpy(dir, home, sizeof(dir)); ++ uml_dir++; ++ } ++ len = strlen(dir); ++ strncat(dir, uml_dir, sizeof(dir) - len); ++ len = strlen(dir); ++ if((len > 0) && (len < sizeof(dir) - 1) && (dir[len - 1] != '/')){ ++ dir[len] = '/'; ++ dir[len + 1] = '\0'; ++ } ++ ++ uml_dir = malloc(strlen(dir) + 1); ++ if(uml_dir == NULL){ ++ printf("make_uml_dir : malloc failed, errno = %d\n", errno); ++ exit(1); ++ } ++ strcpy(uml_dir, dir); ++ ++ if((mkdir(uml_dir, 0777) < 0) && (errno != EEXIST)){ ++ printf("Failed to mkdir %s - errno = %i\n", uml_dir, errno); ++ return(-1); ++ } ++ return 0; ++} ++ ++static int __init make_umid(int (*printer)(const char *fmt, ...)) ++{ ++ int fd, err; ++ char tmp[strlen(uml_dir) + UMID_LEN + 1]; ++ ++ strncpy(tmp, uml_dir, sizeof(tmp) - 1); ++ tmp[sizeof(tmp) - 1] = '\0'; ++ ++ if(!umid_inited){ ++ strcat(tmp, "XXXXXX"); ++ fd = mkstemp(tmp); ++ if(fd < 0){ ++ (*printer)("make_umid - mkstemp failed, errno = %d\n", ++ errno); ++ return(1); ++ } ++ ++ os_close_file(fd); ++ /* There's a nice tiny little race between this unlink and ++ * the mkdir below. It'd be nice if there were a mkstemp ++ * for directories. ++ */ ++ unlink(tmp); ++ set_umid(&tmp[strlen(uml_dir)], 1, printer); ++ } ++ ++ sprintf(tmp, "%s%s", uml_dir, umid); ++ ++ err = mkdir(tmp, 0777); ++ if(err < 0){ ++ if(errno == EEXIST){ ++ if(not_dead_yet(tmp)){ ++ (*printer)("umid '%s' is in use\n", umid); ++ return(-1); ++ } ++ err = mkdir(tmp, 0777); ++ } ++ } ++ if(err < 0){ ++ (*printer)("Failed to create %s - errno = %d\n", umid, errno); ++ return(-1); ++ } ++ ++ return(0); ++} ++ ++__uml_setup("uml_dir=", set_uml_dir, ++"uml_dir=<directory>\n" ++" The location to place the pid and umid files.\n\n" ++); ++ ++__uml_postsetup(make_uml_dir); ++ ++static int __init make_umid_setup(void) ++{ ++ return(make_umid(printf)); ++} ++ ++__uml_postsetup(make_umid_setup); ++__uml_postsetup(create_pid_file); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/kernel/user_syms.c um/arch/um/kernel/user_syms.c +--- orig/arch/um/kernel/user_syms.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/user_syms.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,116 @@ ++#include <stdio.h> ++#include <unistd.h> ++#include <dirent.h> ++#include <fcntl.h> ++#include <errno.h> ++#include <utime.h> ++#include <string.h> ++#include <sys/stat.h> ++#include <sys/vfs.h> ++#include <sys/ioctl.h> ++#include "user_util.h" ++#include "mem_user.h" ++ ++/* XXX All the __CONFIG_* stuff is broken because this file can't include ++ * config.h ++ */ ++ ++/* Had to steal this from linux/module.h because that file can't be included ++ * since this includes various user-level headers. ++ */ ++ ++struct module_symbol ++{ ++ unsigned long value; ++ const char *name; ++}; ++ ++/* Indirect stringification. */ ++ ++#define __MODULE_STRING_1(x) #x ++#define __MODULE_STRING(x) __MODULE_STRING_1(x) ++ ++#if !defined(__AUTOCONF_INCLUDED__) ++ ++#define __EXPORT_SYMBOL(sym,str) error config_must_be_included_before_module ++#define EXPORT_SYMBOL(var) error config_must_be_included_before_module ++#define EXPORT_SYMBOL_NOVERS(var) error config_must_be_included_before_module ++ ++#elif !defined(__CONFIG_MODULES__) ++ ++#define __EXPORT_SYMBOL(sym,str) ++#define EXPORT_SYMBOL(var) ++#define EXPORT_SYMBOL_NOVERS(var) ++ ++#else ++ ++#define __EXPORT_SYMBOL(sym, str) \ ++const char __kstrtab_##sym[] \ ++__attribute__((section(".kstrtab"))) = str; \ ++const struct module_symbol __ksymtab_##sym \ ++__attribute__((section("__ksymtab"))) = \ ++{ (unsigned long)&sym, __kstrtab_##sym } ++ ++#if defined(__MODVERSIONS__) || !defined(__CONFIG_MODVERSIONS__) ++#define EXPORT_SYMBOL(var) __EXPORT_SYMBOL(var, __MODULE_STRING(var)) ++#else ++#define EXPORT_SYMBOL(var) __EXPORT_SYMBOL(var, __MODULE_STRING(__VERSIONED_SYMBOL(var))) ++#endif ++ ++#define EXPORT_SYMBOL_NOVERS(var) __EXPORT_SYMBOL(var, __MODULE_STRING(var)) ++ ++#endif ++ ++EXPORT_SYMBOL(__errno_location); ++ ++EXPORT_SYMBOL(access); ++EXPORT_SYMBOL(open); ++EXPORT_SYMBOL(open64); ++EXPORT_SYMBOL(close); ++EXPORT_SYMBOL(read); ++EXPORT_SYMBOL(write); ++EXPORT_SYMBOL(dup2); ++EXPORT_SYMBOL(__xstat); ++EXPORT_SYMBOL(__lxstat); ++EXPORT_SYMBOL(__lxstat64); ++EXPORT_SYMBOL(lseek); ++EXPORT_SYMBOL(lseek64); ++EXPORT_SYMBOL(chown); ++EXPORT_SYMBOL(truncate); ++EXPORT_SYMBOL(utime); ++EXPORT_SYMBOL(chmod); ++EXPORT_SYMBOL(rename); ++EXPORT_SYMBOL(__xmknod); ++ ++EXPORT_SYMBOL(symlink); ++EXPORT_SYMBOL(link); ++EXPORT_SYMBOL(unlink); ++EXPORT_SYMBOL(readlink); ++ ++EXPORT_SYMBOL(mkdir); ++EXPORT_SYMBOL(rmdir); ++EXPORT_SYMBOL(opendir); ++EXPORT_SYMBOL(readdir); ++EXPORT_SYMBOL(closedir); ++EXPORT_SYMBOL(seekdir); ++EXPORT_SYMBOL(telldir); ++ ++EXPORT_SYMBOL(ioctl); ++ ++extern ssize_t pread64 (int __fd, void *__buf, size_t __nbytes, ++ __off64_t __offset); ++extern ssize_t pwrite64 (int __fd, __const void *__buf, size_t __n, ++ __off64_t __offset); ++EXPORT_SYMBOL(pread64); ++EXPORT_SYMBOL(pwrite64); ++ ++EXPORT_SYMBOL(statfs); ++EXPORT_SYMBOL(statfs64); ++ ++EXPORT_SYMBOL(memcpy); ++EXPORT_SYMBOL(getuid); ++ ++EXPORT_SYMBOL(memset); ++EXPORT_SYMBOL(strstr); ++ ++EXPORT_SYMBOL(find_iomem); +diff -Naur -X ../exclude-files orig/arch/um/kernel/user_util.c um/arch/um/kernel/user_util.c +--- orig/arch/um/kernel/user_util.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/kernel/user_util.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,164 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdio.h> ++#include <stdlib.h> ++#include <unistd.h> ++#include <limits.h> ++#include <sys/mman.h> ++#include <sys/stat.h> ++#include <sys/ptrace.h> ++#include <sys/utsname.h> ++#include <sys/param.h> ++#include <sys/time.h> ++#include "asm/types.h" ++#include <ctype.h> ++#include <signal.h> ++#include <wait.h> ++#include <errno.h> ++#include <stdarg.h> ++#include <sched.h> ++#include <termios.h> ++#include <string.h> ++#include "user_util.h" ++#include "kern_util.h" ++#include "user.h" ++#include "mem_user.h" ++#include "init.h" ++#include "helper.h" ++#include "uml-config.h" ++ ++#define COMMAND_LINE_SIZE _POSIX_ARG_MAX ++ ++/* Changed in linux_main and setup_arch, which run before SMP is started */ ++char saved_command_line[COMMAND_LINE_SIZE] = { 0 }; ++char command_line[COMMAND_LINE_SIZE] = { 0 }; ++ ++void add_arg(char *cmd_line, char *arg) ++{ ++ if (strlen(cmd_line) + strlen(arg) + 1 > COMMAND_LINE_SIZE) { ++ printf("add_arg: Too much command line!\n"); ++ exit(1); ++ } ++ if(strlen(cmd_line) > 0) strcat(cmd_line, " "); ++ strcat(cmd_line, arg); ++} ++ ++void stop(void) ++{ ++ while(1) sleep(1000000); ++} ++ ++void stack_protections(unsigned long address) ++{ ++ int prot = PROT_READ | PROT_WRITE | PROT_EXEC; ++ ++ if(mprotect((void *) address, page_size(), prot) < 0) ++ panic("protecting stack failed, errno = %d", errno); ++} ++ ++void task_protections(unsigned long address) ++{ ++ unsigned long guard = address + page_size(); ++ unsigned long stack = guard + page_size(); ++ int prot = 0, pages; ++#ifdef notdef ++ if(mprotect((void *) guard, page_size(), prot) < 0) ++ panic("protecting guard page failed, errno = %d", errno); ++#endif ++ pages = (1 << UML_CONFIG_KERNEL_STACK_ORDER) - 2; ++ prot = PROT_READ | PROT_WRITE | PROT_EXEC; ++ if(mprotect((void *) stack, pages * page_size(), prot) < 0) ++ panic("protecting stack failed, errno = %d", errno); ++} ++ ++int wait_for_stop(int pid, int sig, int cont_type, void *relay) ++{ ++ sigset_t *relay_signals = relay; ++ int status, ret; ++ ++ while(1){ ++ ret = waitpid(pid, &status, WUNTRACED); ++ if((ret < 0) || ++ !WIFSTOPPED(status) || (WSTOPSIG(status) != sig)){ ++ if(ret < 0){ ++ if(errno == EINTR) continue; ++ printk("wait failed, errno = %d\n", ++ errno); ++ } ++ else if(WIFEXITED(status)) ++ printk("process exited with status %d\n", ++ WEXITSTATUS(status)); ++ else if(WIFSIGNALED(status)) ++ printk("process exited with signal %d\n", ++ WTERMSIG(status)); ++ else if((WSTOPSIG(status) == SIGVTALRM) || ++ (WSTOPSIG(status) == SIGALRM) || ++ (WSTOPSIG(status) == SIGIO) || ++ (WSTOPSIG(status) == SIGPROF) || ++ (WSTOPSIG(status) == SIGCHLD) || ++ (WSTOPSIG(status) == SIGWINCH) || ++ (WSTOPSIG(status) == SIGINT)){ ++ ptrace(cont_type, pid, 0, WSTOPSIG(status)); ++ continue; ++ } ++ else if((relay_signals != NULL) && ++ sigismember(relay_signals, WSTOPSIG(status))){ ++ ptrace(cont_type, pid, 0, WSTOPSIG(status)); ++ continue; ++ } ++ else printk("process stopped with signal %d\n", ++ WSTOPSIG(status)); ++ panic("wait_for_stop failed to wait for %d to stop " ++ "with %d\n", pid, sig); ++ } ++ return(status); ++ } ++} ++ ++int raw(int fd, int complain) ++{ ++ struct termios tt; ++ int err; ++ ++ tcgetattr(fd, &tt); ++ cfmakeraw(&tt); ++ err = tcsetattr(fd, TCSANOW, &tt); ++ if((err < 0) && complain){ ++ printk("tcsetattr failed, errno = %d\n", errno); ++ return(-errno); ++ } ++ return(0); ++} ++ ++void setup_machinename(char *machine_out) ++{ ++ struct utsname host; ++ ++ uname(&host); ++ strcpy(machine_out, host.machine); ++} ++ ++char host_info[(_UTSNAME_LENGTH + 1) * 4 + _UTSNAME_NODENAME_LENGTH + 1]; ++ ++void setup_hostinfo(void) ++{ ++ struct utsname host; ++ ++ uname(&host); ++ sprintf(host_info, "%s %s %s %s %s", host.sysname, host.nodename, ++ host.release, host.version, host.machine); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/link.ld.in um/arch/um/link.ld.in +--- orig/arch/um/link.ld.in 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/link.ld.in 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,94 @@ ++OUTPUT_FORMAT("ELF_FORMAT") ++OUTPUT_ARCH(ELF_ARCH) ++ENTRY(_start) ++ ++SECTIONS ++{ ++ . = START() + SIZEOF_HEADERS; ++ ++ __binary_start = .; ++ifdef(`MODE_TT', ` ++ .thread_private : { ++ __start_thread_private = .; ++ errno = .; ++ . += 4; ++ arch/um/kernel/tt/unmap_fin.o (.data) ++ __end_thread_private = .; ++ } ++ . = ALIGN(4096); ++ .remap : { arch/um/kernel/tt/unmap_fin.o (.text) } ++') ++ . = ALIGN(4096); /* Init code and data */ ++ _stext = .; ++ __init_begin = .; ++ .text.init : { *(.text.init) } ++ . = ALIGN(4096); ++ .text : ++ { ++ *(.text) ++ /* .gnu.warning sections are handled specially by elf32.em. */ ++ *(.gnu.warning) ++ *(.gnu.linkonce.t*) ++ } ++ .fini : { *(.fini) } =0x9090 ++ .rodata : { *(.rodata) *(.gnu.linkonce.r*) } ++ .rodata1 : { *(.rodata1) } ++ _etext = .; ++ PROVIDE (etext = .); ++ ++ . = ALIGN(4096); ++ PROVIDE (_sdata = .); ++ ++include(`arch/um/common.ld.in') ++ ++ .data : ++ { ++ . = ALIGN(KERNEL_STACK_SIZE); /* init_task */ ++ *(.data.init_task) ++ *(.data) ++ *(.gnu.linkonce.d*) ++ CONSTRUCTORS ++ } ++ .data1 : { *(.data1) } ++ .ctors : ++ { ++ *(.ctors) ++ } ++ .dtors : ++ { ++ *(.dtors) ++ } ++ ++ .got : { *(.got.plt) *(.got) } ++ .dynamic : { *(.dynamic) } ++ /* We want the small data sections together, so single-instruction offsets ++ can access them all, and initialized data all before uninitialized, so ++ we can shorten the on-disk segment size. */ ++ .sdata : { *(.sdata) } ++ _edata = .; ++ PROVIDE (edata = .); ++ . = ALIGN(0x1000); ++ .sbss : ++ { ++ __bss_start = .; ++ PROVIDE(_bss_start = .); ++ *(.sbss) ++ *(.scommon) ++ } ++ .bss : ++ { ++ *(.dynbss) ++ *(.bss) ++ *(COMMON) ++ } ++ _end = . ; ++ PROVIDE (end = .); ++ /* Stabs debugging sections. */ ++ .stab 0 : { *(.stab) } ++ .stabstr 0 : { *(.stabstr) } ++ .stab.excl 0 : { *(.stab.excl) } ++ .stab.exclstr 0 : { *(.stab.exclstr) } ++ .stab.index 0 : { *(.stab.index) } ++ .stab.indexstr 0 : { *(.stab.indexstr) } ++ .comment 0 : { *(.comment) } ++} +diff -Naur -X ../exclude-files orig/arch/um/main.c um/arch/um/main.c +--- orig/arch/um/main.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/main.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,198 @@ ++/* ++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <unistd.h> ++#include <stdio.h> ++#include <stdlib.h> ++#include <string.h> ++#include <signal.h> ++#include <errno.h> ++#include <sys/resource.h> ++#include <sys/mman.h> ++#include <sys/user.h> ++#include <asm/page.h> ++#include "user_util.h" ++#include "kern_util.h" ++#include "mem_user.h" ++#include "signal_user.h" ++#include "user.h" ++#include "init.h" ++#include "mode.h" ++#include "choose-mode.h" ++#include "uml-config.h" ++ ++/* Set in set_stklim, which is called from main and __wrap_malloc. ++ * __wrap_malloc only calls it if main hasn't started. ++ */ ++unsigned long stacksizelim; ++ ++/* Set in main */ ++char *linux_prog; ++ ++#define PGD_BOUND (4 * 1024 * 1024) ++#define STACKSIZE (8 * 1024 * 1024) ++#define THREAD_NAME_LEN (256) ++ ++static void set_stklim(void) ++{ ++ struct rlimit lim; ++ ++ if(getrlimit(RLIMIT_STACK, &lim) < 0){ ++ perror("getrlimit"); ++ exit(1); ++ } ++ if((lim.rlim_cur == RLIM_INFINITY) || (lim.rlim_cur > STACKSIZE)){ ++ lim.rlim_cur = STACKSIZE; ++ if(setrlimit(RLIMIT_STACK, &lim) < 0){ ++ perror("setrlimit"); ++ exit(1); ++ } ++ } ++ stacksizelim = (lim.rlim_cur + PGD_BOUND - 1) & ~(PGD_BOUND - 1); ++} ++ ++static __init void do_uml_initcalls(void) ++{ ++ initcall_t *call; ++ ++ call = &__uml_initcall_start; ++ while (call < &__uml_initcall_end){; ++ (*call)(); ++ call++; ++ } ++} ++ ++static void last_ditch_exit(int sig) ++{ ++ CHOOSE_MODE(kmalloc_ok = 0, (void) 0); ++ signal(SIGINT, SIG_DFL); ++ signal(SIGTERM, SIG_DFL); ++ signal(SIGHUP, SIG_DFL); ++ uml_cleanup(); ++ exit(1); ++} ++ ++extern int uml_exitcode; ++ ++int main(int argc, char **argv, char **envp) ++{ ++ char **new_argv; ++ sigset_t mask; ++ int ret, i; ++ ++ /* Enable all signals except SIGIO - in some environments, we can ++ * enter with some signals blocked ++ */ ++ ++ sigemptyset(&mask); ++ sigaddset(&mask, SIGIO); ++ if(sigprocmask(SIG_SETMASK, &mask, NULL) < 0){ ++ perror("sigprocmask"); ++ exit(1); ++ } ++ ++#ifdef UML_CONFIG_MODE_TT ++ /* Allocate memory for thread command lines */ ++ if(argc < 2 || strlen(argv[1]) < THREAD_NAME_LEN - 1){ ++ ++ char padding[THREAD_NAME_LEN] = { ++ [ 0 ... THREAD_NAME_LEN - 2] = ' ', '\0' ++ }; ++ ++ new_argv = malloc((argc + 2) * sizeof(char*)); ++ if(!new_argv) { ++ perror("Allocating extended argv"); ++ exit(1); ++ } ++ ++ new_argv[0] = argv[0]; ++ new_argv[1] = padding; ++ ++ for(i = 2; i <= argc; i++) ++ new_argv[i] = argv[i - 1]; ++ new_argv[argc + 1] = NULL; ++ ++ execvp(new_argv[0], new_argv); ++ perror("execing with extended args"); ++ exit(1); ++ } ++#endif ++ ++ linux_prog = argv[0]; ++ ++ set_stklim(); ++ ++ new_argv = malloc((argc + 1) * sizeof(char *)); ++ if(new_argv == NULL){ ++ perror("Mallocing argv"); ++ exit(1); ++ } ++ for(i=0;i<argc;i++){ ++ new_argv[i] = strdup(argv[i]); ++ if(new_argv[i] == NULL){ ++ perror("Mallocing an arg"); ++ exit(1); ++ } ++ } ++ new_argv[argc] = NULL; ++ ++ set_handler(SIGINT, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); ++ set_handler(SIGTERM, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); ++ set_handler(SIGHUP, last_ditch_exit, SA_ONESHOT | SA_NODEFER, -1); ++ ++ do_uml_initcalls(); ++ ret = linux_main(argc, argv); ++ ++ /* Reboot */ ++ if(ret){ ++ printf("\n"); ++ execvp(new_argv[0], new_argv); ++ perror("Failed to exec kernel"); ++ ret = 1; ++ } ++ printf("\n"); ++ return(uml_exitcode); ++} ++ ++#define CAN_KMALLOC() \ ++ (kmalloc_ok && CHOOSE_MODE((getpid() != tracing_pid), 1)) ++ ++extern void *__real_malloc(int); ++ ++void *__wrap_malloc(int size) ++{ ++ if(CAN_KMALLOC()) ++ return(um_kmalloc(size)); ++ else ++ return(__real_malloc(size)); ++} ++ ++void *__wrap_calloc(int n, int size) ++{ ++ void *ptr = __wrap_malloc(n * size); ++ ++ if(ptr == NULL) return(NULL); ++ memset(ptr, 0, n * size); ++ return(ptr); ++} ++ ++extern void __real_free(void *); ++ ++void __wrap_free(void *ptr) ++{ ++ if(CAN_KMALLOC()) kfree(ptr); ++ else __real_free(ptr); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/Makefile um/arch/um/Makefile +--- orig/arch/um/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/Makefile 2003-12-17 03:02:28.000000000 -0500 +@@ -0,0 +1,174 @@ ++# ++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++# Licensed under the GPL ++# ++ ++OS := $(shell uname -s) ++ ++ARCH_DIR = arch/um ++ ++core-y := kernel sys-$(SUBARCH) os-$(OS) ++drivers-y := fs drivers ++subdir-y := $(core-y) $(drivers-y) ++SUBDIRS += $(foreach dir,$(subdir-y),$(ARCH_DIR)/$(dir)) ++ ++CORE_FILES += $(foreach dir,$(core-y),$(ARCH_DIR)/$(dir)/built-in.o) ++DRIVERS += $(foreach dir,$(drivers-y),$(ARCH_DIR)/$(dir)/built-in.o) ++ ++include $(ARCH_DIR)/Makefile-$(SUBARCH) ++include $(ARCH_DIR)/Makefile-os-$(OS) ++ ++MAKEFILE-$(CONFIG_MODE_TT) += Makefile-tt ++MAKEFILE-$(CONFIG_MODE_SKAS) += Makefile-skas ++ ++ifneq ($(MAKEFILE-y),) ++ include $(addprefix $(ARCH_DIR)/,$(MAKEFILE-y)) ++endif ++ ++EXTRAVERSION := $(EXTRAVERSION)-1um ++ ++include/linux/version.h: arch/$(ARCH)/Makefile ++ ++# Recalculate MODLIB to reflect the EXTRAVERSION changes (via KERNELRELEASE) ++# The way the toplevel Makefile is written EXTRAVERSION is not supposed ++# to be changed outside the toplevel Makefile, but recalculating MODLIB is ++# a sufficient workaround until we no longer need architecture dependent ++# EXTRAVERSION... ++MODLIB := $(INSTALL_MOD_PATH)/lib/modules/$(KERNELRELEASE) ++ ++ifeq ($(CONFIG_DEBUGSYM),y) ++CFLAGS := $(subst -fomit-frame-pointer,,$(CFLAGS)) ++endif ++ ++CFLAGS-$(CONFIG_DEBUGSYM) += -g ++ ++ARCH_INCLUDE = -I$(TOPDIR)/$(ARCH_DIR)/include ++ ++# -Derrno=kernel_errno - This turns all kernel references to errno into ++# kernel_errno to separate them from the libc errno. This allows -fno-common ++# in CFLAGS. Otherwise, it would cause ld to complain about the two different ++# errnos. ++ ++CFLAGS += $(ARCH_CFLAGS) $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \ ++ -D_LARGEFILE64_SOURCE $(ARCH_INCLUDE) -Derrno=kernel_errno \ ++ $(MODE_INCLUDE) ++ ++LINKFLAGS += -r ++ ++LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc ++ ++# These are needed for clean and mrproper, since in that case .config is not ++# included; the values here are meaningless ++ ++CONFIG_NEST_LEVEL ?= 0 ++CONFIG_KERNEL_HALF_GIGS ?= 0 ++ ++SIZE = (($(CONFIG_NEST_LEVEL) + $(CONFIG_KERNEL_HALF_GIGS)) * 0x20000000) ++ ++# These aren't in Makefile-tt because they are needed in the !CONFIG_MODE_TT + ++# CONFIG_MODE_SKAS + CONFIG_STATIC_LINK case. ++ ++LINK_TT = -static ++LD_SCRIPT_TT := link.ld ++ ++ifeq ($(CONFIG_STATIC_LINK),y) ++ LINK-y += $(LINK_TT) ++ LD_SCRIPT-y := $(LD_SCRIPT_TT) ++else ++ifeq ($(CONFIG_MODE_TT),y) ++ LINK-y += $(LINK_TT) ++ LD_SCRIPT-y := $(LD_SCRIPT_TT) ++else ++ifeq ($(CONFIG_MODE_SKAS),y) ++ LINK-y += $(LINK_SKAS) ++ LD_SCRIPT-y := $(LD_SCRIPT_SKAS) ++endif ++endif ++endif ++ ++LD_SCRIPT-y := $(ARCH_DIR)/$(LD_SCRIPT-y) ++M4_MODE_TT := $(shell [ "$(CONFIG_MODE_TT)" = "y" ] && echo -DMODE_TT) ++ ++$(LD_SCRIPT-y): $(LD_SCRIPT-y).in ++ pages=$$(( 1 << $(CONFIG_KERNEL_STACK_ORDER) )) ; \ ++ m4 -DSTART=$$(($(TOP_ADDR) - $(SIZE))) -DELF_ARCH=$(ELF_ARCH) \ ++ -DELF_FORMAT=$(ELF_FORMAT) $(M4_MODE_TT) \ ++ -DKERNEL_STACK_SIZE=$$(( 4096 * $$pages )) $< > $@ ++ ++SYMLINK_HEADERS = include/asm-um/archparam.h include/asm-um/system.h \ ++ include/asm-um/sigcontext.h include/asm-um/processor.h \ ++ include/asm-um/ptrace.h include/asm-um/arch-signal.h ++ ++ARCH_SYMLINKS = include/asm-um/arch arch/um/include/sysdep arch/um/os \ ++ $(SYMLINK_HEADERS) $(ARCH_DIR)/include/uml-config.h ++ ++ifeq ($(CONFIG_MODE_SKAS), y) ++$(SYS_HEADERS) : $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h ++endif ++ ++GEN_HEADERS += $(ARCH_DIR)/include/task.h $(ARCH_DIR)/include/kern_constants.h ++ ++setup: $(ARCH_SYMLINKS) $(SYS_HEADERS) $(GEN_HEADERS) ++ ++linux: setup $(ARCH_DIR)/main.o vmlinux $(LD_SCRIPT-y) ++ mv vmlinux vmlinux.o ++ $(CC) -Wl,-T,$(LD_SCRIPT-y) $(LINK-y) $(LINK_WRAPS) \ ++ -o linux $(ARCH_DIR)/main.o vmlinux.o -L/usr/lib -lutil ++ ++USER_CFLAGS := $(patsubst -I%,,$(CFLAGS)) ++USER_CFLAGS := $(patsubst -Derrno=kernel_errno,,$(USER_CFLAGS)) ++USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \ ++ $(MODE_INCLUDE) ++ ++# To get a definition of F_SETSIG ++USER_CFLAGS += -D_GNU_SOURCE ++ ++CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/link.ld $(ARCH_DIR)/dyn_link.ld \ ++ $(GEN_HEADERS) $(ARCH_DIR)/include/uml-config.h ++ ++$(ARCH_DIR)/main.o: $(ARCH_DIR)/main.c ++ $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< ++ ++archmrproper: ++ rm -f $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) include/asm \ ++ $(LD_SCRIPT) $(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) ++ ++archclean: sysclean ++ find . \( -name '*.bb' -o -name '*.bbg' -o -name '*.da' \ ++ -o -name '*.gcov' \) -type f -print | xargs rm -f ++ cd $(ARCH_DIR) ; \ ++ for dir in $(subdir-y) util ; do $(MAKE) -C $$dir clean; done ++ ++archdep: ++ ++$(SYMLINK_HEADERS): ++ cd $(TOPDIR)/$(dir $@) ; \ ++ ln -sf $(basename $(notdir $@))-$(SUBARCH)$(suffix $@) $(notdir $@) ++ ++include/asm-um/arch: ++ cd $(TOPDIR)/include/asm-um && ln -sf ../asm-$(SUBARCH) arch ++ ++arch/um/include/sysdep: ++ cd $(TOPDIR)/arch/um/include && ln -sf sysdep-$(SUBARCH) sysdep ++ ++arch/um/os: ++ cd $(ARCH_DIR) && ln -sf os-$(OS) os ++ ++$(ARCH_DIR)/include/task.h : $(ARCH_DIR)/util/mk_task ++ $< > $@ ++ ++$(ARCH_DIR)/include/kern_constants.h : $(ARCH_DIR)/util/mk_constants ++ $< > $@ ++ ++$(ARCH_DIR)/include/uml-config.h : $(TOPDIR)/include/linux/autoconf.h ++ sed 's/ CONFIG/ UML_CONFIG/' $(TOPDIR)/include/linux/autoconf.h > $@ ++ ++$(ARCH_DIR)/util/mk_task : $(ARCH_DIR)/util/mk_task_user.c \ ++ $(ARCH_DIR)/util/mk_task_kern.c $(SYS_HEADERS) ++ $(MAKE) $(MFLAGS) -C $(ARCH_DIR)/util mk_task ++ ++$(ARCH_DIR)/util/mk_constants : $(ARCH_DIR)/util/mk_constants_user.c \ ++ $(ARCH_DIR)/util/mk_constants_kern.c ++ $(MAKE) $(MFLAGS) -C $(ARCH_DIR)/util mk_constants ++ ++export SUBARCH USER_CFLAGS OS +diff -Naur -X ../exclude-files orig/arch/um/Makefile-i386 um/arch/um/Makefile-i386 +--- orig/arch/um/Makefile-i386 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/Makefile-i386 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,35 @@ ++ifeq ($(CONFIG_HOST_2G_2G), y) ++TOP_ADDR = 0x80000000 ++else ++TOP_ADDR = 0xc0000000 ++endif ++ ++ARCH_CFLAGS = -U__$(SUBARCH)__ -U$(SUBARCH) -DUM_FASTCALL ++ELF_ARCH = $(SUBARCH) ++ELF_FORMAT = elf32-$(SUBARCH) ++ ++I386_H = $(ARCH_DIR)/include/sysdep-i386 ++SYS = $(ARCH_DIR)/sys-i386 ++UTIL = $(SYS)/util ++SUBDIRS += $(UTIL) ++ ++SYS_HEADERS = $(I386_H)/sc.h $(I386_H)/thread.h ++ ++$(I386_H)/sc.h : $(UTIL)/mk_sc ++ $(UTIL)/mk_sc > $@ ++ ++$(I386_H)/thread.h : $(UTIL)/mk_thread ++ $(UTIL)/mk_thread > $@ ++ ++$(UTIL)/mk_sc : $(UTIL)/mk_sc.c ++ $(MAKE) -C $(UTIL) mk_sc ++ ++$(UTIL)/mk_thread : $(UTIL)/mk_thread_user.c $(UTIL)/mk_thread_kern.c \ ++ $(I386_H)/sc.h ++ $(MAKE) -C $(UTIL) mk_thread ++ ++sysclean : ++ rm -f $(SYS_HEADERS) ++ $(MAKE) -C $(UTIL) clean ++ $(MAKE) -C $(SYS) clean ++ +diff -Naur -X ../exclude-files orig/arch/um/Makefile-ia64 um/arch/um/Makefile-ia64 +--- orig/arch/um/Makefile-ia64 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/Makefile-ia64 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1 @@ ++START_ADDR = 0x1000000000000000 +diff -Naur -X ../exclude-files orig/arch/um/Makefile-os-Linux um/arch/um/Makefile-os-Linux +--- orig/arch/um/Makefile-os-Linux 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/Makefile-os-Linux 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,7 @@ ++# ++# Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++# Licensed under the GPL ++# ++ ++SUBDIRS += $(ARCH_DIR)/os-$(OS)/drivers ++DRIVERS += $(ARCH_DIR)/os-$(OS)/drivers/drivers.o +diff -Naur -X ../exclude-files orig/arch/um/Makefile-ppc um/arch/um/Makefile-ppc +--- orig/arch/um/Makefile-ppc 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/Makefile-ppc 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,9 @@ ++ifeq ($(CONFIG_HOST_2G_2G), y) ++START_ADDR = 0x80000000 ++else ++START_ADDR = 0xc0000000 ++endif ++ARCH_CFLAGS = -U__powerpc__ -D__UM_PPC__ ++ ++# The arch is ppc, but the elf32 name is powerpc ++ELF_SUBARCH = powerpc +diff -Naur -X ../exclude-files orig/arch/um/Makefile-skas um/arch/um/Makefile-skas +--- orig/arch/um/Makefile-skas 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/Makefile-skas 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,20 @@ ++# ++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++# Licensed under the GPL ++# ++ ++PROFILE += -pg ++ ++CFLAGS-$(CONFIG_GCOV) += -fprofile-arcs -ftest-coverage ++CFLAGS-$(CONFIG_GPROF) += $(PROFILE) ++LINK-$(CONFIG_GPROF) += $(PROFILE) ++ ++MODE_INCLUDE += -I$(TOPDIR)/$(ARCH_DIR)/kernel/skas/include ++ ++LINK_SKAS = -Wl,-rpath,/lib ++LD_SCRIPT_SKAS = dyn_link.ld ++ ++GEN_HEADERS += $(ARCH_DIR)/kernel/skas/include/skas_ptregs.h ++ ++$(ARCH_DIR)/kernel/skas/include/skas_ptregs.h : ++ $(MAKE) -C $(ARCH_DIR)/kernel/skas include/skas_ptregs.h +diff -Naur -X ../exclude-files orig/arch/um/Makefile-tt um/arch/um/Makefile-tt +--- orig/arch/um/Makefile-tt 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/Makefile-tt 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,7 @@ ++# ++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++# Licensed under the GPL ++# ++ ++MODE_INCLUDE += -I$(TOPDIR)/$(ARCH_DIR)/kernel/tt/include ++ +diff -Naur -X ../exclude-files orig/arch/um/os-Linux/drivers/etap.h um/arch/um/os-Linux/drivers/etap.h +--- orig/arch/um/os-Linux/drivers/etap.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/os-Linux/drivers/etap.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,27 @@ ++/* ++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "net_user.h" ++ ++struct ethertap_data { ++ char *dev_name; ++ char *gate_addr; ++ int data_fd; ++ int control_fd; ++ void *dev; ++}; ++ ++extern struct net_user_info ethertap_user_info; ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/os-Linux/drivers/ethertap_kern.c um/arch/um/os-Linux/drivers/ethertap_kern.c +--- orig/arch/um/os-Linux/drivers/ethertap_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/os-Linux/drivers/ethertap_kern.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,122 @@ ++/* ++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and ++ * James Leu (jleu@mindspring.net). ++ * Copyright (C) 2001 by various other people who didn't put their name here. ++ * Licensed under the GPL. ++ */ ++ ++#include "linux/init.h" ++#include "linux/netdevice.h" ++#include "linux/etherdevice.h" ++#include "linux/init.h" ++#include "net_kern.h" ++#include "net_user.h" ++#include "etap.h" ++ ++struct ethertap_init { ++ char *dev_name; ++ char *gate_addr; ++}; ++ ++static void etap_init(struct net_device *dev, void *data) ++{ ++ struct uml_net_private *pri; ++ struct ethertap_data *epri; ++ struct ethertap_init *init = data; ++ ++ init_etherdev(dev, 0); ++ pri = dev->priv; ++ epri = (struct ethertap_data *) pri->user; ++ *epri = ((struct ethertap_data) ++ { .dev_name = init->dev_name, ++ .gate_addr = init->gate_addr, ++ .data_fd = -1, ++ .control_fd = -1, ++ .dev = dev }); ++ ++ printk("ethertap backend - %s", epri->dev_name); ++ if(epri->gate_addr != NULL) ++ printk(", IP = %s", epri->gate_addr); ++ printk("\n"); ++} ++ ++static int etap_read(int fd, struct sk_buff **skb, struct uml_net_private *lp) ++{ ++ int len; ++ ++ *skb = ether_adjust_skb(*skb, ETH_HEADER_ETHERTAP); ++ if(*skb == NULL) return(-ENOMEM); ++ len = net_recvfrom(fd, (*skb)->mac.raw, ++ (*skb)->dev->mtu + 2 * ETH_HEADER_ETHERTAP); ++ if(len <= 0) return(len); ++ skb_pull(*skb, 2); ++ len -= 2; ++ return(len); ++} ++ ++static int etap_write(int fd, struct sk_buff **skb, struct uml_net_private *lp) ++{ ++ if(skb_headroom(*skb) < 2){ ++ struct sk_buff *skb2; ++ ++ skb2 = skb_realloc_headroom(*skb, 2); ++ dev_kfree_skb(*skb); ++ if (skb2 == NULL) return(-ENOMEM); ++ *skb = skb2; ++ } ++ skb_push(*skb, 2); ++ return(net_send(fd, (*skb)->data, (*skb)->len)); ++} ++ ++struct net_kern_info ethertap_kern_info = { ++ .init = etap_init, ++ .protocol = eth_protocol, ++ .read = etap_read, ++ .write = etap_write, ++}; ++ ++int ethertap_setup(char *str, char **mac_out, void *data) ++{ ++ struct ethertap_init *init = data; ++ ++ *init = ((struct ethertap_init) ++ { .dev_name = NULL, ++ .gate_addr = NULL }); ++ if(tap_setup_common(str, "ethertap", &init->dev_name, mac_out, ++ &init->gate_addr)) ++ return(0); ++ if(init->dev_name == NULL){ ++ printk("ethertap_setup : Missing tap device name\n"); ++ return(0); ++ } ++ ++ return(1); ++} ++ ++static struct transport ethertap_transport = { ++ .list = LIST_HEAD_INIT(ethertap_transport.list), ++ .name = "ethertap", ++ .setup = ethertap_setup, ++ .user = ðertap_user_info, ++ .kern = ðertap_kern_info, ++ .private_size = sizeof(struct ethertap_data), ++}; ++ ++static int register_ethertap(void) ++{ ++ register_transport(ðertap_transport); ++ return(1); ++} ++ ++__initcall(register_ethertap); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/os-Linux/drivers/ethertap_user.c um/arch/um/os-Linux/drivers/ethertap_user.c +--- orig/arch/um/os-Linux/drivers/ethertap_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/os-Linux/drivers/ethertap_user.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,238 @@ ++/* ++ * Copyright (C) 2001 Lennert Buytenhek (buytenh@gnu.org) and ++ * James Leu (jleu@mindspring.net). ++ * Copyright (C) 2001 by various other people who didn't put their name here. ++ * Licensed under the GPL. ++ */ ++ ++#include <stdio.h> ++#include <unistd.h> ++#include <stddef.h> ++#include <stdlib.h> ++#include <sys/errno.h> ++#include <sys/socket.h> ++#include <sys/wait.h> ++#include <sys/un.h> ++#include <net/if.h> ++#include "user.h" ++#include "kern_util.h" ++#include "net_user.h" ++#include "etap.h" ++#include "helper.h" ++#include "os.h" ++ ++#define MAX_PACKET ETH_MAX_PACKET ++ ++void etap_user_init(void *data, void *dev) ++{ ++ struct ethertap_data *pri = data; ++ ++ pri->dev = dev; ++} ++ ++struct addr_change { ++ enum { ADD_ADDR, DEL_ADDR } what; ++ unsigned char addr[4]; ++ unsigned char netmask[4]; ++}; ++ ++static void etap_change(int op, unsigned char *addr, unsigned char *netmask, ++ int fd) ++{ ++ struct addr_change change; ++ void *output; ++ int n; ++ ++ change.what = op; ++ memcpy(change.addr, addr, sizeof(change.addr)); ++ memcpy(change.netmask, netmask, sizeof(change.netmask)); ++ n = os_write_file(fd, &change, sizeof(change)); ++ if(n != sizeof(change)) ++ printk("etap_change - request failed, err = %d\n", -n); ++ output = um_kmalloc(page_size()); ++ if(output == NULL) ++ printk("etap_change : Failed to allocate output buffer\n"); ++ read_output(fd, output, page_size()); ++ if(output != NULL){ ++ printk("%s", output); ++ kfree(output); ++ } ++} ++ ++static void etap_open_addr(unsigned char *addr, unsigned char *netmask, ++ void *arg) ++{ ++ etap_change(ADD_ADDR, addr, netmask, *((int *) arg)); ++} ++ ++static void etap_close_addr(unsigned char *addr, unsigned char *netmask, ++ void *arg) ++{ ++ etap_change(DEL_ADDR, addr, netmask, *((int *) arg)); ++} ++ ++struct etap_pre_exec_data { ++ int control_remote; ++ int control_me; ++ int data_me; ++}; ++ ++static void etap_pre_exec(void *arg) ++{ ++ struct etap_pre_exec_data *data = arg; ++ ++ dup2(data->control_remote, 1); ++ os_close_file(data->data_me); ++ os_close_file(data->control_me); ++} ++ ++static int etap_tramp(char *dev, char *gate, int control_me, ++ int control_remote, int data_me, int data_remote) ++{ ++ struct etap_pre_exec_data pe_data; ++ int pid, status, err, n; ++ char version_buf[sizeof("nnnnn\0")]; ++ char data_fd_buf[sizeof("nnnnnn\0")]; ++ char gate_buf[sizeof("nnn.nnn.nnn.nnn\0")]; ++ char *setup_args[] = { "uml_net", version_buf, "ethertap", dev, ++ data_fd_buf, gate_buf, NULL }; ++ char *nosetup_args[] = { "uml_net", version_buf, "ethertap", ++ dev, data_fd_buf, NULL }; ++ char **args, c; ++ ++ sprintf(data_fd_buf, "%d", data_remote); ++ sprintf(version_buf, "%d", UML_NET_VERSION); ++ if(gate != NULL){ ++ strcpy(gate_buf, gate); ++ args = setup_args; ++ } ++ else args = nosetup_args; ++ ++ err = 0; ++ pe_data.control_remote = control_remote; ++ pe_data.control_me = control_me; ++ pe_data.data_me = data_me; ++ pid = run_helper(etap_pre_exec, &pe_data, args, NULL); ++ ++ if(pid < 0) err = pid; ++ os_close_file(data_remote); ++ os_close_file(control_remote); ++ n = os_read_file(control_me, &c, sizeof(c)); ++ if(n != sizeof(c)){ ++ printk("etap_tramp : read of status failed, err = %d\n", -n); ++ return(-EINVAL); ++ } ++ if(c != 1){ ++ printk("etap_tramp : uml_net failed\n"); ++ err = -EINVAL; ++ if(waitpid(pid, &status, 0) < 0) ++ err = -errno; ++ else if(!WIFEXITED(status) || (WEXITSTATUS(status) != 1)) ++ printk("uml_net didn't exit with status 1\n"); ++ } ++ return(err); ++} ++ ++static int etap_open(void *data) ++{ ++ struct ethertap_data *pri = data; ++ char *output; ++ int data_fds[2], control_fds[2], err, output_len; ++ ++ err = tap_open_common(pri->dev, pri->gate_addr); ++ if(err) return(err); ++ ++ err = os_pipe(data_fds, 0, 0); ++ if(err < 0){ ++ printk("data os_pipe failed - err = %d\n", -err); ++ return(err); ++ } ++ ++ err = os_pipe(control_fds, 1, 0); ++ if(err < 0){ ++ printk("control os_pipe failed - err = %d\n", -err); ++ return(err); ++ } ++ ++ err = etap_tramp(pri->dev_name, pri->gate_addr, control_fds[0], ++ control_fds[1], data_fds[0], data_fds[1]); ++ output_len = page_size(); ++ output = um_kmalloc(output_len); ++ read_output(control_fds[0], output, output_len); ++ ++ if(output == NULL) ++ printk("etap_open : failed to allocate output buffer\n"); ++ else { ++ printk("%s", output); ++ kfree(output); ++ } ++ ++ if(err < 0){ ++ printk("etap_tramp failed - err = %d\n", -err); ++ return(err); ++ } ++ ++ pri->data_fd = data_fds[0]; ++ pri->control_fd = control_fds[0]; ++ iter_addresses(pri->dev, etap_open_addr, &pri->control_fd); ++ return(data_fds[0]); ++} ++ ++static void etap_close(int fd, void *data) ++{ ++ struct ethertap_data *pri = data; ++ ++ iter_addresses(pri->dev, etap_close_addr, &pri->control_fd); ++ os_close_file(fd); ++ os_shutdown_socket(pri->data_fd, 1, 1); ++ os_close_file(pri->data_fd); ++ pri->data_fd = -1; ++ os_close_file(pri->control_fd); ++ pri->control_fd = -1; ++} ++ ++static int etap_set_mtu(int mtu, void *data) ++{ ++ return(mtu); ++} ++ ++static void etap_add_addr(unsigned char *addr, unsigned char *netmask, ++ void *data) ++{ ++ struct ethertap_data *pri = data; ++ ++ tap_check_ips(pri->gate_addr, addr); ++ if(pri->control_fd == -1) return; ++ etap_open_addr(addr, netmask, &pri->control_fd); ++} ++ ++static void etap_del_addr(unsigned char *addr, unsigned char *netmask, ++ void *data) ++{ ++ struct ethertap_data *pri = data; ++ ++ if(pri->control_fd == -1) return; ++ etap_close_addr(addr, netmask, &pri->control_fd); ++} ++ ++struct net_user_info ethertap_user_info = { ++ .init = etap_user_init, ++ .open = etap_open, ++ .close = etap_close, ++ .remove = NULL, ++ .set_mtu = etap_set_mtu, ++ .add_address = etap_add_addr, ++ .delete_address = etap_del_addr, ++ .max_packet = MAX_PACKET - ETH_HEADER_ETHERTAP ++}; ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/os-Linux/drivers/Makefile um/arch/um/os-Linux/drivers/Makefile +--- orig/arch/um/os-Linux/drivers/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/os-Linux/drivers/Makefile 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,31 @@ ++# ++# Copyright (C) 2000, 2002 Jeff Dike (jdike@karaya.com) ++# Licensed under the GPL ++# ++ ++O_TARGET := drivers.o ++ ++list-multi := tuntap.o ethertap.o ++ ++ethertap-objs := ethertap_kern.o ethertap_user.o ++tuntap-objs := tuntap_kern.o tuntap_user.o ++ ++obj-y = ++obj-$(CONFIG_UML_NET_ETHERTAP) += ethertap.o ++obj-$(CONFIG_UML_NET_TUNTAP) += tuntap.o ++ ++USER_SINGLE_OBJS = $(foreach f,$(patsubst %.o,%,$(obj-y)),$($(f)-objs)) ++ ++USER_OBJS = $(filter %_user.o,$(obj-y) $(USER_SINGLE_OBJS)) ++ ++include $(TOPDIR)/Rules.make ++ ++$(USER_OBJS) : %.o: %.c ++ $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< ++ ++ethertap.o : $(ethertap-objs) ++ ++tuntap.o : $(tuntap-objs) ++ ++$(list-multi) : # This doesn't work, but should : '%.o : $(%-objs)' ++ $(LD) $(LD_RFLAG) -r -o $@ $($(patsubst %.o,%,$@)-objs) +diff -Naur -X ../exclude-files orig/arch/um/os-Linux/drivers/tuntap.h um/arch/um/os-Linux/drivers/tuntap.h +--- orig/arch/um/os-Linux/drivers/tuntap.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/os-Linux/drivers/tuntap.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,32 @@ ++/* ++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UM_TUNTAP_H ++#define __UM_TUNTAP_H ++ ++#include "net_user.h" ++ ++struct tuntap_data { ++ char *dev_name; ++ int fixed_config; ++ char *gate_addr; ++ int fd; ++ void *dev; ++}; ++ ++extern struct net_user_info tuntap_user_info; ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/os-Linux/drivers/tuntap_kern.c um/arch/um/os-Linux/drivers/tuntap_kern.c +--- orig/arch/um/os-Linux/drivers/tuntap_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/os-Linux/drivers/tuntap_kern.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,105 @@ ++/* ++ * Copyright (C) 2001 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/stddef.h" ++#include "linux/netdevice.h" ++#include "linux/etherdevice.h" ++#include "linux/skbuff.h" ++#include "linux/init.h" ++#include "asm/errno.h" ++#include "net_kern.h" ++#include "net_user.h" ++#include "tuntap.h" ++ ++struct tuntap_init { ++ char *dev_name; ++ char *gate_addr; ++}; ++ ++static void tuntap_init(struct net_device *dev, void *data) ++{ ++ struct uml_net_private *pri; ++ struct tuntap_data *tpri; ++ struct tuntap_init *init = data; ++ ++ init_etherdev(dev, 0); ++ pri = dev->priv; ++ tpri = (struct tuntap_data *) pri->user; ++ *tpri = ((struct tuntap_data) ++ { .dev_name = init->dev_name, ++ .fixed_config = (init->dev_name != NULL), ++ .gate_addr = init->gate_addr, ++ .fd = -1, ++ .dev = dev }); ++ printk("TUN/TAP backend - "); ++ if(tpri->gate_addr != NULL) ++ printk("IP = %s", tpri->gate_addr); ++ printk("\n"); ++} ++ ++static int tuntap_read(int fd, struct sk_buff **skb, ++ struct uml_net_private *lp) ++{ ++ *skb = ether_adjust_skb(*skb, ETH_HEADER_OTHER); ++ if(*skb == NULL) return(-ENOMEM); ++ return(net_read(fd, (*skb)->mac.raw, ++ (*skb)->dev->mtu + ETH_HEADER_OTHER)); ++} ++ ++static int tuntap_write(int fd, struct sk_buff **skb, ++ struct uml_net_private *lp) ++{ ++ return(net_write(fd, (*skb)->data, (*skb)->len)); ++} ++ ++struct net_kern_info tuntap_kern_info = { ++ .init = tuntap_init, ++ .protocol = eth_protocol, ++ .read = tuntap_read, ++ .write = tuntap_write, ++}; ++ ++int tuntap_setup(char *str, char **mac_out, void *data) ++{ ++ struct tuntap_init *init = data; ++ ++ *init = ((struct tuntap_init) ++ { .dev_name = NULL, ++ .gate_addr = NULL }); ++ if(tap_setup_common(str, "tuntap", &init->dev_name, mac_out, ++ &init->gate_addr)) ++ return(0); ++ ++ return(1); ++} ++ ++static struct transport tuntap_transport = { ++ .list = LIST_HEAD_INIT(tuntap_transport.list), ++ .name = "tuntap", ++ .setup = tuntap_setup, ++ .user = &tuntap_user_info, ++ .kern = &tuntap_kern_info, ++ .private_size = sizeof(struct tuntap_data), ++ .setup_size = sizeof(struct tuntap_init), ++}; ++ ++static int register_tuntap(void) ++{ ++ register_transport(&tuntap_transport); ++ return(1); ++} ++ ++__initcall(register_tuntap); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/os-Linux/drivers/tuntap_user.c um/arch/um/os-Linux/drivers/tuntap_user.c +--- orig/arch/um/os-Linux/drivers/tuntap_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/os-Linux/drivers/tuntap_user.c 2003-11-12 00:02:30.000000000 -0500 +@@ -0,0 +1,224 @@ ++/* ++ * Copyright (C) 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdio.h> ++#include <stddef.h> ++#include <stdlib.h> ++#include <unistd.h> ++#include <errno.h> ++#include <sys/wait.h> ++#include <sys/socket.h> ++#include <sys/un.h> ++#include <sys/uio.h> ++#include <sys/ioctl.h> ++#include <net/if.h> ++#include <linux/if_tun.h> ++#include "net_user.h" ++#include "tuntap.h" ++#include "kern_util.h" ++#include "user.h" ++#include "helper.h" ++#include "os.h" ++ ++#define MAX_PACKET ETH_MAX_PACKET ++ ++void tuntap_user_init(void *data, void *dev) ++{ ++ struct tuntap_data *pri = data; ++ ++ pri->dev = dev; ++} ++ ++static void tuntap_add_addr(unsigned char *addr, unsigned char *netmask, ++ void *data) ++{ ++ struct tuntap_data *pri = data; ++ ++ tap_check_ips(pri->gate_addr, addr); ++ if((pri->fd == -1) || pri->fixed_config) return; ++ open_addr(addr, netmask, pri->dev_name); ++} ++ ++static void tuntap_del_addr(unsigned char *addr, unsigned char *netmask, ++ void *data) ++{ ++ struct tuntap_data *pri = data; ++ ++ if((pri->fd == -1) || pri->fixed_config) return; ++ close_addr(addr, netmask, pri->dev_name); ++} ++ ++struct tuntap_pre_exec_data { ++ int stdout; ++ int close_me; ++}; ++ ++static void tuntap_pre_exec(void *arg) ++{ ++ struct tuntap_pre_exec_data *data = arg; ++ ++ dup2(data->stdout, 1); ++ os_close_file(data->close_me); ++} ++ ++static int tuntap_open_tramp(char *gate, int *fd_out, int me, int remote, ++ char *buffer, int buffer_len, int *used_out) ++{ ++ struct tuntap_pre_exec_data data; ++ char version_buf[sizeof("nnnnn\0")]; ++ char *argv[] = { "uml_net", version_buf, "tuntap", "up", gate, ++ NULL }; ++ char buf[CMSG_SPACE(sizeof(*fd_out))]; ++ struct msghdr msg; ++ struct cmsghdr *cmsg; ++ struct iovec iov; ++ int pid, n; ++ ++ sprintf(version_buf, "%d", UML_NET_VERSION); ++ ++ data.stdout = remote; ++ data.close_me = me; ++ ++ pid = run_helper(tuntap_pre_exec, &data, argv, NULL); ++ ++ if(pid < 0) return(-pid); ++ ++ os_close_file(remote); ++ ++ msg.msg_name = NULL; ++ msg.msg_namelen = 0; ++ if(buffer != NULL){ ++ iov = ((struct iovec) { buffer, buffer_len }); ++ msg.msg_iov = &iov; ++ msg.msg_iovlen = 1; ++ } ++ else { ++ msg.msg_iov = NULL; ++ msg.msg_iovlen = 0; ++ } ++ msg.msg_control = buf; ++ msg.msg_controllen = sizeof(buf); ++ msg.msg_flags = 0; ++ n = recvmsg(me, &msg, 0); ++ *used_out = n; ++ if(n < 0){ ++ printk("tuntap_open_tramp : recvmsg failed - errno = %d\n", ++ errno); ++ return(-errno); ++ } ++ waitpid(pid, NULL, 0); ++ ++ cmsg = CMSG_FIRSTHDR(&msg); ++ if(cmsg == NULL){ ++ printk("tuntap_open_tramp : didn't receive a message\n"); ++ return(-EINVAL); ++ } ++ if((cmsg->cmsg_level != SOL_SOCKET) || ++ (cmsg->cmsg_type != SCM_RIGHTS)){ ++ printk("tuntap_open_tramp : didn't receive a descriptor\n"); ++ return(-EINVAL); ++ } ++ *fd_out = ((int *) CMSG_DATA(cmsg))[0]; ++ return(0); ++} ++ ++static int tuntap_open(void *data) ++{ ++ struct ifreq ifr; ++ struct tuntap_data *pri = data; ++ char *output, *buffer; ++ int err, fds[2], len, used; ++ ++ err = tap_open_common(pri->dev, pri->gate_addr); ++ if(err < 0) ++ return(err); ++ ++ if(pri->fixed_config){ ++ pri->fd = os_open_file("/dev/net/tun", of_rdwr(OPENFLAGS()), 0); ++ if(pri->fd < 0){ ++ printk("Failed to open /dev/net/tun, err = %d\n", ++ -pri->fd); ++ return(pri->fd); ++ } ++ memset(&ifr, 0, sizeof(ifr)); ++ ifr.ifr_flags = IFF_TAP | IFF_NO_PI; ++ strncpy(ifr.ifr_name, pri->dev_name, sizeof(ifr.ifr_name) - 1); ++ if(ioctl(pri->fd, TUNSETIFF, (void *) &ifr) < 0){ ++ printk("TUNSETIFF failed, errno = %d\n", errno); ++ os_close_file(pri->fd); ++ return(-errno); ++ } ++ } ++ else { ++ err = os_pipe(fds, 0, 0); ++ if(err < 0){ ++ printk("tuntap_open : os_pipe failed - err = %d\n", ++ -err); ++ return(err); ++ } ++ ++ buffer = get_output_buffer(&len); ++ if(buffer != NULL) len--; ++ used = 0; ++ ++ err = tuntap_open_tramp(pri->gate_addr, &pri->fd, fds[0], ++ fds[1], buffer, len, &used); ++ ++ output = buffer; ++ if(err < 0) { ++ printk("%s", output); ++ free_output_buffer(buffer); ++ printk("tuntap_open_tramp failed - err = %d\n", -err); ++ return(err); ++ } ++ ++ pri->dev_name = uml_strdup(buffer); ++ output += IFNAMSIZ; ++ printk("%s", output); ++ free_output_buffer(buffer); ++ ++ os_close_file(fds[0]); ++ iter_addresses(pri->dev, open_addr, pri->dev_name); ++ } ++ ++ return(pri->fd); ++} ++ ++static void tuntap_close(int fd, void *data) ++{ ++ struct tuntap_data *pri = data; ++ ++ if(!pri->fixed_config) ++ iter_addresses(pri->dev, close_addr, pri->dev_name); ++ os_close_file(fd); ++ pri->fd = -1; ++} ++ ++static int tuntap_set_mtu(int mtu, void *data) ++{ ++ return(mtu); ++} ++ ++struct net_user_info tuntap_user_info = { ++ .init = tuntap_user_init, ++ .open = tuntap_open, ++ .close = tuntap_close, ++ .remove = NULL, ++ .set_mtu = tuntap_set_mtu, ++ .add_address = tuntap_add_addr, ++ .delete_address = tuntap_del_addr, ++ .max_packet = MAX_PACKET ++}; ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/os-Linux/file.c um/arch/um/os-Linux/file.c +--- orig/arch/um/os-Linux/file.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/os-Linux/file.c 2003-11-30 20:18:39.000000000 -0500 +@@ -0,0 +1,669 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdio.h> ++#include <unistd.h> ++#include <errno.h> ++#include <fcntl.h> ++#include <signal.h> ++#include <sys/types.h> ++#include <sys/stat.h> ++#include <sys/socket.h> ++#include <sys/un.h> ++#include <sys/ioctl.h> ++#include <sys/mount.h> ++#include <sys/uio.h> ++#include "os.h" ++#include "user.h" ++#include "kern_util.h" ++ ++static void copy_stat(struct uml_stat *dst, struct stat64 *src) ++{ ++ *dst = ((struct uml_stat) { ++ .ust_dev = src->st_dev, /* device */ ++ .ust_ino = src->st_ino, /* inode */ ++ .ust_mode = src->st_mode, /* protection */ ++ .ust_nlink = src->st_nlink, /* number of hard links */ ++ .ust_uid = src->st_uid, /* user ID of owner */ ++ .ust_gid = src->st_gid, /* group ID of owner */ ++ .ust_size = src->st_size, /* total size, in bytes */ ++ .ust_blksize = src->st_blksize, /* blocksize for filesys I/O */ ++ .ust_blocks = src->st_blocks, /* number of blocks allocated */ ++ .ust_atime = src->st_atime, /* time of last access */ ++ .ust_mtime = src->st_mtime, /* time of last modification */ ++ .ust_ctime = src->st_ctime, /* time of last change */ ++ }); ++} ++ ++int os_stat_fd(const int fd, struct uml_stat *ubuf) ++{ ++ struct stat64 sbuf; ++ int err; ++ ++ do { ++ err = fstat64(fd, &sbuf); ++ } while((err < 0) && (errno == EINTR)) ; ++ ++ if(err < 0) ++ return(-errno); ++ ++ if(ubuf != NULL) ++ copy_stat(ubuf, &sbuf); ++ return(err); ++} ++ ++int os_stat_file(const char *file_name, struct uml_stat *ubuf) ++{ ++ struct stat64 sbuf; ++ int err; ++ ++ do { ++ err = stat64(file_name, &sbuf); ++ } while((err < 0) && (errno == EINTR)) ; ++ ++ if(err < 0) ++ return(-errno); ++ ++ if(ubuf != NULL) ++ copy_stat(ubuf, &sbuf); ++ return(err); ++} ++ ++int os_access(const char* file, int mode) ++{ ++ int amode, err; ++ ++ amode=(mode&OS_ACC_R_OK ? R_OK : 0) | (mode&OS_ACC_W_OK ? W_OK : 0) | ++ (mode&OS_ACC_X_OK ? X_OK : 0) | (mode&OS_ACC_F_OK ? F_OK : 0) ; ++ ++ err = access(file, amode); ++ if(err < 0) ++ return(-errno); ++ ++ return(0); ++} ++ ++void os_print_error(int error, const char* str) ++{ ++ errno = error < 0 ? -error : error; ++ ++ perror(str); ++} ++ ++/* FIXME? required only by hostaudio (because it passes ioctls verbatim) */ ++int os_ioctl_generic(int fd, unsigned int cmd, unsigned long arg) ++{ ++ int err; ++ ++ err = ioctl(fd, cmd, arg); ++ if(err < 0) ++ return(-errno); ++ ++ return(err); ++} ++ ++int os_window_size(int fd, int *rows, int *cols) ++{ ++ struct winsize size; ++ ++ if(ioctl(fd, TIOCGWINSZ, &size) < 0) ++ return(-errno); ++ ++ *rows = size.ws_row; ++ *cols = size.ws_col; ++ ++ return(0); ++} ++ ++int os_new_tty_pgrp(int fd, int pid) ++{ ++ if(ioctl(fd, TIOCSCTTY, 0) < 0){ ++ printk("TIOCSCTTY failed, errno = %d\n", errno); ++ return(-errno); ++ } ++ ++ if(tcsetpgrp(fd, pid) < 0){ ++ printk("tcsetpgrp failed, errno = %d\n", errno); ++ return(-errno); ++ } ++ ++ return(0); ++} ++ ++/* FIXME: ensure namebuf in os_get_if_name is big enough */ ++int os_get_ifname(int fd, char* namebuf) ++{ ++ if(ioctl(fd, SIOCGIFNAME, namebuf) < 0) ++ return(-errno); ++ ++ return(0); ++} ++ ++int os_set_slip(int fd) ++{ ++ int disc, sencap; ++ ++ disc = N_SLIP; ++ if(ioctl(fd, TIOCSETD, &disc) < 0){ ++ printk("Failed to set slip line discipline - " ++ "errno = %d\n", errno); ++ return(-errno); ++ } ++ ++ sencap = 0; ++ if(ioctl(fd, SIOCSIFENCAP, &sencap) < 0){ ++ printk("Failed to set slip encapsulation - " ++ "errno = %d\n", errno); ++ return(-errno); ++ } ++ ++ return(0); ++} ++ ++int os_set_owner(int fd, int pid) ++{ ++ if(fcntl(fd, F_SETOWN, pid) < 0){ ++ int save_errno = errno; ++ ++ if(fcntl(fd, F_GETOWN, 0) != pid){ ++ return(-save_errno); ++ } ++ } ++ ++ return(0); ++} ++ ++/* FIXME? moved wholesale from sigio_user.c to get fcntls out of that file */ ++int os_sigio_async(int master, int slave) ++{ ++ int flags; ++ ++ flags = fcntl(master, F_GETFL); ++ if(flags < 0) { ++ printk("fcntl F_GETFL failed, errno = %d\n", errno); ++ return(-errno); ++ } ++ ++ if((fcntl(master, F_SETFL, flags | O_NONBLOCK | O_ASYNC) < 0) || ++ (fcntl(master, F_SETOWN, os_getpid()) < 0)){ ++ printk("fcntl F_SETFL or F_SETOWN failed, errno = %d\n", errno); ++ return(-errno); ++ } ++ ++ if((fcntl(slave, F_SETFL, flags | O_NONBLOCK) < 0)){ ++ printk("fcntl F_SETFL failed, errno = %d\n", errno); ++ return(-errno); ++ } ++ ++ return(0); ++} ++ ++int os_mode_fd(int fd, int mode) ++{ ++ int err; ++ ++ do { ++ err = fchmod(fd, mode); ++ } while((err < 0) && (errno==EINTR)) ; ++ ++ if(err < 0) ++ return(-errno); ++ ++ return(0); ++} ++ ++int os_file_type(char *file) ++{ ++ struct uml_stat buf; ++ int err; ++ ++ err = os_stat_file(file, &buf); ++ if(err < 0) ++ return(err); ++ ++ if(S_ISDIR(buf.ust_mode)) return(OS_TYPE_DIR); ++ else if(S_ISLNK(buf.ust_mode)) return(OS_TYPE_SYMLINK); ++ else if(S_ISCHR(buf.ust_mode)) return(OS_TYPE_CHARDEV); ++ else if(S_ISBLK(buf.ust_mode)) return(OS_TYPE_BLOCKDEV); ++ else if(S_ISFIFO(buf.ust_mode)) return(OS_TYPE_FIFO); ++ else if(S_ISSOCK(buf.ust_mode)) return(OS_TYPE_SOCK); ++ else return(OS_TYPE_FILE); ++} ++ ++int os_file_mode(char *file, struct openflags *mode_out) ++{ ++ int err; ++ ++ *mode_out = OPENFLAGS(); ++ ++ err = os_access(file, OS_ACC_W_OK); ++ if((err < 0) && (err != -EACCES)) ++ return(err); ++ ++ *mode_out = of_write(*mode_out); ++ ++ err = os_access(file, OS_ACC_R_OK); ++ if((err < 0) && (err != -EACCES)) ++ return(err); ++ ++ *mode_out = of_read(*mode_out); ++ ++ return(0); ++} ++ ++int os_open_file(char *file, struct openflags flags, int mode) ++{ ++ int fd, f = 0; ++ ++ if(flags.r && flags.w) f = O_RDWR; ++ else if(flags.r) f = O_RDONLY; ++ else if(flags.w) f = O_WRONLY; ++ else f = 0; ++ ++ if(flags.s) f |= O_SYNC; ++ if(flags.c) f |= O_CREAT; ++ if(flags.t) f |= O_TRUNC; ++ if(flags.e) f |= O_EXCL; ++ ++ fd = open64(file, f, mode); ++ if(fd < 0) ++ return(-errno); ++ ++ if(flags.cl && fcntl(fd, F_SETFD, 1)){ ++ os_close_file(fd); ++ return(-errno); ++ } ++ ++ return(fd); ++} ++ ++int os_connect_socket(char *name) ++{ ++ struct sockaddr_un sock; ++ int fd, err; ++ ++ sock.sun_family = AF_UNIX; ++ snprintf(sock.sun_path, sizeof(sock.sun_path), "%s", name); ++ ++ fd = socket(AF_UNIX, SOCK_STREAM, 0); ++ if(fd < 0) ++ return(fd); ++ ++ err = connect(fd, (struct sockaddr *) &sock, sizeof(sock)); ++ if(err) ++ return(-errno); ++ ++ return(fd); ++} ++ ++void os_close_file(int fd) ++{ ++ close(fd); ++} ++ ++int os_seek_file(int fd, __u64 offset) ++{ ++ __u64 actual; ++ ++ actual = lseek64(fd, offset, SEEK_SET); ++ if(actual != offset) return(-errno); ++ return(0); ++} ++ ++static int fault_buffer(void *start, int len, ++ int (*copy_proc)(void *addr, void *buf, int len)) ++{ ++ int page = getpagesize(), i; ++ char c; ++ ++ for(i = 0; i < len; i += page){ ++ if((*copy_proc)(start + i, &c, sizeof(c))) ++ return(-EFAULT); ++ } ++ if((len % page) != 0){ ++ if((*copy_proc)(start + len - 1, &c, sizeof(c))) ++ return(-EFAULT); ++ } ++ return(0); ++} ++ ++static int file_io(int fd, void *buf, int len, ++ int (*io_proc)(int fd, void *buf, int len), ++ int (*copy_user_proc)(void *addr, void *buf, int len)) ++{ ++ int n, err; ++ ++ do { ++ n = (*io_proc)(fd, buf, len); ++ if((n < 0) && (errno == EFAULT)){ ++ err = fault_buffer(buf, len, copy_user_proc); ++ if(err) ++ return(err); ++ n = (*io_proc)(fd, buf, len); ++ } ++ } while((n < 0) && (errno == EINTR)); ++ ++ if(n < 0) ++ return(-errno); ++ return(n); ++} ++ ++int os_read_file(int fd, void *buf, int len) ++{ ++ return(file_io(fd, buf, len, (int (*)(int, void *, int)) read, ++ copy_from_user_proc)); ++} ++ ++int os_write_file(int fd, const void *buf, int len) ++{ ++ return(file_io(fd, (void *) buf, len, ++ (int (*)(int, void *, int)) write, copy_to_user_proc)); ++} ++ ++int os_file_size(char *file, long long *size_out) ++{ ++ struct uml_stat buf; ++ int err; ++ ++ err = os_stat_file(file, &buf); ++ if(err < 0){ ++ printk("Couldn't stat \"%s\" : err = %d\n", file, -err); ++ return(err); ++ } ++ ++ if(S_ISBLK(buf.ust_mode)){ ++ int fd, blocks; ++ ++ fd = os_open_file(file, of_read(OPENFLAGS()), 0); ++ if(fd < 0){ ++ printk("Couldn't open \"%s\", errno = %d\n", file, -fd); ++ return(fd); ++ } ++ if(ioctl(fd, BLKGETSIZE, &blocks) < 0){ ++ printk("Couldn't get the block size of \"%s\", " ++ "errno = %d\n", file, errno); ++ err = -errno; ++ os_close_file(fd); ++ return(err); ++ } ++ *size_out = ((long long) blocks) * 512; ++ os_close_file(fd); ++ return(0); ++ } ++ *size_out = buf.ust_size; ++ return(0); ++} ++ ++int os_file_modtime(char *file, unsigned long *modtime) ++{ ++ struct uml_stat buf; ++ int err; ++ ++ err = os_stat_file(file, &buf); ++ if(err < 0){ ++ printk("Couldn't stat \"%s\" : err = %d\n", file, -err); ++ return(err); ++ } ++ ++ *modtime = buf.ust_mtime; ++ return(0); ++} ++ ++int os_get_exec_close(int fd, int* close_on_exec) ++{ ++ int ret; ++ ++ do { ++ ret = fcntl(fd, F_GETFD); ++ } while((ret < 0) && (errno == EINTR)) ; ++ ++ if(ret < 0) ++ return(-errno); ++ ++ *close_on_exec = (ret&FD_CLOEXEC) ? 1 : 0; ++ return(ret); ++} ++ ++int os_set_exec_close(int fd, int close_on_exec) ++{ ++ int flag, err; ++ ++ if(close_on_exec) flag = FD_CLOEXEC; ++ else flag = 0; ++ ++ do { ++ err = fcntl(fd, F_SETFD, flag); ++ } while((err < 0) && (errno == EINTR)) ; ++ ++ if(err < 0) ++ return(-errno); ++ return(err); ++} ++ ++int os_pipe(int *fds, int stream, int close_on_exec) ++{ ++ int err, type = stream ? SOCK_STREAM : SOCK_DGRAM; ++ ++ err = socketpair(AF_UNIX, type, 0, fds); ++ if(err < 0) ++ return(-errno); ++ ++ if(!close_on_exec) ++ return(0); ++ ++ err = os_set_exec_close(fds[0], 1); ++ if(err < 0) ++ goto error; ++ ++ err = os_set_exec_close(fds[1], 1); ++ if(err < 0) ++ goto error; ++ ++ return(0); ++ ++ error: ++ printk("os_pipe : Setting FD_CLOEXEC failed, err = %d\n", -err); ++ os_close_file(fds[1]); ++ os_close_file(fds[0]); ++ return(err); ++} ++ ++int os_set_fd_async(int fd, int owner) ++{ ++ /* XXX This should do F_GETFL first */ ++ if(fcntl(fd, F_SETFL, O_ASYNC | O_NONBLOCK) < 0){ ++ printk("os_set_fd_async : failed to set O_ASYNC and " ++ "O_NONBLOCK on fd # %d, errno = %d\n", fd, errno); ++ return(-errno); ++ } ++#ifdef notdef ++ if(fcntl(fd, F_SETFD, 1) < 0){ ++ printk("os_set_fd_async : Setting FD_CLOEXEC failed, " ++ "errno = %d\n", errno); ++ } ++#endif ++ ++ if((fcntl(fd, F_SETSIG, SIGIO) < 0) || ++ (fcntl(fd, F_SETOWN, owner) < 0)){ ++ printk("os_set_fd_async : Failed to fcntl F_SETOWN " ++ "(or F_SETSIG) fd %d to pid %d, errno = %d\n", fd, ++ owner, errno); ++ return(-errno); ++ } ++ ++ return(0); ++} ++ ++int os_set_fd_block(int fd, int blocking) ++{ ++ int flags; ++ ++ flags = fcntl(fd, F_GETFL); ++ ++ if(blocking) flags &= ~O_NONBLOCK; ++ else flags |= O_NONBLOCK; ++ ++ if(fcntl(fd, F_SETFL, flags) < 0){ ++ printk("Failed to change blocking on fd # %d, errno = %d\n", ++ fd, errno); ++ return(-errno); ++ } ++ return(0); ++} ++ ++int os_accept_connection(int fd) ++{ ++ int new; ++ ++ new = accept(fd, NULL, 0); ++ if(new < 0) ++ return(-errno); ++ return(new); ++} ++ ++#ifndef SHUT_RD ++#define SHUT_RD 0 ++#endif ++ ++#ifndef SHUT_WR ++#define SHUT_WR 1 ++#endif ++ ++#ifndef SHUT_RDWR ++#define SHUT_RDWR 2 ++#endif ++ ++int os_shutdown_socket(int fd, int r, int w) ++{ ++ int what, err; ++ ++ if(r && w) what = SHUT_RDWR; ++ else if(r) what = SHUT_RD; ++ else if(w) what = SHUT_WR; ++ else { ++ printk("os_shutdown_socket : neither r or w was set\n"); ++ return(-EINVAL); ++ } ++ err = shutdown(fd, what); ++ if(err < 0) ++ return(-errno); ++ return(0); ++} ++ ++int os_rcv_fd(int fd, int *helper_pid_out) ++{ ++ int new, n; ++ char buf[CMSG_SPACE(sizeof(new))]; ++ struct msghdr msg; ++ struct cmsghdr *cmsg; ++ struct iovec iov; ++ ++ msg.msg_name = NULL; ++ msg.msg_namelen = 0; ++ iov = ((struct iovec) { .iov_base = helper_pid_out, ++ .iov_len = sizeof(*helper_pid_out) }); ++ msg.msg_iov = &iov; ++ msg.msg_iovlen = 1; ++ msg.msg_control = buf; ++ msg.msg_controllen = sizeof(buf); ++ msg.msg_flags = 0; ++ ++ n = recvmsg(fd, &msg, 0); ++ if(n < 0) ++ return(-errno); ++ ++ else if(n != sizeof(iov.iov_len)) ++ *helper_pid_out = -1; ++ ++ cmsg = CMSG_FIRSTHDR(&msg); ++ if(cmsg == NULL){ ++ printk("rcv_fd didn't receive anything, error = %d\n", errno); ++ return(-1); ++ } ++ if((cmsg->cmsg_level != SOL_SOCKET) || ++ (cmsg->cmsg_type != SCM_RIGHTS)){ ++ printk("rcv_fd didn't receive a descriptor\n"); ++ return(-1); ++ } ++ ++ new = ((int *) CMSG_DATA(cmsg))[0]; ++ return(new); ++} ++ ++int os_create_unix_socket(char *file, int len, int close_on_exec) ++{ ++ struct sockaddr_un addr; ++ int sock, err; ++ ++ sock = socket(PF_UNIX, SOCK_DGRAM, 0); ++ if (sock < 0){ ++ printk("create_unix_socket - socket failed, errno = %d\n", ++ errno); ++ return(-errno); ++ } ++ ++ if(close_on_exec) { ++ err = os_set_exec_close(sock, 1); ++ if(err < 0) ++ printk("create_unix_socket : close_on_exec failed, " ++ "err = %d", -err); ++ } ++ ++ addr.sun_family = AF_UNIX; ++ ++ /* XXX Be more careful about overflow */ ++ snprintf(addr.sun_path, len, "%s", file); ++ ++ err = bind(sock, (struct sockaddr *) &addr, sizeof(addr)); ++ if (err < 0){ ++ printk("create_listening_socket at '%s' - bind failed, " ++ "errno = %d\n", file, errno); ++ return(-errno); ++ } ++ ++ return(sock); ++} ++ ++void os_flush_stdout(void) ++{ ++ fflush(stdout); ++} ++ ++int os_lock_file(int fd, int excl) ++{ ++ int type = excl ? F_WRLCK : F_RDLCK; ++ struct flock lock = ((struct flock) { .l_type = type, ++ .l_whence = SEEK_SET, ++ .l_start = 0, ++ .l_len = 0 } ); ++ int err, save; ++ ++ err = fcntl(fd, F_SETLK, &lock); ++ if(!err) ++ goto out; ++ ++ save = -errno; ++ err = fcntl(fd, F_GETLK, &lock); ++ if(err){ ++ err = -errno; ++ goto out; ++ } ++ ++ printk("F_SETLK failed, file already locked by pid %d\n", lock.l_pid); ++ err = save; ++ out: ++ return(err); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/os-Linux/include/file.h um/arch/um/os-Linux/include/file.h +--- orig/arch/um/os-Linux/include/file.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/os-Linux/include/file.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,22 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __OS_FILE_H__ ++#define __OS_FILE_H__ ++ ++#define DEV_NULL "/dev/null" ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/os-Linux/Makefile um/arch/um/os-Linux/Makefile +--- orig/arch/um/os-Linux/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/os-Linux/Makefile 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,17 @@ ++# ++# Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++# Licensed under the GPL ++# ++ ++O_TARGET = built-in.o ++ ++obj-y = file.o process.o tty.o ++ ++include $(TOPDIR)/Rules.make ++ ++$(obj-y) : %.o: %.c ++ $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< ++ ++clean : ++ ++archmrproper: +diff -Naur -X ../exclude-files orig/arch/um/os-Linux/process.c um/arch/um/os-Linux/process.c +--- orig/arch/um/os-Linux/process.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/os-Linux/process.c 2003-12-18 03:08:34.000000000 -0500 +@@ -0,0 +1,148 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@addtoit.com) ++ * Licensed under the GPL ++ */ ++ ++#include <unistd.h> ++#include <stdio.h> ++#include <errno.h> ++#include <signal.h> ++#include <sys/mman.h> ++#include <sys/wait.h> ++#include "os.h" ++#include "user.h" ++ ++#define ARBITRARY_ADDR -1 ++#define FAILURE_PID -1 ++ ++unsigned long os_process_pc(int pid) ++{ ++ char proc_stat[sizeof("/proc/#####/stat\0")], buf[256]; ++ unsigned long pc; ++ int fd, err; ++ ++ sprintf(proc_stat, "/proc/%d/stat", pid); ++ fd = os_open_file(proc_stat, of_read(OPENFLAGS()), 0); ++ if(fd < 0){ ++ printk("os_process_pc - couldn't open '%s', err = %d\n", ++ proc_stat, -fd); ++ return(ARBITRARY_ADDR); ++ } ++ err = os_read_file(fd, buf, sizeof(buf)); ++ if(err < 0){ ++ printk("os_process_pc - couldn't read '%s', err = %d\n", ++ proc_stat, -err); ++ os_close_file(fd); ++ return(ARBITRARY_ADDR); ++ } ++ os_close_file(fd); ++ pc = ARBITRARY_ADDR; ++ if(sscanf(buf, "%*d %*s %*c %*d %*d %*d %*d %*d %*d %*d %*d " ++ "%*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d %*d " ++ "%*d %*d %*d %*d %ld", &pc) != 1){ ++ printk("os_process_pc - couldn't find pc in '%s'\n", buf); ++ } ++ return(pc); ++} ++ ++int os_process_parent(int pid) ++{ ++ char stat[sizeof("/proc/nnnnn/stat\0")]; ++ char data[256]; ++ int parent, n, fd; ++ ++ if(pid == -1) return(-1); ++ ++ snprintf(stat, sizeof(stat), "/proc/%d/stat", pid); ++ fd = os_open_file(stat, of_read(OPENFLAGS()), 0); ++ if(fd < 0){ ++ printk("Couldn't open '%s', err = %d\n", stat, -fd); ++ return(FAILURE_PID); ++ } ++ ++ n = os_read_file(fd, data, sizeof(data)); ++ os_close_file(fd); ++ ++ if(n < 0){ ++ printk("Couldn't read '%s', err = %d\n", stat, -n); ++ return(FAILURE_PID); ++ } ++ ++ parent = FAILURE_PID; ++ /* XXX This will break if there is a space in the command */ ++ n = sscanf(data, "%*d %*s %*c %d", &parent); ++ if(n != 1) ++ printk("Failed to scan '%s'\n", data); ++ ++ return(parent); ++} ++ ++void os_stop_process(int pid) ++{ ++ kill(pid, SIGSTOP); ++} ++ ++void os_kill_process(int pid, int reap_child) ++{ ++ kill(pid, SIGKILL); ++ if(reap_child) ++ waitpid(pid, NULL, 0); ++ ++} ++ ++void os_usr1_process(int pid) ++{ ++ kill(pid, SIGUSR1); ++} ++ ++int os_getpid(void) ++{ ++ return(getpid()); ++} ++ ++int os_map_memory(void *virt, int fd, unsigned long long off, unsigned long len, ++ int r, int w, int x) ++{ ++ void *loc; ++ int prot; ++ ++ prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | ++ (x ? PROT_EXEC : 0); ++ ++ loc = mmap64((void *) virt, len, prot, MAP_SHARED | MAP_FIXED, ++ fd, off); ++ if(loc == MAP_FAILED) ++ return(-errno); ++ return(0); ++} ++ ++int os_protect_memory(void *addr, unsigned long len, int r, int w, int x) ++{ ++ int prot = ((r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | ++ (x ? PROT_EXEC : 0)); ++ ++ if(mprotect(addr, len, prot) < 0) ++ return(-errno); ++ return(0); ++} ++ ++int os_unmap_memory(void *addr, int len) ++{ ++ int err; ++ ++ err = munmap(addr, len); ++ if(err < 0) ++ return(-errno); ++ return(0); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/os-Linux/tty.c um/arch/um/os-Linux/tty.c +--- orig/arch/um/os-Linux/tty.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/os-Linux/tty.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,61 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdlib.h> ++#include <errno.h> ++#include "os.h" ++#include "user.h" ++#include "kern_util.h" ++ ++struct grantpt_info { ++ int fd; ++ int res; ++ int err; ++}; ++ ++static void grantpt_cb(void *arg) ++{ ++ struct grantpt_info *info = arg; ++ ++ info->res = grantpt(info->fd); ++ info->err = errno; ++} ++ ++int get_pty(void) ++{ ++ struct grantpt_info info; ++ int fd; ++ ++ fd = os_open_file("/dev/ptmx", of_rdwr(OPENFLAGS()), 0); ++ if(fd < 0){ ++ printk("get_pty : Couldn't open /dev/ptmx - err = %d\n", -fd); ++ return(fd); ++ } ++ ++ info.fd = fd; ++ initial_thread_cb(grantpt_cb, &info); ++ ++ if(info.res < 0){ ++ printk("get_pty : Couldn't grant pty - errno = %d\n", ++ -info.err); ++ return(-1); ++ } ++ if(unlockpt(fd) < 0){ ++ printk("get_pty : Couldn't unlock pty - errno = %d\n", errno); ++ return(-1); ++ } ++ return(fd); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/sys-i386/bugs.c um/arch/um/sys-i386/bugs.c +--- orig/arch/um/sys-i386/bugs.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-i386/bugs.c 2003-11-15 02:54:48.000000000 -0500 +@@ -0,0 +1,221 @@ ++/* ++ * 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 cpu_has_cmov = 1; ++int cpu_has_xmm = 0; ++ ++static char token(int fd, char *buf, int len, char stop) ++{ ++ int n; ++ char *ptr, *end, c; ++ ++ ptr = buf; ++ end = &buf[len]; ++ do { ++ n = 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)) ++ cpu_has_cmov = have_it; ++ if(check_cpu_flag("xmm", &have_it)) ++ cpu_has_xmm = have_it; ++} ++ ++int arch_handle_signal(int sig, union uml_pt_regs *regs) ++{ ++ unsigned long ip; ++ ++ /* This is testing for a cmov (0x0f 0x4x) instruction causing a ++ * SIGILL in init. ++ */ ++ if((sig != SIGILL) || (TASK_PID(get_current()) != 1)) return(0); ++ ++ ip = UPT_IP(regs); ++ if((*((char *) ip) != 0x0f) || ((*((char *) (ip + 1)) & 0xf0) != 0x40)) ++ return(0); ++ ++ if(cpu_has_cmov == 0) ++ panic("SIGILL caused by cmov, which this processor doesn't " ++ "implement, boot a filesystem compiled for older " ++ "processors"); ++ else if(cpu_has_cmov == 1) ++ panic("SIGILL caused by cmov, which this processor claims to " ++ "implement"); ++ else if(cpu_has_cmov == -1) ++ panic("SIGILL caused by cmov, couldn't tell if this processor " ++ "implements it, boot a filesystem compiled for older " ++ "processors"); ++ else panic("Bad value for cpu_has_cmov (%d)", cpu_has_cmov); ++ return(0); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/sys-i386/checksum.S um/arch/um/sys-i386/checksum.S +--- orig/arch/um/sys-i386/checksum.S 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-i386/checksum.S 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,460 @@ ++/* ++ * INET An implementation of the TCP/IP protocol suite for the LINUX ++ * operating system. INET is implemented using the BSD Socket ++ * interface as the means of communication with the user level. ++ * ++ * IP/TCP/UDP checksumming routines ++ * ++ * Authors: Jorge Cwik, <jorge@laser.satlink.net> ++ * Arnt Gulbrandsen, <agulbra@nvg.unit.no> ++ * Tom May, <ftom@netcom.com> ++ * Pentium Pro/II routines: ++ * Alexander Kjeldaas <astor@guardian.no> ++ * Finn Arne Gangstad <finnag@guardian.no> ++ * Lots of code moved from tcp.c and ip.c; see those files ++ * for more names. ++ * ++ * Changes: Ingo Molnar, converted csum_partial_copy() to 2.1 exception ++ * handling. ++ * Andi Kleen, add zeroing on error ++ * converted to pure assembler ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ */ ++ ++#include <linux/config.h> ++#include <asm/errno.h> ++ ++/* ++ * computes a partial checksum, e.g. for TCP/UDP fragments ++ */ ++ ++/* ++unsigned int csum_partial(const unsigned char * buff, int len, unsigned int sum) ++ */ ++ ++.text ++.align 4 ++.globl arch_csum_partial ++ ++#ifndef CONFIG_X86_USE_PPRO_CHECKSUM ++ ++ /* ++ * Experiments with Ethernet and SLIP connections show that buff ++ * is aligned on either a 2-byte or 4-byte boundary. We get at ++ * least a twofold speedup on 486 and Pentium if it is 4-byte aligned. ++ * Fortunately, it is easy to convert 2-byte alignment to 4-byte ++ * alignment for the unrolled loop. ++ */ ++arch_csum_partial: ++ pushl %esi ++ pushl %ebx ++ movl 20(%esp),%eax # Function arg: unsigned int sum ++ movl 16(%esp),%ecx # Function arg: int len ++ movl 12(%esp),%esi # Function arg: unsigned char *buff ++ testl $2, %esi # Check alignment. ++ jz 2f # Jump if alignment is ok. ++ subl $2, %ecx # Alignment uses up two bytes. ++ jae 1f # Jump if we had at least two bytes. ++ addl $2, %ecx # ecx was < 2. Deal with it. ++ jmp 4f ++1: movw (%esi), %bx ++ addl $2, %esi ++ addw %bx, %ax ++ adcl $0, %eax ++2: ++ movl %ecx, %edx ++ shrl $5, %ecx ++ jz 2f ++ testl %esi, %esi ++1: movl (%esi), %ebx ++ adcl %ebx, %eax ++ movl 4(%esi), %ebx ++ adcl %ebx, %eax ++ movl 8(%esi), %ebx ++ adcl %ebx, %eax ++ movl 12(%esi), %ebx ++ adcl %ebx, %eax ++ movl 16(%esi), %ebx ++ adcl %ebx, %eax ++ movl 20(%esi), %ebx ++ adcl %ebx, %eax ++ movl 24(%esi), %ebx ++ adcl %ebx, %eax ++ movl 28(%esi), %ebx ++ adcl %ebx, %eax ++ lea 32(%esi), %esi ++ dec %ecx ++ jne 1b ++ adcl $0, %eax ++2: movl %edx, %ecx ++ andl $0x1c, %edx ++ je 4f ++ shrl $2, %edx # This clears CF ++3: adcl (%esi), %eax ++ lea 4(%esi), %esi ++ dec %edx ++ jne 3b ++ adcl $0, %eax ++4: andl $3, %ecx ++ jz 7f ++ cmpl $2, %ecx ++ jb 5f ++ movw (%esi),%cx ++ leal 2(%esi),%esi ++ je 6f ++ shll $16,%ecx ++5: movb (%esi),%cl ++6: addl %ecx,%eax ++ adcl $0, %eax ++7: ++ popl %ebx ++ popl %esi ++ ret ++ ++#else ++ ++/* Version for PentiumII/PPro */ ++ ++arch_csum_partial: ++ pushl %esi ++ pushl %ebx ++ movl 20(%esp),%eax # Function arg: unsigned int sum ++ movl 16(%esp),%ecx # Function arg: int len ++ movl 12(%esp),%esi # Function arg: const unsigned char *buf ++ ++ testl $2, %esi ++ jnz 30f ++10: ++ movl %ecx, %edx ++ movl %ecx, %ebx ++ andl $0x7c, %ebx ++ shrl $7, %ecx ++ addl %ebx,%esi ++ shrl $2, %ebx ++ negl %ebx ++ lea 45f(%ebx,%ebx,2), %ebx ++ testl %esi, %esi ++ jmp *%ebx ++ ++ # Handle 2-byte-aligned regions ++20: addw (%esi), %ax ++ lea 2(%esi), %esi ++ adcl $0, %eax ++ jmp 10b ++ ++30: subl $2, %ecx ++ ja 20b ++ je 32f ++ movzbl (%esi),%ebx # csumming 1 byte, 2-aligned ++ addl %ebx, %eax ++ adcl $0, %eax ++ jmp 80f ++32: ++ addw (%esi), %ax # csumming 2 bytes, 2-aligned ++ adcl $0, %eax ++ jmp 80f ++ ++40: ++ addl -128(%esi), %eax ++ adcl -124(%esi), %eax ++ adcl -120(%esi), %eax ++ adcl -116(%esi), %eax ++ adcl -112(%esi), %eax ++ adcl -108(%esi), %eax ++ adcl -104(%esi), %eax ++ adcl -100(%esi), %eax ++ adcl -96(%esi), %eax ++ adcl -92(%esi), %eax ++ adcl -88(%esi), %eax ++ adcl -84(%esi), %eax ++ adcl -80(%esi), %eax ++ adcl -76(%esi), %eax ++ adcl -72(%esi), %eax ++ adcl -68(%esi), %eax ++ adcl -64(%esi), %eax ++ adcl -60(%esi), %eax ++ adcl -56(%esi), %eax ++ adcl -52(%esi), %eax ++ adcl -48(%esi), %eax ++ adcl -44(%esi), %eax ++ adcl -40(%esi), %eax ++ adcl -36(%esi), %eax ++ adcl -32(%esi), %eax ++ adcl -28(%esi), %eax ++ adcl -24(%esi), %eax ++ adcl -20(%esi), %eax ++ adcl -16(%esi), %eax ++ adcl -12(%esi), %eax ++ adcl -8(%esi), %eax ++ adcl -4(%esi), %eax ++45: ++ lea 128(%esi), %esi ++ adcl $0, %eax ++ dec %ecx ++ jge 40b ++ movl %edx, %ecx ++50: andl $3, %ecx ++ jz 80f ++ ++ # Handle the last 1-3 bytes without jumping ++ notl %ecx # 1->2, 2->1, 3->0, higher bits are masked ++ movl $0xffffff,%ebx # by the shll and shrl instructions ++ shll $3,%ecx ++ shrl %cl,%ebx ++ andl -128(%esi),%ebx # esi is 4-aligned so should be ok ++ addl %ebx,%eax ++ adcl $0,%eax ++80: ++ popl %ebx ++ popl %esi ++ ret ++ ++#endif ++ ++/* ++unsigned int csum_partial_copy_generic (const char *src, char *dst, ++ int len, int sum, int *src_err_ptr, int *dst_err_ptr) ++ */ ++ ++/* ++ * Copy from ds while checksumming, otherwise like csum_partial ++ * ++ * The macros SRC and DST specify the type of access for the instruction. ++ * thus we can call a custom exception handler for all access types. ++ * ++ * FIXME: could someone double-check whether I haven't mixed up some SRC and ++ * DST definitions? It's damn hard to trigger all cases. I hope I got ++ * them all but there's no guarantee. ++ */ ++ ++#define SRC(y...) \ ++ 9999: y; \ ++ .section __ex_table, "a"; \ ++ .long 9999b, 6001f ; \ ++ .previous ++ ++#define DST(y...) \ ++ 9999: y; \ ++ .section __ex_table, "a"; \ ++ .long 9999b, 6002f ; \ ++ .previous ++ ++.align 4 ++.globl csum_partial_copy_generic_i386 ++ ++#ifndef CONFIG_X86_USE_PPRO_CHECKSUM ++ ++#define ARGBASE 16 ++#define FP 12 ++ ++csum_partial_copy_generic_i386: ++ subl $4,%esp ++ pushl %edi ++ pushl %esi ++ pushl %ebx ++ movl ARGBASE+16(%esp),%eax # sum ++ movl ARGBASE+12(%esp),%ecx # len ++ movl ARGBASE+4(%esp),%esi # src ++ movl ARGBASE+8(%esp),%edi # dst ++ ++ testl $2, %edi # Check alignment. ++ jz 2f # Jump if alignment is ok. ++ subl $2, %ecx # Alignment uses up two bytes. ++ jae 1f # Jump if we had at least two bytes. ++ addl $2, %ecx # ecx was < 2. Deal with it. ++ jmp 4f ++SRC(1: movw (%esi), %bx ) ++ addl $2, %esi ++DST( movw %bx, (%edi) ) ++ addl $2, %edi ++ addw %bx, %ax ++ adcl $0, %eax ++2: ++ movl %ecx, FP(%esp) ++ shrl $5, %ecx ++ jz 2f ++ testl %esi, %esi ++SRC(1: movl (%esi), %ebx ) ++SRC( movl 4(%esi), %edx ) ++ adcl %ebx, %eax ++DST( movl %ebx, (%edi) ) ++ adcl %edx, %eax ++DST( movl %edx, 4(%edi) ) ++ ++SRC( movl 8(%esi), %ebx ) ++SRC( movl 12(%esi), %edx ) ++ adcl %ebx, %eax ++DST( movl %ebx, 8(%edi) ) ++ adcl %edx, %eax ++DST( movl %edx, 12(%edi) ) ++ ++SRC( movl 16(%esi), %ebx ) ++SRC( movl 20(%esi), %edx ) ++ adcl %ebx, %eax ++DST( movl %ebx, 16(%edi) ) ++ adcl %edx, %eax ++DST( movl %edx, 20(%edi) ) ++ ++SRC( movl 24(%esi), %ebx ) ++SRC( movl 28(%esi), %edx ) ++ adcl %ebx, %eax ++DST( movl %ebx, 24(%edi) ) ++ adcl %edx, %eax ++DST( movl %edx, 28(%edi) ) ++ ++ lea 32(%esi), %esi ++ lea 32(%edi), %edi ++ dec %ecx ++ jne 1b ++ adcl $0, %eax ++2: movl FP(%esp), %edx ++ movl %edx, %ecx ++ andl $0x1c, %edx ++ je 4f ++ shrl $2, %edx # This clears CF ++SRC(3: movl (%esi), %ebx ) ++ adcl %ebx, %eax ++DST( movl %ebx, (%edi) ) ++ lea 4(%esi), %esi ++ lea 4(%edi), %edi ++ dec %edx ++ jne 3b ++ adcl $0, %eax ++4: andl $3, %ecx ++ jz 7f ++ cmpl $2, %ecx ++ jb 5f ++SRC( movw (%esi), %cx ) ++ leal 2(%esi), %esi ++DST( movw %cx, (%edi) ) ++ leal 2(%edi), %edi ++ je 6f ++ shll $16,%ecx ++SRC(5: movb (%esi), %cl ) ++DST( movb %cl, (%edi) ) ++6: addl %ecx, %eax ++ adcl $0, %eax ++7: ++5000: ++ ++# Exception handler: ++.section .fixup, "ax" ++ ++6001: ++ movl ARGBASE+20(%esp), %ebx # src_err_ptr ++ movl $-EFAULT, (%ebx) ++ ++ # zero the complete destination - computing the rest ++ # is too much work ++ movl ARGBASE+8(%esp), %edi # dst ++ movl ARGBASE+12(%esp), %ecx # len ++ xorl %eax,%eax ++ rep ; stosb ++ ++ jmp 5000b ++ ++6002: ++ movl ARGBASE+24(%esp), %ebx # dst_err_ptr ++ movl $-EFAULT,(%ebx) ++ jmp 5000b ++ ++.previous ++ ++ popl %ebx ++ popl %esi ++ popl %edi ++ popl %ecx # equivalent to addl $4,%esp ++ ret ++ ++#else ++ ++/* Version for PentiumII/PPro */ ++ ++#define ROUND1(x) \ ++ SRC(movl x(%esi), %ebx ) ; \ ++ addl %ebx, %eax ; \ ++ DST(movl %ebx, x(%edi) ) ; ++ ++#define ROUND(x) \ ++ SRC(movl x(%esi), %ebx ) ; \ ++ adcl %ebx, %eax ; \ ++ DST(movl %ebx, x(%edi) ) ; ++ ++#define ARGBASE 12 ++ ++csum_partial_copy_generic_i386: ++ pushl %ebx ++ pushl %edi ++ pushl %esi ++ movl ARGBASE+4(%esp),%esi #src ++ movl ARGBASE+8(%esp),%edi #dst ++ movl ARGBASE+12(%esp),%ecx #len ++ movl ARGBASE+16(%esp),%eax #sum ++# movl %ecx, %edx ++ movl %ecx, %ebx ++ movl %esi, %edx ++ shrl $6, %ecx ++ andl $0x3c, %ebx ++ negl %ebx ++ subl %ebx, %esi ++ subl %ebx, %edi ++ lea -1(%esi),%edx ++ andl $-32,%edx ++ lea 3f(%ebx,%ebx), %ebx ++ testl %esi, %esi ++ jmp *%ebx ++1: addl $64,%esi ++ addl $64,%edi ++ SRC(movb -32(%edx),%bl) ; SRC(movb (%edx),%bl) ++ ROUND1(-64) ROUND(-60) ROUND(-56) ROUND(-52) ++ ROUND (-48) ROUND(-44) ROUND(-40) ROUND(-36) ++ ROUND (-32) ROUND(-28) ROUND(-24) ROUND(-20) ++ ROUND (-16) ROUND(-12) ROUND(-8) ROUND(-4) ++3: adcl $0,%eax ++ addl $64, %edx ++ dec %ecx ++ jge 1b ++4: movl ARGBASE+12(%esp),%edx #len ++ andl $3, %edx ++ jz 7f ++ cmpl $2, %edx ++ jb 5f ++SRC( movw (%esi), %dx ) ++ leal 2(%esi), %esi ++DST( movw %dx, (%edi) ) ++ leal 2(%edi), %edi ++ je 6f ++ shll $16,%edx ++5: ++SRC( movb (%esi), %dl ) ++DST( movb %dl, (%edi) ) ++6: addl %edx, %eax ++ adcl $0, %eax ++7: ++.section .fixup, "ax" ++6001: movl ARGBASE+20(%esp), %ebx # src_err_ptr ++ movl $-EFAULT, (%ebx) ++ # zero the complete destination (computing the rest is too much work) ++ movl ARGBASE+8(%esp),%edi # dst ++ movl ARGBASE+12(%esp),%ecx # len ++ xorl %eax,%eax ++ rep; stosb ++ jmp 7b ++6002: movl ARGBASE+24(%esp), %ebx # dst_err_ptr ++ movl $-EFAULT, (%ebx) ++ jmp 7b ++.previous ++ ++ popl %esi ++ popl %edi ++ popl %ebx ++ ret ++ ++#undef ROUND ++#undef ROUND1 ++ ++#endif +diff -Naur -X ../exclude-files orig/arch/um/sys-i386/fault.c um/arch/um/sys-i386/fault.c +--- orig/arch/um/sys-i386/fault.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-i386/fault.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <signal.h> ++#include "sysdep/ptrace.h" ++#include "sysdep/sigcontext.h" ++ ++extern unsigned long search_exception_table(unsigned long addr); ++ ++int arch_fixup(unsigned long address, void *sc_ptr) ++{ ++ struct sigcontext *sc = sc_ptr; ++ unsigned long fixup; ++ ++ fixup = search_exception_table(address); ++ if(fixup != 0){ ++ sc->eip = fixup; ++ return(1); ++ } ++ return(0); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/sys-i386/ksyms.c um/arch/um/sys-i386/ksyms.c +--- orig/arch/um/sys-i386/ksyms.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-i386/ksyms.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,17 @@ ++#include "linux/module.h" ++#include "linux/in6.h" ++#include "linux/rwsem.h" ++#include "asm/byteorder.h" ++#include "asm/semaphore.h" ++#include "asm/uaccess.h" ++#include "asm/checksum.h" ++#include "asm/errno.h" ++ ++EXPORT_SYMBOL(__down_failed); ++EXPORT_SYMBOL(__down_failed_interruptible); ++EXPORT_SYMBOL(__down_failed_trylock); ++EXPORT_SYMBOL(__up_wakeup); ++ ++/* Networking helper routines. */ ++EXPORT_SYMBOL(csum_partial_copy_from); ++EXPORT_SYMBOL(csum_partial_copy_to); +diff -Naur -X ../exclude-files orig/arch/um/sys-i386/ldt.c um/arch/um/sys-i386/ldt.c +--- orig/arch/um/sys-i386/ldt.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-i386/ldt.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,92 @@ ++/* ++ * 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); ++ ++int sys_modify_ldt_tt(int func, void *ptr, unsigned long bytecount) ++{ ++ if(verify_area(VERIFY_READ, ptr, bytecount)) return(-EFAULT); ++ return(modify_ldt(func, ptr, bytecount)); ++} ++#endif ++ ++#ifdef CONFIG_MODE_SKAS ++extern int userspace_pid; ++ ++int sys_modify_ldt_skas(int func, void *ptr, unsigned long bytecount) ++{ ++ struct ptrace_ldt ldt; ++ void *buf; ++ int res, n; ++ ++ buf = kmalloc(bytecount, GFP_KERNEL); ++ if(buf == NULL) ++ return(-ENOMEM); ++ ++ res = 0; ++ ++ switch(func){ ++ case 1: ++ case 0x11: ++ res = copy_from_user(buf, ptr, bytecount); ++ break; ++ } ++ ++ if(res != 0){ ++ res = -EFAULT; ++ goto out; ++ } ++ ++ ldt = ((struct ptrace_ldt) { .func = func, ++ .ptr = buf, ++ .bytecount = bytecount }); ++ res = ptrace(PTRACE_LDT, userspace_pid, 0, (unsigned long) &ldt); ++ if(res < 0) ++ goto out; ++ ++ switch(func){ ++ case 0: ++ case 2: ++ n = res; ++ res = copy_to_user(ptr, buf, n); ++ if(res != 0) ++ res = -EFAULT; ++ else ++ res = n; ++ break; ++ } ++ ++ out: ++ kfree(buf); ++ return(res); ++} ++#endif ++ ++int sys_modify_ldt(int func, void *ptr, unsigned long bytecount) ++{ ++ return(CHOOSE_MODE_PROC(sys_modify_ldt_tt, sys_modify_ldt_skas, func, ++ ptr, bytecount)); ++} ++ ++ ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/sys-i386/Makefile um/arch/um/sys-i386/Makefile +--- orig/arch/um/sys-i386/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-i386/Makefile 2003-11-09 11:55:24.000000000 -0500 +@@ -0,0 +1,46 @@ ++# ++# Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++# Licensed under the GPL ++# ++ ++O_TARGET = built-in.o ++ ++obj-y = bugs.o checksum.o extable.o fault.o ksyms.o ldt.o ptrace.o \ ++ ptrace_user.o semaphore.o sigcontext.o syscalls.o sysrq.o time.o ++export-objs = ksyms.o ++ ++USER_OBJS = bugs.o ptrace_user.o sigcontext.o fault.o ++ ++SYMLINKS = semaphore.c extable.c ++ ++semaphore.c-dir = kernel ++extable.c-dir = mm ++ ++include $(TOPDIR)/Rules.make ++ ++$(USER_OBJS) : %.o: %.c ++ $(CC) $(CFLAGS_$@) $(USER_CFLAGS) -c -o $@ $< ++ ++define make_link ++ -rm -f $1 ++ ln -sf $(TOPDIR)/arch/i386/$($1-dir)/$1 $1 ++endef ++ ++$(SYMLINKS): ++ $(call make_link,$@) ++ ++clean: ++ $(MAKE) -C util clean ++ rm -f $(SYMLINKS) ++ ++fastdep: ++ ++dep: ++ ++archmrproper: ++ ++archclean: ++ ++archdep: ++ ++modules: +diff -Naur -X ../exclude-files orig/arch/um/sys-i386/ptrace.c um/arch/um/sys-i386/ptrace.c +--- orig/arch/um/sys-i386/ptrace.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-i386/ptrace.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,365 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/sched.h" ++#include "asm/elf.h" ++#include "asm/ptrace.h" ++#include "asm/uaccess.h" ++#include "ptrace_user.h" ++#include "sysdep/sigcontext.h" ++#include "sysdep/sc.h" ++ ++void arch_switch(void) ++{ ++ update_debugregs(current->thread.arch.debugregs_seq); ++} ++ ++int is_syscall(unsigned long addr) ++{ ++ unsigned short instr; ++ int n; ++ ++ n = copy_from_user(&instr, (void *) addr, sizeof(instr)); ++ if(n){ ++ printk("is_syscall : failed to read instruction from 0x%lu\n", ++ addr); ++ return(0); ++ } ++ return(instr == 0x80cd); ++} ++ ++/* determines which flags the user has access to. */ ++/* 1 = access 0 = no access */ ++#define FLAG_MASK 0x00044dd5 ++ ++int putreg(struct task_struct *child, int regno, unsigned long value) ++{ ++ regno >>= 2; ++ switch (regno) { ++ case FS: ++ if (value && (value & 3) != 3) ++ return -EIO; ++ PT_REGS_FS(&child->thread.regs) = value; ++ return 0; ++ case GS: ++ if (value && (value & 3) != 3) ++ return -EIO; ++ PT_REGS_GS(&child->thread.regs) = value; ++ return 0; ++ case DS: ++ case ES: ++ if (value && (value & 3) != 3) ++ return -EIO; ++ value &= 0xffff; ++ break; ++ case SS: ++ case CS: ++ if ((value & 3) != 3) ++ return -EIO; ++ value &= 0xffff; ++ break; ++ case EFL: ++ value &= FLAG_MASK; ++ value |= PT_REGS_EFLAGS(&child->thread.regs); ++ break; ++ } ++ PT_REGS_SET(&child->thread.regs, regno, value); ++ return 0; ++} ++ ++unsigned long getreg(struct task_struct *child, int regno) ++{ ++ unsigned long retval = ~0UL; ++ ++ regno >>= 2; ++ switch (regno) { ++ case FS: ++ case GS: ++ case DS: ++ case ES: ++ case SS: ++ case CS: ++ retval = 0xffff; ++ /* fall through */ ++ default: ++ retval &= PT_REG(&child->thread.regs, regno); ++ } ++ return retval; ++} ++ ++struct i387_fxsave_struct { ++ unsigned short cwd; ++ unsigned short swd; ++ unsigned short twd; ++ unsigned short fop; ++ long fip; ++ long fcs; ++ long foo; ++ long fos; ++ long mxcsr; ++ long reserved; ++ long st_space[32]; /* 8*16 bytes for each FP-reg = 128 bytes */ ++ long xmm_space[32]; /* 8*16 bytes for each XMM-reg = 128 bytes */ ++ long padding[56]; ++}; ++ ++/* ++ * FPU tag word conversions. ++ */ ++ ++static inline unsigned short twd_i387_to_fxsr( unsigned short twd ) ++{ ++ unsigned int tmp; /* to avoid 16 bit prefixes in the code */ ++ ++ /* Transform each pair of bits into 01 (valid) or 00 (empty) */ ++ tmp = ~twd; ++ tmp = (tmp | (tmp>>1)) & 0x5555; /* 0V0V0V0V0V0V0V0V */ ++ /* and move the valid bits to the lower byte. */ ++ tmp = (tmp | (tmp >> 1)) & 0x3333; /* 00VV00VV00VV00VV */ ++ tmp = (tmp | (tmp >> 2)) & 0x0f0f; /* 0000VVVV0000VVVV */ ++ tmp = (tmp | (tmp >> 4)) & 0x00ff; /* 00000000VVVVVVVV */ ++ return tmp; ++} ++ ++static inline unsigned long twd_fxsr_to_i387( struct i387_fxsave_struct *fxsave ) ++{ ++ struct _fpxreg *st = NULL; ++ unsigned long twd = (unsigned long) fxsave->twd; ++ unsigned long tag; ++ unsigned long ret = 0xffff0000; ++ int i; ++ ++#define FPREG_ADDR(f, n) ((char *)&(f)->st_space + (n) * 16); ++ ++ for ( i = 0 ; i < 8 ; i++ ) { ++ if ( twd & 0x1 ) { ++ st = (struct _fpxreg *) FPREG_ADDR( fxsave, i ); ++ ++ switch ( st->exponent & 0x7fff ) { ++ case 0x7fff: ++ tag = 2; /* Special */ ++ break; ++ case 0x0000: ++ if ( !st->significand[0] && ++ !st->significand[1] && ++ !st->significand[2] && ++ !st->significand[3] ) { ++ tag = 1; /* Zero */ ++ } else { ++ tag = 2; /* Special */ ++ } ++ break; ++ default: ++ if ( st->significand[3] & 0x8000 ) { ++ tag = 0; /* Valid */ ++ } else { ++ tag = 2; /* Special */ ++ } ++ break; ++ } ++ } else { ++ tag = 3; /* Empty */ ++ } ++ ret |= (tag << (2 * i)); ++ twd = twd >> 1; ++ } ++ return ret; ++} ++ ++/* ++ * FXSR floating point environment conversions. ++ */ ++ ++#ifdef CONFIG_MODE_TT ++static inline int convert_fxsr_to_user_tt(struct _fpstate *buf, ++ struct pt_regs *regs) ++{ ++ struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); ++ unsigned long env[7]; ++ struct _fpreg *to; ++ struct _fpxreg *from; ++ int i; ++ ++ env[0] = (unsigned long)fxsave->cwd | 0xffff0000; ++ env[1] = (unsigned long)fxsave->swd | 0xffff0000; ++ env[2] = twd_fxsr_to_i387(fxsave); ++ env[3] = fxsave->fip; ++ env[4] = fxsave->fcs | ((unsigned long)fxsave->fop << 16); ++ env[5] = fxsave->foo; ++ env[6] = fxsave->fos; ++ ++ if ( __copy_to_user( buf, env, 7 * sizeof(unsigned long) ) ) ++ return 1; ++ ++ to = &buf->_st[0]; ++ from = (struct _fpxreg *) &fxsave->st_space[0]; ++ for ( i = 0 ; i < 8 ; i++, to++, from++ ) { ++ if ( __copy_to_user( to, from, sizeof(*to) ) ) ++ return 1; ++ } ++ return 0; ++} ++#endif ++ ++static inline int convert_fxsr_to_user(struct _fpstate *buf, ++ struct pt_regs *regs) ++{ ++ return(CHOOSE_MODE(convert_fxsr_to_user_tt(buf, regs), 0)); ++} ++ ++#ifdef CONFIG_MODE_TT ++static inline int convert_fxsr_from_user_tt(struct pt_regs *regs, ++ struct _fpstate *buf) ++{ ++ struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); ++ unsigned long env[7]; ++ struct _fpxreg *to; ++ struct _fpreg *from; ++ int i; ++ ++ if ( __copy_from_user( env, buf, 7 * sizeof(long) ) ) ++ return 1; ++ ++ fxsave->cwd = (unsigned short)(env[0] & 0xffff); ++ fxsave->swd = (unsigned short)(env[1] & 0xffff); ++ fxsave->twd = twd_i387_to_fxsr((unsigned short)(env[2] & 0xffff)); ++ fxsave->fip = env[3]; ++ fxsave->fop = (unsigned short)((env[4] & 0xffff0000) >> 16); ++ fxsave->fcs = (env[4] & 0xffff); ++ fxsave->foo = env[5]; ++ fxsave->fos = env[6]; ++ ++ to = (struct _fpxreg *) &fxsave->st_space[0]; ++ from = &buf->_st[0]; ++ for ( i = 0 ; i < 8 ; i++, to++, from++ ) { ++ if ( __copy_from_user( to, from, sizeof(*from) ) ) ++ return 1; ++ } ++ return 0; ++} ++#endif ++ ++static inline int convert_fxsr_from_user(struct pt_regs *regs, ++ struct _fpstate *buf) ++{ ++ return(CHOOSE_MODE(convert_fxsr_from_user_tt(regs, buf), 0)); ++} ++ ++int get_fpregs(unsigned long buf, struct task_struct *child) ++{ ++ int err; ++ ++ err = convert_fxsr_to_user((struct _fpstate *) buf, ++ &child->thread.regs); ++ if(err) return(-EFAULT); ++ else return(0); ++} ++ ++int set_fpregs(unsigned long buf, struct task_struct *child) ++{ ++ int err; ++ ++ err = convert_fxsr_from_user(&child->thread.regs, ++ (struct _fpstate *) buf); ++ if(err) return(-EFAULT); ++ else return(0); ++} ++ ++#ifdef CONFIG_MODE_TT ++int get_fpxregs_tt(unsigned long buf, struct task_struct *tsk) ++{ ++ struct pt_regs *regs = &tsk->thread.regs; ++ struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); ++ int err; ++ ++ err = __copy_to_user((void *) buf, fxsave, ++ sizeof(struct user_fxsr_struct)); ++ if(err) return -EFAULT; ++ else return 0; ++} ++#endif ++ ++int get_fpxregs(unsigned long buf, struct task_struct *tsk) ++{ ++ return(CHOOSE_MODE(get_fpxregs_tt(buf, tsk), 0)); ++} ++ ++#ifdef CONFIG_MODE_TT ++int set_fpxregs_tt(unsigned long buf, struct task_struct *tsk) ++{ ++ struct pt_regs *regs = &tsk->thread.regs; ++ struct i387_fxsave_struct *fxsave = SC_FXSR_ENV(PT_REGS_SC(regs)); ++ int err; ++ ++ err = __copy_from_user(fxsave, (void *) buf, ++ sizeof(struct user_fxsr_struct) ); ++ if(err) return -EFAULT; ++ else return 0; ++} ++#endif ++ ++int set_fpxregs(unsigned long buf, struct task_struct *tsk) ++{ ++ return(CHOOSE_MODE(set_fpxregs_tt(buf, tsk), 0)); ++} ++ ++#ifdef notdef ++int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu) ++{ ++ fpu->cwd = (((SC_FP_CW(PT_REGS_SC(regs)) & 0xffff) << 16) | ++ (SC_FP_SW(PT_REGS_SC(regs)) & 0xffff)); ++ fpu->swd = SC_FP_CSSEL(PT_REGS_SC(regs)) & 0xffff; ++ fpu->twd = SC_FP_IPOFF(PT_REGS_SC(regs)); ++ fpu->fip = SC_FP_CSSEL(PT_REGS_SC(regs)) & 0xffff; ++ fpu->fcs = SC_FP_DATAOFF(PT_REGS_SC(regs)); ++ fpu->foo = SC_FP_DATASEL(PT_REGS_SC(regs)); ++ fpu->fos = 0; ++ memcpy(fpu->st_space, (void *) SC_FP_ST(PT_REGS_SC(regs)), ++ sizeof(fpu->st_space)); ++ return(1); ++} ++#endif ++ ++#ifdef CONFIG_MODE_TT ++static inline void copy_fpu_fxsave_tt(struct pt_regs *regs, ++ struct user_i387_struct *buf) ++{ ++ struct i387_fxsave_struct *fpu = SC_FXSR_ENV(PT_REGS_SC(regs)); ++ unsigned short *to; ++ unsigned short *from; ++ int i; ++ ++ memcpy( buf, fpu, 7 * sizeof(long) ); ++ ++ to = (unsigned short *) &buf->st_space[0]; ++ from = (unsigned short *) &fpu->st_space[0]; ++ for ( i = 0 ; i < 8 ; i++, to += 5, from += 8 ) { ++ memcpy( to, from, 5 * sizeof(unsigned short) ); ++ } ++} ++#endif ++ ++static inline void copy_fpu_fxsave(struct pt_regs *regs, ++ struct user_i387_struct *buf) ++{ ++ (void) CHOOSE_MODE(copy_fpu_fxsave_tt(regs, buf), 0); ++} ++ ++int dump_fpu(struct pt_regs *regs, elf_fpregset_t *fpu ) ++{ ++ copy_fpu_fxsave(regs, (struct user_i387_struct *) fpu); ++ return(1); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/sys-i386/ptrace_user.c um/arch/um/sys-i386/ptrace_user.c +--- orig/arch/um/sys-i386/ptrace_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-i386/ptrace_user.c 2003-12-17 01:33:17.000000000 -0500 +@@ -0,0 +1,117 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stdio.h> ++#include <errno.h> ++#include <unistd.h> ++#include <linux/stddef.h> ++#include <sys/ptrace.h> ++#include <asm/ptrace.h> ++#include <asm/user.h> ++#include "kern_util.h" ++#include "sysdep/thread.h" ++#include "user.h" ++#include "os.h" ++ ++int ptrace_getregs(long pid, unsigned long *regs_out) ++{ ++ return(ptrace(PTRACE_GETREGS, pid, 0, regs_out)); ++} ++ ++int ptrace_setregs(long pid, unsigned long *regs) ++{ ++ return(ptrace(PTRACE_SETREGS, pid, 0, regs)); ++} ++ ++int ptrace_getfpregs(long pid, unsigned long *regs) ++{ ++ return(ptrace(PTRACE_GETFPREGS, pid, 0, regs)); ++} ++ ++static void write_debugregs(int pid, unsigned long *regs) ++{ ++ struct user *dummy; ++ int nregs, i; ++ ++ dummy = NULL; ++ nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]); ++ for(i = 0; i < nregs; i++){ ++ if((i == 4) || (i == 5)) continue; ++ if(ptrace(PTRACE_POKEUSER, pid, &dummy->u_debugreg[i], ++ regs[i]) < 0) ++ printk("write_debugregs - ptrace failed on " ++ "register %d, errno = %d\n", errno); ++ } ++} ++ ++static void read_debugregs(int pid, unsigned long *regs) ++{ ++ struct user *dummy; ++ int nregs, i; ++ ++ dummy = NULL; ++ nregs = sizeof(dummy->u_debugreg)/sizeof(dummy->u_debugreg[0]); ++ for(i = 0; i < nregs; i++){ ++ regs[i] = ptrace(PTRACE_PEEKUSER, pid, ++ &dummy->u_debugreg[i], 0); ++ } ++} ++ ++/* Accessed only by the tracing thread */ ++static unsigned long kernel_debugregs[8] = { [ 0 ... 7 ] = 0 }; ++static int debugregs_seq = 0; ++ ++void arch_enter_kernel(void *task, int pid) ++{ ++ read_debugregs(pid, TASK_DEBUGREGS(task)); ++ write_debugregs(pid, kernel_debugregs); ++} ++ ++void arch_leave_kernel(void *task, int pid) ++{ ++ read_debugregs(pid, kernel_debugregs); ++ write_debugregs(pid, TASK_DEBUGREGS(task)); ++} ++ ++void ptrace_pokeuser(unsigned long addr, unsigned long data) ++{ ++ if((addr < offsetof(struct user, u_debugreg[0])) || ++ (addr > offsetof(struct user, u_debugreg[7]))) ++ return; ++ addr -= offsetof(struct user, u_debugreg[0]); ++ addr = addr >> 2; ++ if(kernel_debugregs[addr] == data) return; ++ ++ kernel_debugregs[addr] = data; ++ debugregs_seq++; ++} ++ ++static void update_debugregs_cb(void *arg) ++{ ++ int pid = *((int *) arg); ++ ++ write_debugregs(pid, kernel_debugregs); ++} ++ ++void update_debugregs(int seq) ++{ ++ int me; ++ ++ if(seq == debugregs_seq) return; ++ ++ me = os_getpid(); ++ initial_thread_cb(update_debugregs_cb, &me); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/sys-i386/sigcontext.c um/arch/um/sys-i386/sigcontext.c +--- orig/arch/um/sys-i386/sigcontext.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-i386/sigcontext.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,80 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include <stddef.h> ++#include <string.h> ++#include <asm/ptrace.h> ++#include <asm/sigcontext.h> ++#include "sysdep/ptrace.h" ++#include "kern_util.h" ++#include "frame_user.h" ++ ++int sc_size(void *data) ++{ ++ struct arch_frame_data *arch = data; ++ ++ return(sizeof(struct sigcontext) + arch->fpstate_size); ++} ++ ++void sc_to_sc(void *to_ptr, void *from_ptr) ++{ ++ struct sigcontext *to = to_ptr, *from = from_ptr; ++ int size = sizeof(*to) + signal_frame_sc.common.arch.fpstate_size; ++ ++ memcpy(to, from, size); ++ if(from->fpstate != NULL) to->fpstate = (struct _fpstate *) (to + 1); ++} ++ ++unsigned long *sc_sigmask(void *sc_ptr) ++{ ++ struct sigcontext *sc = sc_ptr; ++ ++ return(&sc->oldmask); ++} ++ ++int sc_get_fpregs(unsigned long buf, void *sc_ptr) ++{ ++ struct sigcontext *sc = sc_ptr; ++ struct _fpstate *from = sc->fpstate, *to = (struct _fpstate *) buf; ++ int err = 0; ++ ++ if(from == NULL){ ++ err |= clear_user_proc(&to->cw, sizeof(to->cw)); ++ err |= clear_user_proc(&to->sw, sizeof(to->sw)); ++ err |= clear_user_proc(&to->tag, sizeof(to->tag)); ++ err |= clear_user_proc(&to->ipoff, sizeof(to->ipoff)); ++ err |= clear_user_proc(&to->cssel, sizeof(to->cssel)); ++ err |= clear_user_proc(&to->dataoff, sizeof(to->dataoff)); ++ err |= clear_user_proc(&to->datasel, sizeof(to->datasel)); ++ err |= clear_user_proc(&to->_st, sizeof(to->_st)); ++ } ++ else { ++ err |= copy_to_user_proc(&to->cw, &from->cw, sizeof(to->cw)); ++ err |= copy_to_user_proc(&to->sw, &from->sw, sizeof(to->sw)); ++ err |= copy_to_user_proc(&to->tag, &from->tag, ++ sizeof(to->tag)); ++ err |= copy_to_user_proc(&to->ipoff, &from->ipoff, ++ sizeof(to->ipoff)); ++ err |= copy_to_user_proc(&to->cssel,& from->cssel, ++ sizeof(to->cssel)); ++ err |= copy_to_user_proc(&to->dataoff, &from->dataoff, ++ sizeof(to->dataoff)); ++ err |= copy_to_user_proc(&to->datasel, &from->datasel, ++ sizeof(to->datasel)); ++ err |= copy_to_user_proc(to->_st, from->_st, sizeof(to->_st)); ++ } ++ return(err); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/sys-i386/syscalls.c um/arch/um/sys-i386/syscalls.c +--- orig/arch/um/sys-i386/syscalls.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-i386/syscalls.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,68 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "asm/mman.h" ++#include "asm/uaccess.h" ++#include "asm/unistd.h" ++ ++/* ++ * Perform the select(nd, in, out, ex, tv) and mmap() system ++ * calls. Linux/i386 didn't use to be able to handle more than ++ * 4 system call parameters, so these system calls used a memory ++ * block for parameter passing.. ++ */ ++ ++struct mmap_arg_struct { ++ unsigned long addr; ++ unsigned long len; ++ unsigned long prot; ++ unsigned long flags; ++ unsigned long fd; ++ unsigned long offset; ++}; ++ ++extern int old_mmap(unsigned long addr, unsigned long len, ++ unsigned long prot, unsigned long flags, ++ unsigned long fd, unsigned long offset); ++ ++int old_mmap_i386(struct mmap_arg_struct *arg) ++{ ++ struct mmap_arg_struct a; ++ int err = -EFAULT; ++ ++ if (copy_from_user(&a, arg, sizeof(a))) ++ goto out; ++ ++ err = old_mmap(a.addr, a.len, a.prot, a.flags, a.fd, a.offset); ++ out: ++ return err; ++} ++ ++struct sel_arg_struct { ++ unsigned long n; ++ fd_set *inp, *outp, *exp; ++ struct timeval *tvp; ++}; ++ ++int old_select(struct sel_arg_struct *arg) ++{ ++ struct sel_arg_struct a; ++ ++ if (copy_from_user(&a, arg, sizeof(a))) ++ return -EFAULT; ++ /* sys_select() does the appropriate kernel locking */ ++ return sys_select(a.n, a.inp, a.outp, a.exp, a.tvp); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/sys-i386/sysrq.c um/arch/um/sys-i386/sysrq.c +--- orig/arch/um/sys-i386/sysrq.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-i386/sysrq.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,30 @@ ++#include "linux/kernel.h" ++#include "linux/smp.h" ++#include "linux/sched.h" ++#include "asm/ptrace.h" ++#include "sysrq.h" ++ ++void show_regs(struct pt_regs *regs) ++{ ++ printk("\n"); ++ printk("EIP: %04lx:[<%08lx>] CPU: %d %s", ++ 0xffff & PT_REGS_CS(regs), PT_REGS_IP(regs), ++ smp_processor_id(), print_tainted()); ++ if (PT_REGS_CS(regs) & 3) ++ printk(" ESP: %04lx:%08lx", 0xffff & PT_REGS_SS(regs), ++ PT_REGS_SP(regs)); ++ printk(" EFLAGS: %08lx\n %s\n", PT_REGS_EFLAGS(regs), ++ print_tainted()); ++ printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", ++ PT_REGS_EAX(regs), PT_REGS_EBX(regs), ++ PT_REGS_ECX(regs), ++ PT_REGS_EDX(regs)); ++ printk("ESI: %08lx EDI: %08lx EBP: %08lx", ++ PT_REGS_ESI(regs), PT_REGS_EDI(regs), ++ PT_REGS_EBP(regs)); ++ printk(" DS: %04lx ES: %04lx\n", ++ 0xffff & PT_REGS_DS(regs), ++ 0xffff & PT_REGS_ES(regs)); ++ ++ show_trace((unsigned long *) ®s); ++} +diff -Naur -X ../exclude-files orig/arch/um/sys-i386/time.c um/arch/um/sys-i386/time.c +--- orig/arch/um/sys-i386/time.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-i386/time.c 2003-11-10 01:46:49.000000000 -0500 +@@ -0,0 +1,24 @@ ++/* ++ * sys-i386/time.c ++ * Created 25.9.2002 Sapan Bhatia ++ * ++ */ ++ ++unsigned long long time_stamp(void) ++{ ++ unsigned long low, high; ++ ++ asm("rdtsc" : "=a" (low), "=d" (high)); ++ return((((unsigned long long) high) << 32) + low); ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/sys-i386/util/Makefile um/arch/um/sys-i386/util/Makefile +--- orig/arch/um/sys-i386/util/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-i386/util/Makefile 2003-11-08 08:26:40.000000000 -0500 +@@ -0,0 +1,28 @@ ++EXE = mk_sc mk_thread ++ ++include $(TOPDIR)/Rules.make ++ ++all : $(EXE) ++ ++mk_sc : mk_sc.o ++ $(HOSTCC) -o mk_sc mk_sc.o ++ ++mk_sc.o : mk_sc.c ++ $(HOSTCC) -c $< ++ ++mk_thread : mk_thread_user.o mk_thread_kern.o ++ $(HOSTCC) -o mk_thread mk_thread_user.o mk_thread_kern.o ++ ++mk_thread_user.o : mk_thread_user.c ++ $(HOSTCC) -c $< ++ ++mk_thread_kern.o : mk_thread_kern.c ++ $(HOSTCC) $(CFLAGS) -c $< ++ ++clean : ++ $(RM) $(EXE) *.o ++ ++archmrproper : clean ++ ++fastdep : ++ +diff -Naur -X ../exclude-files orig/arch/um/sys-i386/util/mk_sc.c um/arch/um/sys-i386/util/mk_sc.c +--- orig/arch/um/sys-i386/util/mk_sc.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-i386/util/mk_sc.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,52 @@ ++#include <stdio.h> ++#include <signal.h> ++#include <linux/stddef.h> ++ ++#define SC_OFFSET(name, field) \ ++ printf("#define " name "(sc) *((unsigned long *) &(((char *) (sc))[%d]))\n",\ ++ offsetof(struct sigcontext, field)) ++ ++#define SC_FP_OFFSET(name, field) \ ++ printf("#define " name \ ++ "(sc) *((unsigned long *) &(((char *) (SC_FPSTATE(sc)))[%d]))\n",\ ++ offsetof(struct _fpstate, field)) ++ ++#define SC_FP_OFFSET_PTR(name, field, type) \ ++ printf("#define " name \ ++ "(sc) ((" type " *) &(((char *) (SC_FPSTATE(sc)))[%d]))\n",\ ++ offsetof(struct _fpstate, field)) ++ ++int main(int argc, char **argv) ++{ ++ SC_OFFSET("SC_IP", eip); ++ SC_OFFSET("SC_SP", esp); ++ SC_OFFSET("SC_FS", fs); ++ SC_OFFSET("SC_GS", gs); ++ SC_OFFSET("SC_DS", ds); ++ SC_OFFSET("SC_ES", es); ++ SC_OFFSET("SC_SS", ss); ++ SC_OFFSET("SC_CS", cs); ++ SC_OFFSET("SC_EFLAGS", eflags); ++ SC_OFFSET("SC_EAX", eax); ++ SC_OFFSET("SC_EBX", ebx); ++ SC_OFFSET("SC_ECX", ecx); ++ SC_OFFSET("SC_EDX", edx); ++ SC_OFFSET("SC_EDI", edi); ++ SC_OFFSET("SC_ESI", esi); ++ SC_OFFSET("SC_EBP", ebp); ++ SC_OFFSET("SC_TRAPNO", trapno); ++ SC_OFFSET("SC_ERR", err); ++ SC_OFFSET("SC_CR2", cr2); ++ SC_OFFSET("SC_FPSTATE", fpstate); ++ SC_OFFSET("SC_SIGMASK", oldmask); ++ SC_FP_OFFSET("SC_FP_CW", cw); ++ SC_FP_OFFSET("SC_FP_SW", sw); ++ SC_FP_OFFSET("SC_FP_TAG", tag); ++ SC_FP_OFFSET("SC_FP_IPOFF", ipoff); ++ SC_FP_OFFSET("SC_FP_CSSEL", cssel); ++ SC_FP_OFFSET("SC_FP_DATAOFF", dataoff); ++ SC_FP_OFFSET("SC_FP_DATASEL", datasel); ++ SC_FP_OFFSET_PTR("SC_FP_ST", _st, "struct _fpstate"); ++ SC_FP_OFFSET_PTR("SC_FXSR_ENV", _fxsr_env, "void"); ++ return(0); ++} +diff -Naur -X ../exclude-files orig/arch/um/sys-i386/util/mk_thread_kern.c um/arch/um/sys-i386/util/mk_thread_kern.c +--- orig/arch/um/sys-i386/util/mk_thread_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-i386/util/mk_thread_kern.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,22 @@ ++#include "linux/config.h" ++#include "linux/stddef.h" ++#include "linux/sched.h" ++ ++extern void print_head(void); ++extern void print_constant_ptr(char *name, int value); ++extern void print_constant(char *name, char *type, int value); ++extern void print_tail(void); ++ ++#define THREAD_OFFSET(field) offsetof(struct task_struct, thread.field) ++ ++int main(int argc, char **argv) ++{ ++ print_head(); ++ print_constant_ptr("TASK_DEBUGREGS", THREAD_OFFSET(arch.debugregs)); ++#ifdef CONFIG_MODE_TT ++ print_constant("TASK_EXTERN_PID", "int", THREAD_OFFSET(mode.tt.extern_pid)); ++#endif ++ print_tail(); ++ return(0); ++} ++ +diff -Naur -X ../exclude-files orig/arch/um/sys-i386/util/mk_thread_user.c um/arch/um/sys-i386/util/mk_thread_user.c +--- orig/arch/um/sys-i386/util/mk_thread_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-i386/util/mk_thread_user.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,30 @@ ++#include <stdio.h> ++ ++void print_head(void) ++{ ++ printf("/*\n"); ++ printf(" * Generated by mk_thread\n"); ++ printf(" */\n"); ++ printf("\n"); ++ printf("#ifndef __UM_THREAD_H\n"); ++ printf("#define __UM_THREAD_H\n"); ++ printf("\n"); ++} ++ ++void print_constant_ptr(char *name, int value) ++{ ++ printf("#define %s(task) ((unsigned long *) " ++ "&(((char *) (task))[%d]))\n", name, value); ++} ++ ++void print_constant(char *name, char *type, int value) ++{ ++ printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type, ++ value); ++} ++ ++void print_tail(void) ++{ ++ printf("\n"); ++ printf("#endif\n"); ++} +diff -Naur -X ../exclude-files orig/arch/um/sys-ia64/Makefile um/arch/um/sys-ia64/Makefile +--- orig/arch/um/sys-ia64/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-ia64/Makefile 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,26 @@ ++OBJ = sys.o ++ ++OBJS = ++ ++all: $(OBJ) ++ ++$(OBJ): $(OBJS) ++ rm -f $@ ++ $(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@ ++clean: ++ rm -f $(OBJS) ++ ++fastdep: ++ ++archmrproper: ++ ++archclean: ++ rm -f link.ld ++ @$(MAKEBOOT) clean ++ ++archdep: ++ @$(MAKEBOOT) dep ++ ++modules: ++ ++include $(TOPDIR)/Rules.make +diff -Naur -X ../exclude-files orig/arch/um/sys-ppc/Makefile um/arch/um/sys-ppc/Makefile +--- orig/arch/um/sys-ppc/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-ppc/Makefile 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,80 @@ ++OBJ = sys.o ++ ++.S.o: ++ $(CC) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o ++ ++OBJS = ptrace.o sigcontext.o semaphore.o checksum.o miscthings.o misc.o \ ++ ptrace_user.o sysrq.o ++ ++EXTRA_AFLAGS := -DCONFIG_ALL_PPC -I. -I$(TOPDIR)/arch/ppc/kernel ++ ++all: $(OBJ) ++ ++$(OBJ): $(OBJS) ++ rm -f $@ ++ $(LD) $(LINKFLAGS) --start-group $^ --end-group -o $@ ++ ++ptrace_user.o: ptrace_user.c ++ $(CC) -D__KERNEL__ $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< ++ ++sigcontext.o: sigcontext.c ++ $(CC) $(USER_CFLAGS) $(EXTRA_CFLAGS) -c -o $@ $< ++ ++semaphore.c: ++ rm -f $@ ++ ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@ ++ ++checksum.S: ++ rm -f $@ ++ ln -s $(TOPDIR)/arch/ppc/lib/$@ $@ ++ ++mk_defs.c: ++ rm -f $@ ++ ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@ ++ ++ppc_defs.head: ++ rm -f $@ ++ ln -s $(TOPDIR)/arch/ppc/kernel/$@ $@ ++ ++ppc_defs.h: mk_defs.c ppc_defs.head \ ++ $(TOPDIR)/include/asm-ppc/mmu.h \ ++ $(TOPDIR)/include/asm-ppc/processor.h \ ++ $(TOPDIR)/include/asm-ppc/pgtable.h \ ++ $(TOPDIR)/include/asm-ppc/ptrace.h ++# $(CC) $(CFLAGS) -S mk_defs.c ++ cp ppc_defs.head ppc_defs.h ++# for bk, this way we can write to the file even if it's not checked out ++ echo '#define THREAD 608' >> ppc_defs.h ++ echo '#define PT_REGS 8' >> ppc_defs.h ++ echo '#define CLONE_VM 256' >> ppc_defs.h ++# chmod u+w ppc_defs.h ++# grep '^#define' mk_defs.s >> ppc_defs.h ++# rm mk_defs.s ++ ++# the asm link is horrible, and breaks the other targets. This is also ++# not going to work with parallel makes. ++ ++checksum.o: checksum.S ++ rm -f asm ++ ln -s $(TOPDIR)/include/asm-ppc asm ++ $(CC) $(EXTRA_AFLAGS) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o ++ rm -f asm ++ ++misc.o: misc.S ppc_defs.h ++ rm -f asm ++ ln -s $(TOPDIR)/include/asm-ppc asm ++ $(CC) $(EXTRA_AFLAGS) $(AFLAGS) -D__ASSEMBLY__ -D__UM_PPC__ -c $< -o $*.o ++ rm -f asm ++ ++clean: ++ rm -f $(OBJS) ++ rm -f ppc_defs.h ++ rm -f checksum.S semaphore.c mk_defs.c ++ ++fastdep: ++ ++dep: ++ ++modules: ++ ++include $(TOPDIR)/Rules.make +diff -Naur -X ../exclude-files orig/arch/um/sys-ppc/misc.S um/arch/um/sys-ppc/misc.S +--- orig/arch/um/sys-ppc/misc.S 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-ppc/misc.S 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,116 @@ ++/* ++ * This file contains miscellaneous low-level functions. ++ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org) ++ * ++ * Largely rewritten by Cort Dougan (cort@cs.nmt.edu) ++ * and Paul Mackerras. ++ * ++ * A couple of functions stolen from arch/ppc/kernel/misc.S for UML ++ * by Chris Emerson. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License ++ * as published by the Free Software Foundation; either version ++ * 2 of the License, or (at your option) any later version. ++ * ++ */ ++ ++#include <linux/config.h> ++#include <asm/processor.h> ++#include "ppc_asm.h" ++ ++#if defined(CONFIG_4xx) || defined(CONFIG_8xx) ++#define CACHE_LINE_SIZE 16 ++#define LG_CACHE_LINE_SIZE 4 ++#define MAX_COPY_PREFETCH 1 ++#elif !defined(CONFIG_PPC64BRIDGE) ++#define CACHE_LINE_SIZE 32 ++#define LG_CACHE_LINE_SIZE 5 ++#define MAX_COPY_PREFETCH 4 ++#else ++#define CACHE_LINE_SIZE 128 ++#define LG_CACHE_LINE_SIZE 7 ++#define MAX_COPY_PREFETCH 1 ++#endif /* CONFIG_4xx || CONFIG_8xx */ ++ ++ .text ++ ++/* ++ * Clear a page using the dcbz instruction, which doesn't cause any ++ * memory traffic (except to write out any cache lines which get ++ * displaced). This only works on cacheable memory. ++ */ ++_GLOBAL(clear_page) ++ li r0,4096/CACHE_LINE_SIZE ++ mtctr r0 ++#ifdef CONFIG_8xx ++ li r4, 0 ++1: stw r4, 0(r3) ++ stw r4, 4(r3) ++ stw r4, 8(r3) ++ stw r4, 12(r3) ++#else ++1: dcbz 0,r3 ++#endif ++ addi r3,r3,CACHE_LINE_SIZE ++ bdnz 1b ++ blr ++ ++/* ++ * Copy a whole page. We use the dcbz instruction on the destination ++ * to reduce memory traffic (it eliminates the unnecessary reads of ++ * the destination into cache). This requires that the destination ++ * is cacheable. ++ */ ++#define COPY_16_BYTES \ ++ lwz r6,4(r4); \ ++ lwz r7,8(r4); \ ++ lwz r8,12(r4); \ ++ lwzu r9,16(r4); \ ++ stw r6,4(r3); \ ++ stw r7,8(r3); \ ++ stw r8,12(r3); \ ++ stwu r9,16(r3) ++ ++_GLOBAL(copy_page) ++ addi r3,r3,-4 ++ addi r4,r4,-4 ++ li r5,4 ++ ++#ifndef CONFIG_8xx ++#if MAX_COPY_PREFETCH > 1 ++ li r0,MAX_COPY_PREFETCH ++ li r11,4 ++ mtctr r0 ++11: dcbt r11,r4 ++ addi r11,r11,CACHE_LINE_SIZE ++ bdnz 11b ++#else /* MAX_COPY_PREFETCH == 1 */ ++ dcbt r5,r4 ++ li r11,CACHE_LINE_SIZE+4 ++#endif /* MAX_COPY_PREFETCH */ ++#endif /* CONFIG_8xx */ ++ ++ li r0,4096/CACHE_LINE_SIZE ++ mtctr r0 ++1: ++#ifndef CONFIG_8xx ++ dcbt r11,r4 ++ dcbz r5,r3 ++#endif ++ COPY_16_BYTES ++#if CACHE_LINE_SIZE >= 32 ++ COPY_16_BYTES ++#if CACHE_LINE_SIZE >= 64 ++ COPY_16_BYTES ++ COPY_16_BYTES ++#if CACHE_LINE_SIZE >= 128 ++ COPY_16_BYTES ++ COPY_16_BYTES ++ COPY_16_BYTES ++ COPY_16_BYTES ++#endif ++#endif ++#endif ++ bdnz 1b ++ blr +diff -Naur -X ../exclude-files orig/arch/um/sys-ppc/miscthings.c um/arch/um/sys-ppc/miscthings.c +--- orig/arch/um/sys-ppc/miscthings.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-ppc/miscthings.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,53 @@ ++#include "linux/threads.h" ++#include "linux/stddef.h" // for NULL ++#include "linux/elf.h" // for AT_NULL ++ ++/* The following function nicked from arch/ppc/kernel/process.c and ++ * adapted slightly */ ++/* ++ * XXX ld.so expects the auxiliary table to start on ++ * a 16-byte boundary, so we have to find it and ++ * move it up. :-( ++ */ ++void shove_aux_table(unsigned long sp) ++{ ++ int argc; ++ char *p; ++ unsigned long e; ++ unsigned long aux_start, offset; ++ ++ argc = *(int *)sp; ++ sp += sizeof(int) + (argc + 1) * sizeof(char *); ++ /* skip over the environment pointers */ ++ do { ++ p = *(char **)sp; ++ sp += sizeof(char *); ++ } while (p != NULL); ++ aux_start = sp; ++ /* skip to the end of the auxiliary table */ ++ do { ++ e = *(unsigned long *)sp; ++ sp += 2 * sizeof(unsigned long); ++ } while (e != AT_NULL); ++ offset = ((aux_start + 15) & ~15) - aux_start; ++ if (offset != 0) { ++ do { ++ sp -= sizeof(unsigned long); ++ e = *(unsigned long *)sp; ++ *(unsigned long *)(sp + offset) = e; ++ } while (sp > aux_start); ++ } ++} ++/* END stuff taken from arch/ppc/kernel/process.c */ ++ ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/sys-ppc/ptrace.c um/arch/um/sys-ppc/ptrace.c +--- orig/arch/um/sys-ppc/ptrace.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-ppc/ptrace.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,28 @@ ++#include "linux/sched.h" ++#include "asm/ptrace.h" ++ ++int putreg(struct task_struct *child, unsigned long regno, ++ unsigned long value) ++{ ++ child->thread.process_regs.regs[regno >> 2] = value; ++ return 0; ++} ++ ++unsigned long getreg(struct task_struct *child, unsigned long regno) ++{ ++ unsigned long retval = ~0UL; ++ ++ retval &= child->thread.process_regs.regs[regno >> 2]; ++ return retval; ++} ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/sys-ppc/ptrace_user.c um/arch/um/sys-ppc/ptrace_user.c +--- orig/arch/um/sys-ppc/ptrace_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-ppc/ptrace_user.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,40 @@ ++#include <sys/ptrace.h> ++#include <errno.h> ++#include <asm/ptrace.h> ++#include "sysdep/ptrace.h" ++ ++int ptrace_getregs(long pid, unsigned long *regs_out) ++{ ++ int i; ++ for (i=0; i < sizeof(struct sys_pt_regs)/sizeof(PPC_REG); ++i) { ++ errno = 0; ++ regs_out->regs[i] = ptrace(PTRACE_PEEKUSER, pid, i*4, 0); ++ if (errno) { ++ return -errno; ++ } ++ } ++ return 0; ++} ++ ++int ptrace_setregs(long pid, unsigned long *regs_in) ++{ ++ int i; ++ for (i=0; i < sizeof(struct sys_pt_regs)/sizeof(PPC_REG); ++i) { ++ if (i != 34 /* FIXME: PT_ORIG_R3 */ && i <= PT_MQ) { ++ if (ptrace(PTRACE_POKEUSER, pid, i*4, regs_in->regs[i]) < 0) { ++ return -errno; ++ } ++ } ++ } ++ return 0; ++} ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/sys-ppc/sigcontext.c um/arch/um/sys-ppc/sigcontext.c +--- orig/arch/um/sys-ppc/sigcontext.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-ppc/sigcontext.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,15 @@ ++#include "asm/ptrace.h" ++#include "asm/sigcontext.h" ++#include "sysdep/ptrace.h" ++#include "user_util.h" ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/sys-ppc/sysrq.c um/arch/um/sys-ppc/sysrq.c +--- orig/arch/um/sys-ppc/sysrq.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/sys-ppc/sysrq.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,43 @@ ++/* ++ * Copyright (C) 2001 Chris Emerson (cemerson@chiark.greenend.org.uk) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/kernel.h" ++#include "linux/smp.h" ++#include "asm/ptrace.h" ++#include "sysrq.h" ++ ++void show_regs(struct pt_regs_subarch *regs) ++{ ++ printk("\n"); ++ printk("show_regs(): insert regs here.\n"); ++#if 0 ++ printk("\n"); ++ printk("EIP: %04x:[<%08lx>] CPU: %d",0xffff & regs->xcs, regs->eip, ++ smp_processor_id()); ++ if (regs->xcs & 3) ++ printk(" ESP: %04x:%08lx",0xffff & regs->xss, regs->esp); ++ printk(" EFLAGS: %08lx\n", regs->eflags); ++ printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", ++ regs->eax, regs->ebx, regs->ecx, regs->edx); ++ printk("ESI: %08lx EDI: %08lx EBP: %08lx", ++ regs->esi, regs->edi, regs->ebp); ++ printk(" DS: %04x ES: %04x\n", ++ 0xffff & regs->xds, 0xffff & regs->xes); ++#endif ++ ++ show_trace(®s->gpr[1]); ++} ++ ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/arch/um/util/Makefile um/arch/um/util/Makefile +--- orig/arch/um/util/Makefile 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/util/Makefile 2003-11-08 02:51:30.000000000 -0500 +@@ -0,0 +1,26 @@ ++ALL = mk_task mk_constants ++ ++all : $(ALL) ++ ++mk_task : mk_task_user.o mk_task_kern.o ++ $(HOSTCC) -o mk_task mk_task_user.o mk_task_kern.o ++ ++mk_task_user.o : mk_task_user.c ++ $(HOSTCC) -c $< ++ ++mk_task_kern.o : mk_task_kern.c ++ $(HOSTCC) $(CFLAGS) -c $< ++ ++mk_constants : mk_constants_user.o mk_constants_kern.o ++ $(HOSTCC) -o mk_constants mk_constants_user.o mk_constants_kern.o ++ ++mk_constants_user.o : mk_constants_user.c ++ $(HOSTCC) -c $< ++ ++mk_constants_kern.o : mk_constants_kern.c ++ $(HOSTCC) $(CFLAGS) -c $< ++ ++clean : ++ $(RM) $(ALL) *.o *~ ++ ++archmrproper : clean +diff -Naur -X ../exclude-files orig/arch/um/util/mk_constants_kern.c um/arch/um/util/mk_constants_kern.c +--- orig/arch/um/util/mk_constants_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/util/mk_constants_kern.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,24 @@ ++#include "linux/kernel.h" ++#include "linux/stringify.h" ++#include "asm/page.h" ++ ++extern void print_head(void); ++extern void print_constant_str(char *name, char *value); ++extern void print_constant_int(char *name, int value); ++extern void print_tail(void); ++ ++int main(int argc, char **argv) ++{ ++ print_head(); ++ print_constant_int("UM_KERN_PAGE_SIZE", PAGE_SIZE); ++ print_constant_str("UM_KERN_EMERG", KERN_EMERG); ++ print_constant_str("UM_KERN_ALERT", KERN_ALERT); ++ print_constant_str("UM_KERN_CRIT", KERN_CRIT); ++ print_constant_str("UM_KERN_ERR", KERN_ERR); ++ print_constant_str("UM_KERN_WARNING", KERN_WARNING); ++ print_constant_str("UM_KERN_NOTICE", KERN_NOTICE); ++ print_constant_str("UM_KERN_INFO", KERN_INFO); ++ print_constant_str("UM_KERN_DEBUG", KERN_DEBUG); ++ print_tail(); ++ return(0); ++} +diff -Naur -X ../exclude-files orig/arch/um/util/mk_constants_user.c um/arch/um/util/mk_constants_user.c +--- orig/arch/um/util/mk_constants_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/util/mk_constants_user.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,28 @@ ++#include <stdio.h> ++ ++void print_head(void) ++{ ++ printf("/*\n"); ++ printf(" * Generated by mk_constants\n"); ++ printf(" */\n"); ++ printf("\n"); ++ printf("#ifndef __UM_CONSTANTS_H\n"); ++ printf("#define __UM_CONSTANTS_H\n"); ++ printf("\n"); ++} ++ ++void print_constant_str(char *name, char *value) ++{ ++ printf("#define %s \"%s\"\n", name, value); ++} ++ ++void print_constant_int(char *name, int value) ++{ ++ printf("#define %s %d\n", name, value); ++} ++ ++void print_tail(void) ++{ ++ printf("\n"); ++ printf("#endif\n"); ++} +diff -Naur -X ../exclude-files orig/arch/um/util/mk_task_kern.c um/arch/um/util/mk_task_kern.c +--- orig/arch/um/util/mk_task_kern.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/util/mk_task_kern.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,17 @@ ++#include "linux/sched.h" ++#include "linux/stddef.h" ++ ++extern void print(char *name, char *type, int offset); ++extern void print_ptr(char *name, char *type, int offset); ++extern void print_head(void); ++extern void print_tail(void); ++ ++int main(int argc, char **argv) ++{ ++ print_head(); ++ print_ptr("TASK_REGS", "union uml_pt_regs", ++ offsetof(struct task_struct, thread.regs)); ++ print("TASK_PID", "int", offsetof(struct task_struct, pid)); ++ print_tail(); ++ return(0); ++} +diff -Naur -X ../exclude-files orig/arch/um/util/mk_task_user.c um/arch/um/util/mk_task_user.c +--- orig/arch/um/util/mk_task_user.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/arch/um/util/mk_task_user.c 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,30 @@ ++#include <stdio.h> ++ ++void print(char *name, char *type, int offset) ++{ ++ printf("#define %s(task) *((%s *) &(((char *) (task))[%d]))\n", name, type, ++ offset); ++} ++ ++void print_ptr(char *name, char *type, int offset) ++{ ++ printf("#define %s(task) ((%s *) &(((char *) (task))[%d]))\n", name, type, ++ offset); ++} ++ ++void print_head(void) ++{ ++ printf("/*\n"); ++ printf(" * Generated by mk_task\n"); ++ printf(" */\n"); ++ printf("\n"); ++ printf("#ifndef __TASK_H\n"); ++ printf("#define __TASK_H\n"); ++ printf("\n"); ++} ++ ++void print_tail(void) ++{ ++ printf("\n"); ++ printf("#endif\n"); ++} +diff -Naur -X ../exclude-files orig/CREDITS um/CREDITS +--- orig/CREDITS 2003-12-16 22:16:23.000000000 -0500 ++++ um/CREDITS 2003-12-16 22:17:22.000000000 -0500 +@@ -434,6 +434,7 @@ + E: lars@nocrew.org + W: http://lars.nocrew.org/ + D: dsp56k device driver ++D: ptrace proxy in user mode kernel port + S: Kopmansg 2 + S: 411 13 Goteborg + S: Sweden +@@ -719,7 +720,7 @@ + E: jdike@karaya.com + W: http://user-mode-linux.sourceforge.net + D: User mode kernel port +-S: RR1 Box 67C ++S: 375 Tubbs Hill Rd + S: Deering NH 03244 + S: USA + +diff -Naur -X ../exclude-files orig/Documentation/Configure.help um/Documentation/Configure.help +--- orig/Documentation/Configure.help 2003-12-16 22:16:23.000000000 -0500 ++++ um/Documentation/Configure.help 2003-12-16 22:17:22.000000000 -0500 +@@ -15821,6 +15821,63 @@ + The module will be called speedtch.o. If you want to compile it as + a module, say M here and read <file:Documentation/modules.txt>. + ++Support for /proc/mm ++CONFIG_PROC_MM ++ Enables support for address space separation through /proc/mm. ++ A host kernel needs to have this enabled in order for UML to ++ run in skas mode. UML kernels do not need to have this option ++ unless they will host sub-UMLs. ++ ++ If you don't know what this does just say Y. ++ ++Separate Kernel Address Space support ++CONFIG_MODE_SKAS ++ This option controls whether skas (separate kernel address space) ++ support is compiled in. If you have applied the skas patch to the ++ host and enabled support for /proc/mm in the host kernel, then you ++ certainly want to say Y here (and consider saying N to ++ CONFIG_MODE_TT). Otherwise, it is safe to say Y. Disabling this ++ option will shrink the UML binary slightly. ++ ++Tracing thread support ++CONFIG_MODE_TT ++ This option controls whether tracing thread support is compiled ++ into UML. Normally, this should be set to Y. If you intend to ++ use only skas mode (and the host has the skas patch applied to it), ++ then it is OK to say N here. ++ ++Force a static link ++CONFIG_STATIC_LINK ++ If CONFIG_MODE_TT is disabled, then this option gives you the ability ++ to force a static link of UML. Normally, if only skas mode is built ++ in to UML, it will be linked as a shared binary. This is inconvenient ++ for use in a chroot jail. So, if you intend to run UML inside a ++ chroot, and you disable CONFIG_MODE_TT, you probably want to say Y ++ here. ++ ++2G/2G host address space split ++CONFIG_HOST_2G_2G ++ Most Linux machines are configured so that the kernel occupies the ++ upper 1G of the 4G address space and processes use the lower 3G. ++ However, some machine are configured with a 2G/2G split, with the ++ kernel occupying the upper 2G and processes using the lower 2G. ++ ++ To allow UML to run on a such host you have to say Y here. N should be ++ a safe choice most of the time. ++ ++Kernel stack size order ++CONFIG_KERNEL_STACK_ORDER ++ This option determines the size of UML kernel stacks. They will ++ be 1 << order pages. The default is OK unless you're running Valgrind ++ on UML, in which case, set this to 3. ++ ++UML ubd block driver ++CONFIG_BLK_DEV_UBD ++ The User-Mode Linux port includes a driver called UBD which will let ++ you access arbitrary files on the host computer as block devices. ++ Unless you know that you do not need such virtual block devices say ++ Y here. ++ + CONFIG_USB_GADGET + USB is a master/slave protocol, organized with one master + host (such as a PC) controlling up to 127 peripheral devices. +@@ -15905,17 +15962,15 @@ + + Always do synchronous disk IO for UBD + CONFIG_BLK_DEV_UBD_SYNC +- The User-Mode Linux port includes a driver called UBD which will let +- you access arbitrary files on the host computer as block devices. +- Writes to such a block device are not immediately written to the +- host's disk; this may cause problems if, for example, the User-Mode +- Linux 'Virtual Machine' uses a journalling file system and the host +- computer crashes. ++ Writes to the virtual block device are not immediately written to the host's ++ disk; this may cause problems if, for example, the User-Mode Linux ++ 'Virtual Machine' uses a journalling filesystem and the host computer ++ crashes. + + Synchronous operation (i.e. always writing data to the host's disk + immediately) is configurable on a per-UBD basis by using a special + kernel command line option. Alternatively, you can say Y here to +- turn on synchronous operation by default for all block. ++ turn on synchronous operation by default for all block devices. + + If you're running a journalling file system (like reiserfs, for + example) in your virtual machine, you will want to say Y here. If +@@ -15927,6 +15982,7 @@ + CONFIG_PT_PROXY + This option enables a debugging interface which allows gdb to debug + the kernel without needing to actually attach to kernel threads. ++ CONFIG_XTERM_CHAN must be enabled in order to enable CONFIG_PT_PROXY. + If you want to do kernel debugging, say Y here; otherwise say N. + + Management console +@@ -15959,7 +16015,7 @@ + This option allows developers to retrieve coverage data from a UML + session. + +- See <http://user-mode-linux.sourceforge.net/gcov.html> for more ++ See <http://user-mode-linux.sourceforge.net/gprof.html> for more + details. + + If you're involved in UML kernel development and want to use gcov, +@@ -15996,6 +16052,19 @@ + If you'd like to be able to work with files stored on the host, + say Y or M here; otherwise say N. + ++HoneyPot ProcFS ++CONFIG_HPPFS ++ hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc ++ entries to be overridden, removed, or fabricated from the host. ++ Its purpose is to allow a UML to appear to be a physical machine ++ by removing or changing anything in /proc which gives away the ++ identity of a UML. ++ ++ See <http://user-mode-linux.sf.net/hppfs.html> for more information. ++ ++ You only need this if you are setting up a UML honeypot. Otherwise, ++ it is safe to say 'N' here. ++ + Example IO Memory driver + CONFIG_MMAPPER + The User-Mode Linux port can provide support for IO Memory +@@ -16011,6 +16080,21 @@ + If you'd like to be able to provide a simulated IO port space for + User-Mode Linux processes, say Y. If unsure, say N. + ++Anonymous Memory support ++CONFIG_DEV_ANON ++ Don't ask. Just say Y. ++ ++Support for software watchdog inside UML ++CONFIG_UML_WATCHDOG ++ Support for a virtual hardware watchdog. It's safe to say N here. ++ ++COW block device ++CONFIG_COW ++ This is a layered driver which sits above two other block devices. ++ One is read-only, and the other is a read-write layer which stores ++ all changes. This provides the illusion that the read-only layer ++ can be mounted read-write and changed. ++ + Virtual Serial Line + CONFIG_SSL + The User-Mode Linux environment allows you to create virtual serial +@@ -16121,26 +16205,197 @@ + + SLIP transport + CONFIG_UML_NET_SLIP +- The Slip User-Mode Linux network transport allows a running UML to ++ The slip User-Mode Linux network transport allows a running UML to + network with its host over a point-to-point link. Unlike Ethertap, + which can carry any Ethernet frame (and hence even non-IP packets), +- the Slip transport can only carry IP packets. ++ the slip transport can only carry IP packets. + +- To use this, your host must support Slip devices. ++ To use this, your host must support slip devices. + + For more information, see + <http://user-mode-linux.sourceforge.net/networking.html>. That site +- has examples of the UML command line to use to enable Slip ++ has examples of the UML command line to use to enable slip + networking, and details of a few quirks with it. + +- The Ethertap Transport is preferred over Slip because of its +- limitation. If you prefer Slip, however, say Y here. Otherwise ++ The Ethertap Transport is preferred over slip because of its ++ limitations. If you prefer slip, however, say Y here. Otherwise + choose the Multicast transport (to network multiple UMLs on + multiple hosts), Ethertap (to network with the host and the + outside world), and/or the Daemon transport (to network multiple + UMLs on a single host). You may choose more than one without + conflict. If you don't need UML networking, say N. + ++SLiRP transport ++CONFIG_UML_NET_SLIRP ++ The SLiRP User-Mode Linux network transport allows a running UML ++ to network by invoking a program that can handle SLIP encapsulated ++ packets. This is commonly (but not limited to) the application ++ known as SLiRP, a program that can re-socket IP packets back onto ++ the host on which it is run. Only IP packets are supported, ++ unlike other network transports that can handle all Ethernet ++ frames. In general, slirp allows the UML the same IP connectivity ++ to the outside world that the host user is permitted, and unlike ++ other transports, SLiRP works without the need of root level ++ privleges, setuid binaries, or SLIP devices on the host. This ++ also means not every type of connection is possible, but most ++ situations can be accomodated with carefully crafted slirp ++ commands that can be passed along as part of the network device's ++ setup string. The effect of this transport on the UML is similar ++ that of a host behind a firewall that masquerades all network ++ connections passing through it (but is less secure). ++ ++ To use this you should first have slirp compiled somewhere ++ accessible on the host, and have read its documentation. If you ++ don't need UML networking, say N. ++ ++ Startup example: "eth0=slirp,FE:FD:01:02:03:04,/usr/local/bin/slirp" ++ ++pcap transport ++CONFIG_UML_NET_PCAP ++ The pcap transport makes a pcap packet stream on the host look ++ like an ethernet device inside UML. This is useful for making ++ UML act as a network monitor for the host. You must have libcap ++ installed in order to build the pcap transport into UML. ++ ++ For more information, see ++ <http://user-mode-linux.sourceforge.net/networking.html> That site ++ has examples of the UML command line to use to enable this option. ++ ++ If you intend to use UML as a network monitor for the host, say ++ Y here. Otherwise, say N. ++ ++Default main console channel initialization ++CONFIG_CON_ZERO_CHAN ++ This is the string describing the channel to which the main console ++ will be attached by default. This value can be overridden from the ++ command line. The default value is "fd:0,fd:1", which attaches the ++ main console to stdin and stdout. ++ It is safe to leave this unchanged. ++ ++Default console channel initialization ++CONFIG_CON_CHAN ++ This is the string describing the channel to which all consoles ++ except the main console will be attached by default. This value can ++ be overridden from the command line. The default value is "xterm", ++ which brings them up in xterms. ++ It is safe to leave this unchanged, although you may wish to change ++ this if you expect the UML that you build to be run in environments ++ which don't have X or xterm available. ++ ++Default serial line channel initialization ++CONFIG_SSL_CHAN ++ This is the string describing the channel to which the serial lines ++ will be attached by default. This value can be overridden from the ++ command line. The default value is "pty", which attaches them to ++ traditional pseudo-terminals. ++ It is safe to leave this unchanged, although you may wish to change ++ this if you expect the UML that you build to be run in environments ++ which don't have a set of /dev/pty* devices. ++ ++Nesting level ++CONFIG_NEST_LEVEL ++ This is set to the number of layers of UMLs that this UML will be run ++ in. Normally, this is zero, meaning that it will run directly on the ++ host. Setting it to one will build a UML that can run inside a UML ++ that is running on the host. Generally, if you intend this UML to run ++ inside another UML, set CONFIG_NEST_LEVEL to one more than the host UML. ++ Note that if the hosting UML has its CONFIG_KERNEL_HALF_GIGS set to ++ greater than one, then the guest UML should have its CONFIG_NEST_LEVEL ++ set to the host's CONFIG_NEST_LEVEL + CONFIG_KERNEL_HALF_GIGS. ++ Only change this if you are running nested UMLs. ++ ++Kernel address space size (in .5G units) ++CONFIG_KERNEL_HALF_GIGS ++ This determines the amount of address space that UML will allocate for ++ its own, measured in half Gigabyte units. The default is 1. ++ Change this only if you need to boot UML with an unusually large amount ++ of physical memory. ++ ++UML sound support ++CONFIG_UML_SOUND ++ This option enables UML sound support. If enabled, it will pull in ++ soundcore and the UML hostaudio relay, which acts as a intermediary ++ between the host's dsp and mixer devices and the UML sound system. ++ It is safe to say 'Y' here. ++ ++UML SMP support ++CONFIG_UML_SMP ++ This option enables UML SMP support. UML implements virtual SMP by ++ allowing as many processes to run simultaneously on the host as ++ there are virtual processors configured. Obviously, if the host is ++ a uniprocessor, those processes will timeshare, but, inside UML, ++ will appear to be running simultaneously. If the host is a ++ multiprocessor, then UML processes may run simultaneously, depending ++ on the host scheduler. ++ CONFIG_SMP will be set to whatever this option is set to. ++ It is safe to leave this unchanged. ++ ++file descriptor channel support ++CONFIG_FD_CHAN ++ This option enables support for attaching UML consoles and serial ++ lines to already set up file descriptors. Generally, the main ++ console is attached to file descriptors 0 and 1 (stdin and stdout), ++ so it would be wise to leave this enabled unless you intend to ++ attach it to some other host device. ++ ++null device channel support ++CONFIG_NULL_CHAN ++ This option enables support for attaching UML consoles and serial ++ lines to a device similar to /dev/null. Data written to it disappears ++ and there is never any data to be read. ++ ++port channel support ++CONFIG_PORT_CHAN ++ This option enables support for attaching UML consoles and serial ++ lines to host portals. They may be accessed with 'telnet <host> ++ <port number>'. Any number of consoles and serial lines may be ++ attached to a single portal, although what UML device you get when ++ you telnet to that portal will be unpredictable. ++ It is safe to say 'Y' here. ++ ++pty channel support ++CONFIG_PTY_CHAN ++ This option enables support for attaching UML consoles and serial ++ lines to host pseudo-terminals. Access to both traditional ++ pseudo-terminals (/dev/pty*) and pts pseudo-terminals are controlled ++ with this option. The assignment of UML devices to host devices ++ will be announced in the kernel message log. ++ It is safe to say 'Y' here. ++ ++tty channel support ++CONFIG_TTY_CHAN ++ This option enables support for attaching UML consoles and serial ++ lines to host terminals. Access to both virtual consoles ++ (/dev/tty*) and the slave side of pseudo-terminals (/dev/ttyp* and ++ /dev/pts/*) are controlled by this option. ++ It is safe to say 'Y' here. ++ ++xterm channel support ++CONFIG_XTERM_CHAN ++ This option enables support for attaching UML consoles and serial ++ lines to xterms. Each UML device so assigned will be brought up in ++ its own xterm. ++ If you disable this option, then CONFIG_PT_PROXY will be disabled as ++ well, since UML's gdb currently requires an xterm. ++ It is safe to say 'Y' here. ++ ++tty logging ++CONFIG_TTY_LOG ++ This option enables logging of all data going through pseudo-terminals ++ to the host. This is primarily useful for honeypots, where you want ++ secure keystroke logging that can't be detected or disabled by root. ++ Say 'N' unless you are setting up a UML honeypot or otherwise know that ++ you want this option. ++ ++UML real-time clock support ++CONFIG_UML_REAL_TIME_CLOCK ++ This option ties the UML clock to the host clock, so that time passes at ++ the same rate as on the host, regardless of how much CPU time the UML is ++ getting. This should normally be enabled. The exception would be if you're ++ debugging UML. In this case, time spent staring at the debugger with UML ++ stopped will cause lots of timer ticks to be backed up, and UML will spent ++ lots of time calling the timer when it is finally continued. ++ + Microtek USB scanner support + CONFIG_USB_MICROTEK + Say Y here if you want support for the Microtek X6USB and +diff -Naur -X ../exclude-files orig/drivers/char/Makefile um/drivers/char/Makefile +--- orig/drivers/char/Makefile 2003-12-16 22:16:26.000000000 -0500 ++++ um/drivers/char/Makefile 2003-12-16 22:17:25.000000000 -0500 +@@ -109,6 +109,12 @@ + endif + endif + ++ifeq ($(ARCH),um) ++ KEYMAP = ++ KEYBD = ++ CONSOLE = ++endif ++ + ifeq ($(ARCH),sh) + KEYMAP = + KEYBD = +diff -Naur -X ../exclude-files orig/drivers/char/mem.c um/drivers/char/mem.c +--- orig/drivers/char/mem.c 2003-12-16 22:16:27.000000000 -0500 ++++ um/drivers/char/mem.c 2003-12-16 22:17:25.000000000 -0500 +@@ -220,7 +220,8 @@ + ssize_t read = 0; + ssize_t virtr = 0; + char * kbuf; /* k-addr because vread() takes vmlist_lock rwlock */ +- ++ ++ p = (unsigned long) __va(p); + if (p < (unsigned long) high_memory) { + read = count; + if (count > (unsigned long) high_memory - p) +@@ -269,7 +270,7 @@ + } + free_page((unsigned long)kbuf); + } +- *ppos = p; ++ *ppos = __pa((void *) p); + return virtr + read; + } + +@@ -664,6 +665,8 @@ + write: write_full, + }; + ++extern struct file_operations anon_file_operations; ++ + static int memory_open(struct inode * inode, struct file * filp) + { + switch (MINOR(inode->i_rdev)) { +@@ -693,6 +696,9 @@ + case 9: + filp->f_op = &urandom_fops; + break; ++ case 10: ++ filp->f_op = &anon_file_operations; ++ break; + default: + return -ENXIO; + } +@@ -719,7 +725,8 @@ + {5, "zero", S_IRUGO | S_IWUGO, &zero_fops}, + {7, "full", S_IRUGO | S_IWUGO, &full_fops}, + {8, "random", S_IRUGO | S_IWUSR, &random_fops}, +- {9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops} ++ {9, "urandom", S_IRUGO | S_IWUSR, &urandom_fops}, ++ {10, "anon", S_IRUGO | S_IWUSR, &anon_file_operations}, + }; + int i; + +diff -Naur -X ../exclude-files orig/drivers/char/tty_io.c um/drivers/char/tty_io.c +--- orig/drivers/char/tty_io.c 2003-12-16 22:16:27.000000000 -0500 ++++ um/drivers/char/tty_io.c 2003-12-16 22:17:25.000000000 -0500 +@@ -649,6 +649,23 @@ + wake_up_interruptible(&tty->write_wait); + } + ++#ifdef CONFIG_TTY_LOG ++ ++int (*open_log)(void *, void *) = NULL; ++int (*write_log)(int, const char *, int, void *, int) = NULL; ++void (*close_log)(int, void *) = NULL; ++ ++void register_tty_logger(int (*opener)(void *, void *), ++ int (*writer)(int, const char *, int, void *, int), ++ void (*closer)(int, void *)) ++{ ++ open_log = opener; ++ write_log = writer; ++ close_log = closer; ++} ++ ++#endif ++ + static ssize_t tty_read(struct file * file, char * buf, size_t count, + loff_t *ppos) + { +@@ -689,8 +706,13 @@ + else + i = -EIO; + unlock_kernel(); +- if (i > 0) ++ if (i > 0){ + inode->i_atime = CURRENT_TIME; ++#ifdef CONFIG_TTY_LOG ++ if((tty->log_fd >= 0) && (write_log != NULL)) ++ (*write_log)(tty->log_fd, buf, i, tty, 1); ++#endif ++ } + return i; + } + +@@ -744,6 +766,10 @@ + if (written) { + file->f_dentry->d_inode->i_mtime = CURRENT_TIME; + ret = written; ++#ifdef CONFIG_TTY_LOG ++ if((tty->log_fd >= 0) && (write_log != NULL)) ++ (*write_log)(tty->log_fd, buf - ret, ret, tty, 0); ++#endif + } + up(&tty->atomic_write); + return ret; +@@ -971,6 +997,7 @@ + goto release_mem_out; + } + } ++ + goto success; + + /* +@@ -1290,6 +1317,11 @@ + run_task_queue(&tq_timer); + flush_scheduled_tasks(); + ++#ifdef CONFIG_TTY_LOG ++ if((tty->log_fd >= 0) && (close_log != NULL)) ++ (*close_log)(tty->log_fd, tty); ++#endif ++ + /* + * The release_mem function takes care of the details of clearing + * the slots and preserving the termios structure. +@@ -1448,6 +1480,11 @@ + nr_warns++; + } + } ++ ++#ifdef CONFIG_TTY_LOG ++ if((tty->log_fd < 0) && (open_log != NULL)) ++ tty->log_fd = (*open_log)(tty, current->tty); ++#endif + return 0; + } + +@@ -2047,6 +2084,9 @@ + spin_lock_init(&tty->read_lock); + INIT_LIST_HEAD(&tty->tty_files); + INIT_TQUEUE(&tty->SAK_tq, 0, 0); ++#ifdef CONFIG_TTY_LOG ++ tty->log_fd = -1; ++#endif + } + + /* +diff -Naur -X ../exclude-files orig/drivers/net/setup.c um/drivers/net/setup.c +--- orig/drivers/net/setup.c 2002-09-15 12:13:19.000000000 -0400 ++++ um/drivers/net/setup.c 2003-10-21 03:26:07.000000000 -0400 +@@ -28,7 +28,6 @@ + extern int lmc_setup(void); + + extern int madgemc_probe(void); +-extern int uml_net_probe(void); + + /* Pad device name to IFNAMSIZ=16. F.e. __PAD6 is string of 9 zeros. */ + #define __PAD6 "\0\0\0\0\0\0\0\0\0" +@@ -103,9 +102,6 @@ + #ifdef CONFIG_MADGEMC + {madgemc_probe, 0}, + #endif +-#ifdef CONFIG_UML_NET +- {uml_net_probe, 0}, +-#endif + + {NULL, 0}, + }; +diff -Naur -X ../exclude-files orig/fs/bad_inode.c um/fs/bad_inode.c +--- orig/fs/bad_inode.c 2002-08-21 11:47:27.000000000 -0400 ++++ um/fs/bad_inode.c 2003-10-21 03:26:07.000000000 -0400 +@@ -83,6 +83,7 @@ + + void make_bad_inode(struct inode * inode) + { ++ inode->i_state = 0; + inode->i_mode = S_IFREG; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_op = &bad_inode_ops; +diff -Naur -X ../exclude-files orig/include/asm-i386/hardirq.h um/include/asm-i386/hardirq.h +--- orig/include/asm-i386/hardirq.h 2003-12-16 22:16:35.000000000 -0500 ++++ um/include/asm-i386/hardirq.h 2003-12-17 02:16:13.000000000 -0500 +@@ -4,6 +4,7 @@ + #include <linux/config.h> + #include <linux/threads.h> + #include <linux/irq.h> ++#include <asm/processor.h> /* for cpu_relax */ + + /* assembly code in softirq.h is sensitive to the offsets of these fields */ + typedef struct { +diff -Naur -X ../exclude-files orig/include/asm-um/a.out.h um/include/asm-um/a.out.h +--- orig/include/asm-um/a.out.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/a.out.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,20 @@ ++#ifndef __UM_A_OUT_H ++#define __UM_A_OUT_H ++ ++#include "linux/config.h" ++#include "asm/arch/a.out.h" ++#include "choose-mode.h" ++ ++#undef STACK_TOP ++ ++extern unsigned long stacksizelim; ++ ++extern unsigned long host_task_size; ++ ++#define STACK_ROOM (stacksizelim) ++ ++extern int honeypot; ++#define STACK_TOP \ ++ CHOOSE_MODE((honeypot ? host_task_size : task_size), task_size) ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/archparam-i386.h um/include/asm-um/archparam-i386.h +--- orig/include/asm-um/archparam-i386.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/archparam-i386.h 2003-12-16 08:50:39.000000000 -0500 +@@ -0,0 +1,80 @@ ++/* ++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UM_ARCHPARAM_I386_H ++#define __UM_ARCHPARAM_I386_H ++ ++/********* Bits for asm-um/elf.h ************/ ++ ++#include "user.h" ++ ++#define ELF_PLATFORM "i586" ++ ++#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) ++ ++typedef struct user_i387_struct elf_fpregset_t; ++typedef unsigned long elf_greg_t; ++ ++#define ELF_NGREG (sizeof (struct user_regs_struct) / sizeof(elf_greg_t)) ++typedef elf_greg_t elf_gregset_t[ELF_NGREG]; ++ ++#define ELF_DATA ELFDATA2LSB ++#define ELF_ARCH EM_386 ++ ++#define ELF_PLAT_INIT(regs, load_addr) do { \ ++ PT_REGS_EBX(regs) = 0; \ ++ PT_REGS_ECX(regs) = 0; \ ++ PT_REGS_EDX(regs) = 0; \ ++ PT_REGS_ESI(regs) = 0; \ ++ PT_REGS_EDI(regs) = 0; \ ++ PT_REGS_EBP(regs) = 0; \ ++ PT_REGS_EAX(regs) = 0; \ ++} while(0) ++ ++/* Shamelessly stolen from include/asm-i386/elf.h */ ++ ++#define ELF_CORE_COPY_REGS(pr_reg, regs) do { \ ++ pr_reg[0] = PT_REGS_EBX(regs); \ ++ pr_reg[1] = PT_REGS_ECX(regs); \ ++ pr_reg[2] = PT_REGS_EDX(regs); \ ++ pr_reg[3] = PT_REGS_ESI(regs); \ ++ pr_reg[4] = PT_REGS_EDI(regs); \ ++ pr_reg[5] = PT_REGS_EBP(regs); \ ++ pr_reg[6] = PT_REGS_EAX(regs); \ ++ pr_reg[7] = PT_REGS_DS(regs); \ ++ pr_reg[8] = PT_REGS_ES(regs); \ ++ /* fake once used fs and gs selectors? */ \ ++ pr_reg[9] = PT_REGS_DS(regs); \ ++ pr_reg[10] = PT_REGS_DS(regs); \ ++ pr_reg[11] = PT_REGS_SYSCALL_NR(regs); \ ++ pr_reg[12] = PT_REGS_IP(regs); \ ++ pr_reg[13] = PT_REGS_CS(regs); \ ++ pr_reg[14] = PT_REGS_EFLAGS(regs); \ ++ pr_reg[15] = PT_REGS_SP(regs); \ ++ pr_reg[16] = PT_REGS_SS(regs); \ ++} while(0); ++ ++/********* Bits for asm-um/delay.h **********/ ++ ++typedef unsigned long um_udelay_t; ++ ++/********* Nothing for asm-um/hardirq.h **********/ ++ ++/********* Nothing for asm-um/hw_irq.h **********/ ++ ++/********* Nothing for asm-um/string.h **********/ ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/include/asm-um/archparam-ppc.h um/include/asm-um/archparam-ppc.h +--- orig/include/asm-um/archparam-ppc.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/archparam-ppc.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,41 @@ ++#ifndef __UM_ARCHPARAM_PPC_H ++#define __UM_ARCHPARAM_PPC_H ++ ++/********* Bits for asm-um/elf.h ************/ ++ ++#define ELF_PLATFORM (0) ++ ++#define ELF_ET_DYN_BASE (0x08000000) ++ ++/* the following stolen from asm-ppc/elf.h */ ++#define ELF_NGREG 48 /* includes nip, msr, lr, etc. */ ++#define ELF_NFPREG 33 /* includes fpscr */ ++/* General registers */ ++typedef unsigned long elf_greg_t; ++typedef elf_greg_t elf_gregset_t[ELF_NGREG]; ++ ++/* Floating point registers */ ++typedef double elf_fpreg_t; ++typedef elf_fpreg_t elf_fpregset_t[ELF_NFPREG]; ++ ++#define ELF_DATA ELFDATA2MSB ++#define ELF_ARCH EM_PPC ++ ++/********* Bits for asm-um/delay.h **********/ ++ ++typedef unsigned int um_udelay_t; ++ ++/********* Bits for asm-um/hw_irq.h **********/ ++ ++struct hw_interrupt_type; ++ ++/********* Bits for asm-um/hardirq.h **********/ ++ ++#define irq_enter(cpu, irq) hardirq_enter(cpu) ++#define irq_exit(cpu, irq) hardirq_exit(cpu) ++ ++/********* Bits for asm-um/string.h **********/ ++ ++#define __HAVE_ARCH_STRRCHR ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/arch-signal-i386.h um/include/asm-um/arch-signal-i386.h +--- orig/include/asm-um/arch-signal-i386.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/arch-signal-i386.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,24 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UM_ARCH_SIGNAL_I386_H ++#define __UM_ARCH_SIGNAL_I386_H ++ ++struct arch_signal_context { ++ unsigned long extrasigs[_NSIG_WORDS]; ++}; ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/include/asm-um/atomic.h um/include/asm-um/atomic.h +--- orig/include/asm-um/atomic.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/atomic.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,6 @@ ++#ifndef __UM_ATOMIC_H ++#define __UM_ATOMIC_H ++ ++#include "asm/arch/atomic.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/bitops.h um/include/asm-um/bitops.h +--- orig/include/asm-um/bitops.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/bitops.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,6 @@ ++#ifndef __UM_BITOPS_H ++#define __UM_BITOPS_H ++ ++#include "asm/arch/bitops.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/boot.h um/include/asm-um/boot.h +--- orig/include/asm-um/boot.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/boot.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_BOOT_H ++#define __UM_BOOT_H ++ ++#include "asm/arch/boot.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/bugs.h um/include/asm-um/bugs.h +--- orig/include/asm-um/bugs.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/bugs.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_BUGS_H ++#define __UM_BUGS_H ++ ++void check_bugs(void); ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/byteorder.h um/include/asm-um/byteorder.h +--- orig/include/asm-um/byteorder.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/byteorder.h 2003-12-16 22:26:55.000000000 -0500 +@@ -0,0 +1,6 @@ ++#ifndef __UM_BYTEORDER_H ++#define __UM_BYTEORDER_H ++ ++#include "asm/arch/byteorder.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/cache.h um/include/asm-um/cache.h +--- orig/include/asm-um/cache.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/cache.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_CACHE_H ++#define __UM_CACHE_H ++ ++#define L1_CACHE_BYTES 32 ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/checksum.h um/include/asm-um/checksum.h +--- orig/include/asm-um/checksum.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/checksum.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_CHECKSUM_H ++#define __UM_CHECKSUM_H ++ ++#include "sysdep/checksum.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/cobalt.h um/include/asm-um/cobalt.h +--- orig/include/asm-um/cobalt.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/cobalt.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_COBALT_H ++#define __UM_COBALT_H ++ ++#include "asm/arch/cobalt.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/current.h um/include/asm-um/current.h +--- orig/include/asm-um/current.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/current.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,34 @@ ++/* ++ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UM_CURRENT_H ++#define __UM_CURRENT_H ++ ++#ifndef __ASSEMBLY__ ++ ++#include "linux/config.h" ++#include "asm/page.h" ++ ++struct task_struct; ++ ++#define CURRENT_TASK(dummy) (((unsigned long) &dummy) & \ ++ (PAGE_MASK << CONFIG_KERNEL_STACK_ORDER)) ++ ++#define current ({ int dummy; (struct task_struct *) CURRENT_TASK(dummy); }) ++ ++#endif /* __ASSEMBLY__ */ ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/include/asm-um/delay.h um/include/asm-um/delay.h +--- orig/include/asm-um/delay.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/delay.h 2003-12-16 22:26:58.000000000 -0500 +@@ -0,0 +1,7 @@ ++#ifndef __UM_DELAY_H ++#define __UM_DELAY_H ++ ++#include "asm/arch/delay.h" ++#include "asm/archparam.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/desc.h um/include/asm-um/desc.h +--- orig/include/asm-um/desc.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/desc.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_DESC_H ++#define __UM_DESC_H ++ ++#include "asm/arch/desc.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/div64.h um/include/asm-um/div64.h +--- orig/include/asm-um/div64.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/div64.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef _UM_DIV64_H ++#define _UM_DIV64_H ++ ++#include "asm/arch/div64.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/dma.h um/include/asm-um/dma.h +--- orig/include/asm-um/dma.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/dma.h 2003-12-15 00:26:39.000000000 -0500 +@@ -0,0 +1,10 @@ ++#ifndef __UM_DMA_H ++#define __UM_DMA_H ++ ++#include "asm/io.h" ++ ++extern unsigned long uml_physmem; ++ ++#define MAX_DMA_ADDRESS (uml_physmem) ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/elf.h um/include/asm-um/elf.h +--- orig/include/asm-um/elf.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/elf.h 2003-12-16 22:29:20.000000000 -0500 +@@ -0,0 +1,18 @@ ++#ifndef __UM_ELF_H ++#define __UM_ELF_H ++ ++#include "asm/archparam.h" ++ ++#define ELF_HWCAP (0) ++ ++#define SET_PERSONALITY(ex, ibcs2) do ; while(0) ++ ++#define ELF_EXEC_PAGESIZE 4096 ++ ++#define elf_check_arch(x) (1) ++ ++#define ELF_CLASS ELFCLASS32 ++ ++#define USE_ELF_CORE_DUMP ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/errno.h um/include/asm-um/errno.h +--- orig/include/asm-um/errno.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/errno.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_ERRNO_H ++#define __UM_ERRNO_H ++ ++#include "asm/arch/errno.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/fcntl.h um/include/asm-um/fcntl.h +--- orig/include/asm-um/fcntl.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/fcntl.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_FCNTL_H ++#define __UM_FCNTL_H ++ ++#include "asm/arch/fcntl.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/fixmap.h um/include/asm-um/fixmap.h +--- orig/include/asm-um/fixmap.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/fixmap.h 2003-12-17 02:16:14.000000000 -0500 +@@ -0,0 +1,89 @@ ++#ifndef __UM_FIXMAP_H ++#define __UM_FIXMAP_H ++ ++#include <linux/config.h> ++#include <asm/kmap_types.h> ++ ++/* ++ * Here we define all the compile-time 'special' virtual ++ * addresses. The point is to have a constant address at ++ * compile time, but to set the physical address only ++ * in the boot process. We allocate these special addresses ++ * from the end of virtual memory (0xfffff000) backwards. ++ * Also this lets us do fail-safe vmalloc(), we ++ * can guarantee that these special addresses and ++ * vmalloc()-ed addresses never overlap. ++ * ++ * these 'compile-time allocated' memory buffers are ++ * fixed-size 4k pages. (or larger if used with an increment ++ * highger than 1) use fixmap_set(idx,phys) to associate ++ * physical memory with fixmap indices. ++ * ++ * TLB entries of such buffers will not be flushed across ++ * task switches. ++ */ ++ ++/* ++ * on UP currently we will have no trace of the fixmap mechanizm, ++ * no page table allocations, etc. This might change in the ++ * future, say framebuffers for the console driver(s) could be ++ * fix-mapped? ++ */ ++enum fixed_addresses { ++#ifdef CONFIG_HIGHMEM ++ FIX_KMAP_BEGIN, /* reserved pte's for temporary kernel mappings */ ++ FIX_KMAP_END = FIX_KMAP_BEGIN+(KM_TYPE_NR*NR_CPUS)-1, ++#endif ++ __end_of_fixed_addresses ++}; ++ ++extern void __set_fixmap (enum fixed_addresses idx, ++ unsigned long phys, pgprot_t flags); ++ ++#define set_fixmap(idx, phys) \ ++ __set_fixmap(idx, phys, PAGE_KERNEL) ++/* ++ * Some hardware wants to get fixmapped without caching. ++ */ ++#define set_fixmap_nocache(idx, phys) \ ++ __set_fixmap(idx, phys, PAGE_KERNEL_NOCACHE) ++/* ++ * used by vmalloc.c. ++ * ++ * Leave one empty page between vmalloc'ed areas and ++ * the start of the fixmap, and leave one page empty ++ * at the top of mem.. ++ */ ++extern unsigned long get_kmem_end(void); ++ ++#define FIXADDR_TOP (get_kmem_end() - 0x2000) ++#define FIXADDR_SIZE (__end_of_fixed_addresses << PAGE_SHIFT) ++#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE) ++ ++#define __fix_to_virt(x) (FIXADDR_TOP - ((x) << PAGE_SHIFT)) ++ ++extern void __this_fixmap_does_not_exist(void); ++ ++/* ++ * 'index to address' translation. If anyone tries to use the idx ++ * directly without tranlation, we catch the bug with a NULL-deference ++ * kernel oops. Illegal ranges of incoming indices are caught too. ++ */ ++static inline unsigned long fix_to_virt(const unsigned int idx) ++{ ++ /* ++ * this branch gets completely eliminated after inlining, ++ * except when someone tries to use fixaddr indices in an ++ * illegal way. (such as mixing up address types or using ++ * out-of-range indices). ++ * ++ * If it doesn't get removed, the linker will complain ++ * loudly with a reasonably clear error message.. ++ */ ++ if (idx >= __end_of_fixed_addresses) ++ __this_fixmap_does_not_exist(); ++ ++ return __fix_to_virt(idx); ++} ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/floppy.h um/include/asm-um/floppy.h +--- orig/include/asm-um/floppy.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/floppy.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_FLOPPY_H ++#define __UM_FLOPPY_H ++ ++#include "asm/arch/floppy.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/hardirq.h um/include/asm-um/hardirq.h +--- orig/include/asm-um/hardirq.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/hardirq.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,6 @@ ++#ifndef __UM_HARDIRQ_H ++#define __UM_HARDIRQ_H ++ ++#include "asm/arch/hardirq.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/hdreg.h um/include/asm-um/hdreg.h +--- orig/include/asm-um/hdreg.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/hdreg.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_HDREG_H ++#define __UM_HDREG_H ++ ++#include "asm/arch/hdreg.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/highmem.h um/include/asm-um/highmem.h +--- orig/include/asm-um/highmem.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/highmem.h 2003-12-17 02:16:14.000000000 -0500 +@@ -0,0 +1,12 @@ ++#ifndef __UM_HIGHMEM_H ++#define __UM_HIGHMEM_H ++ ++#include "asm/page.h" ++#include "asm/fixmap.h" ++#include "asm/arch/highmem.h" ++ ++#undef PKMAP_BASE ++ ++#define PKMAP_BASE ((FIXADDR_START - LAST_PKMAP * PAGE_SIZE) & PMD_MASK) ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/hw_irq.h um/include/asm-um/hw_irq.h +--- orig/include/asm-um/hw_irq.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/hw_irq.h 2003-12-16 22:26:55.000000000 -0500 +@@ -0,0 +1,10 @@ ++#ifndef _ASM_UM_HW_IRQ_H ++#define _ASM_UM_HW_IRQ_H ++ ++#include "asm/irq.h" ++#include "asm/archparam.h" ++ ++static inline void hw_resend_irq(struct hw_interrupt_type *h, unsigned int i) ++{} ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/ide.h um/include/asm-um/ide.h +--- orig/include/asm-um/ide.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/ide.h 2003-12-15 00:29:05.000000000 -0500 +@@ -0,0 +1,6 @@ ++#ifndef __UM_IDE_H ++#define __UM_IDE_H ++ ++#include "asm/arch/ide.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/init.h um/include/asm-um/init.h +--- orig/include/asm-um/init.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/init.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,11 @@ ++#ifndef _UM_INIT_H ++#define _UM_INIT_H ++ ++#ifdef notdef ++#define __init ++#define __initdata ++#define __initfunc(__arginit) __arginit ++#define __cacheline_aligned ++#endif ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/ioctl.h um/include/asm-um/ioctl.h +--- orig/include/asm-um/ioctl.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/ioctl.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_IOCTL_H ++#define __UM_IOCTL_H ++ ++#include "asm/arch/ioctl.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/ioctls.h um/include/asm-um/ioctls.h +--- orig/include/asm-um/ioctls.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/ioctls.h 2003-11-07 02:10:43.000000000 -0500 +@@ -0,0 +1,6 @@ ++#ifndef __UM_IOCTLS_H ++#define __UM_IOCTLS_H ++ ++#include "asm/arch/ioctls.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/io.h um/include/asm-um/io.h +--- orig/include/asm-um/io.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/io.h 2003-12-15 00:26:39.000000000 -0500 +@@ -0,0 +1,25 @@ ++#ifndef __UM_IO_H ++#define __UM_IO_H ++ ++#include "asm/page.h" ++ ++#define IO_SPACE_LIMIT 0xdeadbeef /* Sure hope nothing uses this */ ++ ++static inline int inb(unsigned long i) { return(0); } ++static inline void outb(char c, unsigned long i) { } ++ ++/* ++ * Change virtual addresses to physical addresses and vv. ++ * These are pretty trivial ++ */ ++static inline unsigned long virt_to_phys(volatile void * address) ++{ ++ return __pa((void *) address); ++} ++ ++static inline void * phys_to_virt(unsigned long address) ++{ ++ return __va(address); ++} ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/ipcbuf.h um/include/asm-um/ipcbuf.h +--- orig/include/asm-um/ipcbuf.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/ipcbuf.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_IPCBUF_H ++#define __UM_IPCBUF_H ++ ++#include "asm/arch/ipcbuf.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/ipc.h um/include/asm-um/ipc.h +--- orig/include/asm-um/ipc.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/ipc.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_IPC_H ++#define __UM_IPC_H ++ ++#include "asm/arch/ipc.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/irq.h um/include/asm-um/irq.h +--- orig/include/asm-um/irq.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/irq.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,22 @@ ++#ifndef __UM_IRQ_H ++#define __UM_IRQ_H ++ ++#define TIMER_IRQ 0 ++#define UMN_IRQ 1 ++#define CONSOLE_IRQ 2 ++#define CONSOLE_WRITE_IRQ 3 ++#define UBD_IRQ 4 ++#define UM_ETH_IRQ 5 ++#define SSL_IRQ 6 ++#define SSL_WRITE_IRQ 7 ++#define ACCEPT_IRQ 8 ++#define MCONSOLE_IRQ 9 ++#define WINCH_IRQ 10 ++#define SIGIO_WRITE_IRQ 11 ++#define TELNETD_IRQ 12 ++#define XTERM_IRQ 13 ++ ++#define LAST_IRQ XTERM_IRQ ++#define NR_IRQS (LAST_IRQ + 1) ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/keyboard.h um/include/asm-um/keyboard.h +--- orig/include/asm-um/keyboard.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/keyboard.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_KEYBOARD_H ++#define __UM_KEYBOARD_H ++ ++#include "asm/arch/keyboard.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/kmap_types.h um/include/asm-um/kmap_types.h +--- orig/include/asm-um/kmap_types.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/kmap_types.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,11 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UM_KMAP_TYPES_H ++#define __UM_KMAP_TYPES_H ++ ++#include "asm/arch/kmap_types.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/linux_logo.h um/include/asm-um/linux_logo.h +--- orig/include/asm-um/linux_logo.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/linux_logo.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_LINUX_LOGO_H ++#define __UM_LINUX_LOGO_H ++ ++#include "asm/arch/linux_logo.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/locks.h um/include/asm-um/locks.h +--- orig/include/asm-um/locks.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/locks.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_LOCKS_H ++#define __UM_LOCKS_H ++ ++#include "asm/arch/locks.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/mca_dma.h um/include/asm-um/mca_dma.h +--- orig/include/asm-um/mca_dma.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/mca_dma.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef mca___UM_DMA_H ++#define mca___UM_DMA_H ++ ++#include "asm/arch/mca_dma.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/mman.h um/include/asm-um/mman.h +--- orig/include/asm-um/mman.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/mman.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_MMAN_H ++#define __UM_MMAN_H ++ ++#include "asm/arch/mman.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/mmu_context.h um/include/asm-um/mmu_context.h +--- orig/include/asm-um/mmu_context.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/mmu_context.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,72 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UM_MMU_CONTEXT_H ++#define __UM_MMU_CONTEXT_H ++ ++#include "linux/sched.h" ++#include "choose-mode.h" ++ ++#define get_mmu_context(task) do ; while(0) ++#define activate_context(tsk) do ; while(0) ++ ++static inline void activate_mm(struct mm_struct *old, struct mm_struct *new) ++{ ++} ++ ++extern void switch_mm_skas(int mm_fd); ++ ++static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, ++ struct task_struct *tsk, unsigned cpu) ++{ ++ if(prev != next){ ++ clear_bit(cpu, &prev->cpu_vm_mask); ++ set_bit(cpu, &next->cpu_vm_mask); ++ if(next != &init_mm) ++ CHOOSE_MODE((void) 0, ++ switch_mm_skas(next->context.skas.mm_fd)); ++ } ++} ++ ++static inline void enter_lazy_tlb(struct mm_struct *mm, ++ struct task_struct *tsk, unsigned cpu) ++{ ++} ++ ++extern int init_new_context_skas(struct task_struct *task, ++ struct mm_struct *mm); ++ ++static inline int init_new_context_tt(struct task_struct *task, ++ struct mm_struct *mm) ++{ ++ return(0); ++} ++ ++static inline int init_new_context(struct task_struct *task, ++ struct mm_struct *mm) ++{ ++ return(CHOOSE_MODE_PROC(init_new_context_tt, init_new_context_skas, ++ task, mm)); ++} ++ ++extern void destroy_context_skas(struct mm_struct *mm); ++ ++static inline void destroy_context(struct mm_struct *mm) ++{ ++ CHOOSE_MODE((void) 0, destroy_context_skas(mm)); ++} ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/include/asm-um/mmu.h um/include/asm-um/mmu.h +--- orig/include/asm-um/mmu.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/mmu.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,22 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __MMU_H ++#define __MMU_H ++ ++#include "um_mmu.h" ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/include/asm-um/module.h um/include/asm-um/module.h +--- orig/include/asm-um/module.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/module.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_MODULE_H ++#define __UM_MODULE_H ++ ++#include "asm/arch/module.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/msgbuf.h um/include/asm-um/msgbuf.h +--- orig/include/asm-um/msgbuf.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/msgbuf.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_MSGBUF_H ++#define __UM_MSGBUF_H ++ ++#include "asm/arch/msgbuf.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/mtrr.h um/include/asm-um/mtrr.h +--- orig/include/asm-um/mtrr.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/mtrr.h 2003-12-17 10:48:33.000000000 -0500 +@@ -0,0 +1,6 @@ ++#ifndef __UM_MTRR_H ++#define __UM_MTRR_H ++ ++#include "asm/arch/mtrr.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/namei.h um/include/asm-um/namei.h +--- orig/include/asm-um/namei.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/namei.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_NAMEI_H ++#define __UM_NAMEI_H ++ ++#include "asm/arch/namei.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/page.h um/include/asm-um/page.h +--- orig/include/asm-um/page.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/page.h 2003-12-15 00:26:37.000000000 -0500 +@@ -0,0 +1,68 @@ ++/* ++ * Copyright (C) 2000 - 2003 Jeff Dike (jdike@addtoit.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UM_PAGE_H ++#define __UM_PAGE_H ++ ++struct page; ++ ++#include "asm/arch/page.h" ++ ++#undef BUG ++#undef PAGE_BUG ++#undef __pa ++#undef __va ++#undef virt_to_page ++#undef VALID_PAGE ++#undef PAGE_OFFSET ++#undef KERNELBASE ++ ++extern unsigned long uml_physmem; ++ ++#define PAGE_OFFSET (uml_physmem) ++#define KERNELBASE PAGE_OFFSET ++ ++#ifndef __ASSEMBLY__ ++ ++extern void stop(void); ++ ++#define BUG() do { \ ++ panic("kernel BUG at %s:%d!\n", __FILE__, __LINE__); \ ++} while (0) ++ ++#define PAGE_BUG(page) do { \ ++ BUG(); \ ++} while (0) ++ ++#endif /* __ASSEMBLY__ */ ++ ++#define __va_space (8*1024*1024) ++ ++extern unsigned long to_phys(void *virt); ++extern void *to_virt(unsigned long phys); ++ ++#define __pa(virt) to_phys((void *) virt) ++#define __va(phys) to_virt((unsigned long) phys) ++ ++#define VALID_PAGE(page) ((page - mem_map) < max_mapnr) ++ ++extern struct page *arch_validate(struct page *page, int mask, int order); ++#define HAVE_ARCH_VALIDATE ++ ++extern void arch_free_page(struct page *page, int order); ++#define HAVE_ARCH_FREE_PAGE ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/include/asm-um/page_offset.h um/include/asm-um/page_offset.h +--- orig/include/asm-um/page_offset.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/page_offset.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1 @@ ++#define PAGE_OFFSET_RAW (uml_physmem) +diff -Naur -X ../exclude-files orig/include/asm-um/param.h um/include/asm-um/param.h +--- orig/include/asm-um/param.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/param.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,24 @@ ++#ifndef _UM_PARAM_H ++#define _UM_PARAM_H ++ ++#ifndef HZ ++#define HZ 52 ++#endif ++ ++#define EXEC_PAGESIZE 4096 ++ ++#ifndef NGROUPS ++#define NGROUPS 32 ++#endif ++ ++#ifndef NOGROUP ++#define NOGROUP (-1) ++#endif ++ ++#define MAXHOSTNAMELEN 64 /* max length of hostname */ ++ ++#ifdef __KERNEL__ ++# define CLOCKS_PER_SEC 100 /* frequency at which times() counts */ ++#endif ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/pci.h um/include/asm-um/pci.h +--- orig/include/asm-um/pci.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/pci.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_PCI_H ++#define __UM_PCI_H ++ ++#define PCI_DMA_BUS_IS_PHYS (1) ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/pgalloc.h um/include/asm-um/pgalloc.h +--- orig/include/asm-um/pgalloc.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/pgalloc.h 2003-12-17 02:16:14.000000000 -0500 +@@ -0,0 +1,164 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Derived from include/asm-i386/pgalloc.h and include/asm-i386/pgtable.h ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UM_PGALLOC_H ++#define __UM_PGALLOC_H ++ ++#include "linux/config.h" ++#include "linux/mm.h" ++#include "asm/fixmap.h" ++#include "choose-mode.h" ++ ++#define pgd_quicklist (current_cpu_data.pgd_quick) ++#define pmd_quicklist (current_cpu_data.pmd_quick) ++#define pte_quicklist (current_cpu_data.pte_quick) ++#define pgtable_cache_size (current_cpu_data.pgtable_cache_sz) ++ ++#define pmd_populate(mm, pmd, pte) set_pmd(pmd, __pmd(_PAGE_TABLE + __pa(pte))) ++ ++/* ++ * Allocate and free page tables. ++ */ ++ ++static inline pgd_t *get_pgd_slow_tt(void) ++{ ++ pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL); ++ ++ if (pgd) { ++ memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); ++ memcpy(pgd + USER_PTRS_PER_PGD, ++ swapper_pg_dir + USER_PTRS_PER_PGD, ++ (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t)); ++ } ++ return pgd; ++} ++ ++static inline pgd_t *get_pgd_slow_skas(void) ++{ ++ pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL); ++ ++ if (pgd) ++ memset(pgd, 0, USER_PTRS_PER_PGD * sizeof(pgd_t)); ++ return pgd; ++} ++ ++static inline pgd_t *get_pgd_slow(void) ++{ ++ return(CHOOSE_MODE(get_pgd_slow_tt(), get_pgd_slow_skas())); ++} ++ ++static inline pgd_t *get_pgd_fast(void) ++{ ++ unsigned long *ret; ++ ++ ret = pgd_quicklist; ++ if (ret != NULL) { ++ pgd_quicklist = (unsigned long *)(*ret); ++ ret[0] = 0; ++ pgtable_cache_size--; ++ } else ++ ret = (unsigned long *)get_pgd_slow(); ++ return (pgd_t *)ret; ++} ++ ++static inline void free_pgd_fast(pgd_t *pgd) ++{ ++ *(unsigned long *)pgd = (unsigned long) pgd_quicklist; ++ pgd_quicklist = (unsigned long *) pgd; ++ pgtable_cache_size++; ++} ++ ++static inline void free_pgd_slow(pgd_t *pgd) ++{ ++ free_page((unsigned long)pgd); ++} ++ ++static inline pte_t *pte_alloc_one(struct mm_struct *mm, unsigned long address) ++{ ++ pte_t *pte; ++ ++ pte = (pte_t *) __get_free_page(GFP_KERNEL); ++ if (pte) ++ clear_page(pte); ++ return pte; ++} ++ ++static inline pte_t *pte_alloc_one_fast(struct mm_struct *mm, unsigned long address) ++{ ++ unsigned long *ret; ++ ++ ret = (unsigned long *)pte_quicklist; ++ if (ret != NULL) { ++ pte_quicklist = (unsigned long *)(*ret); ++ ret[0] = ret[1]; ++ pgtable_cache_size--; ++ } ++ return (pte_t *)ret; ++} ++ ++static inline void pte_free_fast(pte_t *pte) ++{ ++ *(unsigned long *)pte = (unsigned long) pte_quicklist; ++ pte_quicklist = (unsigned long *) pte; ++ pgtable_cache_size++; ++} ++ ++static inline void pte_free_slow(pte_t *pte) ++{ ++ free_page((unsigned long)pte); ++} ++ ++#define pte_free(pte) pte_free_fast(pte) ++#define pgd_free(pgd) free_pgd_slow(pgd) ++#define pgd_alloc(mm) get_pgd_fast() ++ ++/* ++ * allocating and freeing a pmd is trivial: the 1-entry pmd is ++ * inside the pgd, so has no extra memory associated with it. ++ */ ++ ++#define pmd_alloc_one_fast(mm, addr) ({ BUG(); ((pmd_t *)1); }) ++#define pmd_alloc_one(mm, addr) ({ BUG(); ((pmd_t *)2); }) ++#define pmd_free_slow(x) do { } while (0) ++#define pmd_free_fast(x) do { } while (0) ++#define pmd_free(x) do { } while (0) ++#define pgd_populate(mm, pmd, pte) BUG() ++ ++/* ++ * TLB flushing: ++ * ++ * - flush_tlb() flushes the current mm struct TLBs ++ * - flush_tlb_all() flushes all processes TLBs ++ * - flush_tlb_mm(mm) flushes the specified mm context TLB's ++ * - flush_tlb_page(vma, vmaddr) flushes one page ++ * - flush_tlb_kernel_vm() flushes the kernel vm area ++ * - flush_tlb_range(mm, start, end) flushes a range of pages ++ * - flush_tlb_pgtables(mm, start, end) flushes a range of page tables ++ */ ++ ++extern void flush_tlb_all(void); ++extern void flush_tlb_mm(struct mm_struct *mm); ++extern void flush_tlb_range(struct mm_struct *mm, unsigned long start, ++ unsigned long end); ++extern void flush_tlb_page(struct vm_area_struct *vma, unsigned long vmaddr); ++extern void flush_tlb_kernel_vm(void); ++ ++static inline void flush_tlb_pgtables(struct mm_struct *mm, ++ unsigned long start, unsigned long end) ++{ ++} ++ ++#endif ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/include/asm-um/pgtable.h um/include/asm-um/pgtable.h +--- orig/include/asm-um/pgtable.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/pgtable.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,413 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Derived from include/asm-i386/pgtable.h ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UM_PGTABLE_H ++#define __UM_PGTABLE_H ++ ++#include "linux/sched.h" ++#include "asm/processor.h" ++#include "asm/page.h" ++ ++extern pgd_t swapper_pg_dir[1024]; ++ ++#define flush_cache_all() do ; while (0) ++#define flush_cache_mm(mm) do ; while (0) ++#define flush_cache_range(vma, start, end) do ; while (0) ++#define flush_cache_page(vma, vmaddr) do ; while (0) ++#define flush_page_to_ram(page) do ; while (0) ++#define flush_dcache_page(page) do ; while (0) ++#define flush_icache_range(from, to) do ; while (0) ++#define flush_icache_page(vma,pg) do ; while (0) ++#define flush_icache_user_range(vma,pg,adr,len) do ; while (0) ++ ++extern void __flush_tlb_one(unsigned long addr); ++ ++extern void pte_free(pte_t *pte); ++ ++extern void pgd_free(pgd_t *pgd); ++ ++extern int do_check_pgt_cache(int, int); ++ ++extern void *um_virt_to_phys(struct task_struct *task, unsigned long virt, ++ pte_t *pte_out); ++ ++/* zero page used for uninitialized stuff */ ++extern unsigned long *empty_zero_page; ++ ++#define pgtable_cache_init() do ; while (0) ++ ++/* PMD_SHIFT determines the size of the area a second-level page table can map */ ++#define PMD_SHIFT 22 ++#define PMD_SIZE (1UL << PMD_SHIFT) ++#define PMD_MASK (~(PMD_SIZE-1)) ++ ++/* PGDIR_SHIFT determines what a third-level page table entry can map */ ++#define PGDIR_SHIFT 22 ++#define PGDIR_SIZE (1UL << PGDIR_SHIFT) ++#define PGDIR_MASK (~(PGDIR_SIZE-1)) ++ ++/* ++ * entries per page directory level: the i386 is two-level, so ++ * we don't really have any PMD directory physically. ++ */ ++#define PTRS_PER_PTE 1024 ++#define PTRS_PER_PMD 1 ++#define PTRS_PER_PGD 1024 ++#define USER_PTRS_PER_PGD (TASK_SIZE/PGDIR_SIZE) ++#define FIRST_USER_PGD_NR 0 ++ ++#define pte_ERROR(e) \ ++ printk("%s:%d: bad pte %08lx.\n", __FILE__, __LINE__, pte_val(e)) ++#define pmd_ERROR(e) \ ++ printk("%s:%d: bad pmd %08lx.\n", __FILE__, __LINE__, pmd_val(e)) ++#define pgd_ERROR(e) \ ++ printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e)) ++ ++/* ++ * pgd entries used up by user/kernel: ++ */ ++ ++#define USER_PGD_PTRS (TASK_SIZE >> PGDIR_SHIFT) ++#define KERNEL_PGD_PTRS (PTRS_PER_PGD-USER_PGD_PTRS) ++ ++#ifndef __ASSEMBLY__ ++/* Just any arbitrary offset to the start of the vmalloc VM area: the ++ * current 8MB value just means that there will be a 8MB "hole" after the ++ * physical memory until the kernel virtual memory starts. That means that ++ * any out-of-bounds memory accesses will hopefully be caught. ++ * The vmalloc() routines leaves a hole of 4kB between each vmalloced ++ * area for the same reason. ;) ++ */ ++ ++extern unsigned long end_iomem; ++ ++#define VMALLOC_OFFSET (__va_space) ++#define VMALLOC_START ((end_iomem + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1)) ++#define VMALLOC_VMADDR(x) ((unsigned long)(x)) ++ ++#if CONFIG_HIGHMEM ++# define VMALLOC_END (PKMAP_BASE-2*PAGE_SIZE) ++#else ++# define VMALLOC_END (FIXADDR_START-2*PAGE_SIZE) ++#endif ++ ++#define _PAGE_PRESENT 0x001 ++#define _PAGE_NEWPAGE 0x002 ++#define _PAGE_PROTNONE 0x004 /* If not present */ ++#define _PAGE_RW 0x008 ++#define _PAGE_USER 0x010 ++#define _PAGE_ACCESSED 0x020 ++#define _PAGE_DIRTY 0x040 ++#define _PAGE_NEWPROT 0x080 ++ ++#define REGION_MASK 0xf0000000 ++#define REGION_SHIFT 28 ++ ++#define _PAGE_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED | _PAGE_DIRTY) ++#define _KERNPG_TABLE (_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCESSED | _PAGE_DIRTY) ++#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) ++ ++#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED) ++#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED) ++#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) ++#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) ++#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED) ++#define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED) ++ ++/* ++ * The i386 can't do page protection for execute, and considers that the same are read. ++ * Also, write permissions imply read permissions. This is the closest we can get.. ++ */ ++#define __P000 PAGE_NONE ++#define __P001 PAGE_READONLY ++#define __P010 PAGE_COPY ++#define __P011 PAGE_COPY ++#define __P100 PAGE_READONLY ++#define __P101 PAGE_READONLY ++#define __P110 PAGE_COPY ++#define __P111 PAGE_COPY ++ ++#define __S000 PAGE_NONE ++#define __S001 PAGE_READONLY ++#define __S010 PAGE_SHARED ++#define __S011 PAGE_SHARED ++#define __S100 PAGE_READONLY ++#define __S101 PAGE_READONLY ++#define __S110 PAGE_SHARED ++#define __S111 PAGE_SHARED ++ ++/* ++ * Define this if things work differently on an i386 and an i486: ++ * it will (on an i486) warn about kernel memory accesses that are ++ * done without a 'verify_area(VERIFY_WRITE,..)' ++ */ ++#undef TEST_VERIFY_AREA ++ ++/* page table for 0-4MB for everybody */ ++extern unsigned long pg0[1024]; ++ ++/* ++ * BAD_PAGETABLE is used when we need a bogus page-table, while ++ * BAD_PAGE is used for a bogus page. ++ * ++ * ZERO_PAGE is a global shared page that is always zero: used ++ * for zero-mapped memory areas etc.. ++ */ ++extern pte_t __bad_page(void); ++extern pte_t * __bad_pagetable(void); ++ ++#define BAD_PAGETABLE __bad_pagetable() ++#define BAD_PAGE __bad_page() ++ ++#define ZERO_PAGE(vaddr) virt_to_page(empty_zero_page) ++ ++/* number of bits that fit into a memory pointer */ ++#define BITS_PER_PTR (8*sizeof(unsigned long)) ++ ++/* to align the pointer to a pointer address */ ++#define PTR_MASK (~(sizeof(void*)-1)) ++ ++/* sizeof(void*)==1<<SIZEOF_PTR_LOG2 */ ++/* 64-bit machines, beware! SRB. */ ++#define SIZEOF_PTR_LOG2 2 ++ ++/* to find an entry in a page-table */ ++#define PAGE_PTR(address) \ ++((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK) ++ ++#define pte_none(x) !(pte_val(x) & ~_PAGE_NEWPAGE) ++#define pte_present(x) (pte_val(x) & (_PAGE_PRESENT | _PAGE_PROTNONE)) ++ ++#define pte_clear(xp) do { pte_val(*(xp)) = _PAGE_NEWPAGE; } while (0) ++ ++#define pmd_none(x) (!(pmd_val(x) & ~_PAGE_NEWPAGE)) ++#define pmd_bad(x) ((pmd_val(x) & (~PAGE_MASK & ~_PAGE_USER)) != _KERNPG_TABLE) ++#define pmd_present(x) (pmd_val(x) & _PAGE_PRESENT) ++#define pmd_clear(xp) do { pmd_val(*(xp)) = _PAGE_NEWPAGE; } while (0) ++ ++#define pmd_newpage(x) (pmd_val(x) & _PAGE_NEWPAGE) ++#define pmd_mkuptodate(x) (pmd_val(x) &= ~_PAGE_NEWPAGE) ++ ++/* ++ * The "pgd_xxx()" functions here are trivial for a folded two-level ++ * setup: the pgd is never bad, and a pmd always exists (as it's folded ++ * into the pgd entry) ++ */ ++static inline int pgd_none(pgd_t pgd) { return 0; } ++static inline int pgd_bad(pgd_t pgd) { return 0; } ++static inline int pgd_present(pgd_t pgd) { return 1; } ++static inline void pgd_clear(pgd_t * pgdp) { } ++ ++#define pages_to_mb(x) ((x) >> (20-PAGE_SHIFT)) ++ ++#define pte_page(pte) virt_to_page(__va(pte_val(pte))) ++#define pmd_page(pmd) ((unsigned long) __va(pmd_val(pmd) & PAGE_MASK)) ++ ++extern struct page *phys_to_page(const unsigned long phys); ++extern struct page *__virt_to_page(const unsigned long virt); ++#define virt_to_page(addr) __virt_to_page((const unsigned long) addr) ++ ++static inline pte_t pte_mknewprot(pte_t pte) ++{ ++ pte_val(pte) |= _PAGE_NEWPROT; ++ return(pte); ++} ++ ++static inline pte_t pte_mknewpage(pte_t pte) ++{ ++ pte_val(pte) |= _PAGE_NEWPAGE; ++ return(pte); ++} ++ ++static inline void set_pte(pte_t *pteptr, pte_t pteval) ++{ ++ /* If it's a swap entry, it needs to be marked _PAGE_NEWPAGE so ++ * fix_range knows to unmap it. _PAGE_NEWPROT is specific to ++ * mapped pages. ++ */ ++ *pteptr = pte_mknewpage(pteval); ++ if(pte_present(*pteptr)) *pteptr = pte_mknewprot(*pteptr); ++} ++ ++/* ++ * (pmds are folded into pgds so this doesnt get actually called, ++ * but the define is needed for a generic inline function.) ++ */ ++#define set_pmd(pmdptr, pmdval) (*(pmdptr) = pmdval) ++#define set_pgd(pgdptr, pgdval) (*(pgdptr) = pgdval) ++ ++/* ++ * The following only work if pte_present() is true. ++ * Undefined behaviour if not.. ++ */ ++static inline int pte_read(pte_t pte) ++{ ++ return((pte_val(pte) & _PAGE_USER) && ++ !(pte_val(pte) & _PAGE_PROTNONE)); ++} ++ ++static inline int pte_exec(pte_t pte){ ++ return((pte_val(pte) & _PAGE_USER) && ++ !(pte_val(pte) & _PAGE_PROTNONE)); ++} ++ ++static inline int pte_write(pte_t pte) ++{ ++ return((pte_val(pte) & _PAGE_RW) && ++ !(pte_val(pte) & _PAGE_PROTNONE)); ++} ++ ++static inline int pte_dirty(pte_t pte) { return pte_val(pte) & _PAGE_DIRTY; } ++static inline int pte_young(pte_t pte) { return pte_val(pte) & _PAGE_ACCESSED; } ++static inline int pte_newpage(pte_t pte) { return pte_val(pte) & _PAGE_NEWPAGE; } ++static inline int pte_newprot(pte_t pte) ++{ ++ return(pte_present(pte) && (pte_val(pte) & _PAGE_NEWPROT)); ++} ++ ++static inline pte_t pte_rdprotect(pte_t pte) ++{ ++ pte_val(pte) &= ~_PAGE_USER; ++ return(pte_mknewprot(pte)); ++} ++ ++static inline pte_t pte_exprotect(pte_t pte) ++{ ++ pte_val(pte) &= ~_PAGE_USER; ++ return(pte_mknewprot(pte)); ++} ++ ++static inline pte_t pte_mkclean(pte_t pte) ++{ ++ pte_val(pte) &= ~_PAGE_DIRTY; ++ return(pte); ++} ++ ++static inline pte_t pte_mkold(pte_t pte) ++{ ++ pte_val(pte) &= ~_PAGE_ACCESSED; ++ return(pte); ++} ++ ++static inline pte_t pte_wrprotect(pte_t pte) ++{ ++ pte_val(pte) &= ~_PAGE_RW; ++ return(pte_mknewprot(pte)); ++} ++ ++static inline pte_t pte_mkread(pte_t pte) ++{ ++ pte_val(pte) |= _PAGE_USER; ++ return(pte_mknewprot(pte)); ++} ++ ++static inline pte_t pte_mkexec(pte_t pte) ++{ ++ pte_val(pte) |= _PAGE_USER; ++ return(pte_mknewprot(pte)); ++} ++ ++static inline pte_t pte_mkdirty(pte_t pte) ++{ ++ pte_val(pte) |= _PAGE_DIRTY; ++ return(pte); ++} ++ ++static inline pte_t pte_mkyoung(pte_t pte) ++{ ++ pte_val(pte) |= _PAGE_ACCESSED; ++ return(pte); ++} ++ ++static inline pte_t pte_mkwrite(pte_t pte) ++{ ++ pte_val(pte) |= _PAGE_RW; ++ return(pte_mknewprot(pte)); ++} ++ ++static inline pte_t pte_mkuptodate(pte_t pte) ++{ ++ pte_val(pte) &= ~_PAGE_NEWPAGE; ++ if(pte_present(pte)) pte_val(pte) &= ~_PAGE_NEWPROT; ++ return(pte); ++} ++ ++extern unsigned long page_to_phys(struct page *page); ++ ++/* ++ * Conversion functions: convert a page and protection to a page entry, ++ * and a page entry and page directory to the page they refer to. ++ */ ++ ++extern pte_t mk_pte(struct page *page, pgprot_t pgprot); ++ ++/* This takes a physical page address that is used by the remapping ++ * functions ++ */ ++#define mk_pte_phys(phys, pgprot) \ ++ (pte_mknewpage(mk_pte(virt_to_page(__va(phys)), pgprot))) ++ ++static inline pte_t pte_modify(pte_t pte, pgprot_t newprot) ++{ ++ pte_val(pte) = (pte_val(pte) & _PAGE_CHG_MASK) | pgprot_val(newprot); ++ if(pte_present(pte)) pte = pte_mknewpage(pte_mknewprot(pte)); ++ return pte; ++} ++ ++/* to find an entry in a page-table-directory. */ ++#define pgd_index(address) ((address >> PGDIR_SHIFT) & (PTRS_PER_PGD-1)) ++#define __pgd_offset(address) pgd_index(address) ++ ++/* to find an entry in a page-table-directory */ ++#define pgd_offset(mm, address) \ ++((mm)->pgd + ((address) >> PGDIR_SHIFT)) ++ ++/* to find an entry in a kernel page-table-directory */ ++#define pgd_offset_k(address) pgd_offset(&init_mm, address) ++ ++#define __pmd_offset(address) \ ++ (((address) >> PMD_SHIFT) & (PTRS_PER_PMD-1)) ++ ++/* Find an entry in the second-level page table.. */ ++static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address) ++{ ++ return (pmd_t *) dir; ++} ++ ++/* Find an entry in the third-level page table.. */ ++#define pte_offset(pmd, address) \ ++ ((pte_t *) (pmd_page(*pmd) + ((address>>10) & ((PTRS_PER_PTE-1)<<2)))) ++ ++#define update_mmu_cache(vma,address,pte) do ; while (0) ++ ++/* Encode and de-code a swap entry */ ++#define SWP_TYPE(x) (((x).val >> 3) & 0x7f) ++#define SWP_OFFSET(x) ((x).val >> 10) ++ ++#define SWP_ENTRY(type, offset) \ ++ ((swp_entry_t) { ((type) << 3) | ((offset) << 10) }) ++#define pte_to_swp_entry(pte) \ ++ ((swp_entry_t) { pte_val(pte_mkuptodate(pte)) }) ++#define swp_entry_to_pte(x) ((pte_t) { (x).val }) ++ ++#define PageSkip(x) (0) ++#define kern_addr_valid(addr) (1) ++ ++#include <asm-generic/pgtable.h> ++ ++#endif ++ ++#endif ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/include/asm-um/poll.h um/include/asm-um/poll.h +--- orig/include/asm-um/poll.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/poll.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_POLL_H ++#define __UM_POLL_H ++ ++#include "asm/arch/poll.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/posix_types.h um/include/asm-um/posix_types.h +--- orig/include/asm-um/posix_types.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/posix_types.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_POSIX_TYPES_H ++#define __UM_POSIX_TYPES_H ++ ++#include "asm/arch/posix_types.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/processor-generic.h um/include/asm-um/processor-generic.h +--- orig/include/asm-um/processor-generic.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/processor-generic.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,177 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UM_PROCESSOR_GENERIC_H ++#define __UM_PROCESSOR_GENERIC_H ++ ++struct pt_regs; ++ ++struct task_struct; ++ ++#include "linux/config.h" ++#include "linux/signal.h" ++#include "asm/ptrace.h" ++#include "asm/siginfo.h" ++#include "choose-mode.h" ++ ++struct mm_struct; ++ ++#define current_text_addr() ((void *) 0) ++ ++#define cpu_relax() do ; while (0) ++ ++struct thread_struct { ++ int forking; ++ unsigned long kernel_stack; ++ int nsyscalls; ++ struct pt_regs regs; ++ unsigned long cr2; ++ int err; ++ unsigned long trap_no; ++ void *fault_addr; ++ void *fault_catcher; ++ struct task_struct *prev_sched; ++ unsigned long temp_stack; ++ void *exec_buf; ++ struct arch_thread arch; ++ union { ++#ifdef CONFIG_MODE_TT ++ struct { ++ int extern_pid; ++ int tracing; ++ int switch_pipe[2]; ++ int singlestep_syscall; ++ int vm_seq; ++ } tt; ++#endif ++#ifdef CONFIG_MODE_SKAS ++ struct { ++ void *switch_buf; ++ void *fork_buf; ++ int mm_count; ++ } skas; ++#endif ++ } mode; ++ struct { ++ int op; ++ union { ++ struct { ++ int pid; ++ } fork, exec; ++ struct { ++ int (*proc)(void *); ++ void *arg; ++ } thread; ++ struct { ++ void (*proc)(void *); ++ void *arg; ++ } cb; ++ } u; ++ } request; ++}; ++ ++#define INIT_THREAD \ ++{ \ ++ .forking = 0, \ ++ .kernel_stack = 0, \ ++ .nsyscalls = 0, \ ++ .regs = EMPTY_REGS, \ ++ .cr2 = 0, \ ++ .err = 0, \ ++ .fault_addr = NULL, \ ++ .prev_sched = NULL, \ ++ .temp_stack = 0, \ ++ .exec_buf = NULL, \ ++ .arch = INIT_ARCH_THREAD, \ ++ .request = { 0 } \ ++} ++ ++#define THREAD_SIZE ((1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE) ++ ++typedef struct { ++ unsigned long seg; ++} mm_segment_t; ++ ++extern struct task_struct *alloc_task_struct(void); ++extern void free_task_struct(struct task_struct *task); ++ ++#define get_task_struct(tsk) atomic_inc(&virt_to_page(tsk)->count) ++ ++extern void release_thread(struct task_struct *); ++extern int arch_kernel_thread(int (*fn)(void *), void * arg, ++ unsigned long flags); ++extern void dump_thread(struct pt_regs *regs, struct user *u); ++ ++extern unsigned long thread_saved_pc(struct thread_struct *t); ++ ++static inline void mm_copy_segments(struct mm_struct *from_mm, ++ struct mm_struct *new_mm) ++{ ++} ++ ++static inline void copy_segments(struct task_struct *p, ++ struct mm_struct *new_mm) ++{ ++} ++ ++static inline void release_segments(struct mm_struct *mm) ++{ ++} ++ ++#define init_task (init_task_union.task) ++#define init_stack (init_task_union.stack) ++ ++/* ++ * User space process size: 3GB (default). ++ */ ++extern unsigned long task_size; ++ ++#define TASK_SIZE (task_size) ++ ++/* This decides where the kernel will search for a free chunk of vm ++ * space during mmap's. ++ */ ++#define TASK_UNMAPPED_BASE (0x40000000) ++ ++extern void start_thread(struct pt_regs *regs, unsigned long entry, ++ unsigned long stack); ++ ++struct cpuinfo_um { ++ unsigned long loops_per_jiffy; ++ unsigned long *pgd_quick; ++ unsigned long *pmd_quick; ++ unsigned long *pte_quick; ++ unsigned long pgtable_cache_sz; ++ int ipi_pipe[2]; ++}; ++ ++extern struct cpuinfo_um boot_cpu_data; ++ ++#define my_cpu_data cpu_data[smp_processor_id()] ++ ++#ifdef CONFIG_SMP ++extern struct cpuinfo_um cpu_data[]; ++#define current_cpu_data cpu_data[smp_processor_id()] ++#else ++#define cpu_data (&boot_cpu_data) ++#define current_cpu_data boot_cpu_data ++#endif ++ ++#define KSTK_EIP(tsk) (PT_REGS_IP(&tsk->thread.regs)) ++#define KSTK_ESP(tsk) (PT_REGS_SP(&tsk->thread.regs)) ++#define get_wchan(p) (0) ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/include/asm-um/processor-i386.h um/include/asm-um/processor-i386.h +--- orig/include/asm-um/processor-i386.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/processor-i386.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,35 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UM_PROCESSOR_I386_H ++#define __UM_PROCESSOR_I386_H ++ ++extern int cpu_has_xmm; ++extern int cpu_has_cmov; ++ ++struct arch_thread { ++ unsigned long debugregs[8]; ++ int debugregs_seq; ++}; ++ ++#define INIT_ARCH_THREAD { .debugregs = { [ 0 ... 7 ] = 0 }, \ ++ .debugregs_seq = 0 } ++ ++#include "asm/arch/user.h" ++ ++#include "asm/processor-generic.h" ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/include/asm-um/processor-ppc.h um/include/asm-um/processor-ppc.h +--- orig/include/asm-um/processor-ppc.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/processor-ppc.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,15 @@ ++#ifndef __UM_PROCESSOR_PPC_H ++#define __UM_PROCESSOR_PPC_H ++ ++#if defined(__ASSEMBLY__) ++ ++#define CONFIG_ALL_PPC ++#include "arch/processor.h" ++ ++#else ++ ++#include "asm/processor-generic.h" ++ ++#endif ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/ptrace-generic.h um/include/asm-um/ptrace-generic.h +--- orig/include/asm-um/ptrace-generic.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/ptrace-generic.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,74 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UM_PTRACE_GENERIC_H ++#define __UM_PTRACE_GENERIC_H ++ ++#ifndef __ASSEMBLY__ ++ ++#include "linux/config.h" ++ ++#include "asm/current.h" ++ ++#define pt_regs pt_regs_subarch ++#define show_regs show_regs_subarch ++ ++#include "asm/arch/ptrace.h" ++ ++#undef pt_regs ++#undef show_regs ++#undef user_mode ++#undef instruction_pointer ++ ++#include "sysdep/ptrace.h" ++#include "skas_ptrace.h" ++ ++struct pt_regs { ++ union uml_pt_regs regs; ++}; ++ ++#define EMPTY_REGS { regs : EMPTY_UML_PT_REGS } ++ ++#define PT_REGS_IP(r) UPT_IP(&(r)->regs) ++#define PT_REGS_SP(r) UPT_SP(&(r)->regs) ++ ++#define PT_REG(r, reg) UPT_REG(&(r)->regs, reg) ++#define PT_REGS_SET(r, reg, val) UPT_SET(&(r)->regs, reg, val) ++ ++#define PT_REGS_SET_SYSCALL_RETURN(r, res) \ ++ UPT_SET_SYSCALL_RETURN(&(r)->regs, res) ++#define PT_REGS_RESTART_SYSCALL(r) UPT_RESTART_SYSCALL(&(r)->regs) ++ ++#define PT_REGS_SYSCALL_NR(r) UPT_SYSCALL_NR(&(r)->regs) ++ ++#define PT_REGS_SC(r) UPT_SC(&(r)->regs) ++ ++struct task_struct; ++ ++extern unsigned long getreg(struct task_struct *child, int regno); ++extern int putreg(struct task_struct *child, int regno, unsigned long value); ++extern int get_fpregs(unsigned long buf, struct task_struct *child); ++extern int set_fpregs(unsigned long buf, struct task_struct *child); ++extern int get_fpxregs(unsigned long buf, struct task_struct *child); ++extern int set_fpxregs(unsigned long buf, struct task_struct *tsk); ++ ++extern void show_regs(struct pt_regs *regs); ++ ++#define INIT_TASK_SIZE ((1 << CONFIG_KERNEL_STACK_ORDER) * PAGE_SIZE) ++ ++#endif ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/include/asm-um/ptrace-i386.h um/include/asm-um/ptrace-i386.h +--- orig/include/asm-um/ptrace-i386.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/ptrace-i386.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,46 @@ ++/* ++ * Copyright (C) 2000, 2001, 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UM_PTRACE_I386_H ++#define __UM_PTRACE_I386_H ++ ++#include "sysdep/ptrace.h" ++#include "asm/ptrace-generic.h" ++ ++#define PT_REGS_EAX(r) UPT_EAX(&(r)->regs) ++#define PT_REGS_EBX(r) UPT_EBX(&(r)->regs) ++#define PT_REGS_ECX(r) UPT_ECX(&(r)->regs) ++#define PT_REGS_EDX(r) UPT_EDX(&(r)->regs) ++#define PT_REGS_ESI(r) UPT_ESI(&(r)->regs) ++#define PT_REGS_EDI(r) UPT_EDI(&(r)->regs) ++#define PT_REGS_EBP(r) UPT_EBP(&(r)->regs) ++ ++#define PT_REGS_CS(r) UPT_CS(&(r)->regs) ++#define PT_REGS_SS(r) UPT_SS(&(r)->regs) ++#define PT_REGS_DS(r) UPT_DS(&(r)->regs) ++#define PT_REGS_ES(r) UPT_ES(&(r)->regs) ++#define PT_REGS_FS(r) UPT_FS(&(r)->regs) ++#define PT_REGS_GS(r) UPT_GS(&(r)->regs) ++ ++#define PT_REGS_EFLAGS(r) UPT_EFLAGS(&(r)->regs) ++ ++#define PT_REGS_ORIG_SYSCALL(r) PT_REGS_EAX(r) ++#define PT_REGS_SYSCALL_RET(r) PT_REGS_EAX(r) ++#define PT_FIX_EXEC_STACK(sp) do ; while(0) ++ ++#define user_mode(r) UPT_IS_USER(&(r)->regs) ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/include/asm-um/resource.h um/include/asm-um/resource.h +--- orig/include/asm-um/resource.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/resource.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_RESOURCE_H ++#define __UM_RESOURCE_H ++ ++#include "asm/arch/resource.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/rwlock.h um/include/asm-um/rwlock.h +--- orig/include/asm-um/rwlock.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/rwlock.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_RWLOCK_H ++#define __UM_RWLOCK_H ++ ++#include "asm/arch/rwlock.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/rwsem.h um/include/asm-um/rwsem.h +--- orig/include/asm-um/rwsem.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/rwsem.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,10 @@ ++#ifndef __UM_RWSEM_H__ ++#define __UM_RWSEM_H__ ++ ++#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 96) ++#define __builtin_expect(exp,c) (exp) ++#endif ++ ++#include "asm/arch/rwsem.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/scatterlist.h um/include/asm-um/scatterlist.h +--- orig/include/asm-um/scatterlist.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/scatterlist.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_SCATTERLIST_H ++#define __UM_SCATTERLIST_H ++ ++#include "asm/arch/scatterlist.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/segment.h um/include/asm-um/segment.h +--- orig/include/asm-um/segment.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/segment.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,4 @@ ++#ifndef __UM_SEGMENT_H ++#define __UM_SEGMENT_H ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/semaphore.h um/include/asm-um/semaphore.h +--- orig/include/asm-um/semaphore.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/semaphore.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,6 @@ ++#ifndef __UM_SEMAPHORE_H ++#define __UM_SEMAPHORE_H ++ ++#include "asm/arch/semaphore.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/sembuf.h um/include/asm-um/sembuf.h +--- orig/include/asm-um/sembuf.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/sembuf.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_SEMBUF_H ++#define __UM_SEMBUF_H ++ ++#include "asm/arch/sembuf.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/serial.h um/include/asm-um/serial.h +--- orig/include/asm-um/serial.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/serial.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_SERIAL_H ++#define __UM_SERIAL_H ++ ++#include "asm/arch/serial.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/shmbuf.h um/include/asm-um/shmbuf.h +--- orig/include/asm-um/shmbuf.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/shmbuf.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_SHMBUF_H ++#define __UM_SHMBUF_H ++ ++#include "asm/arch/shmbuf.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/shmparam.h um/include/asm-um/shmparam.h +--- orig/include/asm-um/shmparam.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/shmparam.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_SHMPARAM_H ++#define __UM_SHMPARAM_H ++ ++#include "asm/arch/shmparam.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/sigcontext-generic.h um/include/asm-um/sigcontext-generic.h +--- orig/include/asm-um/sigcontext-generic.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/sigcontext-generic.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_SIGCONTEXT_GENERIC_H ++#define __UM_SIGCONTEXT_GENERIC_H ++ ++#include "asm/arch/sigcontext.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/sigcontext-i386.h um/include/asm-um/sigcontext-i386.h +--- orig/include/asm-um/sigcontext-i386.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/sigcontext-i386.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_SIGCONTEXT_I386_H ++#define __UM_SIGCONTEXT_I386_H ++ ++#include "asm/sigcontext-generic.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/sigcontext-ppc.h um/include/asm-um/sigcontext-ppc.h +--- orig/include/asm-um/sigcontext-ppc.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/sigcontext-ppc.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,10 @@ ++#ifndef __UM_SIGCONTEXT_PPC_H ++#define __UM_SIGCONTEXT_PPC_H ++ ++#define pt_regs sys_pt_regs ++ ++#include "asm/sigcontext-generic.h" ++ ++#undef pt_regs ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/siginfo.h um/include/asm-um/siginfo.h +--- orig/include/asm-um/siginfo.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/siginfo.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,6 @@ ++#ifndef __UM_SIGINFO_H ++#define __UM_SIGINFO_H ++ ++#include "asm/arch/siginfo.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/signal.h um/include/asm-um/signal.h +--- orig/include/asm-um/signal.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/signal.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,22 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UM_SIGNAL_H ++#define __UM_SIGNAL_H ++ ++#include "asm/arch/signal.h" ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/include/asm-um/smp.h um/include/asm-um/smp.h +--- orig/include/asm-um/smp.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/smp.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,19 @@ ++#ifndef __UM_SMP_H ++#define __UM_SMP_H ++ ++#ifdef CONFIG_SMP ++ ++#include "linux/config.h" ++#include "asm/current.h" ++ ++#define smp_processor_id() (current->processor) ++#define cpu_logical_map(n) (n) ++#define cpu_number_map(n) (n) ++#define PROC_CHANGE_PENALTY 15 /* Pick a number, any number */ ++extern int hard_smp_processor_id(void); ++extern unsigned long cpu_online_map; ++#define NO_PROC_ID -1 ++ ++#endif ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/smplock.h um/include/asm-um/smplock.h +--- orig/include/asm-um/smplock.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/smplock.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,6 @@ ++#ifndef __UM_SMPLOCK_H ++#define __UM_SMPLOCK_H ++ ++#include "asm/arch/smplock.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/socket.h um/include/asm-um/socket.h +--- orig/include/asm-um/socket.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/socket.h 2003-11-07 02:10:43.000000000 -0500 +@@ -0,0 +1,6 @@ ++#ifndef __UM_SOCKET_H ++#define __UM_SOCKET_H ++ ++#include "asm/arch/socket.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/sockios.h um/include/asm-um/sockios.h +--- orig/include/asm-um/sockios.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/sockios.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_SOCKIOS_H ++#define __UM_SOCKIOS_H ++ ++#include "asm/arch/sockios.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/softirq.h um/include/asm-um/softirq.h +--- orig/include/asm-um/softirq.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/softirq.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,13 @@ ++#ifndef __UM_SOFTIRQ_H ++#define __UM_SOFTIRQ_H ++ ++#include "linux/smp.h" ++#include "asm/system.h" ++#include "asm/processor.h" ++ ++/* A gratuitous name change */ ++#define i386_bh_lock um_bh_lock ++#include "asm/arch/softirq.h" ++#undef i386_bh_lock ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/spinlock.h um/include/asm-um/spinlock.h +--- orig/include/asm-um/spinlock.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/spinlock.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,10 @@ ++#ifndef __UM_SPINLOCK_H ++#define __UM_SPINLOCK_H ++ ++#include "linux/config.h" ++ ++#ifdef CONFIG_SMP ++#include "asm/arch/spinlock.h" ++#endif ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/statfs.h um/include/asm-um/statfs.h +--- orig/include/asm-um/statfs.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/statfs.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,6 @@ ++#ifndef _UM_STATFS_H ++#define _UM_STATFS_H ++ ++#include "asm/arch/statfs.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/stat.h um/include/asm-um/stat.h +--- orig/include/asm-um/stat.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/stat.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_STAT_H ++#define __UM_STAT_H ++ ++#include "asm/arch/stat.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/string.h um/include/asm-um/string.h +--- orig/include/asm-um/string.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/string.h 2003-12-16 22:26:55.000000000 -0500 +@@ -0,0 +1,7 @@ ++#ifndef __UM_STRING_H ++#define __UM_STRING_H ++ ++#include "asm/arch/string.h" ++#include "asm/archparam.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/system-generic.h um/include/asm-um/system-generic.h +--- orig/include/asm-um/system-generic.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/system-generic.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,50 @@ ++#ifndef __UM_SYSTEM_GENERIC_H ++#define __UM_SYSTEM_GENERIC_H ++ ++#include "asm/arch/system.h" ++ ++#undef prepare_to_switch ++#undef switch_to ++#undef __save_flags ++#undef save_flags ++#undef __restore_flags ++#undef restore_flags ++#undef __cli ++#undef __sti ++#undef cli ++#undef sti ++#undef local_irq_save ++#undef local_irq_restore ++#undef local_irq_disable ++#undef local_irq_enable ++ ++#define prepare_to_switch() do ; while(0) ++ ++void *_switch_to(void *prev, void *next); ++ ++#define switch_to(prev, next, last) prev = _switch_to(prev, next) ++ ++extern int get_signals(void); ++extern int set_signals(int enable); ++extern void block_signals(void); ++extern void unblock_signals(void); ++ ++#define local_irq_save(flags) do { (flags) = set_signals(0); } while(0) ++ ++#define local_irq_restore(flags) do { set_signals(flags); } while(0) ++ ++#define local_irq_enable() unblock_signals() ++#define local_irq_disable() block_signals() ++ ++#define __sti() unblock_signals() ++#define sti() unblock_signals() ++#define __cli() block_signals() ++#define cli() block_signals() ++ ++#define __save_flags(x) do { (x) = get_signals(); } while(0) ++#define save_flags(x) __save_flags(x) ++ ++#define __restore_flags(x) local_irq_restore(x) ++#define restore_flags(x) __restore_flags(x) ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/system-i386.h um/include/asm-um/system-i386.h +--- orig/include/asm-um/system-i386.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/system-i386.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,39 @@ ++#ifndef __UM_SYSTEM_I386_H ++#define __UM_SYSTEM_I386_H ++ ++#include "asm/system-generic.h" ++ ++#define __HAVE_ARCH_CMPXCHG 1 ++ ++static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old, ++ unsigned long new, int size) ++{ ++ unsigned long prev; ++ switch (size) { ++ case 1: ++ __asm__ __volatile__(LOCK_PREFIX "cmpxchgb %b1,%2" ++ : "=a"(prev) ++ : "q"(new), "m"(*__xg(ptr)), "0"(old) ++ : "memory"); ++ return prev; ++ case 2: ++ __asm__ __volatile__(LOCK_PREFIX "cmpxchgw %w1,%2" ++ : "=a"(prev) ++ : "q"(new), "m"(*__xg(ptr)), "0"(old) ++ : "memory"); ++ return prev; ++ case 4: ++ __asm__ __volatile__(LOCK_PREFIX "cmpxchgl %1,%2" ++ : "=a"(prev) ++ : "q"(new), "m"(*__xg(ptr)), "0"(old) ++ : "memory"); ++ return prev; ++ } ++ return old; ++} ++ ++#define cmpxchg(ptr,o,n)\ ++ ((__typeof__(*(ptr)))__cmpxchg((ptr),(unsigned long)(o),\ ++ (unsigned long)(n),sizeof(*(ptr)))) ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/system-ppc.h um/include/asm-um/system-ppc.h +--- orig/include/asm-um/system-ppc.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/system-ppc.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,12 @@ ++#ifndef __UM_SYSTEM_PPC_H ++#define __UM_SYSTEM_PPC_H ++ ++#define _switch_to _ppc_switch_to ++ ++#include "asm/arch/system.h" ++ ++#undef _switch_to ++ ++#include "asm/system-generic.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/termbits.h um/include/asm-um/termbits.h +--- orig/include/asm-um/termbits.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/termbits.h 2003-11-07 02:10:43.000000000 -0500 +@@ -0,0 +1,6 @@ ++#ifndef __UM_TERMBITS_H ++#define __UM_TERMBITS_H ++ ++#include "asm/arch/termbits.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/termios.h um/include/asm-um/termios.h +--- orig/include/asm-um/termios.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/termios.h 2003-12-16 22:26:55.000000000 -0500 +@@ -0,0 +1,6 @@ ++#ifndef __UM_TERMIOS_H ++#define __UM_TERMIOS_H ++ ++#include "asm/arch/termios.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/timex.h um/include/asm-um/timex.h +--- orig/include/asm-um/timex.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/timex.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,18 @@ ++#ifndef __UM_TIMEX_H ++#define __UM_TIMEX_H ++ ++#include "linux/time.h" ++ ++typedef unsigned long cycles_t; ++ ++#define cacheflush_time (0) ++ ++static inline cycles_t get_cycles (void) ++{ ++ return 0; ++} ++ ++#define vxtime_lock() do ; while (0) ++#define vxtime_unlock() do ; while (0) ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/tlb.h um/include/asm-um/tlb.h +--- orig/include/asm-um/tlb.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/tlb.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1 @@ ++#include <asm-generic/tlb.h> +diff -Naur -X ../exclude-files orig/include/asm-um/types.h um/include/asm-um/types.h +--- orig/include/asm-um/types.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/types.h 2003-12-15 00:26:37.000000000 -0500 +@@ -0,0 +1,6 @@ ++#ifndef __UM_TYPES_H ++#define __UM_TYPES_H ++ ++#include "asm/arch/types.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/uaccess.h um/include/asm-um/uaccess.h +--- orig/include/asm-um/uaccess.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/uaccess.h 2003-12-17 02:16:13.000000000 -0500 +@@ -0,0 +1,99 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __UM_UACCESS_H ++#define __UM_UACCESS_H ++ ++#include "linux/sched.h" ++ ++#define VERIFY_READ 0 ++#define VERIFY_WRITE 1 ++ ++/* ++ * The fs value determines whether argument validity checking should be ++ * performed or not. If get_fs() == USER_DS, checking is performed, with ++ * get_fs() == KERNEL_DS, checking is bypassed. ++ * ++ * For historical reasons, these macros are grossly misnamed. ++ */ ++ ++#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) }) ++ ++#define KERNEL_DS MAKE_MM_SEG(0xFFFFFFFF) ++#define USER_DS MAKE_MM_SEG(TASK_SIZE) ++ ++#define get_ds() (KERNEL_DS) ++#define get_fs() (current->addr_limit) ++#define set_fs(x) (current->addr_limit = (x)) ++ ++#define segment_eq(a, b) ((a).seg == (b).seg) ++ ++#include "um_uaccess.h" ++ ++#define __copy_from_user(to, from, n) copy_from_user(to, from, n) ++ ++#define __copy_to_user(to, from, n) copy_to_user(to, from, n) ++ ++#define __get_user(x, ptr) \ ++({ \ ++ const __typeof__(ptr) __private_ptr = ptr; \ ++ __typeof__(*(__private_ptr)) __private_val; \ ++ int __private_ret = -EFAULT; \ ++ (x) = 0; \ ++ if (__copy_from_user(&__private_val, (__private_ptr), \ ++ sizeof(*(__private_ptr))) == 0) {\ ++ (x) = (__typeof__(*(__private_ptr))) __private_val; \ ++ __private_ret = 0; \ ++ } \ ++ __private_ret; \ ++}) ++ ++#define get_user(x, ptr) \ ++({ \ ++ const __typeof__((*ptr)) *private_ptr = (ptr); \ ++ (access_ok(VERIFY_READ, private_ptr, sizeof(*private_ptr)) ? \ ++ __get_user(x, private_ptr) : ((x) = 0, -EFAULT)); \ ++}) ++ ++#define __put_user(x, ptr) \ ++({ \ ++ __typeof__(ptr) __private_ptr = ptr; \ ++ __typeof__(*(__private_ptr)) __private_val; \ ++ int __private_ret = -EFAULT; \ ++ __private_val = (__typeof__(*(__private_ptr))) (x); \ ++ if (__copy_to_user((__private_ptr), &__private_val, \ ++ sizeof(*(__private_ptr))) == 0) { \ ++ __private_ret = 0; \ ++ } \ ++ __private_ret; \ ++}) ++ ++#define put_user(x, ptr) \ ++({ \ ++ __typeof__(*(ptr)) *private_ptr = (ptr); \ ++ (access_ok(VERIFY_WRITE, private_ptr, sizeof(*private_ptr)) ? \ ++ __put_user(x, private_ptr) : -EFAULT); \ ++}) ++ ++#define strlen_user(str) strnlen_user(str, ~0UL >> 1) ++ ++struct exception_table_entry ++{ ++ unsigned long insn; ++ unsigned long fixup; ++}; ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/include/asm-um/ucontext.h um/include/asm-um/ucontext.h +--- orig/include/asm-um/ucontext.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/ucontext.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef _ASM_UM_UCONTEXT_H ++#define _ASM_UM_UCONTEXT_H ++ ++#include "asm/arch/ucontext.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/unaligned.h um/include/asm-um/unaligned.h +--- orig/include/asm-um/unaligned.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/unaligned.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_UNALIGNED_H ++#define __UM_UNALIGNED_H ++ ++#include "asm/arch/unaligned.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/unistd.h um/include/asm-um/unistd.h +--- orig/include/asm-um/unistd.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/unistd.h 2003-12-17 02:16:14.000000000 -0500 +@@ -0,0 +1,121 @@ ++/* ++ * Copyright (C) 2000, 2001 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef _UM_UNISTD_H_ ++#define _UM_UNISTD_H_ ++ ++#include "linux/resource.h" ++#include "asm/uaccess.h" ++ ++extern long sys_open(const char *filename, int flags, int mode); ++extern long sys_dup(unsigned int fildes); ++extern long sys_close(unsigned int fd); ++extern int um_execve(const char *file, char *const argv[], char *const env[]); ++extern long sys_setsid(void); ++extern long sys_waitpid(pid_t pid, unsigned int * stat_addr, int options); ++extern long sys_wait4(pid_t pid,unsigned int *stat_addr, int options, ++ struct rusage *ru); ++extern long sys_mount(char *dev_name, char *dir_name, char *type, ++ unsigned long flags, void *data); ++extern long sys_select(int n, fd_set *inp, fd_set *outp, fd_set *exp, ++ struct timeval *tvp); ++extern long sys_lseek(unsigned int fildes, unsigned long offset, int whence); ++extern long sys_read(unsigned int fildes, char *buf, int len); ++extern long sys_write(unsigned int fildes, char *buf, int len); ++ ++#ifdef __KERNEL_SYSCALLS__ ++ ++#define KERNEL_CALL(ret_t, sys, args...) \ ++ mm_segment_t fs = get_fs(); \ ++ ret_t ret; \ ++ set_fs(KERNEL_DS); \ ++ ret = sys(args); \ ++ set_fs(fs); \ ++ if (ret >= 0) \ ++ return ret; \ ++ errno = -(long)ret; \ ++ return -1; ++ ++static inline long open(const char *pathname, int flags, int mode) ++{ ++ KERNEL_CALL(int, sys_open, pathname, flags, mode) ++} ++ ++static inline long dup(unsigned int fd) ++{ ++ KERNEL_CALL(int, sys_dup, fd); ++} ++ ++static inline long close(unsigned int fd) ++{ ++ KERNEL_CALL(int, sys_close, fd); ++} ++ ++static inline int execve(const char *filename, char *const argv[], ++ char *const envp[]) ++{ ++ KERNEL_CALL(int, um_execve, filename, argv, envp); ++} ++ ++static inline long waitpid(pid_t pid, unsigned int *status, int options) ++{ ++ KERNEL_CALL(pid_t, sys_wait4, pid, status, options, NULL) ++} ++ ++static inline pid_t wait(int *status) ++{ ++ KERNEL_CALL(pid_t, sys_wait4, -1, status, 0, NULL) ++} ++ ++static inline pid_t setsid(void) ++{ ++ KERNEL_CALL(pid_t, sys_setsid) ++} ++ ++static inline long lseek(unsigned int fd, off_t offset, unsigned int whence) ++{ ++ KERNEL_CALL(long, sys_lseek, fd, offset, whence) ++} ++ ++static inline int read(unsigned int fd, char * buf, int len) ++{ ++ KERNEL_CALL(int, sys_read, fd, buf, len) ++} ++ ++static inline int write(unsigned int fd, char * buf, int len) ++{ ++ KERNEL_CALL(int, sys_write, fd, buf, len) ++} ++ ++#endif ++ ++/* Save the value of __KERNEL_SYSCALLS__, undefine it, include the underlying ++ * arch's unistd.h for the system call numbers, and restore the old ++ * __KERNEL_SYSCALLS__. ++ */ ++ ++#ifdef __KERNEL_SYSCALLS__ ++#define __SAVE_KERNEL_SYSCALLS__ __KERNEL_SYSCALLS__ ++#endif ++ ++#undef __KERNEL_SYSCALLS__ ++#include "asm/arch/unistd.h" ++ ++#ifdef __KERNEL_SYSCALLS__ ++#define __KERNEL_SYSCALLS__ __SAVE_KERNEL_SYSCALLS__ ++#endif ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/include/asm-um/user.h um/include/asm-um/user.h +--- orig/include/asm-um/user.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/user.h 2003-12-17 02:18:31.000000000 -0500 +@@ -0,0 +1,6 @@ ++#ifndef __UM_USER_H ++#define __UM_USER_H ++ ++#include "asm/arch/user.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/vga.h um/include/asm-um/vga.h +--- orig/include/asm-um/vga.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/vga.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_VGA_H ++#define __UM_VGA_H ++ ++#include "asm/arch/vga.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/asm-um/xor.h um/include/asm-um/xor.h +--- orig/include/asm-um/xor.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/asm-um/xor.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,6 @@ ++#ifndef __UM_XOR_H ++#define __UM_XOR_H ++ ++#include "asm-generic/xor.h" ++ ++#endif +diff -Naur -X ../exclude-files orig/include/linux/blk.h um/include/linux/blk.h +--- orig/include/linux/blk.h 2002-09-15 12:13:19.000000000 -0400 ++++ um/include/linux/blk.h 2003-12-17 02:16:30.000000000 -0500 +@@ -320,6 +320,24 @@ + #define DEVICE_REQUEST do_ida_request + #define DEVICE_NR(device) (MINOR(device) >> 4) + ++#elif (MAJOR_NR == UBD_MAJOR) ++ ++#define DEVICE_NAME "User-mode block device" ++#define DEVICE_INTR do_ubd ++#define DEVICE_REQUEST do_ubd_request ++#define DEVICE_NR(device) (MINOR(device) >> UBD_SHIFT) ++#define DEVICE_ON(device) ++#define DEVICE_OFF(device) ++ ++#elif (MAJOR_NR == COW_MAJOR) ++ ++#define DEVICE_NAME "COW device" ++#define DEVICE_INTR do_cow ++#define DEVICE_REQUEST do_cow_request ++#define DEVICE_NR(device) (MINOR(device) >> COW_SHIFT) ++#define DEVICE_ON(device) ++#define DEVICE_OFF(device) ++ + #endif /* MAJOR_NR == whatever */ + + /* provide DEVICE_xxx defaults, if not explicitly defined +diff -Naur -X ../exclude-files orig/include/linux/fs.h um/include/linux/fs.h +--- orig/include/linux/fs.h 2003-12-16 22:16:36.000000000 -0500 ++++ um/include/linux/fs.h 2003-12-17 02:16:13.000000000 -0500 +@@ -320,6 +320,8 @@ + #include <linux/ncp_fs_i.h> + #include <linux/proc_fs_i.h> + #include <linux/usbdev_fs_i.h> ++#include <linux/hostfs_fs_i.h> ++#include <linux/hppfs_fs_i.h> + #include <linux/jffs2_fs_i.h> + #include <linux/cramfs_fs_sb.h> + +@@ -516,7 +518,9 @@ + struct proc_inode_info proc_i; + struct socket socket_i; + struct usbdev_inode_info usbdev_i; +- struct jffs2_inode_info jffs2_i; ++ struct hostfs_inode_info hostfs_i; ++ struct hppfs_inode_info hppfs_i; ++ struct jffs2_inode_info jffs2_i; + void *generic_ip; + } u; + }; +@@ -864,6 +868,8 @@ + unsigned int (*poll) (struct file *, struct poll_table_struct *); + int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); + int (*mmap) (struct file *, struct vm_area_struct *); ++ void (*munmap) (struct file *, struct vm_area_struct *, ++ unsigned long start, unsigned long len); + int (*open) (struct inode *, struct file *); + int (*flush) (struct file *); + int (*release) (struct inode *, struct file *); +diff -Naur -X ../exclude-files orig/include/linux/ghash.h um/include/linux/ghash.h +--- orig/include/linux/ghash.h 1997-07-07 11:24:28.000000000 -0400 ++++ um/include/linux/ghash.h 2003-10-21 03:26:07.000000000 -0400 +@@ -153,6 +153,26 @@ + return NULL;\ + } + ++/* LINKAGE - empty or "static", depending on whether you want the definitions to ++ * be public or not ++ * NAME - a string to stick in names to make this hash table type distinct from ++ * any others ++ * HASHSIZE - number of buckets ++ * TYPE - type of data contained in the buckets - must be a structure, one ++ * field is of type NAME_ptrs, another is the hash key ++ * PTRS - TYPE must contain a field of type NAME_ptrs, PTRS is the name of that ++ * field ++ * KEYTYPE - type of the key field within TYPE ++ * KEY - name of the key field within TYPE ++ * KEYCMP - pointer to function that compares KEYTYPEs to each other - the ++ * prototype is int KEYCMP(KEYTYPE, KEYTYPE), it returns zero for equal, ++ * non-zero for not equal ++ * HASHFN - the hash function - the prototype is int HASHFN(KEYTYPE), ++ * it returns a number in the range 0 ... HASHSIZE - 1 ++ * Call DEF_HASH_STRUCTS, define your hash table as a NAME_table, then call ++ * DEF_HASH. ++ */ ++ + #define DEF_HASH_STRUCTS(NAME,HASHSIZE,TYPE) \ + \ + struct NAME##_table {\ +@@ -165,7 +185,7 @@ + TYPE * prev_hash;\ + }; + +-#define DEF_HASH(LINKAGE,NAME,HASHSIZE,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,KEYEQ,HASHFN)\ ++#define DEF_HASH(LINKAGE,NAME,TYPE,PTRS,KEYTYPE,KEY,KEYCMP,HASHFN)\ + \ + LINKAGE void insert_##NAME##_hash(struct NAME##_table * tbl, TYPE * elem)\ + {\ +@@ -206,12 +226,10 @@ + \ + LINKAGE TYPE * find_##NAME##_hash(struct NAME##_table * tbl, KEYTYPE pos)\ + {\ +- int ix = hashfn(pos);\ ++ int ix = HASHFN(pos);\ + TYPE * ptr = tbl->hashtable[ix];\ + while(ptr && KEYCMP(ptr->KEY, pos))\ + ptr = ptr->PTRS.next_hash;\ +- if(ptr && !KEYEQ(ptr->KEY, pos))\ +- ptr = NULL;\ + return ptr;\ + } + +diff -Naur -X ../exclude-files orig/include/linux/hostfs_fs_i.h um/include/linux/hostfs_fs_i.h +--- orig/include/linux/hostfs_fs_i.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/linux/hostfs_fs_i.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,21 @@ ++#ifndef _HOSTFS_FS_I ++#define _HOSTFS_FS_I ++ ++struct hostfs_inode_info { ++ char *host_filename; ++ int fd; ++ int mode; ++}; ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/include/linux/hppfs_fs_i.h um/include/linux/hppfs_fs_i.h +--- orig/include/linux/hppfs_fs_i.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/linux/hppfs_fs_i.h 2003-10-21 03:26:07.000000000 -0400 +@@ -0,0 +1,19 @@ ++#ifndef _HPPFS_FS_I ++#define _HPPFS_FS_I ++ ++struct hppfs_inode_info { ++ struct dentry *proc_dentry; ++}; ++ ++#endif ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/include/linux/kernel.h um/include/linux/kernel.h +--- orig/include/linux/kernel.h 2003-02-27 13:04:27.000000000 -0500 ++++ um/include/linux/kernel.h 2003-12-17 02:16:13.000000000 -0500 +@@ -49,7 +49,7 @@ + # define ATTRIB_NORET __attribute__((noreturn)) + # define NORET_AND noreturn, + +-#ifdef __i386__ ++#if defined(__i386__) || defined(UM_FASTCALL) + #define FASTCALL(x) x __attribute__((regparm(3))) + #else + #define FASTCALL(x) x +diff -Naur -X ../exclude-files orig/include/linux/kernel_stat.h um/include/linux/kernel_stat.h +--- orig/include/linux/kernel_stat.h 2003-08-29 17:26:25.000000000 -0400 ++++ um/include/linux/kernel_stat.h 2003-12-17 02:16:13.000000000 -0500 +@@ -12,7 +12,7 @@ + * used by rstatd/perfmeter + */ + +-#define DK_MAX_MAJOR 16 ++#define DK_MAX_MAJOR 99 + #define DK_MAX_DISK 16 + + struct kernel_stat { +diff -Naur -X ../exclude-files orig/include/linux/mm.h um/include/linux/mm.h +--- orig/include/linux/mm.h 2003-12-16 22:16:36.000000000 -0500 ++++ um/include/linux/mm.h 2003-12-17 02:16:13.000000000 -0500 +@@ -438,6 +438,18 @@ + extern struct page * FASTCALL(__alloc_pages(unsigned int gfp_mask, unsigned int order, zonelist_t *zonelist)); + extern struct page * alloc_pages_node(int nid, unsigned int gfp_mask, unsigned int order); + ++#ifndef HAVE_ARCH_VALIDATE ++static inline struct page *arch_validate(struct page *page, ++ unsigned int gfp_mask, int order) ++{ ++ return(page); ++} ++#endif ++ ++#ifndef HAVE_ARCH_FREE_PAGE ++static inline void arch_free_page(struct page *page, int order) { } ++#endif ++ + static inline struct page * alloc_pages(unsigned int gfp_mask, unsigned int order) + { + /* +@@ -445,7 +457,7 @@ + */ + if (order >= MAX_ORDER) + return NULL; +- return _alloc_pages(gfp_mask, order); ++ return arch_validate(_alloc_pages(gfp_mask, order), gfp_mask, order); + } + + #define alloc_page(gfp_mask) alloc_pages(gfp_mask, 0) +@@ -505,6 +517,9 @@ + int get_user_pages(struct task_struct *tsk, struct mm_struct *mm, unsigned long start, + int len, int write, int force, struct page **pages, struct vm_area_struct **vmas); + ++extern long do_mprotect(struct mm_struct *mm, unsigned long start, ++ size_t len, unsigned long prot); ++ + /* + * On a two-level page table, this ends up being trivial. Thus the + * inlining and the symmetry break with pte_alloc() that does all +@@ -552,9 +567,10 @@ + + extern unsigned long get_unmapped_area(struct file *, unsigned long, unsigned long, unsigned long, unsigned long); + +-extern unsigned long do_mmap_pgoff(struct file *file, unsigned long addr, +- unsigned long len, unsigned long prot, +- unsigned long flag, unsigned long pgoff); ++extern unsigned long do_mmap_pgoff(struct mm_struct *mm, struct file *file, ++ unsigned long addr, unsigned long len, ++ unsigned long prot, unsigned long flag, ++ unsigned long pgoff); + + static inline unsigned long do_mmap(struct file *file, unsigned long addr, + unsigned long len, unsigned long prot, +@@ -564,7 +580,8 @@ + if ((offset + PAGE_ALIGN(len)) < offset) + goto out; + if (!(offset & ~PAGE_MASK)) +- ret = do_mmap_pgoff(file, addr, len, prot, flag, offset >> PAGE_SHIFT); ++ ret = do_mmap_pgoff(current->mm, file, addr, len, prot, flag, ++ offset >> PAGE_SHIFT); + out: + return ret; + } +diff -Naur -X ../exclude-files orig/include/linux/proc_mm.h um/include/linux/proc_mm.h +--- orig/include/linux/proc_mm.h 1969-12-31 19:00:00.000000000 -0500 ++++ um/include/linux/proc_mm.h 2003-12-17 02:17:30.000000000 -0500 +@@ -0,0 +1,48 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#ifndef __PROC_MM_H ++#define __PROC_MM_H ++ ++#include "linux/sched.h" ++ ++#define MM_MMAP 54 ++#define MM_MUNMAP 55 ++#define MM_MPROTECT 56 ++#define MM_COPY_SEGMENTS 57 ++ ++struct mm_mmap { ++ unsigned long addr; ++ unsigned long len; ++ unsigned long prot; ++ unsigned long flags; ++ unsigned long fd; ++ unsigned long offset; ++}; ++ ++struct mm_munmap { ++ unsigned long addr; ++ unsigned long len; ++}; ++ ++struct mm_mprotect { ++ unsigned long addr; ++ unsigned long len; ++ unsigned int prot; ++}; ++ ++struct proc_mm_op { ++ int op; ++ union { ++ struct mm_mmap mmap; ++ struct mm_munmap munmap; ++ struct mm_mprotect mprotect; ++ int copy_segments; ++ } u; ++}; ++ ++extern struct mm_struct *proc_mm_get_mm(int fd); ++ ++#endif +diff -Naur -X ../exclude-files orig/include/linux/shmem_fs.h um/include/linux/shmem_fs.h +--- orig/include/linux/shmem_fs.h 2003-09-02 15:44:03.000000000 -0400 ++++ um/include/linux/shmem_fs.h 2003-12-09 00:03:31.000000000 -0500 +@@ -22,6 +22,8 @@ + unsigned long next_index; + swp_entry_t i_direct[SHMEM_NR_DIRECT]; /* for the first blocks */ + void **i_indirect; /* indirect blocks */ ++ unsigned long map_direct[SHMEM_NR_DIRECT]; ++ void **map_indirect; + unsigned long swapped; /* data pages assigned to swap */ + unsigned long flags; + struct list_head list; +diff -Naur -X ../exclude-files orig/include/linux/tty.h um/include/linux/tty.h +--- orig/include/linux/tty.h 2003-08-29 17:26:26.000000000 -0400 ++++ um/include/linux/tty.h 2003-12-17 02:16:13.000000000 -0500 +@@ -309,6 +309,9 @@ + spinlock_t read_lock; + /* If the tty has a pending do_SAK, queue it here - akpm */ + struct tq_struct SAK_tq; ++#ifdef CONFIG_TTY_LOG ++ int log_fd; ++#endif + }; + + /* tty magic number */ +@@ -365,6 +368,7 @@ + extern int specialix_init(void); + extern int espserial_init(void); + extern int macserial_init(void); ++extern int stdio_init(void); + extern int a2232board_init(void); + + extern int tty_paranoia_check(struct tty_struct *tty, kdev_t device, +@@ -420,5 +424,7 @@ + extern int vt_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg); + ++extern void stdio_console_init(void); ++ + #endif /* __KERNEL__ */ + #endif +diff -Naur -X ../exclude-files orig/init/do_mounts.c um/init/do_mounts.c +--- orig/init/do_mounts.c 2003-12-16 22:16:36.000000000 -0500 ++++ um/init/do_mounts.c 2003-12-16 22:17:32.000000000 -0500 +@@ -154,6 +154,22 @@ + { "pf", 0x2f00 }, + { "apblock", APBLOCK_MAJOR << 8}, + { "ddv", DDV_MAJOR << 8}, ++ { "ubd0", UBD_MAJOR << 8 | 0 << 4}, ++ { "ubda", UBD_MAJOR << 8 | 0 << 4}, ++ { "ubd1", UBD_MAJOR << 8 | 1 << 4}, ++ { "ubdb", UBD_MAJOR << 8 | 1 << 4}, ++ { "ubd2", UBD_MAJOR << 8 | 2 << 4}, ++ { "ubdc", UBD_MAJOR << 8 | 2 << 4}, ++ { "ubd3", UBD_MAJOR << 8 | 3 << 4}, ++ { "ubdd", UBD_MAJOR << 8 | 3 << 4}, ++ { "ubd4", UBD_MAJOR << 8 | 4 << 4}, ++ { "ubde", UBD_MAJOR << 8 | 4 << 4}, ++ { "ubd5", UBD_MAJOR << 8 | 5 << 4}, ++ { "ubdf", UBD_MAJOR << 8 | 5 << 4}, ++ { "ubd6", UBD_MAJOR << 8 | 6 << 4}, ++ { "ubdg", UBD_MAJOR << 8 | 6 << 4}, ++ { "ubd7", UBD_MAJOR << 8 | 7 << 4}, ++ { "ubdh", UBD_MAJOR << 8 | 7 << 4}, + { "jsfd", JSFD_MAJOR << 8}, + #if defined(CONFIG_ARCH_S390) + { "dasda", (DASD_MAJOR << MINORBITS) }, +diff -Naur -X ../exclude-files orig/kernel/panic.c um/kernel/panic.c +--- orig/kernel/panic.c 2003-12-16 22:16:36.000000000 -0500 ++++ um/kernel/panic.c 2003-12-16 22:17:32.000000000 -0500 +@@ -74,7 +74,7 @@ + smp_send_stop(); + #endif + +- notifier_call_chain(&panic_notifier_list, 0, NULL); ++ notifier_call_chain(&panic_notifier_list, 0, buf); + + if (panic_timeout > 0) + { +diff -Naur -X ../exclude-files orig/MAINTAINERS um/MAINTAINERS +--- orig/MAINTAINERS 2003-12-16 22:16:23.000000000 -0500 ++++ um/MAINTAINERS 2003-12-16 22:17:22.000000000 -0500 +@@ -2055,6 +2055,14 @@ + L: linux-usb-devel@lists.sourceforge.net + W: http://usb.in.tum.de + S: Maintained ++ ++USER-MODE PORT ++P: Jeff Dike ++M: jdike@karaya.com ++L: user-mode-linux-devel@lists.sourceforge.net ++L: user-mode-linux-user@lists.sourceforge.net ++W: http://user-mode-linux.sourceforge.net ++S: Maintained + + USB "USBNET" DRIVER + P: David Brownell +diff -Naur -X ../exclude-files orig/Makefile um/Makefile +--- orig/Makefile 2003-12-16 22:16:23.000000000 -0500 ++++ um/Makefile 2003-12-16 22:17:22.000000000 -0500 +@@ -5,7 +5,15 @@ + + KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) + +-ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) ++# SUBARCH tells the usermode build what the underlying arch is. That is set ++# first, and if a usermode build is happening, the "ARCH=um" on the command ++# line overrides the setting of ARCH below. If a native build is happening, ++# then ARCH is assigned, getting whatever value it gets normally, and ++# SUBARCH is subsequently ignored. ++ ++SUBARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) ++ARCH := $(SUBARCH) ++ + KERNELPATH=kernel-$(shell echo $(KERNELRELEASE) | sed -e "s/-//g") + + CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ +diff -Naur -X ../exclude-files orig/mm/Makefile um/mm/Makefile +--- orig/mm/Makefile 2002-08-21 11:47:43.000000000 -0400 ++++ um/mm/Makefile 2003-10-21 03:26:08.000000000 -0400 +@@ -17,5 +17,6 @@ + shmem.o + + obj-$(CONFIG_HIGHMEM) += highmem.o ++obj-$(CONFIG_PROC_MM) += proc_mm.o + + include $(TOPDIR)/Rules.make +diff -Naur -X ../exclude-files orig/mm/mmap.c um/mm/mmap.c +--- orig/mm/mmap.c 2003-12-16 22:16:36.000000000 -0500 ++++ um/mm/mmap.c 2003-12-16 22:17:32.000000000 -0500 +@@ -390,10 +390,11 @@ + return 0; + } + +-unsigned long do_mmap_pgoff(struct file * file, unsigned long addr, unsigned long len, +- unsigned long prot, unsigned long flags, unsigned long pgoff) ++unsigned long do_mmap_pgoff(struct mm_struct *mm, struct file * file, ++ unsigned long addr, unsigned long len, ++ unsigned long prot, unsigned long flags, ++ unsigned long pgoff) + { +- struct mm_struct * mm = current->mm; + struct vm_area_struct * vma, * prev; + unsigned int vm_flags; + int correct_wcount = 0; +@@ -994,6 +995,11 @@ + remove_shared_vm_struct(mpnt); + mm->map_count--; + ++ if((mpnt->vm_file != NULL) && (mpnt->vm_file->f_op != NULL) && ++ (mpnt->vm_file->f_op->munmap != NULL)) ++ mpnt->vm_file->f_op->munmap(mpnt->vm_file, mpnt, st, ++ size); ++ + zap_page_range(mm, st, size); + + /* +diff -Naur -X ../exclude-files orig/mm/mprotect.c um/mm/mprotect.c +--- orig/mm/mprotect.c 2003-12-16 22:16:36.000000000 -0500 ++++ um/mm/mprotect.c 2003-12-16 22:17:32.000000000 -0500 +@@ -264,7 +264,8 @@ + return 0; + } + +-asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot) ++long do_mprotect(struct mm_struct *mm, unsigned long start, size_t len, ++ unsigned long prot) + { + unsigned long nstart, end, tmp; + struct vm_area_struct * vma, * next, * prev; +@@ -281,9 +282,9 @@ + if (end == start) + return 0; + +- down_write(¤t->mm->mmap_sem); ++ down_write(&mm->mmap_sem); + +- vma = find_vma_prev(current->mm, start, &prev); ++ vma = find_vma_prev(mm, start, &prev); + error = -ENOMEM; + if (!vma || vma->vm_start > start) + goto out; +@@ -332,6 +333,11 @@ + prev->vm_mm->map_count--; + } + out: +- up_write(¤t->mm->mmap_sem); ++ up_write(&mm->mmap_sem); + return error; + } ++ ++asmlinkage long sys_mprotect(unsigned long start, size_t len, unsigned long prot) ++{ ++ return(do_mprotect(current->mm, start, len, prot)); ++} +diff -Naur -X ../exclude-files orig/mm/page_alloc.c um/mm/page_alloc.c +--- orig/mm/page_alloc.c 2003-12-16 22:16:36.000000000 -0500 ++++ um/mm/page_alloc.c 2003-12-16 22:17:32.000000000 -0500 +@@ -89,6 +89,7 @@ + struct page *base; + zone_t *zone; + ++ arch_free_page(page, order); + /* + * Yes, think what happens when other parts of the kernel take + * a reference to a page in order to pin it for io. -ben +diff -Naur -X ../exclude-files orig/mm/proc_mm.c um/mm/proc_mm.c +--- orig/mm/proc_mm.c 1969-12-31 19:00:00.000000000 -0500 ++++ um/mm/proc_mm.c 2003-10-21 03:26:08.000000000 -0400 +@@ -0,0 +1,173 @@ ++/* ++ * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) ++ * Licensed under the GPL ++ */ ++ ++#include "linux/init.h" ++#include "linux/proc_fs.h" ++#include "linux/proc_mm.h" ++#include "linux/file.h" ++#include "asm/uaccess.h" ++#include "asm/mmu_context.h" ++ ++static struct file_operations proc_mm_fops; ++ ++struct mm_struct *proc_mm_get_mm(int fd) ++{ ++ struct mm_struct *ret = ERR_PTR(-EBADF); ++ struct file *file; ++ ++ file = fget(fd); ++ if (!file) ++ goto out; ++ ++ ret = ERR_PTR(-EINVAL); ++ if(file->f_op != &proc_mm_fops) ++ goto out_fput; ++ ++ ret = file->private_data; ++ out_fput: ++ fput(file); ++ out: ++ return(ret); ++} ++ ++extern long do_mmap2(struct mm_struct *mm, unsigned long addr, ++ unsigned long len, unsigned long prot, ++ unsigned long flags, unsigned long fd, ++ unsigned long pgoff); ++ ++static ssize_t write_proc_mm(struct file *file, const char *buffer, ++ size_t count, loff_t *ppos) ++{ ++ struct mm_struct *mm = file->private_data; ++ struct proc_mm_op req; ++ int n, ret; ++ ++ if(count > sizeof(req)) ++ return(-EINVAL); ++ ++ n = copy_from_user(&req, buffer, count); ++ if(n != 0) ++ return(-EFAULT); ++ ++ ret = count; ++ switch(req.op){ ++ case MM_MMAP: { ++ struct mm_mmap *map = &req.u.mmap; ++ ++ ret = do_mmap2(mm, map->addr, map->len, map->prot, ++ map->flags, map->fd, map->offset >> PAGE_SHIFT); ++ if((ret & ~PAGE_MASK) == 0) ++ ret = count; ++ ++ break; ++ } ++ case MM_MUNMAP: { ++ struct mm_munmap *unmap = &req.u.munmap; ++ ++ down_write(&mm->mmap_sem); ++ ret = do_munmap(mm, unmap->addr, unmap->len); ++ up_write(&mm->mmap_sem); ++ ++ if(ret == 0) ++ ret = count; ++ break; ++ } ++ case MM_MPROTECT: { ++ struct mm_mprotect *protect = &req.u.mprotect; ++ ++ ret = do_mprotect(mm, protect->addr, protect->len, ++ protect->prot); ++ if(ret == 0) ++ ret = count; ++ break; ++ } ++ ++ case MM_COPY_SEGMENTS: { ++ struct mm_struct *from = proc_mm_get_mm(req.u.copy_segments); ++ ++ if(IS_ERR(from)){ ++ ret = PTR_ERR(from); ++ break; ++ } ++ ++ mm_copy_segments(from, mm); ++ break; ++ } ++ default: ++ ret = -EINVAL; ++ break; ++ } ++ ++ return(ret); ++} ++ ++static int open_proc_mm(struct inode *inode, struct file *file) ++{ ++ struct mm_struct *mm = mm_alloc(); ++ int ret; ++ ++ ret = -ENOMEM; ++ if(mm == NULL) ++ goto out_mem; ++ ++ ret = init_new_context(current, mm); ++ if(ret) ++ goto out_free; ++ ++ spin_lock(&mmlist_lock); ++ list_add(&mm->mmlist, ¤t->mm->mmlist); ++ mmlist_nr++; ++ spin_unlock(&mmlist_lock); ++ ++ file->private_data = mm; ++ ++ return(0); ++ ++ out_free: ++ mmput(mm); ++ out_mem: ++ return(ret); ++} ++ ++static int release_proc_mm(struct inode *inode, struct file *file) ++{ ++ struct mm_struct *mm = file->private_data; ++ ++ mmput(mm); ++ return(0); ++} ++ ++static struct file_operations proc_mm_fops = { ++ .open = open_proc_mm, ++ .release = release_proc_mm, ++ .write = write_proc_mm, ++}; ++ ++static int make_proc_mm(void) ++{ ++ struct proc_dir_entry *ent; ++ ++ ent = create_proc_entry("mm", 0222, &proc_root); ++ if(ent == NULL){ ++ printk("make_proc_mm : Failed to register /proc/mm\n"); ++ return(0); ++ } ++ ent->proc_fops = &proc_mm_fops; ++ ++ return(0); ++} ++ ++__initcall(make_proc_mm); ++ ++/* ++ * Overrides for Emacs so that we follow Linus's tabbing style. ++ * Emacs will notice this stuff at the end of the file and automatically ++ * adjust the settings for this buffer only. This must remain at the end ++ * of the file. ++ * --------------------------------------------------------------------------- ++ * Local variables: ++ * c-file-style: "linux" ++ * End: ++ */ +diff -Naur -X ../exclude-files orig/mm/shmem.c um/mm/shmem.c +--- orig/mm/shmem.c 2003-12-16 22:16:36.000000000 -0500 ++++ um/mm/shmem.c 2003-12-16 22:17:32.000000000 -0500 +@@ -128,16 +128,17 @@ + * +-> 48-51 + * +-> 52-55 + */ +-static swp_entry_t *shmem_swp_entry(struct shmem_inode_info *info, unsigned long index, unsigned long *page) ++static void *shmem_block(unsigned long index, unsigned long *page, ++ unsigned long *direct, void ***indirect) + { + unsigned long offset; + void **dir; + + if (index < SHMEM_NR_DIRECT) +- return info->i_direct+index; +- if (!info->i_indirect) { ++ return direct+index; ++ if (!*indirect) { + if (page) { +- info->i_indirect = (void **) *page; ++ *indirect = (void **) *page; + *page = 0; + } + return NULL; /* need another page */ +@@ -146,7 +147,7 @@ + index -= SHMEM_NR_DIRECT; + offset = index % ENTRIES_PER_PAGE; + index /= ENTRIES_PER_PAGE; +- dir = info->i_indirect; ++ dir = *indirect; + + if (index >= ENTRIES_PER_PAGE/2) { + index -= ENTRIES_PER_PAGE/2; +@@ -169,7 +170,21 @@ + *dir = (void *) *page; + *page = 0; + } +- return (swp_entry_t *) *dir + offset; ++ return (unsigned long **) *dir + offset; ++} ++ ++static swp_entry_t *shmem_swp_entry(struct shmem_inode_info *info, unsigned long index, unsigned long *page) ++{ ++ return((swp_entry_t *) shmem_block(index, page, ++ (unsigned long *) info->i_direct, ++ &info->i_indirect)); ++} ++ ++static unsigned long *shmem_map_count(struct shmem_inode_info *info, ++ unsigned long index, unsigned long *page) ++{ ++ return((unsigned long *) shmem_block(index, page, info->map_direct, ++ &info->map_indirect)); + } + + /* +@@ -838,6 +853,7 @@ + ops = &shmem_vm_ops; + if (!S_ISREG(inode->i_mode)) + return -EACCES; ++ + UPDATE_ATIME(inode); + vma->vm_ops = ops; + return 0; +@@ -1723,4 +1739,125 @@ + return 0; + } + ++static int adjust_map_counts(struct shmem_inode_info *info, ++ unsigned long offset, unsigned long len, ++ int adjust) ++{ ++ unsigned long idx, i, *count, page = 0; ++ ++ spin_lock(&info->lock); ++ offset >>= PAGE_SHIFT; ++ len >>= PAGE_SHIFT; ++ for(i = 0; i < len; i++){ ++ idx = (i + offset) >> (PAGE_CACHE_SHIFT - PAGE_SHIFT); ++ ++ while((count = shmem_map_count(info, idx, &page)) == NULL){ ++ spin_unlock(&info->lock); ++ page = get_zeroed_page(GFP_KERNEL); ++ if(page == 0) ++ return(-ENOMEM); ++ spin_lock(&info->lock); ++ } ++ ++ if(page != 0) ++ free_page(page); ++ ++ *count += adjust; ++ } ++ spin_unlock(&info->lock); ++ return(0); ++} ++ + EXPORT_SYMBOL(shmem_file_setup); ++ ++struct file_operations anon_file_operations; ++ ++static int anon_mmap(struct file *file, struct vm_area_struct *vma) ++{ ++ struct file *new; ++ struct inode *inode; ++ loff_t size = vma->vm_end - vma->vm_start; ++ int err; ++ ++ if(file->private_data == NULL){ ++ new = shmem_file_setup("dev/anon", size); ++ if(IS_ERR(new)) ++ return(PTR_ERR(new)); ++ ++ new->f_op = &anon_file_operations; ++ file->private_data = new; ++ } ++ ++ if (vma->vm_file) ++ fput(vma->vm_file); ++ vma->vm_file = file->private_data; ++ get_file(vma->vm_file); ++ ++ inode = vma->vm_file->f_dentry->d_inode; ++ err = adjust_map_counts(SHMEM_I(inode), vma->vm_pgoff, size, 1); ++ if(err) ++ return(err); ++ ++ vma->vm_ops = &shmem_vm_ops; ++ return 0; ++} ++ ++static void anon_munmap(struct file *file, struct vm_area_struct *vma, ++ unsigned long start, unsigned long len) ++{ ++ struct inode *inode = file->f_dentry->d_inode; ++ struct shmem_inode_info *info = SHMEM_I(inode); ++ pgd_t *pgd; ++ pmd_t *pmd; ++ pte_t *pte; ++ struct page *page; ++ unsigned long addr, idx, *count; ++ ++ for(addr = start; addr < start + len; addr += PAGE_SIZE){ ++ idx = (addr - vma->vm_start + vma->vm_pgoff); ++ idx >>= PAGE_CACHE_SHIFT; ++ ++ count = shmem_map_count(info, idx, NULL); ++ BUG_ON(count == NULL); ++ ++ (*count)--; ++ if(*count > 0) ++ continue; ++ ++ pgd = pgd_offset(vma->vm_mm, addr); ++ if(pgd_none(*pgd)) ++ continue; ++ ++ pmd = pmd_offset(pgd, addr); ++ if(pmd_none(*pmd)) ++ continue; ++ ++ pte = pte_offset(pmd, addr); ++ if(!pte_present(*pte)) /* XXX need to handle swapped pages */ ++ continue; ++ ++ *pte = pte_mkclean(*pte); ++ ++ page = pte_page(*pte); ++ LockPage(page); ++ lru_cache_del(page); ++ ClearPageDirty(page); ++ remove_inode_page(page); ++ UnlockPage(page); ++ ++ page_cache_release(page); ++ } ++} ++ ++int anon_release(struct inode *inode, struct file *file) ++{ ++ if(file->private_data != NULL) ++ fput(file->private_data); ++ return(0); ++} ++ ++struct file_operations anon_file_operations = { ++ .mmap = anon_mmap, ++ .munmap = anon_munmap, ++ .release = anon_release, ++}; diff --git a/lustre/kernel_patches/series/vanilla-2.4.24 b/lustre/kernel_patches/series/vanilla-2.4.24 new file mode 100644 index 0000000..8a25fd0 --- /dev/null +++ b/lustre/kernel_patches/series/vanilla-2.4.24 @@ -0,0 +1,35 @@ +uml-patch-2.4.23-1.patch +uml-2.4.20-do_mmap_pgoff-fix.patch +uml-export-end_iomem.patch +configurable-x86-stack-2.4.20.patch +dev_read_only_2.4.20-rh.patch +exports_2.4.20-rh-hp.patch +lustre_version.patch +vfs_intent-2.4.20-vanilla.patch +invalidate_show.patch +export-truncate.patch +iod-stock-exports-2.4.22.patch +ext3-htree-2.4.22-rh.patch +linux-2.4.24-xattr-0.8.54.patch +ext3-orphan_lock-2.4.22-rh.patch +ext3-noread-2.4.20.patch +ext3-delete_thread-suse.patch +extN-wantedi.patch +ext3-san-2.4.20.patch +ext3-map_inode_page.patch +ext3-error-export.patch +iopen-2.4.20.patch +tcp-zero-copy-2.4.22-rh.patch +jbd-dont-account-blocks-twice.patch +jbd-commit-tricks.patch +ext3-no-write-super-chaos.patch +add_page_private.patch +nfs_export_kernel-2.4.22.patch +ext3-raw-lookup.patch +ext3-ea-in-inode-2.4.22-rh.patch +listman-2.4.20.patch +ext3-trusted_ea-2.4.20.patch +kernel_text_address-2.4.22-vanilla.patch +gfp_memalloc-2.4.24.patch +ext3-xattr-ptr-arith-fix.patch +3.5G-address-space-2.4.22-vanilla.patch -- 1.8.3.1