libpthread support for x86_64.
This commit is contained in:
parent
894bd3ad9d
commit
1627b9c342
132
lib/libpthread/arch/x86_64/_context_u.S
Normal file
132
lib/libpthread/arch/x86_64/_context_u.S
Normal file
@ -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
|
92
lib/libpthread/arch/x86_64/genassym.cf
Normal file
92
lib/libpthread/arch/x86_64/genassym.cf
Normal file
@ -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
|
154
lib/libpthread/arch/x86_64/pthread_md.h
Normal file
154
lib/libpthread/arch/x86_64/pthread_md.h
Normal file
@ -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 */
|
344
lib/libpthread/arch/x86_64/pthread_switch.S
Normal file
344
lib/libpthread/arch/x86_64/pthread_switch.S
Normal file
@ -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
Block a user