aboutsummaryrefslogtreecommitdiffstats
path: root/arch/um
diff options
context:
space:
mode:
authorBodo Stroesser <bstroesser@fujitsu-siemens.com>2005-07-07 20:56:50 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-07-07 21:23:44 -0400
commit9786a8f3cbc61f990266e23ffdb338ee3118b03d (patch)
treec987811d30508728f954cc8aaa14de1f7fa5b44a /arch/um
parentd67b569f5f620c0fb95d5212642746b7ba9d29e4 (diff)
[PATCH] uml: Proper clone support for skas0
This patch implements the clone-stub mechanism, which allows skas0 to run with proc_mm==0, even if the clib in UML uses modify_ldt. Note: There is a bug in skas3.v7 host patch, that avoids UML-skas from running properly on a SMP-box. In full skas3, I never really saw problems, but in skas0 they showed up. More commentary by jdike - What this patch does is makes sure that the host parent of each new host process matches the UML parent of the corresponding UML process. This ensures that any changed LDTs are inherited. This is done by having clone actually called by the UML process from its stub, rather than by the kernel. We have special syscall stubs that are loaded onto the stub code page because that code must be completely self-contained. These stubs are given C interfaces, and used like normal C functions, but there are subtleties. Principally, we have to be careful about stack variables in stub_clone_handler after the clone. The code is written so that there aren't any - everything boils down to a fixed address. If there were any locals, references to them after the clone would be wrong because the stack just changed. Signed-off-by: Bodo Stroesser <bstroesser@fujitsu-siemens.com> 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/include/sysdep-i386/stub.h47
-rw-r--r--arch/um/include/sysdep-x86_64/stub.h39
-rw-r--r--arch/um/include/time_user.h1
-rw-r--r--arch/um/kernel/skas/Makefile7
-rw-r--r--arch/um/kernel/skas/clone.c44
-rw-r--r--arch/um/kernel/skas/include/skas.h1
-rw-r--r--arch/um/kernel/skas/include/stub-data.h18
-rw-r--r--arch/um/kernel/skas/mmu.c7
-rw-r--r--arch/um/kernel/skas/process.c63
-rw-r--r--arch/um/kernel/time.c7
10 files changed, 231 insertions, 3 deletions
diff --git a/arch/um/include/sysdep-i386/stub.h b/arch/um/include/sysdep-i386/stub.h
index fed9ff1cea52..d3699fe1c613 100644
--- a/arch/um/include/sysdep-i386/stub.h
+++ b/arch/um/include/sysdep-i386/stub.h
@@ -10,9 +10,56 @@
10#include <asm/unistd.h> 10#include <asm/unistd.h>
11 11
12extern void stub_segv_handler(int sig); 12extern void stub_segv_handler(int sig);
13extern void stub_clone_handler(void);
13 14
14#define STUB_SYSCALL_RET EAX 15#define STUB_SYSCALL_RET EAX
15#define STUB_MMAP_NR __NR_mmap2 16#define STUB_MMAP_NR __NR_mmap2
16#define MMAP_OFFSET(o) ((o) >> PAGE_SHIFT) 17#define MMAP_OFFSET(o) ((o) >> PAGE_SHIFT)
17 18
19static inline long stub_syscall2(long syscall, long arg1, long arg2)
20{
21 long ret;
22
23 __asm__("movl %0, %%ecx; " : : "g" (arg2) : "%ecx");
24 __asm__("movl %0, %%ebx; " : : "g" (arg1) : "%ebx");
25 __asm__("movl %0, %%eax; " : : "g" (syscall) : "%eax");
26 __asm__("int $0x80;" : : : "%eax");
27 __asm__ __volatile__("movl %%eax, %0; " : "=g" (ret) :);
28 return(ret);
29}
30
31static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3)
32{
33 __asm__("movl %0, %%edx; " : : "g" (arg3) : "%edx");
34 return(stub_syscall2(syscall, arg1, arg2));
35}
36
37static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3,
38 long arg4)
39{
40 __asm__("movl %0, %%esi; " : : "g" (arg4) : "%esi");
41 return(stub_syscall3(syscall, arg1, arg2, arg3));
42}
43
44static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3,
45 long arg4, long arg5, long arg6)
46{
47 long ret;
48 __asm__("movl %0, %%eax; " : : "g" (syscall) : "%eax");
49 __asm__("movl %0, %%ebx; " : : "g" (arg1) : "%ebx");
50 __asm__("movl %0, %%ecx; " : : "g" (arg2) : "%ecx");
51 __asm__("movl %0, %%edx; " : : "g" (arg3) : "%edx");
52 __asm__("movl %0, %%esi; " : : "g" (arg4) : "%esi");
53 __asm__("movl %0, %%edi; " : : "g" (arg5) : "%edi");
54 __asm__ __volatile__("pushl %%ebp ; movl %1, %%ebp; "
55 "int $0x80; popl %%ebp ; "
56 "movl %%eax, %0; " : "=g" (ret) : "g" (arg6) : "%eax");
57 return(ret);
58}
59
60static inline void trap_myself(void)
61{
62 __asm("int3");
63}
64
18#endif 65#endif
diff --git a/arch/um/include/sysdep-x86_64/stub.h b/arch/um/include/sysdep-x86_64/stub.h
index 6b5447ad590d..f599058d8263 100644
--- a/arch/um/include/sysdep-x86_64/stub.h
+++ b/arch/um/include/sysdep-x86_64/stub.h
@@ -11,9 +11,48 @@
11#include <sysdep/ptrace_user.h> 11#include <sysdep/ptrace_user.h>
12 12
13extern void stub_segv_handler(int sig); 13extern void stub_segv_handler(int sig);
14extern void stub_clone_handler(void);
14 15
15#define STUB_SYSCALL_RET PT_INDEX(RAX) 16#define STUB_SYSCALL_RET PT_INDEX(RAX)
16#define STUB_MMAP_NR __NR_mmap 17#define STUB_MMAP_NR __NR_mmap
17#define MMAP_OFFSET(o) (o) 18#define MMAP_OFFSET(o) (o)
18 19
20static inline long stub_syscall2(long syscall, long arg1, long arg2)
21{
22 long ret;
23
24 __asm__("movq %0, %%rsi; " : : "g" (arg2) : "%rsi");
25 __asm__("movq %0, %%rdi; " : : "g" (arg1) : "%rdi");
26 __asm__("movq %0, %%rax; " : : "g" (syscall) : "%rax");
27 __asm__("syscall;" : : : "%rax", "%r11", "%rcx");
28 __asm__ __volatile__("movq %%rax, %0; " : "=g" (ret) :);
29 return(ret);
30}
31
32static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3)
33{
34 __asm__("movq %0, %%rdx; " : : "g" (arg3) : "%rdx");
35 return(stub_syscall2(syscall, arg1, arg2));
36}
37
38static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3,
39 long arg4)
40{
41 __asm__("movq %0, %%r10; " : : "g" (arg4) : "%r10");
42 return(stub_syscall3(syscall, arg1, arg2, arg3));
43}
44
45static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3,
46 long arg4, long arg5, long arg6)
47{
48 __asm__("movq %0, %%r9; " : : "g" (arg6) : "%r9");
49 __asm__("movq %0, %%r8; " : : "g" (arg5) : "%r8");
50 return(stub_syscall4(syscall, arg1, arg2, arg3, arg4));
51}
52
53static inline void trap_myself(void)
54{
55 __asm("int3");
56}
57
19#endif 58#endif
diff --git a/arch/um/include/time_user.h b/arch/um/include/time_user.h
index f64ef77019a3..17d7ef2141f4 100644
--- a/arch/um/include/time_user.h
+++ b/arch/um/include/time_user.h
@@ -10,6 +10,7 @@ extern void timer(void);
10extern void switch_timers(int to_real); 10extern void switch_timers(int to_real);
11extern void idle_sleep(int secs); 11extern void idle_sleep(int secs);
12extern void enable_timer(void); 12extern void enable_timer(void);
13extern void prepare_timer(void * ptr);
13extern void disable_timer(void); 14extern void disable_timer(void);
14extern unsigned long time_lock(void); 15extern unsigned long time_lock(void);
15extern void time_unlock(unsigned long); 16extern void time_unlock(unsigned long);
diff --git a/arch/um/kernel/skas/Makefile b/arch/um/kernel/skas/Makefile
index ff69c4b312c0..d296d55ade4b 100644
--- a/arch/um/kernel/skas/Makefile
+++ b/arch/um/kernel/skas/Makefile
@@ -3,11 +3,14 @@
3# Licensed under the GPL 3# Licensed under the GPL
4# 4#
5 5
6obj-y := exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \ 6obj-y := clone.o exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \
7 syscall_kern.o syscall_user.o tlb.o trap_user.o uaccess.o \ 7 syscall_kern.o syscall_user.o tlb.o trap_user.o uaccess.o \
8 8
9subdir- := util 9subdir- := util
10 10
11USER_OBJS := process.o 11USER_OBJS := process.o clone.o
12 12
13include arch/um/scripts/Makefile.rules 13include arch/um/scripts/Makefile.rules
14
15# clone.o is in the stub, so it can't be built with profiling
16$(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 000000000000..4dc55f10cd18
--- /dev/null
+++ b/arch/um/kernel/skas/clone.c
@@ -0,0 +1,44 @@
1#include <sched.h>
2#include <signal.h>
3#include <sys/mman.h>
4#include <sys/time.h>
5#include <asm/unistd.h>
6#include <asm/page.h>
7#include "ptrace_user.h"
8#include "skas.h"
9#include "stub-data.h"
10#include "uml-config.h"
11#include "sysdep/stub.h"
12
13/* This is in a separate file because it needs to be compiled with any
14 * extraneous gcc flags (-pg, -fprofile-arcs, -ftest-coverage) disabled
15 */
16void __attribute__ ((__section__ (".__syscall_stub")))
17stub_clone_handler(void)
18{
19 long err;
20 struct stub_data *from = (struct stub_data *) UML_CONFIG_STUB_DATA;
21
22 err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD,
23 UML_CONFIG_STUB_DATA + PAGE_SIZE / 2 -
24 sizeof(void *));
25 if(err != 0)
26 goto out;
27
28 err = stub_syscall4(__NR_ptrace, PTRACE_TRACEME, 0, 0, 0);
29 if(err)
30 goto out;
31
32 err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL,
33 (long) &from->timer, 0);
34 if(err)
35 goto out;
36
37 err = stub_syscall6(STUB_MMAP_NR, UML_CONFIG_STUB_DATA, PAGE_SIZE,
38 PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED,
39 from->fd, from->offset);
40 out:
41 /* save current result. Parent: pid; child: retcode of mmap */
42 from->err = err;
43 trap_myself();
44}
diff --git a/arch/um/kernel/skas/include/skas.h b/arch/um/kernel/skas/include/skas.h
index d91a60f3830a..d983ea842547 100644
--- a/arch/um/kernel/skas/include/skas.h
+++ b/arch/um/kernel/skas/include/skas.h
@@ -32,6 +32,7 @@ extern int protect(struct mm_id * mm_idp, unsigned long addr,
32extern 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);
33extern int new_mm(int from); 33extern int new_mm(int from);
34extern int start_userspace(unsigned long stub_stack); 34extern int start_userspace(unsigned long stub_stack);
35extern int copy_context_skas0(unsigned long stack, int pid);
35extern void get_skas_faultinfo(int pid, struct faultinfo * fi); 36extern void get_skas_faultinfo(int pid, struct faultinfo * fi);
36extern long execute_syscall_skas(void *r); 37extern long execute_syscall_skas(void *r);
37extern unsigned long current_stub_stack(void); 38extern unsigned long current_stub_stack(void);
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 000000000000..f6ed92c3727d
--- /dev/null
+++ b/arch/um/kernel/skas/include/stub-data.h
@@ -0,0 +1,18 @@
1/*
2 * Copyright (C) 2005 Jeff Dike (jdike@karaya.com)
3 * Licensed under the GPL
4 */
5
6#ifndef __STUB_DATA_H
7#define __STUB_DATA_H
8
9#include <sys/time.h>
10
11struct stub_data {
12 long offset;
13 int fd;
14 struct itimerval timer;
15 long err;
16};
17
18#endif
diff --git a/arch/um/kernel/skas/mmu.c b/arch/um/kernel/skas/mmu.c
index 511a855c9ec0..d232daa42c31 100644
--- a/arch/um/kernel/skas/mmu.c
+++ b/arch/um/kernel/skas/mmu.c
@@ -75,6 +75,7 @@ static int init_stub_pte(struct mm_struct *mm, unsigned long proc,
75int 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)
76{ 76{
77 struct mm_struct *cur_mm = current->mm; 77 struct mm_struct *cur_mm = current->mm;
78 struct mm_id *cur_mm_id = &cur_mm->context.skas.id;
78 struct mm_id *mm_id = &mm->context.skas.id; 79 struct mm_id *mm_id = &mm->context.skas.id;
79 unsigned long stack; 80 unsigned long stack;
80 int from, ret; 81 int from, ret;
@@ -115,7 +116,11 @@ int init_new_context_skas(struct task_struct *task, struct mm_struct *mm)
115 goto out_free; 116 goto out_free;
116 117
117 mm->nr_ptes--; 118 mm->nr_ptes--;
118 mm_id->u.pid = start_userspace(stack); 119
120 if((cur_mm != NULL) && (cur_mm != &init_mm))
121 mm_id->u.pid = copy_context_skas0(stack,
122 cur_mm_id->u.pid);
123 else mm_id->u.pid = start_userspace(stack);
119 } 124 }
120 125
121 return 0; 126 return 0;
diff --git a/arch/um/kernel/skas/process.c b/arch/um/kernel/skas/process.c
index 1647abb0d1aa..ba671dab8878 100644
--- a/arch/um/kernel/skas/process.c
+++ b/arch/um/kernel/skas/process.c
@@ -13,6 +13,7 @@
13#include <sys/wait.h> 13#include <sys/wait.h>
14#include <sys/mman.h> 14#include <sys/mman.h>
15#include <sys/user.h> 15#include <sys/user.h>
16#include <sys/time.h>
16#include <asm/unistd.h> 17#include <asm/unistd.h>
17#include <asm/types.h> 18#include <asm/types.h>
18#include "user.h" 19#include "user.h"
@@ -22,6 +23,7 @@
22#include "user_util.h" 23#include "user_util.h"
23#include "kern_util.h" 24#include "kern_util.h"
24#include "skas.h" 25#include "skas.h"
26#include "stub-data.h"
25#include "mm_id.h" 27#include "mm_id.h"
26#include "sysdep/sigcontext.h" 28#include "sysdep/sigcontext.h"
27#include "sysdep/stub.h" 29#include "sysdep/stub.h"
@@ -296,6 +298,67 @@ void userspace(union uml_pt_regs *regs)
296#define INIT_JMP_HALT 3 298#define INIT_JMP_HALT 3
297#define INIT_JMP_REBOOT 4 299#define INIT_JMP_REBOOT 4
298 300
301
302int copy_context_skas0(unsigned long new_stack, int pid)
303{
304 int err;
305 unsigned long regs[MAX_REG_NR];
306 unsigned long current_stack = current_stub_stack();
307 struct stub_data *data = (struct stub_data *) current_stack;
308 struct stub_data *child_data = (struct stub_data *) new_stack;
309 __u64 new_offset;
310 int new_fd = phys_mapping(to_phys((void *)new_stack), &new_offset);
311
312 /* prepare offset and fd of child's stack as argument for parent's
313 * and child's mmap2 calls
314 */
315 *data = ((struct stub_data) { .offset = MMAP_OFFSET(new_offset),
316 .fd = new_fd,
317 .timer = ((struct itimerval)
318 { { 0, 1000000 / hz() },
319 { 0, 1000000 / hz() }})});
320 get_safe_registers(regs);
321
322 /* Set parent's instruction pointer to start of clone-stub */
323 regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE +
324 (unsigned long) stub_clone_handler -
325 (unsigned long) &__syscall_stub_start;
326 regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE -
327 sizeof(void *);
328 err = ptrace_setregs(pid, regs);
329 if(err < 0)
330 panic("copy_context_skas0 : PTRACE_SETREGS failed, "
331 "pid = %d, errno = %d\n", pid, errno);
332
333 /* set a well known return code for detection of child write failure */
334 child_data->err = 12345678;
335
336 /* Wait, until parent has finished its work: read child's pid from
337 * parent's stack, and check, if bad result.
338 */
339 wait_stub_done(pid, 0, "copy_context_skas0");
340
341 pid = data->err;
342 if(pid < 0)
343 panic("copy_context_skas0 - stub-parent reports error %d\n",
344 pid);
345
346 /* Wait, until child has finished too: read child's result from
347 * child's stack and check it.
348 */
349 wait_stub_done(pid, -1, "copy_context_skas0");
350 if (child_data->err != UML_CONFIG_STUB_DATA)
351 panic("copy_context_skas0 - stub-child reports error %d\n",
352 child_data->err);
353
354 if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL,
355 (void *)PTRACE_O_TRACESYSGOOD) < 0)
356 panic("copy_context_skas0 : PTRACE_SETOPTIONS failed, "
357 "errno = %d\n", errno);
358
359 return pid;
360}
361
299void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, 362void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr,
300 void (*handler)(int)) 363 void (*handler)(int))
301{ 364{
diff --git a/arch/um/kernel/time.c b/arch/um/kernel/time.c
index f829b309b63c..c40b611e3d93 100644
--- a/arch/um/kernel/time.c
+++ b/arch/um/kernel/time.c
@@ -48,6 +48,13 @@ void enable_timer(void)
48 set_interval(ITIMER_VIRTUAL); 48 set_interval(ITIMER_VIRTUAL);
49} 49}
50 50
51void prepare_timer(void * ptr)
52{
53 int usec = 1000000/hz();
54 *(struct itimerval *)ptr = ((struct itimerval) { { 0, usec },
55 { 0, usec }});
56}
57
51void disable_timer(void) 58void disable_timer(void)
52{ 59{
53 struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); 60 struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }});