summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMiod Vallat <miod@cvs.openbsd.org>2013-08-26 21:38:10 +0000
committerMiod Vallat <miod@cvs.openbsd.org>2013-08-26 21:38:10 +0000
commite9f4bf1da1af81716733684468d927489693c23c (patch)
treecefe9ea0aad52683d7075fedab912e36a9e15471
parentd3f9c59d503b5b2c53f52910f4a5969042fa5fa9 (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.S24
-rw-r--r--sys/arch/m88k/include/proc.h4
-rw-r--r--sys/arch/m88k/include/tcb.h65
-rw-r--r--sys/arch/m88k/m88k/trap.c5
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) {