1/* -----------------------------------------------------------------------
2   sysv.h - Copyright (c) 2003 Jakub Jelinek <jakub@redhat.com>
3	    Copyright (c) 2008 Red Hat, Inc.
4
5   PowerPC64 Assembly glue.
6
7   Permission is hereby granted, free of charge, to any person obtaining
8   a copy of this software and associated documentation files (the
9   ``Software''), to deal in the Software without restriction, including
10   without limitation the rights to use, copy, modify, merge, publish,
11   distribute, sublicense, and/or sell copies of the Software, and to
12   permit persons to whom the Software is furnished to do so, subject to
13   the following conditions:
14
15   The above copyright notice and this permission notice shall be included
16   in all copies or substantial portions of the Software.
17
18   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
19   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25   DEALINGS IN THE SOFTWARE.
26   ----------------------------------------------------------------------- */
27#define LIBFFI_ASM
28#include <fficonfig.h>
29#include <ffi.h>
30
31	.file	"linux64_closure.S"
32
33#ifdef POWERPC64
34	FFI_HIDDEN (ffi_closure_LINUX64)
35	.globl  ffi_closure_LINUX64
36# if _CALL_ELF == 2
37	.text
38ffi_closure_LINUX64:
39	addis	%r2, %r12, .TOC.-ffi_closure_LINUX64@ha
40	addi	%r2, %r2, .TOC.-ffi_closure_LINUX64@l
41	.localentry ffi_closure_LINUX64, . - ffi_closure_LINUX64
42# else
43	.section        ".opd","aw"
44	.align  3
45ffi_closure_LINUX64:
46#  ifdef _CALL_LINUX
47	.quad   .L.ffi_closure_LINUX64,.TOC.@tocbase,0
48	.type   ffi_closure_LINUX64,@function
49	.text
50.L.ffi_closure_LINUX64:
51#  else
52	FFI_HIDDEN (.ffi_closure_LINUX64)
53	.globl  .ffi_closure_LINUX64
54	.quad   .ffi_closure_LINUX64,.TOC.@tocbase,0
55	.size   ffi_closure_LINUX64,24
56	.type   .ffi_closure_LINUX64,@function
57	.text
58.ffi_closure_LINUX64:
59#  endif
60# endif
61
62# if _CALL_ELF == 2
63#  32 byte special reg save area + 64 byte parm save area
64#  + 64 byte retval area + 13*8 fpr save area + round to 16
65#  define STACKFRAME 272
66#  define PARMSAVE 32
67#  define RETVAL PARMSAVE+64
68# else
69#  48 bytes special reg save area + 64 bytes parm save area
70#  + 16 bytes retval area + 13*8 bytes fpr save area + round to 16
71#  define STACKFRAME 240
72#  define PARMSAVE 48
73#  define RETVAL PARMSAVE+64
74# endif
75
76.LFB1:
77# if _CALL_ELF == 2
78	ld	%r12, FFI_TRAMPOLINE_SIZE(%r11)		# closure->cif
79	mflr	%r0
80	lwz	%r12, 28(%r12)				# cif->flags
81	mtcrf	0x40, %r12
82	addi	%r12, %r1, PARMSAVE
83	bt	7, .Lparmsave
84	# Our caller has not allocated a parameter save area.
85	# We need to allocate one here and use it to pass gprs to
86	# ffi_closure_helper_LINUX64.
87	addi	%r12, %r1, -STACKFRAME+PARMSAVE
88.Lparmsave:
89	std	%r0, 16(%r1)
90	# Save general regs into parm save area
91	std	%r3, 0(%r12)
92	std	%r4, 8(%r12)
93	std	%r5, 16(%r12)
94	std	%r6, 24(%r12)
95	std	%r7, 32(%r12)
96	std	%r8, 40(%r12)
97	std	%r9, 48(%r12)
98	std	%r10, 56(%r12)
99
100	# load up the pointer to the parm save area
101	mr	%r5, %r12
102# else
103	# copy r2 to r11 and load TOC into r2
104	mr	%r11, %r2
105	ld	%r2, 16(%r11)
106
107	mflr	%r0
108	# Save general regs into parm save area
109	# This is the parameter save area set up by our caller.
110	std	%r3, PARMSAVE+0(%r1)
111	std	%r4, PARMSAVE+8(%r1)
112	std	%r5, PARMSAVE+16(%r1)
113	std	%r6, PARMSAVE+24(%r1)
114	std	%r7, PARMSAVE+32(%r1)
115	std	%r8, PARMSAVE+40(%r1)
116	std	%r9, PARMSAVE+48(%r1)
117	std	%r10, PARMSAVE+56(%r1)
118
119	std	%r0, 16(%r1)
120
121	# load up the pointer to the parm save area
122	addi	%r5, %r1, PARMSAVE
123# endif
124
125	# next save fpr 1 to fpr 13
126	stfd	%f1, -104+(0*8)(%r1)
127	stfd	%f2, -104+(1*8)(%r1)
128	stfd	%f3, -104+(2*8)(%r1)
129	stfd	%f4, -104+(3*8)(%r1)
130	stfd	%f5, -104+(4*8)(%r1)
131	stfd	%f6, -104+(5*8)(%r1)
132	stfd	%f7, -104+(6*8)(%r1)
133	stfd	%f8, -104+(7*8)(%r1)
134	stfd	%f9, -104+(8*8)(%r1)
135	stfd	%f10, -104+(9*8)(%r1)
136	stfd	%f11, -104+(10*8)(%r1)
137	stfd	%f12, -104+(11*8)(%r1)
138	stfd	%f13, -104+(12*8)(%r1)
139
140	# load up the pointer to the saved fpr registers */
141	addi	%r6, %r1, -104
142
143	# load up the pointer to the result storage
144	addi	%r4, %r1, -STACKFRAME+RETVAL
145
146	stdu	%r1, -STACKFRAME(%r1)
147.LCFI0:
148
149	# get the context pointer from the trampoline
150	mr	%r3, %r11
151
152	# make the call
153# if defined _CALL_LINUX || _CALL_ELF == 2
154	bl ffi_closure_helper_LINUX64
155# else
156	bl .ffi_closure_helper_LINUX64
157# endif
158.Lret:
159
160	# now r3 contains the return type
161	# so use it to look up in a table
162	# so we know how to deal with each type
163
164	# look up the proper starting point in table
165	# by using return type as offset
166	ld %r0, STACKFRAME+16(%r1)
167	cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT
168	bge .Lsmall
169	mflr %r4		# move address of .Lret to r4
170	sldi %r3, %r3, 4	# now multiply return type by 16
171	addi %r4, %r4, .Lret_type0 - .Lret
172	add %r3, %r3, %r4	# add contents of table to table address
173	mtctr %r3
174	bctr			# jump to it
175
176# Each of the ret_typeX code fragments has to be exactly 16 bytes long
177# (4 instructions). For cache effectiveness we align to a 16 byte boundary
178# first.
179	.align 4
180
181.Lret_type0:
182# case FFI_TYPE_VOID
183	mtlr %r0
184	addi %r1, %r1, STACKFRAME
185	blr
186	nop
187# case FFI_TYPE_INT
188# ifdef __LITTLE_ENDIAN__
189	lwa %r3, RETVAL+0(%r1)
190# else
191	lwa %r3, RETVAL+4(%r1)
192# endif
193	mtlr %r0
194	addi %r1, %r1, STACKFRAME
195	blr
196# case FFI_TYPE_FLOAT
197	lfs %f1, RETVAL+0(%r1)
198	mtlr %r0
199	addi %r1, %r1, STACKFRAME
200	blr
201# case FFI_TYPE_DOUBLE
202	lfd %f1, RETVAL+0(%r1)
203	mtlr %r0
204	addi %r1, %r1, STACKFRAME
205	blr
206# case FFI_TYPE_LONGDOUBLE
207	lfd %f1, RETVAL+0(%r1)
208	mtlr %r0
209	lfd %f2, RETVAL+8(%r1)
210	b .Lfinish
211# case FFI_TYPE_UINT8
212# ifdef __LITTLE_ENDIAN__
213	lbz %r3, RETVAL+0(%r1)
214# else
215	lbz %r3, RETVAL+7(%r1)
216# endif
217	mtlr %r0
218	addi %r1, %r1, STACKFRAME
219	blr
220# case FFI_TYPE_SINT8
221# ifdef __LITTLE_ENDIAN__
222	lbz %r3, RETVAL+0(%r1)
223# else
224	lbz %r3, RETVAL+7(%r1)
225# endif
226	extsb %r3,%r3
227	mtlr %r0
228	b .Lfinish
229# case FFI_TYPE_UINT16
230# ifdef __LITTLE_ENDIAN__
231	lhz %r3, RETVAL+0(%r1)
232# else
233	lhz %r3, RETVAL+6(%r1)
234# endif
235	mtlr %r0
236.Lfinish:
237	addi %r1, %r1, STACKFRAME
238	blr
239# case FFI_TYPE_SINT16
240# ifdef __LITTLE_ENDIAN__
241	lha %r3, RETVAL+0(%r1)
242# else
243	lha %r3, RETVAL+6(%r1)
244# endif
245	mtlr %r0
246	addi %r1, %r1, STACKFRAME
247	blr
248# case FFI_TYPE_UINT32
249# ifdef __LITTLE_ENDIAN__
250	lwz %r3, RETVAL+0(%r1)
251# else
252	lwz %r3, RETVAL+4(%r1)
253# endif
254	mtlr %r0
255	addi %r1, %r1, STACKFRAME
256	blr
257# case FFI_TYPE_SINT32
258# ifdef __LITTLE_ENDIAN__
259	lwa %r3, RETVAL+0(%r1)
260# else
261	lwa %r3, RETVAL+4(%r1)
262# endif
263	mtlr %r0
264	addi %r1, %r1, STACKFRAME
265	blr
266# case FFI_TYPE_UINT64
267	ld %r3, RETVAL+0(%r1)
268	mtlr %r0
269	addi %r1, %r1, STACKFRAME
270	blr
271# case FFI_TYPE_SINT64
272	ld %r3, RETVAL+0(%r1)
273	mtlr %r0
274	addi %r1, %r1, STACKFRAME
275	blr
276# case FFI_TYPE_STRUCT
277	mtlr %r0
278	addi %r1, %r1, STACKFRAME
279	blr
280	nop
281# case FFI_TYPE_POINTER
282	ld %r3, RETVAL+0(%r1)
283	mtlr %r0
284	addi %r1, %r1, STACKFRAME
285	blr
286# case FFI_V2_TYPE_FLOAT_HOMOG
287	lfs %f1, RETVAL+0(%r1)
288	lfs %f2, RETVAL+4(%r1)
289	lfs %f3, RETVAL+8(%r1)
290	b .Lmorefloat
291# case FFI_V2_TYPE_DOUBLE_HOMOG
292	lfd %f1, RETVAL+0(%r1)
293	lfd %f2, RETVAL+8(%r1)
294	lfd %f3, RETVAL+16(%r1)
295	lfd %f4, RETVAL+24(%r1)
296	mtlr %r0
297	lfd %f5, RETVAL+32(%r1)
298	lfd %f6, RETVAL+40(%r1)
299	lfd %f7, RETVAL+48(%r1)
300	lfd %f8, RETVAL+56(%r1)
301	addi %r1, %r1, STACKFRAME
302	blr
303.Lmorefloat:
304	lfs %f4, RETVAL+12(%r1)
305	mtlr %r0
306	lfs %f5, RETVAL+16(%r1)
307	lfs %f6, RETVAL+20(%r1)
308	lfs %f7, RETVAL+24(%r1)
309	lfs %f8, RETVAL+28(%r1)
310	addi %r1, %r1, STACKFRAME
311	blr
312.Lsmall:
313# ifdef __LITTLE_ENDIAN__
314	ld %r3,RETVAL+0(%r1)
315	mtlr %r0
316	ld %r4,RETVAL+8(%r1)
317	addi %r1, %r1, STACKFRAME
318	blr
319# else
320	# A struct smaller than a dword is returned in the low bits of r3
321	# ie. right justified.  Larger structs are passed left justified
322	# in r3 and r4.  The return value area on the stack will have
323	# the structs as they are usually stored in memory.
324	cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT + 7 # size 8 bytes?
325	neg %r5, %r3
326	ld %r3,RETVAL+0(%r1)
327	blt .Lsmalldown
328	mtlr %r0
329	ld %r4,RETVAL+8(%r1)
330	addi %r1, %r1, STACKFRAME
331	blr
332.Lsmalldown:
333	addi %r5, %r5, FFI_V2_TYPE_SMALL_STRUCT + 7
334	mtlr %r0
335	sldi %r5, %r5, 3
336	addi %r1, %r1, STACKFRAME
337	srd %r3, %r3, %r5
338	blr
339# endif
340
341.LFE1:
342	.long	0
343	.byte	0,12,0,1,128,0,0,0
344# if _CALL_ELF == 2
345	.size	ffi_closure_LINUX64,.-ffi_closure_LINUX64
346# else
347#  ifdef _CALL_LINUX
348	.size	ffi_closure_LINUX64,.-.L.ffi_closure_LINUX64
349#  else
350	.size	.ffi_closure_LINUX64,.-.ffi_closure_LINUX64
351#  endif
352# endif
353
354	.section	.eh_frame,EH_FRAME_FLAGS,@progbits
355.Lframe1:
356	.4byte	.LECIE1-.LSCIE1	 # Length of Common Information Entry
357.LSCIE1:
358	.4byte	0x0	 # CIE Identifier Tag
359	.byte	0x1	 # CIE Version
360	.ascii "zR\0"	 # CIE Augmentation
361	.uleb128 0x1	 # CIE Code Alignment Factor
362	.sleb128 -8	 # CIE Data Alignment Factor
363	.byte	0x41	 # CIE RA Column
364	.uleb128 0x1	 # Augmentation size
365	.byte	0x14	 # FDE Encoding (pcrel udata8)
366	.byte	0xc	 # DW_CFA_def_cfa
367	.uleb128 0x1
368	.uleb128 0x0
369	.align 3
370.LECIE1:
371.LSFDE1:
372	.4byte	.LEFDE1-.LASFDE1	 # FDE Length
373.LASFDE1:
374	.4byte	.LASFDE1-.Lframe1	 # FDE CIE offset
375	.8byte	.LFB1-.	 # FDE initial location
376	.8byte	.LFE1-.LFB1	 # FDE address range
377	.uleb128 0x0	 # Augmentation size
378	.byte	0x2	 # DW_CFA_advance_loc1
379	.byte	.LCFI0-.LFB1
380	.byte	0xe	 # DW_CFA_def_cfa_offset
381	.uleb128 STACKFRAME
382	.byte	0x11	 # DW_CFA_offset_extended_sf
383	.uleb128 0x41
384	.sleb128 -2
385	.align 3
386.LEFDE1:
387
388#endif
389
390#if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2
391	.section	.note.GNU-stack,"",@progbits
392#endif
393