1/* -----------------------------------------------------------------------
2   sysv.S - Copyright (c) 1998, 2008 Red Hat, Inc.
3
4   ARM Foreign Function Interface
5
6   Permission is hereby granted, free of charge, to any person obtaining
7   a copy of this software and associated documentation files (the
8   ``Software''), to deal in the Software without restriction, including
9   without limitation the rights to use, copy, modify, merge, publish,
10   distribute, sublicense, and/or sell copies of the Software, and to
11   permit persons to whom the Software is furnished to do so, subject to
12   the following conditions:
13
14   The above copyright notice and this permission notice shall be included
15   in all copies or substantial portions of the Software.
16
17   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
18   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24   DEALINGS IN THE SOFTWARE.
25   ----------------------------------------------------------------------- */
26
27#define LIBFFI_ASM
28#include <fficonfig.h>
29#include <ffi.h>
30#ifdef HAVE_MACHINE_ASM_H
31#include <machine/asm.h>
32#else
33#ifdef __USER_LABEL_PREFIX__
34#define CONCAT1(a, b) CONCAT2(a, b)
35#define CONCAT2(a, b) a ## b
36
37/* Use the right prefix for global labels.  */
38#define CNAME(x) CONCAT1 (__USER_LABEL_PREFIX__, x)
39#else
40#define CNAME(x) x
41#endif
42#define ENTRY(x) .globl CNAME(x); .type CNAME(x),%function; CNAME(x):
43#endif
44
45#ifdef __ELF__
46#define LSYM(x) .x
47#else
48#define LSYM(x) x
49#endif
50
51/* We need a better way of testing for this, but for now, this is all
52   we can do.  */
53@ This selects the minimum architecture level required.
54#define __ARM_ARCH__ 3
55
56#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
57# undef __ARM_ARCH__
58# define __ARM_ARCH__ 4
59#endif
60
61#if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \
62	|| defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \
63	|| defined(__ARM_ARCH_5TEJ__)
64# undef __ARM_ARCH__
65# define __ARM_ARCH__ 5
66#endif
67
68#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \
69        || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \
70        || defined(__ARM_ARCH_6ZK__)
71# undef __ARM_ARCH__
72# define __ARM_ARCH__ 6
73#endif
74
75#if __ARM_ARCH__ >= 5
76# define call_reg(x)	blx	x
77#elif defined (__ARM_ARCH_4T__)
78# define call_reg(x)	mov	lr, pc ; bx	x
79# if defined(__thumb__) || defined(__THUMB_INTERWORK__)
80#  define __INTERWORKING__
81# endif
82#else
83# define call_reg(x)	mov	lr, pc ; mov	pc, x
84#endif
85
86/* Conditionally compile unwinder directives.  */
87#ifdef __ARM_EABI__
88#define UNWIND
89#else
90#define UNWIND @
91#endif
92
93
94#if defined(__thumb__) && !defined(__THUMB_INTERWORK__)
95.macro	ARM_FUNC_START name
96	.text
97	.align 0
98	.thumb
99	.thumb_func
100	ENTRY(\name)
101	bx	pc
102	nop
103	.arm
104	UNWIND .fnstart
105/* A hook to tell gdb that we've switched to ARM mode.  Also used to call
106   directly from other local arm routines.  */
107_L__\name:
108.endm
109#else
110.macro	ARM_FUNC_START name
111	.text
112	.align 0
113	.arm
114	ENTRY(\name)
115	UNWIND .fnstart
116.endm
117#endif
118
119.macro	RETLDM	regs=, cond=, dirn=ia
120#if defined (__INTERWORKING__)
121	.ifc "\regs",""
122	ldr\cond	lr, [sp], #4
123	.else
124	ldm\cond\dirn	sp!, {\regs, lr}
125	.endif
126	bx\cond	lr
127#else
128	.ifc "\regs",""
129	ldr\cond	pc, [sp], #4
130	.else
131	ldm\cond\dirn	sp!, {\regs, pc}
132	.endif
133#endif
134.endm
135
136
137	@ r0:   ffi_prep_args
138	@ r1:   &ecif
139	@ r2:   cif->bytes
140	@ r3:   fig->flags
141	@ sp+0: ecif.rvalue
142	@ sp+4: fn
143
144	@ This assumes we are using gas.
145ARM_FUNC_START ffi_call_SYSV
146	@ Save registers
147        stmfd	sp!, {r0-r3, fp, lr}
148	UNWIND .save	{r0-r3, fp, lr}
149	mov	fp, sp
150
151	UNWIND .setfp	fp, sp
152
153	@ Make room for all of the new args.
154	sub	sp, fp, r2
155
156	@ Place all of the ffi_prep_args in position
157	mov	ip, r0
158	mov	r0, sp
159	@     r1 already set
160
161	@ Call ffi_prep_args(stack, &ecif)
162	call_reg(ip)
163
164	@ move first 4 parameters in registers
165	ldmia	sp, {r0-r3}
166
167	@ and adjust stack
168	ldr	ip, [fp, #8]
169        cmp	ip, #16
170	movhs	ip, #16
171        add	sp, sp, ip
172
173	@ call (fn) (...)
174	ldr	ip, [fp, #28]
175	call_reg(ip)
176
177	@ Remove the space we pushed for the args
178	mov	sp, fp
179
180	@ Load r2 with the pointer to storage for the return value
181	ldr	r2, [sp, #24]
182
183	@ Load r3 with the return type code
184	ldr	r3, [sp, #12]
185
186	@ If the return value pointer is NULL, assume no return value.
187	cmp	r2, #0
188	beq	LSYM(Lepilogue)
189
190@ return INT
191	cmp	r3, #FFI_TYPE_INT
192#ifdef __SOFTFP__
193	cmpne	r3, #FFI_TYPE_FLOAT
194#endif
195	streq	r0, [r2]
196	beq	LSYM(Lepilogue)
197
198	@ return INT64
199	cmp	r3, #FFI_TYPE_SINT64
200#ifdef __SOFTFP__
201	cmpne	r3, #FFI_TYPE_DOUBLE
202#endif
203	stmeqia	r2, {r0, r1}
204
205#ifndef __SOFTFP__
206	beq	LSYM(Lepilogue)
207
208@ return FLOAT
209	cmp	r3, #FFI_TYPE_FLOAT
210	stfeqs	f0, [r2]
211	beq	LSYM(Lepilogue)
212
213@ return DOUBLE or LONGDOUBLE
214	cmp	r3, #FFI_TYPE_DOUBLE
215	stfeqd	f0, [r2]
216#endif
217
218LSYM(Lepilogue):
219	RETLDM	"r0-r3,fp"
220
221.ffi_call_SYSV_end:
222	UNWIND .fnend
223        .size    CNAME(ffi_call_SYSV),.ffi_call_SYSV_end-CNAME(ffi_call_SYSV)
224
225/*
226	unsigned int FFI_HIDDEN
227	ffi_closure_SYSV_inner (closure, respp, args)
228	     ffi_closure *closure;
229	     void **respp;
230  	     void *args;
231*/
232
233ARM_FUNC_START ffi_closure_SYSV
234	UNWIND .pad #16
235	add	ip, sp, #16
236	stmfd	sp!, {ip, lr}
237	UNWIND .save	{r0, lr}
238	add	r2, sp, #8
239	.pad #16
240	sub	sp, sp, #16
241	str	sp, [sp, #8]
242	add	r1, sp, #8
243	bl	ffi_closure_SYSV_inner
244	cmp	r0, #FFI_TYPE_INT
245	beq	.Lretint
246
247	cmp	r0, #FFI_TYPE_FLOAT
248#ifdef __SOFTFP__
249	beq	.Lretint
250#else
251	beq	.Lretfloat
252#endif
253
254	cmp	r0, #FFI_TYPE_DOUBLE
255#ifdef __SOFTFP__
256	beq	.Lretlonglong
257#else
258	beq	.Lretdouble
259#endif
260
261	cmp	r0, #FFI_TYPE_LONGDOUBLE
262#ifdef __SOFTFP__
263	beq	.Lretlonglong
264#else
265	beq	.Lretlongdouble
266#endif
267
268	cmp	r0, #FFI_TYPE_SINT64
269	beq	.Lretlonglong
270.Lclosure_epilogue:
271	add	sp, sp, #16
272	ldmfd	sp, {sp, pc}
273.Lretint:
274	ldr	r0, [sp]
275	b	.Lclosure_epilogue
276.Lretlonglong:
277	ldr	r0, [sp]
278	ldr	r1, [sp, #4]
279	b	.Lclosure_epilogue
280
281#ifndef __SOFTFP__
282.Lretfloat:
283	ldfs	f0, [sp]
284	b	.Lclosure_epilogue
285.Lretdouble:
286	ldfd	f0, [sp]
287	b	.Lclosure_epilogue
288.Lretlongdouble:
289	ldfd	f0, [sp]
290	b	.Lclosure_epilogue
291#endif
292
293.ffi_closure_SYSV_end:
294	UNWIND .fnend
295        .size    CNAME(ffi_closure_SYSV),.ffi_closure_SYSV_end-CNAME(ffi_closure_SYSV)
296
297#if defined __ELF__ && defined __linux__
298	.section	.note.GNU-stack,"",%progbits
299#endif
300