summaryrefslogtreecommitdiffstats
path: root/arch/um
diff options
context:
space:
mode:
Diffstat (limited to 'arch/um')
-rw-r--r--arch/um/Kconfig16
-rw-r--r--arch/um/Kconfig_i38612
-rw-r--r--arch/um/Kconfig_net2
-rw-r--r--arch/um/Kconfig_x86_6412
-rw-r--r--arch/um/Makefile35
-rw-r--r--arch/um/Makefile-i38632
-rw-r--r--arch/um/Makefile-x86_648
-rw-r--r--arch/um/defconfig58
-rw-r--r--arch/um/drivers/Makefile19
-rw-r--r--arch/um/drivers/cow.h4
-rw-r--r--arch/um/drivers/daemon_user.c6
-rw-r--r--arch/um/drivers/hostaudio_kern.c4
-rw-r--r--arch/um/drivers/line.c59
-rw-r--r--arch/um/drivers/mconsole_kern.c38
-rw-r--r--arch/um/drivers/net_kern.c32
-rw-r--r--arch/um/drivers/port_kern.c1
-rw-r--r--arch/um/drivers/ssl.c9
-rw-r--r--arch/um/drivers/stdio_console.c7
-rw-r--r--arch/um/drivers/ubd_kern.c37
-rw-r--r--arch/um/drivers/xterm_kern.c1
-rw-r--r--arch/um/include/line.h3
-rw-r--r--arch/um/include/mconsole_kern.h3
-rw-r--r--arch/um/include/mem.h1
-rw-r--r--arch/um/include/registers.h1
-rw-r--r--arch/um/include/sysdep-i386/ptrace_user.h13
-rw-r--r--arch/um/include/sysdep-i386/stub.h65
-rw-r--r--arch/um/include/sysdep-x86_64/ptrace_user.h14
-rw-r--r--arch/um/include/sysdep-x86_64/stub.h58
-rw-r--r--arch/um/include/time_user.h3
-rw-r--r--arch/um/include/tlb.h30
-rw-r--r--arch/um/kernel/dyn.lds.S6
-rw-r--r--arch/um/kernel/exitcode.c2
-rw-r--r--arch/um/kernel/helper.c14
-rw-r--r--arch/um/kernel/irq.c11
-rw-r--r--arch/um/kernel/irq_user.c2
-rw-r--r--arch/um/kernel/main.c1
-rw-r--r--arch/um/kernel/mem.c1
-rw-r--r--arch/um/kernel/physmem.c8
-rw-r--r--arch/um/kernel/process.c97
-rw-r--r--arch/um/kernel/process_kern.c16
-rw-r--r--arch/um/kernel/reboot.c15
-rw-r--r--arch/um/kernel/skas/Makefile9
-rw-r--r--arch/um/kernel/skas/clone.c44
-rw-r--r--arch/um/kernel/skas/exec_kern.c2
-rw-r--r--arch/um/kernel/skas/include/mm_id.h17
-rw-r--r--arch/um/kernel/skas/include/mmu-skas.h7
-rw-r--r--arch/um/kernel/skas/include/mode-skas.h1
-rw-r--r--arch/um/kernel/skas/include/skas.h16
-rw-r--r--arch/um/kernel/skas/include/stub-data.h18
-rw-r--r--arch/um/kernel/skas/mem.c6
-rw-r--r--arch/um/kernel/skas/mem_user.c225
-rw-r--r--arch/um/kernel/skas/mmu.c141
-rw-r--r--arch/um/kernel/skas/process.c216
-rw-r--r--arch/um/kernel/skas/process_kern.c46
-rw-r--r--arch/um/kernel/skas/syscall_user.c4
-rw-r--r--arch/um/kernel/skas/time.c30
-rw-r--r--arch/um/kernel/skas/tlb.c29
-rw-r--r--arch/um/kernel/skas/trap_user.c1
-rw-r--r--arch/um/kernel/syscall_kern.c19
-rw-r--r--arch/um/kernel/time.c36
-rw-r--r--arch/um/kernel/time_kern.c7
-rw-r--r--arch/um/kernel/tlb.c132
-rw-r--r--arch/um/kernel/tt/Makefile19
-rw-r--r--arch/um/kernel/tt/gdb.c4
-rw-r--r--arch/um/kernel/tt/gdb_kern.c2
-rw-r--r--arch/um/kernel/tt/include/debug.h17
-rw-r--r--arch/um/kernel/tt/include/mode-tt.h1
-rw-r--r--arch/um/kernel/tt/process_kern.c17
-rw-r--r--arch/um/kernel/tt/time.c28
-rw-r--r--arch/um/kernel/tt/tlb.c4
-rw-r--r--arch/um/kernel/tt/unmap.c31
-rw-r--r--arch/um/kernel/um_arch.c19
-rw-r--r--arch/um/kernel/uml.lds.S22
-rw-r--r--arch/um/os-Linux/elf_aux.c5
-rw-r--r--arch/um/os-Linux/sys-i386/registers.c5
-rw-r--r--arch/um/os-Linux/sys-x86_64/registers.c5
-rw-r--r--arch/um/os-Linux/user_syms.c3
-rw-r--r--arch/um/scripts/Makefile.rules11
-rw-r--r--arch/um/scripts/Makefile.unmap22
-rw-r--r--arch/um/sys-i386/Makefile14
-rw-r--r--arch/um/sys-i386/ldt.c114
-rw-r--r--arch/um/sys-i386/signal.c2
-rw-r--r--arch/um/sys-i386/stub.S8
-rw-r--r--arch/um/sys-i386/stub_segv.c30
-rw-r--r--arch/um/sys-i386/syscalls.c23
-rw-r--r--arch/um/sys-i386/unmap.c25
-rw-r--r--arch/um/sys-x86_64/Makefile14
-rw-r--r--arch/um/sys-x86_64/signal.c2
-rw-r--r--arch/um/sys-x86_64/stub.S15
-rw-r--r--arch/um/sys-x86_64/stub_segv.c31
-rw-r--r--arch/um/sys-x86_64/syscalls.c23
-rw-r--r--arch/um/sys-x86_64/unmap.c25
92 files changed, 1581 insertions, 722 deletions
diff --git a/arch/um/Kconfig b/arch/um/Kconfig
index c5292181a66..f945444df49 100644
--- a/arch/um/Kconfig
+++ b/arch/um/Kconfig
@@ -35,6 +35,11 @@ config GENERIC_CALIBRATE_DELAY
bool
default y
+# Used in kernel/irq/manage.c and include/linux/irq.h
+config IRQ_RELEASE_METHOD
+ bool
+ default y
+
menu "UML-specific options"
config MODE_TT
@@ -69,6 +74,7 @@ config MODE_SKAS
option will shrink the UML binary slightly.
source "arch/um/Kconfig_arch"
+source "mm/Kconfig"
config LD_SCRIPT_STATIC
bool
@@ -122,7 +128,6 @@ config HOSTFS
config HPPFS
tristate "HoneyPot ProcFS (EXPERIMENTAL)"
- depends on BROKEN
help
hppfs (HoneyPot ProcFS) is a filesystem which allows UML /proc
entries to be overridden, removed, or fabricated from the host.
@@ -135,8 +140,9 @@ config HPPFS
You only need this if you are setting up a UML honeypot. Otherwise,
it is safe to say 'N' here.
- If you are actively using it, please ask for it to be fixed. In this
- moment, it does not work on 2.6 (it works somehow on 2.4).
+ If you are actively using it, please report any problems, since it's
+ getting fixed. In this moment, it is experimental on 2.6 (it works on
+ 2.4).
config MCONSOLE
bool "Management console"
@@ -269,6 +275,8 @@ endmenu
source "init/Kconfig"
+source "net/Kconfig"
+
source "drivers/base/Kconfig"
source "arch/um/Kconfig_char"
@@ -281,7 +289,7 @@ config NETDEVICES
source "arch/um/Kconfig_net"
-source "net/Kconfig"
+source "drivers/net/Kconfig"
source "fs/Kconfig"
diff --git a/arch/um/Kconfig_i386 b/arch/um/Kconfig_i386
index e41f3748d30..27c18a8d9d1 100644
--- a/arch/um/Kconfig_i386
+++ b/arch/um/Kconfig_i386
@@ -19,6 +19,18 @@ config 3_LEVEL_PGTABLES
memory. All the memory that can't be mapped directly will be treated
as high memory.
+config STUB_CODE
+ hex
+ default 0xbfffe000
+
+config STUB_DATA
+ hex
+ default 0xbffff000
+
+config STUB_START
+ hex
+ default STUB_CODE
+
config ARCH_HAS_SC_SIGNALS
bool
default y
diff --git a/arch/um/Kconfig_net b/arch/um/Kconfig_net
index 1c2f9a70d91..fa2ab2dd78b 100644
--- a/arch/um/Kconfig_net
+++ b/arch/um/Kconfig_net
@@ -135,7 +135,7 @@ config UML_NET_MCAST
config UML_NET_PCAP
bool "pcap transport"
- depends on UML_NET && BROKEN
+ depends on UML_NET && EXPERIMENTAL
help
The pcap transport makes a pcap packet stream on the host look
like an ethernet device inside UML. This is useful for making
diff --git a/arch/um/Kconfig_x86_64 b/arch/um/Kconfig_x86_64
index f162f50f0b1..735a047c890 100644
--- a/arch/um/Kconfig_x86_64
+++ b/arch/um/Kconfig_x86_64
@@ -14,6 +14,18 @@ config 3_LEVEL_PGTABLES
bool
default y
+config STUB_CODE
+ hex
+ default 0x7fbfffe000
+
+config STUB_DATA
+ hex
+ default 0x7fbffff000
+
+config STUB_START
+ hex
+ default STUB_CODE
+
config ARCH_HAS_SC_SIGNALS
bool
default n
diff --git a/arch/um/Makefile b/arch/um/Makefile
index f2a0c40a920..f5a83a72aa7 100644
--- a/arch/um/Makefile
+++ b/arch/um/Makefile
@@ -51,25 +51,26 @@ MRPROPER_DIRS += $(ARCH_DIR)/include2
endif
SYS_DIR := $(ARCH_DIR)/include/sysdep-$(SUBARCH)
-include $(srctree)/$(ARCH_DIR)/Makefile-$(SUBARCH)
+# -Dvmap=kernel_vmap affects everything, and prevents anything from
+# referencing the libpcap.o symbol so named.
+
+CFLAGS += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
+ $(ARCH_INCLUDE) $(MODE_INCLUDE) -Dvmap=kernel_vmap
-core-y += $(SUBARCH_CORE)
-libs-y += $(SUBARCH_LIBS)
+USER_CFLAGS := $(patsubst -I%,,$(CFLAGS))
+USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \
+ $(MODE_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 += $(CFLAGS-y) -D__arch_um__ -DSUBARCH=\"$(SUBARCH)\" \
- $(ARCH_INCLUDE) $(MODE_INCLUDE)
-
-USER_CFLAGS := $(patsubst -I%,,$(CFLAGS))
-USER_CFLAGS := $(patsubst -D__KERNEL__,,$(USER_CFLAGS)) $(ARCH_INCLUDE) \
- $(MODE_INCLUDE) $(ARCH_USER_CFLAGS)
CFLAGS += -Derrno=kernel_errno -Dsigprocmask=kernel_sigprocmask
CFLAGS += $(call cc-option,-fno-unit-at-a-time,)
+include $(srctree)/$(ARCH_DIR)/Makefile-$(SUBARCH)
+
#This will adjust *FLAGS accordingly to the platform.
include $(srctree)/$(ARCH_DIR)/Makefile-os-$(OS)
@@ -116,18 +117,19 @@ CONFIG_KERNEL_STACK_ORDER ?= 2
STACK_SIZE := $(shell echo $$[ 4096 * (1 << $(CONFIG_KERNEL_STACK_ORDER)) ] )
ifndef START
- START = $$(($(TOP_ADDR) - $(SIZE)))
+ START = $(shell echo $$[ $(TOP_ADDR) - $(SIZE) ] )
endif
-CPPFLAGS_vmlinux.lds = $(shell echo -U$(SUBARCH) \
+CPPFLAGS_vmlinux.lds = -U$(SUBARCH) \
-DSTART=$(START) -DELF_ARCH=$(ELF_ARCH) \
- -DELF_FORMAT=\"$(ELF_FORMAT)\" $(CPP_MODE-y) \
- -DKERNEL_STACK_SIZE=$(STACK_SIZE))
+ -DELF_FORMAT="$(ELF_FORMAT)" $(CPP_MODE-y) \
+ -DKERNEL_STACK_SIZE=$(STACK_SIZE) \
+ -DUNMAP_PATH=arch/um/sys-$(SUBARCH)/unmap_fin.o
#The wrappers will select whether using "malloc" or the kernel allocator.
LINK_WRAPS = -Wl,--wrap,malloc -Wl,--wrap,free -Wl,--wrap,calloc
-CFLAGS_vmlinux = $(LINK-y) $(LINK_WRAPS)
+CFLAGS_vmlinux := $(LINK-y) $(LINK_WRAPS)
define cmd_vmlinux__
$(CC) $(CFLAGS_vmlinux) -o $@ \
-Wl,-T,$(vmlinux-lds) $(vmlinux-init) \
@@ -140,7 +142,8 @@ endef
#When cleaning we don't include .config, so we don't include
#TT or skas makefiles and don't clean skas_ptregs.h.
CLEAN_FILES += linux x.i gmon.out $(ARCH_DIR)/include/uml-config.h \
- $(GEN_HEADERS) $(ARCH_DIR)/include/skas_ptregs.h
+ $(GEN_HEADERS) $(ARCH_DIR)/include/skas_ptregs.h \
+ $(ARCH_DIR)/include/user_constants.h
MRPROPER_FILES += $(SYMLINK_HEADERS) $(ARCH_SYMLINKS) \
$(addprefix $(ARCH_DIR)/kernel/,$(KERN_SYMLINKS)) $(ARCH_DIR)/os \
@@ -242,7 +245,7 @@ $(ARCH_DIR)/util: scripts_basic $(SYS_DIR)/sc.h $(ARCH_DIR)/kernel-offsets.h FOR
$(ARCH_DIR)/kernel/skas/util: scripts_basic $(ARCH_DIR)/user-offsets.h FORCE
$(Q)$(MAKE) $(build)=$@
-$(ARCH_DIR)/os-$(OS)/util: scripts_basic FORCE
+$(ARCH_DIR)/os-$(OS)/util: scripts_basic $(ARCH_DIR)/user-offsets.h FORCE
$(Q)$(MAKE) $(build)=$@
export SUBARCH USER_CFLAGS OS
diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386
index 29e182d5a83..a777e57dbf8 100644
--- a/arch/um/Makefile-i386
+++ b/arch/um/Makefile-i386
@@ -1,4 +1,4 @@
-SUBARCH_CORE := arch/um/sys-i386/ arch/i386/crypto/
+core-y += arch/um/sys-i386/ arch/i386/crypto/
TOP_ADDR := $(CONFIG_TOP_ADDR)
@@ -8,21 +8,33 @@ ifeq ($(CONFIG_MODE_SKAS),y)
endif
endif
-CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH)
-ARCH_USER_CFLAGS :=
+LDFLAGS += -m elf_i386
+ELF_ARCH := $(SUBARCH)
+ELF_FORMAT := elf32-$(SUBARCH)
+OBJCOPYFLAGS := -O binary -R .note -R .comment -S
+
+ifeq ("$(origin SUBARCH)", "command line")
+ifneq ("$(shell uname -m | sed -e s/i.86/i386/)", "$(SUBARCH)")
+CFLAGS += $(call cc-option,-m32)
+USER_CFLAGS += $(call cc-option,-m32)
+HOSTCFLAGS += $(call cc-option,-m32)
+HOSTLDFLAGS += $(call cc-option,-m32)
+AFLAGS += $(call cc-option,-m32)
+LINK-y += $(call cc-option,-m32)
+UML_OBJCOPYFLAGS += -F $(ELF_FORMAT)
+
+export LDFLAGS HOSTCFLAGS HOSTLDFLAGS UML_OBJCOPYFLAGS
+endif
+endif
+
+CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH) $(STUB_CFLAGS)
ifneq ($(CONFIG_GPROF),y)
ARCH_CFLAGS += -DUM_FASTCALL
endif
-ELF_ARCH := $(SUBARCH)
-ELF_FORMAT := elf32-$(SUBARCH)
-
-OBJCOPYFLAGS := -O binary -R .note -R .comment -S
-
SYS_UTIL_DIR := $(ARCH_DIR)/sys-i386/util
-
-SYS_HEADERS := $(SYS_DIR)/sc.h $(SYS_DIR)/thread.h
+SYS_HEADERS := $(SYS_DIR)/sc.h $(SYS_DIR)/thread.h
prepare: $(SYS_HEADERS)
diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64
index 32144562c27..aa2f7174ebc 100644
--- a/arch/um/Makefile-x86_64
+++ b/arch/um/Makefile-x86_64
@@ -1,11 +1,13 @@
# Copyright 2003 - 2004 Pathscale, Inc
# Released under the GPL
-SUBARCH_LIBS := arch/um/sys-x86_64/
+libs-y += arch/um/sys-x86_64/
START := 0x60000000
-CFLAGS += -U__$(SUBARCH)__ -fno-builtin
-ARCH_USER_CFLAGS := -D__x86_64__
+#We #undef __x86_64__ for kernelspace, not for userspace where
+#it's needed for headers to work!
+CFLAGS += -U__$(SUBARCH)__ -fno-builtin $(STUB_CFLAGS)
+USER_CFLAGS += -fno-builtin
ELF_ARCH := i386:x86-64
ELF_FORMAT := elf64-x86-64
diff --git a/arch/um/defconfig b/arch/um/defconfig
index 4067c3aa5b6..80d30d19d75 100644
--- a/arch/um/defconfig
+++ b/arch/um/defconfig
@@ -1,7 +1,7 @@
#
# Automatically generated make config: don't edit
-# Linux kernel version: 2.6.12-rc3-skas3-v9-pre2
-# Sun Apr 24 19:46:10 2005
+# Linux kernel version: 2.6.12-rc6-mm1
+# Tue Jun 14 18:22:21 2005
#
CONFIG_GENERIC_HARDIRQS=y
CONFIG_UML=y
@@ -13,23 +13,32 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y
#
# UML-specific options
#
-CONFIG_MODE_TT=y
+# CONFIG_MODE_TT is not set
+# CONFIG_STATIC_LINK is not set
CONFIG_MODE_SKAS=y
CONFIG_UML_X86=y
# CONFIG_64BIT is not set
CONFIG_TOP_ADDR=0xc0000000
# CONFIG_3_LEVEL_PGTABLES is not set
+CONFIG_STUB_CODE=0xbfffe000
+CONFIG_STUB_DATA=0xbffff000
+CONFIG_STUB_START=0xbfffe000
CONFIG_ARCH_HAS_SC_SIGNALS=y
CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA=y
-CONFIG_LD_SCRIPT_STATIC=y
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_LD_SCRIPT_DYN=y
CONFIG_NET=y
CONFIG_BINFMT_ELF=y
CONFIG_BINFMT_MISC=m
-CONFIG_HOSTFS=y
+# CONFIG_HOSTFS is not set
CONFIG_MCONSOLE=y
# CONFIG_MAGIC_SYSRQ is not set
# CONFIG_HOST_2G_2G is not set
-# CONFIG_SMP is not set
CONFIG_NEST_LEVEL=0
CONFIG_KERNEL_HALF_GIGS=1
# CONFIG_HIGHMEM is not set
@@ -63,6 +72,8 @@ CONFIG_IKCONFIG_PROC=y
CONFIG_KALLSYMS=y
# CONFIG_KALLSYMS_ALL is not set
CONFIG_KALLSYMS_EXTRA_PASS=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
CONFIG_BASE_FULL=y
CONFIG_FUTEX=y
CONFIG_EPOLL=y
@@ -81,6 +92,7 @@ CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
# CONFIG_MODULE_FORCE_UNLOAD is not set
CONFIG_OBSOLETE_MODPARM=y
+# CONFIG_MODVERSIONS is not set
# CONFIG_MODULE_SRCVERSION_ALL is not set
CONFIG_KMOD=y
@@ -115,6 +127,7 @@ CONFIG_UML_SOUND=m
CONFIG_SOUND=m
CONFIG_HOSTAUDIO=m
CONFIG_UML_RANDOM=y
+# CONFIG_MMAPPER is not set
#
# Block devices
@@ -176,6 +189,17 @@ CONFIG_INET=y
# CONFIG_INET_TUNNEL is not set
CONFIG_IP_TCPDIAG=y
# CONFIG_IP_TCPDIAG_IPV6 is not set
+
+#
+# TCP congestion control
+#
+CONFIG_TCP_CONG_BIC=y
+CONFIG_TCP_CONG_WESTWOOD=y
+CONFIG_TCP_CONG_HTCP=y
+# CONFIG_TCP_CONG_HSTCP is not set
+# CONFIG_TCP_CONG_HYBLA is not set
+# CONFIG_TCP_CONG_VEGAS is not set
+# CONFIG_TCP_CONG_SCALABLE is not set
# CONFIG_IPV6 is not set
# CONFIG_NETFILTER is not set
@@ -206,11 +230,15 @@ CONFIG_IP_TCPDIAG=y
# Network testing
#
# CONFIG_NET_PKTGEN is not set
+# CONFIG_KGDBOE is not set
# CONFIG_NETPOLL is not set
+# CONFIG_NETPOLL_RX is not set
+# CONFIG_NETPOLL_TRAP is not set
# CONFIG_NET_POLL_CONTROLLER is not set
# CONFIG_HAMRADIO is not set
# CONFIG_IRDA is not set
# CONFIG_BT is not set
+# CONFIG_IEEE80211 is not set
CONFIG_DUMMY=m
# CONFIG_BONDING is not set
# CONFIG_EQUALIZER is not set
@@ -227,6 +255,7 @@ CONFIG_PPP=m
# CONFIG_PPP_SYNC_TTY is not set
# CONFIG_PPP_DEFLATE is not set
# CONFIG_PPP_BSDCOMP is not set
+# CONFIG_PPP_MPPE is not set
# CONFIG_PPPOE is not set
CONFIG_SLIP=m
# CONFIG_SLIP_COMPRESSED is not set
@@ -240,10 +269,12 @@ CONFIG_SLIP=m
#
CONFIG_EXT2_FS=y
# CONFIG_EXT2_FS_XATTR is not set
+# CONFIG_EXT2_FS_XIP is not set
CONFIG_EXT3_FS=y
# CONFIG_EXT3_FS_XATTR is not set
CONFIG_JBD=y
# CONFIG_JBD_DEBUG is not set
+# CONFIG_REISER4_FS is not set
CONFIG_REISERFS_FS=y
# CONFIG_REISERFS_CHECK is not set
# CONFIG_REISERFS_PROC_INFO is not set
@@ -256,6 +287,7 @@ CONFIG_REISERFS_FS=y
# CONFIG_XFS_FS is not set
# CONFIG_MINIX_FS is not set
# CONFIG_ROMFS_FS is not set
+CONFIG_INOTIFY=y
CONFIG_QUOTA=y
# CONFIG_QFMT_V1 is not set
# CONFIG_QFMT_V2 is not set
@@ -265,6 +297,12 @@ CONFIG_AUTOFS_FS=m
CONFIG_AUTOFS4_FS=m
#
+# Caches
+#
+# CONFIG_FSCACHE is not set
+# CONFIG_FUSE_FS is not set
+
+#
# CD-ROM/DVD Filesystems
#
CONFIG_ISO9660_FS=m
@@ -291,6 +329,8 @@ CONFIG_TMPFS=y
# CONFIG_TMPFS_XATTR is not set
# CONFIG_HUGETLB_PAGE is not set
CONFIG_RAMFS=y
+# CONFIG_CONFIGFS_FS is not set
+# CONFIG_RELAYFS_FS is not set
#
# Miscellaneous filesystems
@@ -319,6 +359,7 @@ CONFIG_RAMFS=y
# CONFIG_NCP_FS is not set
# CONFIG_CODA_FS is not set
# CONFIG_AFS_FS is not set
+# CONFIG_9P_FS is not set
#
# Partition Types
@@ -404,14 +445,15 @@ CONFIG_CRC32=m
# CONFIG_PRINTK_TIME is not set
CONFIG_DEBUG_KERNEL=y
CONFIG_LOG_BUF_SHIFT=14
+CONFIG_DETECT_SOFTLOCKUP=y
# CONFIG_SCHEDSTATS is not set
-# CONFIG_DEBUG_SLAB is not set
+CONFIG_DEBUG_SLAB=y
# CONFIG_DEBUG_SPINLOCK is not set
# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
# CONFIG_DEBUG_KOBJECT is not set
CONFIG_DEBUG_INFO=y
# CONFIG_DEBUG_FS is not set
CONFIG_FRAME_POINTER=y
-CONFIG_PT_PROXY=y
+# CONFIG_GPROF is not set
# CONFIG_GCOV is not set
# CONFIG_SYSCALL_DEBUG is not set
diff --git a/arch/um/drivers/Makefile b/arch/um/drivers/Makefile
index b2de9916c32..de17d4c6e02 100644
--- a/arch/um/drivers/Makefile
+++ b/arch/um/drivers/Makefile
@@ -10,7 +10,6 @@ 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)
net-objs := net_kern.o net_user.o
mconsole-objs := mconsole_kern.o mconsole_user.o
hostaudio-objs := hostaudio_kern.o
@@ -18,6 +17,19 @@ ubd-objs := ubd_kern.o ubd_user.o
port-objs := port_kern.o port_user.o
harddog-objs := harddog_kern.o harddog_user.o
+LDFLAGS_pcap.o := -r $(shell $(CC) $(CFLAGS) -print-file-name=libpcap.a)
+
+targets := pcap_kern.o pcap_user.o
+
+$(obj)/pcap.o: $(obj)/pcap_kern.o $(obj)/pcap_user.o
+ $(LD) -r -dp -o $@ $^ $(LDFLAGS) $(LDFLAGS_pcap.o)
+#XXX: The call below does not work because the flags are added before the
+# object name, so nothing from the library gets linked.
+#$(call if_changed,ld)
+
+# When the above is fixed, don't forget to add this too!
+#targets += $(obj)/pcap.o
+
obj-y := stdio_console.o fd.o chan_kern.o chan_user.o line.o
obj-$(CONFIG_SSL) += ssl.o
obj-$(CONFIG_STDERR_CONSOLE) += stderr_console.o
@@ -26,7 +38,7 @@ obj-$(CONFIG_UML_NET_SLIP) += slip.o slip_common.o
obj-$(CONFIG_UML_NET_SLIRP) += slirp.o slip_common.o
obj-$(CONFIG_UML_NET_DAEMON) += daemon.o
obj-$(CONFIG_UML_NET_MCAST) += mcast.o
-#obj-$(CONFIG_UML_NET_PCAP) += pcap.o $(PCAP)
+obj-$(CONFIG_UML_NET_PCAP) += pcap.o
obj-$(CONFIG_UML_NET) += net.o
obj-$(CONFIG_MCONSOLE) += mconsole.o
obj-$(CONFIG_MMAPPER) += mmapper_kern.o
@@ -41,6 +53,7 @@ obj-$(CONFIG_UML_WATCHDOG) += harddog.o
obj-$(CONFIG_BLK_DEV_COW_COMMON) += cow_user.o
obj-$(CONFIG_UML_RANDOM) += random.o
-USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o
+# pcap_user.o must be added explicitly.
+USER_OBJS := fd.o null.o pty.o tty.o xterm.o slip_common.o pcap_user.o
include arch/um/scripts/Makefile.rules
diff --git a/arch/um/drivers/cow.h b/arch/um/drivers/cow.h
index 4fcbe8b1b77..4fcf3a8d13f 100644
--- a/arch/um/drivers/cow.h
+++ b/arch/um/drivers/cow.h
@@ -3,10 +3,10 @@
#include <asm/types.h>
-#if __BYTE_ORDER == __BIG_ENDIAN
+#if defined(__BIG_ENDIAN)
# define ntohll(x) (x)
# define htonll(x) (x)
-#elif __BYTE_ORDER == __LITTLE_ENDIAN
+#elif defined(__LITTLE_ENDIAN)
# define ntohll(x) bswap_64(x)
# define htonll(x) bswap_64(x)
#else
diff --git a/arch/um/drivers/daemon_user.c b/arch/um/drivers/daemon_user.c
index cf15b4a8b51..c1b03f7c1da 100644
--- a/arch/um/drivers/daemon_user.c
+++ b/arch/um/drivers/daemon_user.c
@@ -157,9 +157,9 @@ static void daemon_remove(void *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);
+ kfree(pri->data_addr);
+ kfree(pri->ctl_addr);
+ kfree(pri->local_addr);
}
int daemon_user_write(int fd, void *buf, int len, struct daemon_data *pri)
diff --git a/arch/um/drivers/hostaudio_kern.c b/arch/um/drivers/hostaudio_kern.c
index d5742783e19..59602b81b24 100644
--- a/arch/um/drivers/hostaudio_kern.c
+++ b/arch/um/drivers/hostaudio_kern.c
@@ -57,10 +57,10 @@ __uml_setup("mixer=", set_mixer, "mixer=<mixer device>\n" MIXER_HELP);
#else /*MODULE*/
-MODULE_PARM(dsp, "s");
+module_param(dsp, charp, 0644);
MODULE_PARM_DESC(dsp, DSP_HELP);
-MODULE_PARM(mixer, "s");
+module_param(mixer, charp, 0644);
MODULE_PARM_DESC(mixer, MIXER_HELP);
#endif
diff --git a/arch/um/drivers/line.c b/arch/um/drivers/line.c
index 025d3be8aca..e0fdffa2d54 100644
--- a/arch/um/drivers/line.c
+++ b/arch/um/drivers/line.c
@@ -406,14 +406,12 @@ void line_disable(struct tty_struct *tty, int current_irq)
if(line->driver->read_irq == current_irq)
free_irq_later(line->driver->read_irq, tty);
else {
- free_irq_by_irq_and_dev(line->driver->read_irq, tty);
free_irq(line->driver->read_irq, tty);
}
if(line->driver->write_irq == current_irq)
free_irq_later(line->driver->write_irq, tty);
else {
- free_irq_by_irq_and_dev(line->driver->write_irq, tty);
free_irq(line->driver->write_irq, tty);
}
@@ -604,11 +602,26 @@ int line_get_config(char *name, struct line *lines, unsigned int num, char *str,
return n;
}
-int line_remove(struct line *lines, unsigned int num, char *str)
+int line_id(char **str, int *start_out, int *end_out)
+{
+ char *end;
+ int n;
+
+ n = simple_strtoul(*str, &end, 0);
+ if((*end != '\0') || (end == *str))
+ return -1;
+
+ *str = end;
+ *start_out = n;
+ *end_out = n;
+ return n;
+}
+
+int line_remove(struct line *lines, unsigned int num, int n)
{
char config[sizeof("conxxxx=none\0")];
- sprintf(config, "%s=none", str);
+ sprintf(config, "%d=none", n);
return !line_setup(lines, num, config, 0);
}
@@ -650,11 +663,15 @@ struct tty_driver *line_register_devfs(struct lines *set,
return driver;
}
+static spinlock_t winch_handler_lock;
+LIST_HEAD(winch_handlers);
+
void lines_init(struct line *lines, int nlines)
{
struct line *line;
int i;
+ spin_lock_init(&winch_handler_lock);
for(i = 0; i < nlines; i++){
line = &lines[i];
INIT_LIST_HEAD(&line->chan_list);
@@ -711,31 +728,30 @@ irqreturn_t winch_interrupt(int irq, void *data, struct pt_regs *unused)
return IRQ_HANDLED;
}
-DECLARE_MUTEX(winch_handler_sem);
-LIST_HEAD(winch_handlers);
-
void register_winch_irq(int fd, int tty_fd, int pid, struct tty_struct *tty)
{
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;
+ return;
}
+
*winch = ((struct winch) { .list = LIST_HEAD_INIT(winch->list),
.fd = fd,
.tty_fd = tty_fd,
.pid = pid,
.tty = tty });
+
+ spin_lock(&winch_handler_lock);
list_add(&winch->list, &winch_handlers);
+ spin_unlock(&winch_handler_lock);
+
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 unregister_winch(struct tty_struct *tty)
@@ -743,7 +759,7 @@ static void unregister_winch(struct tty_struct *tty)
struct list_head *ele;
struct winch *winch, *found = NULL;
- down(&winch_handler_sem);
+ spin_lock(&winch_handler_lock);
list_for_each(ele, &winch_handlers){
winch = list_entry(ele, struct winch, list);
if(winch->tty == tty){
@@ -751,21 +767,25 @@ static void unregister_winch(struct tty_struct *tty)
break;
}
}
-
if(found == NULL)
- goto out;
+ goto err;
+
+ list_del(&winch->list);
+ spin_unlock(&winch_handler_lock);
if(winch->pid != -1)
os_kill_process(winch->pid, 1);
- free_irq_by_irq_and_dev(WINCH_IRQ, winch);
free_irq(WINCH_IRQ, winch);
- list_del(&winch->list);
kfree(winch);
- out:
- up(&winch_handler_sem);
+
+ return;
+err:
+ spin_unlock(&winch_handler_lock);
}
+/* XXX: No lock as it's an exitcall... is this valid? Depending on cleanup
+ * order... are we sure that nothing else is done on the list? */
static void winch_cleanup(void)
{
struct list_head *ele;
@@ -774,6 +794,9 @@ static void winch_cleanup(void)
list_for_each(ele, &winch_handlers){
winch = list_entry(ele, struct winch, list);
if(winch->fd != -1){
+ /* Why is this different from the above free_irq(),
+ * which deactivates SIGIO? This searches the FD
+ * somewhere else and removes it from the list... */
deactivate_fd(winch->fd, WINCH_IRQ);
os_close_file(winch->fd);
}
diff --git a/arch/um/drivers/mconsole_kern.c b/arch/um/drivers/mconsole_kern.c
index d7c7adcc0a6..c190c241419 100644
--- a/arch/um/drivers/mconsole_kern.c
+++ b/arch/um/drivers/mconsole_kern.c
@@ -419,8 +419,9 @@ void mconsole_config(struct mc_request *req)
void mconsole_remove(struct mc_request *req)
{
struct mc_device *dev;
- char *ptr = req->request.data;
- int err;
+ char *ptr = req->request.data, *err_msg = "";
+ char error[256];
+ int err, start, end, n;
ptr += strlen("remove");
while(isspace(*ptr)) ptr++;
@@ -429,8 +430,35 @@ void mconsole_remove(struct mc_request *req)
mconsole_reply(req, "Bad remove option", 1, 0);
return;
}
- err = (*dev->remove)(&ptr[strlen(dev->name)]);
- mconsole_reply(req, "", err, 0);
+
+ ptr = &ptr[strlen(dev->name)];
+
+ err = 1;
+ n = (*dev->id)(&ptr, &start, &end);
+ if(n < 0){
+ err_msg = "Couldn't parse device number";
+ goto out;
+ }
+ else if((n < start) || (n > end)){
+ sprintf(error, "Invalid device number - must be between "
+ "%d and %d", start, end);
+ err_msg = error;
+ goto out;
+ }
+
+ err = (*dev->remove)(n);
+ switch(err){
+ case -ENODEV:
+ err_msg = "Device doesn't exist";
+ break;
+ case -EBUSY:
+ err_msg = "Device is currently open";
+ break;
+ default:
+ break;
+ }
+ out:
+ mconsole_reply(req, err_msg, err, 0);
}
#ifdef CONFIG_MAGIC_SYSRQ
@@ -529,7 +557,7 @@ static int create_proc_mconsole(void)
ent = create_proc_entry("mconsole", S_IFREG | 0200, NULL);
if(ent == NULL){
- printk("create_proc_mconsole : create_proc_entry failed\n");
+ printk(KERN_INFO "create_proc_mconsole : create_proc_entry failed\n");
return(0);
}
diff --git a/arch/um/drivers/net_kern.c b/arch/um/drivers/net_kern.c
index 4eeaf88c1e9..1495007bf6c 100644
--- a/arch/um/drivers/net_kern.c
+++ b/arch/um/drivers/net_kern.c
@@ -146,7 +146,6 @@ static int uml_net_close(struct net_device *dev)
netif_stop_queue(dev);
spin_lock(&lp->lock);
- free_irq_by_irq_and_dev(dev->irq, dev);
free_irq(dev->irq, dev);
if(lp->close != NULL)
(*lp->close)(lp->fd, &lp->user);
@@ -613,25 +612,35 @@ static int net_config(char *str)
return(err);
}
-static int net_remove(char *str)
+static int net_id(char **str, int *start_out, int *end_out)
+{
+ char *end;
+ int n;
+
+ n = simple_strtoul(*str, &end, 0);
+ if((*end != '\0') || (end == *str))
+ return -1;
+
+ *start_out = n;
+ *end_out = n;
+ *str = end;
+ return n;
+}
+
+static int net_remove(int n)
{
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);
+ return -ENODEV;
dev = device->dev;
lp = dev->priv;
- if(lp->fd > 0) return(-1);
+ if(lp->fd > 0)
+ return -EBUSY;
if(lp->remove != NULL) (*lp->remove)(&lp->user);
unregister_netdev(dev);
platform_device_unregister(&device->pdev);
@@ -639,13 +648,14 @@ static int net_remove(char *str)
list_del(&device->list);
kfree(device);
free_netdev(dev);
- return(0);
+ return 0;
}
static struct mc_device net_mc = {
.name = "eth",
.config = net_config,
.get_config = NULL,
+ .id = net_id,
.remove = net_remove,
};
diff --git a/arch/um/drivers/port_kern.c b/arch/um/drivers/port_kern.c
index b5ee07472f7..c41efd207fc 100644
--- a/arch/um/drivers/port_kern.c
+++ b/arch/um/drivers/port_kern.c
@@ -257,7 +257,6 @@ int port_wait(void *data)
* connection. Then we loop here throwing out failed
* connections until a good one is found.
*/
- free_irq_by_irq_and_dev(TELNETD_IRQ, conn);
free_irq(TELNETD_IRQ, conn);
if(conn->fd >= 0) break;
diff --git a/arch/um/drivers/ssl.c b/arch/um/drivers/ssl.c
index b32a77010fb..62e04ecfada 100644
--- a/arch/um/drivers/ssl.c
+++ b/arch/um/drivers/ssl.c
@@ -49,7 +49,7 @@ static struct chan_opts opts = {
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 int ssl_remove(int n);
static struct line_driver driver = {
.name = "UML serial line",
@@ -69,6 +69,7 @@ static struct line_driver driver = {
.name = "ssl",
.config = ssl_config,
.get_config = ssl_get_config,
+ .id = line_id,
.remove = ssl_remove,
},
};
@@ -94,10 +95,10 @@ static int ssl_get_config(char *dev, char *str, int size, char **error_out)
str, size, error_out));
}
-static int ssl_remove(char *str)
+static int ssl_remove(int n)
{
- return(line_remove(serial_lines,
- sizeof(serial_lines)/sizeof(serial_lines[0]), str));
+ return line_remove(serial_lines,
+ sizeof(serial_lines)/sizeof(serial_lines[0]), n);
}
int ssl_open(struct tty_struct *tty, struct file *filp)
diff --git a/arch/um/drivers/stdio_console.c b/arch/um/drivers/stdio_console.c
index afbe1e71ed8..005aa6333b6 100644
--- a/arch/um/drivers/stdio_console.c
+++ b/arch/um/drivers/stdio_console.c
@@ -55,7 +55,7 @@ static struct chan_opts opts = {
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 int con_remove(int n);
static struct line_driver driver = {
.name = "UML console",
@@ -75,6 +75,7 @@ static struct line_driver driver = {
.name = "con",
.config = con_config,
.get_config = con_get_config,
+ .id = line_id,
.remove = con_remove,
},
};
@@ -99,9 +100,9 @@ static int con_get_config(char *dev, char *str, int size, char **error_out)
size, error_out));
}
-static int con_remove(char *str)
+static int con_remove(int n)
{
- return(line_remove(vts, sizeof(vts)/sizeof(vts[0]), str));
+ return line_remove(vts, sizeof(vts)/sizeof(vts[0]), n);
}
static int con_open(struct tty_struct *tty, struct file *filp)
diff --git a/arch/um/drivers/ubd_kern.c b/arch/um/drivers/ubd_kern.c
index 2a7f6892c55..344b24d09a7 100644
--- a/arch/um/drivers/ubd_kern.c
+++ b/arch/um/drivers/ubd_kern.c
@@ -754,24 +754,34 @@ static int ubd_get_config(char *name, char *str, int size, char **error_out)
return(len);
}
-static int ubd_remove(char *str)
+static int ubd_id(char **str, int *start_out, int *end_out)
+{
+ int n;
+
+ n = parse_unit(str);
+ *start_out = 0;
+ *end_out = MAX_DEV - 1;
+ return n;
+}
+
+static int ubd_remove(int n)
{
struct ubd *dev;
- int n, err = -ENODEV;
+ int err = -ENODEV;
- n = parse_unit(&str);
+ spin_lock(&ubd_lock);
- if((n < 0) || (n >= MAX_DEV))
- return(err);
+ if(ubd_gendisk[n] == NULL)
+ goto out;
dev = &ubd_dev[n];
- if(dev->count > 0)
- return(-EBUSY); /* you cannot remove a open disk */
- err = 0;
- spin_lock(&ubd_lock);
+ if(dev->file == NULL)
+ goto out;
- if(ubd_gendisk[n] == NULL)
+ /* you cannot remove a open disk */
+ err = -EBUSY;
+ if(dev->count > 0)
goto out;
del_gendisk(ubd_gendisk[n]);
@@ -787,15 +797,16 @@ static int ubd_remove(char *str)
platform_device_unregister(&dev->pdev);
*dev = ((struct ubd) DEFAULT_UBD);
err = 0;
- out:
- spin_unlock(&ubd_lock);
- return(err);
+out:
+ spin_unlock(&ubd_lock);
+ return err;
}
static struct mc_device ubd_mc = {
.name = "ubd",
.config = ubd_config,
.get_config = ubd_get_config,
+ .id = ubd_id,
.remove = ubd_remove,
};
diff --git a/arch/um/drivers/xterm_kern.c b/arch/um/drivers/xterm_kern.c
index a4fdf3584ad..d269a80f4b0 100644
--- a/arch/um/drivers/xterm_kern.c
+++ b/arch/um/drivers/xterm_kern.c
@@ -69,7 +69,6 @@ int xterm_fd(int socket, int *pid_out)
* isn't set) this will hang... */
wait_for_completion(&data->ready);
- free_irq_by_irq_and_dev(XTERM_IRQ, data);
free_irq(XTERM_IRQ, data);
ret = data->new_fd;
diff --git a/arch/um/include/line.h b/arch/um/include/line.h
index 4c5e92c04cc..5323d22a6ca 100644
--- a/arch/um/include/line.h
+++ b/arch/um/include/line.h
@@ -101,7 +101,8 @@ 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, unsigned int sizeof_lines, char *str);
-extern int line_remove(struct line *lines, unsigned int sizeof_lines, char *str);
+extern int line_id(char **str, int *start_out, int *end_out);
+extern int line_remove(struct line *lines, unsigned int sizeof_lines, int n);
extern int line_get_config(char *dev, struct line *lines, unsigned int sizeof_lines, char *str,
int size, char **error_out);
diff --git a/arch/um/include/mconsole_kern.h b/arch/um/include/mconsole_kern.h
index 61c274fcee5..d86ee14260c 100644
--- a/arch/um/include/mconsole_kern.h
+++ b/arch/um/include/mconsole_kern.h
@@ -20,7 +20,8 @@ struct mc_device {
char *name;
int (*config)(char *);
int (*get_config)(char *, char *, int, char **);
- int (*remove)(char *);
+ int (*id)(char **, int *, int *);
+ int (*remove)(int);
};
#define CONFIG_CHUNK(str, size, current, chunk, end) \
diff --git a/arch/um/include/mem.h b/arch/um/include/mem.h
index 10c46c38949..99d3ad4a03e 100644
--- a/arch/um/include/mem.h
+++ b/arch/um/include/mem.h
@@ -13,6 +13,7 @@ extern int physmem_subst_mapping(void *virt, int fd, __u64 offset, int w);
extern int is_remapped(void *virt);
extern int physmem_remove_mapping(void *virt);
extern void physmem_forget_descriptor(int fd);
+extern unsigned long to_phys(void *virt);
#endif
diff --git a/arch/um/include/registers.h b/arch/um/include/registers.h
index 8744abb5224..0a35e6d0baa 100644
--- a/arch/um/include/registers.h
+++ b/arch/um/include/registers.h
@@ -14,6 +14,7 @@ extern int restore_fp_registers(int pid, unsigned long *fp_regs);
extern void save_registers(int pid, union uml_pt_regs *regs);
extern void restore_registers(int pid, union uml_pt_regs *regs);
extern void init_registers(int pid);
+extern void get_safe_registers(unsigned long * regs);
#endif
diff --git a/arch/um/include/sysdep-i386/ptrace_user.h b/arch/um/include/sysdep-i386/ptrace_user.h
index eca8066e7a4..899aa4b2a78 100644
--- a/arch/um/include/sysdep-i386/ptrace_user.h
+++ b/arch/um/include/sysdep-i386/ptrace_user.h
@@ -20,11 +20,24 @@
#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_ARG6_OFFSET PT_OFFSET(EBP)
#define PT_SYSCALL_RET_OFFSET PT_OFFSET(EAX)
+#define REGS_SYSCALL_NR EAX /* This is used before a system call */
+#define REGS_SYSCALL_ARG1 EBX
+#define REGS_SYSCALL_ARG2 ECX
+#define REGS_SYSCALL_ARG3 EDX
+#define REGS_SYSCALL_ARG4 ESI
+#define REGS_SYSCALL_ARG5 EDI
+#define REGS_SYSCALL_ARG6 EBP
+
+#define REGS_IP_INDEX EIP
+#define REGS_SP_INDEX UESP
+
#define PT_IP_OFFSET PT_OFFSET(EIP)
#define PT_IP(regs) ((regs)[EIP])
+#define PT_SP_OFFSET PT_OFFSET(UESP)
#define PT_SP(regs) ((regs)[UESP])
#ifndef FRAME_SIZE
diff --git a/arch/um/include/sysdep-i386/stub.h b/arch/um/include/sysdep-i386/stub.h
new file mode 100644
index 00000000000..d3699fe1c61
--- /dev/null
+++ b/arch/um/include/sysdep-i386/stub.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_STUB_H
+#define __SYSDEP_STUB_H
+
+#include <asm/ptrace.h>
+#include <asm/unistd.h>
+
+extern void stub_segv_handler(int sig);
+extern void stub_clone_handler(void);
+
+#define STUB_SYSCALL_RET EAX
+#define STUB_MMAP_NR __NR_mmap2
+#define MMAP_OFFSET(o) ((o) >> PAGE_SHIFT)
+
+static inline long stub_syscall2(long syscall, long arg1, long arg2)
+{
+ long ret;
+
+ __asm__("movl %0, %%ecx; " : : "g" (arg2) : "%ecx");
+ __asm__("movl %0, %%ebx; " : : "g" (arg1) : "%ebx");
+ __asm__("movl %0, %%eax; " : : "g" (syscall) : "%eax");
+ __asm__("int $0x80;" : : : "%eax");
+ __asm__ __volatile__("movl %%eax, %0; " : "=g" (ret) :);
+ return(ret);
+}
+
+static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3)
+{
+ __asm__("movl %0, %%edx; " : : "g" (arg3) : "%edx");
+ return(stub_syscall2(syscall, arg1, arg2));
+}
+
+static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3,
+ long arg4)
+{
+ __asm__("movl %0, %%esi; " : : "g" (arg4) : "%esi");
+ return(stub_syscall3(syscall, arg1, arg2, arg3));
+}
+
+static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3,
+ long arg4, long arg5, long arg6)
+{
+ long ret;
+ __asm__("movl %0, %%eax; " : : "g" (syscall) : "%eax");
+ __asm__("movl %0, %%ebx; " : : "g" (arg1) : "%ebx");
+ __asm__("movl %0, %%ecx; " : : "g" (arg2) : "%ecx");
+ __asm__("movl %0, %%edx; " : : "g" (arg3) : "%edx");
+ __asm__("movl %0, %%esi; " : : "g" (arg4) : "%esi");
+ __asm__("movl %0, %%edi; " : : "g" (arg5) : "%edi");
+ __asm__ __volatile__("pushl %%ebp ; movl %1, %%ebp; "
+ "int $0x80; popl %%ebp ; "
+ "movl %%eax, %0; " : "=g" (ret) : "g" (arg6) : "%eax");
+ return(ret);
+}
+
+static inline void trap_myself(void)
+{
+ __asm("int3");
+}
+
+#endif
diff --git a/arch/um/include/sysdep-x86_64/ptrace_user.h b/arch/um/include/sysdep-x86_64/ptrace_user.h
index 31729973fb1..128faf02736 100644
--- a/arch/um/include/sysdep-x86_64/ptrace_user.h
+++ b/arch/um/include/sysdep-x86_64/ptrace_user.h
@@ -55,6 +55,20 @@
#define PTRACE_OLDSETOPTIONS 21
#endif
+/* These are before the system call, so the the system call number is RAX
+ * rather than ORIG_RAX, and arg4 is R10 rather than RCX
+ */
+#define REGS_SYSCALL_NR PT_INDEX(RAX)
+#define REGS_SYSCALL_ARG1 PT_INDEX(RDI)
+#define REGS_SYSCALL_ARG2 PT_INDEX(RSI)
+#define REGS_SYSCALL_ARG3 PT_INDEX(RDX)
+#define REGS_SYSCALL_ARG4 PT_INDEX(R10)
+#define REGS_SYSCALL_ARG5 PT_INDEX(R8)
+#define REGS_SYSCALL_ARG6 PT_INDEX(R9)
+
+#define REGS_IP_INDEX PT_INDEX(RIP)
+#define REGS_SP_INDEX PT_INDEX(RSP)
+
#endif
/*
diff --git a/arch/um/include/sysdep-x86_64/stub.h b/arch/um/include/sysdep-x86_64/stub.h
new file mode 100644
index 00000000000..f599058d826
--- /dev/null
+++ b/arch/um/include/sysdep-x86_64/stub.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __SYSDEP_STUB_H
+#define __SYSDEP_STUB_H
+
+#include <asm/ptrace.h>
+#include <asm/unistd.h>
+#include <sysdep/ptrace_user.h>
+
+extern void stub_segv_handler(int sig);
+extern void stub_clone_handler(void);
+
+#define STUB_SYSCALL_RET PT_INDEX(RAX)
+#define STUB_MMAP_NR __NR_mmap
+#define MMAP_OFFSET(o) (o)
+
+static inline long stub_syscall2(long syscall, long arg1, long arg2)
+{
+ long ret;
+
+ __asm__("movq %0, %%rsi; " : : "g" (arg2) : "%rsi");
+ __asm__("movq %0, %%rdi; " : : "g" (arg1) : "%rdi");
+ __asm__("movq %0, %%rax; " : : "g" (syscall) : "%rax");
+ __asm__("syscall;" : : : "%rax", "%r11", "%rcx");
+ __asm__ __volatile__("movq %%rax, %0; " : "=g" (ret) :);
+ return(ret);
+}
+
+static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3)
+{
+ __asm__("movq %0, %%rdx; " : : "g" (arg3) : "%rdx");
+ return(stub_syscall2(syscall, arg1, arg2));
+}
+
+static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3,
+ long arg4)
+{
+ __asm__("movq %0, %%r10; " : : "g" (arg4) : "%r10");
+ return(stub_syscall3(syscall, arg1, arg2, arg3));
+}
+
+static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3,
+ long arg4, long arg5, long arg6)
+{
+ __asm__("movq %0, %%r9; " : : "g" (arg6) : "%r9");
+ __asm__("movq %0, %%r8; " : : "g" (arg5) : "%r8");
+ return(stub_syscall4(syscall, arg1, arg2, arg3, arg4));
+}
+
+static inline void trap_myself(void)
+{
+ __asm("int3");
+}
+
+#endif
diff --git a/arch/um/include/time_user.h b/arch/um/include/time_user.h
index 6793a2fcd0a..17d7ef2141f 100644
--- a/arch/um/include/time_user.h
+++ b/arch/um/include/time_user.h
@@ -8,11 +8,12 @@
extern void timer(void);
extern void switch_timers(int to_real);
-extern void set_interval(int timer_type);
extern void idle_sleep(int secs);
extern void enable_timer(void);
+extern void prepare_timer(void * ptr);
extern void disable_timer(void);
extern unsigned long time_lock(void);
extern void time_unlock(unsigned long);
+extern void user_time_init(void);
#endif
diff --git a/arch/um/include/tlb.h b/arch/um/include/tlb.h
index da1097285b8..c6f9628f39b 100644
--- a/arch/um/include/tlb.h
+++ b/arch/um/include/tlb.h
@@ -37,31 +37,25 @@ struct host_vm_op {
extern void mprotect_kernel_vm(int w);
extern void force_flush_all(void);
extern void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
- unsigned long end_addr, int force, int data,
- void (*do_ops)(int, struct host_vm_op *, int));
+ unsigned long end_addr, int force,
+ void (*do_ops)(union mm_context *,
+ struct host_vm_op *, int));
extern int flush_tlb_kernel_range_common(unsigned long start,
unsigned long end);
extern int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
int r, int w, int x, struct host_vm_op *ops, int index,
- int last_filled, int data,
- void (*do_ops)(int, struct host_vm_op *, int));
+ int last_filled, union mm_context *mmu,
+ void (*do_ops)(union mm_context *, struct host_vm_op *,
+ int));
extern int add_munmap(unsigned long addr, unsigned long len,
struct host_vm_op *ops, int index, int last_filled,
- int data, void (*do_ops)(int, struct host_vm_op *, int));
+ union mm_context *mmu,
+ void (*do_ops)(union mm_context *, struct host_vm_op *,
+ int));
extern int add_mprotect(unsigned long addr, unsigned long len, int r, int w,
int x, struct host_vm_op *ops, int index,
- int last_filled, int data,
- void (*do_ops)(int, struct host_vm_op *, int));
+ int last_filled, union mm_context *mmu,
+ void (*do_ops)(union mm_context *, struct host_vm_op *,
+ int));
#endif
-
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S
index 715b0838a68..3942a5f245d 100644
--- a/arch/um/kernel/dyn.lds.S
+++ b/arch/um/kernel/dyn.lds.S
@@ -67,6 +67,12 @@ SECTIONS
*(.stub .text.* .gnu.linkonce.t.*)
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
+
+ . = ALIGN(4096);
+ __syscall_stub_start = .;
+ *(.__syscall_stub*)
+ __syscall_stub_end = .;
+ . = ALIGN(4096);
} =0x90909090
.fini : {
KEEP (*(.fini))
diff --git a/arch/um/kernel/exitcode.c b/arch/um/kernel/exitcode.c
index 0ea87f24b36..d21ebad666b 100644
--- a/arch/um/kernel/exitcode.c
+++ b/arch/um/kernel/exitcode.c
@@ -48,7 +48,7 @@ static int make_proc_exitcode(void)
ent = create_proc_entry("exitcode", 0600, &proc_root);
if(ent == NULL){
- printk("make_proc_exitcode : Failed to register "
+ printk(KERN_WARNING "make_proc_exitcode : Failed to register "
"/proc/exitcode\n");
return(0);
}
diff --git a/arch/um/kernel/helper.c b/arch/um/kernel/helper.c
index 13b1f5c2f7e..f83e1e8e239 100644
--- a/arch/um/kernel/helper.c
+++ b/arch/um/kernel/helper.c
@@ -13,6 +13,7 @@
#include "user.h"
#include "kern_util.h"
#include "user_util.h"
+#include "helper.h"
#include "os.h"
struct helper_data {
@@ -149,7 +150,7 @@ int run_helper_thread(int (*proc)(void *), void *arg, unsigned int flags,
return(pid);
}
-int helper_wait(int pid, int block)
+int helper_wait(int pid)
{
int ret;
@@ -160,14 +161,3 @@ int helper_wait(int pid, int block)
}
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 --git a/arch/um/kernel/irq.c b/arch/um/kernel/irq.c
index d44fb528254..9f18061ef4c 100644
--- a/arch/um/kernel/irq.c
+++ b/arch/um/kernel/irq.c
@@ -124,14 +124,16 @@ void irq_unlock(unsigned long flags)
spin_unlock_irqrestore(&irq_spinlock, flags);
}
-/* presently hw_interrupt_type must define (startup || enable) &&
- * disable && end */
+/* hw_interrupt_type must define (startup || enable) &&
+ * (shutdown || disable) && end */
static void dummy(unsigned int irq)
{
}
-static struct hw_interrupt_type SIGIO_irq_type = {
+/* This is used for everything else than the timer. */
+static struct hw_interrupt_type normal_irq_type = {
.typename = "SIGIO",
+ .release = free_irq_by_irq_and_dev,
.disable = dummy,
.enable = dummy,
.ack = dummy,
@@ -140,6 +142,7 @@ static struct hw_interrupt_type SIGIO_irq_type = {
static struct hw_interrupt_type SIGVTALRM_irq_type = {
.typename = "SIGVTALRM",
+ .release = free_irq_by_irq_and_dev,
.shutdown = dummy, /* never called */
.disable = dummy,
.enable = dummy,
@@ -160,7 +163,7 @@ void __init init_IRQ(void)
irq_desc[i].status = IRQ_DISABLED;
irq_desc[i].action = NULL;
irq_desc[i].depth = 1;
- irq_desc[i].handler = &SIGIO_irq_type;
+ irq_desc[i].handler = &normal_irq_type;
enable_irq(i);
}
}
diff --git a/arch/um/kernel/irq_user.c b/arch/um/kernel/irq_user.c
index b3074cbaa47..c3ccaf24f3e 100644
--- a/arch/um/kernel/irq_user.c
+++ b/arch/um/kernel/irq_user.c
@@ -85,8 +85,6 @@ void sigio_handler(int sig, union uml_pt_regs *regs)
next = irq_fd->next;
if(irq_fd->freed){
free_irq(irq_fd->irq, irq_fd->id);
- free_irq_by_irq_and_dev(irq_fd->irq,
- irq_fd->id);
}
}
}
diff --git a/arch/um/kernel/main.c b/arch/um/kernel/main.c
index e59f5815267..1e1a87f1c51 100644
--- a/arch/um/kernel/main.c
+++ b/arch/um/kernel/main.c
@@ -69,7 +69,6 @@ static __init void do_uml_initcalls(void)
static void last_ditch_exit(int sig)
{
- kmalloc_ok = 0;
signal(SIGINT, SIG_DFL);
signal(SIGTERM, SIG_DFL);
signal(SIGHUP, SIG_DFL);
diff --git a/arch/um/kernel/mem.c b/arch/um/kernel/mem.c
index c22825f13e4..5597bd39e6b 100644
--- a/arch/um/kernel/mem.c
+++ b/arch/um/kernel/mem.c
@@ -53,7 +53,6 @@ static void setup_highmem(unsigned long highmem_start,
for(i = 0; i < highmem_len >> PAGE_SHIFT; i++){
page = &mem_map[highmem_pfn + i];
ClearPageReserved(page);
- set_bit(PG_highmem, &page->flags);
set_page_count(page, 1);
__free_page(page);
}
diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c
index 420e6d51fa0..a24e3b7f4bf 100644
--- a/arch/um/kernel/physmem.c
+++ b/arch/um/kernel/physmem.c
@@ -353,6 +353,8 @@ void map_memory(unsigned long virt, unsigned long phys, unsigned long len,
#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
+extern int __syscall_stub_start, __binary_start;
+
void setup_physmem(unsigned long start, unsigned long reserve_end,
unsigned long len, unsigned long highmem)
{
@@ -371,6 +373,12 @@ void setup_physmem(unsigned long start, unsigned long reserve_end,
exit(1);
}
+ /* Special kludge - This page will be mapped in to userspace processes
+ * from physmem_fd, so it needs to be written out there.
+ */
+ os_seek_file(physmem_fd, __pa(&__syscall_stub_start));
+ os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE);
+
bootmap_size = init_bootmem(pfn, pfn + delta);
free_bootmem(__pa(reserve_end) + bootmap_size,
len - bootmap_size - reserve);
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 1b5ef3e96c7..67acd92c532 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -32,6 +32,7 @@
#include "uml-config.h"
#include "choose-mode.h"
#include "mode.h"
+#include "tempfile.h"
#ifdef UML_CONFIG_MODE_SKAS
#include "skas.h"
#include "skas_ptrace.h"
@@ -130,7 +131,7 @@ int start_fork_tramp(void *thread_arg, unsigned long temp_stack,
return(arg.pid);
}
-static int ptrace_child(void)
+static int ptrace_child(void *arg)
{
int ret;
int pid = os_getpid(), ppid = getppid();
@@ -159,16 +160,20 @@ static int ptrace_child(void)
_exit(ret);
}
-static int start_ptraced_child(void)
+static int start_ptraced_child(void **stack_out)
{
+ void *stack;
+ unsigned long sp;
int pid, n, status;
- pid = fork();
- if(pid == 0)
- ptrace_child();
-
+ 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 : fork failed, errno = %d", errno);
+ panic("check_ptrace : clone failed, errno = %d", errno);
CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
if(n < 0)
panic("check_ptrace : wait failed, errno = %d", errno);
@@ -176,6 +181,7 @@ static int start_ptraced_child(void)
panic("check_ptrace : expected SIGSTOP, got status = %d",
status);
+ *stack_out = stack;
return(pid);
}
@@ -183,12 +189,12 @@ static int start_ptraced_child(void)
* just avoid using sysemu, not panic, but only if SYSEMU features are broken.
* So only for SYSEMU features we test mustpanic, while normal host features
* must work anyway!*/
-static int stop_ptraced_child(int pid, int exitcode, int mustexit)
+static int stop_ptraced_child(int pid, void *stack, int exitcode, int mustpanic)
{
int status, n, ret = 0;
if(ptrace(PTRACE_CONT, pid, 0, 0) < 0)
- panic("stop_ptraced_child : ptrace failed, errno = %d", errno);
+ panic("check_ptrace : ptrace failed, errno = %d", errno);
CATCH_EINTR(n = waitpid(pid, &status, 0));
if(!WIFEXITED(status) || (WEXITSTATUS(status) != exitcode)) {
int exit_with = WEXITSTATUS(status);
@@ -199,24 +205,40 @@ static int stop_ptraced_child(int pid, int exitcode, int mustexit)
printk("check_ptrace : child exited with exitcode %d, while "
"expecting %d; status 0x%x", exit_with,
exitcode, status);
- if (mustexit)
+ if (mustpanic)
panic("\n");
else
printk("\n");
ret = -1;
}
+ if(munmap(stack, PAGE_SIZE) < 0)
+ panic("check_ptrace : munmap failed, errno = %d", errno);
return ret;
}
static int force_sysemu_disabled = 0;
+int ptrace_faultinfo = 1;
+int proc_mm = 1;
+
+static int __init skas0_cmd_param(char *str, int* add)
+{
+ ptrace_faultinfo = proc_mm = 0;
+ return 0;
+}
+
static int __init nosysemu_cmd_param(char *str, int* add)
{
force_sysemu_disabled = 1;
return 0;
}
+__uml_setup("skas0", skas0_cmd_param,
+ "skas0\n"
+ " Disables SKAS3 usage, so that SKAS0 is used, unless you \n"
+ " specify mode=tt.\n\n");
+
__uml_setup("nosysemu", nosysemu_cmd_param,
"nosysemu\n"
" Turns off syscall emulation patch for ptrace (SYSEMU) on.\n"
@@ -227,11 +249,12 @@ __uml_setup("nosysemu", nosysemu_cmd_param,
static void __init check_sysemu(void)
{
+ void *stack;
int pid, syscall, n, status, count=0;
printk("Checking syscall emulation patch for ptrace...");
sysemu_supported = 0;
- pid = start_ptraced_child();
+ pid = start_ptraced_child(&stack);
if(ptrace(PTRACE_SYSEMU, pid, 0, 0) < 0)
goto fail;
@@ -249,7 +272,7 @@ static void __init check_sysemu(void)
panic("check_sysemu : failed to modify system "
"call return, errno = %d", errno);
- if (stop_ptraced_child(pid, 0, 0) < 0)
+ if (stop_ptraced_child(pid, stack, 0, 0) < 0)
goto fail_stopped;
sysemu_supported = 1;
@@ -257,7 +280,7 @@ static void __init check_sysemu(void)
set_using_sysemu(!force_sysemu_disabled);
printk("Checking advanced syscall emulation patch for ptrace...");
- pid = start_ptraced_child();
+ pid = start_ptraced_child(&stack);
while(1){
count++;
if(ptrace(PTRACE_SYSEMU_SINGLESTEP, pid, 0, 0) < 0)
@@ -282,7 +305,7 @@ static void __init check_sysemu(void)
break;
}
}
- if (stop_ptraced_child(pid, 0, 0) < 0)
+ if (stop_ptraced_child(pid, stack, 0, 0) < 0)
goto fail_stopped;
sysemu_supported = 2;
@@ -293,17 +316,18 @@ static void __init check_sysemu(void)
return;
fail:
- stop_ptraced_child(pid, 1, 0);
+ stop_ptraced_child(pid, stack, 1, 0);
fail_stopped:
printk("missing\n");
}
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();
+ pid = start_ptraced_child(&stack);
if (ptrace(PTRACE_OLDSETOPTIONS, pid, 0, (void *)PTRACE_O_TRACESYSGOOD) < 0)
panic("check_ptrace: PTRACE_SETOPTIONS failed, errno = %d", errno);
@@ -330,7 +354,7 @@ void __init check_ptrace(void)
break;
}
}
- stop_ptraced_child(pid, 0, 1);
+ stop_ptraced_child(pid, stack, 0, 1);
printk("OK\n");
check_sysemu();
}
@@ -358,49 +382,54 @@ void forward_pending_sigio(int target)
kill(target, SIGIO);
}
+extern void *__syscall_stub_start, __syscall_stub_end;
+
#ifdef UML_CONFIG_MODE_SKAS
-static inline int check_skas3_ptrace_support(void)
+
+static inline void check_skas3_ptrace_support(void)
{
struct ptrace_faultinfo fi;
- int pid, n, ret = 1;
+ void *stack;
+ int pid, n;
printf("Checking for the skas3 patch in the host...");
- pid = start_ptraced_child();
+ pid = start_ptraced_child(&stack);
n = ptrace(PTRACE_FAULTINFO, pid, 0, &fi);
if (n < 0) {
+ ptrace_faultinfo = 0;
if(errno == EIO)
printf("not found\n");
else {
perror("not found");
}
- ret = 0;
- } else {
- printf("found\n");
+ }
+ else {
+ if (!ptrace_faultinfo)
+ printf("found but disabled on command line\n");
+ else
+ printf("found\n");
}
init_registers(pid);
- stop_ptraced_child(pid, 1, 1);
-
- return(ret);
+ stop_ptraced_child(pid, stack, 1, 1);
}
int can_do_skas(void)
{
- int ret = 1;
-
printf("Checking for /proc/mm...");
if (os_access("/proc/mm", OS_ACC_W_OK) < 0) {
+ proc_mm = 0;
printf("not found\n");
- ret = 0;
- goto out;
} else {
- printf("found\n");
+ if (!proc_mm)
+ printf("found but disabled on command line\n");
+ else
+ printf("found\n");
}
- ret = check_skas3_ptrace_support();
-out:
- return ret;
+ check_skas3_ptrace_support();
+ return 1;
}
#else
int can_do_skas(void)
diff --git a/arch/um/kernel/process_kern.c b/arch/um/kernel/process_kern.c
index 804c6bbdf67..c23d8a08d0f 100644
--- a/arch/um/kernel/process_kern.c
+++ b/arch/um/kernel/process_kern.c
@@ -8,6 +8,7 @@
#include "linux/kernel.h"
#include "linux/sched.h"
#include "linux/interrupt.h"
+#include "linux/string.h"
#include "linux/mm.h"
#include "linux/slab.h"
#include "linux/utsname.h"
@@ -95,8 +96,8 @@ int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
current->thread.request.u.thread.proc = fn;
current->thread.request.u.thread.arg = arg;
- pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0, NULL, 0, NULL,
- NULL);
+ pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0,
+ &current->thread.regs, 0, NULL, NULL);
if(pid < 0)
panic("do_fork failed in kernel_thread, errno = %d", pid);
return(pid);
@@ -168,7 +169,7 @@ int current_pid(void)
void default_idle(void)
{
- uml_idle_timer();
+ CHOOSE_MODE(uml_idle_timer(), (void) 0);
atomic_inc(&init_mm.mm_count);
current->mm = &init_mm;
@@ -322,12 +323,7 @@ void do_uml_exitcalls(void)
char *uml_strdup(char *string)
{
- char *new;
-
- new = kmalloc(strlen(string) + 1, GFP_KERNEL);
- if(new == NULL) return(NULL);
- strcpy(new, string);
- return(new);
+ return kstrdup(string, GFP_KERNEL);
}
int copy_to_user_proc(void __user *to, void *from, int size)
@@ -416,7 +412,7 @@ int __init make_proc_sysemu(void)
if (ent == NULL)
{
- printk("Failed to register /proc/sysemu\n");
+ printk(KERN_WARNING "Failed to register /proc/sysemu\n");
return(0);
}
diff --git a/arch/um/kernel/reboot.c b/arch/um/kernel/reboot.c
index 207f89d7490..a637e885c58 100644
--- a/arch/um/kernel/reboot.c
+++ b/arch/um/kernel/reboot.c
@@ -38,35 +38,28 @@ static void kill_off_processes(void)
void uml_cleanup(void)
{
- kill_off_processes();
+ kmalloc_ok = 0;
do_uml_exitcalls();
+ kill_off_processes();
}
void machine_restart(char * __unused)
{
- do_uml_exitcalls();
- kill_off_processes();
+ uml_cleanup();
CHOOSE_MODE(reboot_tt(), reboot_skas());
}
-EXPORT_SYMBOL(machine_restart);
-
void machine_power_off(void)
{
- do_uml_exitcalls();
- kill_off_processes();
+ uml_cleanup();
CHOOSE_MODE(halt_tt(), halt_skas());
}
-EXPORT_SYMBOL(machine_power_off);
-
void machine_halt(void)
{
machine_power_off();
}
-EXPORT_SYMBOL(machine_halt);
-
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
index d37d1bfcd6f..d296d55ade4 100644
--- a/arch/um/kernel/skas/Makefile
+++ b/arch/um/kernel/skas/Makefile
@@ -3,11 +3,14 @@
# Licensed under the GPL
#
-obj-y := exec_kern.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 \
+obj-y := clone.o exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \
+ syscall_kern.o syscall_user.o tlb.o trap_user.o uaccess.o \
subdir- := util
-USER_OBJS := process.o time.o
+USER_OBJS := process.o clone.o
include arch/um/scripts/Makefile.rules
+
+# clone.o is in the stub, so it can't be built with profiling
+$(obj)/clone.o : c_flags = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c
new file mode 100644
index 00000000000..4dc55f10cd1
--- /dev/null
+++ b/arch/um/kernel/skas/clone.c
@@ -0,0 +1,44 @@
+#include <sched.h>
+#include <signal.h>
+#include <sys/mman.h>
+#include <sys/time.h>
+#include <asm/unistd.h>
+#include <asm/page.h>
+#include "ptrace_user.h"
+#include "skas.h"
+#include "stub-data.h"
+#include "uml-config.h"
+#include "sysdep/stub.h"
+
+/* This is in a separate file because it needs to be compiled with any
+ * extraneous gcc flags (-pg, -fprofile-arcs, -ftest-coverage) disabled
+ */
+void __attribute__ ((__section__ (".__syscall_stub")))
+stub_clone_handler(void)
+{
+ long err;
+ struct stub_data *from = (struct stub_data *) UML_CONFIG_STUB_DATA;
+
+ err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD,
+ UML_CONFIG_STUB_DATA + PAGE_SIZE / 2 -
+ sizeof(void *));
+ if(err != 0)
+ goto out;
+
+ err = stub_syscall4(__NR_ptrace, PTRACE_TRACEME, 0, 0, 0);
+ if(err)
+ goto out;
+
+ err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL,
+ (long) &from->timer, 0);
+ if(err)
+ goto out;
+
+ err = stub_syscall6(STUB_MMAP_NR, UML_CONFIG_STUB_DATA, PAGE_SIZE,
+ PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED,
+ from->fd, from->offset);
+ out:
+ /* save current result. Parent: pid; child: retcode of mmap */
+ from->err = err;
+ trap_myself();
+}
diff --git a/arch/um/kernel/skas/exec_kern.c b/arch/um/kernel/skas/exec_kern.c
index c6b4d5dba78..77ed7bbab21 100644
--- a/arch/um/kernel/skas/exec_kern.c
+++ b/arch/um/kernel/skas/exec_kern.c
@@ -18,7 +18,7 @@
void flush_thread_skas(void)
{
force_flush_all();
- switch_mm_skas(current->mm->context.skas.mm_fd);
+ switch_mm_skas(&current->mm->context.skas.id);
}
void start_thread_skas(struct pt_regs *regs, unsigned long eip,
diff --git a/arch/um/kernel/skas/include/mm_id.h b/arch/um/kernel/skas/include/mm_id.h
new file mode 100644
index 00000000000..48dd0989dda
--- /dev/null
+++ b/arch/um/kernel/skas/include/mm_id.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2005 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __MM_ID_H
+#define __MM_ID_H
+
+struct mm_id {
+ union {
+ int mm_fd;
+ int pid;
+ } u;
+ unsigned long stack;
+};
+
+#endif
diff --git a/arch/um/kernel/skas/include/mmu-skas.h b/arch/um/kernel/skas/include/mmu-skas.h
index 4cd60d7213f..278b72f1d9a 100644
--- a/arch/um/kernel/skas/include/mmu-skas.h
+++ b/arch/um/kernel/skas/include/mmu-skas.h
@@ -6,10 +6,15 @@
#ifndef __SKAS_MMU_H
#define __SKAS_MMU_H
+#include "mm_id.h"
+
struct mmu_context_skas {
- int mm_fd;
+ struct mm_id id;
+ unsigned long last_page_table;
};
+extern void switch_mm_skas(struct mm_id * mm_idp);
+
#endif
/*
diff --git a/arch/um/kernel/skas/include/mode-skas.h b/arch/um/kernel/skas/include/mode-skas.h
index c1e33bd788d..bcd26a6a388 100644
--- a/arch/um/kernel/skas/include/mode-skas.h
+++ b/arch/um/kernel/skas/include/mode-skas.h
@@ -13,7 +13,6 @@ 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 void sig_handler_common_skas(int sig, void *sc_ptr);
extern void halt_skas(void);
extern void reboot_skas(void);
diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h
index 96b51dba347..d983ea84254 100644
--- a/arch/um/kernel/skas/include/skas.h
+++ b/arch/um/kernel/skas/include/skas.h
@@ -6,9 +6,11 @@
#ifndef __SKAS_H
#define __SKAS_H
+#include "mm_id.h"
#include "sysdep/ptrace.h"
extern int userspace_pid[];
+extern int proc_mm, ptrace_faultinfo;
extern void switch_threads(void *me, void *next);
extern void thread_wait(void *sw, void *fb);
@@ -22,16 +24,18 @@ 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 len, int r, int w,
- int x, int phys_fd, unsigned long long offset);
-extern int unmap(int fd, void *addr, unsigned long len);
-extern int protect(int fd, unsigned long addr, unsigned long len,
- int r, int w, int x);
+extern int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len,
+ int r, int w, int x, int phys_fd, unsigned long long offset);
+extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len);
+extern int protect(struct mm_id * mm_idp, unsigned long addr,
+ unsigned long len, int r, int w, int x);
extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
extern int new_mm(int from);
-extern void start_userspace(int cpu);
+extern int start_userspace(unsigned long stub_stack);
+extern int copy_context_skas0(unsigned long stack, int pid);
extern void get_skas_faultinfo(int pid, struct faultinfo * fi);
extern long execute_syscall_skas(void *r);
+extern unsigned long current_stub_stack(void);
#endif
diff --git a/arch/um/kernel/skas/include/stub-data.h b/arch/um/kernel/skas/include/stub-data.h
new file mode 100644
index 00000000000..f6ed92c3727
--- /dev/null
+++ b/arch/um/kernel/skas/include/stub-data.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2005 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#ifndef __STUB_DATA_H
+#define __STUB_DATA_H
+
+#include <sys/time.h>
+
+struct stub_data {
+ long offset;
+ int fd;
+ struct itimerval timer;
+ long err;
+};
+
+#endif
diff --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c
index 438db2f4345..147466d7ff4 100644
--- a/arch/um/kernel/skas/mem.c
+++ b/arch/um/kernel/skas/mem.c
@@ -5,7 +5,9 @@
#include "linux/config.h"
#include "linux/mm.h"
+#include "asm/pgtable.h"
#include "mem_user.h"
+#include "skas.h"
unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
unsigned long *task_size_out)
@@ -18,7 +20,9 @@ unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
*task_size_out = CONFIG_HOST_TASK_SIZE;
#else
*host_size_out = top;
- *task_size_out = top;
+ if (proc_mm && ptrace_faultinfo)
+ *task_size_out = top;
+ else *task_size_out = CONFIG_STUB_START & PGDIR_MASK;
#endif
return(((unsigned long) set_task_sizes_skas) & ~0xffffff);
}
diff --git a/arch/um/kernel/skas/mem_user.c b/arch/um/kernel/skas/mem_user.c
index 1310bf1e88d..b0980ff3bd9 100644
--- a/arch/um/kernel/skas/mem_user.c
+++ b/arch/um/kernel/skas/mem_user.c
@@ -3,100 +3,171 @@
* Licensed under the GPL
*/
+#include <signal.h>
#include <errno.h>
#include <sys/mman.h>
+#include <sys/wait.h>
+#include <asm/page.h>
+#include <asm/unistd.h>
#include "mem_user.h"
#include "mem.h"
+#include "mm_id.h"
#include "user.h"
#include "os.h"
#include "proc_mm.h"
-
-void map(int fd, unsigned long virt, unsigned long len, int r, int w,
- int x, int phys_fd, unsigned long long offset)
+#include "ptrace_user.h"
+#include "user_util.h"
+#include "kern_util.h"
+#include "task.h"
+#include "registers.h"
+#include "uml-config.h"
+#include "sysdep/ptrace.h"
+#include "sysdep/stub.h"
+#include "skas.h"
+
+extern unsigned long syscall_stub, __syscall_stub_start;
+
+extern void wait_stub_done(int pid, int sig, char * fname);
+
+static long run_syscall_stub(struct mm_id * mm_idp, int syscall,
+ unsigned long *args)
{
- struct proc_mm_op map;
- int prot, n;
-
- prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
- (x ? PROT_EXEC : 0);
-
- 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 n, pid = mm_idp->u.pid;
+ unsigned long regs[MAX_REG_NR];
+
+ get_safe_registers(regs);
+ regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
+ ((unsigned long) &syscall_stub -
+ (unsigned long) &__syscall_stub_start);
+ /* XXX Don't have a define for starting a syscall */
+ regs[REGS_SYSCALL_NR] = syscall;
+ regs[REGS_SYSCALL_ARG1] = args[0];
+ regs[REGS_SYSCALL_ARG2] = args[1];
+ regs[REGS_SYSCALL_ARG3] = args[2];
+ regs[REGS_SYSCALL_ARG4] = args[3];
+ regs[REGS_SYSCALL_ARG5] = args[4];
+ regs[REGS_SYSCALL_ARG6] = args[5];
+ n = ptrace_setregs(pid, regs);
+ if(n < 0){
+ printk("run_syscall_stub : PTRACE_SETREGS failed, "
+ "errno = %d\n", n);
+ return(n);
+ }
+
+ wait_stub_done(pid, 0, "run_syscall_stub");
+
+ return(*((unsigned long *) mm_idp->stack));
}
-int unmap(int fd, void *addr, unsigned long len)
+int map(struct mm_id *mm_idp, unsigned long virt, unsigned long len,
+ int r, int w, int x, int phys_fd, unsigned long long offset)
{
- 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 prot, n;
+
+ prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
+ (x ? PROT_EXEC : 0);
+
+ if(proc_mm){
+ struct proc_mm_op map;
+ int fd = mm_idp->u.mm_fd;
+ 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);
+ }
+ else {
+ long res;
+ unsigned long args[] = { virt, len, prot,
+ MAP_SHARED | MAP_FIXED, phys_fd,
+ MMAP_OFFSET(offset) };
+
+ res = run_syscall_stub(mm_idp, STUB_MMAP_NR, args);
+ if((void *) res == MAP_FAILED)
+ printk("mmap stub failed, errno = %d\n", res);
+ }
+
+ return 0;
}
-int protect(int fd, unsigned long addr, unsigned long len, int r, int w,
- int x, int must_succeed)
+int unmap(struct mm_id *mm_idp, void *addr, unsigned long len)
{
- 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);
- }
+ int n;
+
+ if(proc_mm){
+ struct proc_mm_op unmap;
+ int fd = mm_idp->u.mm_fd;
+ 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);
+ }
+ }
+ else {
+ int res;
+ unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0,
+ 0 };
+
+ res = run_syscall_stub(mm_idp, __NR_munmap, args);
+ if(res < 0)
+ printk("munmap stub failed, errno = %d\n", res);
+ }
+
+ return(0);
+}
- return(0);
+int protect(struct mm_id *mm_idp, unsigned long addr, unsigned long len,
+ int r, int w, int x)
+{
+ struct proc_mm_op protect;
+ int prot, n;
+
+ prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
+ (x ? PROT_EXEC : 0);
+
+ if(proc_mm){
+ int fd = mm_idp->u.mm_fd;
+ 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))
+ panic("protect failed, err = %d", -n);
+ }
+ else {
+ int res;
+ unsigned long args[] = { addr, len, prot, 0, 0, 0 };
+
+ res = run_syscall_stub(mm_idp, __NR_mprotect, args);
+ if(res < 0)
+ panic("mprotect stub failed, errno = %d\n", res);
+ }
+
+ 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 --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index 6cb9a6d028a..d232daa42c3 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -3,46 +3,143 @@
* Licensed under the GPL
*/
+#include "linux/config.h"
#include "linux/sched.h"
#include "linux/list.h"
#include "linux/spinlock.h"
#include "linux/slab.h"
+#include "linux/errno.h"
+#include "linux/mm.h"
#include "asm/current.h"
#include "asm/segment.h"
#include "asm/mmu.h"
+#include "asm/pgalloc.h"
+#include "asm/pgtable.h"
#include "os.h"
#include "skas.h"
+extern int __syscall_stub_start;
+
+static int init_stub_pte(struct mm_struct *mm, unsigned long proc,
+ unsigned long kernel)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ pte_t *pte;
+
+ spin_lock(&mm->page_table_lock);
+ pgd = pgd_offset(mm, proc);
+ pud = pud_alloc(mm, pgd, proc);
+ if (!pud)
+ goto out;
+
+ pmd = pmd_alloc(mm, pud, proc);
+ if (!pmd)
+ goto out_pmd;
+
+ pte = pte_alloc_map(mm, pmd, proc);
+ if (!pte)
+ goto out_pte;
+
+ /* There's an interaction between the skas0 stub pages, stack
+ * randomization, and the BUG at the end of exit_mmap. exit_mmap
+ * checks that the number of page tables freed is the same as had
+ * been allocated. If the stack is on the last page table page,
+ * then the stack pte page will be freed, and if not, it won't. To
+ * avoid having to know where the stack is, or if the process mapped
+ * something at the top of its address space for some other reason,
+ * we set TASK_SIZE to end at the start of the last page table.
+ * This keeps exit_mmap off the last page, but introduces a leak
+ * of that page. So, we hang onto it here and free it in
+ * destroy_context_skas.
+ */
+
+ mm->context.skas.last_page_table = pmd_page_kernel(*pmd);
+
+ *pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT));
+ *pte = pte_mkexec(*pte);
+ *pte = pte_wrprotect(*pte);
+ spin_unlock(&mm->page_table_lock);
+ return(0);
+
+ out_pmd:
+ pud_free(pud);
+ out_pte:
+ pmd_free(pmd);
+ out:
+ spin_unlock(&mm->page_table_lock);
+ return(-ENOMEM);
+}
+
int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
{
- int from;
+ struct mm_struct *cur_mm = current->mm;
+ struct mm_id *cur_mm_id = &cur_mm->context.skas.id;
+ struct mm_id *mm_id = &mm->context.skas.id;
+ unsigned long stack;
+ int from, ret;
- if((current->mm != NULL) && (current->mm != &init_mm))
- from = current->mm->context.skas.mm_fd;
- else from = -1;
+ if(proc_mm){
+ if((cur_mm != NULL) && (cur_mm != &init_mm))
+ from = cur_mm->context.skas.id.u.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);
+ ret = new_mm(from);
+ if(ret < 0){
+ printk("init_new_context_skas - new_mm failed, "
+ "errno = %d\n", ret);
+ return ret;
+ }
+ mm_id->u.mm_fd = ret;
}
+ else {
+ /* This zeros the entry that pgd_alloc didn't, needed since
+ * we are about to reinitialize it, and want mm.nr_ptes to
+ * be accurate.
+ */
+ mm->pgd[USER_PTRS_PER_PGD] = __pgd(0);
- return(0);
+ ret = init_stub_pte(mm, CONFIG_STUB_CODE,
+ (unsigned long) &__syscall_stub_start);
+ if(ret)
+ goto out;
+
+ ret = -ENOMEM;
+ stack = get_zeroed_page(GFP_KERNEL);
+ if(stack == 0)
+ goto out;
+ mm_id->stack = stack;
+
+ ret = init_stub_pte(mm, CONFIG_STUB_DATA, stack);
+ if(ret)
+ goto out_free;
+
+ mm->nr_ptes--;
+
+ if((cur_mm != NULL) && (cur_mm != &init_mm))
+ mm_id->u.pid = copy_context_skas0(stack,
+ cur_mm_id->u.pid);
+ else mm_id->u.pid = start_userspace(stack);
+ }
+
+ return 0;
+
+ out_free:
+ free_page(mm_id->stack);
+ out:
+ return ret;
}
void destroy_context_skas(struct mm_struct *mm)
{
- os_close_file(mm->context.skas.mm_fd);
-}
+ struct mmu_context_skas *mmu = &mm->context.skas;
-/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
- * Emacs will notice this stuff at the end of the file and automatically
- * adjust the settings for this buffer only. This must remain at the end
- * of the file.
- * ---------------------------------------------------------------------------
- * Local variables:
- * c-file-style: "linux"
- * End:
- */
+ if(proc_mm)
+ os_close_file(mmu->id.u.mm_fd);
+ else {
+ os_kill_ptraced_process(mmu->id.u.pid, 1);
+ free_page(mmu->id.stack);
+ free_page(mmu->last_page_table);
+ }
+}
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index 773cd2b525f..6dd9e5bf18e 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2002 Jeff Dike (jdike@karaya.com)
+ * Copyright (C) 2002- 2004 Jeff Dike (jdike@addtoit.com)
* Licensed under the GPL
*/
@@ -13,7 +13,9 @@
#include <sys/wait.h>
#include <sys/mman.h>
#include <sys/user.h>
+#include <sys/time.h>
#include <asm/unistd.h>
+#include <asm/types.h>
#include "user.h"
#include "ptrace_user.h"
#include "time_user.h"
@@ -21,13 +23,18 @@
#include "user_util.h"
#include "kern_util.h"
#include "skas.h"
+#include "stub-data.h"
+#include "mm_id.h"
#include "sysdep/sigcontext.h"
+#include "sysdep/stub.h"
#include "os.h"
#include "proc_mm.h"
#include "skas_ptrace.h"
#include "chan_user.h"
#include "signal_user.h"
#include "registers.h"
+#include "mem.h"
+#include "uml-config.h"
#include "process.h"
int is_skas_winch(int pid, int fd, void *data)
@@ -39,20 +46,55 @@ int is_skas_winch(int pid, int fd, void *data)
return(1);
}
-void get_skas_faultinfo(int pid, struct faultinfo * fi)
+void wait_stub_done(int pid, int sig, char * fname)
{
- int err;
-
- err = ptrace(PTRACE_FAULTINFO, pid, 0, fi);
- if(err)
- panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, "
- "errno = %d\n", errno);
+ int n, status, err;
+
+ do {
+ if ( sig != -1 ) {
+ err = ptrace(PTRACE_CONT, pid, 0, sig);
+ if(err)
+ panic("%s : continue failed, errno = %d\n",
+ fname, errno);
+ }
+ sig = 0;
+
+ CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
+ } while((n >= 0) && WIFSTOPPED(status) &&
+ (WSTOPSIG(status) == SIGVTALRM));
+
+ if((n < 0) || !WIFSTOPPED(status) ||
+ (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status) != SIGTRAP)){
+ panic("%s : failed to wait for SIGUSR1/SIGTRAP, "
+ "pid = %d, n = %d, errno = %d, status = 0x%x\n",
+ fname, pid, n, errno, status);
+ }
+}
- /* Special handling for i386, which has different structs */
- if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo))
- memset((char *)fi + sizeof(struct ptrace_faultinfo), 0,
- sizeof(struct faultinfo) -
- sizeof(struct ptrace_faultinfo));
+void get_skas_faultinfo(int pid, struct faultinfo * fi)
+{
+ int err;
+
+ if(ptrace_faultinfo){
+ err = ptrace(PTRACE_FAULTINFO, pid, 0, fi);
+ if(err)
+ panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, "
+ "errno = %d\n", errno);
+
+ /* Special handling for i386, which has different structs */
+ if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo))
+ memset((char *)fi + sizeof(struct ptrace_faultinfo), 0,
+ sizeof(struct faultinfo) -
+ sizeof(struct ptrace_faultinfo));
+ }
+ else {
+ wait_stub_done(pid, SIGSEGV, "get_skas_faultinfo");
+
+ /* faultinfo is prepared by the stub-segv-handler at start of
+ * the stub stack page. We just have to copy it.
+ */
+ memcpy(fi, (void *)current_stub_stack(), sizeof(*fi));
+ }
}
static void handle_segv(int pid, union uml_pt_regs * regs)
@@ -91,11 +133,56 @@ static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu
handle_syscall(regs);
}
-static int userspace_tramp(void *arg)
+extern int __syscall_stub_start;
+
+static int userspace_tramp(void *stack)
{
- init_new_thread_signals(0);
- enable_timer();
+ void *addr;
+
ptrace(PTRACE_TRACEME, 0, 0, 0);
+
+ init_new_thread_signals(1);
+ enable_timer();
+
+ if(!proc_mm){
+ /* This has a pte, but it can't be mapped in with the usual
+ * tlb_flush mechanism because this is part of that mechanism
+ */
+ int fd;
+ __u64 offset;
+
+ fd = phys_mapping(to_phys(&__syscall_stub_start), &offset);
+ addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(),
+ PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
+ if(addr == MAP_FAILED){
+ printk("mapping mmap stub failed, errno = %d\n",
+ errno);
+ exit(1);
+ }
+
+ if(stack != NULL){
+ fd = phys_mapping(to_phys(stack), &offset);
+ addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(),
+ PROT_READ | PROT_WRITE,
+ MAP_FIXED | MAP_SHARED, fd, offset);
+ if(addr == MAP_FAILED){
+ printk("mapping segfault stack failed, "
+ "errno = %d\n", errno);
+ exit(1);
+ }
+ }
+ }
+ if(!ptrace_faultinfo && (stack != NULL)){
+ unsigned long v = UML_CONFIG_STUB_CODE +
+ (unsigned long) stub_segv_handler -
+ (unsigned long) &__syscall_stub_start;
+
+ set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size());
+ set_handler(SIGSEGV, (void *) v, SA_ONSTACK,
+ SIGIO, SIGWINCH, SIGALRM, SIGVTALRM,
+ SIGUSR1, -1);
+ }
+
os_stop_process(os_getpid());
return(0);
}
@@ -105,11 +192,11 @@ static int userspace_tramp(void *arg)
#define NR_CPUS 1
int userspace_pid[NR_CPUS];
-void start_userspace(int cpu)
+int start_userspace(unsigned long stub_stack)
{
void *stack;
unsigned long sp;
- int pid, status, n;
+ int pid, status, n, flags;
stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
@@ -117,8 +204,9 @@ void start_userspace(int cpu)
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);
+ flags = CLONE_FILES | SIGCHLD;
+ if(proc_mm) flags |= CLONE_VM;
+ pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack);
if(pid < 0)
panic("start_userspace : clone failed, errno = %d", errno);
@@ -140,7 +228,7 @@ void start_userspace(int cpu)
if(munmap(stack, PAGE_SIZE) < 0)
panic("start_userspace : munmap failed, errno = %d\n", errno);
- userspace_pid[cpu] = pid;
+ return(pid);
}
void userspace(union uml_pt_regs *regs)
@@ -174,7 +262,9 @@ void userspace(union uml_pt_regs *regs)
if(WIFSTOPPED(status)){
switch(WSTOPSIG(status)){
case SIGSEGV:
- handle_segv(pid, regs);
+ if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo)
+ user_signal(SIGSEGV, regs, pid);
+ else handle_segv(pid, regs);
break;
case SIGTRAP + 0x80:
handle_trap(pid, regs, local_using_sysemu);
@@ -194,6 +284,7 @@ void userspace(union uml_pt_regs *regs)
printk("userspace - child stopped with signal "
"%d\n", WSTOPSIG(status));
}
+ pid = userspace_pid[0];
interrupt_end();
/* Avoid -ERESTARTSYS handling in host */
@@ -207,6 +298,67 @@ void userspace(union uml_pt_regs *regs)
#define INIT_JMP_HALT 3
#define INIT_JMP_REBOOT 4
+
+int copy_context_skas0(unsigned long new_stack, int pid)
+{
+ int err;
+ unsigned long regs[MAX_REG_NR];
+ unsigned long current_stack = current_stub_stack();
+ struct stub_data *data = (struct stub_data *) current_stack;
+ struct stub_data *child_data = (struct stub_data *) new_stack;
+ __u64 new_offset;
+ int new_fd = phys_mapping(to_phys((void *)new_stack), &new_offset);
+
+ /* prepare offset and fd of child's stack as argument for parent's
+ * and child's mmap2 calls
+ */
+ *data = ((struct stub_data) { .offset = MMAP_OFFSET(new_offset),
+ .fd = new_fd,
+ .timer = ((struct itimerval)
+ { { 0, 1000000 / hz() },
+ { 0, 1000000 / hz() }})});
+ get_safe_registers(regs);
+
+ /* Set parent's instruction pointer to start of clone-stub */
+ regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
+ (unsigned long) stub_clone_handler -
+ (unsigned long) &__syscall_stub_start;
+ regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE -
+ sizeof(void *);
+ err = ptrace_setregs(pid, regs);
+ if(err < 0)
+ panic("copy_context_skas0 : PTRACE_SETREGS failed, "
+ "pid = %d, errno = %d\n", pid, errno);
+
+ /* set a well known return code for detection of child write failure */
+ child_data->err = 12345678;
+
+ /* Wait, until parent has finished its work: read child's pid from
+ * parent's stack, and check, if bad result.
+ */
+ wait_stub_done(pid, 0, "copy_context_skas0");
+
+ pid = data->err;
+ if(pid < 0)
+ panic("copy_context_skas0 - stub-parent reports error %d\n",
+ pid);
+
+ /* Wait, until child has finished too: read child's result from
+ * child's stack and check it.
+ */
+ wait_stub_done(pid, -1, "copy_context_skas0");
+ if (child_data->err != UML_CONFIG_STUB_DATA)
+ panic("copy_context_skas0 - stub-child reports error %d\n",
+ child_data->err);
+
+ if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
+ (void *)PTRACE_O_TRACESYSGOOD) < 0)
+ panic("copy_context_skas0 : PTRACE_SETOPTIONS failed, "
+ "errno = %d\n", errno);
+
+ return pid;
+}
+
void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
void (*handler)(int))
{
@@ -334,21 +486,19 @@ void reboot_skas(void)
siglongjmp(initial_jmpbuf, INIT_JMP_REBOOT);
}
-void switch_mm_skas(int mm_fd)
+void switch_mm_skas(struct mm_id *mm_idp)
{
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_ptraced_process(userspace_pid[0], 1);
+ if(proc_mm){
+ err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0,
+ mm_idp->u.mm_fd);
+ if(err)
+ panic("switch_mm_skas - PTRACE_SWITCH_MM failed, "
+ "errno = %d\n", errno);
+ }
+ else userspace_pid[0] = mm_idp->u.pid;
}
/*
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c
index fc71ef29578..cbabab104ac 100644
--- a/arch/um/kernel/skas/process_kern.c
+++ b/arch/um/kernel/skas/process_kern.c
@@ -111,8 +111,7 @@ int copy_thread_skas(int nr, unsigned long clone_flags, unsigned long sp,
void (*handler)(int);
if(current->thread.forking){
- memcpy(&p->thread.regs.regs.skas,
- &current->thread.regs.regs.skas,
+ memcpy(&p->thread.regs.regs.skas, &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;
@@ -176,12 +175,14 @@ static int start_kernel_proc(void *unused)
return(0);
}
+extern int userspace_pid[];
+
int start_uml_skas(void)
{
- start_userspace(0);
+ if(proc_mm)
+ userspace_pid[0] = start_userspace(0);
init_new_thread_signals(1);
- uml_idle_timer();
init_task.thread.request.u.thread.proc = start_kernel_proc;
init_task.thread.request.u.thread.arg = NULL;
@@ -202,13 +203,30 @@ int thread_pid_skas(struct task_struct *task)
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:
- */
+void kill_off_processes_skas(void)
+{
+ if(proc_mm)
+#warning need to loop over userspace_pids in kill_off_processes_skas
+ os_kill_ptraced_process(userspace_pid[0], 1);
+ else {
+ struct task_struct *p;
+ int pid, me;
+
+ me = os_getpid();
+ for_each_process(p){
+ if(p->mm == NULL)
+ continue;
+
+ pid = p->mm->context.skas.id.u.pid;
+ os_kill_ptraced_process(pid, 1);
+ }
+ }
+}
+
+unsigned long current_stub_stack(void)
+{
+ if(current->mm == NULL)
+ return(0);
+
+ return(current->mm->context.skas.id.stack);
+}
diff --git a/arch/um/kernel/skas/syscall_user.c b/arch/um/kernel/skas/syscall_user.c
index 2828e6e3772..6b066497014 100644
--- a/arch/um/kernel/skas/syscall_user.c
+++ b/arch/um/kernel/skas/syscall_user.c
@@ -15,7 +15,7 @@
void handle_syscall(union uml_pt_regs *regs)
{
long result;
-#if UML_CONFIG_SYSCALL_DEBUG
+#ifdef UML_CONFIG_SYSCALL_DEBUG
int index;
index = record_syscall_start(UPT_SYSCALL_NR(regs));
@@ -27,7 +27,7 @@ void handle_syscall(union uml_pt_regs *regs)
REGS_SET_SYSCALL_RETURN(regs->skas.regs, result);
syscall_trace(regs, 1);
-#if UML_CONFIG_SYSCALL_DEBUG
+#ifdef UML_CONFIG_SYSCALL_DEBUG
record_syscall_end(index, result);
#endif
}
diff --git a/arch/um/kernel/skas/time.c b/arch/um/kernel/skas/time.c
deleted file mode 100644
index 98091494b89..00000000000
--- a/arch/um/kernel/skas/time.c
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * 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 --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c
index b8c5e71763d..6230999c672 100644
--- a/arch/um/kernel/skas/tlb.c
+++ b/arch/um/kernel/skas/tlb.c
@@ -6,6 +6,7 @@
#include "linux/stddef.h"
#include "linux/sched.h"
+#include "linux/config.h"
#include "linux/mm.h"
#include "asm/page.h"
#include "asm/pgtable.h"
@@ -17,7 +18,7 @@
#include "os.h"
#include "tlb.h"
-static void do_ops(int fd, struct host_vm_op *ops, int last)
+static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last)
{
struct host_vm_op *op;
int i;
@@ -26,18 +27,18 @@ static void do_ops(int fd, struct host_vm_op *ops, int last)
op = &ops[i];
switch(op->type){
case MMAP:
- map(fd, op->u.mmap.addr, op->u.mmap.len,
+ map(&mmu->skas.id, op->u.mmap.addr, op->u.mmap.len,
op->u.mmap.r, op->u.mmap.w, op->u.mmap.x,
op->u.mmap.fd, op->u.mmap.offset);
break;
case MUNMAP:
- unmap(fd, (void *) op->u.munmap.addr,
+ unmap(&mmu->skas.id, (void *) op->u.munmap.addr,
op->u.munmap.len);
break;
case MPROTECT:
- protect(fd, op->u.mprotect.addr, op->u.mprotect.len,
- op->u.mprotect.r, op->u.mprotect.w,
- op->u.mprotect.x);
+ protect(&mmu->skas.id, op->u.mprotect.addr,
+ op->u.mprotect.len, op->u.mprotect.r,
+ op->u.mprotect.w, op->u.mprotect.x);
break;
default:
printk("Unknown op type %d in do_ops\n", op->type);
@@ -46,12 +47,15 @@ static void do_ops(int fd, struct host_vm_op *ops, int last)
}
}
+extern int proc_mm;
+
static void fix_range(struct mm_struct *mm, unsigned long start_addr,
unsigned long end_addr, int force)
{
- int fd = mm->context.skas.mm_fd;
+ if(!proc_mm && (end_addr > CONFIG_STUB_START))
+ end_addr = CONFIG_STUB_START;
- fix_range_common(mm, start_addr, end_addr, force, fd, do_ops);
+ fix_range_common(mm, start_addr, end_addr, force, do_ops);
}
void __flush_tlb_one_skas(unsigned long addr)
@@ -69,17 +73,20 @@ void flush_tlb_range_skas(struct vm_area_struct *vma, unsigned long start,
void flush_tlb_mm_skas(struct mm_struct *mm)
{
+ unsigned long end;
+
/* Don't bother flushing if this address space is about to be
* destroyed.
*/
if(atomic_read(&mm->mm_users) == 0)
return;
- fix_range(mm, 0, host_task_size, 0);
- flush_tlb_kernel_range_common(start_vm, end_vm);
+ end = proc_mm ? task_size : CONFIG_STUB_START;
+ fix_range(mm, 0, end, 0);
}
void force_flush_all_skas(void)
{
- fix_range(current->mm, 0, host_task_size, 1);
+ unsigned long end = proc_mm ? task_size : CONFIG_STUB_START;
+ fix_range(current->mm, 0, end, 1);
}
diff --git a/arch/um/kernel/skas/trap_user.c b/arch/um/kernel/skas/trap_user.c
index 0dee1d95c80..9950a6716fe 100644
--- a/arch/um/kernel/skas/trap_user.c
+++ b/arch/um/kernel/skas/trap_user.c
@@ -58,7 +58,6 @@ void user_signal(int sig, union uml_pt_regs *regs, int pid)
int segv = ((sig == SIGFPE) || (sig == SIGSEGV) || (sig == SIGBUS) ||
(sig == SIGILL) || (sig == SIGTRAP));
- regs->skas.is_user = 1;
if (segv)
get_skas_faultinfo(pid, &regs->skas.faultinfo);
info = &sig_info[sig];
diff --git a/arch/um/kernel/syscall_kern.c b/arch/um/kernel/syscall_kern.c
index b7a55251e89..8e1a3501ff4 100644
--- a/arch/um/kernel/syscall_kern.c
+++ b/arch/um/kernel/syscall_kern.c
@@ -31,7 +31,8 @@ long sys_fork(void)
long ret;
current->thread.forking = 1;
- ret = do_fork(SIGCHLD, 0, NULL, 0, NULL, NULL);
+ ret = do_fork(SIGCHLD, UPT_SP(&current->thread.regs.regs),
+ &current->thread.regs, 0, NULL, NULL);
current->thread.forking = 0;
return(ret);
}
@@ -41,8 +42,9 @@ long sys_vfork(void)
long ret;
current->thread.forking = 1;
- ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD, 0, NULL, 0, NULL,
- NULL);
+ ret = do_fork(CLONE_VFORK | CLONE_VM | SIGCHLD,
+ UPT_SP(&current->thread.regs.regs),
+ &current->thread.regs, 0, NULL, NULL);
current->thread.forking = 0;
return(ret);
}
@@ -162,14 +164,3 @@ int next_syscall_index(int limit)
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 --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index c40c86a3f91..c40b611e3d9 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -33,7 +33,7 @@ void timer(void)
timeradd(&xtime, &local_offset, &xtime);
}
-void set_interval(int timer_type)
+static void set_interval(int timer_type)
{
int usec = 1000000/hz();
struct itimerval interval = ((struct itimerval) { { 0, usec },
@@ -45,12 +45,14 @@ void set_interval(int timer_type)
void enable_timer(void)
{
+ set_interval(ITIMER_VIRTUAL);
+}
+
+void prepare_timer(void * ptr)
+{
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);
+ *(struct itimerval *)ptr = ((struct itimerval) { { 0, usec },
+ { 0, usec }});
}
void disable_timer(void)
@@ -155,13 +157,15 @@ void idle_sleep(int secs)
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:
- */
+/* XXX This partly duplicates init_irq_signals */
+
+void user_time_init(void)
+{
+ set_handler(SIGVTALRM, (__sighandler_t) alarm_handler,
+ SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH,
+ SIGALRM, SIGUSR2, -1);
+ set_handler(SIGALRM, (__sighandler_t) alarm_handler,
+ SA_ONSTACK | SA_RESTART, SIGUSR1, SIGIO, SIGWINCH,
+ SIGVTALRM, SIGUSR2, -1);
+ set_interval(ITIMER_VIRTUAL);
+}
diff --git a/arch/um/kernel/time_kern.c b/arch/um/kernel/time_kern.c
index 6516fc52afe..4e08f7545d6 100644
--- a/arch/um/kernel/time_kern.c
+++ b/arch/um/kernel/time_kern.c
@@ -137,7 +137,10 @@ long um_stime(int __user *tptr)
void timer_handler(int sig, union uml_pt_regs *regs)
{
local_irq_disable();
- update_process_times(CHOOSE_MODE(user_context(UPT_SP(regs)), (regs)->skas.is_user));
+ irq_enter();
+ update_process_times(CHOOSE_MODE(user_context(UPT_SP(regs)),
+ (regs)->skas.is_user));
+ irq_exit();
local_irq_enable();
if(current_thread->cpu == 0)
timer_irq(regs);
@@ -162,7 +165,7 @@ int __init timer_init(void)
{
int err;
- CHOOSE_MODE(user_time_init_tt(), user_time_init_skas());
+ user_time_init();
err = request_irq(TIMER_IRQ, um_timer, SA_INTERRUPT, "timer", NULL);
if(err != 0)
printk(KERN_ERR "timer_init : request_irq failed - "
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
index eda477edfdf..83ec8d4747f 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -18,13 +18,15 @@
#define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1))
void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
- unsigned long end_addr, int force, int data,
- void (*do_ops)(int, struct host_vm_op *, int))
+ unsigned long end_addr, int force,
+ void (*do_ops)(union mm_context *, struct host_vm_op *,
+ int))
{
pgd_t *npgd;
pud_t *npud;
pmd_t *npmd;
pte_t *npte;
+ union mm_context *mmu = &mm->context;
unsigned long addr, end;
int r, w, x;
struct host_vm_op ops[16];
@@ -40,7 +42,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
end = end_addr;
if(force || pgd_newpage(*npgd)){
op_index = add_munmap(addr, end - addr, ops,
- op_index, last_op, data,
+ op_index, last_op, mmu,
do_ops);
pgd_mkuptodate(*npgd);
}
@@ -55,7 +57,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
end = end_addr;
if(force || pud_newpage(*npud)){
op_index = add_munmap(addr, end - addr, ops,
- op_index, last_op, data,
+ op_index, last_op, mmu,
do_ops);
pud_mkuptodate(*npud);
}
@@ -70,7 +72,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
end = end_addr;
if(force || pmd_newpage(*npmd)){
op_index = add_munmap(addr, end - addr, ops,
- op_index, last_op, data,
+ op_index, last_op, mmu,
do_ops);
pmd_mkuptodate(*npmd);
}
@@ -93,21 +95,21 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
op_index = add_mmap(addr,
pte_val(*npte) & PAGE_MASK,
PAGE_SIZE, r, w, x, ops,
- op_index, last_op, data,
+ op_index, last_op, mmu,
do_ops);
else op_index = add_munmap(addr, PAGE_SIZE, ops,
- op_index, last_op, data,
+ op_index, last_op, mmu,
do_ops);
}
else if(pte_newprot(*npte))
op_index = add_mprotect(addr, PAGE_SIZE, r, w, x, ops,
- op_index, last_op, data,
+ op_index, last_op, mmu,
do_ops);
*npte = pte_mkuptodate(*npte);
addr += PAGE_SIZE;
}
- (*do_ops)(data, ops, op_index);
+ (*do_ops)(mmu, ops, op_index);
}
int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
@@ -195,51 +197,6 @@ int flush_tlb_kernel_range_common(unsigned long start, unsigned long end)
return(updated);
}
-void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
-{
- address &= PAGE_MASK;
- flush_tlb_range(vma, address, address + PAGE_SIZE);
-}
-
-void flush_tlb_all(void)
-{
- flush_tlb_mm(current->mm);
-}
-
-void flush_tlb_kernel_range(unsigned long start, unsigned long end)
-{
- CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt,
- flush_tlb_kernel_range_common, start, end);
-}
-
-void flush_tlb_kernel_vm(void)
-{
- CHOOSE_MODE(flush_tlb_kernel_vm_tt(),
- flush_tlb_kernel_range_common(start_vm, end_vm));
-}
-
-void __flush_tlb_one(unsigned long addr)
-{
- CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
-}
-
-void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
- unsigned long end)
-{
- CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, 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));
@@ -270,9 +227,9 @@ pte_t *addr_pte(struct task_struct *task, unsigned long addr)
}
int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
- int r, int w, int x, struct host_vm_op *ops, int index,
- int last_filled, int data,
- void (*do_ops)(int, struct host_vm_op *, int))
+ int r, int w, int x, struct host_vm_op *ops, int index,
+ int last_filled, union mm_context *mmu,
+ void (*do_ops)(union mm_context *, struct host_vm_op *, int))
{
__u64 offset;
struct host_vm_op *last;
@@ -292,7 +249,7 @@ int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
}
if(index == last_filled){
- (*do_ops)(data, ops, last_filled);
+ (*do_ops)(mmu, ops, last_filled);
index = -1;
}
@@ -310,8 +267,8 @@ int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
}
int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
- int index, int last_filled, int data,
- void (*do_ops)(int, struct host_vm_op *, int))
+ int index, int last_filled, union mm_context *mmu,
+ void (*do_ops)(union mm_context *, struct host_vm_op *, int))
{
struct host_vm_op *last;
@@ -325,7 +282,7 @@ int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
}
if(index == last_filled){
- (*do_ops)(data, ops, last_filled);
+ (*do_ops)(mmu, ops, last_filled);
index = -1;
}
@@ -337,8 +294,9 @@ int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
}
int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
- struct host_vm_op *ops, int index, int last_filled, int data,
- void (*do_ops)(int, struct host_vm_op *, int))
+ struct host_vm_op *ops, int index, int last_filled,
+ union mm_context *mmu,
+ void (*do_ops)(union mm_context *, struct host_vm_op *, int))
{
struct host_vm_op *last;
@@ -354,7 +312,7 @@ int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
}
if(index == last_filled){
- (*do_ops)(data, ops, last_filled);
+ (*do_ops)(mmu, ops, last_filled);
index = -1;
}
@@ -367,3 +325,49 @@ int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
.x = x } } });
return(index);
}
+
+void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
+{
+ address &= PAGE_MASK;
+ flush_tlb_range(vma, address, address + PAGE_SIZE);
+}
+
+void flush_tlb_all(void)
+{
+ flush_tlb_mm(current->mm);
+}
+
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+ CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt,
+ flush_tlb_kernel_range_common, start, end);
+}
+
+void flush_tlb_kernel_vm(void)
+{
+ CHOOSE_MODE(flush_tlb_kernel_vm_tt(),
+ flush_tlb_kernel_range_common(start_vm, end_vm));
+}
+
+void __flush_tlb_one(unsigned long addr)
+{
+ CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
+}
+
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end)
+{
+ CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, 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());
+}
+
diff --git a/arch/um/kernel/tt/Makefile b/arch/um/kernel/tt/Makefile
index c3faea21a99..6939e5af847 100644
--- a/arch/um/kernel/tt/Makefile
+++ b/arch/um/kernel/tt/Makefile
@@ -3,27 +3,12 @@
# Licensed under the GPL
#
-extra-y := unmap_fin.o
-targets := unmap.o
-clean-files := unmap_tmp.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 \
+ syscall_kern.o syscall_user.o tlb.o tracer.o trap_user.o \
uaccess.o uaccess_user.o
obj-$(CONFIG_PT_PROXY) += gdb_kern.o ptproxy/
-USER_OBJS := gdb.o time.o tracer.o
+USER_OBJS := gdb.o tracer.o
include arch/um/scripts/Makefile.rules
-
-UNMAP_CFLAGS := $(patsubst -pg -DPROFILING,,$(USER_CFLAGS))
-UNMAP_CFLAGS := $(patsubst -fprofile-arcs -ftest-coverage,,$(UNMAP_CFLAGS))
-
-#XXX: partially copied from arch/um/scripts/Makefile.rules
-$(obj)/unmap.o: c_flags = -Wp,-MD,$(depfile) $(UNMAP_CFLAGS)
-
-$(obj)/unmap_fin.o : $(obj)/unmap.o
- $(LD) -r -o $(obj)/unmap_tmp.o $< $(shell $(CC) -print-file-name=libc.a)
- $(OBJCOPY) $(obj)/unmap_tmp.o $@ -G switcheroo
-
diff --git a/arch/um/kernel/tt/gdb.c b/arch/um/kernel/tt/gdb.c
index 19a0ad7b35b..37e22d71a0d 100644
--- a/arch/um/kernel/tt/gdb.c
+++ b/arch/um/kernel/tt/gdb.c
@@ -153,10 +153,10 @@ void remove_gdb_cb(void *unused)
exit_debugger_cb(NULL);
}
-int gdb_remove(char *unused)
+int gdb_remove(int unused)
{
initial_thread_cb(remove_gdb_cb, NULL);
- return(0);
+ return 0;
}
void signal_usr1(int sig)
diff --git a/arch/um/kernel/tt/gdb_kern.c b/arch/um/kernel/tt/gdb_kern.c
index 93fb121f86a..26506388a6a 100644
--- a/arch/um/kernel/tt/gdb_kern.c
+++ b/arch/um/kernel/tt/gdb_kern.c
@@ -10,7 +10,7 @@
#ifdef CONFIG_MCONSOLE
extern int gdb_config(char *str);
-extern int gdb_remove(char *unused);
+extern int gdb_remove(int n);
static struct mc_device gdb_mc = {
.name = "gdb",
diff --git a/arch/um/kernel/tt/include/debug.h b/arch/um/kernel/tt/include/debug.h
index 8eff674107c..738435461e1 100644
--- a/arch/um/kernel/tt/include/debug.h
+++ b/arch/um/kernel/tt/include/debug.h
@@ -4,8 +4,8 @@
* Licensed under the GPL
*/
-#ifndef __DEBUG_H
-#define __DEBUG_H
+#ifndef __UML_TT_DEBUG_H
+#define __UML_TT_DEBUG_H
extern int debugger_proxy(int status, pid_t pid);
extern void child_proxy(pid_t pid, int status);
@@ -13,17 +13,6 @@ 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);
+extern int gdb_remove(int 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 --git a/arch/um/kernel/tt/include/mode-tt.h b/arch/um/kernel/tt/include/mode-tt.h
index efe46201906..e171e15fead 100644
--- a/arch/um/kernel/tt/include/mode-tt.h
+++ b/arch/um/kernel/tt/include/mode-tt.h
@@ -13,7 +13,6 @@ 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 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);
diff --git a/arch/um/kernel/tt/process_kern.c b/arch/um/kernel/tt/process_kern.c
index 776310fd5b8..a189a2b9293 100644
--- a/arch/um/kernel/tt/process_kern.c
+++ b/arch/um/kernel/tt/process_kern.c
@@ -266,10 +266,10 @@ int copy_thread_tt(int nr, unsigned long clone_flags, unsigned long sp,
}
if(current->thread.forking){
- sc_to_sc(UPT_SC(&p->thread.regs.regs),
- UPT_SC(&current->thread.regs.regs));
+ sc_to_sc(UPT_SC(&p->thread.regs.regs), UPT_SC(&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;
+ if(sp != 0)
+ SC_SP(UPT_SC(&p->thread.regs.regs)) = sp;
}
p->thread.mode.tt.extern_pid = new_pid;
@@ -459,14 +459,3 @@ int is_valid_pid(int pid)
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 --git a/arch/um/kernel/tt/time.c b/arch/um/kernel/tt/time.c
deleted file mode 100644
index 8565b71b07c..00000000000
--- a/arch/um/kernel/tt/time.c
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- * 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 --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c
index 203216ad86f..2eefb43bc9c 100644
--- a/arch/um/kernel/tt/tlb.c
+++ b/arch/um/kernel/tt/tlb.c
@@ -17,7 +17,7 @@
#include "os.h"
#include "tlb.h"
-static void do_ops(int unused, struct host_vm_op *ops, int last)
+static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last)
{
struct host_vm_op *op;
int i;
@@ -55,7 +55,7 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr,
panic("fix_range fixing wrong address space, current = 0x%p",
current);
- fix_range_common(mm, start_addr, end_addr, force, 0, do_ops);
+ fix_range_common(mm, start_addr, end_addr, force, do_ops);
}
atomic_t vmchange_seq = ATOMIC_INIT(1);
diff --git a/arch/um/kernel/tt/unmap.c b/arch/um/kernel/tt/unmap.c
deleted file mode 100644
index 3f7aecdbe53..00000000000
--- a/arch/um/kernel/tt/unmap.c
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * 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 --git a/arch/um/kernel/um_arch.c b/arch/um/kernel/um_arch.c
index 8736d098f0e..ca2bb6f09a7 100644
--- a/arch/um/kernel/um_arch.c
+++ b/arch/um/kernel/um_arch.c
@@ -38,6 +38,9 @@
#include "choose-mode.h"
#include "mode_kern.h"
#include "mode.h"
+#ifdef UML_CONFIG_MODE_SKAS
+#include "skas.h"
+#endif
#define DEFAULT_COMMAND_LINE "root=98:0"
@@ -318,6 +321,7 @@ int linux_main(int argc, char **argv)
unsigned long avail, diff;
unsigned long virtmem_size, max_physmem;
unsigned int i, add;
+ char * mode;
for (i = 1; i < argc; i++){
if((i == 1) && (argv[i][0] == ' ')) continue;
@@ -338,6 +342,21 @@ int linux_main(int argc, char **argv)
exit(1);
}
#endif
+
+#ifndef CONFIG_MODE_SKAS
+ mode = "TT";
+#else
+ /* Show to the user the result of selection */
+ if (mode_tt)
+ mode = "TT";
+ else if (proc_mm && ptrace_faultinfo)
+ mode = "SKAS3";
+ else
+ mode = "SKAS0";
+#endif
+
+ printf("UML running in %s mode\n", mode);
+
uml_start = CHOOSE_MODE_PROC(set_task_sizes_tt, set_task_sizes_skas, 0,
&host_task_size, &task_size);
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
index dd5355500bd..b03326d391c 100644
--- a/arch/um/kernel/uml.lds.S
+++ b/arch/um/kernel/uml.lds.S
@@ -14,19 +14,10 @@ SECTIONS
/* Used in arch/um/kernel/mem.c. Any memory between START and __binary_start
* is remapped.*/
__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) }
- /* We want it only if we are in MODE_TT. In both cases, however, when MODE_TT
- * is off the resulting binary segfaults.*/
+#ifdef MODE_TT
+ .remap_data : { UNMAP_PATH (.data .bss) }
+ .remap : { UNMAP_PATH (.text) }
. = ALIGN(4096); /* Init code and data */
#endif
@@ -39,6 +30,7 @@ SECTIONS
_einittext = .;
}
. = ALIGN(4096);
+
.text :
{
*(.text)
@@ -48,6 +40,12 @@ SECTIONS
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.gnu.linkonce.t*)
+
+ . = ALIGN(4096);
+ __syscall_stub_start = .;
+ *(.__syscall_stub*)
+ __syscall_stub_end = .;
+ . = ALIGN(4096);
}
#include "asm/common.lds.S"
diff --git a/arch/um/os-Linux/elf_aux.c b/arch/um/os-Linux/elf_aux.c
index f0d6060e3e5..9416e1c2992 100644
--- a/arch/um/os-Linux/elf_aux.c
+++ b/arch/um/os-Linux/elf_aux.c
@@ -9,8 +9,10 @@
*/
#include <elf.h>
#include <stddef.h>
+#include <asm/elf.h>
#include "init.h"
#include "elf_user.h"
+#include "mem_user.h"
#if ELF_CLASS == ELFCLASS32
typedef Elf32_auxv_t elf_auxv_t;
@@ -40,6 +42,9 @@ __init void scan_elf_aux( char **envp)
break;
case AT_SYSINFO_EHDR:
vsyscall_ehdr = auxv->a_un.a_val;
+ /* See if the page is under TASK_SIZE */
+ if (vsyscall_ehdr < (unsigned long) envp)
+ vsyscall_ehdr = 0;
break;
case AT_HWCAP:
elf_aux_hwcap = auxv->a_un.a_val;
diff --git a/arch/um/os-Linux/sys-i386/registers.c b/arch/um/os-Linux/sys-i386/registers.c
index 9a0ad094d92..3125d320722 100644
--- a/arch/um/os-Linux/sys-i386/registers.c
+++ b/arch/um/os-Linux/sys-i386/registers.c
@@ -121,6 +121,11 @@ void init_registers(int pid)
err);
}
+void get_safe_registers(unsigned long *regs)
+{
+ memcpy(regs, exec_regs, HOST_FRAME_SIZE * sizeof(unsigned long));
+}
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/os-Linux/sys-x86_64/registers.c b/arch/um/os-Linux/sys-x86_64/registers.c
index 6286c974bbe..44438d15c3d 100644
--- a/arch/um/os-Linux/sys-x86_64/registers.c
+++ b/arch/um/os-Linux/sys-x86_64/registers.c
@@ -69,6 +69,11 @@ void init_registers(int pid)
err);
}
+void get_safe_registers(unsigned long *regs)
+{
+ memcpy(regs, exec_regs, HOST_FRAME_SIZE * sizeof(unsigned long));
+}
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/os-Linux/user_syms.c b/arch/um/os-Linux/user_syms.c
index 75d7af9ae1d..56d3f870926 100644
--- a/arch/um/os-Linux/user_syms.c
+++ b/arch/um/os-Linux/user_syms.c
@@ -83,6 +83,9 @@ EXPORT_SYMBOL_PROTO(statfs64);
EXPORT_SYMBOL_PROTO(getuid);
+EXPORT_SYMBOL_PROTO(fsync);
+EXPORT_SYMBOL_PROTO(fdatasync);
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
diff --git a/arch/um/scripts/Makefile.rules b/arch/um/scripts/Makefile.rules
index 98346c71149..17f305b6bad 100644
--- a/arch/um/scripts/Makefile.rules
+++ b/arch/um/scripts/Makefile.rules
@@ -10,6 +10,17 @@ USER_OBJS := $(foreach file,$(USER_OBJS),$(obj)/$(file))
$(USER_OBJS) : c_flags = -Wp,-MD,$(depfile) $(USER_CFLAGS) \
$(CFLAGS_$(notdir $@))
+# The stubs and unmap.o can't try to call mcount or update basic block data
+define unprofile
+ $(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1)))
+endef
+
+
+# The stubs and unmap.o can't try to call mcount or update basic block data
+define unprofile
+ $(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1)))
+endef
+
quiet_cmd_make_link = SYMLINK $@
cmd_make_link = ln -sf $(srctree)/arch/$(SUBARCH)/$($(notdir $@)-dir)/$(notdir $@) $@
diff --git a/arch/um/scripts/Makefile.unmap b/arch/um/scripts/Makefile.unmap
new file mode 100644
index 00000000000..802d027a1e1
--- /dev/null
+++ b/arch/um/scripts/Makefile.unmap
@@ -0,0 +1,22 @@
+clean-files += unmap_tmp.o unmap_fin.o unmap.o
+
+ifdef CONFIG_MODE_TT
+
+#Always build unmap_fin.o
+extra-y += unmap_fin.o
+#Do dependency tracking for unmap.o (it will be always built, but won't get the tracking unless we use this).
+targets += unmap.o
+
+#XXX: partially copied from arch/um/scripts/Makefile.rules
+$(obj)/unmap.o: _c_flags = $(call unprofile,$(CFLAGS))
+
+quiet_cmd_wrapld = LD $@
+define cmd_wrapld
+ $(LD) $(LDFLAGS) -r -o $(obj)/unmap_tmp.o $< $(shell $(CC) $(CFLAGS) -print-file-name=libc.a); \
+ $(OBJCOPY) $(UML_OBJCOPYFLAGS) $(obj)/unmap_tmp.o $@ -G switcheroo
+endef
+
+$(obj)/unmap_fin.o : $(obj)/unmap.o FORCE
+ $(call if_changed,wrapld)
+
+endif
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
index 4351e560550..77c3c4d29f5 100644
--- a/arch/um/sys-i386/Makefile
+++ b/arch/um/sys-i386/Makefile
@@ -1,6 +1,6 @@
obj-y = bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
- ptrace_user.o semaphore.o signal.o sigcontext.o syscalls.o sysrq.o \
- sys_call_table.o
+ ptrace_user.o semaphore.o signal.o sigcontext.o stub.o stub_segv.o \
+ syscalls.o sysrq.o sys_call_table.o
obj-$(CONFIG_HIGHMEM) += highmem.o
obj-$(CONFIG_MODULES) += module.o
@@ -16,4 +16,14 @@ semaphore.c-dir = kernel
highmem.c-dir = mm
module.c-dir = kernel
+STUB_CFLAGS = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
+
+# _cflags works with kernel files, not with userspace ones, but c_flags does,
+# why ask why?
+$(obj)/stub_segv.o : c_flags = $(STUB_CFLAGS)
+
+$(obj)/stub.o : a_flags = $(STUB_CFLAGS)
+
subdir- := util
+
+include arch/um/scripts/Makefile.unmap
diff --git a/arch/um/sys-i386/ldt.c b/arch/um/sys-i386/ldt.c
index dc755b0b9db..bd3c34aa52e 100644
--- a/arch/um/sys-i386/ldt.c
+++ b/arch/um/sys-i386/ldt.c
@@ -4,96 +4,106 @@
*/
#include "linux/config.h"
+#include "linux/sched.h"
#include "linux/slab.h"
+#include "linux/types.h"
#include "asm/uaccess.h"
#include "asm/ptrace.h"
+#include "asm/smp.h"
+#include "asm/ldt.h"
#include "choose-mode.h"
#include "kern.h"
+#include "mode_kern.h"
#ifdef CONFIG_MODE_TT
-extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
-/* XXX this needs copy_to_user and copy_from_user */
+extern int modify_ldt(int func, void *ptr, unsigned long bytecount);
-int sys_modify_ldt_tt(int func, void __user *ptr, unsigned long bytecount)
+static int do_modify_ldt_tt(int func, void *ptr, unsigned long bytecount)
{
- if (!access_ok(VERIFY_READ, ptr, bytecount))
- return -EFAULT;
-
return modify_ldt(func, ptr, bytecount);
}
+
#endif
#ifdef CONFIG_MODE_SKAS
-extern int userspace_pid[];
+#include "skas.h"
#include "skas_ptrace.h"
-int sys_modify_ldt_skas(int func, void __user *ptr, unsigned long bytecount)
+static int do_modify_ldt_skas(int func, void *ptr, unsigned long bytecount)
{
struct ptrace_ldt ldt;
- void *buf;
- int res, n;
+ u32 cpu;
+ int res;
- buf = kmalloc(bytecount, GFP_KERNEL);
- if(buf == NULL)
- return(-ENOMEM);
+ ldt = ((struct ptrace_ldt) { .func = func,
+ .ptr = ptr,
+ .bytecount = bytecount });
- res = 0;
+ cpu = get_cpu();
+ res = ptrace(PTRACE_LDT, userspace_pid[cpu], 0, (unsigned long) &ldt);
+ put_cpu();
+
+ return res;
+}
+#endif
+
+int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
+{
+ struct user_desc info;
+ int res = 0;
+ void *buf = NULL;
+ void *p = NULL; /* What we pass to host. */
switch(func){
case 1:
- case 0x11:
- res = copy_from_user(buf, ptr, bytecount);
- break;
- }
+ case 0x11: /* write_ldt */
+ /* Do this check now to avoid overflows. */
+ if (bytecount != sizeof(struct user_desc)) {
+ res = -EINVAL;
+ goto out;
+ }
+
+ if(copy_from_user(&info, ptr, sizeof(info))) {
+ res = -EFAULT;
+ goto out;
+ }
- if(res != 0){
- res = -EFAULT;
+ p = &info;
+ break;
+ case 0:
+ case 2: /* read_ldt */
+
+ /* The use of info avoids kmalloc on the write case, not on the
+ * read one. */
+ buf = kmalloc(bytecount, GFP_KERNEL);
+ if (!buf) {
+ res = -ENOMEM;
+ goto out;
+ }
+ p = buf;
+ default:
+ res = -ENOSYS;
goto out;
}
- ldt = ((struct ptrace_ldt) { .func = func,
- .ptr = buf,
- .bytecount = bytecount });
-#warning Need to look up userspace_pid by cpu
- res = ptrace(PTRACE_LDT, userspace_pid[0], 0, (unsigned long) &ldt);
+ res = CHOOSE_MODE_PROC(do_modify_ldt_tt, do_modify_ldt_skas, func,
+ p, bytecount);
if(res < 0)
goto out;
switch(func){
case 0:
case 2:
- n = res;
- res = copy_to_user(ptr, buf, n);
- if(res != 0)
+ /* Modify_ldt was for reading and returned the number of read
+ * bytes.*/
+ if(copy_to_user(ptr, p, res))
res = -EFAULT;
- else
- res = n;
break;
}
- out:
+out:
kfree(buf);
- return(res);
-}
-#endif
-
-int sys_modify_ldt(int func, void __user *ptr, unsigned long bytecount)
-{
- return(CHOOSE_MODE_PROC(sys_modify_ldt_tt, sys_modify_ldt_skas, func,
- ptr, bytecount));
+ 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 --git a/arch/um/sys-i386/signal.c b/arch/um/sys-i386/signal.c
index 03913ca5d25..4efc69a039d 100644
--- a/arch/um/sys-i386/signal.c
+++ b/arch/um/sys-i386/signal.c
@@ -312,7 +312,7 @@ long sys_sigreturn(struct pt_regs regs)
unsigned long __user *extramask = frame->extramask;
int sig_size = (_NSIG_WORDS - 1) * sizeof(unsigned long);
- if(copy_from_user(&set.sig[0], oldmask, sizeof(&set.sig[0])) ||
+ if(copy_from_user(&set.sig[0], oldmask, sizeof(set.sig[0])) ||
copy_from_user(&set.sig[1], extramask, sig_size))
goto segfault;
diff --git a/arch/um/sys-i386/stub.S b/arch/um/sys-i386/stub.S
new file mode 100644
index 00000000000..2f2c70a8f04
--- /dev/null
+++ b/arch/um/sys-i386/stub.S
@@ -0,0 +1,8 @@
+#include "uml-config.h"
+
+ .globl syscall_stub
+.section .__syscall_stub, "x"
+syscall_stub:
+ int $0x80
+ mov %eax, UML_CONFIG_STUB_DATA
+ int3
diff --git a/arch/um/sys-i386/stub_segv.c b/arch/um/sys-i386/stub_segv.c
new file mode 100644
index 00000000000..68aeabe3a65
--- /dev/null
+++ b/arch/um/sys-i386/stub_segv.c
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include <signal.h>
+#include <asm/sigcontext.h>
+#include <asm/unistd.h>
+#include "uml-config.h"
+#include "sysdep/sigcontext.h"
+#include "sysdep/faultinfo.h"
+
+void __attribute__ ((__section__ (".__syscall_stub")))
+stub_segv_handler(int sig)
+{
+ struct sigcontext *sc = (struct sigcontext *) (&sig + 1);
+
+ GET_FAULTINFO_FROM_SC(*((struct faultinfo *) UML_CONFIG_STUB_DATA),
+ sc);
+
+ __asm__("movl %0, %%eax ; int $0x80": : "g" (__NR_getpid));
+ __asm__("movl %%eax, %%ebx ; movl %0, %%eax ; movl %1, %%ecx ;"
+ "int $0x80": : "g" (__NR_kill), "g" (SIGUSR1));
+ /* Load pointer to sigcontext into esp, since we need to leave
+ * the stack in its original form when we do the sigreturn here, by
+ * hand.
+ */
+ __asm__("mov %0,%%esp ; movl %1, %%eax ; "
+ "int $0x80" : : "a" (sc), "g" (__NR_sigreturn));
+}
diff --git a/arch/um/sys-i386/syscalls.c b/arch/um/sys-i386/syscalls.c
index 335e2d89504..83e9be820a8 100644
--- a/arch/um/sys-i386/syscalls.c
+++ b/arch/um/sys-i386/syscalls.c
@@ -69,15 +69,11 @@ long sys_clone(unsigned long clone_flags, unsigned long newsp,
{
long ret;
- /* XXX: normal arch do here this pass, and also pass the regs to
- * do_fork, instead of NULL. Currently the arch-independent code
- * ignores these values, while the UML code (actually it's
- * copy_thread) does the right thing. But this should change,
- probably. */
- /*if (!newsp)
- newsp = UPT_SP(current->thread.regs);*/
+ if (!newsp)
+ newsp = UPT_SP(&current->thread.regs.regs);
current->thread.forking = 1;
- ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid);
+ ret = do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid,
+ child_tid);
current->thread.forking = 0;
return(ret);
}
@@ -197,14 +193,3 @@ long sys_sigaction(int sig, const struct old_sigaction __user *act,
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 --git a/arch/um/sys-i386/unmap.c b/arch/um/sys-i386/unmap.c
new file mode 100644
index 00000000000..1b0ad0e4adc
--- /dev/null
+++ b/arch/um/sys-i386/unmap.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <linux/mman.h>
+#include <asm/unistd.h>
+
+static int errno;
+
+static inline _syscall2(int,munmap,void *,start,size_t,len)
+static inline _syscall6(void *,mmap2,void *,addr,size_t,len,int,prot,int,flags,int,fd,off_t,offset)
+int switcheroo(int fd, int prot, void *from, void *to, int size)
+{
+ if(munmap(to, size) < 0){
+ return(-1);
+ }
+ if(mmap2(to, size, prot, MAP_SHARED | MAP_FIXED, fd, 0) == (void*) -1 ){
+ return(-1);
+ }
+ if(munmap(from, size) < 0){
+ return(-1);
+ }
+ return(0);
+}
diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile
index 608466ad6b2..7488206ce6f 100644
--- a/arch/um/sys-x86_64/Makefile
+++ b/arch/um/sys-x86_64/Makefile
@@ -6,8 +6,8 @@
#XXX: why into lib-y?
lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o mem.o memcpy.o \
- ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o \
- syscalls.o sysrq.o thunk.o syscall_table.o
+ ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o stub.o \
+ stub_segv.o syscalls.o syscall_table.o sysrq.o thunk.o
obj-y := ksyms.o
obj-$(CONFIG_MODULES) += module.o um_module.o
@@ -28,4 +28,14 @@ semaphore.c-dir = kernel
thunk.S-dir = lib
module.c-dir = kernel
+STUB_CFLAGS = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
+
+# _cflags works with kernel files, not with userspace ones, but c_flags does,
+# why ask why?
+$(obj)/stub_segv.o : c_flags = $(STUB_CFLAGS)
+
+$(obj)/stub.o : a_flags = $(STUB_CFLAGS)
+
subdir- := util
+
+include arch/um/scripts/Makefile.unmap
diff --git a/arch/um/sys-x86_64/signal.c b/arch/um/sys-x86_64/signal.c
index 73a7926f737..8fdaed06c10 100644
--- a/arch/um/sys-x86_64/signal.c
+++ b/arch/um/sys-x86_64/signal.c
@@ -168,7 +168,7 @@ int setup_signal_stack_si(unsigned long stack_top, int sig,
frame = (struct rt_sigframe __user *)
round_down(stack_top - sizeof(struct rt_sigframe), 16) - 8;
- ((unsigned char *) frame) -= 128;
+ frame = (struct rt_sigframe *) ((unsigned long) frame - 128);
if (!access_ok(VERIFY_WRITE, fp, sizeof(struct _fpstate)))
goto out;
diff --git a/arch/um/sys-x86_64/stub.S b/arch/um/sys-x86_64/stub.S
new file mode 100644
index 00000000000..31c14925716
--- /dev/null
+++ b/arch/um/sys-x86_64/stub.S
@@ -0,0 +1,15 @@
+#include "uml-config.h"
+
+ .globl syscall_stub
+.section .__syscall_stub, "x"
+syscall_stub:
+ syscall
+ /* We don't have 64-bit constants, so this constructs the address
+ * we need.
+ */
+ movq $(UML_CONFIG_STUB_DATA >> 32), %rbx
+ salq $32, %rbx
+ movq $(UML_CONFIG_STUB_DATA & 0xffffffff), %rcx
+ or %rcx, %rbx
+ movq %rax, (%rbx)
+ int3
diff --git a/arch/um/sys-x86_64/stub_segv.c b/arch/um/sys-x86_64/stub_segv.c
new file mode 100644
index 00000000000..161d1fe9c03
--- /dev/null
+++ b/arch/um/sys-x86_64/stub_segv.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
+ * Licensed under the GPL
+ */
+
+#include <signal.h>
+#include <linux/compiler.h>
+#include <asm/unistd.h>
+#include "uml-config.h"
+#include "sysdep/sigcontext.h"
+#include "sysdep/faultinfo.h"
+
+void __attribute__ ((__section__ (".__syscall_stub")))
+stub_segv_handler(int sig)
+{
+ struct ucontext *uc;
+
+ __asm__("movq %%rdx, %0" : "=g" (uc) :);
+ GET_FAULTINFO_FROM_SC(*((struct faultinfo *) UML_CONFIG_STUB_DATA),
+ &uc->uc_mcontext);
+
+ __asm__("movq %0, %%rax ; syscall": : "g" (__NR_getpid));
+ __asm__("movq %%rax, %%rdi ; movq %0, %%rax ; movq %1, %%rsi ;"
+ "syscall": : "g" (__NR_kill), "g" (SIGUSR1));
+ /* Two popqs to restore the stack to the state just before entering
+ * the handler, one pops the return address, the other pops the frame
+ * pointer.
+ */
+ __asm__("popq %%rax ; popq %%rax ; movq %0, %%rax ; syscall" : : "g"
+ (__NR_rt_sigreturn));
+}
diff --git a/arch/um/sys-x86_64/syscalls.c b/arch/um/sys-x86_64/syscalls.c
index 6f44f40204e..3259a4db453 100644
--- a/arch/um/sys-x86_64/syscalls.c
+++ b/arch/um/sys-x86_64/syscalls.c
@@ -174,26 +174,11 @@ long sys_clone(unsigned long clone_flags, unsigned long newsp,
{
long ret;
- /* XXX: normal arch do here this pass, and also pass the regs to
- * do_fork, instead of NULL. Currently the arch-independent code
- * ignores these values, while the UML code (actually it's
- * copy_thread) does the right thing. But this should change,
- probably. */
- /*if (!newsp)
- newsp = UPT_SP(current->thread.regs);*/
+ if (!newsp)
+ newsp = UPT_SP(&current->thread.regs.regs);
current->thread.forking = 1;
- ret = do_fork(clone_flags, newsp, NULL, 0, parent_tid, child_tid);
+ ret = do_fork(clone_flags, newsp, &current->thread.regs, 0, parent_tid,
+ child_tid);
current->thread.forking = 0;
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 --git a/arch/um/sys-x86_64/unmap.c b/arch/um/sys-x86_64/unmap.c
new file mode 100644
index 00000000000..f4a4bffd8a1
--- /dev/null
+++ b/arch/um/sys-x86_64/unmap.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2000 Jeff Dike (jdike@karaya.com)
+ * Licensed under the GPL
+ */
+
+#include <linux/mman.h>
+#include <asm/unistd.h>
+
+static int errno;
+
+static inline _syscall2(int,munmap,void *,start,size_t,len)
+static inline _syscall6(void *,mmap,void *,addr,size_t,len,int,prot,int,flags,int,fd,off_t,offset)
+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) == (void*) -1){
+ return(-1);
+ }
+ if(munmap(from, size) < 0){
+ return(-1);
+ }
+ return(0);
+}