diff options
author | 2011-04-05 15:44:40 +0000 | |
---|---|---|
committer | 2011-04-05 15:44:40 +0000 | |
commit | 3595609c45e61ad71974f17cd71ac52905aef42c (patch) | |
tree | f0e0cf6790fa13a8c9f90fe1d95cbfc870ceda03 /sys | |
parent | Bye bye, kern.emul.freebsd (diff) | |
download | wireguard-openbsd-3595609c45e61ad71974f17cd71ac52905aef42c.tar.xz wireguard-openbsd-3595609c45e61ad71974f17cd71ac52905aef42c.zip |
Add set_tid_address() syscall. Lots of help from and okay guenther@.
This is more than a simple syscall.This expands TLS support quite a bit.
Also linux_sys_clone() handles CLONE_CHILD_CLEARTID, CLONE_CHILD_SETTID,
CLONE_PARENT_SETTID flags as well as the CLONE_SETTLS by doing what
set_thread_area() is doing.
Next on the list is futex support which should allow compat to cope with
newer Linux kernels.
Diffstat (limited to 'sys')
-rw-r--r-- | sys/compat/linux/linux_emuldata.h | 11 | ||||
-rw-r--r-- | sys/compat/linux/linux_exec.c | 28 | ||||
-rw-r--r-- | sys/compat/linux/linux_sched.c | 93 | ||||
-rw-r--r-- | sys/compat/linux/syscalls.master | 7 |
4 files changed, 119 insertions, 20 deletions
diff --git a/sys/compat/linux/linux_emuldata.h b/sys/compat/linux/linux_emuldata.h index 316a9816ed4..4eb541081d4 100644 --- a/sys/compat/linux/linux_emuldata.h +++ b/sys/compat/linux/linux_emuldata.h @@ -1,4 +1,4 @@ -/* $OpenBSD: linux_emuldata.h,v 1.4 2008/06/26 05:42:14 ray Exp $ */ +/* $OpenBSD: linux_emuldata.h,v 1.5 2011/04/05 15:44:40 pirofti Exp $ */ /* $NetBSD: linux_emuldata.h,v 1.4 2002/02/15 16:48:02 christos Exp $ */ /*- * Copyright (c) 1998,2002 The NetBSD Foundation, Inc. @@ -39,5 +39,14 @@ */ struct linux_emuldata { caddr_t p_break; /* Cached per-process break value */ + + void *child_set_tid; /* Let the child set the thread ID at start */ + void *child_clear_tid; /* Let the child clear the thread ID on exit */ + unsigned child_tls_base;/* Set the Thread Local Storage on clone */ + + /* Same as above, passed by the parent when forking. */ + void *my_set_tid; + void *my_clear_tid; + unsigned my_tls_base; }; #endif /* !_LINUX_EMULDATA_H */ diff --git a/sys/compat/linux/linux_exec.c b/sys/compat/linux/linux_exec.c index 6eba69a0d41..f9944ab5307 100644 --- a/sys/compat/linux/linux_exec.c +++ b/sys/compat/linux/linux_exec.c @@ -1,4 +1,4 @@ -/* $OpenBSD: linux_exec.c,v 1.32 2011/04/05 01:41:03 pirofti Exp $ */ +/* $OpenBSD: linux_exec.c,v 1.33 2011/04/05 15:44:40 pirofti Exp $ */ /* $NetBSD: linux_exec.c,v 1.13 1996/04/05 00:01:10 christos Exp $ */ /*- @@ -46,6 +46,7 @@ #include <sys/mman.h> #include <sys/syscallargs.h> +#include <sys/signalvar.h> #include <uvm/uvm_extern.h> @@ -173,6 +174,18 @@ linux_e_proc_exec(struct proc *p, struct exec_package *epp) void linux_e_proc_exit(struct proc *p) { + struct linux_emuldata *emul = p->p_emuldata; + + if (emul->my_clear_tid) { + pid_t zero = 0; + + if (copyout(&zero, emul->my_clear_tid, sizeof(zero))) + psignal(p, SIGSEGV); + /* + * not yet: futex(my_clear_tid, FUTEX_WAKE, 1, NULL, NULL, 0) + */ + } + /* free Linux emuldata and set the pointer to null */ free(p->p_emuldata, M_EMULDATA); p->p_emuldata = NULL; @@ -184,15 +197,18 @@ linux_e_proc_exit(struct proc *p) void linux_e_proc_fork(struct proc *p, struct proc *parent) { - /* - * It could be desirable to copy some stuff from parent's - * emuldata. We don't need anything like that for now. - * So just allocate new emuldata for the new process. - */ + struct linux_emuldata *emul = p->p_emuldata; + struct linux_emuldata *p_emul = parent->p_emuldata; + + /* Allocate new emuldata for the new process. */ p->p_emuldata = NULL; /* fork, use parent's vmspace (our vmspace may not be setup yet) */ linux_e_proc_init(p, parent->p_vmspace); + + emul->my_set_tid = p_emul->child_set_tid; + emul->my_clear_tid = p_emul->child_clear_tid; + emul->my_tls_base = p_emul->child_tls_base; } static void * diff --git a/sys/compat/linux/linux_sched.c b/sys/compat/linux/linux_sched.c index 6eda8123e60..61a4b5b98ad 100644 --- a/sys/compat/linux/linux_sched.c +++ b/sys/compat/linux/linux_sched.c @@ -1,4 +1,4 @@ -/* $OpenBSD: linux_sched.c,v 1.9 2011/04/04 23:24:58 pirofti Exp $ */ +/* $OpenBSD: linux_sched.c,v 1.10 2011/04/05 15:44:40 pirofti Exp $ */ /* $NetBSD: linux_sched.c,v 1.6 2000/05/28 05:49:05 thorpej Exp $ */ /*- @@ -41,36 +41,41 @@ #include <sys/proc.h> #include <sys/systm.h> #include <sys/syscallargs.h> +#include <sys/signalvar.h> #include <machine/cpu.h> +#include <machine/pcb.h> +#include <machine/linux_machdep.h> +#include <compat/linux/linux_emuldata.h> #include <compat/linux/linux_types.h> #include <compat/linux/linux_sched.h> #include <compat/linux/linux_signal.h> #include <compat/linux/linux_syscallargs.h> +void linux_child_return(void *); + int linux_sys_clone(struct proc *p, void *v, register_t *retval) { - struct linux_sys_clone_args /* { - syscallarg(int) flags; - syscallarg(void *) stack; - } */ *uap = v; + struct linux_sys_clone_args *uap = v; + struct linux_emuldata *emul = p->p_emuldata; int cflags = SCARG(uap, flags); int flags = FORK_RFORK, sig; + int error = 0; /* * We only support certain bits. The Linux crew keep adding more, * so let's test for anything outside of what we support and complain * about them. Not everything in this list is completely supported, * they just aren't _always_ an error. - * To make nptl threads work we need to add support for at least - * CLONE_SETTLS, CLONE_PARENT_SETTID, and CLONE_CHILD_CLEARTID. */ if (cflags & ~(LINUX_CLONE_CSIGNAL | LINUX_CLONE_VM | LINUX_CLONE_FS | LINUX_CLONE_FILES | LINUX_CLONE_SIGHAND | LINUX_CLONE_VFORK | LINUX_CLONE_PARENT | LINUX_CLONE_THREAD | LINUX_CLONE_SYSVSEM | - LINUX_CLONE_DETACHED | LINUX_CLONE_UNTRACED)) + LINUX_CLONE_DETACHED | LINUX_CLONE_UNTRACED | LINUX_CLONE_SETTLS | + LINUX_CLONE_PARENT_SETTID | LINUX_CLONE_CHILD_CLEARTID | + LINUX_CLONE_CHILD_SETTID)) return (EINVAL); if (cflags & LINUX_CLONE_VM) @@ -137,14 +142,51 @@ linux_sys_clone(struct proc *p, void *v, register_t *retval) return (EINVAL); sig = linux_to_bsd_sig[sig]; + if (cflags & LINUX_CLONE_CHILD_SETTID) + emul->child_set_tid = SCARG(uap, child_tidptr); + else + emul->child_set_tid = NULL; + + if (cflags & LINUX_CLONE_CHILD_CLEARTID) + emul->child_clear_tid = SCARG(uap, child_tidptr); + else + emul->child_clear_tid = NULL; + + if (cflags & LINUX_CLONE_PARENT_SETTID) + if (SCARG(uap, parent_tidptr) == NULL) + return (EINVAL); + + if (cflags & LINUX_CLONE_SETTLS) { + struct l_segment_descriptor ldesc; + + error = copyin(SCARG(uap, tls), &ldesc, sizeof(ldesc)); + if (error) + return (error); + + if (ldesc.entry_number != GUGS_SEL) + return (EINVAL); + emul->child_tls_base = ldesc.base_addr; + } + else + emul->child_tls_base = 0; + /* * Note that Linux does not provide a portable way of specifying * the stack area; the caller must know if the stack grows up * or down. So, we pass a stack size of 0, so that the code * that makes this adjustment is a noop. */ - return (fork1(p, sig, flags, SCARG(uap, stack), 0, NULL, NULL, retval, - NULL)); + error = fork1(p, sig, flags, SCARG(uap, stack), 0, linux_child_return, + p, retval, NULL); + if (error) + return error; + + if (cflags & LINUX_CLONE_PARENT_SETTID) { + pid_t pid = retval[0]; + + error = copyout(&pid, SCARG(uap, parent_tidptr), sizeof(pid)); + } + return (error); } int @@ -346,3 +388,34 @@ linux_sys_sched_get_priority_min(struct proc *cp, void *v, register_t *retval) *retval = 0; return (0); } + +int +linux_sys_set_tid_address(struct proc *p, void *v, register_t *retval) +{ + struct linux_sys_set_tid_address_args *uap = v; + struct linux_emuldata *emul = p->p_emuldata; + + emul->my_clear_tid = SCARG(uap, tidptr); + + *retval = p->p_p->ps_pid; + return 0; +} + +void +linux_child_return(void *arg) +{ + struct proc *p = (struct proc *)arg; + struct linux_emuldata *emul = p->p_emuldata; + + if (i386_set_threadbase(p, &emul->my_tls_base, TSEG_GS)) + return; + + if (emul->my_set_tid) { + pid_t pid = p->p_pid + THREAD_PID_OFFSET; + + if (copyout(&pid, emul->my_set_tid, sizeof(pid))) + psignal(p, SIGSEGV); + } + + child_return(p); +} diff --git a/sys/compat/linux/syscalls.master b/sys/compat/linux/syscalls.master index 046b44df9c4..1ee5c0ee254 100644 --- a/sys/compat/linux/syscalls.master +++ b/sys/compat/linux/syscalls.master @@ -1,4 +1,4 @@ - $OpenBSD: syscalls.master,v 1.54 2011/04/04 21:50:41 pirofti Exp $ + $OpenBSD: syscalls.master,v 1.55 2011/04/05 15:44:40 pirofti Exp $ ; $NetBSD: syscalls.master,v 1.15 1995/12/18 14:35:10 fvdl Exp $ ; @(#)syscalls.master 8.1 (Berkeley) 7/19/93 @@ -212,7 +212,8 @@ caddr_t ptr); } 118 NOARGS { int sys_fsync(int fd); } 119 STD { int linux_sys_sigreturn(struct linux_sigcontext *scp); } -120 STD { int linux_sys_clone(int flags, void *stack); } +120 STD { int linux_sys_clone(int flags, void *stack, \ + void *parent_tidptr, void *tls, void *child_tidptr); } 121 NOARGS { int compat_09_sys_setdomainname(char *name, \ int len); } 122 STD { int linux_sys_uname(struct linux_utsname *up); } @@ -400,7 +401,7 @@ 255 UNIMPL linux_sys_epoll_ctl 256 UNIMPL linux_sys_epoll_wait 257 UNIMPL linux_sys_remap_file_pages -258 UNIMPL linux_sys_set_tid_address +258 STD { int linux_sys_set_tid_address(void *tidptr); } 259 UNIMPL linux_sys_timer_create 260 UNIMPL linux_sys_timer_settime 261 UNIMPL linux_sys_timer_gettime |