summaryrefslogtreecommitdiff
path: root/lib/libpthread
diff options
context:
space:
mode:
authorross <ross@NetBSD.org>2006-07-08 05:09:44 +0000
committerross <ross@NetBSD.org>2006-07-08 05:09:44 +0000
commita228aa3de265fe7643cbbb3a4577825599146812 (patch)
treed0b5d48010df3e7823637ff4300d310757f53cee /lib/libpthread
parent032dc727f738be733b24466c6bb62111ff34e90f (diff)
Revise for LP64.
Encapsulate previously copied code sections into macros.
Diffstat (limited to 'lib/libpthread')
-rw-r--r--lib/libpthread/arch/powerpc64/_context_u.S189
-rw-r--r--lib/libpthread/arch/powerpc64/genassym.cf72
-rw-r--r--lib/libpthread/arch/powerpc64/pthread_md.h125
-rw-r--r--lib/libpthread/arch/powerpc64/pthread_switch.S310
4 files changed, 696 insertions, 0 deletions
diff --git a/lib/libpthread/arch/powerpc64/_context_u.S b/lib/libpthread/arch/powerpc64/_context_u.S
new file mode 100644
index 00000000000..58faf20aae7
--- /dev/null
+++ b/lib/libpthread/arch/powerpc64/_context_u.S
@@ -0,0 +1,189 @@
+/* $NetBSD: _context_u.S,v 1.1 2006/07/08 05:09:44 ross Exp $ */
+
+/*
+ * Copyright (c) 2001 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Allen Briggs for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+#include "assym.h"
+
+/*
+ * Define:
+ * int _getcontext_u(ucontext_t *ctx)
+ * Store the current context in the provided ctx structure.
+ * [only store the callee-saved registers]
+ * int _setcontext_u(const ucontext_t *ctx)
+ * Restore the current context from the provided ctx structure.
+ * int _swapcontext_u(ucontext_t *from_ctx, const ucontext_t *to_ctx)
+ * First, store the current context into from_ctx and then
+ * restore the current context from the to_ctx.
+ */
+
+/*
+ * According to the SVR4 ABI for PPC, r1, r14-r31, LR, and portions of the
+ * CR are non-volatile. I.e., they need to be preserved across the function
+ * call.
+ *
+ * If _getcontext_u is called, set the UC_USER_BIT in the UC_FLAGS. If
+ * _setcontext_u sees that bit, then it will just restore this part of the
+ * context, otherwise, it will call through to setcontext(2).
+ */
+
+/*
+ * Arrange to not include FP save/restore on a soft-float
+ * build. Thread switching shouldn't consume 40 system traps.
+ */
+#ifdef _SOFT_FLOAT
+#define FPUFLAG 0
+#define GETFP(reg)
+#define SETFP
+#else
+#define FPUFLAG _UC_FPU
+#define GETFP(reg) \
+ mffs %r0 ; \
+ stfd %r0, (_REG_FPSCR - 4)(reg) ; \
+ stfd %r14, (_REG_FP0 + 14*8)(reg) ; \
+ stfd %r15, (_REG_FP0 + 15*8)(reg) ; \
+ stfd %r16, (_REG_FP0 + 16*8)(reg) ; \
+ stfd %r17, (_REG_FP0 + 17*8)(reg) ; \
+ stfd %r18, (_REG_FP0 + 18*8)(reg) ; \
+ stfd %r19, (_REG_FP0 + 19*8)(reg) ; \
+ stfd %r20, (_REG_FP0 + 20*8)(reg) ; \
+ stfd %r21, (_REG_FP0 + 21*8)(reg) ; \
+ stfd %r22, (_REG_FP0 + 22*8)(reg) ; \
+ stfd %r23, (_REG_FP0 + 23*8)(reg) ; \
+ stfd %r24, (_REG_FP0 + 24*8)(reg) ; \
+ stfd %r25, (_REG_FP0 + 25*8)(reg) ; \
+ stfd %r26, (_REG_FP0 + 26*8)(reg) ; \
+ stfd %r27, (_REG_FP0 + 27*8)(reg) ; \
+ stfd %r28, (_REG_FP0 + 28*8)(reg) ; \
+ stfd %r29, (_REG_FP0 + 29*8)(reg) ; \
+ stfd %r30, (_REG_FP0 + 30*8)(reg) ; \
+ stfd %r31, (_REG_FP0 + 31*8)(reg)
+
+#define SETFP \
+ andi. %r5, %r3, _UC_FPU ; \
+ beq 1f ; \
+ ; \
+ lwz %r5, (_UC_FPVALID)(%r4) ; \
+ or. %r5, %r5, %r5 ; \
+ beq 1f ; \
+ ; \
+ lfd %r14, (_REG_FP0 + 14*8)(%r4) ; \
+ lfd %r15, (_REG_FP0 + 15*8)(%r4) ; \
+ lfd %r16, (_REG_FP0 + 16*8)(%r4) ; \
+ lfd %r17, (_REG_FP0 + 17*8)(%r4) ; \
+ lfd %r18, (_REG_FP0 + 18*8)(%r4) ; \
+ lfd %r19, (_REG_FP0 + 19*8)(%r4) ; \
+ lfd %r20, (_REG_FP0 + 20*8)(%r4) ; \
+ lfd %r21, (_REG_FP0 + 21*8)(%r4) ; \
+ lfd %r22, (_REG_FP0 + 22*8)(%r4) ; \
+ lfd %r23, (_REG_FP0 + 23*8)(%r4) ; \
+ lfd %r24, (_REG_FP0 + 24*8)(%r4) ; \
+ lfd %r25, (_REG_FP0 + 25*8)(%r4) ; \
+ lfd %r26, (_REG_FP0 + 26*8)(%r4) ; \
+ lfd %r27, (_REG_FP0 + 27*8)(%r4) ; \
+ lfd %r28, (_REG_FP0 + 28*8)(%r4) ; \
+ lfd %r29, (_REG_FP0 + 29*8)(%r4) ; \
+ lfd %r30, (_REG_FP0 + 30*8)(%r4) ; \
+ lfd %r31, (_REG_FP0 + 31*8)(%r4) ; \
+ lfd %r0, (_REG_FPSCR - 4)(%r4) ; \
+ mtfsf 0xff, %r0 ; \
+1:
+#endif
+
+
+#define GETC(reg) \
+ std %r1, (_REG_R0 + 1*8)(reg) ; \
+ i = 0 ; \
+ .rept 31-14+1 ; \
+ std 14+i,[_REG_R0+[[14+i]*8]](reg) ; \
+ i = i+1 ; \
+ .endr ; \
+ mfcr %r0 ; \
+ std %r0, _REG_CR(reg) ; \
+ mflr %r0 ; \
+ std %r0, _REG_LR(reg) ; \
+ std %r0, _REG_PC(reg) ; \
+ ; \
+ GETFP(reg) ; \
+ ; \
+ li %r8, 1 ; \
+ stw %r8, (_UC_FPVALID)(reg) ; \
+ slwi %r9, %r8, _UC_USER_BIT ; \
+ ori %r9, %r9, (_UC_CPU | FPUFLAG) ; \
+ stw %r9, (UC_FLAGS)(reg)
+
+#define SETC \
+ li %r9, 1 ; \
+ slwi %r9, %r9, _UC_USER_BIT ; \
+ lwz %r3, (UC_FLAGS)(%r4) ; \
+ and. %r9, %r3, %r9 ; \
+ beq 2f ; \
+ ; \
+ lwz %r1, (_REG_R0 + 1*4)(%r4) ; \
+ /* lmw %r14, (_REG_R0 + 14*4)(%r4) */ ; \
+ i = 0 ; \
+ .rept 31-14+1 ; \
+ ld 14+i,[_REG_R0+[[14+i]*8]](%r4) ;\
+ i = i+1 ; \
+ .endr ; \
+ lwz %r0, _REG_LR(%r4) ; \
+ mtlr %r0 ; \
+ lwz %r0, _REG_PC(%r4) ; \
+ mtctr %r0 ; \
+ ; \
+ SETFP ; \
+ ; \
+ lwz %r0, _REG_CR(%r4) ; \
+ mtcr %r0 ; \
+ bctr ; \
+2: ; \
+ mr %r3, %r4 ; \
+ b .setcontext ; \
+ nop ; \
+ /* NOTREACHED */
+
+ENTRY(_getcontext_u)
+ GETC(%r3)
+ xor %r3,%r3,%r3
+ blr
+
+ENTRY(_setcontext_u)
+ mr %r4,%r3
+ SETC
+
+ENTRY(_swapcontext_u)
+ GETC(%r3)
+ SETC
diff --git a/lib/libpthread/arch/powerpc64/genassym.cf b/lib/libpthread/arch/powerpc64/genassym.cf
new file mode 100644
index 00000000000..827552bad4b
--- /dev/null
+++ b/lib/libpthread/arch/powerpc64/genassym.cf
@@ -0,0 +1,72 @@
+# $NetBSD: genassym.cf,v 1.1 2006/07/08 05:09:44 ross Exp $
+
+# Copyright (c) 2001 Wasabi Systems, Inc.
+# All rights reserved.
+#
+# Written by Allen Briggs for Wasabi Systems, Inc.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the distribution.
+# 3. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed for the NetBSD Project by
+# Wasabi Systems, Inc.
+# 4. The name of Wasabi Systems, Inc. may not be used to endorse
+# or promote products derived from this software without specific prior
+# written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+# BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+# POSSIBILITY OF SUCH DAMAGE.
+#
+
+include <ucontext.h>
+include <sys/queue.h>
+include "pthread.h"
+include "pthread_int.h"
+include "pthread_md.h"
+
+# for _context_u.S
+define UC_FLAGS offsetof(ucontext_t, uc_flags)
+define _UC_FPVALID offsetof(ucontext_t, uc_mcontext.__fpregs.__fpu_valid)
+define _REG_R0 offsetof(ucontext_t, uc_mcontext.__gregs[_REG_R0])
+define _REG_CR offsetof(ucontext_t, uc_mcontext.__gregs[_REG_CR])
+define _REG_LR offsetof(ucontext_t, uc_mcontext.__gregs[_REG_LR])
+define _REG_PC offsetof(ucontext_t, uc_mcontext.__gregs[_REG_PC])
+define _REG_MSR offsetof(ucontext_t, uc_mcontext.__gregs[_REG_MSR])
+define _REG_CTR offsetof(ucontext_t, uc_mcontext.__gregs[_REG_CTR])
+define _REG_XER offsetof(ucontext_t, uc_mcontext.__gregs[_REG_XER])
+define _REG_FP0 offsetof(ucontext_t, uc_mcontext.__fpregs.__fpu_regs[0])
+define _REG_FPSCR offsetof(ucontext_t, uc_mcontext.__fpregs.__fpu_fpscr)
+
+# uc_flags
+define _UC_CPU _UC_CPU
+define _UC_FPU _UC_FPU
+define _UC_USER_BIT _UC_USER_BIT
+
+#========================================================================
+# for pthread_switch.S
+define PT_UC offsetof(struct __pthread_st, pt_uc)
+define PT_TRAPUC offsetof(struct __pthread_st, pt_trapuc)
+define PT_NEXT offsetof(struct __pthread_st, pt_next)
+define PT_SPINLOCKS offsetof(struct __pthread_st, pt_spinlocks)
+define PT_SWITCHTO offsetof(struct __pthread_st, pt_switchto)
+define PT_SWITCHTOUC offsetof(struct __pthread_st, pt_switchtouc)
+define PT_HELDLOCK offsetof(struct __pthread_st, pt_heldlock)
+
+define CONTEXTSIZE sizeof(ucontext_t)
+define STACKSPACE STACKSPACE
diff --git a/lib/libpthread/arch/powerpc64/pthread_md.h b/lib/libpthread/arch/powerpc64/pthread_md.h
new file mode 100644
index 00000000000..5e33899aaf2
--- /dev/null
+++ b/lib/libpthread/arch/powerpc64/pthread_md.h
@@ -0,0 +1,125 @@
+/* $NetBSD: pthread_md.h,v 1.1 2006/07/08 05:09:44 ross Exp $ */
+
+/*
+ * Copyright (c) 2001 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Allen Briggs for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _LIB_PTHREAD_POWERPC_MD_H
+#define _LIB_PTHREAD_POWERPC_MD_H
+
+static inline long
+pthread__sp(void)
+{
+ long ret;
+
+ __asm("mr %0,1" : "=r" (ret));
+
+ return ret;
+}
+
+#define pthread__uc_sp(ucp) ((ucp)->uc_mcontext.__gregs[1])
+#define pthread__uc_pc(ucp) ((ucp)->uc_mcontext.__gregs[34])
+
+/*
+ * Set initial, sane values for registers whose values aren't just
+ * "don't care".
+ * 0xd032 is PSL_USERSET from arch/powerpc/include/psl.h
+ */
+#define _INITCONTEXT_U_MD(ucp) \
+ (ucp)->uc_mcontext.__gregs[_REG_MSR] = 0xd032;
+
+/*
+ * Usable stack space below the ucontext_t.
+ * For a good time, see comments in pthread_switch.S and
+ * ../i386/pthread_switch.S about STACK_SWITCH.
+ */
+#define STACKSPACE 16 /* room for 4 integer values */
+
+/*
+ * Conversions between struct reg and struct mcontext. Used by
+ * libpthread_dbg.
+ */
+
+#define PTHREAD_UCONTEXT_TO_REG(reg, uc) do { \
+ memcpy((reg)->fixreg, (uc)->uc_mcontext.__gregs, 32 * 4); \
+ (reg)->cr = (uc)->uc_mcontext.__gregs[_REG_CR]; \
+ (reg)->lr = (uc)->uc_mcontext.__gregs[_REG_LR]; \
+ (reg)->pc = (uc)->uc_mcontext.__gregs[_REG_PC]; \
+ (reg)->ctr = (uc)->uc_mcontext.__gregs[_REG_CTR]; \
+ (reg)->xer = (uc)->uc_mcontext.__gregs[_REG_XER]; \
+ } while (/*CONSTCOND*/0)
+
+#define PTHREAD_REG_TO_UCONTEXT(uc, reg) do { \
+ memcpy((uc)->uc_mcontext.__gregs, (reg)->fixreg, 32 * 4); \
+ (uc)->uc_mcontext.__gregs[_REG_CR] = (reg)->cr; \
+ (uc)->uc_mcontext.__gregs[_REG_LR] = (reg)->lr; \
+ (uc)->uc_mcontext.__gregs[_REG_PC] = (reg)->pc; \
+ (uc)->uc_mcontext.__gregs[_REG_CTR] = (reg)->ctr; \
+ (uc)->uc_mcontext.__gregs[_REG_XER] = (reg)->xer; \
+ (uc)->uc_flags = ((uc)->uc_flags | _UC_CPU) & ~_UC_USER; \
+ } while (/*CONSTCOND*/0)
+
+#define PTHREAD_UCONTEXT_TO_FPREG(freg, uc) do { \
+ memcpy((freg)->fpreg, (uc)->uc_mcontext.__fpregs.__fpu_regs, \
+ 32 * 4); \
+ (freg)->fpscr = (uc)->uc_mcontext.__fpregs.__fpu_fpscr; \
+ } while (/*CONSTCOND*/0)
+
+#define PTHREAD_FPREG_TO_UCONTEXT(uc, freg) do { \
+ memcpy((uc)->uc_mcontext.__fpregs.__fpu_regs, (freg)->fpreg, \
+ 32 * 4); \
+ (uc)->uc_mcontext.__fpregs.__fpu_fpscr = (freg)->fpscr; \
+ (uc)->uc_flags = ((uc)->uc_flags | _UC_FPU) & ~_UC_USER; \
+ } while (/*CONSTCOND*/0)
+
+#define PTHREAD_UCONTEXT_XREG_FLAG _UC_POWERPC_VEC
+
+#define PTHREAD_UCONTEXT_TO_XREG(xreg, uc) do { \
+ memcpy(((struct vreg *)(xreg))->vreg, \
+ (uc)->uc_mcontext.__vrf.__vrs, \
+ 16 * _NVR); \
+ ((struct vreg *)(xreg))->vscr = (uc)->uc_mcontext.__vrf.__vscr; \
+ ((struct vreg *)(xreg))->vrsave = (uc)->uc_mcontext.__vrf.__vrsave; \
+ } while (/*CONSTCOND*/0)
+
+#define PTHREAD_XREG_TO_UCONTEXT(uc, xreg) do { \
+ memcpy((uc)->uc_mcontext.__vrf.__vrs, \
+ ((struct vreg *)(xreg))->vreg, \
+ 16 * _NVR); \
+ (uc)->uc_mcontext.__vrf.__vscr = ((struct vreg *)(xreg))->vscr; \
+ (uc)->uc_mcontext.__vrf.__vrsave = ((struct vreg *)(xreg))->vrsave; \
+ (uc)->uc_flags = ((uc)->uc_flags | _UC_POWERPC_VEC) & ~_UC_USER; \
+ } while (/*CONSTCOND*/0)
+
+#endif /* _LIB_PTHREAD_POWERPC_MD_H */
diff --git a/lib/libpthread/arch/powerpc64/pthread_switch.S b/lib/libpthread/arch/powerpc64/pthread_switch.S
new file mode 100644
index 00000000000..99442f3e91a
--- /dev/null
+++ b/lib/libpthread/arch/powerpc64/pthread_switch.S
@@ -0,0 +1,310 @@
+/* $NetBSD: pthread_switch.S,v 1.1 2006/07/08 05:09:44 ross Exp $ */
+
+/*
+ * Copyright (c) 2001 Wasabi Systems, Inc.
+ * All rights reserved.
+ *
+ * Written by Allen Briggs for Wasabi Systems, Inc.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed for the NetBSD Project by
+ * Wasabi Systems, Inc.
+ * 4. The name of Wasabi Systems, Inc. may not be used to endorse
+ * or promote products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <machine/asm.h>
+#include "assym.h"
+
+#define NOTREACHED
+
+/*
+ * PowerPC ABI says stack pointer must be 16-byte aligned.
+ */
+#define RND_CTXSIZE ((CONTEXTSIZE + 15) & 0xfffffff0)
+
+/*
+ * Define:
+ * void pthread__switch(pthread_t self, pthread_t next)
+ * void pthread__upcall_switch(pthread_t self, pthread_t next)
+ * void pthread__locked_switch(pthread_t self, pthread_t next,
+ * pt_spin_t *lock)
+ */
+
+
+/*
+ * Evil STACK_SWITCH()
+ * See comments in ../i386/pthread_switch.S.
+ */
+#define STACK_SWITCH(pt,tmp,z) \
+ ld tmp, PT_TRAPUC(pt) ; \
+ or. tmp, tmp, tmp ; \
+ bne 1f ; \
+ ld tmp, PT_UC(pt) ; \
+1: la %r1, -STACKSPACE(tmp) ; \
+ li z, 0 ; \
+ std z, PT_TRAPUC(pt)
+
+/*
+ * void
+ * pthread__switch(pthread_t self (%r3), pthread_t next (%r4))
+ *
+ * Plain switch that doesn't do any special checking or handle spin-
+ * preemption. It isn't used much by normal code, actually; its main
+ * purpose is to be a basic switch engine when the MI code is already
+ * dealing with spin-preemption or other gunk.
+ *
+ * What we do here is allocate the ucontext for the 'self' thread on its
+ * stack, saving the pointer in self's pthread structure, then swapping
+ * context to 'next', effectively deallocating next's context on the way
+ * out.
+ *
+ * Stack:
+ * ------------------------------------------------------------------
+ * highest addresses
+ * saved r31 8 (offset is framesize - 8)
+ * pad 8 pad r31 space up to 16
+ * pad to round ucontext_t up to a 16 byte boundary
+ * ucontext_t (offset is SF_SZ )
+ * other elf stack frame (SF_PARAM_SZ )
+ * elf stack frame header (SF_HEADER_SZ )
+ * lowest addresses
+ * ------------------------------------------------------------------
+ */
+ENTRY(pthread__switch)
+ frameSize = SF_SZ + RND_CTXSIZE + 16 # need +8 for r31, & align
+ saved31 = frameSize - 8
+.macro init_frame
+ stdu %r1, -frameSize(%r1) /* alloc stack space */
+ mflr %r0
+ std %r31,saved31(%r1)
+ std %r3, SF_PARAM+0(%r1) /* self */
+ std %r4, SF_PARAM+8(%r1) /* next */
+ std %r5, SF_PARAM+16(%r1) /* lock, for locked_switch */
+ std %r0, frameSize+SF_LR(%r1) /* Save return address */
+ la %r31, SF_SZ(%r1) /* %r31 = ucontext */
+.endm
+ init_frame
+
+.macro switch_context
+ /* Get the current context */
+ mr %r3, %r31
+ CALL(_getcontext_u)
+ ld %r3, SF_PARAM+0(%r1)
+ ld %r4, SF_PARAM+8(%r1)
+ ld %r5, SF_PARAM+16(%r1)
+ /*
+ * Edit the context to make it continue at switch_return instead of
+ * here.
+ */
+ ld %r6, pthread__common_return@got(%r2)
+ std %r6, SF_SZ+_REG_PC(%r1)
+ std %r31, PT_UC(%r3)
+
+ STACK_SWITCH(%r4, %r7, %r6)
+.endm
+ switch_context
+
+.macro set_context
+ mr %r3, %r7
+ b ._setcontext_u
+.endm
+ set_context
+ NOTREACHED
+
+
+
+pthread__switch_away:
+ STACK_SWITCH(%r4, %r6, %r7)
+
+ or. %r5, %r5, %r5
+ beq 1f
+ lwz %r7, PT_SPINLOCKS(%r3) # w OK
+ addi %r7, %r7, -1
+ stw %r7, PT_SPINLOCKS(%r3) # w OK
+
+1: mr %r3, %r6
+ b ._setcontext_u
+ NOTREACHED
+
+/*
+ * void
+ * pthread__upcall_switch(pthread_t self (%r3), pthread_t next (%r4))
+ */
+ENTRY(pthread__upcall_switch)
+ lwz %r6, PT_SPINLOCKS(%r4) # w OK
+ addi %r6, %r6, 1
+ stw %r6, PT_SPINLOCKS(%r4) # w OK
+
+ STACK_SWITCH(%r4, %r5, %r6)
+
+ ld %r7, PT_NEXT(%r3)
+ or. %r7, %r7, %r7
+ beq 1f
+
+ std %r5, PT_SWITCHTOUC(%r3)
+ std %r4, PT_SWITCHTO(%r3)
+ mr %r3, %r4
+ mr %r4, %r7
+ li %r5, 1
+ b pthread__switch_away
+ NOTREACHED
+
+1: mr %r14, %r3
+ mr %r15, %r4
+ mr %r16, %r5
+ CALL(pthread__sa_recycle)
+ mr %r3, %r14
+ mr %r4, %r15
+ mr %r5, %r16
+
+ lwz %r6, PT_SPINLOCKS(%r4) # w OK
+ addi %r6, %r6, -1
+ stw %r6, PT_SPINLOCKS(%r4) # w OK
+
+ ld %r7, PT_NEXT(%r4)
+ or. %r7, %r7, %r7
+ beq 2f
+
+ std %r5, PT_SWITCHTOUC(%r4)
+ std %r4, PT_SWITCHTO(%r4)
+ mr %r3, %r4
+ mr %r4, %r7
+ li %r5, 0
+ b pthread__switch_away
+ NOTREACHED
+
+2: mr %r3, %r16
+ b ._setcontext_u
+ NOTREACHED
+
+/*
+ * void
+ * pthread__locked_switch(pthread_t self (%r3), pthread_t next (%r4),
+ * pt_spin_t *lock (%r5))
+ *
+ * THIS STACK FRAME APPLIES ONLY TO THE ORIGINAL ILP32 CODE
+ *
+ * Stack is:
+ * high addr -- return addr ( 4 bytes)
+ * %r1@call caller saved %r1 ( 4 bytes)
+ * any padding to make %r1 a multiple of 16 ... *
+ * saved %r31 ( 4 bytes) *
+ * saved %r9 ( 4 bytes) *
+ * saved %r5 ( 4 bytes) *
+ * saved %r4 ( 4 bytes) *
+ * saved %r3 ( 4 bytes) *
+ * context (RND_CTXSIZE bytes) *
+ * padding to 16 bytes ( 20 bytes) *
+ * space for callee ra ( 4 bytes) *
+ * low addr p__l_s saved %r1 ( 4 bytes) *
+ *
+ * STACKSPACE is the space between the bottom of the stack and
+ * the ucontext on the stack. i.e., 8, but we want to keep the stack
+ * rounded to a multiple of 16, so it's really 16.
+ */
+
+ .type locked_return,@function
+
+ENTRY(pthread__locked_switch)
+
+ init_frame
+
+ /* increment spinlock to make sure that next gets continued */
+ lwz %r6, PT_SPINLOCKS(%r4) # w OK
+ addi %r6, %r6, 1
+ stw %r6, PT_SPINLOCKS(%r4) # w OK
+
+ switch_context
+
+ /* Check if the switcher was preempted and continued to here. */
+ ld %r8, PT_NEXT(%r3)
+ or. %r8, %r8, %r8
+ beq 1f
+
+ /*
+ * Yes, it was. Stash the thread we were going to switch to,
+ * the lock the original thread was holding, and switch to the
+ * next thread in the continuation chain. Mark the fact that
+ * this was a locked switch, and so the thread does not need to
+ * be put on a run queue.
+ * Don't release the lock. It's possible that if we do so,
+ * PT_SWITCHTO will be stomped by another switch_lock and preemption.
+ */
+ std %r5, PT_HELDLOCK(%r3)
+ std %r7, PT_SWITCHTOUC(%r3)
+ std %r4, PT_SWITCHTO(%r3)
+ lwz %r6, PT_SPINLOCKS(%r3) # w OK
+ addi %r6, %r6, -1
+ stw %r6, PT_SPINLOCKS(%r3) # w OK
+
+ mr %r3, %r4
+ mr %r4, %r8
+ li %r5, 1
+ b pthread__switch_away
+ NOTREACHED
+
+ /* No locked old-preemption */
+1: /*
+ * We've moved to the new stack, and the old context has been
+ * saved. The queue lock can be released.
+ */
+ /* Reduce the lock count... */
+ lwz %r6, PT_SPINLOCKS(%r3) # w OK
+ addi %r6, %r6, -1
+ stw %r6, PT_SPINLOCKS(%r3) # w OK
+ /* ... actually release the lock ... */
+ sync
+ xor %r9,%r9,%r9
+ std %r9, 0(%r5)
+ /* ... and remove the fake lock */
+ lwz %r6, PT_SPINLOCKS(%r4) # w OK
+ addi %r6, %r6, -1
+ stw %r6, PT_SPINLOCKS(%r4) # w OK
+
+ /* Check to see if we were preempted while holding the fake lock */
+ ld %r8, PT_NEXT(%r4)
+ or. %r8, %r8, %r8
+ beq 2f
+
+ /* Yes, we were. Go to the next element in the chain. */
+ std %r7, PT_SWITCHTOUC(%r4)
+ std %r4, PT_SWITCHTO(%r4)
+ mr %r3, %r4
+ mr %r4, %r8
+ li %r5, 0
+ b pthread__switch_away
+ NOTREACHED
+
+2: set_context
+ NOTREACHED
+
+
+ENTRY(pthread__common_return)
+ ld %r31, saved31(%r1)
+ ld %r0, frameSize+SF_LR(%r1)
+ la %r1, frameSize(%r1)
+ mtlr %r0
+ blr