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	lfs %f1,112+0(%r1)
126	mtlr %r0
127	addi %r1,%r1,144
128	blr
129
130# case FFI_TYPE_DOUBLE
131	lfd %f1,112+0(%r1)
132	mtlr %r0
133	addi %r1,%r1,144
134	blr
135
136# case FFI_TYPE_LONGDOUBLE
137	lfd %f1,112+0(%r1)
138	lfd %f2,112+8(%r1)
139	mtlr %r0
140	b .Lfinish
141
142# case FFI_TYPE_UINT8
143	lbz %r3,112+3(%r1)
144	mtlr %r0
145	addi %r1,%r1,144
146	blr
147
148# case FFI_TYPE_SINT8
149	lbz %r3,112+3(%r1)
150	extsb %r3,%r3
151	mtlr %r0
152	b .Lfinish
153
154# case FFI_TYPE_UINT16
155	lhz %r3,112+2(%r1)
156	mtlr %r0
157	addi %r1,%r1,144
158	blr
159
160# case FFI_TYPE_SINT16
161	lha %r3,112+2(%r1)
162	mtlr %r0
163	addi %r1,%r1,144
164	blr
165
166# case FFI_TYPE_UINT32
167	lwz %r3,112+0(%r1)
168	mtlr %r0
169	addi %r1,%r1,144
170	blr
171
172# case FFI_TYPE_SINT32
173	lwz %r3,112+0(%r1)
174	mtlr %r0
175	addi %r1,%r1,144
176	blr
177
178# case FFI_TYPE_UINT64
179	lwz %r3,112+0(%r1)
180	lwz %r4,112+4(%r1)
181	mtlr %r0
182	b .Lfinish
183
184# case FFI_TYPE_SINT64
185	lwz %r3,112+0(%r1)
186	lwz %r4,112+4(%r1)
187	mtlr %r0
188	b .Lfinish
189
190# case FFI_TYPE_STRUCT
191	mtlr %r0
192	addi %r1,%r1,144
193	blr
194	nop
195
196# case FFI_TYPE_POINTER
197	lwz %r3,112+0(%r1)
198	mtlr %r0
199	addi %r1,%r1,144
200	blr
201
202# case FFI_TYPE_UINT128
203	lwz %r3,112+0(%r1)
204	lwz %r4,112+4(%r1)
205	lwz %r5,112+8(%r1)
206	bl .Luint128
207
208# The return types below are only used when the ABI type is FFI_SYSV.
209# case FFI_SYSV_TYPE_SMALL_STRUCT + 1. One byte struct.
210	lbz %r3,112+0(%r1)
211	mtlr %r0
212	addi %r1,%r1,144
213	blr
214
215# case FFI_SYSV_TYPE_SMALL_STRUCT + 2. Two byte struct.
216	lhz %r3,112+0(%r1)
217	mtlr %r0
218	addi %r1,%r1,144
219	blr
220
221# case FFI_SYSV_TYPE_SMALL_STRUCT + 3. Three byte struct.
222	lwz %r3,112+0(%r1)
223	srwi %r3,%r3,8
224	mtlr %r0
225	b .Lfinish
226
227# case FFI_SYSV_TYPE_SMALL_STRUCT + 4. Four byte struct.
228	lwz %r3,112+0(%r1)
229	mtlr %r0
230	addi %r1,%r1,144
231	blr
232
233# case FFI_SYSV_TYPE_SMALL_STRUCT + 5. Five byte struct.
234	lwz %r3,112+0(%r1)
235	lwz %r4,112+4(%r1)
236	li %r5,24
237	b .Lstruct567
238
239# case FFI_SYSV_TYPE_SMALL_STRUCT + 6. Six byte struct.
240	lwz %r3,112+0(%r1)
241	lwz %r4,112+4(%r1)
242	li %r5,16
243	b .Lstruct567
244
245# case FFI_SYSV_TYPE_SMALL_STRUCT + 7. Seven byte struct.
246	lwz %r3,112+0(%r1)
247	lwz %r4,112+4(%r1)
248	li %r5,8
249	b .Lstruct567
250
251# case FFI_SYSV_TYPE_SMALL_STRUCT + 8. Eight byte struct.
252	lwz %r3,112+0(%r1)
253	lwz %r4,112+4(%r1)
254	mtlr %r0
255	b .Lfinish
256
257.Lstruct567:
258	subfic %r6,%r5,32
259	srw %r4,%r4,%r5
260	slw %r6,%r3,%r6
261	srw %r3,%r3,%r5
262	or %r4,%r6,%r4
263	mtlr %r0
264	addi %r1,%r1,144
265	blr
266
267.Luint128:
268	lwz %r6,112+12(%r1)
269	mtlr %r0
270	addi %r1,%r1,144
271	blr
272
273END(ffi_closure_SYSV)
274
275	.section	".eh_frame",EH_FRAME_FLAGS,@progbits
276.Lframe1:
277	.4byte	.LECIE1-.LSCIE1	 # Length of Common Information Entry
278.LSCIE1:
279	.4byte	0x0	 # CIE Identifier Tag
280	.byte	0x1	 # CIE Version
281#if defined _RELOCATABLE || defined __PIC__
282	.ascii "zR\0"	 # CIE Augmentation
283#else
284	.ascii "\0"	 # CIE Augmentation
285#endif
286	.uleb128 0x1	 # CIE Code Alignment Factor
287	.sleb128 -4	 # CIE Data Alignment Factor
288	.byte	0x41	 # CIE RA Column
289#if defined _RELOCATABLE || defined __PIC__
290	.uleb128 0x1	 # Augmentation size
291	.byte	0x1b	 # FDE Encoding (pcrel sdata4)
292#endif
293	.byte	0xc	 # DW_CFA_def_cfa
294	.uleb128 0x1
295	.uleb128 0x0
296	.align 2
297.LECIE1:
298.LSFDE1:
299	.4byte	.LEFDE1-.LASFDE1	 # FDE Length
300.LASFDE1:
301	.4byte	.LASFDE1-.Lframe1	 # FDE CIE offset
302#if defined _RELOCATABLE || defined __PIC__
303	.4byte	.LFB1-.	 # FDE initial location
304#else
305	.4byte	.LFB1	 # FDE initial location
306#endif
307	.4byte	.LFE1-.LFB1	 # FDE address range
308#if defined _RELOCATABLE || defined __PIC__
309	.uleb128 0x0	 # Augmentation size
310#endif
311	.byte	0x4	 # DW_CFA_advance_loc4
312	.4byte	.LCFI0-.LFB1
313	.byte	0xe	 # DW_CFA_def_cfa_offset
314	.uleb128 144
315	.byte	0x4	 # DW_CFA_advance_loc4
316	.4byte	.LCFI1-.LCFI0
317	.byte	0x11	 # DW_CFA_offset_extended_sf
318	.uleb128 0x41
319	.sleb128 -1
320	.align 2
321.LEFDE1:
322
323#endif
324
325#if defined __ELF__ && defined __linux__
326	.section	.note.GNU-stack,"",@progbits
327#endif
328