summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorpirofti <pirofti@openbsd.org>2011-04-05 15:44:40 +0000
committerpirofti <pirofti@openbsd.org>2011-04-05 15:44:40 +0000
commit3595609c45e61ad71974f17cd71ac52905aef42c (patch)
treef0e0cf6790fa13a8c9f90fe1d95cbfc870ceda03 /sys
parentBye bye, kern.emul.freebsd (diff)
downloadwireguard-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.h11
-rw-r--r--sys/compat/linux/linux_exec.c28
-rw-r--r--sys/compat/linux/linux_sched.c93
-rw-r--r--sys/compat/linux/syscalls.master7
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