1/* ----------------------------------------------------------------------
2  ffi.c - Copyright (c) 2013 Imagination Technologies
3
4  Meta Foreign Function Interface
5  Permission is hereby granted, free of charge, to any person obtaining
6  a copy of this software and associated documentation files (the
7  `Software''), to deal in the Software without restriction, including
8  without limitation the rights to use, copy, modify, merge, publish,
9  distribute, sublicense, and/or sell copies of the Software, and to
10  permit persons to whom the Software is furnished to do so, subject to
11  the following conditions:
12
13  The above copyright notice and this permission notice shall be included
14  in all copies or substantial portions of the Software.
15
16  THE SOFTWARE IS PROVIDED `AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
17  OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19  IN NO EVENT SHALL SIMON POSNJAK BE LIABLE FOR ANY CLAIM, DAMAGES OR
20  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22  OTHER DEALINGS IN THE SOFTWARE.
23----------------------------------------------------------------------- */
24
25#include <ffi.h>
26#include <ffi_common.h>
27
28#include <stdlib.h>
29
30#define MIN(a,b) (((a) < (b)) ? (a) : (b))
31
32/*
33 * ffi_prep_args is called by the assembly routine once stack space has been
34 * allocated for the function's arguments
35 */
36
37unsigned int ffi_prep_args(char *stack, extended_cif *ecif)
38{
39	register unsigned int i;
40	register void **p_argv;
41	register char *argp;
42	register ffi_type **p_arg;
43
44	argp = stack;
45
46	/* Store return value */
47	if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
48		argp -= 4;
49		*(void **) argp = ecif->rvalue;
50	}
51
52	p_argv = ecif->avalue;
53
54	/* point to next location */
55	for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; (i != 0); i--, p_arg++, p_argv++)
56	{
57		size_t z;
58
59		/* Move argp to address of argument */
60		z = (*p_arg)->size;
61		argp -= z;
62
63		/* Align if necessary */
64		argp = (char *) ALIGN_DOWN(ALIGN_DOWN(argp, (*p_arg)->alignment), 4);
65
66		if (z < sizeof(int)) {
67			z = sizeof(int);
68			switch ((*p_arg)->type)
69			{
70			case FFI_TYPE_SINT8:
71				*(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
72				break;
73			case FFI_TYPE_UINT8:
74				*(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
75				break;
76			case FFI_TYPE_SINT16:
77				*(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
78				break;
79			case FFI_TYPE_UINT16:
80				*(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
81			case FFI_TYPE_STRUCT:
82				memcpy(argp, *p_argv, (*p_arg)->size);
83				break;
84			default:
85				FFI_ASSERT(0);
86			}
87		} else if ( z == sizeof(int)) {
88			*(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
89		} else {
90			memcpy(argp, *p_argv, z);
91		}
92	}
93
94	/* return the size of the arguments to be passed in registers,
95	   padded to an 8 byte boundary to preserve stack alignment */
96	return ALIGN(MIN(stack - argp, 6*4), 8);
97}
98
99/* Perform machine dependent cif processing */
100ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
101{
102	ffi_type **ptr;
103	unsigned i, bytes = 0;
104
105	for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++) {
106		if ((*ptr)->size == 0)
107			return FFI_BAD_TYPEDEF;
108
109		/* Perform a sanity check on the argument type, do this
110		   check after the initialization.  */
111		FFI_ASSERT_VALID_TYPE(*ptr);
112
113		/* Add any padding if necessary */
114		if (((*ptr)->alignment - 1) & bytes)
115			bytes = ALIGN(bytes, (*ptr)->alignment);
116
117		bytes += ALIGN((*ptr)->size, 4);
118	}
119
120	/* Ensure arg space is aligned to an 8-byte boundary */
121	bytes = ALIGN(bytes, 8);
122
123	/* Make space for the return structure pointer */
124	if (cif->rtype->type == FFI_TYPE_STRUCT) {
125		bytes += sizeof(void*);
126
127		/* Ensure stack is aligned to an 8-byte boundary */
128		bytes = ALIGN(bytes, 8);
129	}
130
131	cif->bytes = bytes;
132
133	/* Set the return type flag */
134	switch (cif->rtype->type) {
135	case FFI_TYPE_VOID:
136	case FFI_TYPE_FLOAT:
137	case FFI_TYPE_DOUBLE:
138		cif->flags = (unsigned) cif->rtype->type;
139		break;
140	case FFI_TYPE_SINT64:
141	case FFI_TYPE_UINT64:
142		cif->flags = (unsigned) FFI_TYPE_SINT64;
143		break;
144	case FFI_TYPE_STRUCT:
145		/* Meta can store return values which are <= 64 bits */
146		if (cif->rtype->size <= 4)
147			/* Returned to D0Re0 as 32-bit value */
148			cif->flags = (unsigned)FFI_TYPE_INT;
149		else if ((cif->rtype->size > 4) && (cif->rtype->size <= 8))
150			/* Returned valued is stored to D1Re0|R0Re0 */
151			cif->flags = (unsigned)FFI_TYPE_DOUBLE;
152		else
153			/* value stored in memory */
154			cif->flags = (unsigned)FFI_TYPE_STRUCT;
155		break;
156	default:
157		cif->flags = (unsigned)FFI_TYPE_INT;
158		break;
159	}
160	return FFI_OK;
161}
162
163extern void ffi_call_SYSV(void (*fn)(void), extended_cif *, unsigned, unsigned, double *);
164
165/*
166 * Exported in API. Entry point
167 * cif -> ffi_cif object
168 * fn -> function pointer
169 * rvalue -> pointer to return value
170 * avalue -> vector of void * pointers pointing to memory locations holding the
171 * arguments
172 */
173void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
174{
175	extended_cif ecif;
176
177	int small_struct = (((cif->flags == FFI_TYPE_INT) || (cif->flags == FFI_TYPE_DOUBLE)) && (cif->rtype->type == FFI_TYPE_STRUCT));
178	ecif.cif = cif;
179	ecif.avalue = avalue;
180
181	double temp;
182
183	/*
184	 * If the return value is a struct and we don't have a return value address
185	 * then we need to make one
186	 */
187
188	if ((rvalue == NULL ) && (cif->flags == FFI_TYPE_STRUCT))
189		ecif.rvalue = alloca(cif->rtype->size);
190	else if (small_struct)
191		ecif.rvalue = &temp;
192	else
193		ecif.rvalue = rvalue;
194
195	switch (cif->abi) {
196	case FFI_SYSV:
197		ffi_call_SYSV(fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
198		break;
199	default:
200		FFI_ASSERT(0);
201		break;
202	}
203
204	if (small_struct)
205		memcpy (rvalue, &temp, cif->rtype->size);
206}
207
208/* private members */
209
210static void ffi_prep_incoming_args_SYSV (char *, void **, void **,
211	ffi_cif*, float *);
212
213void ffi_closure_SYSV (ffi_closure *);
214
215/* Do NOT change that without changing the FFI_TRAMPOLINE_SIZE */
216extern unsigned int ffi_metag_trampoline[10]; /* 10 instructions */
217
218/* end of private members */
219
220/*
221 * __tramp: trampoline memory location
222 * __fun: assembly routine
223 * __ctx: memory location for wrapper
224 *
225 * At this point, tramp[0] == __ctx !
226 */
227void ffi_init_trampoline(unsigned char *__tramp, unsigned int __fun, unsigned int __ctx) {
228	memcpy (__tramp, ffi_metag_trampoline, sizeof(ffi_metag_trampoline));
229	*(unsigned int*) &__tramp[40] = __ctx;
230	*(unsigned int*) &__tramp[44] = __fun;
231	/* This will flush the instruction cache */
232	__builtin_meta2_cachewd(&__tramp[0], 1);
233	__builtin_meta2_cachewd(&__tramp[47], 1);
234}
235
236
237
238/* the cif must already be prepared */
239
240ffi_status
241ffi_prep_closure_loc (ffi_closure *closure,
242	ffi_cif* cif,
243	void (*fun)(ffi_cif*,void*,void**,void*),
244	void *user_data,
245	void *codeloc)
246{
247	void (*closure_func)(ffi_closure*) = NULL;
248
249	if (cif->abi == FFI_SYSV)
250		closure_func = &ffi_closure_SYSV;
251	else
252		return FFI_BAD_ABI;
253
254	ffi_init_trampoline(
255		(unsigned char*)&closure->tramp[0],
256		(unsigned int)closure_func,
257		(unsigned int)codeloc);
258
259	closure->cif = cif;
260	closure->user_data = user_data;
261	closure->fun = fun;
262
263	return FFI_OK;
264}
265
266
267/* This function is jumped to by the trampoline */
268unsigned int ffi_closure_SYSV_inner (closure, respp, args, vfp_args)
269	ffi_closure *closure;
270	void **respp;
271	void *args;
272	void *vfp_args;
273{
274	ffi_cif *cif;
275	void **arg_area;
276
277	cif = closure->cif;
278	arg_area = (void**) alloca (cif->nargs * sizeof (void*));
279
280	/*
281	 * This call will initialize ARG_AREA, such that each
282	 * element in that array points to the corresponding
283	 * value on the stack; and if the function returns
284	 * a structure, it will re-set RESP to point to the
285	 * structure return address.
286	 */
287	ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif, vfp_args);
288
289	(closure->fun) ( cif, *respp, arg_area, closure->user_data);
290
291	return cif->flags;
292}
293
294static void ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
295	void **avalue, ffi_cif *cif,
296	float *vfp_stack)
297{
298	register unsigned int i;
299	register void **p_argv;
300	register char *argp;
301	register ffi_type **p_arg;
302
303	/* stack points to original arguments */
304	argp = stack;
305
306	/* Store return value */
307	if ( cif->flags == FFI_TYPE_STRUCT ) {
308		argp -= 4;
309		*rvalue = *(void **) argp;
310	}
311
312	p_argv = avalue;
313
314	for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) {
315		size_t z;
316		size_t alignment;
317
318		alignment = (*p_arg)->alignment;
319		if (alignment < 4)
320			alignment = 4;
321		if ((alignment - 1) & (unsigned)argp)
322			argp = (char *) ALIGN(argp, alignment);
323
324		z = (*p_arg)->size;
325		*p_argv = (void*) argp;
326		p_argv++;
327		argp -= z;
328	}
329	return;
330}
331