1/* -----------------------------------------------------------------------
2   sysv.h - Copyright (c) 2003 Jakub Jelinek <jakub@redhat.com>
3	    Copyright (c) 2008 Red Hat, Inc.
4
5   PowerPC 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#include <powerpc/asm.h>
31
32	.file   "ppc_closure.S"
33
34#ifndef POWERPC64
35
36FFI_HIDDEN(ffi_closure_SYSV)
37ENTRY(ffi_closure_SYSV)
38	.cfi_startproc
39	stwu %r1,-144(%r1)
40	.cfi_def_cfa_offset 144
41	mflr %r0
42	stw %r0,148(%r1)
43	.cfi_offset 65, 4
44
45# we want to build up an areas for the parameters passed
46# in registers (both floating point and integer)
47
48	# so first save gpr 3 to gpr 10 (aligned to 4)
49	stw   %r3, 16(%r1)
50	stw   %r4, 20(%r1)
51	stw   %r5, 24(%r1)
52
53	# set up registers for the routine that does the work
54
55	# closure->cif
56	lwz %r3,FFI_TRAMPOLINE_SIZE(%r11)
57	# closure->fun
58	lwz %r4,FFI_TRAMPOLINE_SIZE+4(%r11)
59	# closure->user_data
60	lwz %r5,FFI_TRAMPOLINE_SIZE+8(%r11)
61
62.Ldoclosure:
63	stw   %r6, 28(%r1)
64	stw   %r7, 32(%r1)
65	stw   %r8, 36(%r1)
66	stw   %r9, 40(%r1)
67	stw   %r10,44(%r1)
68
69#ifndef __NO_FPRS__
70	# next save fpr 1 to fpr 8 (aligned to 8)
71	stfd  %f1, 48(%r1)
72	stfd  %f2, 56(%r1)
73	stfd  %f3, 64(%r1)
74	stfd  %f4, 72(%r1)
75	stfd  %f5, 80(%r1)
76	stfd  %f6, 88(%r1)
77	stfd  %f7, 96(%r1)
78	stfd  %f8, 104(%r1)
79#endif
80
81	# pointer to the result storage
82	addi %r6,%r1,112
83
84	# pointer to the saved gpr registers
85	addi %r7,%r1,16
86
87	# pointer to the saved fpr registers
88	addi %r8,%r1,48
89
90	# pointer to the outgoing parameter save area in the previous frame
91	# i.e. the previous frame pointer + 8
92	addi %r9,%r1,152
93
94	# make the call
95	bl ffi_closure_helper_SYSV@local
96.Lret:
97	# now r3 contains the return type
98	# so use it to look up in a table
99	# so we know how to deal with each type
100
101	# look up the proper starting point in table
102	# by using return type as offset
103
104	mflr %r4		# move address of .Lret to r4
105	slwi %r3,%r3,4		# now multiply return type by 16
106	addi %r4, %r4, .Lret_type0 - .Lret
107	lwz %r0,148(%r1)
108	add %r3,%r3,%r4		# add contents of table to table address
109	mtctr %r3
110	bctr			# jump to it
111
112# Each of the ret_typeX code fragments has to be exactly 16 bytes long
113# (4 instructions). For cache effectiveness we align to a 16 byte boundary
114# first.
115	.align 4
116# case FFI_TYPE_VOID
117.Lret_type0:
118	mtlr %r0
119	addi %r1,%r1,144
120	.cfi_def_cfa_offset 0
121	blr
122	.cfi_def_cfa_offset 144
123	nop
124
125# case FFI_TYPE_INT
126	lwz %r3,112+0(%r1)
127	mtlr %r0
128.Lfinish:
129	addi %r1,%r1,144
130	.cfi_def_cfa_offset 0
131	blr
132	.cfi_def_cfa_offset 144
133
134# case FFI_TYPE_FLOAT
135#ifndef __NO_FPRS__
136	lfs %f1,112+0(%r1)
137#else
138	nop
139#endif
140	mtlr %r0
141	addi %r1,%r1,144
142	.cfi_def_cfa_offset 0
143	blr
144	.cfi_def_cfa_offset 144
145
146# case FFI_TYPE_DOUBLE
147#ifndef __NO_FPRS__
148	lfd %f1,112+0(%r1)
149#else
150	nop
151#endif
152	mtlr %r0
153	addi %r1,%r1,144
154	.cfi_def_cfa_offset 0
155	blr
156	.cfi_def_cfa_offset 144
157
158# case FFI_TYPE_LONGDOUBLE
159#ifndef __NO_FPRS__
160	lfd %f1,112+0(%r1)
161	lfd %f2,112+8(%r1)
162	mtlr %r0
163	b .Lfinish
164#else
165	mtlr %r0
166	addi %r1,%r1,144
167	.cfi_def_cfa_offset 0
168	blr
169	.cfi_def_cfa_offset 144
170	nop
171#endif
172
173# case FFI_TYPE_UINT8
174#ifdef __LITTLE_ENDIAN__
175	lbz %r3,112+0(%r1)
176#else
177	lbz %r3,112+3(%r1)
178#endif
179	mtlr %r0
180	addi %r1,%r1,144
181	.cfi_def_cfa_offset 0
182	blr
183	.cfi_def_cfa_offset 144
184
185# case FFI_TYPE_SINT8
186#ifdef __LITTLE_ENDIAN__
187	lbz %r3,112+0(%r1)
188#else
189	lbz %r3,112+3(%r1)
190#endif
191	extsb %r3,%r3
192	mtlr %r0
193	b .Lfinish
194
195# case FFI_TYPE_UINT16
196#ifdef __LITTLE_ENDIAN__
197	lhz %r3,112+0(%r1)
198#else
199	lhz %r3,112+2(%r1)
200#endif
201	mtlr %r0
202	addi %r1,%r1,144
203	.cfi_def_cfa_offset 0
204	blr
205	.cfi_def_cfa_offset 144
206
207# case FFI_TYPE_SINT16
208#ifdef __LITTLE_ENDIAN__
209	lha %r3,112+0(%r1)
210#else
211	lha %r3,112+2(%r1)
212#endif
213	mtlr %r0
214	addi %r1,%r1,144
215	.cfi_def_cfa_offset 0
216	blr
217	.cfi_def_cfa_offset 144
218
219# case FFI_TYPE_UINT32
220	lwz %r3,112+0(%r1)
221	mtlr %r0
222	addi %r1,%r1,144
223	.cfi_def_cfa_offset 0
224	blr
225	.cfi_def_cfa_offset 144
226
227# case FFI_TYPE_SINT32
228	lwz %r3,112+0(%r1)
229	mtlr %r0
230	addi %r1,%r1,144
231	.cfi_def_cfa_offset 0
232	blr
233	.cfi_def_cfa_offset 144
234
235# case FFI_TYPE_UINT64
236	lwz %r3,112+0(%r1)
237	lwz %r4,112+4(%r1)
238	mtlr %r0
239	b .Lfinish
240
241# case FFI_TYPE_SINT64
242	lwz %r3,112+0(%r1)
243	lwz %r4,112+4(%r1)
244	mtlr %r0
245	b .Lfinish
246
247# case FFI_TYPE_STRUCT
248	mtlr %r0
249	addi %r1,%r1,144
250	.cfi_def_cfa_offset 0
251	blr
252	.cfi_def_cfa_offset 144
253	nop
254
255# case FFI_TYPE_POINTER
256	lwz %r3,112+0(%r1)
257	mtlr %r0
258	addi %r1,%r1,144
259	.cfi_def_cfa_offset 0
260	blr
261	.cfi_def_cfa_offset 144
262
263# case FFI_TYPE_UINT128
264	lwz %r3,112+0(%r1)
265	lwz %r4,112+4(%r1)
266	lwz %r5,112+8(%r1)
267	b .Luint128
268
269# The return types below are only used when the ABI type is FFI_SYSV.
270# case FFI_SYSV_TYPE_SMALL_STRUCT + 1. One byte struct.
271	lbz %r3,112+0(%r1)
272	mtlr %r0
273	addi %r1,%r1,144
274	.cfi_def_cfa_offset 0
275	blr
276	.cfi_def_cfa_offset 144
277
278# case FFI_SYSV_TYPE_SMALL_STRUCT + 2. Two byte struct.
279	lhz %r3,112+0(%r1)
280	mtlr %r0
281	addi %r1,%r1,144
282	.cfi_def_cfa_offset 0
283	blr
284	.cfi_def_cfa_offset 144
285
286# case FFI_SYSV_TYPE_SMALL_STRUCT + 3. Three byte struct.
287	lwz %r3,112+0(%r1)
288#ifdef __LITTLE_ENDIAN__
289	mtlr %r0
290	addi %r1,%r1,144
291	.cfi_def_cfa_offset 0
292	blr
293	.cfi_def_cfa_offset 144
294#else
295	srwi %r3,%r3,8
296	mtlr %r0
297	b .Lfinish
298#endif
299
300# case FFI_SYSV_TYPE_SMALL_STRUCT + 4. Four byte struct.
301	lwz %r3,112+0(%r1)
302	mtlr %r0
303	addi %r1,%r1,144
304	.cfi_def_cfa_offset 0
305	blr
306	.cfi_def_cfa_offset 144
307
308# case FFI_SYSV_TYPE_SMALL_STRUCT + 5. Five byte struct.
309	lwz %r3,112+0(%r1)
310	lwz %r4,112+4(%r1)
311#ifdef __LITTLE_ENDIAN__
312	mtlr %r0
313	b .Lfinish
314#else
315	li %r5,24
316	b .Lstruct567
317#endif
318
319# case FFI_SYSV_TYPE_SMALL_STRUCT + 6. Six byte struct.
320	lwz %r3,112+0(%r1)
321	lwz %r4,112+4(%r1)
322#ifdef __LITTLE_ENDIAN__
323	mtlr %r0
324	b .Lfinish
325#else
326	li %r5,16
327	b .Lstruct567
328#endif
329
330# case FFI_SYSV_TYPE_SMALL_STRUCT + 7. Seven byte struct.
331	lwz %r3,112+0(%r1)
332	lwz %r4,112+4(%r1)
333#ifdef __LITTLE_ENDIAN__
334	mtlr %r0
335	b .Lfinish
336#else
337	li %r5,8
338	b .Lstruct567
339#endif
340
341# case FFI_SYSV_TYPE_SMALL_STRUCT + 8. Eight byte struct.
342	lwz %r3,112+0(%r1)
343	lwz %r4,112+4(%r1)
344	mtlr %r0
345	b .Lfinish
346
347#ifndef __LITTLE_ENDIAN__
348.Lstruct567:
349	subfic %r6,%r5,32
350	srw %r4,%r4,%r5
351	slw %r6,%r3,%r6
352	srw %r3,%r3,%r5
353	or %r4,%r6,%r4
354	mtlr %r0
355	addi %r1,%r1,144
356	.cfi_def_cfa_offset 0
357	blr
358	.cfi_def_cfa_offset 144
359#endif
360
361.Luint128:
362	lwz %r6,112+12(%r1)
363	mtlr %r0
364	addi %r1,%r1,144
365	.cfi_def_cfa_offset 0
366	blr
367	.cfi_endproc
368END(ffi_closure_SYSV)
369
370
371FFI_HIDDEN(ffi_go_closure_sysv)
372ENTRY(ffi_go_closure_sysv)
373	.cfi_startproc
374	stwu %r1,-144(%r1)
375	.cfi_def_cfa_offset 144
376	mflr %r0
377	stw %r0,148(%r1)
378	.cfi_offset 65, 4
379
380	stw   %r3, 16(%r1)
381	stw   %r4, 20(%r1)
382	stw   %r5, 24(%r1)
383
384	# closure->cif
385	lwz %r3,4(%r11)
386	# closure->fun
387	lwz %r4,8(%r11)
388	# user_data
389	mr %r5,%r11
390	b .Ldoclosure
391	.cfi_endproc
392END(ffi_go_closure_sysv)
393
394#if defined __ELF__ && defined __linux__
395	.section	.note.GNU-stack,"",@progbits
396#endif
397#endif
398