1 /* ----------------------------------------------------------------------- 2 ffi.c - Copyright (c) 2003, 2004 Kaz Kojima 3 Copyright (c) 2008 Anthony Green 4 5 SuperH SHmedia Foreign Function Interface 6 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: 14 15 The above copyright notice and this permission notice shall be included 16 in all copies or substantial portions of the Software. 17 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 ----------------------------------------------------------------------- */ 27 28 #include <ffi.h> 29 #include <ffi_common.h> 30 31 #include <stdlib.h> 32 33 #define NGREGARG 8 34 #define NFREGARG 12 35 36 static int 37 return_type (ffi_type *arg) 38 { 39 40 if (arg->type != FFI_TYPE_STRUCT) 41 return arg->type; 42 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; 52 53 return FFI_TYPE_STRUCT; 54 } 55 56 /* ffi_prep_args is called by the assembly routine once stack space 57 has been allocated for the function's arguments */ 58 59 /*@-exportheader@*/ 60 void ffi_prep_args(char *stack, extended_cif *ecif) 61 /*@=exportheader@*/ 62 { 63 register unsigned int i; 64 register unsigned int avn; 65 register void **p_argv; 66 register char *argp; 67 register ffi_type **p_arg; 68 69 argp = stack; 70 71 if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT) 72 { 73 *(void **) argp = ecif->rvalue; 74 argp += sizeof (UINT64); 75 } 76 77 avn = ecif->cif->nargs; 78 p_argv = ecif->avalue; 79 80 for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++) 81 { 82 size_t z; 83 int align; 84 85 z = (*p_arg)->size; 86 align = (*p_arg)->alignment; 87 if (z < sizeof (UINT32)) 88 { 89 switch ((*p_arg)->type) 90 { 91 case FFI_TYPE_SINT8: 92 *(SINT64 *) argp = (SINT64) *(SINT8 *)(*p_argv); 93 break; 94 95 case FFI_TYPE_UINT8: 96 *(UINT64 *) argp = (UINT64) *(UINT8 *)(*p_argv); 97 break; 98 99 case FFI_TYPE_SINT16: 100 *(SINT64 *) argp = (SINT64) *(SINT16 *)(*p_argv); 101 break; 102 103 case FFI_TYPE_UINT16: 104 *(UINT64 *) argp = (UINT64) *(UINT16 *)(*p_argv); 105 break; 106 107 case FFI_TYPE_STRUCT: 108 memcpy (argp, *p_argv, z); 109 break; 110 111 default: 112 FFI_ASSERT(0); 113 } 114 argp += sizeof (UINT64); 115 } 116 else if (z == sizeof (UINT32) && align == sizeof (UINT32)) 117 { 118 switch ((*p_arg)->type) 119 { 120 case FFI_TYPE_INT: 121 case FFI_TYPE_SINT32: 122 *(SINT64 *) argp = (SINT64) *(SINT32 *) (*p_argv); 123 break; 124 125 case FFI_TYPE_FLOAT: 126 case FFI_TYPE_POINTER: 127 case FFI_TYPE_UINT32: 128 case FFI_TYPE_STRUCT: 129 *(UINT64 *) argp = (UINT64) *(UINT32 *) (*p_argv); 130 break; 131 132 default: 133 FFI_ASSERT(0); 134 break; 135 } 136 argp += sizeof (UINT64); 137 } 138 else if (z == sizeof (UINT64) 139 && align == sizeof (UINT64) 140 && ((int) *p_argv & (sizeof (UINT64) - 1)) == 0) 141 { 142 *(UINT64 *) argp = *(UINT64 *) (*p_argv); 143 argp += sizeof (UINT64); 144 } 145 else 146 { 147 int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64); 148 149 memcpy (argp, *p_argv, z); 150 argp += n * sizeof (UINT64); 151 } 152 } 153 154 return; 155 } 156 157 /* Perform machine dependent cif processing */ 158 ffi_status ffi_prep_cif_machdep(ffi_cif *cif) 159 { 160 int i, j; 161 int size, type; 162 int n, m; 163 int greg; 164 int freg; 165 166 greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0); 167 freg = 0; 168 cif->flags2 = 0; 169 170 for (i = j = 0; i < cif->nargs; i++) 171 { 172 type = (cif->arg_types)[i]->type; 173 switch (type) 174 { 175 case FFI_TYPE_FLOAT: 176 greg++; 177 cif->bytes += sizeof (UINT64) - sizeof (float); 178 if (freg >= NFREGARG - 1) 179 continue; 180 freg++; 181 cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++); 182 break; 183 184 case FFI_TYPE_DOUBLE: 185 if (greg++ >= NGREGARG && (freg + 1) >= NFREGARG) 186 continue; 187 if ((freg + 1) < NFREGARG) 188 { 189 freg = (freg + 1) & ~1; 190 freg += 2; 191 cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++); 192 } 193 else 194 cif->flags2 += FFI_TYPE_INT << (2 * j++); 195 break; 196 197 default: 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) 203 continue; 204 else if (greg + n - 1 >= NGREGARG) 205 greg = NGREGARG; 206 else 207 greg += n; 208 for (m = 0; m < n; m++) 209 cif->flags2 += FFI_TYPE_INT << (2 * j++); 210 break; 211 } 212 } 213 214 /* Set the return type flag */ 215 switch (cif->rtype->type) 216 { 217 case FFI_TYPE_STRUCT: 218 cif->flags = return_type (cif->rtype); 219 break; 220 221 case FFI_TYPE_VOID: 222 case FFI_TYPE_FLOAT: 223 case FFI_TYPE_DOUBLE: 224 case FFI_TYPE_SINT64: 225 case FFI_TYPE_UINT64: 226 cif->flags = cif->rtype->type; 227 break; 228 229 default: 230 cif->flags = FFI_TYPE_INT; 231 break; 232 } 233 234 return FFI_OK; 235 } 236 237 /*@-declundef@*/ 238 /*@-exportheader@*/ 239 extern void ffi_call_SYSV(void (*)(char *, extended_cif *), 240 /*@out@*/ extended_cif *, 241 unsigned, unsigned, long long, 242 /*@out@*/ unsigned *, 243 void (*fn)(void)); 244 /*@=declundef@*/ 245 /*@=exportheader@*/ 246 247 void ffi_call(/*@dependent@*/ ffi_cif *cif, 248 void (*fn)(void), 249 /*@out@*/ void *rvalue, 250 /*@dependent@*/ void **avalue) 251 { 252 extended_cif ecif; 253 UINT64 trvalue; 254 255 ecif.cif = cif; 256 ecif.avalue = avalue; 257 258 /* If the return value is a struct and we don't have a return */ 259 /* value address then we need to make one */ 260 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)) 266 { 267 /*@-sysunrecog@*/ 268 ecif.rvalue = alloca(cif->rtype->size); 269 /*@=sysunrecog@*/ 270 } 271 else 272 ecif.rvalue = rvalue; 273 274 switch (cif->abi) 275 { 276 case FFI_SYSV: 277 /*@-usedef@*/ 278 ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, 279 cif->flags, cif->flags2, ecif.rvalue, fn); 280 /*@=usedef@*/ 281 break; 282 default: 283 FFI_ASSERT(0); 284 break; 285 } 286 287 if (rvalue 288 && cif->rtype->type == FFI_TYPE_STRUCT 289 && return_type (cif->rtype) != FFI_TYPE_STRUCT) 290 memcpy (rvalue, &trvalue, cif->rtype->size); 291 } 292 293 extern void ffi_closure_SYSV (void); 294 extern void __ic_invalidate (void *line); 295 296 ffi_status 297 ffi_prep_closure (ffi_closure *closure, 298 ffi_cif *cif, 299 void (*fun)(ffi_cif*, void*, void**, void*), 300 void *user_data) 301 { 302 unsigned int *tramp; 303 304 FFI_ASSERT (cif->abi == FFI_GCC_SYSV); 305 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. 309 SHcompact part: 310 mova @(1,pc),r0; add #1,r0; jmp @r0; nop; 311 SHmedia part: 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; 317 #else 318 tramp[0] = 0xc7017001; 319 tramp[1] = 0x402b0009; 320 #endif 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; 327 328 closure->cif = cif; 329 closure->fun = fun; 330 closure->user_data = user_data; 331 332 /* Flush the icache. */ 333 asm volatile ("ocbwb %0,0; synco; icbi %0,0; synci" : : "r" (tramp)); 334 335 return FFI_OK; 336 } 337 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. 344 */ 345 346 int 347 ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue, 348 UINT64 *pgr, UINT64 *pfr, UINT64 *pst) 349 { 350 void **avalue; 351 ffi_type **p_arg; 352 int i, avn; 353 int greg, freg; 354 ffi_cif *cif; 355 356 cif = closure->cif; 357 avalue = alloca (cif->nargs * sizeof (void *)); 358 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) 362 { 363 rvalue = *pgr; 364 greg = 1; 365 } 366 else 367 greg = 0; 368 369 freg = 0; 370 cif = closure->cif; 371 avn = cif->nargs; 372 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++) 375 { 376 size_t z; 377 void *p; 378 379 z = (*p_arg)->size; 380 if (z < sizeof (UINT32)) 381 { 382 p = pgr + greg++; 383 384 switch ((*p_arg)->type) 385 { 386 case FFI_TYPE_SINT8: 387 case FFI_TYPE_UINT8: 388 case FFI_TYPE_SINT16: 389 case FFI_TYPE_UINT16: 390 case FFI_TYPE_STRUCT: 391 #ifdef __LITTLE_ENDIAN__ 392 avalue[i] = p; 393 #else 394 avalue[i] = ((char *) p) + sizeof (UINT32) - z; 395 #endif 396 break; 397 398 default: 399 FFI_ASSERT(0); 400 } 401 } 402 else if (z == sizeof (UINT32)) 403 { 404 if ((*p_arg)->type == FFI_TYPE_FLOAT) 405 { 406 if (freg < NFREGARG - 1) 407 #ifdef __LITTLE_ENDIAN__ 408 avalue[i] = (UINT32 *) pfr + (1 ^ freg++); 409 #else 410 avalue[i] = (UINT32 *) pfr + freg++; 411 #endif 412 else 413 #ifdef __LITTLE_ENDIAN__ 414 avalue[i] = pgr + greg; 415 #else 416 avalue[i] = (UINT32 *) (pgr + greg) + 1; 417 #endif 418 } 419 else 420 #ifdef __LITTLE_ENDIAN__ 421 avalue[i] = pgr + greg; 422 #else 423 avalue[i] = (UINT32 *) (pgr + greg) + 1; 424 #endif 425 greg++; 426 } 427 else if ((*p_arg)->type == FFI_TYPE_DOUBLE) 428 { 429 if (freg + 1 >= NFREGARG) 430 avalue[i] = pgr + greg; 431 else 432 { 433 freg = (freg + 1) & ~1; 434 avalue[i] = pfr + (freg >> 1); 435 freg += 2; 436 } 437 greg++; 438 } 439 else 440 { 441 int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64); 442 443 avalue[i] = pgr + greg; 444 greg += n; 445 } 446 } 447 448 (closure->fun) (cif, rvalue, avalue, closure->user_data); 449 450 /* Tell ffi_closure_SYSV how to perform return type promotions. */ 451 return return_type (cif->rtype); 452 } 453 454