1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2003, 2004 Kaz Kojima
3 Copyright (c) 2008 Anthony Green
5 SuperH SHmedia Foreign Function Interface
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:
15 The above copyright notice and this permission notice shall be included
16 in all copies or substantial portions of the Software.
18 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
19 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 DEALINGS IN THE SOFTWARE.
26 ----------------------------------------------------------------------- */
29 #include <ffi_common.h>
37 return_type (ffi_type *arg)
40 if (arg->type != FFI_TYPE_STRUCT)
43 /* gcc uses r2 if the result can be packed in on register. */
44 if (arg->size <= sizeof (UINT8))
45 return FFI_TYPE_UINT8;
46 else if (arg->size <= sizeof (UINT16))
47 return FFI_TYPE_UINT16;
48 else if (arg->size <= sizeof (UINT32))
49 return FFI_TYPE_UINT32;
50 else if (arg->size <= sizeof (UINT64))
51 return FFI_TYPE_UINT64;
53 return FFI_TYPE_STRUCT;
56 /* ffi_prep_args is called by the assembly routine once stack space
57 has been allocated for the function's arguments */
60 void ffi_prep_args(char *stack, extended_cif *ecif)
63 register unsigned int i;
64 register unsigned int avn;
65 register void **p_argv;
67 register ffi_type **p_arg;
71 if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
73 *(void **) argp = ecif->rvalue;
74 argp += sizeof (UINT64);
77 avn = ecif->cif->nargs;
78 p_argv = ecif->avalue;
80 for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
86 align = (*p_arg)->alignment;
87 if (z < sizeof (UINT32))
89 switch ((*p_arg)->type)
92 *(SINT64 *) argp = (SINT64) *(SINT8 *)(*p_argv);
96 *(UINT64 *) argp = (UINT64) *(UINT8 *)(*p_argv);
100 *(SINT64 *) argp = (SINT64) *(SINT16 *)(*p_argv);
103 case FFI_TYPE_UINT16:
104 *(UINT64 *) argp = (UINT64) *(UINT16 *)(*p_argv);
107 case FFI_TYPE_STRUCT:
108 memcpy (argp, *p_argv, z);
114 argp += sizeof (UINT64);
116 else if (z == sizeof (UINT32) && align == sizeof (UINT32))
118 switch ((*p_arg)->type)
121 case FFI_TYPE_SINT32:
122 *(SINT64 *) argp = (SINT64) *(SINT32 *) (*p_argv);
126 case FFI_TYPE_POINTER:
127 case FFI_TYPE_UINT32:
128 case FFI_TYPE_STRUCT:
129 *(UINT64 *) argp = (UINT64) *(UINT32 *) (*p_argv);
136 argp += sizeof (UINT64);
138 else if (z == sizeof (UINT64)
139 && align == sizeof (UINT64)
140 && ((int) *p_argv & (sizeof (UINT64) - 1)) == 0)
142 *(UINT64 *) argp = *(UINT64 *) (*p_argv);
143 argp += sizeof (UINT64);
147 int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
149 memcpy (argp, *p_argv, z);
150 argp += n * sizeof (UINT64);
157 /* Perform machine dependent cif processing */
158 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
166 greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0);
170 for (i = j = 0; i < cif->nargs; i++)
172 type = (cif->arg_types)[i]->type;
177 cif->bytes += sizeof (UINT64) - sizeof (float);
178 if (freg >= NFREGARG - 1)
181 cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
184 case FFI_TYPE_DOUBLE:
185 if (greg++ >= NGREGARG && (freg + 1) >= NFREGARG)
187 if ((freg + 1) < NFREGARG)
189 freg = (freg + 1) & ~1;
191 cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
194 cif->flags2 += FFI_TYPE_INT << (2 * j++);
198 size = (cif->arg_types)[i]->size;
199 if (size < sizeof (UINT64))
200 cif->bytes += sizeof (UINT64) - size;
201 n = (size + sizeof (UINT64) - 1) / sizeof (UINT64);
202 if (greg >= NGREGARG)
204 else if (greg + n - 1 >= NGREGARG)
208 for (m = 0; m < n; m++)
209 cif->flags2 += FFI_TYPE_INT << (2 * j++);
214 /* Set the return type flag */
215 switch (cif->rtype->type)
217 case FFI_TYPE_STRUCT:
218 cif->flags = return_type (cif->rtype);
223 case FFI_TYPE_DOUBLE:
224 case FFI_TYPE_SINT64:
225 case FFI_TYPE_UINT64:
226 cif->flags = cif->rtype->type;
230 cif->flags = FFI_TYPE_INT;
239 extern void ffi_call_SYSV(void (*)(char *, extended_cif *),
240 /*@out@*/ extended_cif *,
241 unsigned, unsigned, long long,
242 /*@out@*/ unsigned *,
247 void ffi_call(/*@dependent@*/ ffi_cif *cif,
249 /*@out@*/ void *rvalue,
250 /*@dependent@*/ void **avalue)
256 ecif.avalue = avalue;
258 /* If the return value is a struct and we don't have a return */
259 /* value address then we need to make one */
261 if (cif->rtype->type == FFI_TYPE_STRUCT
262 && return_type (cif->rtype) != FFI_TYPE_STRUCT)
263 ecif.rvalue = &trvalue;
264 else if ((rvalue == NULL) &&
265 (cif->rtype->type == FFI_TYPE_STRUCT))
268 ecif.rvalue = alloca(cif->rtype->size);
272 ecif.rvalue = rvalue;
278 ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes,
279 cif->flags, cif->flags2, ecif.rvalue, fn);
288 && cif->rtype->type == FFI_TYPE_STRUCT
289 && return_type (cif->rtype) != FFI_TYPE_STRUCT)
290 memcpy (rvalue, &trvalue, cif->rtype->size);
293 extern void ffi_closure_SYSV (void);
294 extern void __ic_invalidate (void *line);
297 ffi_prep_closure (ffi_closure *closure,
299 void (*fun)(ffi_cif*, void*, void**, void*),
304 FFI_ASSERT (cif->abi == FFI_GCC_SYSV);
306 tramp = (unsigned int *) &closure->tramp[0];
307 /* Since ffi_closure is an aligned object, the ffi trampoline is
308 called as an SHcompact code. Sigh.
310 mova @(1,pc),r0; add #1,r0; jmp @r0; nop;
312 movi fnaddr >> 16,r1; shori fnaddr,r1; ptabs/l r1,tr0
313 movi cxt >> 16,r1; shori cxt,r1; blink tr0,r63 */
314 #ifdef __LITTLE_ENDIAN__
315 tramp[0] = 0x7001c701;
316 tramp[1] = 0x0009402b;
318 tramp[0] = 0xc7017001;
319 tramp[1] = 0x402b0009;
321 tramp[2] = 0xcc000010 | (((UINT32) ffi_closure_SYSV) >> 16) << 10;
322 tramp[3] = 0xc8000010 | (((UINT32) ffi_closure_SYSV) & 0xffff) << 10;
323 tramp[4] = 0x6bf10600;
324 tramp[5] = 0xcc000010 | (((UINT32) closure) >> 16) << 10;
325 tramp[6] = 0xc8000010 | (((UINT32) closure) & 0xffff) << 10;
326 tramp[7] = 0x4401fff0;
330 closure->user_data = user_data;
332 /* Flush the icache. */
333 asm volatile ("ocbwb %0,0; synco; icbi %0,0; synci" : : "r" (tramp));
338 /* Basically the trampoline invokes ffi_closure_SYSV, and on
339 * entry, r3 holds the address of the closure.
340 * After storing the registers that could possibly contain
341 * parameters to be passed into the stack frame and setting
342 * up space for a return value, ffi_closure_SYSV invokes the
343 * following helper function to do most of the work.
347 ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue,
348 UINT64 *pgr, UINT64 *pfr, UINT64 *pst)
357 avalue = alloca (cif->nargs * sizeof (void *));
359 /* Copy the caller's structure return value address so that the closure
360 returns the data directly to the caller. */
361 if (return_type (cif->rtype) == FFI_TYPE_STRUCT)
373 /* Grab the addresses of the arguments from the stack frame. */
374 for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
380 if (z < sizeof (UINT32))
384 switch ((*p_arg)->type)
388 case FFI_TYPE_SINT16:
389 case FFI_TYPE_UINT16:
390 case FFI_TYPE_STRUCT:
391 #ifdef __LITTLE_ENDIAN__
394 avalue[i] = ((char *) p) + sizeof (UINT32) - z;
402 else if (z == sizeof (UINT32))
404 if ((*p_arg)->type == FFI_TYPE_FLOAT)
406 if (freg < NFREGARG - 1)
407 #ifdef __LITTLE_ENDIAN__
408 avalue[i] = (UINT32 *) pfr + (1 ^ freg++);
410 avalue[i] = (UINT32 *) pfr + freg++;
413 #ifdef __LITTLE_ENDIAN__
414 avalue[i] = pgr + greg;
416 avalue[i] = (UINT32 *) (pgr + greg) + 1;
420 #ifdef __LITTLE_ENDIAN__
421 avalue[i] = pgr + greg;
423 avalue[i] = (UINT32 *) (pgr + greg) + 1;
427 else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
429 if (freg + 1 >= NFREGARG)
430 avalue[i] = pgr + greg;
433 freg = (freg + 1) & ~1;
434 avalue[i] = pfr + (freg >> 1);
441 int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
443 avalue[i] = pgr + greg;
448 (closure->fun) (cif, rvalue, avalue, closure->user_data);
450 /* Tell ffi_closure_SYSV how to perform return type promotions. */
451 return return_type (cif->rtype);