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	.text
37	.cfi_startproc
38# if _CALL_ELF == 2
39ffi_closure_LINUX64:
40	addis	%r2, %r12, .TOC.-ffi_closure_LINUX64@ha
41	addi	%r2, %r2, .TOC.-ffi_closure_LINUX64@l
42	.localentry ffi_closure_LINUX64, . - ffi_closure_LINUX64
43# else
44	.section        ".opd","aw"
45	.align  3
46ffi_closure_LINUX64:
47#  ifdef _CALL_LINUX
48	.quad   .L.ffi_closure_LINUX64,.TOC.@tocbase,0
49	.type   ffi_closure_LINUX64,@function
50	.text
51.L.ffi_closure_LINUX64:
52#  else
53	FFI_HIDDEN (.ffi_closure_LINUX64)
54	.globl  .ffi_closure_LINUX64
55	.quad   .ffi_closure_LINUX64,.TOC.@tocbase,0
56	.size   ffi_closure_LINUX64,24
57	.type   .ffi_closure_LINUX64,@function
58	.text
59.ffi_closure_LINUX64:
60#  endif
61# endif
62
63# if _CALL_ELF == 2
64#  32 byte special reg save area + 64 byte parm save area
65#  + 64 byte retval area + 13*8 fpr save area + round to 16
66#  define STACKFRAME 272
67#  define PARMSAVE 32
68#  define RETVAL PARMSAVE+64
69# else
70#  48 bytes special reg save area + 64 bytes parm save area
71#  + 16 bytes retval area + 13*8 bytes fpr save area + round to 16
72#  define STACKFRAME 240
73#  define PARMSAVE 48
74#  define RETVAL PARMSAVE+64
75# endif
76
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, 0f
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
880:
89	# Save general regs into parm save area
90	std	%r3, 0(%r12)
91	std	%r4, 8(%r12)
92	std	%r5, 16(%r12)
93	std	%r6, 24(%r12)
94	std	%r7, 32(%r12)
95	std	%r8, 40(%r12)
96	std	%r9, 48(%r12)
97	std	%r10, 56(%r12)
98
99	# load up the pointer to the parm save area
100	mr	%r7, %r12
101# else
102	# copy r2 to r11 and load TOC into r2
103	mr	%r11, %r2
104	ld	%r2, 16(%r2)
105
106	mflr	%r0
107	# Save general regs into parm save area
108	# This is the parameter save area set up by our caller.
109	std	%r3, PARMSAVE+0(%r1)
110	std	%r4, PARMSAVE+8(%r1)
111	std	%r5, PARMSAVE+16(%r1)
112	std	%r6, PARMSAVE+24(%r1)
113	std	%r7, PARMSAVE+32(%r1)
114	std	%r8, PARMSAVE+40(%r1)
115	std	%r9, PARMSAVE+48(%r1)
116	std	%r10, PARMSAVE+56(%r1)
117
118	# load up the pointer to the parm save area
119	addi	%r7, %r1, PARMSAVE
120# endif
121	std	%r0, 16(%r1)
122
123	# closure->cif
124	ld	%r3, FFI_TRAMPOLINE_SIZE(%r11)
125	# closure->fun
126	ld	%r4, FFI_TRAMPOLINE_SIZE+8(%r11)
127	# closure->user_data
128	ld	%r5, FFI_TRAMPOLINE_SIZE+16(%r11)
129
130.Ldoclosure:
131	# next save fpr 1 to fpr 13
132	stfd	%f1, -104+(0*8)(%r1)
133	stfd	%f2, -104+(1*8)(%r1)
134	stfd	%f3, -104+(2*8)(%r1)
135	stfd	%f4, -104+(3*8)(%r1)
136	stfd	%f5, -104+(4*8)(%r1)
137	stfd	%f6, -104+(5*8)(%r1)
138	stfd	%f7, -104+(6*8)(%r1)
139	stfd	%f8, -104+(7*8)(%r1)
140	stfd	%f9, -104+(8*8)(%r1)
141	stfd	%f10, -104+(9*8)(%r1)
142	stfd	%f11, -104+(10*8)(%r1)
143	stfd	%f12, -104+(11*8)(%r1)
144	stfd	%f13, -104+(12*8)(%r1)
145
146	# load up the pointer to the saved fpr registers */
147	addi	%r8, %r1, -104
148
149	# load up the pointer to the result storage
150	addi	%r6, %r1, -STACKFRAME+RETVAL
151
152	stdu	%r1, -STACKFRAME(%r1)
153	.cfi_def_cfa_offset STACKFRAME
154	.cfi_offset 65, 16
155
156	# make the call
157# if defined _CALL_LINUX || _CALL_ELF == 2
158	bl ffi_closure_helper_LINUX64
159# else
160	bl .ffi_closure_helper_LINUX64
161# endif
162.Lret:
163
164	# now r3 contains the return type
165	# so use it to look up in a table
166	# so we know how to deal with each type
167
168	# look up the proper starting point in table
169	# by using return type as offset
170	ld %r0, STACKFRAME+16(%r1)
171	cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT
172	bge .Lsmall
173	mflr %r4		# move address of .Lret to r4
174	sldi %r3, %r3, 4	# now multiply return type by 16
175	addi %r4, %r4, .Lret_type0 - .Lret
176	add %r3, %r3, %r4	# add contents of table to table address
177	mtctr %r3
178	bctr			# jump to it
179
180# Each of the ret_typeX code fragments has to be exactly 16 bytes long
181# (4 instructions). For cache effectiveness we align to a 16 byte boundary
182# first.
183	.align 4
184
185.Lret_type0:
186# case FFI_TYPE_VOID
187	mtlr %r0
188	addi %r1, %r1, STACKFRAME
189	.cfi_def_cfa_offset 0
190	blr
191	.cfi_def_cfa_offset STACKFRAME
192	nop
193# case FFI_TYPE_INT
194# ifdef __LITTLE_ENDIAN__
195	lwa %r3, RETVAL+0(%r1)
196# else
197	lwa %r3, RETVAL+4(%r1)
198# endif
199	mtlr %r0
200	addi %r1, %r1, STACKFRAME
201	.cfi_def_cfa_offset 0
202	blr
203	.cfi_def_cfa_offset STACKFRAME
204# case FFI_TYPE_FLOAT
205	lfs %f1, RETVAL+0(%r1)
206	mtlr %r0
207	addi %r1, %r1, STACKFRAME
208	.cfi_def_cfa_offset 0
209	blr
210	.cfi_def_cfa_offset STACKFRAME
211# case FFI_TYPE_DOUBLE
212	lfd %f1, RETVAL+0(%r1)
213	mtlr %r0
214	addi %r1, %r1, STACKFRAME
215	.cfi_def_cfa_offset 0
216	blr
217	.cfi_def_cfa_offset STACKFRAME
218# case FFI_TYPE_LONGDOUBLE
219	lfd %f1, RETVAL+0(%r1)
220	mtlr %r0
221	lfd %f2, RETVAL+8(%r1)
222	b .Lfinish
223# case FFI_TYPE_UINT8
224# ifdef __LITTLE_ENDIAN__
225	lbz %r3, RETVAL+0(%r1)
226# else
227	lbz %r3, RETVAL+7(%r1)
228# endif
229	mtlr %r0
230	addi %r1, %r1, STACKFRAME
231	.cfi_def_cfa_offset 0
232	blr
233	.cfi_def_cfa_offset STACKFRAME
234# case FFI_TYPE_SINT8
235# ifdef __LITTLE_ENDIAN__
236	lbz %r3, RETVAL+0(%r1)
237# else
238	lbz %r3, RETVAL+7(%r1)
239# endif
240	extsb %r3,%r3
241	mtlr %r0
242	b .Lfinish
243# case FFI_TYPE_UINT16
244# ifdef __LITTLE_ENDIAN__
245	lhz %r3, RETVAL+0(%r1)
246# else
247	lhz %r3, RETVAL+6(%r1)
248# endif
249	mtlr %r0
250.Lfinish:
251	addi %r1, %r1, STACKFRAME
252	.cfi_def_cfa_offset 0
253	blr
254	.cfi_def_cfa_offset STACKFRAME
255# case FFI_TYPE_SINT16
256# ifdef __LITTLE_ENDIAN__
257	lha %r3, RETVAL+0(%r1)
258# else
259	lha %r3, RETVAL+6(%r1)
260# endif
261	mtlr %r0
262	addi %r1, %r1, STACKFRAME
263	.cfi_def_cfa_offset 0
264	blr
265	.cfi_def_cfa_offset STACKFRAME
266# case FFI_TYPE_UINT32
267# ifdef __LITTLE_ENDIAN__
268	lwz %r3, RETVAL+0(%r1)
269# else
270	lwz %r3, RETVAL+4(%r1)
271# endif
272	mtlr %r0
273	addi %r1, %r1, STACKFRAME
274	.cfi_def_cfa_offset 0
275	blr
276	.cfi_def_cfa_offset STACKFRAME
277# case FFI_TYPE_SINT32
278# ifdef __LITTLE_ENDIAN__
279	lwa %r3, RETVAL+0(%r1)
280# else
281	lwa %r3, RETVAL+4(%r1)
282# endif
283	mtlr %r0
284	addi %r1, %r1, STACKFRAME
285	.cfi_def_cfa_offset 0
286	blr
287	.cfi_def_cfa_offset STACKFRAME
288# case FFI_TYPE_UINT64
289	ld %r3, RETVAL+0(%r1)
290	mtlr %r0
291	addi %r1, %r1, STACKFRAME
292	.cfi_def_cfa_offset 0
293	blr
294	.cfi_def_cfa_offset STACKFRAME
295# case FFI_TYPE_SINT64
296	ld %r3, RETVAL+0(%r1)
297	mtlr %r0
298	addi %r1, %r1, STACKFRAME
299	.cfi_def_cfa_offset 0
300	blr
301	.cfi_def_cfa_offset STACKFRAME
302# case FFI_TYPE_STRUCT
303	mtlr %r0
304	addi %r1, %r1, STACKFRAME
305	.cfi_def_cfa_offset 0
306	blr
307	.cfi_def_cfa_offset STACKFRAME
308	nop
309# case FFI_TYPE_POINTER
310	ld %r3, RETVAL+0(%r1)
311	mtlr %r0
312	addi %r1, %r1, STACKFRAME
313	.cfi_def_cfa_offset 0
314	blr
315	.cfi_def_cfa_offset STACKFRAME
316# case FFI_V2_TYPE_FLOAT_HOMOG
317	lfs %f1, RETVAL+0(%r1)
318	lfs %f2, RETVAL+4(%r1)
319	lfs %f3, RETVAL+8(%r1)
320	b .Lmorefloat
321# case FFI_V2_TYPE_DOUBLE_HOMOG
322	lfd %f1, RETVAL+0(%r1)
323	lfd %f2, RETVAL+8(%r1)
324	lfd %f3, RETVAL+16(%r1)
325	lfd %f4, RETVAL+24(%r1)
326	mtlr %r0
327	lfd %f5, RETVAL+32(%r1)
328	lfd %f6, RETVAL+40(%r1)
329	lfd %f7, RETVAL+48(%r1)
330	lfd %f8, RETVAL+56(%r1)
331	addi %r1, %r1, STACKFRAME
332	.cfi_def_cfa_offset 0
333	blr
334	.cfi_def_cfa_offset STACKFRAME
335.Lmorefloat:
336	lfs %f4, RETVAL+12(%r1)
337	mtlr %r0
338	lfs %f5, RETVAL+16(%r1)
339	lfs %f6, RETVAL+20(%r1)
340	lfs %f7, RETVAL+24(%r1)
341	lfs %f8, RETVAL+28(%r1)
342	addi %r1, %r1, STACKFRAME
343	.cfi_def_cfa_offset 0
344	blr
345	.cfi_def_cfa_offset STACKFRAME
346.Lsmall:
347# ifdef __LITTLE_ENDIAN__
348	ld %r3,RETVAL+0(%r1)
349	mtlr %r0
350	ld %r4,RETVAL+8(%r1)
351	addi %r1, %r1, STACKFRAME
352	.cfi_def_cfa_offset 0
353	blr
354# else
355	# A struct smaller than a dword is returned in the low bits of r3
356	# ie. right justified.  Larger structs are passed left justified
357	# in r3 and r4.  The return value area on the stack will have
358	# the structs as they are usually stored in memory.
359	cmpldi %r3, FFI_V2_TYPE_SMALL_STRUCT + 7 # size 8 bytes?
360	neg %r5, %r3
361	ld %r3,RETVAL+0(%r1)
362	blt .Lsmalldown
363	mtlr %r0
364	ld %r4,RETVAL+8(%r1)
365	addi %r1, %r1, STACKFRAME
366	.cfi_def_cfa_offset 0
367	blr
368	.cfi_def_cfa_offset STACKFRAME
369.Lsmalldown:
370	addi %r5, %r5, FFI_V2_TYPE_SMALL_STRUCT + 7
371	mtlr %r0
372	sldi %r5, %r5, 3
373	addi %r1, %r1, STACKFRAME
374	.cfi_def_cfa_offset 0
375	srd %r3, %r3, %r5
376	blr
377# endif
378
379	.cfi_endproc
380# if _CALL_ELF == 2
381	.size	ffi_closure_LINUX64,.-ffi_closure_LINUX64
382# else
383#  ifdef _CALL_LINUX
384	.size	ffi_closure_LINUX64,.-.L.ffi_closure_LINUX64
385#  else
386	.long	0
387	.byte	0,12,0,1,128,0,0,0
388	.size	.ffi_closure_LINUX64,.-.ffi_closure_LINUX64
389#  endif
390# endif
391
392
393	FFI_HIDDEN (ffi_go_closure_linux64)
394	.globl  ffi_go_closure_linux64
395	.text
396	.cfi_startproc
397# if _CALL_ELF == 2
398ffi_go_closure_linux64:
399	addis	%r2, %r12, .TOC.-ffi_go_closure_linux64@ha
400	addi	%r2, %r2, .TOC.-ffi_go_closure_linux64@l
401	.localentry ffi_go_closure_linux64, . - ffi_go_closure_linux64
402# else
403	.section        ".opd","aw"
404	.align  3
405ffi_go_closure_linux64:
406#  ifdef _CALL_LINUX
407	.quad   .L.ffi_go_closure_linux64,.TOC.@tocbase,0
408	.type   ffi_go_closure_linux64,@function
409	.text
410.L.ffi_go_closure_linux64:
411#  else
412	FFI_HIDDEN (.ffi_go_closure_linux64)
413	.globl  .ffi_go_closure_linux64
414	.quad   .ffi_go_closure_linux64,.TOC.@tocbase,0
415	.size   ffi_go_closure_linux64,24
416	.type   .ffi_go_closure_linux64,@function
417	.text
418.ffi_go_closure_linux64:
419#  endif
420# endif
421
422# if _CALL_ELF == 2
423	ld	%r12, 8(%r11)				# closure->cif
424	mflr	%r0
425	lwz	%r12, 28(%r12)				# cif->flags
426	mtcrf	0x40, %r12
427	addi	%r12, %r1, PARMSAVE
428	bt	7, 0f
429	# Our caller has not allocated a parameter save area.
430	# We need to allocate one here and use it to pass gprs to
431	# ffi_closure_helper_LINUX64.
432	addi	%r12, %r1, -STACKFRAME+PARMSAVE
4330:
434	# Save general regs into parm save area
435	std	%r3, 0(%r12)
436	std	%r4, 8(%r12)
437	std	%r5, 16(%r12)
438	std	%r6, 24(%r12)
439	std	%r7, 32(%r12)
440	std	%r8, 40(%r12)
441	std	%r9, 48(%r12)
442	std	%r10, 56(%r12)
443
444	# load up the pointer to the parm save area
445	mr	%r7, %r12
446# else
447	mflr	%r0
448	# Save general regs into parm save area
449	# This is the parameter save area set up by our caller.
450	std	%r3, PARMSAVE+0(%r1)
451	std	%r4, PARMSAVE+8(%r1)
452	std	%r5, PARMSAVE+16(%r1)
453	std	%r6, PARMSAVE+24(%r1)
454	std	%r7, PARMSAVE+32(%r1)
455	std	%r8, PARMSAVE+40(%r1)
456	std	%r9, PARMSAVE+48(%r1)
457	std	%r10, PARMSAVE+56(%r1)
458
459	# load up the pointer to the parm save area
460	addi	%r7, %r1, PARMSAVE
461# endif
462	std	%r0, 16(%r1)
463
464	# closure->cif
465	ld	%r3, 8(%r11)
466	# closure->fun
467	ld	%r4, 16(%r11)
468	# user_data
469	mr	%r5, %r11
470	b	.Ldoclosure
471
472	.cfi_endproc
473# if _CALL_ELF == 2
474	.size	ffi_go_closure_linux64,.-ffi_go_closure_linux64
475# else
476#  ifdef _CALL_LINUX
477	.size	ffi_go_closure_linux64,.-.L.ffi_go_closure_linux64
478#  else
479	.long	0
480	.byte	0,12,0,1,128,0,0,0
481	.size	.ffi_go_closure_linux64,.-.ffi_go_closure_linux64
482#  endif
483# endif
484#endif
485
486#if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2
487	.section	.note.GNU-stack,"",@progbits
488#endif
489