1/* -----------------------------------------------------------------------
2   darwin.S - Copyright (c) 2000 John Hornkvist
3	      Copyright (c) 2004 Free Software Foundation, 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, EXPRESS
19   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
21   IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
22   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
23   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
24   OTHER DEALINGS IN THE SOFTWARE.
25   ----------------------------------------------------------------------- */
26
27#if defined(__ppc64__)
28#define MODE_CHOICE(x, y) y
29#else
30#define MODE_CHOICE(x, y) x
31#endif
32
33#define g_long  MODE_CHOICE(long, quad)         /* usage is ".g_long" */
34
35#define LOG2_GPR_BYTES  MODE_CHOICE(2,3)        /* log2(GPR_BYTES) */
36
37#define LIBFFI_ASM
38#include <fficonfig.h>
39#include <ffi.h>
40#define JUMPTARGET(name) name
41#define L(x) x
42.text
43	.align 2
44.globl _ffi_prep_args
45
46.text
47	.align 2
48.globl _ffi_call_DARWIN
49.text
50	.align 2
51_ffi_call_DARWIN:
52LFB0:
53	mr   	r12,r8	/* We only need r12 until the call,
54			   so it doesn't have to be saved.  */
55LFB1:
56	/* Save the old stack pointer as AP.  */
57	mr	r8,r1
58LCFI0:
59	/* Allocate the stack space we need.  */
60	stwux	r1,r1,r4
61
62	/* Save registers we use.  */
63	mflr	r9
64
65	stw	r28,-16(r8)
66	stw	r29,-12(r8)
67	stw	r30,-8(r8)
68	stw	r31,-4(r8)
69
70	stw	r9,8(r8)
71	stw	r2,20(r1)
72LCFI1:
73
74	/* Save arguments over call.  */
75	mr	r31,r5	/* flags,  */
76	mr	r30,r6	/* rvalue,  */
77	mr	r29,r7	/* function address,  */
78	mr	r28,r8	/* our AP.  */
79LCFI2:
80	/* Call ffi_prep_args.  */
81	mr	r4,r1
82// ANDROID: these changes were necessary in 2.x; not yet tested in 3.x
83//	subi    r1,r1,32 /* Android: adjust stack for parameter / scratch area */
84	li	r9,0
85
86	mtctr	r12 /* r12 holds address of _ffi_prep_args.  */
87	bctrl
88//	addi    r1,r1,32 /* Android: readjust stack (see subi above) */
89	lwz     r2,20(r1)
90
91	/* Now do the call.
92	   Set up cr1 with bits 4-7 of the flags.  */
93	mtcrf	0x40,r31
94	/* Get the address to call into CTR.  */
95	mtctr	r29
96	/* Load all those argument registers.
97	   We have set up a nice stack frame, just load it into registers.  */
98	lwz     r3,20+(1*4)(r1)
99	lwz     r4,20+(2*4)(r1)
100	lwz     r5,20+(3*4)(r1)
101	lwz     r6,20+(4*4)(r1)
102	nop
103	lwz     r7,20+(5*4)(r1)
104	lwz     r8,20+(6*4)(r1)
105	lwz     r9,20+(7*4)(r1)
106	lwz     r10,20+(8*4)(r1)
107
108L1:
109	/* Load all the FP registers.  */
110	bf	6,L2	/* No floats to load.  */
111	lfd	f1,-16-(13*8)(r28)
112	lfd	f2,-16-(12*8)(r28)
113	lfd	f3,-16-(11*8)(r28)
114	lfd	f4,-16-(10*8)(r28)
115	nop
116	lfd	f5,-16-(9*8)(r28)
117	lfd	f6,-16-(8*8)(r28)
118	lfd	f7,-16-(7*8)(r28)
119	lfd	f8,-16-(6*8)(r28)
120	nop
121	lfd     f9,-16-(5*8)(r28)
122	lfd     f10,-16-(4*8)(r28)
123	lfd     f11,-16-(3*8)(r28)
124	lfd     f12,-16-(2*8)(r28)
125	nop
126	lfd     f13,-16-(1*8)(r28)
127
128L2:
129	mr	r12,r29	/* Put the target address in r12 as specified.  */
130	mtctr  	r12
131	nop
132	nop
133	/* Make the call.  */
134	bctrl
135
136	/* Now, deal with the return value.  */
137	mtcrf	0x01,r31
138
139	bt	30,L(done_return_value)
140	bt	29,L(fp_return_value)
141	stw	r3,0(r30)
142	bf	28,L(done_return_value)
143	stw	r4,4(r30)
144
145	/* Fall through.  */
146
147L(done_return_value):
148	/* Restore the registers we used and return.  */
149	lwz	r9,8(r28)
150	lwz	r31,-4(r28)
151	mtlr	r9
152	lwz	r30,-8(r28)
153	lwz	r29,-12(r28)
154	lwz	r28,-16(r28)
155	lwz	r1,0(r1)
156	blr
157
158L(fp_return_value):
159	/* Do we have long double to store?  */
160	bf	31,L(fd_return_value)
161	stfd	f1,0(r30)
162	stfd	f2,8(r30)
163	b	L(done_return_value)
164
165L(fd_return_value):
166	/* Do we have double to store?  */
167	bf	28,L(float_return_value)
168	stfd	f1,0(r30)
169	b	L(done_return_value)
170
171L(float_return_value):
172	/* We only have a float to store.  */
173	stfs	f1,0(r30)
174	b	L(done_return_value)
175
176LFE1:
177/* END(_ffi_call_DARWIN)  */
178
179/* Provide a null definition of _ffi_call_AIX.  */
180.text
181	.align 2
182.globl _ffi_call_AIX
183.text
184	.align 2
185_ffi_call_AIX:
186	blr
187/* END(_ffi_call_AIX)  */
188
189.data
190.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms
191EH_frame1:
192	.set	L$set$0,LECIE1-LSCIE1
193	.long	L$set$0	; Length of Common Information Entry
194LSCIE1:
195	.long	0x0	; CIE Identifier Tag
196	.byte	0x1	; CIE Version
197	.ascii	"zR\0"	; CIE Augmentation
198	.byte	0x1	; uleb128 0x1; CIE Code Alignment Factor
199	.byte	0x7c	; sleb128 -4; CIE Data Alignment Factor
200	.byte	0x41	; CIE RA Column
201	.byte	0x1	; uleb128 0x1; Augmentation size
202	.byte	0x90	; FDE Encoding (indirect pcrel)
203	.byte	0xc	; DW_CFA_def_cfa
204	.byte	0x1	; uleb128 0x1
205	.byte	0x0	; uleb128 0x0
206	.align	LOG2_GPR_BYTES
207LECIE1:
208.globl _ffi_call_DARWIN.eh
209_ffi_call_DARWIN.eh:
210LSFDE1:
211	.set	L$set$1,LEFDE1-LASFDE1
212	.long	L$set$1	; FDE Length
213LASFDE1:
214	.long	LASFDE1-EH_frame1 ; FDE CIE offset
215	.g_long	LLFB0$non_lazy_ptr-.	; FDE initial location
216	.set	L$set$3,LFE1-LFB0
217	.g_long	L$set$3	; FDE address range
218	.byte   0x0     ; uleb128 0x0; Augmentation size
219	.byte	0x4	; DW_CFA_advance_loc4
220	.set	L$set$4,LCFI0-LFB1
221	.long	L$set$4
222	.byte	0xd	; DW_CFA_def_cfa_register
223	.byte	0x08	; uleb128 0x08
224	.byte	0x4	; DW_CFA_advance_loc4
225	.set	L$set$5,LCFI1-LCFI0
226	.long	L$set$5
227	.byte   0x11    ; DW_CFA_offset_extended_sf
228	.byte	0x41	; uleb128 0x41
229	.byte   0x7e    ; sleb128 -2
230	.byte	0x9f	; DW_CFA_offset, column 0x1f
231	.byte	0x1	; uleb128 0x1
232	.byte	0x9e	; DW_CFA_offset, column 0x1e
233	.byte	0x2	; uleb128 0x2
234	.byte	0x9d	; DW_CFA_offset, column 0x1d
235	.byte	0x3	; uleb128 0x3
236	.byte	0x9c	; DW_CFA_offset, column 0x1c
237	.byte	0x4	; uleb128 0x4
238	.byte	0x4	; DW_CFA_advance_loc4
239	.set	L$set$6,LCFI2-LCFI1
240	.long	L$set$6
241	.byte	0xd	; DW_CFA_def_cfa_register
242	.byte	0x1c	; uleb128 0x1c
243	.align LOG2_GPR_BYTES
244LEFDE1:
245.data
246	.align LOG2_GPR_BYTES
247LLFB0$non_lazy_ptr:
248	.g_long LFB0
249