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