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 37unsigned 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 */ 100ffi_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 163extern 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 */ 173void 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 210static void ffi_prep_incoming_args_SYSV (char *, void **, void **, 211 ffi_cif*, float *); 212 213void ffi_closure_SYSV (ffi_closure *); 214 215/* Do NOT change that without changing the FFI_TRAMPOLINE_SIZE */ 216extern 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 */ 227void 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 240ffi_status 241ffi_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 */ 268unsigned 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 294static 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