diff options
author | Miod Vallat <miod@cvs.openbsd.org> | 2013-08-26 21:38:10 +0000 |
---|---|---|
committer | Miod Vallat <miod@cvs.openbsd.org> | 2013-08-26 21:38:10 +0000 |
commit | e9f4bf1da1af81716733684468d927489693c23c (patch) | |
tree | cefe9ea0aad52683d7075fedab912e36a9e15471 | |
parent | d3f9c59d503b5b2c53f52910f4a5969042fa5fa9 (diff) |
Use %r27 as the thread control block pointer, allowing for __get_tcb() calls
in libpthread to be optimized away.
While there, follow DG/UX's example of using more than one register for thread
purposes (after all, the ABI reserves four of them), and also use %r26 to store
a pointer to the current thread's errno.
Since it is not possible to initialize %r26 at thread creation without
intrusive and potentially race-prone changes, have __tfork() reset %r26 to
zero, and libpthread's __cerror lazy initialize it. As soon as %r26 is nonzero,
it will be used instead of calling __errno().
This means that binaries linked against HEAD libpthread need to run on HEAD
kernels, and we are belatedly jumping on the 64-bit time_t bump (since there
are no 64-bit time_t m88k snapshots yet).
Joint work with guenther@; "Your love of asm is sick and wrong, and yet
beautiful." and ok guenther@
-rw-r--r-- | lib/librthread/arch/m88k/cerror.S | 24 | ||||
-rw-r--r-- | sys/arch/m88k/include/proc.h | 4 | ||||
-rw-r--r-- | sys/arch/m88k/include/tcb.h | 65 | ||||
-rw-r--r-- | sys/arch/m88k/m88k/trap.c | 5 |
4 files changed, 86 insertions, 12 deletions
diff --git a/lib/librthread/arch/m88k/cerror.S b/lib/librthread/arch/m88k/cerror.S index fecea2caa09..d31dc807c50 100644 --- a/lib/librthread/arch/m88k/cerror.S +++ b/lib/librthread/arch/m88k/cerror.S @@ -1,4 +1,4 @@ -/* $OpenBSD: cerror.S,v 1.4 2013/01/27 09:56:05 miod Exp $ */ +/* $OpenBSD: cerror.S,v 1.5 2013/08/26 21:38:08 miod Exp $ */ /*- * Copyright (c) 1990 The Regents of the University of California. @@ -37,7 +37,16 @@ .globl _C_LABEL(__errno) +/* + * long long __cerror(register_t errcode) + * stores `errcode' into the current thread's errno variable, and returns + * -1LL. + */ + ASENTRY(__cerror) + /* if %r26 has been initialized, don't bother setting up a frame */ + bcnd ne0, %r26, has_r26 + subu %r31,%r31,16 st %r25,%r0,%r31 st %r1,%r31,4 @@ -48,13 +57,16 @@ ASENTRY(__cerror) bsr.n _C_LABEL(__errno) #endif or %r25,%r0,%r2 - st %r25,%r0,%r2 - - subu %r2,%r0,1 - or %r3, %r0, %r2 + or %r26,%r0,%r2 /* save errno ptr */ + or %r2,%r0,%r25 /* and restore errno value */ ld %r1,%r31,4 ld %r25,%r0,%r31 + addu %r31,%r31,16 + +has_r26: + st %r2,%r0,%r26 + subu %r2,%r0,1 jmp.n %r1 - addu %r31,%r31,16 + or %r3, %r0, %r2 END(__cerror) diff --git a/sys/arch/m88k/include/proc.h b/sys/arch/m88k/include/proc.h index 95d041da92a..10921594bec 100644 --- a/sys/arch/m88k/include/proc.h +++ b/sys/arch/m88k/include/proc.h @@ -1,4 +1,4 @@ -/* $OpenBSD: proc.h,v 1.5 2011/03/23 16:54:35 pirofti Exp $ */ +/* $OpenBSD: proc.h,v 1.6 2013/08/26 21:38:08 miod Exp $ */ /* * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. @@ -67,4 +67,6 @@ struct mdproc { u_int md_bp1save; }; +#define __HAVE_MD_TCB + #endif /* _M88K_PROC_H_ */ diff --git a/sys/arch/m88k/include/tcb.h b/sys/arch/m88k/include/tcb.h index 03109f8a103..10851b6fc08 100644 --- a/sys/arch/m88k/include/tcb.h +++ b/sys/arch/m88k/include/tcb.h @@ -1,4 +1,4 @@ -/* $OpenBSD: tcb.h,v 1.1 2011/10/27 04:01:17 guenther Exp $ */ +/* $OpenBSD: tcb.h,v 1.2 2013/08/26 21:38:08 miod Exp $ */ /* * Copyright (c) 2011 Philip Guenther <guenther@openbsd.org> @@ -19,14 +19,71 @@ #ifndef _MACHINE_TCB_H_ #define _MACHINE_TCB_H_ +/* + * In userspace, register %r27 contains the address of the thread's TCB, + * and register %r26 contains the address of the thread's errno. + * It is the responsibility of the kernel to set %r27 to the proper value + * when creating the thread, while initialization of %r26 is done in + * userland within libpthread on a needed basis. + */ + #ifdef _KERNEL -#error "not yet" +#include <machine/reg.h> + +#define TCB_GET(p) \ + ((void *)(p)->p_md.md_tf->tf_r[27]) +#define TCB_SET(p, addr) \ + ((p)->p_md.md_tf->tf_r[27] = (register_t)(addr)) #else /* _KERNEL */ -/* Not ELF, so for now use a big TCB to save a memory reference for errno */ -#define TLS_VARIANT 2 +/* + * It is unknown whether the m88k ELF ABI mentions TLS. On m88k, since only + * unsigned offsets in (register + immediate offset) addressing is supported + * on all processors, it makes sense to use a small TCB, with static TLS data + * after it. + */ +#define TLS_VARIANT 1 + +#if defined(__GNUC__) && __GNUC__ > 4 + +struct thread_control_block; +__register__ struct thread_control_block *__tcb __asm__ ("%r27"); +#define TCB_GET() (__tcb) +#define TCB_SET(tcb) ((__tcb) = (tcb)) +#define TCB_GET_MEMBER(member) ((void *)(__tcb->member)) + +#else /* __GNUC__ > 4 */ + +#include <stddef.h> /* for offsetof */ + +/* Get a pointer to the TCB itself */ +static inline void * +__m88k_get_tcb(void) +{ + void *val; + __asm__ ("or %0,%%r27,%%r0" : "=r" (val)); + return val; +} + +/* Get the value of a specific member in the TCB */ +static inline void * +__m88k_read_tcb(size_t offset) +{ + void *val; + /* XXX the `offset' constraint ought to be "I" but this causes a warning */ + __asm__ ("ld %0,%%r27,%1" : "=r" (val) : "r" (offset)); + return val; +} + +#define TCB_GET() __m88k_get_tcb() +#define TCB_SET(tcb) __asm __volatile("or %%r27,%0,%r0" : : "r" (tcb)) + +#define TCB_GET_MEMBER(member) \ + __m88k_read_tcb(offsetof(struct thread_control_block, member)) + +#endif /* __GNUC__ > 4 */ #endif /* _KERNEL */ diff --git a/sys/arch/m88k/m88k/trap.c b/sys/arch/m88k/m88k/trap.c index 9881e063f9b..d3e39d878b1 100644 --- a/sys/arch/m88k/m88k/trap.c +++ b/sys/arch/m88k/m88k/trap.c @@ -1,4 +1,4 @@ -/* $OpenBSD: trap.c,v 1.86 2013/08/18 22:17:26 miod Exp $ */ +/* $OpenBSD: trap.c,v 1.87 2013/08/26 21:38:09 miod Exp $ */ /* * Copyright (c) 2004, Miodrag Vallat. * Copyright (c) 1998 Steve Murphree, Jr. @@ -1401,6 +1401,9 @@ child_return(arg) tf->tf_r[2] = 0; tf->tf_r[3] = 0; tf->tf_epsr &= ~PSR_C; + /* reset r26 (used by the threads library) if __tfork */ + if (p->p_flag & P_THREAD) + tf->tf_r[26] = 0; /* skip br instruction as in syscall() */ #ifdef M88100 if (CPU_IS88100) { |