1 /* -----------------------------------------------------------------------
2 ffi.c
3
4 CSKY 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 #include <ffi.h>
28 #include <ffi_common.h>
29
30 #include <stdlib.h>
31
32 /* ffi_prep_args is called by the assembly routine once stack space
33 has been allocated for the function's arguments
34 */
35 void ffi_prep_args(char *stack, extended_cif *ecif)
36 {
37 register unsigned int i;
38 register void **p_argv;
39 register char *argp;
40 register ffi_type **p_arg;
41
42 argp = stack;
43
44 if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
45 *(void **) argp = ecif->rvalue;
46 argp += 4;
47 }
48
49 p_argv = ecif->avalue;
50
51 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
52 (i != 0);
53 i--, p_arg++)
54 {
55 size_t z;
56 size_t alignment;
57
58 /* Align if necessary */
59 alignment = (*p_arg)->alignment;
60 #ifdef __CSKYABIV1__
61 /*
62 * Adapt ABIV1 bug.
63 * If struct's size is larger than 8 bytes, then it always alignment as 4 bytes.
64 */
65 if (((*p_arg)->type == FFI_TYPE_STRUCT) && ((*p_arg)->size > 8) && (alignment == 8)) {
66 alignment = 4;
67 }
68 #endif
69
70 if ((alignment - 1) & (unsigned) argp) {
71 argp = (char *) FFI_ALIGN(argp, alignment);
72 }
73
74 if ((*p_arg)->type == FFI_TYPE_STRUCT)
75 argp = (char *) FFI_ALIGN(argp, 4);
76
77 z = (*p_arg)->size;
78 if (z < sizeof(int))
79 {
80 z = sizeof(int);
81 switch ((*p_arg)->type)
82 {
83 case FFI_TYPE_SINT8:
84 *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
85 break;
86
87 case FFI_TYPE_UINT8:
88 *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
89 break;
90
91 case FFI_TYPE_SINT16:
92 *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
93 break;
94
95 case FFI_TYPE_UINT16:
96 *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
97 break;
98
99 case FFI_TYPE_STRUCT:
100 #ifdef __CSKYBE__
101 memcpy((argp + 4 - (*p_arg)->size), *p_argv, (*p_arg)->size);
102 #else
103 memcpy(argp, *p_argv, (*p_arg)->size);
104 #endif
105 break;
106
107 default:
108 FFI_ASSERT(0);
109 }
110 }
111 else if (z == sizeof(int))
112 {
113 *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
114 }
115 else
116 {
117 memcpy(argp, *p_argv, z);
118 }
119 p_argv++;
120 argp += z;
121 }
122
123 return;
124 }
125
126 /* Perform machine dependent cif processing */
127 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
128 {
129 /* Round the stack up to a multiple of 8 bytes. This isn't needed
130 everywhere, but it is on some platforms, and it doesn't hcsky anything
131 when it isn't needed. */
132 cif->bytes = (cif->bytes + 7) & ~7;
133
134 /* Set the return type flag */
135 switch (cif->rtype->type)
136 {
137
138 case FFI_TYPE_DOUBLE:
139 case FFI_TYPE_SINT64:
140 case FFI_TYPE_UINT64:
141 cif->flags = (unsigned) FFI_TYPE_SINT64;
142 break;
143
144 case FFI_TYPE_STRUCT:
145 if (cif->rtype->size <= 4)
146 /* A Composite Type not larger than 4 bytes is returned in r0. */
147 cif->flags = (unsigned)FFI_TYPE_INT;
148 else if (cif->rtype->size <= 8)
149 /* A Composite Type not larger than 8 bytes is returned in r0, r1. */
150 cif->flags = (unsigned)FFI_TYPE_SINT64;
151 else
152 /* A Composite Type larger than 8 bytes, or whose size cannot
153 be determined statically ... is stored in memory at an
154 address passed [in r0]. */
155 cif->flags = (unsigned)FFI_TYPE_STRUCT;
156 break;
157
158 default:
159 cif->flags = FFI_TYPE_INT;
160 break;
161 }
162
163 return FFI_OK;
164 }
165
166 /* Perform machine dependent cif processing for variadic calls */
167 ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
168 unsigned int nfixedargs,
169 unsigned int ntotalargs)
170 {
171 return ffi_prep_cif_machdep(cif);
172 }
173
174 /* Prototypes for assembly functions, in sysv.S */
175 extern void ffi_call_SYSV (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
176
177 void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
178 {
179 extended_cif ecif;
180
181 int small_struct = (cif->flags == FFI_TYPE_INT
182 && cif->rtype->type == FFI_TYPE_STRUCT);
183
184 ecif.cif = cif;
185 ecif.avalue = avalue;
186
187 unsigned int temp;
188
189 /* If the return value is a struct and we don't have a return */
190 /* value address then we need to make one */
191
192 if ((rvalue == NULL) &&
193 (cif->flags == FFI_TYPE_STRUCT))
194 {
195 ecif.rvalue = alloca(cif->rtype->size);
196 }
197 else if (small_struct)
198 ecif.rvalue = &temp;
199 else
200 ecif.rvalue = rvalue;
201
202 switch (cif->abi)
203 {
204 case FFI_SYSV:
205 ffi_call_SYSV (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
206 break;
207
208 default:
209 FFI_ASSERT(0);
210 break;
211 }
212 if (small_struct)
213 #ifdef __CSKYBE__
214 memcpy (rvalue, ((unsigned char *)&temp + (4 - cif->rtype->size)), cif->rtype->size);
215 #else
216 memcpy (rvalue, &temp, cif->rtype->size);
217 #endif
218 }
219
220 /** private members **/
221
222 static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
223 void** args, ffi_cif* cif);
224
225 void ffi_closure_SYSV (ffi_closure *);
226
227 /* This function is jumped to by the trampoline */
228
229 unsigned int
230 ffi_closure_SYSV_inner (closure, respp, args)
231 ffi_closure *closure;
232 void **respp;
233 void *args;
234 {
235 // our various things...
236 ffi_cif *cif;
237 void **arg_area;
238
239 cif = closure->cif;
240 arg_area = (void**) alloca (cif->nargs * sizeof (void*));
241
242 /* this call will initialize ARG_AREA, such that each
243 * element in that array points to the corresponding
244 * value on the stack; and if the function returns
245 * a structure, it will re-set RESP to point to the
246 * structure return address. */
247
248 ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
249
250 (closure->fun) (cif, *respp, arg_area, closure->user_data);
251
252 #ifdef __CSKYBE__
253 if (cif->flags == FFI_TYPE_INT && cif->rtype->type == FFI_TYPE_STRUCT) {
254 unsigned int tmp = 0;
255 tmp = *(unsigned int *)(*respp);
256 *(unsigned int *)(*respp) = (tmp >> ((4 - cif->rtype->size) * 8));
257 }
258 #endif
259
260 return cif->flags;
261 }
262
263
264 static void
265 ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
266 void **avalue, ffi_cif *cif)
267 {
268 register unsigned int i;
269 register void **p_argv;
270 register char *argp;
271 register ffi_type **p_arg;
272
273 argp = stack;
274
275 if ( cif->flags == FFI_TYPE_STRUCT ) {
276 *rvalue = *(void **) argp;
277 argp += 4;
278 }
279
280 p_argv = avalue;
281
282 for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
283 {
284 size_t z;
285 size_t alignment;
286
287 alignment = (*p_arg)->alignment;
288 if (alignment < 4)
289 alignment = 4;
290
291 #ifdef __CSKYABIV1__
292 /*
293 * Adapt ABIV1 bug.
294 * If struct's size is larger than 8 bytes, then it always alignment as 4 bytes.
295 */
296 if (((*p_arg)->type == FFI_TYPE_STRUCT) && ((*p_arg)->size > 8) && (alignment == 8)) {
297 alignment = 4;
298 }
299 #endif
300
301 /* Align if necessary */
302 if ((alignment - 1) & (unsigned) argp) {
303 argp = (char *) FFI_ALIGN(argp, alignment);
304 }
305
306 z = (*p_arg)->size;
307
308 #ifdef __CSKYBE__
309 unsigned int tmp = 0;
310 if ((*p_arg)->size < 4) {
311 tmp = *(unsigned int *)argp;
312 memcpy(argp, ((unsigned char *)&tmp + (4 - (*p_arg)->size)), (*p_arg)->size);
313 }
314 #else
315 /* because we're little endian, this is what it turns into. */
316 #endif
317 *p_argv = (void*) argp;
318
319 p_argv++;
320 argp += z;
321 }
322
323 return;
324 }
325
326 /* How to make a trampoline. */
327
328 extern unsigned char ffi_csky_trampoline[TRAMPOLINE_SIZE];
329
330 /*
331 * Since there is no __clear_cache in libgcc in csky toolchain.
332 * define ffi_csky_cacheflush in sysv.S.
333 * void ffi_csky_cacheflush(uint32 start_addr, uint32 size, int cache)
334 */
335 #define CACHEFLUSH_IN_FFI 1
336 #if CACHEFLUSH_IN_FFI
337 extern void ffi_csky_cacheflush(unsigned char *__tramp, unsigned int k,
338 int i);
339 #define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
340 ({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
341 unsigned int __fun = (unsigned int)(FUN); \
342 unsigned int __ctx = (unsigned int)(CTX); \
343 unsigned char *insns = (unsigned char *)(CTX); \
344 memcpy (__tramp, ffi_csky_trampoline, TRAMPOLINE_SIZE); \
345 *(unsigned int*) &__tramp[TRAMPOLINE_SIZE] = __ctx; \
346 *(unsigned int*) &__tramp[TRAMPOLINE_SIZE + 4] = __fun; \
347 ffi_csky_cacheflush(&__tramp[0], TRAMPOLINE_SIZE, 3); /* Clear data mapping. */ \
348 ffi_csky_cacheflush(insns, TRAMPOLINE_SIZE, 3); \
349 /* Clear instruction \
350 mapping. */ \
351 })
352 #else
353 #define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX) \
354 ({ unsigned char *__tramp = (unsigned char*)(TRAMP); \
355 unsigned int __fun = (unsigned int)(FUN); \
356 unsigned int __ctx = (unsigned int)(CTX); \
357 unsigned char *insns = (unsigned char *)(CTX); \
358 memcpy (__tramp, ffi_csky_trampoline, TRAMPOLINE_SIZE); \
359 *(unsigned int*) &__tramp[TRAMPOLINE_SIZE] = __ctx; \
360 *(unsigned int*) &__tramp[TRAMPOLINE_SIZE + 4] = __fun; \
361 __clear_cache((&__tramp[0]), (&__tramp[TRAMPOLINE_SIZE-1])); /* Clear data mapping. */ \
362 __clear_cache(insns, insns + TRAMPOLINE_SIZE); \
363 /* Clear instruction \
364 mapping. */ \
365 })
366 #endif
367
368 /* the cif must already be prep'ed */
369
370 ffi_status
371 ffi_prep_closure_loc (ffi_closure* closure,
372 ffi_cif* cif,
373 void (*fun)(ffi_cif*,void*,void**,void*),
374 void *user_data,
375 void *codeloc)
376 {
377 void (*closure_func)(ffi_closure*) = NULL;
378
379 if (cif->abi == FFI_SYSV)
380 closure_func = &ffi_closure_SYSV;
381 else
382 return FFI_BAD_ABI;
383
384 FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
385 closure_func, \
386 codeloc);
387
388 closure->cif = cif;
389 closure->user_data = user_data;
390 closure->fun = fun;
391
392 return FFI_OK;
393 }
394
395