1/* Copyright (C) 2008-2016 Free Software Foundation, Inc. 2 Contributed by Richard Henderson <rth@redhat.com>. 3 4 This file is part of the GNU Transactional Memory Library (libitm). 5 6 Libitm is free software; you can redistribute it and/or modify it 7 under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 3 of the License, or 9 (at your option) any later version. 10 11 Libitm is distributed in the hope that it will be useful, but WITHOUT ANY 12 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 FOR A PARTICULAR PURPOSE. See the GNU General Public License for 14 more details. 15 16 Under Section 7 of GPL version 3, you are granted additional 17 permissions described in the GCC Runtime Library Exception, version 18 3.1, as published by the Free Software Foundation. 19 20 You should have received a copy of the GNU General Public License and 21 a copy of the GCC Runtime Library Exception along with this program; 22 see the files COPYING3 and COPYING.RUNTIME respectively. If not, see 23 <http://www.gnu.org/licenses/>. */ 24 25 26#include "asmcfi.h" 27#include "config.h" 28 29#define CONCAT1(a, b) CONCAT2(a, b) 30#define CONCAT2(a, b) a ## b 31 32#ifdef __USER_LABEL_PREFIX__ 33# define SYM(x) CONCAT1 (__USER_LABEL_PREFIX__, x) 34#else 35# define SYM(x) x 36#endif 37 38#ifdef __ELF__ 39# define TYPE(x) .type SYM(x), @function 40# define SIZE(x) .size SYM(x), . - SYM(x) 41# ifdef HAVE_ATTRIBUTE_VISIBILITY 42# define HIDDEN(x) .hidden SYM(x) 43# else 44# define HIDDEN(x) 45# endif 46#else 47# define TYPE(x) 48# define SIZE(x) 49# ifdef __MACH__ 50# define HIDDEN(x) .private_extern SYM(x) 51# else 52# define HIDDEN(x) 53# endif 54#endif 55 56/* These are duplicates of the canonical definitions in libitm.h. Note that 57 the code relies on pr_uninstrumentedCode == a_runUninstrumentedCode. */ 58#define pr_uninstrumentedCode 0x02 59#define pr_hasNoAbort 0x08 60#define pr_HTMRetryableAbort 0x800000 61#define pr_HTMRetriedAfterAbort 0x1000000 62#define a_runInstrumentedCode 0x01 63#define a_runUninstrumentedCode 0x02 64#define a_tryHTMFastPath 0x20 65 66#define _XABORT_EXPLICIT (1 << 0) 67#define _XABORT_RETRY (1 << 1) 68 69 .text 70 71 .align 4 72 .globl SYM(_ITM_beginTransaction) 73 74SYM(_ITM_beginTransaction): 75 cfi_startproc 76#ifdef __x86_64__ 77#ifdef HAVE_AS_RTM 78 /* Custom HTM fast path. We start the HW transaction here and let 79 gtm_thread::begin_transaction (aka GTM_begin_transaction) decide 80 how to proceed on aborts: We either retry the fast path, or fall 81 back to another execution method. RTM restores all registers after 82 a HW transaction abort, so we can do the SW setjmp after aborts, 83 and we have to because we might choose a SW fall back. However, 84 we have to explicitly save/restore the first argument (edi). 85 The htm_fastpath field is the second int in gtm_rwlock. */ 86 cmpl $0, (SYM(gtm_serial_lock)+4)(%rip) 87 jz .Lno_htm 88 testl $pr_hasNoAbort, %edi 89 jz .Lno_htm 90.Lhtm_fastpath: 91 xbegin .Ltxn_abort 92 /* Monitor the serial lock (specifically, the 32b writer/summary field 93 at its start), and only continue if there is no serial-mode 94 transaction. Note that we might be just a nested transaction and 95 our outermost transaction might be in serial mode; we check for 96 this case in the retry policy implementation. */ 97 cmpl $0, SYM(gtm_serial_lock)(%rip) 98 jnz 1f 99 /* Now also check that HW transactions are still allowed to run (see 100 gtm_thread::begin_transaction for why this is necessary). */ 101 cmpl $0, (SYM(gtm_serial_lock)+4)(%rip) 102 jz 1f 103 /* Everything is good. Run the transaction, preferably using the 104 uninstrumented code path. Note that the following works because 105 pr_uninstrumentedCode == a_runUninstrumentedCode. */ 106 andl $pr_uninstrumentedCode, %edi 107 mov $a_runInstrumentedCode, %eax 108 cmovnz %edi, %eax 109 ret 110 /* There is a serial-mode transaction or HW transactions are not 111 allowed anymore, so abort (see htm_abort() regarding the abort 112 code). */ 1131: xabort $0xff 114.Ltxn_abort: 115 /* If it might make sense to retry the HTM fast path, let the C++ 116 code decide. */ 117 testl $(_XABORT_RETRY|_XABORT_EXPLICIT), %eax 118 jz .Lno_htm 119 orl $pr_HTMRetryableAbort, %edi 120 /* Let the C++ code handle the retry policy. */ 121.Lno_htm: 122#endif 123 leaq 8(%rsp), %rax 124 subq $72, %rsp 125 cfi_adjust_cfa_offset(72) 126 /* Store edi for future HTM fast path retries. We use a stack slot 127 lower than the jmpbuf so that the jmpbuf's rip field will overlap 128 with the proper return address on the stack. */ 129 movl %edi, 8(%rsp) 130 /* Save the jmpbuf for any non-HTM-fastpath execution method. 131 Because rsp-based addressing is 1 byte larger and we've got rax 132 handy, use it. */ 133 movq %rax, -64(%rax) 134 movq %rbx, -56(%rax) 135 movq %rbp, -48(%rax) 136 movq %r12, -40(%rax) 137 movq %r13, -32(%rax) 138 movq %r14, -24(%rax) 139 movq %r15, -16(%rax) 140 leaq -64(%rax), %rsi 141 call SYM(GTM_begin_transaction) 142 movl 8(%rsp), %edi 143 addq $72, %rsp 144 cfi_adjust_cfa_offset(-72) 145#ifdef HAVE_AS_RTM 146 /* If a_tryHTMFastPath was returned, then we need to retry the 147 fast path. We also restore edi and set pr_HTMRetriedAfterAbort 148 to state that we have retried the fast path already (it's harmless 149 if this bit is set even if we don't retry the fast path because it 150 is checked iff pr_HTMRetryableAbort is set). We clear 151 pr_HTMRetryableAbort because it applies to a previous HW 152 transaction attempt. */ 153 cmpl $a_tryHTMFastPath, %eax 154 jnz 2f 155 andl $(0xffffffff-pr_HTMRetryableAbort), %edi 156 orl $pr_HTMRetriedAfterAbort, %edi 157 jmp .Lhtm_fastpath 1582: 159#endif 160#else 161 leal 4(%esp), %ecx 162 movl 4(%esp), %eax 163 subl $28, %esp 164 cfi_def_cfa_offset(32) 165 movl %ecx, 8(%esp) 166 movl %ebx, 12(%esp) 167 movl %esi, 16(%esp) 168 movl %edi, 20(%esp) 169 movl %ebp, 24(%esp) 170 leal 8(%esp), %edx 171#if defined HAVE_ATTRIBUTE_VISIBILITY || !defined __PIC__ 172 call SYM(GTM_begin_transaction) 173#elif defined __ELF__ 174 call 1f 1751: popl %ebx 176 addl $_GLOBAL_OFFSET_TABLE_+[.-1b], %ebx 177 call SYM(GTM_begin_transaction)@PLT 178 movl 12(%esp), %ebx 179#else 180# error "Unsupported PIC sequence" 181#endif 182 addl $28, %esp 183 cfi_def_cfa_offset(4) 184#endif 185 ret 186 cfi_endproc 187 188 TYPE(_ITM_beginTransaction) 189 SIZE(_ITM_beginTransaction) 190 191 .align 4 192 .globl SYM(GTM_longjmp) 193 194SYM(GTM_longjmp): 195 cfi_startproc 196#ifdef __x86_64__ 197 movq (%rsi), %rcx 198 movq 8(%rsi), %rbx 199 movq 16(%rsi), %rbp 200 movq 24(%rsi), %r12 201 movq 32(%rsi), %r13 202 movq 40(%rsi), %r14 203 movq 48(%rsi), %r15 204 movl %edi, %eax 205 cfi_def_cfa(%rsi, 0) 206 cfi_offset(%rip, 56) 207 cfi_register(%rsp, %rcx) 208 movq %rcx, %rsp 209 jmp *56(%rsi) 210#else 211 movl (%edx), %ecx 212 movl 4(%edx), %ebx 213 movl 8(%edx), %esi 214 movl 12(%edx), %edi 215 movl 16(%edx), %ebp 216 cfi_def_cfa(%edx, 0) 217 cfi_offset(%eip, 20) 218 cfi_register(%esp, %ecx) 219 movl %ecx, %esp 220 jmp *20(%edx) 221#endif 222 cfi_endproc 223 224 TYPE(GTM_longjmp) 225 HIDDEN(GTM_longjmp) 226 SIZE(GTM_longjmp) 227 228#ifdef __linux__ 229.section .note.GNU-stack, "", @progbits 230#endif 231