1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2003, 2004, 2006, 2007 Kaz Kojima
4 SuperH SHmedia Foreign Function Interface
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:
14 The above copyright notice and this permission notice shall be included
15 in all copies or substantial portions of the Software.
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 ----------------------------------------------------------------------- */
28 #include <ffi_common.h>
36 return_type (ffi_type
*arg
)
39 if (arg
->type
!= FFI_TYPE_STRUCT
)
42 /* gcc uses r2 if the result can be packed in on register. */
43 if (arg
->size
<= sizeof (UINT8
))
44 return FFI_TYPE_UINT8
;
45 else if (arg
->size
<= sizeof (UINT16
))
46 return FFI_TYPE_UINT16
;
47 else if (arg
->size
<= sizeof (UINT32
))
48 return FFI_TYPE_UINT32
;
49 else if (arg
->size
<= sizeof (UINT64
))
50 return FFI_TYPE_UINT64
;
52 return FFI_TYPE_STRUCT
;
55 /* ffi_prep_args is called by the assembly routine once stack space
56 has been allocated for the function's arguments */
58 void ffi_prep_args(char *stack
, extended_cif
*ecif
)
60 register unsigned int i
;
61 register unsigned int avn
;
62 register void **p_argv
;
64 register ffi_type
**p_arg
;
68 if (return_type (ecif
->cif
->rtype
) == FFI_TYPE_STRUCT
)
70 *(void **) argp
= ecif
->rvalue
;
71 argp
+= sizeof (UINT64
);
74 avn
= ecif
->cif
->nargs
;
75 p_argv
= ecif
->avalue
;
77 for (i
= 0, p_arg
= ecif
->cif
->arg_types
; i
< avn
; i
++, p_arg
++, p_argv
++)
83 align
= (*p_arg
)->alignment
;
84 if (z
< sizeof (UINT32
))
86 switch ((*p_arg
)->type
)
89 *(SINT64
*) argp
= (SINT64
) *(SINT8
*)(*p_argv
);
93 *(UINT64
*) argp
= (UINT64
) *(UINT8
*)(*p_argv
);
97 *(SINT64
*) argp
= (SINT64
) *(SINT16
*)(*p_argv
);
100 case FFI_TYPE_UINT16
:
101 *(UINT64
*) argp
= (UINT64
) *(UINT16
*)(*p_argv
);
104 case FFI_TYPE_STRUCT
:
105 memcpy (argp
, *p_argv
, z
);
111 argp
+= sizeof (UINT64
);
113 else if (z
== sizeof (UINT32
) && align
== sizeof (UINT32
))
115 switch ((*p_arg
)->type
)
118 case FFI_TYPE_SINT32
:
119 *(SINT64
*) argp
= (SINT64
) *(SINT32
*) (*p_argv
);
123 case FFI_TYPE_POINTER
:
124 case FFI_TYPE_UINT32
:
125 case FFI_TYPE_STRUCT
:
126 *(UINT64
*) argp
= (UINT64
) *(UINT32
*) (*p_argv
);
133 argp
+= sizeof (UINT64
);
135 else if (z
== sizeof (UINT64
)
136 && align
== sizeof (UINT64
)
137 && ((int) *p_argv
& (sizeof (UINT64
) - 1)) == 0)
139 *(UINT64
*) argp
= *(UINT64
*) (*p_argv
);
140 argp
+= sizeof (UINT64
);
144 int n
= (z
+ sizeof (UINT64
) - 1) / sizeof (UINT64
);
146 memcpy (argp
, *p_argv
, z
);
147 argp
+= n
* sizeof (UINT64
);
154 /* Perform machine dependent cif processing */
155 ffi_status
ffi_prep_cif_machdep(ffi_cif
*cif
)
164 greg
= (return_type (cif
->rtype
) == FFI_TYPE_STRUCT
? 1 : 0);
168 for (i
= j
= 0; i
< cif
->nargs
; i
++)
170 type
= (cif
->arg_types
)[i
]->type
;
175 cif
->bytes
+= sizeof (UINT64
) - sizeof (float);
176 if (freg
>= NFREGARG
- 1)
185 cif
->flags2
+= ((cif
->arg_types
)[i
]->type
) << (2 * j
++);
188 case FFI_TYPE_DOUBLE
:
189 if (greg
++ >= NGREGARG
&& (freg
+ 1) >= NFREGARG
)
191 if ((freg
+ 1) < NFREGARG
)
194 cif
->flags2
+= ((cif
->arg_types
)[i
]->type
) << (2 * j
++);
197 cif
->flags2
+= FFI_TYPE_INT
<< (2 * j
++);
201 size
= (cif
->arg_types
)[i
]->size
;
202 if (size
< sizeof (UINT64
))
203 cif
->bytes
+= sizeof (UINT64
) - size
;
204 n
= (size
+ sizeof (UINT64
) - 1) / sizeof (UINT64
);
205 if (greg
>= NGREGARG
)
207 else if (greg
+ n
- 1 >= NGREGARG
)
211 for (m
= 0; m
< n
; m
++)
212 cif
->flags2
+= FFI_TYPE_INT
<< (2 * j
++);
217 /* Set the return type flag */
218 switch (cif
->rtype
->type
)
220 case FFI_TYPE_STRUCT
:
221 cif
->flags
= return_type (cif
->rtype
);
226 case FFI_TYPE_DOUBLE
:
227 case FFI_TYPE_SINT64
:
228 case FFI_TYPE_UINT64
:
229 cif
->flags
= cif
->rtype
->type
;
233 cif
->flags
= FFI_TYPE_INT
;
240 extern void ffi_call_SYSV(void (*)(char *, extended_cif
*), extended_cif
*,
241 unsigned, unsigned, long long, unsigned *,
244 void ffi_call(ffi_cif
*cif
, void (*fn
)(), void *rvalue
, void **avalue
)
250 ecif
.avalue
= avalue
;
252 /* If the return value is a struct and we don't have a return */
253 /* value address then we need to make one */
255 if (cif
->rtype
->type
== FFI_TYPE_STRUCT
256 && return_type (cif
->rtype
) != FFI_TYPE_STRUCT
)
257 ecif
.rvalue
= &trvalue
;
258 else if ((rvalue
== NULL
) &&
259 (cif
->rtype
->type
== FFI_TYPE_STRUCT
))
261 ecif
.rvalue
= alloca(cif
->rtype
->size
);
264 ecif
.rvalue
= rvalue
;
269 ffi_call_SYSV(ffi_prep_args
, &ecif
, cif
->bytes
, cif
->flags
, cif
->flags2
,
278 && cif
->rtype
->type
== FFI_TYPE_STRUCT
279 && return_type (cif
->rtype
) != FFI_TYPE_STRUCT
)
280 memcpy (rvalue
, &trvalue
, cif
->rtype
->size
);
283 extern void ffi_closure_SYSV (void);
284 extern void __ic_invalidate (void *line
);
287 ffi_prep_closure_loc (ffi_closure
*closure
,
289 void (*fun
)(ffi_cif
*, void*, void**, void*),
295 FFI_ASSERT (cif
->abi
== FFI_GCC_SYSV
);
297 tramp
= (unsigned int *) &closure
->tramp
[0];
298 /* Since ffi_closure is an aligned object, the ffi trampoline is
299 called as an SHcompact code. Sigh.
301 mova @(1,pc),r0; add #1,r0; jmp @r0; nop;
303 movi fnaddr >> 16,r1; shori fnaddr,r1; ptabs/l r1,tr0
304 movi cxt >> 16,r1; shori cxt,r1; blink tr0,r63 */
305 #ifdef __LITTLE_ENDIAN__
306 tramp
[0] = 0x7001c701;
307 tramp
[1] = 0x0009402b;
309 tramp
[0] = 0xc7017001;
310 tramp
[1] = 0x402b0009;
312 tramp
[2] = 0xcc000010 | (((UINT32
) ffi_closure_SYSV
) >> 16) << 10;
313 tramp
[3] = 0xc8000010 | (((UINT32
) ffi_closure_SYSV
) & 0xffff) << 10;
314 tramp
[4] = 0x6bf10600;
315 tramp
[5] = 0xcc000010 | (((UINT32
) codeloc
) >> 16) << 10;
316 tramp
[6] = 0xc8000010 | (((UINT32
) codeloc
) & 0xffff) << 10;
317 tramp
[7] = 0x4401fff0;
321 closure
->user_data
= user_data
;
323 /* Flush the icache. */
324 asm volatile ("ocbwb %0,0; synco; icbi %1,0; synci" : : "r" (tramp
),
330 /* Basically the trampoline invokes ffi_closure_SYSV, and on
331 * entry, r3 holds the address of the closure.
332 * After storing the registers that could possibly contain
333 * parameters to be passed into the stack frame and setting
334 * up space for a return value, ffi_closure_SYSV invokes the
335 * following helper function to do most of the work.
339 ffi_closure_helper_SYSV (ffi_closure
*closure
, UINT64
*rvalue
,
340 UINT64
*pgr
, UINT64
*pfr
, UINT64
*pst
)
350 avalue
= alloca (cif
->nargs
* sizeof (void *));
352 /* Copy the caller's structure return value address so that the closure
353 returns the data directly to the caller. */
354 if (return_type (cif
->rtype
) == FFI_TYPE_STRUCT
)
356 rvalue
= (UINT64
*) *pgr
;
366 /* Grab the addresses of the arguments from the stack frame. */
367 for (i
= 0, p_arg
= cif
->arg_types
; i
< avn
; i
++, p_arg
++)
373 if (z
< sizeof (UINT32
))
377 switch ((*p_arg
)->type
)
381 case FFI_TYPE_SINT16
:
382 case FFI_TYPE_UINT16
:
383 case FFI_TYPE_STRUCT
:
384 #ifdef __LITTLE_ENDIAN__
387 avalue
[i
] = ((char *) p
) + sizeof (UINT32
) - z
;
395 else if (z
== sizeof (UINT32
))
397 if ((*p_arg
)->type
== FFI_TYPE_FLOAT
)
399 if (freg
< NFREGARG
- 1)
403 avalue
[i
] = (UINT32
*) pfr
+ fpair
;
408 #ifdef __LITTLE_ENDIAN__
410 avalue
[i
] = (UINT32
*) pfr
+ (1 ^ freg
);
413 avalue
[i
] = (UINT32
*) pfr
+ freg
;
419 #ifdef __LITTLE_ENDIAN__
420 avalue
[i
] = pgr
+ greg
;
422 avalue
[i
] = (UINT32
*) (pgr
+ greg
) + 1;
426 #ifdef __LITTLE_ENDIAN__
427 avalue
[i
] = pgr
+ greg
;
429 avalue
[i
] = (UINT32
*) (pgr
+ greg
) + 1;
433 else if ((*p_arg
)->type
== FFI_TYPE_DOUBLE
)
435 if (freg
+ 1 >= NFREGARG
)
436 avalue
[i
] = pgr
+ greg
;
439 avalue
[i
] = pfr
+ (freg
>> 1);
446 int n
= (z
+ sizeof (UINT64
) - 1) / sizeof (UINT64
);
448 avalue
[i
] = pgr
+ greg
;
453 (closure
->fun
) (cif
, rvalue
, avalue
, closure
->user_data
);
455 /* Tell ffi_closure_SYSV how to perform return type promotions. */
456 return return_type (cif
->rtype
);