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