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