summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPhilip Guenthe <guenther@cvs.openbsd.org>2011-10-15 23:35:30 +0000
committerPhilip Guenthe <guenther@cvs.openbsd.org>2011-10-15 23:35:30 +0000
commit67874eb615d7ff9c8ac1f262fa286e41e2e0e32f (patch)
treea4438f1bc677ce643f078f2bfaef615b6264844d
parentae0a9206a9212a9f09180c0e6c63b4973377fc50 (diff)
"TLS-lite": add kernel support for a per-thread userspace pointer,
for pointing to the thread-control-block. Support for mapping this to the correct hardware register can be added as it's finished; start with support for amd64, sparc, and sparc64. Includes syscalls for getting and setting it (for a portable __errno implementation) as well as creating a new thread with an initial value for it. discussed with miod@, kettenis@, deraadt@; committing to get the syscalls in with the impending libc bump and do further refinements in tree
-rw-r--r--sys/arch/amd64/include/proc.h8
-rw-r--r--sys/arch/amd64/include/tcb.h56
-rw-r--r--sys/arch/sparc/include/proc.h4
-rw-r--r--sys/arch/sparc/include/tcb.h75
-rw-r--r--sys/arch/sparc64/include/proc.h2
-rw-r--r--sys/arch/sparc64/include/tcb.h75
-rw-r--r--sys/kern/kern_fork.c55
-rw-r--r--sys/kern/kern_prot.c30
-rw-r--r--sys/kern/syscalls.master5
-rw-r--r--sys/sys/proc.h10
-rw-r--r--sys/sys/unistd.h9
11 files changed, 317 insertions, 12 deletions
diff --git a/sys/arch/amd64/include/proc.h b/sys/arch/amd64/include/proc.h
index b56cdb7e50f..733c93ea5cc 100644
--- a/sys/arch/amd64/include/proc.h
+++ b/sys/arch/amd64/include/proc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: proc.h,v 1.6 2011/03/23 16:54:34 pirofti Exp $ */
+/* $OpenBSD: proc.h,v 1.7 2011/10/15 23:35:29 guenther Exp $ */
/* $NetBSD: proc.h,v 1.1 2003/04/26 18:39:46 fvdl Exp $ */
/*
@@ -35,11 +35,10 @@
#ifndef _MACHINE_PROC_H_
#define _MACHINE_PROC_H_
-#include <machine/frame.h>
-
/*
* Machine-dependent part of the proc structure for amd64.
*/
+struct trapframe;
struct mdproc {
struct trapframe *md_regs; /* registers on current frame */
int md_flags;
@@ -49,5 +48,8 @@ struct mdproc {
/* md_flags */
#define MDP_USEDFPU 0x0001 /* has used the FPU */
#define MDP_IRET 0x0002 /* return via iret, not sysret */
+ /* (iret can restore r11 and rcx) */
+
+#define __HAVE_MD_TCB
#endif /* _MACHINE_PROC_H_ */
diff --git a/sys/arch/amd64/include/tcb.h b/sys/arch/amd64/include/tcb.h
new file mode 100644
index 00000000000..f6a0ed87a7f
--- /dev/null
+++ b/sys/arch/amd64/include/tcb.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2011 Philip Guenther <guenther@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _MACHINE_TCB_H_
+#define _MACHINE_TCB_H_
+
+#ifdef _KERNEL
+
+#include <machine/pcb.h>
+
+#define TCB_GET(p) \
+ ((void *)((struct pcb *)(p)->p_addr)->pcb_fsbase)
+#define TCB_SET(p, addr) \
+ (((struct pcb *)(p)->p_addr)->pcb_fsbase = (u_int64_t)(addr))
+
+#else /* _KERNEL */
+
+#include <stddef.h> /* for offsetof */
+
+/* ELF TLS ABI calls for big TCB, with static TLS data at negative offsets */
+#define TLS_VARIANT 2
+
+/* Read a slot from the TCB */
+static inline void *
+__amd64_read_tcb(long offset)
+{
+ void *val;
+ __asm__ ("movq %%fs:(%1),%0" : "=r" (val) : "r" (offset));
+ return val;
+}
+
+/* Get a pointer to the TCB itself */
+#define TCB_GET() __amd64_read_tcb(0)
+
+/* Get the value of a specific member in the TCB */
+#define TCB_GET_MEMBER(member) \
+ __amd64_read_tcb(offsetof(struct thread_control_block, member))
+
+/* Setting the TCB pointer can only be done via syscall, so no TCB_SET() */
+
+#endif /* _KERNEL */
+
+#endif /* _MACHINE_TCB_H_ */
diff --git a/sys/arch/sparc/include/proc.h b/sys/arch/sparc/include/proc.h
index 419d945ac75..d8d5f867904 100644
--- a/sys/arch/sparc/include/proc.h
+++ b/sys/arch/sparc/include/proc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: proc.h,v 1.4 2010/11/27 19:41:45 miod Exp $ */
+/* $OpenBSD: proc.h,v 1.5 2011/10/15 23:35:29 guenther Exp $ */
/* $NetBSD: proc.h,v 1.3 1996/09/26 18:51:17 christos Exp $ */
/*
@@ -48,3 +48,5 @@ struct mdproc {
struct trapframe *md_tf; /* trap/syscall registers */
struct fpstate *md_fpstate; /* fpu state, if any; always resident */
};
+
+#define __HAVE_MD_TCB
diff --git a/sys/arch/sparc/include/tcb.h b/sys/arch/sparc/include/tcb.h
new file mode 100644
index 00000000000..b445918b925
--- /dev/null
+++ b/sys/arch/sparc/include/tcb.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2011 Philip Guenther <guenther@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _MACHINE_TCB_H_
+#define _MACHINE_TCB_H_
+
+#ifdef _KERNEL
+
+#include <machine/reg.h>
+
+/*
+ * In userspace, register %g7 contains the address of the thread's TCB
+ */
+#define TCB_GET(p) \
+ ((void *)(p)->p_md.md_tf->tf_global[7])
+#define TCB_SET(p, addr) \
+ ((p)->p_md.md_tf->tf_global[7] = (int)(addr))
+
+#else /* _KERNEL */
+
+/* ELF TLS ABI calls for big TCB, with static TLS data at negative offsets */
+#define TLS_VARIANT 2
+
+#if 0 /* XXX perhaps use the gcc global register extension? */
+struct thread_control_block;
+__register__ struct thread_control_block *__tcb __asm__ ("%g7");
+#define TCB_GET() (__tcb)
+#define TCB_GET_MEMBER(member) ((void *)(__tcb->member))
+#define TCB_SET(tcb) ((__tcb) = (tcb))
+
+#else
+
+#include <stddef.h> /* for offsetof */
+
+/* Get a pointer to the TCB itself */
+static inline void *
+__sparc_get_tcb(void)
+{
+ void *val;
+ __asm__ ("mov %%g7, %0" : "=r" (val));
+ return val;
+}
+#define TCB_GET() __sparc_get_tcb()
+
+/* Get the value of a specific member in the TCB */
+static inline void *
+__sparc_get_tcb(int offset)
+{
+ void *val;
+ __asm__ ("ld [%%g7 + %1], %0" : "=r" (val) : "r" (offset));
+ return val;
+}
+#define TCB_GET_MEMBER(member) \
+ __sparc_get_tcb(offsetof(struct thread_control_block, member))
+
+#define TCB_SET(tcb) (__asm __volatile("mov %0, %%g7" : : "r" (tcb)))
+
+#endif /* 0 */
+
+#endif /* _KERNEL */
+
+#endif /* _MACHINE_TCB_H_ */
diff --git a/sys/arch/sparc64/include/proc.h b/sys/arch/sparc64/include/proc.h
index 0559c74bcc9..6ae7daa48d7 100644
--- a/sys/arch/sparc64/include/proc.h
+++ b/sys/arch/sparc64/include/proc.h
@@ -48,3 +48,5 @@ struct mdproc {
struct fpstate64 *md_fpstate; /* fpu state, if any; always resident */
__volatile int md_astpending;
};
+
+#define __HAVE_MD_TCB
diff --git a/sys/arch/sparc64/include/tcb.h b/sys/arch/sparc64/include/tcb.h
new file mode 100644
index 00000000000..6dedb858c05
--- /dev/null
+++ b/sys/arch/sparc64/include/tcb.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2011 Philip Guenther <guenther@openbsd.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef _MACHINE_TCB_H_
+#define _MACHINE_TCB_H_
+
+#ifdef _KERNEL
+
+#include <machine/reg.h>
+
+/*
+ * In userspace, register %g7 contains the address of the thread's TCB
+ */
+#define TCB_GET(p) \
+ ((void *)(p)->p_md.md_tf->tf_global[7])
+#define TCB_SET(p, addr) \
+ ((p)->p_md.md_tf->tf_global[7] = (int64_t)(addr))
+
+#else /* _KERNEL */
+
+/* ELF TLS ABI calls for big TCB, with static TLS data at negative offsets */
+#define TLS_VARIANT 2
+
+#if 0 /* XXX perhaps use the gcc global register extension? */
+struct thread_control_block;
+__register__ struct thread_control_block *__tcb __asm__ ("%g7");
+#define TCB_GET() (__tcb)
+#define TCB_GET_MEMBER(member) ((void *)(__tcb->member))
+#define TCB_SET(tcb) ((__tcb) = (tcb))
+
+#else
+
+#include <stddef.h> /* for offsetof */
+
+/* Get a pointer to the TCB itself */
+static inline void *
+__sparc64_get_tcb(void)
+{
+ void *val;
+ __asm__ ("mov %%g7, %0" : "=r" (val));
+ return val;
+}
+#define TCB_GET() __sparc64_get_tcb()
+
+/* Get the value of a specific member in the TCB */
+static inline void *
+__sparc64_get_tcb(int offset)
+{
+ void *val;
+ __asm__ ("ldx [%%g7 + %1], %0" : "=r" (val) : "r" (offset));
+ return val;
+}
+#define TCB_GET_MEMBER(member) \
+ __sparc64_get_tcb(offsetof(struct thread_control_block, member))
+
+#define TCB_SET(tcb) (__asm __volatile("mov %0, %%g7" : : "r" (tcb)))
+
+#endif /* 0 */
+
+#endif /* _KERNEL */
+
+#endif /* _MACHINE_TCB_H_ */
diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c
index 59334cfdd03..39c2249638b 100644
--- a/sys/kern/kern_fork.c
+++ b/sys/kern/kern_fork.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_fork.c,v 1.128 2011/07/07 18:00:33 guenther Exp $ */
+/* $OpenBSD: kern_fork.c,v 1.129 2011/10/15 23:35:29 guenther Exp $ */
/* $NetBSD: kern_fork.c,v 1.29 1996/02/09 18:59:34 christos Exp $ */
/*
@@ -65,12 +65,17 @@
#include <uvm/uvm_extern.h>
#include <uvm/uvm_map.h>
+#ifdef __HAVE_MD_TCB
+# include <machine/tcb.h>
+#endif
+
int nprocs = 1; /* process 0 */
int randompid; /* when set to 1, pid's go random */
pid_t lastpid;
struct forkstat forkstat;
void fork_return(void *);
+void tfork_child_return(void *);
int pidtaken(pid_t);
void process_new(struct proc *, struct proc *);
@@ -148,6 +153,39 @@ sys_rfork(struct proc *p, void *v, register_t *retval)
return (fork1(p, SIGCHLD, flags, NULL, 0, NULL, NULL, retval, NULL));
}
+int
+sys___tfork(struct proc *p, void *v, register_t *retval)
+{
+ struct sys___tfork_args /* {
+ syscallarg(struct __tfork) *param;
+ } */ *uap = v;
+ struct __tfork param;
+ int flags;
+ int error;
+
+ if ((error = copyin(SCARG(uap, param), &param, sizeof(param))))
+ return (error);
+
+ /* XXX will supersede rfork at some point... */
+ if (param.tf_flags != 0)
+ return (EINVAL);
+
+ flags = FORK_TFORK | FORK_THREAD | FORK_SIGHAND | FORK_SHAREVM
+ | FORK_NOZOMBIE | FORK_SHAREFILES;
+
+ return (fork1(p, 0, flags, NULL, param.tf_tid, tfork_child_return,
+ param.tf_tcb, retval, NULL));
+}
+
+void
+tfork_child_return(void *arg)
+{
+ struct proc *p = curproc;
+
+ TCB_SET(p, arg);
+ child_return(p);
+}
+
/*
* Allocate and initialize a new process.
*/
@@ -196,7 +234,7 @@ process_new(struct proc *newproc, struct proc *parentproc)
struct timeval fork_tfmrate = { 10, 0 };
int
-fork1(struct proc *p1, int exitsig, int flags, void *stack, size_t stacksize,
+fork1(struct proc *p1, int exitsig, int flags, void *stack, pid_t *tidptr,
void (*func)(void *), void *arg, register_t *retval,
struct proc **rnewprocp)
{
@@ -364,7 +402,7 @@ fork1(struct proc *p1, int exitsig, int flags, void *stack, size_t stacksize,
* different path later.
*/
uvm_fork(p1, p2, ((flags & FORK_SHAREVM) ? TRUE : FALSE), stack,
- stacksize, func ? func : child_return, arg ? arg : p2);
+ 0, func ? func : child_return, arg ? arg : p2);
timeout_set(&p2->p_stats->p_virt_to, virttimer_trampoline, p2);
timeout_set(&p2->p_stats->p_prof_to, proftimer_trampoline, p2);
@@ -377,6 +415,10 @@ fork1(struct proc *p1, int exitsig, int flags, void *stack, size_t stacksize,
} else if (flags & FORK_VFORK) {
forkstat.cntvfork++;
forkstat.sizvfork += vm->vm_dsize + vm->vm_ssize;
+#if 0
+ } else if (flags & FORK_TFORK) {
+ forkstat.cnttfork++;
+#endif
} else if (flags & FORK_RFORK) {
forkstat.cntrfork++;
forkstat.sizrfork += vm->vm_dsize + vm->vm_ssize;
@@ -425,6 +467,13 @@ fork1(struct proc *p1, int exitsig, int flags, void *stack, size_t stacksize,
systrace_fork(p1, p2, newstrp);
#endif
+ if (tidptr != NULL) {
+ pid_t pid = p2->p_pid + THREAD_PID_OFFSET;
+
+ if (copyout(&pid, tidptr, sizeof(pid)))
+ psignal(p1, SIGSEGV);
+ }
+
/*
* Make child runnable, set start time, and add to run queue.
*/
diff --git a/sys/kern/kern_prot.c b/sys/kern/kern_prot.c
index 1a0f724db41..e936e44970e 100644
--- a/sys/kern/kern_prot.c
+++ b/sys/kern/kern_prot.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: kern_prot.c,v 1.50 2011/07/25 20:32:06 tedu Exp $ */
+/* $OpenBSD: kern_prot.c,v 1.51 2011/10/15 23:35:29 guenther Exp $ */
/* $NetBSD: kern_prot.c,v 1.33 1996/02/09 18:59:42 christos Exp $ */
/*
@@ -54,6 +54,10 @@
#include <sys/mount.h>
#include <sys/syscallargs.h>
+#ifdef __HAVE_MD_TCB
+# include <machine/tcb.h>
+#endif
+
/* ARGSUSED */
int
sys_getpid(struct proc *p, void *v, register_t *retval)
@@ -890,3 +894,27 @@ proc_cansugid(struct proc *p)
/* Allow. */
return (1);
}
+
+/*
+ * Set address of the proc's thread-control-block
+ */
+int
+sys___set_tcb(struct proc *p, void *v, register_t *retval)
+{
+ struct sys___set_tcb_args /* {
+ syscallarg(void *) tcb;
+ } */ *uap = v;
+
+ TCB_SET(p, SCARG(uap, tcb));
+ return (0);
+}
+
+/*
+ * Get address of the proc's thread-control-block
+ */
+int
+sys___get_tcb(struct proc *p, void *v, register_t *retval)
+{
+ *retval = (register_t)TCB_GET(p);
+ return (0);
+}
diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master
index cd4a7899bcb..c8011d97d42 100644
--- a/sys/kern/syscalls.master
+++ b/sys/kern/syscalls.master
@@ -1,4 +1,4 @@
-; $OpenBSD: syscalls.master,v 1.118 2011/07/18 00:16:54 matthew Exp $
+; $OpenBSD: syscalls.master,v 1.119 2011/10/15 23:35:29 guenther Exp $
; $NetBSD: syscalls.master,v 1.32 1996/04/23 10:24:21 mycroft Exp $
; @(#)syscalls.master 8.2 (Berkeley) 1/13/94
@@ -574,3 +574,6 @@
const struct timespec *times, int flag); }
327 STD { int sys_futimens(int fd, \
const struct timespec *times); }
+328 STD { int sys___tfork(struct __tfork *param); }
+329 STD NOLOCK { void sys___set_tcb(void *tcb); }
+330 STD NOLOCK { void *sys___get_tcb(void); }
diff --git a/sys/sys/proc.h b/sys/sys/proc.h
index 3a4aa490181..bc2a43962d8 100644
--- a/sys/sys/proc.h
+++ b/sys/sys/proc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: proc.h,v 1.143 2011/09/20 10:07:37 deraadt Exp $ */
+/* $OpenBSD: proc.h,v 1.144 2011/10/15 23:35:29 guenther Exp $ */
/* $NetBSD: proc.h,v 1.44 1996/04/22 01:23:21 christos Exp $ */
/*-
@@ -235,6 +235,11 @@ struct proc {
long p_thrslpid; /* for thrsleep syscall */
int p_sigwait; /* signal handled by sigwait() */
+#ifndef __HAVE_MD_TCB
+ void *p_tcb; /* user-space thread-control-block address */
+# define TCB_SET(p, addr) ((p)->p_tcb = (addr))
+# define TCB_GET(p) ((p)->p_tcb)
+#endif
/* scheduling */
u_int p_estcpu; /* Time averaged value of p_cpticks. */
@@ -425,6 +430,7 @@ struct uidinfo *uid_find(uid_t);
#define FORK_CLEANFILES 0x00000020
#define FORK_NOZOMBIE 0x00000040
#define FORK_SHAREVM 0x00000080
+#define FORK_TFORK 0x00000100
#define FORK_SIGHAND 0x00000200
#define FORK_PTRACE 0x00000400
#define FORK_THREAD 0x00000800
@@ -483,7 +489,7 @@ void reaper(void);
void exit1(struct proc *, int, int);
void exit2(struct proc *);
void cpu_exit(struct proc *);
-int fork1(struct proc *, int, int, void *, size_t, void (*)(void *),
+int fork1(struct proc *, int, int, void *, pid_t *, void (*)(void *),
void *, register_t *, struct proc **);
int groupmember(gid_t, struct ucred *);
diff --git a/sys/sys/unistd.h b/sys/sys/unistd.h
index 7a5b3ede8af..52b8545c6a6 100644
--- a/sys/sys/unistd.h
+++ b/sys/sys/unistd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: unistd.h,v 1.18 2010/10/28 02:05:59 deraadt Exp $ */
+/* $OpenBSD: unistd.h,v 1.19 2011/10/15 23:35:29 guenther Exp $ */
/* $NetBSD: unistd.h,v 1.10 1994/06/29 06:46:06 cgd Exp $ */
/*
@@ -72,6 +72,13 @@
#define L_SET SEEK_SET
#define L_INCR SEEK_CUR
#define L_XTND SEEK_END
+
+/* the parameters argument passed to the __tfork() syscall */
+struct __tfork {
+ void *tf_tcb;
+ pid_t *tf_tid;
+ int tf_flags;
+};
#endif
/* configurable pathname variables */