diff options
-rw-r--r-- | lib/libkse/arch/sparc64/Makefile.inc | 5 | ||||
-rw-r--r-- | lib/libkse/arch/sparc64/include/atomic_ops.h | 75 | ||||
-rw-r--r-- | lib/libkse/arch/sparc64/include/pthread_md.h | 243 | ||||
-rw-r--r-- | lib/libkse/arch/sparc64/sparc64/assym.s | 13 | ||||
-rw-r--r-- | lib/libkse/arch/sparc64/sparc64/pthread_md.c | 88 | ||||
-rw-r--r-- | lib/libkse/arch/sparc64/sparc64/thr_getcontext.S | 85 | ||||
-rw-r--r-- | lib/libpthread/arch/sparc64/Makefile.inc | 5 | ||||
-rw-r--r-- | lib/libpthread/arch/sparc64/include/atomic_ops.h | 75 | ||||
-rw-r--r-- | lib/libpthread/arch/sparc64/include/pthread_md.h | 243 | ||||
-rw-r--r-- | lib/libpthread/arch/sparc64/sparc64/assym.s | 13 | ||||
-rw-r--r-- | lib/libpthread/arch/sparc64/sparc64/pthread_md.c | 88 | ||||
-rw-r--r-- | lib/libpthread/arch/sparc64/sparc64/thr_getcontext.S | 85 |
12 files changed, 1018 insertions, 0 deletions
diff --git a/lib/libkse/arch/sparc64/Makefile.inc b/lib/libkse/arch/sparc64/Makefile.inc new file mode 100644 index 0000000..07107b4 --- /dev/null +++ b/lib/libkse/arch/sparc64/Makefile.inc @@ -0,0 +1,5 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH} + +SRCS+= pthread_md.c thr_getcontext.S diff --git a/lib/libkse/arch/sparc64/include/atomic_ops.h b/lib/libkse/arch/sparc64/include/atomic_ops.h new file mode 100644 index 0000000..4f4d8af --- /dev/null +++ b/lib/libkse/arch/sparc64/include/atomic_ops.h @@ -0,0 +1,75 @@ +/*- + * Copyright (c) 2003 Jake Burkholder <jake@FreeBSD.org> + * All rights reserved. + * + * 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. Neither the name of the author nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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. + * + * $FreeBSD$ + */ + +#ifndef _ATOMIC_OPS_H_ +#define _ATOMIC_OPS_H_ + +#include <machine/atomic.h> + +/* + * Atomic swap: + * Atomic (tmp = *dst, *dst = val), then *res = tmp + * + * void atomic_swap_long(long *dst, long val, long *res); + */ +static __inline void +atomic_swap_long(long *dst, long val, long *res) +{ + long tmp; + long r; + + tmp = *dst; + for (;;) { + r = atomic_cas_64(dst, tmp, val); + if (r == tmp) + break; + tmp = r; + } + *res = tmp; +} + +static __inline void +atomic_swap_int(int *dst, int val, int *res) +{ + int tmp; + int r; + + tmp = *dst; + for (;;) { + r = atomic_cas_32(dst, tmp, val); + if (r == tmp) + break; + tmp = r; + } + *res = tmp; +} + +#define atomic_swap_ptr(dst, val, res) \ + atomic_swap_long((long *)dst, (long)val, (long *)res) + +#endif diff --git a/lib/libkse/arch/sparc64/include/pthread_md.h b/lib/libkse/arch/sparc64/include/pthread_md.h new file mode 100644 index 0000000..17ebc3b --- /dev/null +++ b/lib/libkse/arch/sparc64/include/pthread_md.h @@ -0,0 +1,243 @@ +/*- + * Copyright (c) 2003 Jake Burkholder <jake@freebsd.org>. + * Copyright (c) 2003 Marcel Moolenaar + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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. + * + * $FreeBSD$ + */ + +/* + * Machine-dependent thread prototypes/definitions for the thread kernel. + */ +#ifndef _PTHREAD_MD_H_ +#define _PTHREAD_MD_H_ + +#include <sys/kse.h> +#include <stddef.h> +#include <ucontext.h> + +#define KSE_STACKSIZE 16384 + +int _thr_setcontext(mcontext_t *, intptr_t, intptr_t *); +int _thr_getcontext(mcontext_t *); + +#define THR_GETCONTEXT(ucp) _thr_getcontext(&(ucp)->uc_mcontext) +#define THR_SETCONTEXT(ucp) _thr_setcontext(&(ucp)->uc_mcontext, 0, NULL) + +#define PER_THREAD + +struct kcb; +struct kse; +struct pthread; +struct tcb; +struct tdv; /* We don't know what this is yet? */ + + +/* + * %g6 points to one of these. We define the static TLS as an array + * of long double to enforce 16-byte alignment of the TLS memory. + * + * XXX - Both static and dynamic allocation of any of these structures + * will result in a valid, well-aligned thread pointer??? + */ +struct sparc64_tp { + struct tdv *tp_tdv; /* dynamic TLS */ + uint64_t _reserved_; + long double tp_tls[0]; /* static TLS */ +}; + +struct tcb { + struct pthread *tcb_thread; + void *tcb_addr; /* allocated tcb address */ + struct kcb *tcb_curkcb; + uint64_t tcb_isfake; + uint64_t tcb_spare[4]; + struct kse_thr_mailbox tcb_tmbx; /* needs 64-byte alignment */ + struct sparc64_tp tcb_tp; +} __aligned(64); + +struct kcb { + struct kse_mailbox kcb_kmbx; + struct tcb kcb_faketcb; + struct tcb *kcb_curtcb; + struct kse *kcb_kse; +}; + +register struct sparc64_tp *_tp __asm("%g6"); + +#define _tcb ((struct tcb*)((char*)(_tp) - offsetof(struct tcb, tcb_tp))) + +/* + * The kcb and tcb constructors. + */ +struct tcb *_tcb_ctor(struct pthread *); +void _tcb_dtor(struct tcb *); +struct kcb *_kcb_ctor(struct kse *kse); +void _kcb_dtor(struct kcb *); + +/* Called from the KSE to set its private data. */ +static __inline void +_kcb_set(struct kcb *kcb) +{ + /* There is no thread yet; use the fake tcb. */ + _tp = &kcb->kcb_faketcb.tcb_tp; +} + +/* + * Get the current kcb. + * + * This can only be called while in a critical region; don't + * worry about having the kcb changed out from under us. + */ +static __inline struct kcb * +_kcb_get(void) +{ + return (_tcb->tcb_curkcb); +} + +/* + * Enter a critical region. + * + * Read and clear km_curthread in the kse mailbox. + */ +static __inline struct kse_thr_mailbox * +_kcb_critical_enter(void) +{ + struct kse_thr_mailbox *crit; + uint32_t flags; + + if (_tcb->tcb_isfake != 0) { + /* + * We already are in a critical region since + * there is no current thread. + */ + crit = NULL; + } else { + flags = _tcb->tcb_tmbx.tm_flags; + _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL; + crit = _tcb->tcb_curkcb->kcb_kmbx.km_curthread; + _tcb->tcb_curkcb->kcb_kmbx.km_curthread = NULL; + _tcb->tcb_tmbx.tm_flags = flags; + } + return (crit); +} + +static __inline void +_kcb_critical_leave(struct kse_thr_mailbox *crit) +{ + /* No need to do anything if this is a fake tcb. */ + if (_tcb->tcb_isfake == 0) + _tcb->tcb_curkcb->kcb_kmbx.km_curthread = crit; +} + +static __inline int +_kcb_in_critical(void) +{ + uint32_t flags; + int ret; + + if (_tcb->tcb_isfake != 0) { + /* + * We are in a critical region since there is no + * current thread. + */ + ret = 1; + } else { + flags = _tcb->tcb_tmbx.tm_flags; + _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL; + ret = (_tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL); + _tcb->tcb_tmbx.tm_flags = flags; + } + return (ret); +} + +static __inline void +_tcb_set(struct kcb *kcb, struct tcb *tcb) +{ + if (tcb == NULL) + tcb = &kcb->kcb_faketcb; + kcb->kcb_curtcb = tcb; + tcb->tcb_curkcb = kcb; + _tp = &tcb->tcb_tp; +} + +static __inline struct tcb * +_tcb_get(void) +{ + return (_tcb); +} + +static __inline struct pthread * +_get_curthread(void) +{ + return (_tcb->tcb_thread); +} + +/* + * Get the current kse. + * + * Like _kcb_get(), this can only be called while in a critical region. + */ +static __inline struct kse * +_get_curkse(void) +{ + return (_tcb->tcb_curkcb->kcb_kse); +} + +void _sparc64_enter_uts(kse_func_t uts, struct kse_mailbox *km, void *stack, + size_t stacksz); + +static __inline int +_thread_enter_uts(struct tcb *tcb, struct kcb *kcb) +{ + if (_thr_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext) == 0) { + /* Make the fake tcb the current thread. */ + kcb->kcb_curtcb = &kcb->kcb_faketcb; + _tp = &kcb->kcb_faketcb.tcb_tp; + _sparc64_enter_uts(kcb->kcb_kmbx.km_func, &kcb->kcb_kmbx, + kcb->kcb_kmbx.km_stack.ss_sp, + kcb->kcb_kmbx.km_stack.ss_size); + /* We should not reach here. */ + return (-1); + } + return (0); +} + +static __inline int +_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox) +{ + mcontext_t *mc; + + _tcb_set(kcb, tcb); + mc = &tcb->tcb_tmbx.tm_context.uc_mcontext; + if (setmbox) + _thr_setcontext(mc, (intptr_t)&tcb->tcb_tmbx, + (intptr_t *)&kcb->kcb_kmbx.km_curthread); + else + _thr_setcontext(mc, 0, NULL); + /* We should not reach here. */ + return (-1); +} + +#endif /* _PTHREAD_MD_H_ */ diff --git a/lib/libkse/arch/sparc64/sparc64/assym.s b/lib/libkse/arch/sparc64/sparc64/assym.s new file mode 100644 index 0000000..414163b --- /dev/null +++ b/lib/libkse/arch/sparc64/sparc64/assym.s @@ -0,0 +1,13 @@ +/* + * Offsets into structures used from asm. Must be kept in sync with + * appropriate headers. + * + * $FreeBSD$ + */ + +#define UC_MCONTEXT 0x40 + +#define MC_GLOBAL 0x0 +#define MC_OUT 0x40 +#define MC_TPC 0xc8 +#define MC_TNPC 0xc0 diff --git a/lib/libkse/arch/sparc64/sparc64/pthread_md.c b/lib/libkse/arch/sparc64/sparc64/pthread_md.c new file mode 100644 index 0000000..2006069 --- /dev/null +++ b/lib/libkse/arch/sparc64/sparc64/pthread_md.c @@ -0,0 +1,88 @@ +/*- + * Copyright (C) 2003 Jake Burkholder <jake@freebsd.org> + * Copyright (C) 2003 David Xu <davidxu@freebsd.org> + * Copyright (c) 2001,2003 Daniel Eischen <deischen@freebsd.org> + * All rights reserved. + * + * 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. Neither the name of the author nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> + +#include <unistd.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <ucontext.h> + +#include "pthread_md.h" + +struct tcb * +_tcb_ctor(struct pthread *thread) +{ + struct tcb *tcb; + void *addr; + + addr = malloc(sizeof(struct tcb) + 63); + if (addr == NULL) + tcb = NULL; + else { + tcb = (struct tcb *)(((uintptr_t)(addr) + 63) & ~63); + bzero(tcb, sizeof(struct tcb)); + tcb->tcb_addr = addr; + tcb->tcb_thread = thread; + /* XXX - Allocate tdv/tls */ + } + return (tcb); +} + +void +_tcb_dtor(struct tcb *tcb) +{ + void *addr; + + addr = tcb->tcb_addr; + tcb->tcb_addr = NULL; + free(addr); +} + +struct kcb * +_kcb_ctor(struct kse *kse) +{ + struct kcb *kcb; + + kcb = malloc(sizeof(struct kcb)); + if (kcb != NULL) { + bzero(kcb, sizeof(struct kcb)); + kcb->kcb_kse = kse; + } + return (kcb); +} + +void +_kcb_dtor(struct kcb *kcb) +{ + free(kcb); +} diff --git a/lib/libkse/arch/sparc64/sparc64/thr_getcontext.S b/lib/libkse/arch/sparc64/sparc64/thr_getcontext.S new file mode 100644 index 0000000..9c36bf5 --- /dev/null +++ b/lib/libkse/arch/sparc64/sparc64/thr_getcontext.S @@ -0,0 +1,85 @@ +/*- + * Copyright (C) 2003 Jake Burkholder <jake@freebsd.org> + * All rights reserved. + * + * 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. Neither the name of the author nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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> +__FBSDID("$FreeBSD$"); + +#include "assym.s" + + .weak CNAME(_thr_getcontext) + .set CNAME(_thr_getcontext),CNAME(__thr_getcontext) +ENTRY(__thr_getcontext) + add %o7, 8, %o1 + add %o1, 4, %o2 + stx %sp, [%o0 + MC_OUT + (6 * 8)] + stx %o1, [%o0 + MC_TPC] + stx %o2, [%o0 + MC_TNPC] + mov 1, %l0 # Validate the context. + stx %l0, [%o0 + MC_GLOBAL] + retl + nop +END(__thr_getcontext) + + .weak CNAME(_thr_setcontext) + .set CNAME(_thr_setcontext),CNAME(__thr_setcontext) +ENTRY(__thr_setcontext) + save %sp, -CCFSZ, %sp + flushw + mov %i0, %l0 + mov %i1, %l1 + mov %i2, %l2 + ldx [%l0 + MC_GLOBAL + (1 * 8)], %g1 + ldx [%l0 + MC_GLOBAL + (2 * 8)], %g2 + ldx [%l0 + MC_GLOBAL + (3 * 8)], %g3 + ldx [%l0 + MC_GLOBAL + (4 * 8)], %g4 + ldx [%l0 + MC_GLOBAL + (5 * 8)], %g5 + ldx [%l0 + MC_GLOBAL + (6 * 8)], %g6 + ldx [%l0 + MC_GLOBAL + (7 * 8)], %g7 + ldx [%l0 + MC_OUT + (0 * 8)], %i0 + ldx [%l0 + MC_OUT + (1 * 8)], %i1 + ldx [%l0 + MC_OUT + (2 * 8)], %i2 + ldx [%l0 + MC_OUT + (3 * 8)], %i3 + ldx [%l0 + MC_OUT + (4 * 8)], %i4 + ldx [%l0 + MC_OUT + (5 * 8)], %i5 + ldx [%l0 + MC_OUT + (6 * 8)], %i6 + ldx [%l0 + MC_OUT + (7 * 8)], %i7 + ldx [%l0 + MC_TPC], %l4 + ldx [%l0 + MC_TNPC], %l3 + brz %l2, 1f + nop + stx %l1, [%l2] +1: jmpl %l3, %g0 + return %l4 +END(__thr_setcontext) + +ENTRY(_sparc64_enter_uts) + save %sp, -CCFSZ, %sp + flushw + add %i2, %i3, %i2 + sub %i2, SPOFF + CCFSZ, %sp + jmpl %i1, %g0 + mov %i0, %o0 +END(_sparc64_enter_uts) diff --git a/lib/libpthread/arch/sparc64/Makefile.inc b/lib/libpthread/arch/sparc64/Makefile.inc new file mode 100644 index 0000000..07107b4 --- /dev/null +++ b/lib/libpthread/arch/sparc64/Makefile.inc @@ -0,0 +1,5 @@ +# $FreeBSD$ + +.PATH: ${.CURDIR}/arch/${MACHINE_ARCH}/${MACHINE_ARCH} + +SRCS+= pthread_md.c thr_getcontext.S diff --git a/lib/libpthread/arch/sparc64/include/atomic_ops.h b/lib/libpthread/arch/sparc64/include/atomic_ops.h new file mode 100644 index 0000000..4f4d8af --- /dev/null +++ b/lib/libpthread/arch/sparc64/include/atomic_ops.h @@ -0,0 +1,75 @@ +/*- + * Copyright (c) 2003 Jake Burkholder <jake@FreeBSD.org> + * All rights reserved. + * + * 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. Neither the name of the author nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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. + * + * $FreeBSD$ + */ + +#ifndef _ATOMIC_OPS_H_ +#define _ATOMIC_OPS_H_ + +#include <machine/atomic.h> + +/* + * Atomic swap: + * Atomic (tmp = *dst, *dst = val), then *res = tmp + * + * void atomic_swap_long(long *dst, long val, long *res); + */ +static __inline void +atomic_swap_long(long *dst, long val, long *res) +{ + long tmp; + long r; + + tmp = *dst; + for (;;) { + r = atomic_cas_64(dst, tmp, val); + if (r == tmp) + break; + tmp = r; + } + *res = tmp; +} + +static __inline void +atomic_swap_int(int *dst, int val, int *res) +{ + int tmp; + int r; + + tmp = *dst; + for (;;) { + r = atomic_cas_32(dst, tmp, val); + if (r == tmp) + break; + tmp = r; + } + *res = tmp; +} + +#define atomic_swap_ptr(dst, val, res) \ + atomic_swap_long((long *)dst, (long)val, (long *)res) + +#endif diff --git a/lib/libpthread/arch/sparc64/include/pthread_md.h b/lib/libpthread/arch/sparc64/include/pthread_md.h new file mode 100644 index 0000000..17ebc3b --- /dev/null +++ b/lib/libpthread/arch/sparc64/include/pthread_md.h @@ -0,0 +1,243 @@ +/*- + * Copyright (c) 2003 Jake Burkholder <jake@freebsd.org>. + * Copyright (c) 2003 Marcel Moolenaar + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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. + * + * $FreeBSD$ + */ + +/* + * Machine-dependent thread prototypes/definitions for the thread kernel. + */ +#ifndef _PTHREAD_MD_H_ +#define _PTHREAD_MD_H_ + +#include <sys/kse.h> +#include <stddef.h> +#include <ucontext.h> + +#define KSE_STACKSIZE 16384 + +int _thr_setcontext(mcontext_t *, intptr_t, intptr_t *); +int _thr_getcontext(mcontext_t *); + +#define THR_GETCONTEXT(ucp) _thr_getcontext(&(ucp)->uc_mcontext) +#define THR_SETCONTEXT(ucp) _thr_setcontext(&(ucp)->uc_mcontext, 0, NULL) + +#define PER_THREAD + +struct kcb; +struct kse; +struct pthread; +struct tcb; +struct tdv; /* We don't know what this is yet? */ + + +/* + * %g6 points to one of these. We define the static TLS as an array + * of long double to enforce 16-byte alignment of the TLS memory. + * + * XXX - Both static and dynamic allocation of any of these structures + * will result in a valid, well-aligned thread pointer??? + */ +struct sparc64_tp { + struct tdv *tp_tdv; /* dynamic TLS */ + uint64_t _reserved_; + long double tp_tls[0]; /* static TLS */ +}; + +struct tcb { + struct pthread *tcb_thread; + void *tcb_addr; /* allocated tcb address */ + struct kcb *tcb_curkcb; + uint64_t tcb_isfake; + uint64_t tcb_spare[4]; + struct kse_thr_mailbox tcb_tmbx; /* needs 64-byte alignment */ + struct sparc64_tp tcb_tp; +} __aligned(64); + +struct kcb { + struct kse_mailbox kcb_kmbx; + struct tcb kcb_faketcb; + struct tcb *kcb_curtcb; + struct kse *kcb_kse; +}; + +register struct sparc64_tp *_tp __asm("%g6"); + +#define _tcb ((struct tcb*)((char*)(_tp) - offsetof(struct tcb, tcb_tp))) + +/* + * The kcb and tcb constructors. + */ +struct tcb *_tcb_ctor(struct pthread *); +void _tcb_dtor(struct tcb *); +struct kcb *_kcb_ctor(struct kse *kse); +void _kcb_dtor(struct kcb *); + +/* Called from the KSE to set its private data. */ +static __inline void +_kcb_set(struct kcb *kcb) +{ + /* There is no thread yet; use the fake tcb. */ + _tp = &kcb->kcb_faketcb.tcb_tp; +} + +/* + * Get the current kcb. + * + * This can only be called while in a critical region; don't + * worry about having the kcb changed out from under us. + */ +static __inline struct kcb * +_kcb_get(void) +{ + return (_tcb->tcb_curkcb); +} + +/* + * Enter a critical region. + * + * Read and clear km_curthread in the kse mailbox. + */ +static __inline struct kse_thr_mailbox * +_kcb_critical_enter(void) +{ + struct kse_thr_mailbox *crit; + uint32_t flags; + + if (_tcb->tcb_isfake != 0) { + /* + * We already are in a critical region since + * there is no current thread. + */ + crit = NULL; + } else { + flags = _tcb->tcb_tmbx.tm_flags; + _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL; + crit = _tcb->tcb_curkcb->kcb_kmbx.km_curthread; + _tcb->tcb_curkcb->kcb_kmbx.km_curthread = NULL; + _tcb->tcb_tmbx.tm_flags = flags; + } + return (crit); +} + +static __inline void +_kcb_critical_leave(struct kse_thr_mailbox *crit) +{ + /* No need to do anything if this is a fake tcb. */ + if (_tcb->tcb_isfake == 0) + _tcb->tcb_curkcb->kcb_kmbx.km_curthread = crit; +} + +static __inline int +_kcb_in_critical(void) +{ + uint32_t flags; + int ret; + + if (_tcb->tcb_isfake != 0) { + /* + * We are in a critical region since there is no + * current thread. + */ + ret = 1; + } else { + flags = _tcb->tcb_tmbx.tm_flags; + _tcb->tcb_tmbx.tm_flags |= TMF_NOUPCALL; + ret = (_tcb->tcb_curkcb->kcb_kmbx.km_curthread == NULL); + _tcb->tcb_tmbx.tm_flags = flags; + } + return (ret); +} + +static __inline void +_tcb_set(struct kcb *kcb, struct tcb *tcb) +{ + if (tcb == NULL) + tcb = &kcb->kcb_faketcb; + kcb->kcb_curtcb = tcb; + tcb->tcb_curkcb = kcb; + _tp = &tcb->tcb_tp; +} + +static __inline struct tcb * +_tcb_get(void) +{ + return (_tcb); +} + +static __inline struct pthread * +_get_curthread(void) +{ + return (_tcb->tcb_thread); +} + +/* + * Get the current kse. + * + * Like _kcb_get(), this can only be called while in a critical region. + */ +static __inline struct kse * +_get_curkse(void) +{ + return (_tcb->tcb_curkcb->kcb_kse); +} + +void _sparc64_enter_uts(kse_func_t uts, struct kse_mailbox *km, void *stack, + size_t stacksz); + +static __inline int +_thread_enter_uts(struct tcb *tcb, struct kcb *kcb) +{ + if (_thr_getcontext(&tcb->tcb_tmbx.tm_context.uc_mcontext) == 0) { + /* Make the fake tcb the current thread. */ + kcb->kcb_curtcb = &kcb->kcb_faketcb; + _tp = &kcb->kcb_faketcb.tcb_tp; + _sparc64_enter_uts(kcb->kcb_kmbx.km_func, &kcb->kcb_kmbx, + kcb->kcb_kmbx.km_stack.ss_sp, + kcb->kcb_kmbx.km_stack.ss_size); + /* We should not reach here. */ + return (-1); + } + return (0); +} + +static __inline int +_thread_switch(struct kcb *kcb, struct tcb *tcb, int setmbox) +{ + mcontext_t *mc; + + _tcb_set(kcb, tcb); + mc = &tcb->tcb_tmbx.tm_context.uc_mcontext; + if (setmbox) + _thr_setcontext(mc, (intptr_t)&tcb->tcb_tmbx, + (intptr_t *)&kcb->kcb_kmbx.km_curthread); + else + _thr_setcontext(mc, 0, NULL); + /* We should not reach here. */ + return (-1); +} + +#endif /* _PTHREAD_MD_H_ */ diff --git a/lib/libpthread/arch/sparc64/sparc64/assym.s b/lib/libpthread/arch/sparc64/sparc64/assym.s new file mode 100644 index 0000000..414163b --- /dev/null +++ b/lib/libpthread/arch/sparc64/sparc64/assym.s @@ -0,0 +1,13 @@ +/* + * Offsets into structures used from asm. Must be kept in sync with + * appropriate headers. + * + * $FreeBSD$ + */ + +#define UC_MCONTEXT 0x40 + +#define MC_GLOBAL 0x0 +#define MC_OUT 0x40 +#define MC_TPC 0xc8 +#define MC_TNPC 0xc0 diff --git a/lib/libpthread/arch/sparc64/sparc64/pthread_md.c b/lib/libpthread/arch/sparc64/sparc64/pthread_md.c new file mode 100644 index 0000000..2006069 --- /dev/null +++ b/lib/libpthread/arch/sparc64/sparc64/pthread_md.c @@ -0,0 +1,88 @@ +/*- + * Copyright (C) 2003 Jake Burkholder <jake@freebsd.org> + * Copyright (C) 2003 David Xu <davidxu@freebsd.org> + * Copyright (c) 2001,2003 Daniel Eischen <deischen@freebsd.org> + * All rights reserved. + * + * 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. Neither the name of the author nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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 <sys/cdefs.h> +__FBSDID("$FreeBSD$"); + +#include <sys/types.h> + +#include <unistd.h> +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <ucontext.h> + +#include "pthread_md.h" + +struct tcb * +_tcb_ctor(struct pthread *thread) +{ + struct tcb *tcb; + void *addr; + + addr = malloc(sizeof(struct tcb) + 63); + if (addr == NULL) + tcb = NULL; + else { + tcb = (struct tcb *)(((uintptr_t)(addr) + 63) & ~63); + bzero(tcb, sizeof(struct tcb)); + tcb->tcb_addr = addr; + tcb->tcb_thread = thread; + /* XXX - Allocate tdv/tls */ + } + return (tcb); +} + +void +_tcb_dtor(struct tcb *tcb) +{ + void *addr; + + addr = tcb->tcb_addr; + tcb->tcb_addr = NULL; + free(addr); +} + +struct kcb * +_kcb_ctor(struct kse *kse) +{ + struct kcb *kcb; + + kcb = malloc(sizeof(struct kcb)); + if (kcb != NULL) { + bzero(kcb, sizeof(struct kcb)); + kcb->kcb_kse = kse; + } + return (kcb); +} + +void +_kcb_dtor(struct kcb *kcb) +{ + free(kcb); +} diff --git a/lib/libpthread/arch/sparc64/sparc64/thr_getcontext.S b/lib/libpthread/arch/sparc64/sparc64/thr_getcontext.S new file mode 100644 index 0000000..9c36bf5 --- /dev/null +++ b/lib/libpthread/arch/sparc64/sparc64/thr_getcontext.S @@ -0,0 +1,85 @@ +/*- + * Copyright (C) 2003 Jake Burkholder <jake@freebsd.org> + * All rights reserved. + * + * 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. Neither the name of the author nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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> +__FBSDID("$FreeBSD$"); + +#include "assym.s" + + .weak CNAME(_thr_getcontext) + .set CNAME(_thr_getcontext),CNAME(__thr_getcontext) +ENTRY(__thr_getcontext) + add %o7, 8, %o1 + add %o1, 4, %o2 + stx %sp, [%o0 + MC_OUT + (6 * 8)] + stx %o1, [%o0 + MC_TPC] + stx %o2, [%o0 + MC_TNPC] + mov 1, %l0 # Validate the context. + stx %l0, [%o0 + MC_GLOBAL] + retl + nop +END(__thr_getcontext) + + .weak CNAME(_thr_setcontext) + .set CNAME(_thr_setcontext),CNAME(__thr_setcontext) +ENTRY(__thr_setcontext) + save %sp, -CCFSZ, %sp + flushw + mov %i0, %l0 + mov %i1, %l1 + mov %i2, %l2 + ldx [%l0 + MC_GLOBAL + (1 * 8)], %g1 + ldx [%l0 + MC_GLOBAL + (2 * 8)], %g2 + ldx [%l0 + MC_GLOBAL + (3 * 8)], %g3 + ldx [%l0 + MC_GLOBAL + (4 * 8)], %g4 + ldx [%l0 + MC_GLOBAL + (5 * 8)], %g5 + ldx [%l0 + MC_GLOBAL + (6 * 8)], %g6 + ldx [%l0 + MC_GLOBAL + (7 * 8)], %g7 + ldx [%l0 + MC_OUT + (0 * 8)], %i0 + ldx [%l0 + MC_OUT + (1 * 8)], %i1 + ldx [%l0 + MC_OUT + (2 * 8)], %i2 + ldx [%l0 + MC_OUT + (3 * 8)], %i3 + ldx [%l0 + MC_OUT + (4 * 8)], %i4 + ldx [%l0 + MC_OUT + (5 * 8)], %i5 + ldx [%l0 + MC_OUT + (6 * 8)], %i6 + ldx [%l0 + MC_OUT + (7 * 8)], %i7 + ldx [%l0 + MC_TPC], %l4 + ldx [%l0 + MC_TNPC], %l3 + brz %l2, 1f + nop + stx %l1, [%l2] +1: jmpl %l3, %g0 + return %l4 +END(__thr_setcontext) + +ENTRY(_sparc64_enter_uts) + save %sp, -CCFSZ, %sp + flushw + add %i2, %i3, %i2 + sub %i2, SPOFF + CCFSZ, %sp + jmpl %i1, %g0 + mov %i0, %o0 +END(_sparc64_enter_uts) |