aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um
diff options
context:
space:
mode:
authorJeff Dike <jdike@addtoit.com>2005-07-07 20:56:49 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-07-07 21:23:44 -0400
commitd67b569f5f620c0fb95d5212642746b7ba9d29e4 (patch)
treec7ef10c906dd83911e10988c6cea6d7d5644e072 /arch/um
parent1322ad41513f8f9196801f53cc0851df056f3478 (diff)
[PATCH] uml: skas0 - separate kernel address space on stock hosts
UML has had two modes of operation - an insecure, slow mode (tt mode) in which the kernel is mapped into every process address space which requires no host kernel modifications, and a secure, faster mode (skas mode) in which the UML kernel is in a separate host address space, which requires a patch to the host kernel. This patch implements something very close to skas mode for hosts which don't support skas - I'm calling this skas0. It provides the security of the skas host patch, and some of the performance gains. The two main things that are provided by the skas patch, /proc/mm and PTRACE_FAULTINFO, are implemented in a way that require no host patch. For the remote address space changing stuff (mmap, munmap, and mprotect), we set aside two pages in the process above its stack, one of which contains a little bit of code which can call mmap et al. To update the address space, the system call information (system call number and arguments) are written to the stub page above the code. The %esp is set to the beginning of the data, the %eip is set the the start of the stub, and it repeatedly pops the information into its registers and makes the system call until it sees a system call number of zero. This is to amortize the cost of the context switch across multiple address space updates. When the updates are done, it SIGSTOPs itself, and the kernel process continues what it was doing. For a PTRACE_FAULTINFO replacement, we set up a SIGSEGV handler in the child, and let it handle segfaults rather than nullifying them. The handler is in the same page as the mmap stub. The second page is used as the stack. The handler reads cr2 and err from the sigcontext, sticks them at the base of the stack in a faultinfo struct, and SIGSTOPs itself. The kernel then reads the faultinfo and handles the fault. A complication on x86_64 is that this involves resetting the registers to the segfault values when the process is inside the kill system call. This breaks on x86_64 because %rcx will contain %rip because you tell SYSRET where to return to by putting the value in %rcx. So, this corrupts $rcx on return from the segfault. To work around this, I added an arch_finish_segv, which on x86 does nothing, but which on x86_64 ptraces the child back through the sigreturn. This causes %rcx to be restored by sigreturn and avoids the corruption. Ultimately, I think I will replace this with the trick of having it send itself a blocked signal which will be unblocked by the sigreturn. This will allow it to be stopped just after the sigreturn, and PTRACE_SYSCALLed without all the back-and-forth of PTRACE_SYSCALLing it through sigreturn. This runs on a stock host, so theoretically (and hopefully), tt mode isn't needed any more. We need to make sure that this is better in every way than tt mode, though. I'm concerned about the speed of address space updates and page fault handling, since they involve extra round-trips to the child. We can amortize the round-trip cost for large address space updates by writing all of the operations to the data page and having the child execute them all at the same time. This will help fork and exec, but not page faults, since they involve only one page. I can't think of any way to help page faults, except to add something like PTRACE_FAULTINFO to the host. There is PTRACE_SIGINFO, but UML doesn't use siginfo for SIGSEGV (or anything else) because there isn't enough information in the siginfo struct to handle page faults (the faulting operation type is missing). Adding that would make PTRACE_SIGINFO a usable equivalent to PTRACE_FAULTINFO. As for the code itself: - The system call stub is in arch/um/kernel/sys-$(SUBARCH)/stub.S. It is put in its own section of the binary along with stub_segv_handler in arch/um/kernel/skas/process.c. This is manipulated with run_syscall_stub in arch/um/kernel/skas/mem_user.c. syscall_stub will execute any system call at all, but it's only used for mmap, munmap, and mprotect. - The x86_64 stub calls sigreturn by hand rather than allowing the normal sigreturn to happen, because the normal sigreturn is a SA_RESTORER in UML's address space provided by libc. Needless to say, this is not available in the child's address space. Also, it does a couple of odd pops before that which restore the stack to the state it was in at the time the signal handler was called. - There is a new field in the arch mmu_context, which is now a union. This is the pid to be manipulated rather than the /proc/mm file descriptor. Code which deals with this now checks proc_mm to see whether it should use the usual skas code or the new code. - userspace_tramp is now used to create a new host process for every UML process, rather than one per UML processor. It checks proc_mm and ptrace_faultinfo to decide whether to map in the pages above its stack. - start_userspace now makes CLONE_VM conditional on proc_mm since we need separate address spaces now. - switch_mm_skas now just sets userspace_pid[0] to the new pid rather than PTRACE_SWITCH_MM. There is an addition to userspace which updates its idea of the pid being manipulated each time around the loop. This is important on exec, when the pid will change underneath userspace(). - The stub page has a pte, but it can't be mapped in using tlb_flush because it is part of tlb_flush. This is why it's required for it to be mapped in by userspace_tramp. Other random things: - The stub section in uml.lds.S is page aligned. This page is written out to the backing vm file in setup_physmem because it is mapped from there into user processes. - There's some confusion with TASK_SIZE now that there are a couple of extra pages that the process can't use. TASK_SIZE is considered by the elf code to be the usable process memory, which is reasonable, so it is decreased by two pages. This confuses the definition of USER_PGDS_IN_LAST_PML4, making it too small because of the rounding down of the uneven division. So we round it to the nearest PGDIR_SIZE rather than the lower one. - I added a missing PT_SYSCALL_ARG6_OFFSET macro. - um_mmu.h was made into a userspace-usable file. - proc_mm and ptrace_faultinfo are globals which say whether the host supports these features. - There is a bad interaction between the mm.nr_ptes check at the end of exit_mmap, stack randomization, and skas0. exit_mmap will stop freeing pages at the PGDIR_SIZE boundary after the last vma. If the stack isn't on the last page table page, the last pte page won't be freed, as it should be since the stub ptes are there, and exit_mmap will BUG because there is an unfreed page. To get around this, TASK_SIZE is set to the next lowest PGDIR_SIZE boundary and mm->nr_ptes is decremented after the calls to init_stub_pte. This ensures that we know the process stack (and all other process mappings) will be below the top page table page, and thus we know that mm->nr_ptes will be one too many, and can be decremented. Things that need fixing: - We may need better assurrences that the stub code is PIC. - The stub pte is set up in init_new_context_skas. - alloc_pgdir is probably the right place. Signed-off-by: Jeff Dike <jdike@addtoit.com> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/um')
-rw-r--r--arch/um/Kconfig_i38612
-rw-r--r--arch/um/Kconfig_x86_6412
-rw-r--r--arch/um/Makefile-i3862
-rw-r--r--arch/um/Makefile-x86_642
-rw-r--r--arch/um/defconfig58
-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.h18
-rw-r--r--arch/um/include/sysdep-x86_64/ptrace_user.h14
-rw-r--r--arch/um/include/sysdep-x86_64/stub.h19
-rw-r--r--arch/um/include/tlb.h30
-rw-r--r--arch/um/kernel/dyn.lds.S6
-rw-r--r--arch/um/kernel/physmem.c8
-rw-r--r--arch/um/kernel/process.c28
-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/skas.h15
-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.c136
-rw-r--r--arch/um/kernel/skas/process.c153
-rw-r--r--arch/um/kernel/skas/process_kern.c33
-rw-r--r--arch/um/kernel/skas/tlb.c28
-rw-r--r--arch/um/kernel/tlb.c132
-rw-r--r--arch/um/kernel/tt/tlb.c4
-rw-r--r--arch/um/kernel/uml.lds.S7
-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/scripts/Makefile.rules5
-rw-r--r--arch/um/sys-i386/Makefile12
-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-x86_64/Makefile12
-rw-r--r--arch/um/sys-x86_64/stub.S15
-rw-r--r--arch/um/sys-x86_64/stub_segv.c31
37 files changed, 850 insertions, 262 deletions
diff --git a/arch/um/Kconfig_i386 b/arch/um/Kconfig_i386
index e41f3748d30f..27c18a8d9d17 100644
--- a/arch/um/Kconfig_i386
+++ b/arch/um/Kconfig_i386
@@ -19,6 +19,18 @@ config 3_LEVEL_PGTABLES
19 memory. All the memory that can't be mapped directly will be treated 19 memory. All the memory that can't be mapped directly will be treated
20 as high memory. 20 as high memory.
21 21
22config STUB_CODE
23 hex
24 default 0xbfffe000
25
26config STUB_DATA
27 hex
28 default 0xbffff000
29
30config STUB_START
31 hex
32 default STUB_CODE
33
22config ARCH_HAS_SC_SIGNALS 34config ARCH_HAS_SC_SIGNALS
23 bool 35 bool
24 default y 36 default y
diff --git a/arch/um/Kconfig_x86_64 b/arch/um/Kconfig_x86_64
index f162f50f0b17..735a047c890c 100644
--- a/arch/um/Kconfig_x86_64
+++ b/arch/um/Kconfig_x86_64
@@ -14,6 +14,18 @@ config 3_LEVEL_PGTABLES
14 bool 14 bool
15 default y 15 default y
16 16
17config STUB_CODE
18 hex
19 default 0x7fbfffe000
20
21config STUB_DATA
22 hex
23 default 0x7fbffff000
24
25config STUB_START
26 hex
27 default STUB_CODE
28
17config ARCH_HAS_SC_SIGNALS 29config ARCH_HAS_SC_SIGNALS
18 bool 30 bool
19 default n 31 default n
diff --git a/arch/um/Makefile-i386 b/arch/um/Makefile-i386
index 29e182d5a83a..301059062a3e 100644
--- a/arch/um/Makefile-i386
+++ b/arch/um/Makefile-i386
@@ -8,7 +8,7 @@ ifeq ($(CONFIG_MODE_SKAS),y)
8 endif 8 endif
9endif 9endif
10 10
11CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH) 11CFLAGS += -U__$(SUBARCH)__ -U$(SUBARCH) $(STUB_CFLAGS)
12ARCH_USER_CFLAGS := 12ARCH_USER_CFLAGS :=
13 13
14ifneq ($(CONFIG_GPROF),y) 14ifneq ($(CONFIG_GPROF),y)
diff --git a/arch/um/Makefile-x86_64 b/arch/um/Makefile-x86_64
index 32144562c279..d80bd0052e6b 100644
--- a/arch/um/Makefile-x86_64
+++ b/arch/um/Makefile-x86_64
@@ -4,7 +4,7 @@
4SUBARCH_LIBS := arch/um/sys-x86_64/ 4SUBARCH_LIBS := arch/um/sys-x86_64/
5START := 0x60000000 5START := 0x60000000
6 6
7CFLAGS += -U__$(SUBARCH)__ -fno-builtin 7CFLAGS += -U__$(SUBARCH)__ -fno-builtin $(STUB_CFLAGS)
8ARCH_USER_CFLAGS := -D__x86_64__ 8ARCH_USER_CFLAGS := -D__x86_64__
9 9
10ELF_ARCH := i386:x86-64 10ELF_ARCH := i386:x86-64
diff --git a/arch/um/defconfig b/arch/um/defconfig
index 4067c3aa5b60..80d30d19d750 100644
--- a/arch/um/defconfig
+++ b/arch/um/defconfig
@@ -1,7 +1,7 @@
1# 1#
2# Automatically generated make config: don't edit 2# Automatically generated make config: don't edit
3# Linux kernel version: 2.6.12-rc3-skas3-v9-pre2 3# Linux kernel version: 2.6.12-rc6-mm1
4# Sun Apr 24 19:46:10 2005 4# Tue Jun 14 18:22:21 2005
5# 5#
6CONFIG_GENERIC_HARDIRQS=y 6CONFIG_GENERIC_HARDIRQS=y
7CONFIG_UML=y 7CONFIG_UML=y
@@ -13,23 +13,32 @@ CONFIG_GENERIC_CALIBRATE_DELAY=y
13# 13#
14# UML-specific options 14# UML-specific options
15# 15#
16CONFIG_MODE_TT=y 16# CONFIG_MODE_TT is not set
17# CONFIG_STATIC_LINK is not set
17CONFIG_MODE_SKAS=y 18CONFIG_MODE_SKAS=y
18CONFIG_UML_X86=y 19CONFIG_UML_X86=y
19# CONFIG_64BIT is not set 20# CONFIG_64BIT is not set
20CONFIG_TOP_ADDR=0xc0000000 21CONFIG_TOP_ADDR=0xc0000000
21# CONFIG_3_LEVEL_PGTABLES is not set 22# CONFIG_3_LEVEL_PGTABLES is not set
23CONFIG_STUB_CODE=0xbfffe000
24CONFIG_STUB_DATA=0xbffff000
25CONFIG_STUB_START=0xbfffe000
22CONFIG_ARCH_HAS_SC_SIGNALS=y 26CONFIG_ARCH_HAS_SC_SIGNALS=y
23CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA=y 27CONFIG_ARCH_REUSE_HOST_VSYSCALL_AREA=y
24CONFIG_LD_SCRIPT_STATIC=y 28CONFIG_SELECT_MEMORY_MODEL=y
29CONFIG_FLATMEM_MANUAL=y
30# CONFIG_DISCONTIGMEM_MANUAL is not set
31# CONFIG_SPARSEMEM_MANUAL is not set
32CONFIG_FLATMEM=y
33CONFIG_FLAT_NODE_MEM_MAP=y
34CONFIG_LD_SCRIPT_DYN=y
25CONFIG_NET=y 35CONFIG_NET=y
26CONFIG_BINFMT_ELF=y 36CONFIG_BINFMT_ELF=y
27CONFIG_BINFMT_MISC=m 37CONFIG_BINFMT_MISC=m
28CONFIG_HOSTFS=y 38# CONFIG_HOSTFS is not set
29CONFIG_MCONSOLE=y 39CONFIG_MCONSOLE=y
30# CONFIG_MAGIC_SYSRQ is not set 40# CONFIG_MAGIC_SYSRQ is not set
31# CONFIG_HOST_2G_2G is not set 41# CONFIG_HOST_2G_2G is not set
32# CONFIG_SMP is not set
33CONFIG_NEST_LEVEL=0 42CONFIG_NEST_LEVEL=0
34CONFIG_KERNEL_HALF_GIGS=1 43CONFIG_KERNEL_HALF_GIGS=1
35# CONFIG_HIGHMEM is not set 44# CONFIG_HIGHMEM is not set
@@ -63,6 +72,8 @@ CONFIG_IKCONFIG_PROC=y
63CONFIG_KALLSYMS=y 72CONFIG_KALLSYMS=y
64# CONFIG_KALLSYMS_ALL is not set 73# CONFIG_KALLSYMS_ALL is not set
65CONFIG_KALLSYMS_EXTRA_PASS=y 74CONFIG_KALLSYMS_EXTRA_PASS=y
75CONFIG_PRINTK=y
76CONFIG_BUG=y
66CONFIG_BASE_FULL=y 77CONFIG_BASE_FULL=y
67CONFIG_FUTEX=y 78CONFIG_FUTEX=y
68CONFIG_EPOLL=y 79CONFIG_EPOLL=y
@@ -81,6 +92,7 @@ CONFIG_MODULES=y
81CONFIG_MODULE_UNLOAD=y 92CONFIG_MODULE_UNLOAD=y
82# CONFIG_MODULE_FORCE_UNLOAD is not set 93# CONFIG_MODULE_FORCE_UNLOAD is not set
83CONFIG_OBSOLETE_MODPARM=y 94CONFIG_OBSOLETE_MODPARM=y
95# CONFIG_MODVERSIONS is not set
84# CONFIG_MODULE_SRCVERSION_ALL is not set 96# CONFIG_MODULE_SRCVERSION_ALL is not set
85CONFIG_KMOD=y 97CONFIG_KMOD=y
86 98
@@ -115,6 +127,7 @@ CONFIG_UML_SOUND=m
115CONFIG_SOUND=m 127CONFIG_SOUND=m
116CONFIG_HOSTAUDIO=m 128CONFIG_HOSTAUDIO=m
117CONFIG_UML_RANDOM=y 129CONFIG_UML_RANDOM=y
130# CONFIG_MMAPPER is not set
118 131
119# 132#
120# Block devices 133# Block devices
@@ -176,6 +189,17 @@ CONFIG_INET=y
176# CONFIG_INET_TUNNEL is not set 189# CONFIG_INET_TUNNEL is not set
177CONFIG_IP_TCPDIAG=y 190CONFIG_IP_TCPDIAG=y
178# CONFIG_IP_TCPDIAG_IPV6 is not set 191# CONFIG_IP_TCPDIAG_IPV6 is not set
192
193#
194# TCP congestion control
195#
196CONFIG_TCP_CONG_BIC=y
197CONFIG_TCP_CONG_WESTWOOD=y
198CONFIG_TCP_CONG_HTCP=y
199# CONFIG_TCP_CONG_HSTCP is not set
200# CONFIG_TCP_CONG_HYBLA is not set
201# CONFIG_TCP_CONG_VEGAS is not set
202# CONFIG_TCP_CONG_SCALABLE is not set
179# CONFIG_IPV6 is not set 203# CONFIG_IPV6 is not set
180# CONFIG_NETFILTER is not set 204# CONFIG_NETFILTER is not set
181 205
@@ -206,11 +230,15 @@ CONFIG_IP_TCPDIAG=y
206# Network testing 230# Network testing
207# 231#
208# CONFIG_NET_PKTGEN is not set 232# CONFIG_NET_PKTGEN is not set
233# CONFIG_KGDBOE is not set
209# CONFIG_NETPOLL is not set 234# CONFIG_NETPOLL is not set
235# CONFIG_NETPOLL_RX is not set
236# CONFIG_NETPOLL_TRAP is not set
210# CONFIG_NET_POLL_CONTROLLER is not set 237# CONFIG_NET_POLL_CONTROLLER is not set
211# CONFIG_HAMRADIO is not set 238# CONFIG_HAMRADIO is not set
212# CONFIG_IRDA is not set 239# CONFIG_IRDA is not set
213# CONFIG_BT is not set 240# CONFIG_BT is not set
241# CONFIG_IEEE80211 is not set
214CONFIG_DUMMY=m 242CONFIG_DUMMY=m
215# CONFIG_BONDING is not set 243# CONFIG_BONDING is not set
216# CONFIG_EQUALIZER is not set 244# CONFIG_EQUALIZER is not set
@@ -227,6 +255,7 @@ CONFIG_PPP=m
227# CONFIG_PPP_SYNC_TTY is not set 255# CONFIG_PPP_SYNC_TTY is not set
228# CONFIG_PPP_DEFLATE is not set 256# CONFIG_PPP_DEFLATE is not set
229# CONFIG_PPP_BSDCOMP is not set 257# CONFIG_PPP_BSDCOMP is not set
258# CONFIG_PPP_MPPE is not set
230# CONFIG_PPPOE is not set 259# CONFIG_PPPOE is not set
231CONFIG_SLIP=m 260CONFIG_SLIP=m
232# CONFIG_SLIP_COMPRESSED is not set 261# CONFIG_SLIP_COMPRESSED is not set
@@ -240,10 +269,12 @@ CONFIG_SLIP=m
240# 269#
241CONFIG_EXT2_FS=y 270CONFIG_EXT2_FS=y
242# CONFIG_EXT2_FS_XATTR is not set 271# CONFIG_EXT2_FS_XATTR is not set
272# CONFIG_EXT2_FS_XIP is not set
243CONFIG_EXT3_FS=y 273CONFIG_EXT3_FS=y
244# CONFIG_EXT3_FS_XATTR is not set 274# CONFIG_EXT3_FS_XATTR is not set
245CONFIG_JBD=y 275CONFIG_JBD=y
246# CONFIG_JBD_DEBUG is not set 276# CONFIG_JBD_DEBUG is not set
277# CONFIG_REISER4_FS is not set
247CONFIG_REISERFS_FS=y 278CONFIG_REISERFS_FS=y
248# CONFIG_REISERFS_CHECK is not set 279# CONFIG_REISERFS_CHECK is not set
249# CONFIG_REISERFS_PROC_INFO is not set 280# CONFIG_REISERFS_PROC_INFO is not set
@@ -256,6 +287,7 @@ CONFIG_REISERFS_FS=y
256# CONFIG_XFS_FS is not set 287# CONFIG_XFS_FS is not set
257# CONFIG_MINIX_FS is not set 288# CONFIG_MINIX_FS is not set
258# CONFIG_ROMFS_FS is not set 289# CONFIG_ROMFS_FS is not set
290CONFIG_INOTIFY=y
259CONFIG_QUOTA=y 291CONFIG_QUOTA=y
260# CONFIG_QFMT_V1 is not set 292# CONFIG_QFMT_V1 is not set
261# CONFIG_QFMT_V2 is not set 293# CONFIG_QFMT_V2 is not set
@@ -265,6 +297,12 @@ CONFIG_AUTOFS_FS=m
265CONFIG_AUTOFS4_FS=m 297CONFIG_AUTOFS4_FS=m
266 298
267# 299#
300# Caches
301#
302# CONFIG_FSCACHE is not set
303# CONFIG_FUSE_FS is not set
304
305#
268# CD-ROM/DVD Filesystems 306# CD-ROM/DVD Filesystems
269# 307#
270CONFIG_ISO9660_FS=m 308CONFIG_ISO9660_FS=m
@@ -291,6 +329,8 @@ CONFIG_TMPFS=y
291# CONFIG_TMPFS_XATTR is not set 329# CONFIG_TMPFS_XATTR is not set
292# CONFIG_HUGETLB_PAGE is not set 330# CONFIG_HUGETLB_PAGE is not set
293CONFIG_RAMFS=y 331CONFIG_RAMFS=y
332# CONFIG_CONFIGFS_FS is not set
333# CONFIG_RELAYFS_FS is not set
294 334
295# 335#
296# Miscellaneous filesystems 336# Miscellaneous filesystems
@@ -319,6 +359,7 @@ CONFIG_RAMFS=y
319# CONFIG_NCP_FS is not set 359# CONFIG_NCP_FS is not set
320# CONFIG_CODA_FS is not set 360# CONFIG_CODA_FS is not set
321# CONFIG_AFS_FS is not set 361# CONFIG_AFS_FS is not set
362# CONFIG_9P_FS is not set
322 363
323# 364#
324# Partition Types 365# Partition Types
@@ -404,14 +445,15 @@ CONFIG_CRC32=m
404# CONFIG_PRINTK_TIME is not set 445# CONFIG_PRINTK_TIME is not set
405CONFIG_DEBUG_KERNEL=y 446CONFIG_DEBUG_KERNEL=y
406CONFIG_LOG_BUF_SHIFT=14 447CONFIG_LOG_BUF_SHIFT=14
448CONFIG_DETECT_SOFTLOCKUP=y
407# CONFIG_SCHEDSTATS is not set 449# CONFIG_SCHEDSTATS is not set
408# CONFIG_DEBUG_SLAB is not set 450CONFIG_DEBUG_SLAB=y
409# CONFIG_DEBUG_SPINLOCK is not set 451# CONFIG_DEBUG_SPINLOCK is not set
410# CONFIG_DEBUG_SPINLOCK_SLEEP is not set 452# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
411# CONFIG_DEBUG_KOBJECT is not set 453# CONFIG_DEBUG_KOBJECT is not set
412CONFIG_DEBUG_INFO=y 454CONFIG_DEBUG_INFO=y
413# CONFIG_DEBUG_FS is not set 455# CONFIG_DEBUG_FS is not set
414CONFIG_FRAME_POINTER=y 456CONFIG_FRAME_POINTER=y
415CONFIG_PT_PROXY=y 457# CONFIG_GPROF is not set
416# CONFIG_GCOV is not set 458# CONFIG_GCOV is not set
417# CONFIG_SYSCALL_DEBUG is not set 459# CONFIG_SYSCALL_DEBUG is not set
diff --git a/arch/um/include/mem.h b/arch/um/include/mem.h
index 10c46c38949a..99d3ad4a03e5 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);
13extern int is_remapped(void *virt); 13extern int is_remapped(void *virt);
14extern int physmem_remove_mapping(void *virt); 14extern int physmem_remove_mapping(void *virt);
15extern void physmem_forget_descriptor(int fd); 15extern void physmem_forget_descriptor(int fd);
16extern unsigned long to_phys(void *virt);
16 17
17#endif 18#endif
18 19
diff --git a/arch/um/include/registers.h b/arch/um/include/registers.h
index 8744abb5224f..0a35e6d0baa0 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);
14extern void save_registers(int pid, union uml_pt_regs *regs); 14extern void save_registers(int pid, union uml_pt_regs *regs);
15extern void restore_registers(int pid, union uml_pt_regs *regs); 15extern void restore_registers(int pid, union uml_pt_regs *regs);
16extern void init_registers(int pid); 16extern void init_registers(int pid);
17extern void get_safe_registers(unsigned long * regs);
17 18
18#endif 19#endif
19 20
diff --git a/arch/um/include/sysdep-i386/ptrace_user.h b/arch/um/include/sysdep-i386/ptrace_user.h
index eca8066e7a43..899aa4b2a78d 100644
--- a/arch/um/include/sysdep-i386/ptrace_user.h
+++ b/arch/um/include/sysdep-i386/ptrace_user.h
@@ -20,11 +20,24 @@
20#define PT_SYSCALL_ARG3_OFFSET PT_OFFSET(EDX) 20#define PT_SYSCALL_ARG3_OFFSET PT_OFFSET(EDX)
21#define PT_SYSCALL_ARG4_OFFSET PT_OFFSET(ESI) 21#define PT_SYSCALL_ARG4_OFFSET PT_OFFSET(ESI)
22#define PT_SYSCALL_ARG5_OFFSET PT_OFFSET(EDI) 22#define PT_SYSCALL_ARG5_OFFSET PT_OFFSET(EDI)
23#define PT_SYSCALL_ARG6_OFFSET PT_OFFSET(EBP)
23 24
24#define PT_SYSCALL_RET_OFFSET PT_OFFSET(EAX) 25#define PT_SYSCALL_RET_OFFSET PT_OFFSET(EAX)
25 26
27#define REGS_SYSCALL_NR EAX /* This is used before a system call */
28#define REGS_SYSCALL_ARG1 EBX
29#define REGS_SYSCALL_ARG2 ECX
30#define REGS_SYSCALL_ARG3 EDX
31#define REGS_SYSCALL_ARG4 ESI
32#define REGS_SYSCALL_ARG5 EDI
33#define REGS_SYSCALL_ARG6 EBP
34
35#define REGS_IP_INDEX EIP
36#define REGS_SP_INDEX UESP
37
26#define PT_IP_OFFSET PT_OFFSET(EIP) 38#define PT_IP_OFFSET PT_OFFSET(EIP)
27#define PT_IP(regs) ((regs)[EIP]) 39#define PT_IP(regs) ((regs)[EIP])
40#define PT_SP_OFFSET PT_OFFSET(UESP)
28#define PT_SP(regs) ((regs)[UESP]) 41#define PT_SP(regs) ((regs)[UESP])
29 42
30#ifndef FRAME_SIZE 43#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 000000000000..fed9ff1cea52
--- /dev/null
+++ b/arch/um/include/sysdep-i386/stub.h
@@ -0,0 +1,18 @@
1/*
2 * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SYSDEP_STUB_H
7#define __SYSDEP_STUB_H
8
9#include <asm/ptrace.h>
10#include <asm/unistd.h>
11
12extern void stub_segv_handler(int sig);
13
14#define STUB_SYSCALL_RET EAX
15#define STUB_MMAP_NR __NR_mmap2
16#define MMAP_OFFSET(o) ((o) >> PAGE_SHIFT)
17
18#endif
diff --git a/arch/um/include/sysdep-x86_64/ptrace_user.h b/arch/um/include/sysdep-x86_64/ptrace_user.h
index 31729973fb14..128faf027364 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 @@
55#define PTRACE_OLDSETOPTIONS 21 55#define PTRACE_OLDSETOPTIONS 21
56#endif 56#endif
57 57
58/* These are before the system call, so the the system call number is RAX
59 * rather than ORIG_RAX, and arg4 is R10 rather than RCX
60 */
61#define REGS_SYSCALL_NR PT_INDEX(RAX)
62#define REGS_SYSCALL_ARG1 PT_INDEX(RDI)
63#define REGS_SYSCALL_ARG2 PT_INDEX(RSI)
64#define REGS_SYSCALL_ARG3 PT_INDEX(RDX)
65#define REGS_SYSCALL_ARG4 PT_INDEX(R10)
66#define REGS_SYSCALL_ARG5 PT_INDEX(R8)
67#define REGS_SYSCALL_ARG6 PT_INDEX(R9)
68
69#define REGS_IP_INDEX PT_INDEX(RIP)
70#define REGS_SP_INDEX PT_INDEX(RSP)
71
58#endif 72#endif
59 73
60/* 74/*
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 000000000000..6b5447ad590d
--- /dev/null
+++ b/arch/um/include/sysdep-x86_64/stub.h
@@ -0,0 +1,19 @@
1/*
2 * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __SYSDEP_STUB_H
7#define __SYSDEP_STUB_H
8
9#include <asm/ptrace.h>
10#include <asm/unistd.h>
11#include <sysdep/ptrace_user.h>
12
13extern void stub_segv_handler(int sig);
14
15#define STUB_SYSCALL_RET PT_INDEX(RAX)
16#define STUB_MMAP_NR __NR_mmap
17#define MMAP_OFFSET(o) (o)
18
19#endif
diff --git a/arch/um/include/tlb.h b/arch/um/include/tlb.h
index da1097285b8c..c6f9628f39bf 100644
--- a/arch/um/include/tlb.h
+++ b/arch/um/include/tlb.h
@@ -37,31 +37,25 @@ struct host_vm_op {
37extern void mprotect_kernel_vm(int w); 37extern void mprotect_kernel_vm(int w);
38extern void force_flush_all(void); 38extern void force_flush_all(void);
39extern void fix_range_common(struct mm_struct *mm, unsigned long start_addr, 39extern void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
40 unsigned long end_addr, int force, int data, 40 unsigned long end_addr, int force,
41 void (*do_ops)(int, struct host_vm_op *, int)); 41 void (*do_ops)(union mm_context *,
42 struct host_vm_op *, int));
42extern int flush_tlb_kernel_range_common(unsigned long start, 43extern int flush_tlb_kernel_range_common(unsigned long start,
43 unsigned long end); 44 unsigned long end);
44 45
45extern int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, 46extern int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
46 int r, int w, int x, struct host_vm_op *ops, int index, 47 int r, int w, int x, struct host_vm_op *ops, int index,
47 int last_filled, int data, 48 int last_filled, union mm_context *mmu,
48 void (*do_ops)(int, struct host_vm_op *, int)); 49 void (*do_ops)(union mm_context *, struct host_vm_op *,
50 int));
49extern int add_munmap(unsigned long addr, unsigned long len, 51extern int add_munmap(unsigned long addr, unsigned long len,
50 struct host_vm_op *ops, int index, int last_filled, 52 struct host_vm_op *ops, int index, int last_filled,
51 int data, void (*do_ops)(int, struct host_vm_op *, int)); 53 union mm_context *mmu,
54 void (*do_ops)(union mm_context *, struct host_vm_op *,
55 int));
52extern int add_mprotect(unsigned long addr, unsigned long len, int r, int w, 56extern int add_mprotect(unsigned long addr, unsigned long len, int r, int w,
53 int x, struct host_vm_op *ops, int index, 57 int x, struct host_vm_op *ops, int index,
54 int last_filled, int data, 58 int last_filled, union mm_context *mmu,
55 void (*do_ops)(int, struct host_vm_op *, int)); 59 void (*do_ops)(union mm_context *, struct host_vm_op *,
60 int));
56#endif 61#endif
57
58/*
59 * Overrides for Emacs so that we follow Linus's tabbing style.
60 * Emacs will notice this stuff at the end of the file and automatically
61 * adjust the settings for this buffer only. This must remain at the end
62 * of the file.
63 * ---------------------------------------------------------------------------
64 * Local variables:
65 * c-file-style: "linux"
66 * End:
67 */
diff --git a/arch/um/kernel/dyn.lds.S b/arch/um/kernel/dyn.lds.S
index 715b0838a68c..3942a5f245de 100644
--- a/arch/um/kernel/dyn.lds.S
+++ b/arch/um/kernel/dyn.lds.S
@@ -67,6 +67,12 @@ SECTIONS
67 *(.stub .text.* .gnu.linkonce.t.*) 67 *(.stub .text.* .gnu.linkonce.t.*)
68 /* .gnu.warning sections are handled specially by elf32.em. */ 68 /* .gnu.warning sections are handled specially by elf32.em. */
69 *(.gnu.warning) 69 *(.gnu.warning)
70
71 . = ALIGN(4096);
72 __syscall_stub_start = .;
73 *(.__syscall_stub*)
74 __syscall_stub_end = .;
75 . = ALIGN(4096);
70 } =0x90909090 76 } =0x90909090
71 .fini : { 77 .fini : {
72 KEEP (*(.fini)) 78 KEEP (*(.fini))
diff --git a/arch/um/kernel/physmem.c b/arch/um/kernel/physmem.c
index 420e6d51fa0f..a24e3b7f4bf0 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,
353 353
354#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT) 354#define PFN_UP(x) (((x) + PAGE_SIZE-1) >> PAGE_SHIFT)
355 355
356extern int __syscall_stub_start, __binary_start;
357
356void setup_physmem(unsigned long start, unsigned long reserve_end, 358void setup_physmem(unsigned long start, unsigned long reserve_end,
357 unsigned long len, unsigned long highmem) 359 unsigned long len, unsigned long highmem)
358{ 360{
@@ -371,6 +373,12 @@ void setup_physmem(unsigned long start, unsigned long reserve_end,
371 exit(1); 373 exit(1);
372 } 374 }
373 375
376 /* Special kludge - This page will be mapped in to userspace processes
377 * from physmem_fd, so it needs to be written out there.
378 */
379 os_seek_file(physmem_fd, __pa(&__syscall_stub_start));
380 os_write_file(physmem_fd, &__syscall_stub_start, PAGE_SIZE);
381
374 bootmap_size = init_bootmem(pfn, pfn + delta); 382 bootmap_size = init_bootmem(pfn, pfn + delta);
375 free_bootmem(__pa(reserve_end) + bootmap_size, 383 free_bootmem(__pa(reserve_end) + bootmap_size,
376 len - bootmap_size - reserve); 384 len - bootmap_size - reserve);
diff --git a/arch/um/kernel/process.c b/arch/um/kernel/process.c
index 1b5ef3e96c71..c45a60e9c92d 100644
--- a/arch/um/kernel/process.c
+++ b/arch/um/kernel/process.c
@@ -32,6 +32,7 @@
32#include "uml-config.h" 32#include "uml-config.h"
33#include "choose-mode.h" 33#include "choose-mode.h"
34#include "mode.h" 34#include "mode.h"
35#include "tempfile.h"
35#ifdef UML_CONFIG_MODE_SKAS 36#ifdef UML_CONFIG_MODE_SKAS
36#include "skas.h" 37#include "skas.h"
37#include "skas_ptrace.h" 38#include "skas_ptrace.h"
@@ -358,11 +359,16 @@ void forward_pending_sigio(int target)
358 kill(target, SIGIO); 359 kill(target, SIGIO);
359} 360}
360 361
362int ptrace_faultinfo = 0;
363int proc_mm = 1;
364
365extern void *__syscall_stub_start, __syscall_stub_end;
366
361#ifdef UML_CONFIG_MODE_SKAS 367#ifdef UML_CONFIG_MODE_SKAS
362static inline int check_skas3_ptrace_support(void) 368static inline void check_skas3_ptrace_support(void)
363{ 369{
364 struct ptrace_faultinfo fi; 370 struct ptrace_faultinfo fi;
365 int pid, n, ret = 1; 371 int pid, n;
366 372
367 printf("Checking for the skas3 patch in the host..."); 373 printf("Checking for the skas3 patch in the host...");
368 pid = start_ptraced_child(); 374 pid = start_ptraced_child();
@@ -374,33 +380,31 @@ static inline int check_skas3_ptrace_support(void)
374 else { 380 else {
375 perror("not found"); 381 perror("not found");
376 } 382 }
377 ret = 0; 383 }
378 } else { 384 else {
385 ptrace_faultinfo = 1;
379 printf("found\n"); 386 printf("found\n");
380 } 387 }
381 388
382 init_registers(pid); 389 init_registers(pid);
383 stop_ptraced_child(pid, 1, 1); 390 stop_ptraced_child(pid, 1, 1);
384
385 return(ret);
386} 391}
387 392
388int can_do_skas(void) 393int can_do_skas(void)
389{ 394{
390 int ret = 1;
391
392 printf("Checking for /proc/mm..."); 395 printf("Checking for /proc/mm...");
393 if (os_access("/proc/mm", OS_ACC_W_OK) < 0) { 396 if (os_access("/proc/mm", OS_ACC_W_OK) < 0) {
397 proc_mm = 0;
394 printf("not found\n"); 398 printf("not found\n");
395 ret = 0;
396 goto out; 399 goto out;
397 } else { 400 }
401 else {
398 printf("found\n"); 402 printf("found\n");
399 } 403 }
400 404
401 ret = check_skas3_ptrace_support();
402out: 405out:
403 return ret; 406 check_skas3_ptrace_support();
407 return 1;
404} 408}
405#else 409#else
406int can_do_skas(void) 410int can_do_skas(void)
diff --git a/arch/um/kernel/skas/exec_kern.c b/arch/um/kernel/skas/exec_kern.c
index c6b4d5dba789..77ed7bbab219 100644
--- a/arch/um/kernel/skas/exec_kern.c
+++ b/arch/um/kernel/skas/exec_kern.c
@@ -18,7 +18,7 @@
18void flush_thread_skas(void) 18void flush_thread_skas(void)
19{ 19{
20 force_flush_all(); 20 force_flush_all();
21 switch_mm_skas(current->mm->context.skas.mm_fd); 21 switch_mm_skas(&current->mm->context.skas.id);
22} 22}
23 23
24void start_thread_skas(struct pt_regs *regs, unsigned long eip, 24void 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 000000000000..48dd0989ddaa
--- /dev/null
+++ b/arch/um/kernel/skas/include/mm_id.h
@@ -0,0 +1,17 @@
1/*
2 * Copyright (C) 2005 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __MM_ID_H
7#define __MM_ID_H
8
9struct mm_id {
10 union {
11 int mm_fd;
12 int pid;
13 } u;
14 unsigned long stack;
15};
16
17#endif
diff --git a/arch/um/kernel/skas/include/mmu-skas.h b/arch/um/kernel/skas/include/mmu-skas.h
index 4cd60d7213f3..278b72f1d9ad 100644
--- a/arch/um/kernel/skas/include/mmu-skas.h
+++ b/arch/um/kernel/skas/include/mmu-skas.h
@@ -6,10 +6,15 @@
6#ifndef __SKAS_MMU_H 6#ifndef __SKAS_MMU_H
7#define __SKAS_MMU_H 7#define __SKAS_MMU_H
8 8
9#include "mm_id.h"
10
9struct mmu_context_skas { 11struct mmu_context_skas {
10 int mm_fd; 12 struct mm_id id;
13 unsigned long last_page_table;
11}; 14};
12 15
16extern void switch_mm_skas(struct mm_id * mm_idp);
17
13#endif 18#endif
14 19
15/* 20/*
diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h
index 96b51dba3471..d91a60f3830a 100644
--- a/arch/um/kernel/skas/include/skas.h
+++ b/arch/um/kernel/skas/include/skas.h
@@ -6,9 +6,11 @@
6#ifndef __SKAS_H 6#ifndef __SKAS_H
7#define __SKAS_H 7#define __SKAS_H
8 8
9#include "mm_id.h"
9#include "sysdep/ptrace.h" 10#include "sysdep/ptrace.h"
10 11
11extern int userspace_pid[]; 12extern int userspace_pid[];
13extern int proc_mm, ptrace_faultinfo;
12 14
13extern void switch_threads(void *me, void *next); 15extern void switch_threads(void *me, void *next);
14extern void thread_wait(void *sw, void *fb); 16extern void thread_wait(void *sw, void *fb);
@@ -22,16 +24,17 @@ extern void new_thread_proc(void *stack, void (*handler)(int sig));
22extern void remove_sigstack(void); 24extern void remove_sigstack(void);
23extern void new_thread_handler(int sig); 25extern void new_thread_handler(int sig);
24extern void handle_syscall(union uml_pt_regs *regs); 26extern void handle_syscall(union uml_pt_regs *regs);
25extern void map(int fd, unsigned long virt, unsigned long len, int r, int w, 27extern int map(struct mm_id * mm_idp, unsigned long virt, unsigned long len,
26 int x, int phys_fd, unsigned long long offset); 28 int r, int w, int x, int phys_fd, unsigned long long offset);
27extern int unmap(int fd, void *addr, unsigned long len); 29extern int unmap(struct mm_id * mm_idp, void *addr, unsigned long len);
28extern int protect(int fd, unsigned long addr, unsigned long len, 30extern int protect(struct mm_id * mm_idp, unsigned long addr,
29 int r, int w, int x); 31 unsigned long len, int r, int w, int x);
30extern void user_signal(int sig, union uml_pt_regs *regs, int pid); 32extern void user_signal(int sig, union uml_pt_regs *regs, int pid);
31extern int new_mm(int from); 33extern int new_mm(int from);
32extern void start_userspace(int cpu); 34extern int start_userspace(unsigned long stub_stack);
33extern void get_skas_faultinfo(int pid, struct faultinfo * fi); 35extern void get_skas_faultinfo(int pid, struct faultinfo * fi);
34extern long execute_syscall_skas(void *r); 36extern long execute_syscall_skas(void *r);
37extern unsigned long current_stub_stack(void);
35 38
36#endif 39#endif
37 40
diff --git a/arch/um/kernel/skas/mem.c b/arch/um/kernel/skas/mem.c
index 438db2f43456..147466d7ff4f 100644
--- a/arch/um/kernel/skas/mem.c
+++ b/arch/um/kernel/skas/mem.c
@@ -5,7 +5,9 @@
5 5
6#include "linux/config.h" 6#include "linux/config.h"
7#include "linux/mm.h" 7#include "linux/mm.h"
8#include "asm/pgtable.h"
8#include "mem_user.h" 9#include "mem_user.h"
10#include "skas.h"
9 11
10unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out, 12unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
11 unsigned long *task_size_out) 13 unsigned long *task_size_out)
@@ -18,7 +20,9 @@ unsigned long set_task_sizes_skas(int arg, unsigned long *host_size_out,
18 *task_size_out = CONFIG_HOST_TASK_SIZE; 20 *task_size_out = CONFIG_HOST_TASK_SIZE;
19#else 21#else
20 *host_size_out = top; 22 *host_size_out = top;
21 *task_size_out = top; 23 if (proc_mm && ptrace_faultinfo)
24 *task_size_out = top;
25 else *task_size_out = CONFIG_STUB_START & PGDIR_MASK;
22#endif 26#endif
23 return(((unsigned long) set_task_sizes_skas) & ~0xffffff); 27 return(((unsigned long) set_task_sizes_skas) & ~0xffffff);
24} 28}
diff --git a/arch/um/kernel/skas/mem_user.c b/arch/um/kernel/skas/mem_user.c
index 1310bf1e88d1..b0980ff3bd95 100644
--- a/arch/um/kernel/skas/mem_user.c
+++ b/arch/um/kernel/skas/mem_user.c
@@ -3,100 +3,171 @@
3 * Licensed under the GPL 3 * Licensed under the GPL
4 */ 4 */
5 5
6#include <signal.h>
6#include <errno.h> 7#include <errno.h>
7#include <sys/mman.h> 8#include <sys/mman.h>
9#include <sys/wait.h>
10#include <asm/page.h>
11#include <asm/unistd.h>
8#include "mem_user.h" 12#include "mem_user.h"
9#include "mem.h" 13#include "mem.h"
14#include "mm_id.h"
10#include "user.h" 15#include "user.h"
11#include "os.h" 16#include "os.h"
12#include "proc_mm.h" 17#include "proc_mm.h"
13 18#include "ptrace_user.h"
14void map(int fd, unsigned long virt, unsigned long len, int r, int w, 19#include "user_util.h"
15 int x, int phys_fd, unsigned long long offset) 20#include "kern_util.h"
21#include "task.h"
22#include "registers.h"
23#include "uml-config.h"
24#include "sysdep/ptrace.h"
25#include "sysdep/stub.h"
26#include "skas.h"
27
28extern unsigned long syscall_stub, __syscall_stub_start;
29
30extern void wait_stub_done(int pid, int sig, char * fname);
31
32static long run_syscall_stub(struct mm_id * mm_idp, int syscall,
33 unsigned long *args)
16{ 34{
17 struct proc_mm_op map; 35 int n, pid = mm_idp->u.pid;
18 int prot, n; 36 unsigned long regs[MAX_REG_NR];
19 37
20 prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 38 get_safe_registers(regs);
21 (x ? PROT_EXEC : 0); 39 regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
22 40 ((unsigned long) &syscall_stub -
23 map = ((struct proc_mm_op) { .op = MM_MMAP, 41 (unsigned long) &__syscall_stub_start);
24 .u = 42 /* XXX Don't have a define for starting a syscall */
25 { .mmap = 43 regs[REGS_SYSCALL_NR] = syscall;
26 { .addr = virt, 44 regs[REGS_SYSCALL_ARG1] = args[0];
27 .len = len, 45 regs[REGS_SYSCALL_ARG2] = args[1];
28 .prot = prot, 46 regs[REGS_SYSCALL_ARG3] = args[2];
29 .flags = MAP_SHARED | 47 regs[REGS_SYSCALL_ARG4] = args[3];
30 MAP_FIXED, 48 regs[REGS_SYSCALL_ARG5] = args[4];
31 .fd = phys_fd, 49 regs[REGS_SYSCALL_ARG6] = args[5];
32 .offset = offset 50 n = ptrace_setregs(pid, regs);
33 } } } ); 51 if(n < 0){
34 n = os_write_file(fd, &map, sizeof(map)); 52 printk("run_syscall_stub : PTRACE_SETREGS failed, "
35 if(n != sizeof(map)) 53 "errno = %d\n", n);
36 printk("map : /proc/mm map failed, err = %d\n", -n); 54 return(n);
55 }
56
57 wait_stub_done(pid, 0, "run_syscall_stub");
58
59 return(*((unsigned long *) mm_idp->stack));
37} 60}
38 61
39int unmap(int fd, void *addr, unsigned long len) 62int map(struct mm_id *mm_idp, unsigned long virt, unsigned long len,
63 int r, int w, int x, int phys_fd, unsigned long long offset)
40{ 64{
41 struct proc_mm_op unmap; 65 int prot, n;
42 int n; 66
43 67 prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
44 unmap = ((struct proc_mm_op) { .op = MM_MUNMAP, 68 (x ? PROT_EXEC : 0);
45 .u = 69
46 { .munmap = 70 if(proc_mm){
47 { .addr = (unsigned long) addr, 71 struct proc_mm_op map;
48 .len = len } } } ); 72 int fd = mm_idp->u.mm_fd;
49 n = os_write_file(fd, &unmap, sizeof(unmap)); 73 map = ((struct proc_mm_op) { .op = MM_MMAP,
50 if(n != sizeof(unmap)) { 74 .u =
51 if(n < 0) 75 { .mmap =
52 return(n); 76 { .addr = virt,
53 else if(n > 0) 77 .len = len,
54 return(-EIO); 78 .prot = prot,
55 } 79 .flags = MAP_SHARED |
56 80 MAP_FIXED,
57 return(0); 81 .fd = phys_fd,
82 .offset= offset
83 } } } );
84 n = os_write_file(fd, &map, sizeof(map));
85 if(n != sizeof(map))
86 printk("map : /proc/mm map failed, err = %d\n", -n);
87 }
88 else {
89 long res;
90 unsigned long args[] = { virt, len, prot,
91 MAP_SHARED | MAP_FIXED, phys_fd,
92 MMAP_OFFSET(offset) };
93
94 res = run_syscall_stub(mm_idp, STUB_MMAP_NR, args);
95 if((void *) res == MAP_FAILED)
96 printk("mmap stub failed, errno = %d\n", res);
97 }
98
99 return 0;
58} 100}
59 101
60int protect(int fd, unsigned long addr, unsigned long len, int r, int w, 102int unmap(struct mm_id *mm_idp, void *addr, unsigned long len)
61 int x, int must_succeed)
62{ 103{
63 struct proc_mm_op protect; 104 int n;
64 int prot, n; 105
65 106 if(proc_mm){
66 prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) | 107 struct proc_mm_op unmap;
67 (x ? PROT_EXEC : 0); 108 int fd = mm_idp->u.mm_fd;
68 109 unmap = ((struct proc_mm_op) { .op = MM_MUNMAP,
69 protect = ((struct proc_mm_op) { .op = MM_MPROTECT, 110 .u =
70 .u = 111 { .munmap =
71 { .mprotect = 112 { .addr =
72 { .addr = (unsigned long) addr, 113 (unsigned long) addr,
73 .len = len, 114 .len = len } } } );
74 .prot = prot } } } ); 115 n = os_write_file(fd, &unmap, sizeof(unmap));
75 116 if(n != sizeof(unmap)) {
76 n = os_write_file(fd, &protect, sizeof(protect)); 117 if(n < 0)
77 if(n != sizeof(protect)) { 118 return(n);
78 if(n == 0) return(0); 119 else if(n > 0)
79 120 return(-EIO);
80 if(must_succeed) 121 }
81 panic("protect failed, err = %d", -n); 122 }
82 123 else {
83 return(-EIO); 124 int res;
84 } 125 unsigned long args[] = { (unsigned long) addr, len, 0, 0, 0,
126 0 };
127
128 res = run_syscall_stub(mm_idp, __NR_munmap, args);
129 if(res < 0)
130 printk("munmap stub failed, errno = %d\n", res);
131 }
132
133 return(0);
134}
85 135
86 return(0); 136int protect(struct mm_id *mm_idp, unsigned long addr, unsigned long len,
137 int r, int w, int x)
138{
139 struct proc_mm_op protect;
140 int prot, n;
141
142 prot = (r ? PROT_READ : 0) | (w ? PROT_WRITE : 0) |
143 (x ? PROT_EXEC : 0);
144
145 if(proc_mm){
146 int fd = mm_idp->u.mm_fd;
147 protect = ((struct proc_mm_op) { .op = MM_MPROTECT,
148 .u =
149 { .mprotect =
150 { .addr =
151 (unsigned long) addr,
152 .len = len,
153 .prot = prot } } } );
154
155 n = os_write_file(fd, &protect, sizeof(protect));
156 if(n != sizeof(protect))
157 panic("protect failed, err = %d", -n);
158 }
159 else {
160 int res;
161 unsigned long args[] = { addr, len, prot, 0, 0, 0 };
162
163 res = run_syscall_stub(mm_idp, __NR_mprotect, args);
164 if(res < 0)
165 panic("mprotect stub failed, errno = %d\n", res);
166 }
167
168 return(0);
87} 169}
88 170
89void before_mem_skas(unsigned long unused) 171void before_mem_skas(unsigned long unused)
90{ 172{
91} 173}
92
93/*
94 * Overrides for Emacs so that we follow Linus's tabbing style.
95 * Emacs will notice this stuff at the end of the file and automatically
96 * adjust the settings for this buffer only. This must remain at the end
97 * of the file.
98 * ---------------------------------------------------------------------------
99 * Local variables:
100 * c-file-style: "linux"
101 * End:
102 */
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index 6cb9a6d028a9..511a855c9ec0 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -3,46 +3,138 @@
3 * Licensed under the GPL 3 * Licensed under the GPL
4 */ 4 */
5 5
6#include "linux/config.h"
6#include "linux/sched.h" 7#include "linux/sched.h"
7#include "linux/list.h" 8#include "linux/list.h"
8#include "linux/spinlock.h" 9#include "linux/spinlock.h"
9#include "linux/slab.h" 10#include "linux/slab.h"
11#include "linux/errno.h"
12#include "linux/mm.h"
10#include "asm/current.h" 13#include "asm/current.h"
11#include "asm/segment.h" 14#include "asm/segment.h"
12#include "asm/mmu.h" 15#include "asm/mmu.h"
16#include "asm/pgalloc.h"
17#include "asm/pgtable.h"
13#include "os.h" 18#include "os.h"
14#include "skas.h" 19#include "skas.h"
15 20
21extern int __syscall_stub_start;
22
23static int init_stub_pte(struct mm_struct *mm, unsigned long proc,
24 unsigned long kernel)
25{
26 pgd_t *pgd;
27 pud_t *pud;
28 pmd_t *pmd;
29 pte_t *pte;
30
31 spin_lock(&mm->page_table_lock);
32 pgd = pgd_offset(mm, proc);
33 pud = pud_alloc(mm, pgd, proc);
34 if (!pud)
35 goto out;
36
37 pmd = pmd_alloc(mm, pud, proc);
38 if (!pmd)
39 goto out_pmd;
40
41 pte = pte_alloc_map(mm, pmd, proc);
42 if (!pte)
43 goto out_pte;
44
45 /* There's an interaction between the skas0 stub pages, stack
46 * randomization, and the BUG at the end of exit_mmap. exit_mmap
47 * checks that the number of page tables freed is the same as had
48 * been allocated. If the stack is on the last page table page,
49 * then the stack pte page will be freed, and if not, it won't. To
50 * avoid having to know where the stack is, or if the process mapped
51 * something at the top of its address space for some other reason,
52 * we set TASK_SIZE to end at the start of the last page table.
53 * This keeps exit_mmap off the last page, but introduces a leak
54 * of that page. So, we hang onto it here and free it in
55 * destroy_context_skas.
56 */
57
58 mm->context.skas.last_page_table = pmd_page_kernel(*pmd);
59
60 *pte = mk_pte(virt_to_page(kernel), __pgprot(_PAGE_PRESENT));
61 *pte = pte_mkexec(*pte);
62 *pte = pte_wrprotect(*pte);
63 spin_unlock(&mm->page_table_lock);
64 return(0);
65
66 out_pmd:
67 pud_free(pud);
68 out_pte:
69 pmd_free(pmd);
70 out:
71 spin_unlock(&mm->page_table_lock);
72 return(-ENOMEM);
73}
74
16int init_new_context_skas(struct task_struct *task, struct mm_struct *mm) 75int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
17{ 76{
18 int from; 77 struct mm_struct *cur_mm = current->mm;
78 struct mm_id *mm_id = &mm->context.skas.id;
79 unsigned long stack;
80 int from, ret;
19 81
20 if((current->mm != NULL) && (current->mm != &init_mm)) 82 if(proc_mm){
21 from = current->mm->context.skas.mm_fd; 83 if((cur_mm != NULL) && (cur_mm != &init_mm))
22 else from = -1; 84 from = cur_mm->context.skas.id.u.mm_fd;
85 else from = -1;
23 86
24 mm->context.skas.mm_fd = new_mm(from); 87 ret = new_mm(from);
25 if(mm->context.skas.mm_fd < 0){ 88 if(ret < 0){
26 printk("init_new_context_skas - new_mm failed, errno = %d\n", 89 printk("init_new_context_skas - new_mm failed, "
27 mm->context.skas.mm_fd); 90 "errno = %d\n", ret);
28 return(mm->context.skas.mm_fd); 91 return ret;
92 }
93 mm_id->u.mm_fd = ret;
29 } 94 }
95 else {
96 /* This zeros the entry that pgd_alloc didn't, needed since
97 * we are about to reinitialize it, and want mm.nr_ptes to
98 * be accurate.
99 */
100 mm->pgd[USER_PTRS_PER_PGD] = __pgd(0);
30 101
31 return(0); 102 ret = init_stub_pte(mm, CONFIG_STUB_CODE,
103 (unsigned long) &__syscall_stub_start);
104 if(ret)
105 goto out;
106
107 ret = -ENOMEM;
108 stack = get_zeroed_page(GFP_KERNEL);
109 if(stack == 0)
110 goto out;
111 mm_id->stack = stack;
112
113 ret = init_stub_pte(mm, CONFIG_STUB_DATA, stack);
114 if(ret)
115 goto out_free;
116
117 mm->nr_ptes--;
118 mm_id->u.pid = start_userspace(stack);
119 }
120
121 return 0;
122
123 out_free:
124 free_page(mm_id->stack);
125 out:
126 return ret;
32} 127}
33 128
34void destroy_context_skas(struct mm_struct *mm) 129void destroy_context_skas(struct mm_struct *mm)
35{ 130{
36 os_close_file(mm->context.skas.mm_fd); 131 struct mmu_context_skas *mmu = &mm->context.skas;
37}
38 132
39/* 133 if(proc_mm)
40 * Overrides for Emacs so that we follow Linus's tabbing style. 134 os_close_file(mmu->id.u.mm_fd);
41 * Emacs will notice this stuff at the end of the file and automatically 135 else {
42 * adjust the settings for this buffer only. This must remain at the end 136 os_kill_ptraced_process(mmu->id.u.pid, 1);
43 * of the file. 137 free_page(mmu->id.stack);
44 * --------------------------------------------------------------------------- 138 free_page(mmu->last_page_table);
45 * Local variables: 139 }
46 * c-file-style: "linux" 140}
47 * End:
48 */
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index 773cd2b525fc..1647abb0d1aa 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -1,5 +1,5 @@
1/* 1/*
2 * Copyright (C) 2002 Jeff Dike (jdike@karaya.com) 2 * Copyright (C) 2002- 2004 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL 3 * Licensed under the GPL
4 */ 4 */
5 5
@@ -14,6 +14,7 @@
14#include <sys/mman.h> 14#include <sys/mman.h>
15#include <sys/user.h> 15#include <sys/user.h>
16#include <asm/unistd.h> 16#include <asm/unistd.h>
17#include <asm/types.h>
17#include "user.h" 18#include "user.h"
18#include "ptrace_user.h" 19#include "ptrace_user.h"
19#include "time_user.h" 20#include "time_user.h"
@@ -21,13 +22,17 @@
21#include "user_util.h" 22#include "user_util.h"
22#include "kern_util.h" 23#include "kern_util.h"
23#include "skas.h" 24#include "skas.h"
25#include "mm_id.h"
24#include "sysdep/sigcontext.h" 26#include "sysdep/sigcontext.h"
27#include "sysdep/stub.h"
25#include "os.h" 28#include "os.h"
26#include "proc_mm.h" 29#include "proc_mm.h"
27#include "skas_ptrace.h" 30#include "skas_ptrace.h"
28#include "chan_user.h" 31#include "chan_user.h"
29#include "signal_user.h" 32#include "signal_user.h"
30#include "registers.h" 33#include "registers.h"
34#include "mem.h"
35#include "uml-config.h"
31#include "process.h" 36#include "process.h"
32 37
33int is_skas_winch(int pid, int fd, void *data) 38int is_skas_winch(int pid, int fd, void *data)
@@ -39,20 +44,55 @@ int is_skas_winch(int pid, int fd, void *data)
39 return(1); 44 return(1);
40} 45}
41 46
42void get_skas_faultinfo(int pid, struct faultinfo * fi) 47void wait_stub_done(int pid, int sig, char * fname)
43{ 48{
44 int err; 49 int n, status, err;
45 50
46 err = ptrace(PTRACE_FAULTINFO, pid, 0, fi); 51 do {
47 if(err) 52 if ( sig != -1 ) {
48 panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, " 53 err = ptrace(PTRACE_CONT, pid, 0, sig);
49 "errno = %d\n", errno); 54 if(err)
55 panic("%s : continue failed, errno = %d\n",
56 fname, errno);
57 }
58 sig = 0;
59
60 CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
61 } while((n >= 0) && WIFSTOPPED(status) &&
62 (WSTOPSIG(status) == SIGVTALRM));
63
64 if((n < 0) || !WIFSTOPPED(status) ||
65 (WSTOPSIG(status) != SIGUSR1 && WSTOPSIG(status != SIGTRAP))){
66 panic("%s : failed to wait for SIGUSR1/SIGTRAP, "
67 "pid = %d, n = %d, errno = %d, status = 0x%x\n",
68 fname, pid, n, errno, status);
69 }
70}
50 71
51 /* Special handling for i386, which has different structs */ 72void get_skas_faultinfo(int pid, struct faultinfo * fi)
52 if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo)) 73{
53 memset((char *)fi + sizeof(struct ptrace_faultinfo), 0, 74 int err;
54 sizeof(struct faultinfo) - 75
55 sizeof(struct ptrace_faultinfo)); 76 if(ptrace_faultinfo){
77 err = ptrace(PTRACE_FAULTINFO, pid, 0, fi);
78 if(err)
79 panic("get_skas_faultinfo - PTRACE_FAULTINFO failed, "
80 "errno = %d\n", errno);
81
82 /* Special handling for i386, which has different structs */
83 if (sizeof(struct ptrace_faultinfo) < sizeof(struct faultinfo))
84 memset((char *)fi + sizeof(struct ptrace_faultinfo), 0,
85 sizeof(struct faultinfo) -
86 sizeof(struct ptrace_faultinfo));
87 }
88 else {
89 wait_stub_done(pid, SIGSEGV, "get_skas_faultinfo");
90
91 /* faultinfo is prepared by the stub-segv-handler at start of
92 * the stub stack page. We just have to copy it.
93 */
94 memcpy(fi, (void *)current_stub_stack(), sizeof(*fi));
95 }
56} 96}
57 97
58static void handle_segv(int pid, union uml_pt_regs * regs) 98static void handle_segv(int pid, union uml_pt_regs * regs)
@@ -91,11 +131,56 @@ static void handle_trap(int pid, union uml_pt_regs *regs, int local_using_sysemu
91 handle_syscall(regs); 131 handle_syscall(regs);
92} 132}
93 133
94static int userspace_tramp(void *arg) 134extern int __syscall_stub_start;
135
136static int userspace_tramp(void *stack)
95{ 137{
96 init_new_thread_signals(0); 138 void *addr;
97 enable_timer(); 139
98 ptrace(PTRACE_TRACEME, 0, 0, 0); 140 ptrace(PTRACE_TRACEME, 0, 0, 0);
141
142 init_new_thread_signals(1);
143 enable_timer();
144
145 if(!proc_mm){
146 /* This has a pte, but it can't be mapped in with the usual
147 * tlb_flush mechanism because this is part of that mechanism
148 */
149 int fd;
150 __u64 offset;
151
152 fd = phys_mapping(to_phys(&__syscall_stub_start), &offset);
153 addr = mmap64((void *) UML_CONFIG_STUB_CODE, page_size(),
154 PROT_EXEC, MAP_FIXED | MAP_PRIVATE, fd, offset);
155 if(addr == MAP_FAILED){
156 printk("mapping mmap stub failed, errno = %d\n",
157 errno);
158 exit(1);
159 }
160
161 if(stack != NULL){
162 fd = phys_mapping(to_phys(stack), &offset);
163 addr = mmap((void *) UML_CONFIG_STUB_DATA, page_size(),
164 PROT_READ | PROT_WRITE,
165 MAP_FIXED | MAP_SHARED, fd, offset);
166 if(addr == MAP_FAILED){
167 printk("mapping segfault stack failed, "
168 "errno = %d\n", errno);
169 exit(1);
170 }
171 }
172 }
173 if(!ptrace_faultinfo && (stack != NULL)){
174 unsigned long v = UML_CONFIG_STUB_CODE +
175 (unsigned long) stub_segv_handler -
176 (unsigned long) &__syscall_stub_start;
177
178 set_sigstack((void *) UML_CONFIG_STUB_DATA, page_size());
179 set_handler(SIGSEGV, (void *) v, SA_ONSTACK,
180 SIGIO, SIGWINCH, SIGALRM, SIGVTALRM,
181 SIGUSR1, -1);
182 }
183
99 os_stop_process(os_getpid()); 184 os_stop_process(os_getpid());
100 return(0); 185 return(0);
101} 186}
@@ -105,11 +190,11 @@ static int userspace_tramp(void *arg)
105#define NR_CPUS 1 190#define NR_CPUS 1
106int userspace_pid[NR_CPUS]; 191int userspace_pid[NR_CPUS];
107 192
108void start_userspace(int cpu) 193int start_userspace(unsigned long stub_stack)
109{ 194{
110 void *stack; 195 void *stack;
111 unsigned long sp; 196 unsigned long sp;
112 int pid, status, n; 197 int pid, status, n, flags;
113 198
114 stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC, 199 stack = mmap(NULL, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC,
115 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 200 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
@@ -117,8 +202,9 @@ void start_userspace(int cpu)
117 panic("start_userspace : mmap failed, errno = %d", errno); 202 panic("start_userspace : mmap failed, errno = %d", errno);
118 sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *); 203 sp = (unsigned long) stack + PAGE_SIZE - sizeof(void *);
119 204
120 pid = clone(userspace_tramp, (void *) sp, 205 flags = CLONE_FILES | SIGCHLD;
121 CLONE_FILES | CLONE_VM | SIGCHLD, NULL); 206 if(proc_mm) flags |= CLONE_VM;
207 pid = clone(userspace_tramp, (void *) sp, flags, (void *) stub_stack);
122 if(pid < 0) 208 if(pid < 0)
123 panic("start_userspace : clone failed, errno = %d", errno); 209 panic("start_userspace : clone failed, errno = %d", errno);
124 210
@@ -140,7 +226,7 @@ void start_userspace(int cpu)
140 if(munmap(stack, PAGE_SIZE) < 0) 226 if(munmap(stack, PAGE_SIZE) < 0)
141 panic("start_userspace : munmap failed, errno = %d\n", errno); 227 panic("start_userspace : munmap failed, errno = %d\n", errno);
142 228
143 userspace_pid[cpu] = pid; 229 return(pid);
144} 230}
145 231
146void userspace(union uml_pt_regs *regs) 232void userspace(union uml_pt_regs *regs)
@@ -174,7 +260,9 @@ void userspace(union uml_pt_regs *regs)
174 if(WIFSTOPPED(status)){ 260 if(WIFSTOPPED(status)){
175 switch(WSTOPSIG(status)){ 261 switch(WSTOPSIG(status)){
176 case SIGSEGV: 262 case SIGSEGV:
177 handle_segv(pid, regs); 263 if(PTRACE_FULL_FAULTINFO || !ptrace_faultinfo)
264 user_signal(SIGSEGV, regs, pid);
265 else handle_segv(pid, regs);
178 break; 266 break;
179 case SIGTRAP + 0x80: 267 case SIGTRAP + 0x80:
180 handle_trap(pid, regs, local_using_sysemu); 268 handle_trap(pid, regs, local_using_sysemu);
@@ -194,6 +282,7 @@ void userspace(union uml_pt_regs *regs)
194 printk("userspace - child stopped with signal " 282 printk("userspace - child stopped with signal "
195 "%d\n", WSTOPSIG(status)); 283 "%d\n", WSTOPSIG(status));
196 } 284 }
285 pid = userspace_pid[0];
197 interrupt_end(); 286 interrupt_end();
198 287
199 /* Avoid -ERESTARTSYS handling in host */ 288 /* Avoid -ERESTARTSYS handling in host */
@@ -334,21 +423,19 @@ void reboot_skas(void)
334 siglongjmp(initial_jmpbuf, INIT_JMP_REBOOT); 423 siglongjmp(initial_jmpbuf, INIT_JMP_REBOOT);
335} 424}
336 425
337void switch_mm_skas(int mm_fd) 426void switch_mm_skas(struct mm_id *mm_idp)
338{ 427{
339 int err; 428 int err;
340 429
341#warning need cpu pid in switch_mm_skas 430#warning need cpu pid in switch_mm_skas
342 err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0, mm_fd); 431 if(proc_mm){
343 if(err) 432 err = ptrace(PTRACE_SWITCH_MM, userspace_pid[0], 0,
344 panic("switch_mm_skas - PTRACE_SWITCH_MM failed, errno = %d\n", 433 mm_idp->u.mm_fd);
345 errno); 434 if(err)
346} 435 panic("switch_mm_skas - PTRACE_SWITCH_MM failed, "
347 436 "errno = %d\n", errno);
348void kill_off_processes_skas(void) 437 }
349{ 438 else userspace_pid[0] = mm_idp->u.pid;
350#warning need to loop over userspace_pids in kill_off_processes_skas
351 os_kill_ptraced_process(userspace_pid[0], 1);
352} 439}
353 440
354/* 441/*
diff --git a/arch/um/kernel/skas/process_kern.c b/arch/um/kernel/skas/process_kern.c
index 0a7b8aa55db8..cbabab104ac3 100644
--- a/arch/um/kernel/skas/process_kern.c
+++ b/arch/um/kernel/skas/process_kern.c
@@ -175,9 +175,12 @@ static int start_kernel_proc(void *unused)
175 return(0); 175 return(0);
176} 176}
177 177
178extern int userspace_pid[];
179
178int start_uml_skas(void) 180int start_uml_skas(void)
179{ 181{
180 start_userspace(0); 182 if(proc_mm)
183 userspace_pid[0] = start_userspace(0);
181 184
182 init_new_thread_signals(1); 185 init_new_thread_signals(1);
183 186
@@ -199,3 +202,31 @@ int thread_pid_skas(struct task_struct *task)
199#warning Need to look up userspace_pid by cpu 202#warning Need to look up userspace_pid by cpu
200 return(userspace_pid[0]); 203 return(userspace_pid[0]);
201} 204}
205
206void kill_off_processes_skas(void)
207{
208 if(proc_mm)
209#warning need to loop over userspace_pids in kill_off_processes_skas
210 os_kill_ptraced_process(userspace_pid[0], 1);
211 else {
212 struct task_struct *p;
213 int pid, me;
214
215 me = os_getpid();
216 for_each_process(p){
217 if(p->mm == NULL)
218 continue;
219
220 pid = p->mm->context.skas.id.u.pid;
221 os_kill_ptraced_process(pid, 1);
222 }
223 }
224}
225
226unsigned long current_stub_stack(void)
227{
228 if(current->mm == NULL)
229 return(0);
230
231 return(current->mm->context.skas.id.stack);
232}
diff --git a/arch/um/kernel/skas/tlb.c b/arch/um/kernel/skas/tlb.c
index 18f9a7711de1..6230999c672c 100644
--- a/arch/um/kernel/skas/tlb.c
+++ b/arch/um/kernel/skas/tlb.c
@@ -6,6 +6,7 @@
6 6
7#include "linux/stddef.h" 7#include "linux/stddef.h"
8#include "linux/sched.h" 8#include "linux/sched.h"
9#include "linux/config.h"
9#include "linux/mm.h" 10#include "linux/mm.h"
10#include "asm/page.h" 11#include "asm/page.h"
11#include "asm/pgtable.h" 12#include "asm/pgtable.h"
@@ -17,7 +18,7 @@
17#include "os.h" 18#include "os.h"
18#include "tlb.h" 19#include "tlb.h"
19 20
20static void do_ops(int fd, struct host_vm_op *ops, int last) 21static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last)
21{ 22{
22 struct host_vm_op *op; 23 struct host_vm_op *op;
23 int i; 24 int i;
@@ -26,18 +27,18 @@ static void do_ops(int fd, struct host_vm_op *ops, int last)
26 op = &ops[i]; 27 op = &ops[i];
27 switch(op->type){ 28 switch(op->type){
28 case MMAP: 29 case MMAP:
29 map(fd, op->u.mmap.addr, op->u.mmap.len, 30 map(&mmu->skas.id, op->u.mmap.addr, op->u.mmap.len,
30 op->u.mmap.r, op->u.mmap.w, op->u.mmap.x, 31 op->u.mmap.r, op->u.mmap.w, op->u.mmap.x,
31 op->u.mmap.fd, op->u.mmap.offset); 32 op->u.mmap.fd, op->u.mmap.offset);
32 break; 33 break;
33 case MUNMAP: 34 case MUNMAP:
34 unmap(fd, (void *) op->u.munmap.addr, 35 unmap(&mmu->skas.id, (void *) op->u.munmap.addr,
35 op->u.munmap.len); 36 op->u.munmap.len);
36 break; 37 break;
37 case MPROTECT: 38 case MPROTECT:
38 protect(fd, op->u.mprotect.addr, op->u.mprotect.len, 39 protect(&mmu->skas.id, op->u.mprotect.addr,
39 op->u.mprotect.r, op->u.mprotect.w, 40 op->u.mprotect.len, op->u.mprotect.r,
40 op->u.mprotect.x); 41 op->u.mprotect.w, op->u.mprotect.x);
41 break; 42 break;
42 default: 43 default:
43 printk("Unknown op type %d in do_ops\n", op->type); 44 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)
46 } 47 }
47} 48}
48 49
50extern int proc_mm;
51
49static void fix_range(struct mm_struct *mm, unsigned long start_addr, 52static void fix_range(struct mm_struct *mm, unsigned long start_addr,
50 unsigned long end_addr, int force) 53 unsigned long end_addr, int force)
51{ 54{
52 int fd = mm->context.skas.mm_fd; 55 if(!proc_mm && (end_addr > CONFIG_STUB_START))
56 end_addr = CONFIG_STUB_START;
53 57
54 fix_range_common(mm, start_addr, end_addr, force, fd, do_ops); 58 fix_range_common(mm, start_addr, end_addr, force, do_ops);
55} 59}
56 60
57void __flush_tlb_one_skas(unsigned long addr) 61void __flush_tlb_one_skas(unsigned long addr)
@@ -69,16 +73,20 @@ void flush_tlb_range_skas(struct vm_area_struct *vma, unsigned long start,
69 73
70void flush_tlb_mm_skas(struct mm_struct *mm) 74void flush_tlb_mm_skas(struct mm_struct *mm)
71{ 75{
76 unsigned long end;
77
72 /* Don't bother flushing if this address space is about to be 78 /* Don't bother flushing if this address space is about to be
73 * destroyed. 79 * destroyed.
74 */ 80 */
75 if(atomic_read(&mm->mm_users) == 0) 81 if(atomic_read(&mm->mm_users) == 0)
76 return; 82 return;
77 83
78 fix_range(mm, 0, host_task_size, 0); 84 end = proc_mm ? task_size : CONFIG_STUB_START;
85 fix_range(mm, 0, end, 0);
79} 86}
80 87
81void force_flush_all_skas(void) 88void force_flush_all_skas(void)
82{ 89{
83 fix_range(current->mm, 0, host_task_size, 1); 90 unsigned long end = proc_mm ? task_size : CONFIG_STUB_START;
91 fix_range(current->mm, 0, end, 1);
84} 92}
diff --git a/arch/um/kernel/tlb.c b/arch/um/kernel/tlb.c
index eda477edfdf5..83ec8d4747fd 100644
--- a/arch/um/kernel/tlb.c
+++ b/arch/um/kernel/tlb.c
@@ -18,13 +18,15 @@
18#define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1)) 18#define ADD_ROUND(n, inc) (((n) + (inc)) & ~((inc) - 1))
19 19
20void fix_range_common(struct mm_struct *mm, unsigned long start_addr, 20void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
21 unsigned long end_addr, int force, int data, 21 unsigned long end_addr, int force,
22 void (*do_ops)(int, struct host_vm_op *, int)) 22 void (*do_ops)(union mm_context *, struct host_vm_op *,
23 int))
23{ 24{
24 pgd_t *npgd; 25 pgd_t *npgd;
25 pud_t *npud; 26 pud_t *npud;
26 pmd_t *npmd; 27 pmd_t *npmd;
27 pte_t *npte; 28 pte_t *npte;
29 union mm_context *mmu = &mm->context;
28 unsigned long addr, end; 30 unsigned long addr, end;
29 int r, w, x; 31 int r, w, x;
30 struct host_vm_op ops[16]; 32 struct host_vm_op ops[16];
@@ -40,7 +42,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
40 end = end_addr; 42 end = end_addr;
41 if(force || pgd_newpage(*npgd)){ 43 if(force || pgd_newpage(*npgd)){
42 op_index = add_munmap(addr, end - addr, ops, 44 op_index = add_munmap(addr, end - addr, ops,
43 op_index, last_op, data, 45 op_index, last_op, mmu,
44 do_ops); 46 do_ops);
45 pgd_mkuptodate(*npgd); 47 pgd_mkuptodate(*npgd);
46 } 48 }
@@ -55,7 +57,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
55 end = end_addr; 57 end = end_addr;
56 if(force || pud_newpage(*npud)){ 58 if(force || pud_newpage(*npud)){
57 op_index = add_munmap(addr, end - addr, ops, 59 op_index = add_munmap(addr, end - addr, ops,
58 op_index, last_op, data, 60 op_index, last_op, mmu,
59 do_ops); 61 do_ops);
60 pud_mkuptodate(*npud); 62 pud_mkuptodate(*npud);
61 } 63 }
@@ -70,7 +72,7 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
70 end = end_addr; 72 end = end_addr;
71 if(force || pmd_newpage(*npmd)){ 73 if(force || pmd_newpage(*npmd)){
72 op_index = add_munmap(addr, end - addr, ops, 74 op_index = add_munmap(addr, end - addr, ops,
73 op_index, last_op, data, 75 op_index, last_op, mmu,
74 do_ops); 76 do_ops);
75 pmd_mkuptodate(*npmd); 77 pmd_mkuptodate(*npmd);
76 } 78 }
@@ -93,21 +95,21 @@ void fix_range_common(struct mm_struct *mm, unsigned long start_addr,
93 op_index = add_mmap(addr, 95 op_index = add_mmap(addr,
94 pte_val(*npte) & PAGE_MASK, 96 pte_val(*npte) & PAGE_MASK,
95 PAGE_SIZE, r, w, x, ops, 97 PAGE_SIZE, r, w, x, ops,
96 op_index, last_op, data, 98 op_index, last_op, mmu,
97 do_ops); 99 do_ops);
98 else op_index = add_munmap(addr, PAGE_SIZE, ops, 100 else op_index = add_munmap(addr, PAGE_SIZE, ops,
99 op_index, last_op, data, 101 op_index, last_op, mmu,
100 do_ops); 102 do_ops);
101 } 103 }
102 else if(pte_newprot(*npte)) 104 else if(pte_newprot(*npte))
103 op_index = add_mprotect(addr, PAGE_SIZE, r, w, x, ops, 105 op_index = add_mprotect(addr, PAGE_SIZE, r, w, x, ops,
104 op_index, last_op, data, 106 op_index, last_op, mmu,
105 do_ops); 107 do_ops);
106 108
107 *npte = pte_mkuptodate(*npte); 109 *npte = pte_mkuptodate(*npte);
108 addr += PAGE_SIZE; 110 addr += PAGE_SIZE;
109 } 111 }
110 (*do_ops)(data, ops, op_index); 112 (*do_ops)(mmu, ops, op_index);
111} 113}
112 114
113int flush_tlb_kernel_range_common(unsigned long start, unsigned long end) 115int 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)
195 return(updated); 197 return(updated);
196} 198}
197 199
198void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
199{
200 address &= PAGE_MASK;
201 flush_tlb_range(vma, address, address + PAGE_SIZE);
202}
203
204void flush_tlb_all(void)
205{
206 flush_tlb_mm(current->mm);
207}
208
209void flush_tlb_kernel_range(unsigned long start, unsigned long end)
210{
211 CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt,
212 flush_tlb_kernel_range_common, start, end);
213}
214
215void flush_tlb_kernel_vm(void)
216{
217 CHOOSE_MODE(flush_tlb_kernel_vm_tt(),
218 flush_tlb_kernel_range_common(start_vm, end_vm));
219}
220
221void __flush_tlb_one(unsigned long addr)
222{
223 CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
224}
225
226void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
227 unsigned long end)
228{
229 CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start,
230 end);
231}
232
233void flush_tlb_mm(struct mm_struct *mm)
234{
235 CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm);
236}
237
238void force_flush_all(void)
239{
240 CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas());
241}
242
243pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address) 200pgd_t *pgd_offset_proc(struct mm_struct *mm, unsigned long address)
244{ 201{
245 return(pgd_offset(mm, address)); 202 return(pgd_offset(mm, address));
@@ -270,9 +227,9 @@ pte_t *addr_pte(struct task_struct *task, unsigned long addr)
270} 227}
271 228
272int add_mmap(unsigned long virt, unsigned long phys, unsigned long len, 229int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
273 int r, int w, int x, struct host_vm_op *ops, int index, 230 int r, int w, int x, struct host_vm_op *ops, int index,
274 int last_filled, int data, 231 int last_filled, union mm_context *mmu,
275 void (*do_ops)(int, struct host_vm_op *, int)) 232 void (*do_ops)(union mm_context *, struct host_vm_op *, int))
276{ 233{
277 __u64 offset; 234 __u64 offset;
278 struct host_vm_op *last; 235 struct host_vm_op *last;
@@ -292,7 +249,7 @@ int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
292 } 249 }
293 250
294 if(index == last_filled){ 251 if(index == last_filled){
295 (*do_ops)(data, ops, last_filled); 252 (*do_ops)(mmu, ops, last_filled);
296 index = -1; 253 index = -1;
297 } 254 }
298 255
@@ -310,8 +267,8 @@ int add_mmap(unsigned long virt, unsigned long phys, unsigned long len,
310} 267}
311 268
312int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops, 269int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
313 int index, int last_filled, int data, 270 int index, int last_filled, union mm_context *mmu,
314 void (*do_ops)(int, struct host_vm_op *, int)) 271 void (*do_ops)(union mm_context *, struct host_vm_op *, int))
315{ 272{
316 struct host_vm_op *last; 273 struct host_vm_op *last;
317 274
@@ -325,7 +282,7 @@ int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
325 } 282 }
326 283
327 if(index == last_filled){ 284 if(index == last_filled){
328 (*do_ops)(data, ops, last_filled); 285 (*do_ops)(mmu, ops, last_filled);
329 index = -1; 286 index = -1;
330 } 287 }
331 288
@@ -337,8 +294,9 @@ int add_munmap(unsigned long addr, unsigned long len, struct host_vm_op *ops,
337} 294}
338 295
339int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x, 296int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
340 struct host_vm_op *ops, int index, int last_filled, int data, 297 struct host_vm_op *ops, int index, int last_filled,
341 void (*do_ops)(int, struct host_vm_op *, int)) 298 union mm_context *mmu,
299 void (*do_ops)(union mm_context *, struct host_vm_op *, int))
342{ 300{
343 struct host_vm_op *last; 301 struct host_vm_op *last;
344 302
@@ -354,7 +312,7 @@ int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
354 } 312 }
355 313
356 if(index == last_filled){ 314 if(index == last_filled){
357 (*do_ops)(data, ops, last_filled); 315 (*do_ops)(mmu, ops, last_filled);
358 index = -1; 316 index = -1;
359 } 317 }
360 318
@@ -367,3 +325,49 @@ int add_mprotect(unsigned long addr, unsigned long len, int r, int w, int x,
367 .x = x } } }); 325 .x = x } } });
368 return(index); 326 return(index);
369} 327}
328
329void flush_tlb_page(struct vm_area_struct *vma, unsigned long address)
330{
331 address &= PAGE_MASK;
332 flush_tlb_range(vma, address, address + PAGE_SIZE);
333}
334
335void flush_tlb_all(void)
336{
337 flush_tlb_mm(current->mm);
338}
339
340void flush_tlb_kernel_range(unsigned long start, unsigned long end)
341{
342 CHOOSE_MODE_PROC(flush_tlb_kernel_range_tt,
343 flush_tlb_kernel_range_common, start, end);
344}
345
346void flush_tlb_kernel_vm(void)
347{
348 CHOOSE_MODE(flush_tlb_kernel_vm_tt(),
349 flush_tlb_kernel_range_common(start_vm, end_vm));
350}
351
352void __flush_tlb_one(unsigned long addr)
353{
354 CHOOSE_MODE_PROC(__flush_tlb_one_tt, __flush_tlb_one_skas, addr);
355}
356
357void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
358 unsigned long end)
359{
360 CHOOSE_MODE_PROC(flush_tlb_range_tt, flush_tlb_range_skas, vma, start,
361 end);
362}
363
364void flush_tlb_mm(struct mm_struct *mm)
365{
366 CHOOSE_MODE_PROC(flush_tlb_mm_tt, flush_tlb_mm_skas, mm);
367}
368
369void force_flush_all(void)
370{
371 CHOOSE_MODE(force_flush_all_tt(), force_flush_all_skas());
372}
373
diff --git a/arch/um/kernel/tt/tlb.c b/arch/um/kernel/tt/tlb.c
index 203216ad86f1..2eefb43bc9c2 100644
--- a/arch/um/kernel/tt/tlb.c
+++ b/arch/um/kernel/tt/tlb.c
@@ -17,7 +17,7 @@
17#include "os.h" 17#include "os.h"
18#include "tlb.h" 18#include "tlb.h"
19 19
20static void do_ops(int unused, struct host_vm_op *ops, int last) 20static void do_ops(union mm_context *mmu, struct host_vm_op *ops, int last)
21{ 21{
22 struct host_vm_op *op; 22 struct host_vm_op *op;
23 int i; 23 int i;
@@ -55,7 +55,7 @@ static void fix_range(struct mm_struct *mm, unsigned long start_addr,
55 panic("fix_range fixing wrong address space, current = 0x%p", 55 panic("fix_range fixing wrong address space, current = 0x%p",
56 current); 56 current);
57 57
58 fix_range_common(mm, start_addr, end_addr, force, 0, do_ops); 58 fix_range_common(mm, start_addr, end_addr, force, do_ops);
59} 59}
60 60
61atomic_t vmchange_seq = ATOMIC_INIT(1); 61atomic_t vmchange_seq = ATOMIC_INIT(1);
diff --git a/arch/um/kernel/uml.lds.S b/arch/um/kernel/uml.lds.S
index 61dfd4fef752..163476a8cb1b 100644
--- a/arch/um/kernel/uml.lds.S
+++ b/arch/um/kernel/uml.lds.S
@@ -30,6 +30,7 @@ SECTIONS
30 _einittext = .; 30 _einittext = .;
31 } 31 }
32 . = ALIGN(4096); 32 . = ALIGN(4096);
33
33 .text : 34 .text :
34 { 35 {
35 *(.text) 36 *(.text)
@@ -39,6 +40,12 @@ SECTIONS
39 /* .gnu.warning sections are handled specially by elf32.em. */ 40 /* .gnu.warning sections are handled specially by elf32.em. */
40 *(.gnu.warning) 41 *(.gnu.warning)
41 *(.gnu.linkonce.t*) 42 *(.gnu.linkonce.t*)
43
44 . = ALIGN(4096);
45 __syscall_stub_start = .;
46 *(.__syscall_stub*)
47 __syscall_stub_end = .;
48 . = ALIGN(4096);
42 } 49 }
43 50
44 #include "asm/common.lds.S" 51 #include "asm/common.lds.S"
diff --git a/arch/um/os-Linux/sys-i386/registers.c b/arch/um/os-Linux/sys-i386/registers.c
index 9a0ad094d926..3125d320722c 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)
121 err); 121 err);
122} 122}
123 123
124void get_safe_registers(unsigned long *regs)
125{
126 memcpy(regs, exec_regs, HOST_FRAME_SIZE * sizeof(unsigned long));
127}
128
124/* 129/*
125 * Overrides for Emacs so that we follow Linus's tabbing style. 130 * Overrides for Emacs so that we follow Linus's tabbing style.
126 * Emacs will notice this stuff at the end of the file and automatically 131 * 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 6286c974bbeb..44438d15c3d6 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)
69 err); 69 err);
70} 70}
71 71
72void get_safe_registers(unsigned long *regs)
73{
74 memcpy(regs, exec_regs, HOST_FRAME_SIZE * sizeof(unsigned long));
75}
76
72/* 77/*
73 * Overrides for Emacs so that we follow Linus's tabbing style. 78 * Overrides for Emacs so that we follow Linus's tabbing style.
74 * Emacs will notice this stuff at the end of the file and automatically 79 * 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 7459d09c233e..17f305b6bade 100644
--- a/arch/um/scripts/Makefile.rules
+++ b/arch/um/scripts/Makefile.rules
@@ -16,6 +16,11 @@ define unprofile
16endef 16endef
17 17
18 18
19# The stubs and unmap.o can't try to call mcount or update basic block data
20define unprofile
21 $(patsubst -pg,,$(patsubst -fprofile-arcs -ftest-coverage,,$(1)))
22endef
23
19quiet_cmd_make_link = SYMLINK $@ 24quiet_cmd_make_link = SYMLINK $@
20cmd_make_link = ln -sf $(srctree)/arch/$(SUBARCH)/$($(notdir $@)-dir)/$(notdir $@) $@ 25cmd_make_link = ln -sf $(srctree)/arch/$(SUBARCH)/$($(notdir $@)-dir)/$(notdir $@) $@
21 26
diff --git a/arch/um/sys-i386/Makefile b/arch/um/sys-i386/Makefile
index 095bcdb0b9cc..77c3c4d29f55 100644
--- a/arch/um/sys-i386/Makefile
+++ b/arch/um/sys-i386/Makefile
@@ -1,6 +1,6 @@
1obj-y = bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \ 1obj-y = bitops.o bugs.o checksum.o delay.o fault.o ksyms.o ldt.o ptrace.o \
2 ptrace_user.o semaphore.o signal.o sigcontext.o syscalls.o sysrq.o \ 2 ptrace_user.o semaphore.o signal.o sigcontext.o stub.o stub_segv.o \
3 sys_call_table.o 3 syscalls.o sysrq.o sys_call_table.o
4 4
5obj-$(CONFIG_HIGHMEM) += highmem.o 5obj-$(CONFIG_HIGHMEM) += highmem.o
6obj-$(CONFIG_MODULES) += module.o 6obj-$(CONFIG_MODULES) += module.o
@@ -16,6 +16,14 @@ semaphore.c-dir = kernel
16highmem.c-dir = mm 16highmem.c-dir = mm
17module.c-dir = kernel 17module.c-dir = kernel
18 18
19STUB_CFLAGS = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
20
21# _cflags works with kernel files, not with userspace ones, but c_flags does,
22# why ask why?
23$(obj)/stub_segv.o : c_flags = $(STUB_CFLAGS)
24
25$(obj)/stub.o : a_flags = $(STUB_CFLAGS)
26
19subdir- := util 27subdir- := util
20 28
21include arch/um/scripts/Makefile.unmap 29include arch/um/scripts/Makefile.unmap
diff --git a/arch/um/sys-i386/stub.S b/arch/um/sys-i386/stub.S
new file mode 100644
index 000000000000..2f2c70a8f043
--- /dev/null
+++ b/arch/um/sys-i386/stub.S
@@ -0,0 +1,8 @@
1#include "uml-config.h"
2
3 .globl syscall_stub
4.section .__syscall_stub, "x"
5syscall_stub:
6 int $0x80
7 mov %eax, UML_CONFIG_STUB_DATA
8 int3
diff --git a/arch/um/sys-i386/stub_segv.c b/arch/um/sys-i386/stub_segv.c
new file mode 100644
index 000000000000..b251442ad0b1
--- /dev/null
+++ b/arch/um/sys-i386/stub_segv.c
@@ -0,0 +1,30 @@
1/*
2 * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include <signal.h>
7#include <asm/sigcontext.h>
8#include <asm/unistd.h>
9#include "uml-config.h"
10#include "sysdep/sigcontext.h"
11#include "sysdep/faultinfo.h"
12
13void __attribute__ ((__section__ (".__syscall_stub")))
14stub_segv_handler(int sig)
15{
16 struct sigcontext *sc = (struct sigcontext *) (&sig + 1);
17
18 GET_FAULTINFO_FROM_SC(*((struct faultinfo *) UML_CONFIG_STUB_DATA),
19 sc);
20
21 __asm__("movl %0, %%eax ; int $0x80": : "g" (__NR_getpid));
22 __asm__("movl %%eax, %%ebx ; movl %0, %%eax ; movl %1, %%ecx ;"
23 "int $0x80": : "g" (__NR_kill), "g" (SIGUSR1));
24 /* Pop the frame pointer and return address since we need to leave
25 * the stack in its original form when we do the sigreturn here, by
26 * hand.
27 */
28 __asm__("popl %%eax ; popl %%eax ; popl %%eax ; movl %0, %%eax ; "
29 "int $0x80" : : "g" (__NR_sigreturn));
30}
diff --git a/arch/um/sys-x86_64/Makefile b/arch/um/sys-x86_64/Makefile
index 2bc6f6849010..7488206ce6f4 100644
--- a/arch/um/sys-x86_64/Makefile
+++ b/arch/um/sys-x86_64/Makefile
@@ -6,8 +6,8 @@
6 6
7#XXX: why into lib-y? 7#XXX: why into lib-y?
8lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o mem.o memcpy.o \ 8lib-y = bitops.o bugs.o csum-partial.o delay.o fault.o mem.o memcpy.o \
9 ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o \ 9 ptrace.o ptrace_user.o semaphore.o sigcontext.o signal.o stub.o \
10 syscalls.o sysrq.o thunk.o syscall_table.o 10 stub_segv.o syscalls.o syscall_table.o sysrq.o thunk.o
11 11
12obj-y := ksyms.o 12obj-y := ksyms.o
13obj-$(CONFIG_MODULES) += module.o um_module.o 13obj-$(CONFIG_MODULES) += module.o um_module.o
@@ -28,6 +28,14 @@ semaphore.c-dir = kernel
28thunk.S-dir = lib 28thunk.S-dir = lib
29module.c-dir = kernel 29module.c-dir = kernel
30 30
31STUB_CFLAGS = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS))
32
33# _cflags works with kernel files, not with userspace ones, but c_flags does,
34# why ask why?
35$(obj)/stub_segv.o : c_flags = $(STUB_CFLAGS)
36
37$(obj)/stub.o : a_flags = $(STUB_CFLAGS)
38
31subdir- := util 39subdir- := util
32 40
33include arch/um/scripts/Makefile.unmap 41include arch/um/scripts/Makefile.unmap
diff --git a/arch/um/sys-x86_64/stub.S b/arch/um/sys-x86_64/stub.S
new file mode 100644
index 000000000000..31c14925716b
--- /dev/null
+++ b/arch/um/sys-x86_64/stub.S
@@ -0,0 +1,15 @@
1#include "uml-config.h"
2
3 .globl syscall_stub
4.section .__syscall_stub, "x"
5syscall_stub:
6 syscall
7 /* We don't have 64-bit constants, so this constructs the address
8 * we need.
9 */
10 movq $(UML_CONFIG_STUB_DATA >> 32), %rbx
11 salq $32, %rbx
12 movq $(UML_CONFIG_STUB_DATA & 0xffffffff), %rcx
13 or %rcx, %rbx
14 movq %rax, (%rbx)
15 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 000000000000..161d1fe9c034
--- /dev/null
+++ b/arch/um/sys-x86_64/stub_segv.c
@@ -0,0 +1,31 @@
1/*
2 * Copyright (C) 2004 Jeff Dike (jdike@addtoit.com)
3 * Licensed under the GPL
4 */
5
6#include <signal.h>
7#include <linux/compiler.h>
8#include <asm/unistd.h>
9#include "uml-config.h"
10#include "sysdep/sigcontext.h"
11#include "sysdep/faultinfo.h"
12
13void __attribute__ ((__section__ (".__syscall_stub")))
14stub_segv_handler(int sig)
15{
16 struct ucontext *uc;
17
18 __asm__("movq %%rdx, %0" : "=g" (uc) :);
19 GET_FAULTINFO_FROM_SC(*((struct faultinfo *) UML_CONFIG_STUB_DATA),
20 &uc->uc_mcontext);
21
22 __asm__("movq %0, %%rax ; syscall": : "g" (__NR_getpid));
23 __asm__("movq %%rax, %%rdi ; movq %0, %%rax ; movq %1, %%rsi ;"
24 "syscall": : "g" (__NR_kill), "g" (SIGUSR1));
25 /* Two popqs to restore the stack to the state just before entering
26 * the handler, one pops the return address, the other pops the frame
27 * pointer.
28 */
29 __asm__("popq %%rax ; popq %%rax ; movq %0, %%rax ; syscall" : : "g"
30 (__NR_rt_sigreturn));
31}