diff options
Diffstat (limited to 'arch/um')
-rw-r--r-- | arch/um/include/sysdep-i386/stub.h | 47 | ||||
-rw-r--r-- | arch/um/include/sysdep-x86_64/stub.h | 39 | ||||
-rw-r--r-- | arch/um/include/time_user.h | 1 | ||||
-rw-r--r-- | arch/um/kernel/skas/Makefile | 7 | ||||
-rw-r--r-- | arch/um/kernel/skas/clone.c | 44 | ||||
-rw-r--r-- | arch/um/kernel/skas/include/skas.h | 1 | ||||
-rw-r--r-- | arch/um/kernel/skas/include/stub-data.h | 18 | ||||
-rw-r--r-- | arch/um/kernel/skas/mmu.c | 7 | ||||
-rw-r--r-- | arch/um/kernel/skas/process.c | 63 | ||||
-rw-r--r-- | arch/um/kernel/time.c | 7 |
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 @@ #include <asm/unistd.h> extern void stub_segv_handler(int sig); +extern void stub_clone_handler(void); #define STUB_SYSCALL_RET EAX #define STUB_MMAP_NR __NR_mmap2 #define MMAP_OFFSET(o) ((o) >> PAGE_SHIFT) +static inline long stub_syscall2(long syscall, long arg1, long arg2) +{ + long ret; + + __asm__("movl %0, %%ecx; " : : "g" (arg2) : "%ecx"); + __asm__("movl %0, %%ebx; " : : "g" (arg1) : "%ebx"); + __asm__("movl %0, %%eax; " : : "g" (syscall) : "%eax"); + __asm__("int $0x80;" : : : "%eax"); + __asm__ __volatile__("movl %%eax, %0; " : "=g" (ret) :); + return(ret); +} + +static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3) +{ + __asm__("movl %0, %%edx; " : : "g" (arg3) : "%edx"); + return(stub_syscall2(syscall, arg1, arg2)); +} + +static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3, + long arg4) +{ + __asm__("movl %0, %%esi; " : : "g" (arg4) : "%esi"); + return(stub_syscall3(syscall, arg1, arg2, arg3)); +} + +static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3, + long arg4, long arg5, long arg6) +{ + long ret; + __asm__("movl %0, %%eax; " : : "g" (syscall) : "%eax"); + __asm__("movl %0, %%ebx; " : : "g" (arg1) : "%ebx"); + __asm__("movl %0, %%ecx; " : : "g" (arg2) : "%ecx"); + __asm__("movl %0, %%edx; " : : "g" (arg3) : "%edx"); + __asm__("movl %0, %%esi; " : : "g" (arg4) : "%esi"); + __asm__("movl %0, %%edi; " : : "g" (arg5) : "%edi"); + __asm__ __volatile__("pushl %%ebp ; movl %1, %%ebp; " + "int $0x80; popl %%ebp ; " + "movl %%eax, %0; " : "=g" (ret) : "g" (arg6) : "%eax"); + return(ret); +} + +static inline void trap_myself(void) +{ + __asm("int3"); +} + #endif diff --git a/arch/um/include/sysdep-x86_64/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 @@ #include <sysdep/ptrace_user.h> extern void stub_segv_handler(int sig); +extern void stub_clone_handler(void); #define STUB_SYSCALL_RET PT_INDEX(RAX) #define STUB_MMAP_NR __NR_mmap #define MMAP_OFFSET(o) (o) +static inline long stub_syscall2(long syscall, long arg1, long arg2) +{ + long ret; + + __asm__("movq %0, %%rsi; " : : "g" (arg2) : "%rsi"); + __asm__("movq %0, %%rdi; " : : "g" (arg1) : "%rdi"); + __asm__("movq %0, %%rax; " : : "g" (syscall) : "%rax"); + __asm__("syscall;" : : : "%rax", "%r11", "%rcx"); + __asm__ __volatile__("movq %%rax, %0; " : "=g" (ret) :); + return(ret); +} + +static inline long stub_syscall3(long syscall, long arg1, long arg2, long arg3) +{ + __asm__("movq %0, %%rdx; " : : "g" (arg3) : "%rdx"); + return(stub_syscall2(syscall, arg1, arg2)); +} + +static inline long stub_syscall4(long syscall, long arg1, long arg2, long arg3, + long arg4) +{ + __asm__("movq %0, %%r10; " : : "g" (arg4) : "%r10"); + return(stub_syscall3(syscall, arg1, arg2, arg3)); +} + +static inline long stub_syscall6(long syscall, long arg1, long arg2, long arg3, + long arg4, long arg5, long arg6) +{ + __asm__("movq %0, %%r9; " : : "g" (arg6) : "%r9"); + __asm__("movq %0, %%r8; " : : "g" (arg5) : "%r8"); + return(stub_syscall4(syscall, arg1, arg2, arg3, arg4)); +} + +static inline void trap_myself(void) +{ + __asm("int3"); +} + #endif diff --git a/arch/um/include/time_user.h b/arch/um/include/time_user.h index 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); extern void switch_timers(int to_real); extern void idle_sleep(int secs); extern void enable_timer(void); +extern void prepare_timer(void * ptr); extern void disable_timer(void); extern unsigned long time_lock(void); extern void time_unlock(unsigned long); 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 @@ # Licensed under the GPL # -obj-y := exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \ +obj-y := clone.o exec_kern.o mem.o mem_user.o mmu.o process.o process_kern.o \ syscall_kern.o syscall_user.o tlb.o trap_user.o uaccess.o \ subdir- := util -USER_OBJS := process.o +USER_OBJS := process.o clone.o include arch/um/scripts/Makefile.rules + +# clone.o is in the stub, so it can't be built with profiling +$(obj)/clone.o : c_flags = -Wp,-MD,$(depfile) $(call unprofile,$(USER_CFLAGS)) diff --git a/arch/um/kernel/skas/clone.c b/arch/um/kernel/skas/clone.c new file mode 100644 index 000000000000..4dc55f10cd18 --- /dev/null +++ b/arch/um/kernel/skas/clone.c @@ -0,0 +1,44 @@ +#include <sched.h> +#include <signal.h> +#include <sys/mman.h> +#include <sys/time.h> +#include <asm/unistd.h> +#include <asm/page.h> +#include "ptrace_user.h" +#include "skas.h" +#include "stub-data.h" +#include "uml-config.h" +#include "sysdep/stub.h" + +/* This is in a separate file because it needs to be compiled with any + * extraneous gcc flags (-pg, -fprofile-arcs, -ftest-coverage) disabled + */ +void __attribute__ ((__section__ (".__syscall_stub"))) +stub_clone_handler(void) +{ + long err; + struct stub_data *from = (struct stub_data *) UML_CONFIG_STUB_DATA; + + err = stub_syscall2(__NR_clone, CLONE_PARENT | CLONE_FILES | SIGCHLD, + UML_CONFIG_STUB_DATA + PAGE_SIZE / 2 - + sizeof(void *)); + if(err != 0) + goto out; + + err = stub_syscall4(__NR_ptrace, PTRACE_TRACEME, 0, 0, 0); + if(err) + goto out; + + err = stub_syscall3(__NR_setitimer, ITIMER_VIRTUAL, + (long) &from->timer, 0); + if(err) + goto out; + + err = stub_syscall6(STUB_MMAP_NR, UML_CONFIG_STUB_DATA, PAGE_SIZE, + PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED, + from->fd, from->offset); + out: + /* save current result. Parent: pid; child: retcode of mmap */ + from->err = err; + trap_myself(); +} diff --git a/arch/um/kernel/skas/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, extern void user_signal(int sig, union uml_pt_regs *regs, int pid); extern int new_mm(int from); extern int start_userspace(unsigned long stub_stack); +extern int copy_context_skas0(unsigned long stack, int pid); extern void get_skas_faultinfo(int pid, struct faultinfo * fi); extern long execute_syscall_skas(void *r); extern unsigned long current_stub_stack(void); 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 @@ +/* + * Copyright (C) 2005 Jeff Dike (jdike@karaya.com) + * Licensed under the GPL + */ + +#ifndef __STUB_DATA_H +#define __STUB_DATA_H + +#include <sys/time.h> + +struct stub_data { + long offset; + int fd; + struct itimerval timer; + long err; +}; + +#endif diff --git a/arch/um/kernel/skas/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, int init_new_context_skas(struct task_struct *task, struct mm_struct *mm) { struct mm_struct *cur_mm = current->mm; + struct mm_id *cur_mm_id = &cur_mm->context.skas.id; struct mm_id *mm_id = &mm->context.skas.id; unsigned long stack; int from, ret; @@ -115,7 +116,11 @@ int init_new_context_skas(struct task_struct *task, struct mm_struct *mm) goto out_free; mm->nr_ptes--; - mm_id->u.pid = start_userspace(stack); + + if((cur_mm != NULL) && (cur_mm != &init_mm)) + mm_id->u.pid = copy_context_skas0(stack, + cur_mm_id->u.pid); + else mm_id->u.pid = start_userspace(stack); } return 0; 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 @@ #include <sys/wait.h> #include <sys/mman.h> #include <sys/user.h> +#include <sys/time.h> #include <asm/unistd.h> #include <asm/types.h> #include "user.h" @@ -22,6 +23,7 @@ #include "user_util.h" #include "kern_util.h" #include "skas.h" +#include "stub-data.h" #include "mm_id.h" #include "sysdep/sigcontext.h" #include "sysdep/stub.h" @@ -296,6 +298,67 @@ void userspace(union uml_pt_regs *regs) #define INIT_JMP_HALT 3 #define INIT_JMP_REBOOT 4 + +int copy_context_skas0(unsigned long new_stack, int pid) +{ + int err; + unsigned long regs[MAX_REG_NR]; + unsigned long current_stack = current_stub_stack(); + struct stub_data *data = (struct stub_data *) current_stack; + struct stub_data *child_data = (struct stub_data *) new_stack; + __u64 new_offset; + int new_fd = phys_mapping(to_phys((void *)new_stack), &new_offset); + + /* prepare offset and fd of child's stack as argument for parent's + * and child's mmap2 calls + */ + *data = ((struct stub_data) { .offset = MMAP_OFFSET(new_offset), + .fd = new_fd, + .timer = ((struct itimerval) + { { 0, 1000000 / hz() }, + { 0, 1000000 / hz() }})}); + get_safe_registers(regs); + + /* Set parent's instruction pointer to start of clone-stub */ + regs[REGS_IP_INDEX] = UML_CONFIG_STUB_CODE + + (unsigned long) stub_clone_handler - + (unsigned long) &__syscall_stub_start; + regs[REGS_SP_INDEX] = UML_CONFIG_STUB_DATA + PAGE_SIZE - + sizeof(void *); + err = ptrace_setregs(pid, regs); + if(err < 0) + panic("copy_context_skas0 : PTRACE_SETREGS failed, " + "pid = %d, errno = %d\n", pid, errno); + + /* set a well known return code for detection of child write failure */ + child_data->err = 12345678; + + /* Wait, until parent has finished its work: read child's pid from + * parent's stack, and check, if bad result. + */ + wait_stub_done(pid, 0, "copy_context_skas0"); + + pid = data->err; + if(pid < 0) + panic("copy_context_skas0 - stub-parent reports error %d\n", + pid); + + /* Wait, until child has finished too: read child's result from + * child's stack and check it. + */ + wait_stub_done(pid, -1, "copy_context_skas0"); + if (child_data->err != UML_CONFIG_STUB_DATA) + panic("copy_context_skas0 - stub-child reports error %d\n", + child_data->err); + + if (ptrace(PTRACE_OLDSETOPTIONS, pid, NULL, + (void *)PTRACE_O_TRACESYSGOOD) < 0) + panic("copy_context_skas0 : PTRACE_SETOPTIONS failed, " + "errno = %d\n", errno); + + return pid; +} + void new_thread(void *stack, void **switch_buf_ptr, void **fork_buf_ptr, void (*handler)(int)) { 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) set_interval(ITIMER_VIRTUAL); } +void prepare_timer(void * ptr) +{ + int usec = 1000000/hz(); + *(struct itimerval *)ptr = ((struct itimerval) { { 0, usec }, + { 0, usec }}); +} + void disable_timer(void) { struct itimerval disable = ((struct itimerval) { { 0, 0 }, { 0, 0 }}); |