1 /* ----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2013 Imagination Technologies
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:
13 The above copyright notice and this permission notice shall be included
14 in all copies or substantial portions of the Software.
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 ----------------------------------------------------------------------- */
26 #include <ffi_common.h>
30 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
33 * ffi_prep_args is called by the assembly routine once stack space has been
34 * allocated for the function's arguments
37 unsigned int ffi_prep_args(char *stack
, extended_cif
*ecif
)
39 register unsigned int i
;
40 register void **p_argv
;
42 register ffi_type
**p_arg
;
46 /* Store return value */
47 if ( ecif
->cif
->flags
== FFI_TYPE_STRUCT
) {
49 *(void **) argp
= ecif
->rvalue
;
52 p_argv
= ecif
->avalue
;
54 /* point to next location */
55 for (i
= ecif
->cif
->nargs
, p_arg
= ecif
->cif
->arg_types
; (i
!= 0); i
--, p_arg
++, p_argv
++)
59 /* Move argp to address of argument */
63 /* Align if necessary */
64 argp
= (char *) FFI_ALIGN_DOWN(FFI_ALIGN_DOWN(argp
, (*p_arg
)->alignment
), 4);
66 if (z
< sizeof(int)) {
68 switch ((*p_arg
)->type
)
71 *(signed int *) argp
= (signed int)*(SINT8
*)(* p_argv
);
74 *(unsigned int *) argp
= (unsigned int)*(UINT8
*)(* p_argv
);
77 *(signed int *) argp
= (signed int)*(SINT16
*)(* p_argv
);
80 *(unsigned int *) argp
= (unsigned int)*(UINT16
*)(* p_argv
);
82 memcpy(argp
, *p_argv
, (*p_arg
)->size
);
87 } else if ( z
== sizeof(int)) {
88 *(unsigned int *) argp
= (unsigned int)*(UINT32
*)(* p_argv
);
90 memcpy(argp
, *p_argv
, z
);
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 FFI_ALIGN(MIN(stack
- argp
, 6*4), 8);
99 /* Perform machine dependent cif processing */
100 ffi_status
ffi_prep_cif_machdep(ffi_cif
*cif
)
103 unsigned i
, bytes
= 0;
105 for (ptr
= cif
->arg_types
, i
= cif
->nargs
; i
> 0; i
--, ptr
++) {
106 if ((*ptr
)->size
== 0)
107 return FFI_BAD_TYPEDEF
;
109 /* Perform a sanity check on the argument type, do this
110 check after the initialization. */
111 FFI_ASSERT_VALID_TYPE(*ptr
);
113 /* Add any padding if necessary */
114 if (((*ptr
)->alignment
- 1) & bytes
)
115 bytes
= FFI_ALIGN(bytes
, (*ptr
)->alignment
);
117 bytes
+= FFI_ALIGN((*ptr
)->size
, 4);
120 /* Ensure arg space is aligned to an 8-byte boundary */
121 bytes
= FFI_ALIGN(bytes
, 8);
123 /* Make space for the return structure pointer */
124 if (cif
->rtype
->type
== FFI_TYPE_STRUCT
) {
125 bytes
+= sizeof(void*);
127 /* Ensure stack is aligned to an 8-byte boundary */
128 bytes
= FFI_ALIGN(bytes
, 8);
133 /* Set the return type flag */
134 switch (cif
->rtype
->type
) {
137 case FFI_TYPE_DOUBLE
:
138 cif
->flags
= (unsigned) cif
->rtype
->type
;
140 case FFI_TYPE_SINT64
:
141 case FFI_TYPE_UINT64
:
142 cif
->flags
= (unsigned) FFI_TYPE_SINT64
;
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
;
153 /* value stored in memory */
154 cif
->flags
= (unsigned)FFI_TYPE_STRUCT
;
157 cif
->flags
= (unsigned)FFI_TYPE_INT
;
163 extern void ffi_call_SYSV(void (*fn
)(void), extended_cif
*, unsigned, unsigned, double *);
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
173 void ffi_call(ffi_cif
*cif
, void (*fn
)(void), void *rvalue
, void **avalue
)
177 int small_struct
= (((cif
->flags
== FFI_TYPE_INT
) || (cif
->flags
== FFI_TYPE_DOUBLE
)) && (cif
->rtype
->type
== FFI_TYPE_STRUCT
));
179 ecif
.avalue
= avalue
;
184 * If the return value is a struct and we don't have a return value address
185 * then we need to make one
188 if ((rvalue
== NULL
) && (cif
->flags
== FFI_TYPE_STRUCT
))
189 ecif
.rvalue
= alloca(cif
->rtype
->size
);
190 else if (small_struct
)
193 ecif
.rvalue
= rvalue
;
197 ffi_call_SYSV(fn
, &ecif
, cif
->bytes
, cif
->flags
, ecif
.rvalue
);
205 memcpy (rvalue
, &temp
, cif
->rtype
->size
);
208 /* private members */
210 static void ffi_prep_incoming_args_SYSV (char *, void **, void **,
213 void ffi_closure_SYSV (ffi_closure
*);
215 /* Do NOT change that without changing the FFI_TRAMPOLINE_SIZE */
216 extern unsigned int ffi_metag_trampoline
[10]; /* 10 instructions */
218 /* end of private members */
221 * __tramp: trampoline memory location
222 * __fun: assembly routine
223 * __ctx: memory location for wrapper
225 * At this point, tramp[0] == __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);
238 /* the cif must already be prepared */
241 ffi_prep_closure_loc (ffi_closure
*closure
,
243 void (*fun
)(ffi_cif
*,void*,void**,void*),
247 void (*closure_func
)(ffi_closure
*) = NULL
;
249 if (cif
->abi
== FFI_SYSV
)
250 closure_func
= &ffi_closure_SYSV
;
255 (unsigned char*)&closure
->tramp
[0],
256 (unsigned int)closure_func
,
257 (unsigned int)codeloc
);
260 closure
->user_data
= user_data
;
267 /* This function is jumped to by the trampoline */
268 unsigned int ffi_closure_SYSV_inner (closure
, respp
, args
, vfp_args
)
269 ffi_closure
*closure
;
278 arg_area
= (void**) alloca (cif
->nargs
* sizeof (void*));
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.
287 ffi_prep_incoming_args_SYSV(args
, respp
, arg_area
, cif
, vfp_args
);
289 (closure
->fun
) ( cif
, *respp
, arg_area
, closure
->user_data
);
294 static void ffi_prep_incoming_args_SYSV(char *stack
, void **rvalue
,
295 void **avalue
, ffi_cif
*cif
,
298 register unsigned int i
;
299 register void **p_argv
;
301 register ffi_type
**p_arg
;
303 /* stack points to original arguments */
306 /* Store return value */
307 if ( cif
->flags
== FFI_TYPE_STRUCT
) {
309 *rvalue
= *(void **) argp
;
314 for (i
= cif
->nargs
, p_arg
= cif
->arg_types
; (i
!= 0); i
--, p_arg
++) {
318 alignment
= (*p_arg
)->alignment
;
321 if ((alignment
- 1) & (unsigned)argp
)
322 argp
= (char *) FFI_ALIGN(argp
, alignment
);
325 *p_argv
= (void*) argp
;