libpthread support for x86_64.
This commit is contained in:
parent
894bd3ad9d
commit
1627b9c342
|
@ -0,0 +1,132 @@
|
|||
/* $NetBSD: _context_u.S,v 1.1 2003/01/30 02:10:31 fvdl Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2001 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Nathan J. Williams.
|
||||
*
|
||||
* 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 by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
|
||||
*
|
||||
* Adapted for x86_64 by fvdl@netbsd.org
|
||||
*/
|
||||
|
||||
#include <machine/asm.h>
|
||||
#include "assym.h"
|
||||
|
||||
#define GETC \
|
||||
movq (%rsp), %r11 ; \
|
||||
movq %r11, (UC_REGS + _REG_RIP * 8)(%rdi) ; \
|
||||
movq %rbx, (UC_REGS + _REG_RBX * 8)(%rdi) ; \
|
||||
movq %rbp, (UC_REGS + _REG_RBP * 8)(%rdi) ; \
|
||||
movq %r12, (UC_REGS + _REG_R12 * 8)(%rdi) ; \
|
||||
movq %r13, (UC_REGS + _REG_R13 * 8)(%rdi) ; \
|
||||
movq %r14, (UC_REGS + _REG_R14 * 8)(%rdi) ; \
|
||||
movq %r15, (UC_REGS + _REG_R15 * 8)(%rdi) ; \
|
||||
fxsave UC_FPREGS(%rdi) ; \
|
||||
movl $(_UC_USER | _UC_CPU | _UC_FPU),UC_FLAGS(%rdi)
|
||||
|
||||
#define SETC \
|
||||
movl UC_FLAGS(%rdi), %eax ; \
|
||||
btl $_UC_USER_BIT, %eax ; \
|
||||
jnc 1f ; \
|
||||
fxrstor UC_FPREGS(%rdi) ; \
|
||||
movq (UC_REGS + _REG_RBX * 8)(%rdi),%rbx ; \
|
||||
movq (UC_REGS + _REG_RBP * 8)(%rdi),%rbp ; \
|
||||
movq (UC_REGS + _REG_R12 * 8)(%rdi),%r12 ; \
|
||||
movq (UC_REGS + _REG_R13 * 8)(%rdi),%r13 ; \
|
||||
movq (UC_REGS + _REG_R14 * 8)(%rdi),%r14 ; \
|
||||
movq (UC_REGS + _REG_R15 * 8)(%rdi),%r15 ; \
|
||||
movq (UC_REGS + _REG_URSP * 8)(%rdi),%r11 ; \
|
||||
movq (UC_REGS + _REG_RIP * 8)(%rdi),%rax ; \
|
||||
leaq -8(%r11),%rsp ; \
|
||||
movq %rax, (%rsp) ; \
|
||||
ret ; \
|
||||
1: andl $_UC_FPU, %eax ; \
|
||||
jz 2f ; \
|
||||
fxrstor UC_FPREGS(%rdi) ; \
|
||||
2: xorq %rax,%rax ; \
|
||||
movw (UC_REGS + _REG_GS * 8)(%rdi), %gs ; \
|
||||
movw (UC_REGS + _REG_FS * 8)(%rdi), %fs ; \
|
||||
movw (UC_REGS + _REG_ES * 8)(%rdi), %es ; \
|
||||
movq (UC_REGS + _REG_URSP * 8)(%rdi), %r11 ; \
|
||||
movq (UC_REGS + _REG_RBX * 8)(%rdi), %rbx ; \
|
||||
movq (UC_REGS + _REG_RBP * 8)(%rdi), %rbp ; \
|
||||
movq (UC_REGS + _REG_R12 * 8)(%rdi), %r12 ; \
|
||||
movq (UC_REGS + _REG_R13 * 8)(%rdi), %r13 ; \
|
||||
movq (UC_REGS + _REG_R14 * 8)(%rdi), %r14 ; \
|
||||
movq (UC_REGS + _REG_R15 * 8)(%rdi), %r15 ; \
|
||||
movq (UC_REGS + _REG_RBX * 8)(%rdi), %rbx ; \
|
||||
movq (UC_REGS + _REG_R10 * 8)(%rdi), %r10 ; \
|
||||
movq (UC_REGS + _REG_R9 * 8)(%rdi), %r9 ; \
|
||||
movq (UC_REGS + _REG_R8 * 8)(%rdi), %r8 ; \
|
||||
movq (UC_REGS + _REG_RCX * 8)(%rdi), %rcx ; \
|
||||
movq (UC_REGS + _REG_RDX * 8)(%rdi), %rdx ; \
|
||||
movq (UC_REGS + _REG_RSI * 8)(%rdi), %rsi ; \
|
||||
movw (UC_REGS + _REG_CS * 8)(%rdi), %ax ; \
|
||||
movq %rax, -8(%r11) ; \
|
||||
movw (UC_REGS + _REG_DS * 8)(%rdi), %ax ; \
|
||||
movq %rax, -32(%r11) ; \
|
||||
movq (UC_REGS + _REG_RIP * 8)(%rdi), %rax ; \
|
||||
movq %rax, -16(%r11) ; \
|
||||
movq (UC_REGS + _REG_RAX)(%rdi), %rax ; \
|
||||
movq %rax, -24(%r11) ; \
|
||||
movq (UC_REGS + _REG_R11 * 8)(%rdi), %rax ; \
|
||||
movq %rax, -40(%r11) ; \
|
||||
movq (UC_REGS + _REG_RFL * 8)(%rdi), %rax ; \
|
||||
movq %rax, -48(%r11) ; \
|
||||
; \
|
||||
movw (UC_REGS + _REG_SS * 8)(%rdi), %ss ; \
|
||||
movq (UC_REGS + _REG_RDI)(%rdi), %rdi ; \
|
||||
leaq -48(%r11), %rsp ; \
|
||||
; \
|
||||
popfq ; \
|
||||
popq %r11 ; \
|
||||
popq %rax ; \
|
||||
movl %eax,%ds ; \
|
||||
popq %rax ; \
|
||||
lretq
|
||||
|
||||
ENTRY(_getcontext_u)
|
||||
GETC
|
||||
leaq 8(%rsp), %r11
|
||||
movq %r11, (UC_REGS + _REG_URSP * 8)(%rdi)
|
||||
xorl %eax, %eax
|
||||
ret
|
||||
|
||||
ENTRY(_setcontext_u)
|
||||
SETC
|
||||
|
||||
ENTRY(_swapcontext_u)
|
||||
GETC
|
||||
leaq 8(%rsp),%rax
|
||||
movq %rax, (UC_REGS + _REG_URSP * 8)(%rdi)
|
||||
movq %rsi, %rdi
|
||||
SETC
|
|
@ -0,0 +1,92 @@
|
|||
# $NetBSD: genassym.cf,v 1.1 2003/01/30 02:10:31 fvdl Exp $
|
||||
|
||||
# Copyright (c) 2001 The NetBSD Foundation, Inc.
|
||||
# All rights reserved.
|
||||
#
|
||||
# This code is derived from software contributed to The NetBSD Foundation
|
||||
# by Nathan J. Williams.
|
||||
#
|
||||
# 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 by the NetBSD
|
||||
# Foundation, Inc. and its contributors.
|
||||
# 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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 <ucontext.h>
|
||||
include <sys/queue.h>
|
||||
include "pthread.h"
|
||||
include "pthread_int.h"
|
||||
include "pthread_md.h"
|
||||
|
||||
define PT_NEXT offsetof(struct pthread_st, pt_next)
|
||||
define PT_STATE offsetof(struct pthread_st, pt_state)
|
||||
define PT_SWITCHTO offsetof(struct pthread_st, pt_switchto)
|
||||
define PT_SWITCHTOUC offsetof(struct pthread_st, pt_switchtouc)
|
||||
define PT_SLEEPUC offsetof(struct pthread_st, pt_sleepuc)
|
||||
define PT_SPINLOCKS offsetof(struct pthread_st, pt_spinlocks)
|
||||
define PT_HELDLOCK offsetof(struct pthread_st, pt_heldlock)
|
||||
define PT_UC offsetof(struct pthread_st, pt_uc)
|
||||
define CONTEXTSIZE sizeof(ucontext_t)
|
||||
define UC_FLAGS offsetof(ucontext_t, uc_flags)
|
||||
define UC_REGS offsetof(ucontext_t, uc_mcontext.__gregs)
|
||||
define UC_RIP offsetof(ucontext_t, uc_mcontext.__gregs[_REG_RIP])
|
||||
define UC_FPREGS offsetof(ucontext_t, uc_mcontext.__fpregs)
|
||||
|
||||
define PT_STATE_RECYCLABLE PT_STATE_RECYCLABLE
|
||||
define STACKSPACE STACKSPACE
|
||||
|
||||
define _UC_CPU _UC_CPU
|
||||
define _UC_FPU _UC_FPU
|
||||
define _UC_USER _UC_USER
|
||||
define _UC_USER_BIT _UC_USER_BIT
|
||||
|
||||
define _REG_GS _REG_GS
|
||||
define _REG_FS _REG_FS
|
||||
define _REG_ES _REG_ES
|
||||
define _REG_DS _REG_DS
|
||||
define _REG_RDI _REG_RDI
|
||||
define _REG_RSI _REG_RSI
|
||||
define _REG_RBP _REG_RBP
|
||||
define _REG_RBX _REG_RBX
|
||||
define _REG_RDX _REG_RDX
|
||||
define _REG_RCX _REG_RCX
|
||||
define _REG_RAX _REG_RAX
|
||||
define _REG_TRAPNO _REG_TRAPNO
|
||||
define _REG_ERR _REG_ERR
|
||||
define _REG_RIP _REG_RIP
|
||||
define _REG_CS _REG_CS
|
||||
define _REG_RFL _REG_RFL
|
||||
define _REG_URSP _REG_URSP
|
||||
define _REG_SS _REG_SS
|
||||
define _REG_R8 _REG_R8
|
||||
define _REG_R9 _REG_R9
|
||||
define _REG_R10 _REG_R10
|
||||
define _REG_R11 _REG_R11
|
||||
define _REG_R12 _REG_R12
|
||||
define _REG_R13 _REG_R13
|
||||
define _REG_R14 _REG_R14
|
||||
define _REG_R15 _REG_R15
|
|
@ -0,0 +1,154 @@
|
|||
/* $NetBSD: pthread_md.h,v 1.1 2003/01/30 02:10:32 fvdl Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2001 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Nathan J. Williams.
|
||||
*
|
||||
* 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 by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
|
||||
*
|
||||
* Adapted for x86_64 by fvdl@netbsd.org
|
||||
*/
|
||||
|
||||
#ifndef _LIB_PTHREAD_X86_64_MD_H
|
||||
#define _LIB_PTHREAD_X86_64_MD_H
|
||||
|
||||
#include <sys/ucontext.h>
|
||||
|
||||
static __inline long
|
||||
pthread__sp(void)
|
||||
{
|
||||
long ret;
|
||||
__asm("movq %%rsp, %0" : "=g" (ret));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define pthread__uc_sp(ucp) ((ucp)->uc_mcontext.__gregs[_REG_URSP])
|
||||
#define pthread__uc_pc(ucp) ((ucp)->uc_mcontext.__gregs[_REG_RIP])
|
||||
|
||||
/*
|
||||
* Set initial, sane values for registers whose values aren't just
|
||||
* "don't care".
|
||||
* 0x23 is GSEL(GUDATA_SEL, SEL_UPL), and
|
||||
* 0x1b is GSEL(GUCODE_SEL, SEL_UPL).
|
||||
* 0x202 is PSL_USERSET.
|
||||
*/
|
||||
#define _INITCONTEXT_U_MD(ucp) \
|
||||
(ucp)->uc_mcontext.__gregs[_REG_GS] = 0x23, \
|
||||
(ucp)->uc_mcontext.__gregs[_REG_FS] = 0x23, \
|
||||
(ucp)->uc_mcontext.__gregs[_REG_ES] = 0x23, \
|
||||
(ucp)->uc_mcontext.__gregs[_REG_DS] = 0x23, \
|
||||
(ucp)->uc_mcontext.__gregs[_REG_CS] = 0x1b, \
|
||||
(ucp)->uc_mcontext.__gregs[_REG_SS] = 0x23, \
|
||||
(ucp)->uc_mcontext.__gregs[_REG_RFL] = 0x202;
|
||||
|
||||
/*
|
||||
* Usable stack space below the ucontext_t.
|
||||
* See comment in pthread_switch.S about STACK_SWITCH.
|
||||
*/
|
||||
#define STACKSPACE 64 /* room for 8 long values */
|
||||
|
||||
/*
|
||||
* Conversions between struct reg and struct mcontext. Used by
|
||||
* libpthread_dbg.
|
||||
*/
|
||||
|
||||
#define PTHREAD_UCONTEXT_TO_REG(reg, uc) do { \
|
||||
(reg)->r_gs = (uc)->uc_mcontext.__gregs[_REG_GS]; \
|
||||
(reg)->r_fs = (uc)->uc_mcontext.__gregs[_REG_FS]; \
|
||||
(reg)->r_es = (uc)->uc_mcontext.__gregs[_REG_ES]; \
|
||||
(reg)->r_ds = (uc)->uc_mcontext.__gregs[_REG_DS]; \
|
||||
(reg)->r_rdi = (uc)->uc_mcontext.__gregs[_REG_RDI]; \
|
||||
(reg)->r_rsi = (uc)->uc_mcontext.__gregs[_REG_RSI]; \
|
||||
(reg)->r_rbp = (uc)->uc_mcontext.__gregs[_REG_RBP]; \
|
||||
(reg)->r_rbx = (uc)->uc_mcontext.__gregs[_REG_RBX]; \
|
||||
(reg)->r_rdx = (uc)->uc_mcontext.__gregs[_REG_RDX]; \
|
||||
(reg)->r_rcx = (uc)->uc_mcontext.__gregs[_REG_RCX]; \
|
||||
(reg)->r_rax = (uc)->uc_mcontext.__gregs[_REG_RAX]; \
|
||||
(reg)->r_r8 = (uc)->uc_mcontext.__gregs[_REG_R8]; \
|
||||
(reg)->r_r9 = (uc)->uc_mcontext.__gregs[_REG_R9]; \
|
||||
(reg)->r_r10 = (uc)->uc_mcontext.__gregs[_REG_R10]; \
|
||||
(reg)->r_r11 = (uc)->uc_mcontext.__gregs[_REG_R11]; \
|
||||
(reg)->r_r12 = (uc)->uc_mcontext.__gregs[_REG_R12]; \
|
||||
(reg)->r_r13 = (uc)->uc_mcontext.__gregs[_REG_R13]; \
|
||||
(reg)->r_r14 = (uc)->uc_mcontext.__gregs[_REG_R14]; \
|
||||
(reg)->r_r15 = (uc)->uc_mcontext.__gregs[_REG_R15]; \
|
||||
(reg)->r_rip = (uc)->uc_mcontext.__gregs[_REG_RIP]; \
|
||||
(reg)->r_cs = (uc)->uc_mcontext.__gregs[_REG_CS]; \
|
||||
(reg)->r_rflags = (uc)->uc_mcontext.__gregs[_REG_RFL]; \
|
||||
(reg)->r_rsp = (uc)->uc_mcontext.__gregs[_REG_URSP]; \
|
||||
(reg)->r_ss = (uc)->uc_mcontext.__gregs[_REG_SS]; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#define PTHREAD_REG_TO_UCONTEXT(uc, reg) do { \
|
||||
(uc)->uc_mcontext.__gregs[_REG_GS] = (reg)->r_gs; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_FS] = (reg)->r_fs; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_ES] = (reg)->r_es; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_DS] = (reg)->r_ds; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_RDI] = (reg)->r_rdi; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_RSI] = (reg)->r_rsi; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_RBP] = (reg)->r_rbp; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_RBX] = (reg)->r_rbx; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_RDX] = (reg)->r_rdx; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_RCX] = (reg)->r_rcx; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_RAX] = (reg)->r_rax; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_R8] = (reg)->r_r8; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_R9] = (reg)->r_r9; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_R10] = (reg)->r_r10; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_R11] = (reg)->r_r11; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_R12] = (reg)->r_r12; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_R13] = (reg)->r_r13; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_R14] = (reg)->r_r14; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_R15] = (reg)->r_r15; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_RIP] = (reg)->r_rip; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_CS] = (reg)->r_cs; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_RFL] = (reg)->r_rflags; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_URSP]= (reg)->r_rsp; \
|
||||
(uc)->uc_mcontext.__gregs[_REG_SS] = (reg)->r_ss; \
|
||||
/*LINTED precision loss */ \
|
||||
(uc)->uc_flags = ((uc)->uc_flags | _UC_CPU) & ~_UC_USER; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
|
||||
#define PTHREAD_UCONTEXT_TO_FPREG(freg, uc) \
|
||||
(void)memcpy(&(freg)->fxstate, \
|
||||
(uc)->uc_mcontext.__fpregs, sizeof(struct fpreg))
|
||||
|
||||
#define PTHREAD_FPREG_TO_UCONTEXT(uc, freg) do { \
|
||||
(void)memcpy( \
|
||||
(uc)->uc_mcontext.__fpregs, \
|
||||
&(freg)->fxstate, sizeof(struct fpreg)); \
|
||||
/*LINTED precision loss */ \
|
||||
(uc)->uc_flags = ((uc)->uc_flags | _UC_FPU) & ~_UC_USER; \
|
||||
} while (/*CONSTCOND*/0)
|
||||
|
||||
#endif /* _LIB_PTHREAD_X86_64_MD_H */
|
|
@ -0,0 +1,344 @@
|
|||
/* $NetBSD: pthread_switch.S,v 1.1 2003/01/30 02:10:32 fvdl Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2001 The NetBSD Foundation, Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* This code is derived from software contributed to The NetBSD Foundation
|
||||
* by Nathan J. Williams.
|
||||
*
|
||||
* 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 by the NetBSD
|
||||
* Foundation, Inc. and its contributors.
|
||||
* 4. Neither the name of The NetBSD Foundation 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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.
|
||||
*
|
||||
* Adapted for x86_64 by fvdl@netbsd.org
|
||||
*/
|
||||
|
||||
#include <machine/asm.h>
|
||||
#include "assym.h"
|
||||
|
||||
/*
|
||||
* This file implements low-level routines that are exported to
|
||||
* the machine-independent parts of the thread library. The routines are:
|
||||
*
|
||||
* 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);
|
||||
*
|
||||
* as well as some utility code used by these routines.
|
||||
*/
|
||||
|
||||
/* Force an error when "notreached" code is reached. */
|
||||
#define NOTREACHED \
|
||||
int3
|
||||
|
||||
|
||||
/*
|
||||
* Utility macro to switch to the stack of another thread.
|
||||
* WARNING: This is more subtle than it looks.
|
||||
*
|
||||
* There are a couple of motivations for stack switching. One is that
|
||||
* when exiting an upcall and running a thread, we want to recycle the
|
||||
* state of the upcall before continuing the thread. However, the
|
||||
* stack is part of the upcall state, and we can't be on the upcall
|
||||
* stack when we want to recycle it. Therefore, we pre-switch to the
|
||||
* stack of the thread we're about to switch to and borrow some space
|
||||
* on its stack so that we can recycle the upcall.
|
||||
*
|
||||
* Another is that when performing the slightly sensitive operation of
|
||||
* putting the currently running thread on a (locked) sleep queue then
|
||||
* switching to another thread, we don't want to release the queue
|
||||
* lock until we are no longer on the original stack - if we released
|
||||
* it any earlier, it's possible (epecially on a multiprocessor
|
||||
* system) that the original thread could get taken off the queue and
|
||||
* restarted while we're still using its stack, which would be bad
|
||||
* ("Important safety tip. Thanks, Egon").
|
||||
*
|
||||
* The subtlety comes from the contents of the stack of the thread
|
||||
* being switched to. Our convention is that the ucontext_t of the
|
||||
* thread is stored near the top of the stack. When the kernel
|
||||
* preempts a thread, it stores the ucontext_t just above the current
|
||||
* top-of-stack and passes the upcall handler the pointer to the
|
||||
* ucontext_t, and the upcall handler stores it in the the pt_uc field
|
||||
* of the thread structure. When user-level code voluntairly switches
|
||||
* from one thread to another, the ucontext_t is just below the top of
|
||||
* the stack, and we impose a limit on the amount of stack space above
|
||||
* the ucontext_t that may be used. This way, we can perform the stack
|
||||
* switch safely by setting the stack pointer to thread->pt_uc -
|
||||
* STACKSPACE.
|
||||
* Note carefully that we do the subtraction *before* putting the
|
||||
* value in the stack pointer. Since preemption can occur at any time,
|
||||
* and the kernel will happily write the new ucontext_t below the
|
||||
* current stack pointer, it is unsafe for us to ever set the stack
|
||||
* pointer above potentially valid data, even for one instruction.
|
||||
*
|
||||
* Got it? Good. Now go read it again.
|
||||
*
|
||||
*/
|
||||
|
||||
#define STACK_SWITCH \
|
||||
movq PT_UC(%r13), %r11 ; \
|
||||
leaq (-STACKSPACE)(%r11), %rsp
|
||||
|
||||
|
||||
/*
|
||||
* void pthread__switch(pthread_t self, pthread_t next);
|
||||
*
|
||||
* Plain switch that doesn't do any special checking or handle
|
||||
* spin-preemption. It isn't used much by normal code, actually; it's
|
||||
* main purpose is to be a basic switch engine when the MI code is
|
||||
* already dealing with spin-preemption or other gunk.
|
||||
*/
|
||||
ENTRY(pthread__switch)
|
||||
pushq %r12
|
||||
pushq %r13
|
||||
pushq %r14
|
||||
movq %rdi,%r12
|
||||
movq %rsi,%r13
|
||||
/* r12 (eax) holds the current thread */
|
||||
/* r13 (ecx) holds the thread to switch to */
|
||||
subq $CONTEXTSIZE+12, %rsp /* Allocate space for the ucontext_t */
|
||||
leaq 12(%rsp), %r14
|
||||
andq $~(0xf), %r14 /* 16-byte-align the ucontext_t area */
|
||||
/*
|
||||
* Note: Alignment space below the ucontext_t can consume up to
|
||||
* 12 bytes of STACKSPACE.
|
||||
*/
|
||||
movq %r14,%rdi
|
||||
call PIC_PLT(_C_LABEL(_getcontext_u))
|
||||
/*
|
||||
* Edit the context so that it continues as if returning from
|
||||
* the _setcontext_u below.
|
||||
*/
|
||||
#ifdef PIC
|
||||
movq PIC_GOT(switch_return_point), %r11
|
||||
#else
|
||||
leaq locked_return_point, %r11
|
||||
#endif
|
||||
movq %r11, UC_RIP(%r14)
|
||||
|
||||
STACK_SWITCH
|
||||
|
||||
movq %r14, PT_UC(%r12)
|
||||
|
||||
movq %r11, %rdi /* ucontext_t *ucp */
|
||||
call PIC_PLT(_C_LABEL(_setcontext_u))
|
||||
switch_return_point:
|
||||
/* We're back on the original stack. */
|
||||
addq $CONTEXTSIZE+12, %rsp
|
||||
popq %r14
|
||||
popq %r13
|
||||
popq %r12
|
||||
ret
|
||||
|
||||
/*
|
||||
* Helper switch code used by pthread__locked_switch() and
|
||||
* pthread__upcall_switch() when they discover spinlock preemption.
|
||||
*/
|
||||
.globl pthread__switch_away
|
||||
pthread__switch_away:
|
||||
STACK_SWITCH
|
||||
|
||||
/*
|
||||
* If we're invoked from the switch-to-next provisions of
|
||||
* pthread__locked_switch or pthread__upcall_switch, there
|
||||
* may be a fake spinlock-count set. If so, they will set %edx
|
||||
* to let us know, and we decrement it once we're no longer using
|
||||
* the old stack.
|
||||
*/
|
||||
cmpl $0, %r10d
|
||||
jle pthread__switch_no_decrement
|
||||
decl PT_SPINLOCKS(%r12)
|
||||
|
||||
pthread__switch_no_decrement:
|
||||
movq %r15,%rdi /* ucontext_t *ucp */
|
||||
call PIC_PLT(_C_LABEL(_setcontext_u))
|
||||
NOTREACHED
|
||||
|
||||
/*
|
||||
* void pthread__locked_switch(pthread_t self, pthread_t next,
|
||||
* pt_spin_t *lock);
|
||||
*
|
||||
* Switch away from a thread that is holding a lock on a queue (to
|
||||
* prevent being removed from the queue before being switched away).
|
||||
*/
|
||||
ENTRY(pthread__locked_switch)
|
||||
pushq %r12
|
||||
pushq %r13
|
||||
pushq %r14
|
||||
pushq %r15
|
||||
|
||||
movq %rdi, %r12
|
||||
movq %rsi, %r13
|
||||
movq %rdx, %r14
|
||||
incl PT_SPINLOCKS(%r13) /* Make sure we get continued */
|
||||
subq $CONTEXTSIZE+12, %rsp /* Allocate space for the ucontext_t */
|
||||
leaq 12(%rsp), %r15
|
||||
andq $~(0xf), %r15 /* 16-byte-align the ucontext_t area */
|
||||
/*
|
||||
* Note: Alignment space below the ucontext_t can consume up to
|
||||
* 12 bytes of STACKSPACE.
|
||||
*/
|
||||
movq %r15, %rdi
|
||||
call PIC_PLT(_C_LABEL(_getcontext_u))
|
||||
/*
|
||||
* Edit the context so that it continues as if returning from
|
||||
* the _setcontext_u below.
|
||||
*/
|
||||
#ifdef PIC
|
||||
movq PIC_GOT(locked_return_point), %r11
|
||||
#else
|
||||
leaq locked_return_point, %r11
|
||||
#endif
|
||||
movq %r11, UC_RIP(%r15)
|
||||
|
||||
STACK_SWITCH
|
||||
|
||||
movq %r15, PT_UC(%r12)
|
||||
/*
|
||||
* Check if the original thread was preempted while holding
|
||||
* its queue lock.
|
||||
*/
|
||||
cmpq $0, PT_NEXT(%r12)
|
||||
je locked_no_old_preempt
|
||||
|
||||
/*
|
||||
* Yes, it was. Stash the thread we were going to
|
||||
* switch to, the lock the original thread was holding,
|
||||
* and go to the next thread in the 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.
|
||||
*/
|
||||
movq %r13, PT_SWITCHTO(%r12)
|
||||
movq %r11, PT_SWITCHTOUC(%r12)
|
||||
movq %r14, PT_HELDLOCK(%r12)
|
||||
decl PT_SPINLOCKS(%r12)
|
||||
|
||||
/*
|
||||
* Save the context we previously stored in PT_UC(%eax);
|
||||
* that was overwritten when we were preempted and continued,
|
||||
* so we need to put it somewhere.
|
||||
*/
|
||||
movq %r15, PT_SLEEPUC(%r12)
|
||||
|
||||
movq PT_NEXT(%r12), %r11
|
||||
movq %r13, %r12
|
||||
movq %r11, %r13
|
||||
movl $1, %r10d
|
||||
jmp pthread__switch_away
|
||||
NOTREACHED
|
||||
|
||||
locked_no_old_preempt:
|
||||
/*
|
||||
* We've moved to the new stack, and the old context has been
|
||||
* saved. The queue lock can be released.
|
||||
*/
|
||||
decl PT_SPINLOCKS(%r12)
|
||||
/* We happen to know that this is the right way to release a lock. */
|
||||
movl $0, 0(%r14)
|
||||
|
||||
decl PT_SPINLOCKS(%r13)
|
||||
/* Check if we were preempted while holding the fake lock. */
|
||||
cmpq $0, PT_NEXT(%r13)
|
||||
je locked_no_new_preempt
|
||||
/* Yes, we were. Bummer. Go to the next element in the chain. */
|
||||
movq %r13, PT_SWITCHTO(%r13)
|
||||
movq %r11, PT_SWITCHTOUC(%r13)
|
||||
movq %r13, %r12
|
||||
movq PT_NEXT(%r13), %r13
|
||||
movl $-2, %r10d
|
||||
jmp pthread__switch_away
|
||||
NOTREACHED
|
||||
|
||||
locked_no_new_preempt:
|
||||
movq %r11, %rdi /* ucontext_t *ucp */
|
||||
call PIC_PLT(_C_LABEL(_setcontext_u))
|
||||
locked_return_point:
|
||||
/* We're back on the original stack. */
|
||||
addq $CONTEXTSIZE+12, %rsp
|
||||
popq %r15
|
||||
popq %r14
|
||||
popq %r13
|
||||
popq %r12
|
||||
ret
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* void pthread__upcall_switch(pthread_t self, pthread_t next);
|
||||
*
|
||||
* Quit an upcall, recycle it, and jump to the selected thread.
|
||||
*/
|
||||
ENTRY(pthread__upcall_switch)
|
||||
movq %rdi, %r12
|
||||
movq %rsi, %r13
|
||||
incl PT_SPINLOCKS(%r13)
|
||||
|
||||
STACK_SWITCH
|
||||
|
||||
/* Check if the upcall was preempted and continued. */
|
||||
cmpl $0, PT_NEXT(%r12)
|
||||
je upcall_no_old_preempt
|
||||
/*
|
||||
* Yes, it was. Stash the thread we were going to
|
||||
* switch to, and go to the next thread in the chain.
|
||||
*/
|
||||
movq %r13, PT_SWITCHTO(%r12)
|
||||
movq %r11, PT_SWITCHTOUC(%r12)
|
||||
movl $PT_STATE_RECYCLABLE, PT_STATE(%r12)
|
||||
movq PT_NEXT(%r12), %r10
|
||||
movq %r13, %r12
|
||||
movq %r10, %r13
|
||||
movl $1, %r10d
|
||||
jmp pthread__switch_away
|
||||
NOTREACHED
|
||||
|
||||
upcall_no_old_preempt:
|
||||
movq %r12,%rdi
|
||||
movq %r11,%r14
|
||||
call PIC_PLT(_C_LABEL(pthread__sa_recycle))
|
||||
decl PT_SPINLOCKS(%r13)
|
||||
/* Check if we were preempted while holding the fake lock. */
|
||||
cmpq $0, PT_NEXT(%r13)
|
||||
je upcall_no_new_preempt
|
||||
/* Yes, we were. Bummer. Go to the next element in the chain. */
|
||||
movq %r13, PT_SWITCHTO(%r13)
|
||||
movq %r14, PT_SWITCHTOUC(%r13)
|
||||
movq %r13, %r12
|
||||
movq PT_NEXT(%r13), %r13
|
||||
movl $-1, %r10d
|
||||
jmp pthread__switch_away
|
||||
NOTREACHED
|
||||
|
||||
upcall_no_new_preempt:
|
||||
movq %r14, %rdi
|
||||
call PIC_PLT(_C_LABEL(_setcontext_u))
|
||||
NOTREACHED
|
Loading…
Reference in New Issue