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
ffi_prep_args(char * stack,extended_cif * ecif)37 unsigned 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 */
ffi_prep_cif_machdep(ffi_cif * cif)100 ffi_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
163 extern 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 */
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)173 void 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
210 static void ffi_prep_incoming_args_SYSV (char *, void **, void **,
211 ffi_cif*, float *);
212
213 void ffi_closure_SYSV (ffi_closure *);
214
215 /* Do NOT change that without changing the FFI_TRAMPOLINE_SIZE */
216 extern 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 */
ffi_init_trampoline(unsigned char * __tramp,unsigned int __fun,unsigned int __ctx)227 void 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
240 ffi_status
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)241 ffi_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 */
ffi_closure_SYSV_inner(closure,respp,args,vfp_args)268 unsigned 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
ffi_prep_incoming_args_SYSV(char * stack,void ** rvalue,void ** avalue,ffi_cif * cif,float * vfp_stack)294 static 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