1 /* ----------------------------------------------------------------------- 2 ffi.c - Copyright (c) 1998, 2007, 2008, 2012 Red Hat, Inc. 3 Copyright (c) 2000 Hewlett Packard Company 4 Copyright (c) 2011 Anthony Green 5 6 IA64 Foreign Function Interface 7 8 Permission is hereby granted, free of charge, to any person obtaining 9 a copy of this software and associated documentation files (the 10 ``Software''), to deal in the Software without restriction, including 11 without limitation the rights to use, copy, modify, merge, publish, 12 distribute, sublicense, and/or sell copies of the Software, and to 13 permit persons to whom the Software is furnished to do so, subject to 14 the following conditions: 15 16 The above copyright notice and this permission notice shall be included 17 in all copies or substantial portions of the Software. 18 19 THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 20 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 22 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 23 HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 24 WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 25 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 26 DEALINGS IN THE SOFTWARE. 27 ----------------------------------------------------------------------- */ 28 29 #include <ffi.h> 30 #include <ffi_common.h> 31 32 #include <stdlib.h> 33 #include <stdbool.h> 34 #include <float.h> 35 36 #include "ia64_flags.h" 37 38 /* A 64-bit pointer value. In LP64 mode, this is effectively a plain 39 pointer. In ILP32 mode, it's a pointer that's been extended to 40 64 bits by "addp4". */ 41 typedef void *PTR64 __attribute__((mode(DI))); 42 43 /* Memory image of fp register contents. This is the implementation 44 specific format used by ldf.fill/stf.spill. All we care about is 45 that it wants a 16 byte aligned slot. */ 46 typedef struct 47 { 48 UINT64 x[2] __attribute__((aligned(16))); 49 } fpreg; 50 51 52 /* The stack layout given to ffi_call_unix and ffi_closure_unix_inner. */ 53 54 struct ia64_args 55 { 56 fpreg fp_regs[8]; /* Contents of 8 fp arg registers. */ 57 UINT64 gp_regs[8]; /* Contents of 8 gp arg registers. */ 58 UINT64 other_args[]; /* Arguments passed on stack, variable size. */ 59 }; 60 61 62 /* Adjust ADDR, a pointer to an 8 byte slot, to point to the low LEN bytes. */ 63 64 static inline void * 65 endian_adjust (void *addr, size_t len) 66 { 67 #ifdef __BIG_ENDIAN__ 68 return addr + (8 - len); 69 #else 70 return addr; 71 #endif 72 } 73 74 /* Store VALUE to ADDR in the current cpu implementation's fp spill format. 75 This is a macro instead of a function, so that it works for all 3 floating 76 point types without type conversions. Type conversion to long double breaks 77 the denorm support. */ 78 79 #define stf_spill(addr, value) \ 80 asm ("stf.spill %0 = %1%P0" : "=m" (*addr) : "f"(value)); 81 82 /* Load a value from ADDR, which is in the current cpu implementation's 83 fp spill format. As above, this must also be a macro. */ 84 85 #define ldf_fill(result, addr) \ 86 asm ("ldf.fill %0 = %1%P1" : "=f"(result) : "m"(*addr)); 87 88 /* Return the size of the C type associated with with TYPE. Which will 89 be one of the FFI_IA64_TYPE_HFA_* values. */ 90 91 static size_t 92 hfa_type_size (int type) 93 { 94 switch (type) 95 { 96 case FFI_IA64_TYPE_HFA_FLOAT: 97 return sizeof(float); 98 case FFI_IA64_TYPE_HFA_DOUBLE: 99 return sizeof(double); 100 case FFI_IA64_TYPE_HFA_LDOUBLE: 101 return sizeof(__float80); 102 default: 103 abort (); 104 } 105 } 106 107 /* Load from ADDR a value indicated by TYPE. Which will be one of 108 the FFI_IA64_TYPE_HFA_* values. */ 109 110 static void 111 hfa_type_load (fpreg *fpaddr, int type, void *addr) 112 { 113 switch (type) 114 { 115 case FFI_IA64_TYPE_HFA_FLOAT: 116 stf_spill (fpaddr, *(float *) addr); 117 return; 118 case FFI_IA64_TYPE_HFA_DOUBLE: 119 stf_spill (fpaddr, *(double *) addr); 120 return; 121 case FFI_IA64_TYPE_HFA_LDOUBLE: 122 stf_spill (fpaddr, *(__float80 *) addr); 123 return; 124 default: 125 abort (); 126 } 127 } 128 129 /* Load VALUE into ADDR as indicated by TYPE. Which will be one of 130 the FFI_IA64_TYPE_HFA_* values. */ 131 132 static void 133 hfa_type_store (int type, void *addr, fpreg *fpaddr) 134 { 135 switch (type) 136 { 137 case FFI_IA64_TYPE_HFA_FLOAT: 138 { 139 float result; 140 ldf_fill (result, fpaddr); 141 *(float *) addr = result; 142 break; 143 } 144 case FFI_IA64_TYPE_HFA_DOUBLE: 145 { 146 double result; 147 ldf_fill (result, fpaddr); 148 *(double *) addr = result; 149 break; 150 } 151 case FFI_IA64_TYPE_HFA_LDOUBLE: 152 { 153 __float80 result; 154 ldf_fill (result, fpaddr); 155 *(__float80 *) addr = result; 156 break; 157 } 158 default: 159 abort (); 160 } 161 } 162 163 /* Is TYPE a struct containing floats, doubles, or extended doubles, 164 all of the same fp type? If so, return the element type. Return 165 FFI_TYPE_VOID if not. */ 166 167 static int 168 hfa_element_type (ffi_type *type, int nested) 169 { 170 int element = FFI_TYPE_VOID; 171 172 switch (type->type) 173 { 174 case FFI_TYPE_FLOAT: 175 /* We want to return VOID for raw floating-point types, but the 176 synthetic HFA type if we're nested within an aggregate. */ 177 if (nested) 178 element = FFI_IA64_TYPE_HFA_FLOAT; 179 break; 180 181 case FFI_TYPE_DOUBLE: 182 /* Similarly. */ 183 if (nested) 184 element = FFI_IA64_TYPE_HFA_DOUBLE; 185 break; 186 187 case FFI_TYPE_LONGDOUBLE: 188 /* Similarly, except that that HFA is true for double extended, 189 but not quad precision. Both have sizeof == 16, so tell the 190 difference based on the precision. */ 191 if (LDBL_MANT_DIG == 64 && nested) 192 element = FFI_IA64_TYPE_HFA_LDOUBLE; 193 break; 194 195 case FFI_TYPE_STRUCT: 196 { 197 ffi_type **ptr = &type->elements[0]; 198 199 for (ptr = &type->elements[0]; *ptr ; ptr++) 200 { 201 int sub_element = hfa_element_type (*ptr, 1); 202 if (sub_element == FFI_TYPE_VOID) 203 return FFI_TYPE_VOID; 204 205 if (element == FFI_TYPE_VOID) 206 element = sub_element; 207 else if (element != sub_element) 208 return FFI_TYPE_VOID; 209 } 210 } 211 break; 212 213 default: 214 return FFI_TYPE_VOID; 215 } 216 217 return element; 218 } 219 220 221 /* Perform machine dependent cif processing. */ 222 223 ffi_status 224 ffi_prep_cif_machdep(ffi_cif *cif) 225 { 226 int flags; 227 228 /* Adjust cif->bytes to include space for the bits of the ia64_args frame 229 that precedes the integer register portion. The estimate that the 230 generic bits did for the argument space required is good enough for the 231 integer component. */ 232 cif->bytes += offsetof(struct ia64_args, gp_regs[0]); 233 if (cif->bytes < sizeof(struct ia64_args)) 234 cif->bytes = sizeof(struct ia64_args); 235 236 /* Set the return type flag. */ 237 flags = cif->rtype->type; 238 switch (cif->rtype->type) 239 { 240 case FFI_TYPE_LONGDOUBLE: 241 /* Leave FFI_TYPE_LONGDOUBLE as meaning double extended precision, 242 and encode quad precision as a two-word integer structure. */ 243 if (LDBL_MANT_DIG != 64) 244 flags = FFI_IA64_TYPE_SMALL_STRUCT | (16 << 8); 245 break; 246 247 case FFI_TYPE_STRUCT: 248 { 249 size_t size = cif->rtype->size; 250 int hfa_type = hfa_element_type (cif->rtype, 0); 251 252 if (hfa_type != FFI_TYPE_VOID) 253 { 254 size_t nelts = size / hfa_type_size (hfa_type); 255 if (nelts <= 8) 256 flags = hfa_type | (size << 8); 257 } 258 else 259 { 260 if (size <= 32) 261 flags = FFI_IA64_TYPE_SMALL_STRUCT | (size << 8); 262 } 263 } 264 break; 265 266 default: 267 break; 268 } 269 cif->flags = flags; 270 271 return FFI_OK; 272 } 273 274 extern int ffi_call_unix (struct ia64_args *, PTR64, void (*)(void), UINT64); 275 276 void 277 ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) 278 { 279 struct ia64_args *stack; 280 long i, avn, gpcount, fpcount; 281 ffi_type **p_arg; 282 283 FFI_ASSERT (cif->abi == FFI_UNIX); 284 285 /* If we have no spot for a return value, make one. */ 286 if (rvalue == NULL && cif->rtype->type != FFI_TYPE_VOID) 287 rvalue = alloca (cif->rtype->size); 288 289 /* Allocate the stack frame. */ 290 stack = alloca (cif->bytes); 291 292 gpcount = fpcount = 0; 293 avn = cif->nargs; 294 for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++) 295 { 296 switch ((*p_arg)->type) 297 { 298 case FFI_TYPE_SINT8: 299 stack->gp_regs[gpcount++] = *(SINT8 *)avalue[i]; 300 break; 301 case FFI_TYPE_UINT8: 302 stack->gp_regs[gpcount++] = *(UINT8 *)avalue[i]; 303 break; 304 case FFI_TYPE_SINT16: 305 stack->gp_regs[gpcount++] = *(SINT16 *)avalue[i]; 306 break; 307 case FFI_TYPE_UINT16: 308 stack->gp_regs[gpcount++] = *(UINT16 *)avalue[i]; 309 break; 310 case FFI_TYPE_SINT32: 311 stack->gp_regs[gpcount++] = *(SINT32 *)avalue[i]; 312 break; 313 case FFI_TYPE_UINT32: 314 stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i]; 315 break; 316 case FFI_TYPE_SINT64: 317 case FFI_TYPE_UINT64: 318 stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i]; 319 break; 320 321 case FFI_TYPE_POINTER: 322 stack->gp_regs[gpcount++] = (UINT64)(PTR64) *(void **)avalue[i]; 323 break; 324 325 case FFI_TYPE_FLOAT: 326 if (gpcount < 8 && fpcount < 8) 327 stf_spill (&stack->fp_regs[fpcount++], *(float *)avalue[i]); 328 { 329 UINT32 tmp; 330 memcpy (&tmp, avalue[i], sizeof (UINT32)); 331 stack->gp_regs[gpcount++] = tmp; 332 } 333 break; 334 335 case FFI_TYPE_DOUBLE: 336 if (gpcount < 8 && fpcount < 8) 337 stf_spill (&stack->fp_regs[fpcount++], *(double *)avalue[i]); 338 memcpy (&stack->gp_regs[gpcount++], avalue[i], sizeof (UINT64)); 339 break; 340 341 case FFI_TYPE_LONGDOUBLE: 342 if (gpcount & 1) 343 gpcount++; 344 if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8) 345 stf_spill (&stack->fp_regs[fpcount++], *(__float80 *)avalue[i]); 346 memcpy (&stack->gp_regs[gpcount], avalue[i], 16); 347 gpcount += 2; 348 break; 349 350 case FFI_TYPE_STRUCT: 351 { 352 size_t size = (*p_arg)->size; 353 size_t align = (*p_arg)->alignment; 354 int hfa_type = hfa_element_type (*p_arg, 0); 355 356 FFI_ASSERT (align <= 16); 357 if (align == 16 && (gpcount & 1)) 358 gpcount++; 359 360 if (hfa_type != FFI_TYPE_VOID) 361 { 362 size_t hfa_size = hfa_type_size (hfa_type); 363 size_t offset = 0; 364 size_t gp_offset = gpcount * 8; 365 366 while (fpcount < 8 367 && offset < size 368 && gp_offset < 8 * 8) 369 { 370 hfa_type_load (&stack->fp_regs[fpcount], hfa_type, 371 avalue[i] + offset); 372 offset += hfa_size; 373 gp_offset += hfa_size; 374 fpcount += 1; 375 } 376 } 377 378 memcpy (&stack->gp_regs[gpcount], avalue[i], size); 379 gpcount += (size + 7) / 8; 380 } 381 break; 382 383 default: 384 abort (); 385 } 386 } 387 388 ffi_call_unix (stack, rvalue, fn, cif->flags); 389 } 390 391 /* Closures represent a pair consisting of a function pointer, and 392 some user data. A closure is invoked by reinterpreting the closure 393 as a function pointer, and branching to it. Thus we can make an 394 interpreted function callable as a C function: We turn the 395 interpreter itself, together with a pointer specifying the 396 interpreted procedure, into a closure. 397 398 For IA64, function pointer are already pairs consisting of a code 399 pointer, and a gp pointer. The latter is needed to access global 400 variables. Here we set up such a pair as the first two words of 401 the closure (in the "trampoline" area), but we replace the gp 402 pointer with a pointer to the closure itself. We also add the real 403 gp pointer to the closure. This allows the function entry code to 404 both retrieve the user data, and to restore the correct gp pointer. */ 405 406 extern void ffi_closure_unix (); 407 408 ffi_status 409 ffi_prep_closure_loc (ffi_closure* closure, 410 ffi_cif* cif, 411 void (*fun)(ffi_cif*,void*,void**,void*), 412 void *user_data, 413 void *codeloc) 414 { 415 /* The layout of a function descriptor. A C function pointer really 416 points to one of these. */ 417 struct ia64_fd 418 { 419 UINT64 code_pointer; 420 UINT64 gp; 421 }; 422 423 struct ffi_ia64_trampoline_struct 424 { 425 UINT64 code_pointer; /* Pointer to ffi_closure_unix. */ 426 UINT64 fake_gp; /* Pointer to closure, installed as gp. */ 427 UINT64 real_gp; /* Real gp value. */ 428 }; 429 430 struct ffi_ia64_trampoline_struct *tramp; 431 struct ia64_fd *fd; 432 433 if (cif->abi != FFI_UNIX) 434 return FFI_BAD_ABI; 435 436 tramp = (struct ffi_ia64_trampoline_struct *)closure->tramp; 437 fd = (struct ia64_fd *)(void *)ffi_closure_unix; 438 439 tramp->code_pointer = fd->code_pointer; 440 tramp->real_gp = fd->gp; 441 tramp->fake_gp = (UINT64)(PTR64)codeloc; 442 closure->cif = cif; 443 closure->user_data = user_data; 444 closure->fun = fun; 445 446 return FFI_OK; 447 } 448 449 450 UINT64 451 ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack, 452 void *rvalue, void *r8) 453 { 454 ffi_cif *cif; 455 void **avalue; 456 ffi_type **p_arg; 457 long i, avn, gpcount, fpcount; 458 459 cif = closure->cif; 460 avn = cif->nargs; 461 avalue = alloca (avn * sizeof (void *)); 462 463 /* If the structure return value is passed in memory get that location 464 from r8 so as to pass the value directly back to the caller. */ 465 if (cif->flags == FFI_TYPE_STRUCT) 466 rvalue = r8; 467 468 gpcount = fpcount = 0; 469 for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++) 470 { 471 switch ((*p_arg)->type) 472 { 473 case FFI_TYPE_SINT8: 474 case FFI_TYPE_UINT8: 475 avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 1); 476 break; 477 case FFI_TYPE_SINT16: 478 case FFI_TYPE_UINT16: 479 avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 2); 480 break; 481 case FFI_TYPE_SINT32: 482 case FFI_TYPE_UINT32: 483 avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 4); 484 break; 485 case FFI_TYPE_SINT64: 486 case FFI_TYPE_UINT64: 487 avalue[i] = &stack->gp_regs[gpcount++]; 488 break; 489 case FFI_TYPE_POINTER: 490 avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], sizeof(void*)); 491 break; 492 493 case FFI_TYPE_FLOAT: 494 if (gpcount < 8 && fpcount < 8) 495 { 496 fpreg *addr = &stack->fp_regs[fpcount++]; 497 float result; 498 avalue[i] = addr; 499 ldf_fill (result, addr); 500 *(float *)addr = result; 501 } 502 else 503 avalue[i] = endian_adjust(&stack->gp_regs[gpcount], 4); 504 gpcount++; 505 break; 506 507 case FFI_TYPE_DOUBLE: 508 if (gpcount < 8 && fpcount < 8) 509 { 510 fpreg *addr = &stack->fp_regs[fpcount++]; 511 double result; 512 avalue[i] = addr; 513 ldf_fill (result, addr); 514 *(double *)addr = result; 515 } 516 else 517 avalue[i] = &stack->gp_regs[gpcount]; 518 gpcount++; 519 break; 520 521 case FFI_TYPE_LONGDOUBLE: 522 if (gpcount & 1) 523 gpcount++; 524 if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8) 525 { 526 fpreg *addr = &stack->fp_regs[fpcount++]; 527 __float80 result; 528 avalue[i] = addr; 529 ldf_fill (result, addr); 530 *(__float80 *)addr = result; 531 } 532 else 533 avalue[i] = &stack->gp_regs[gpcount]; 534 gpcount += 2; 535 break; 536 537 case FFI_TYPE_STRUCT: 538 { 539 size_t size = (*p_arg)->size; 540 size_t align = (*p_arg)->alignment; 541 int hfa_type = hfa_element_type (*p_arg, 0); 542 543 FFI_ASSERT (align <= 16); 544 if (align == 16 && (gpcount & 1)) 545 gpcount++; 546 547 if (hfa_type != FFI_TYPE_VOID) 548 { 549 size_t hfa_size = hfa_type_size (hfa_type); 550 size_t offset = 0; 551 size_t gp_offset = gpcount * 8; 552 void *addr = alloca (size); 553 554 avalue[i] = addr; 555 556 while (fpcount < 8 557 && offset < size 558 && gp_offset < 8 * 8) 559 { 560 hfa_type_store (hfa_type, addr + offset, 561 &stack->fp_regs[fpcount]); 562 offset += hfa_size; 563 gp_offset += hfa_size; 564 fpcount += 1; 565 } 566 567 if (offset < size) 568 memcpy (addr + offset, (char *)stack->gp_regs + gp_offset, 569 size - offset); 570 } 571 else 572 avalue[i] = &stack->gp_regs[gpcount]; 573 574 gpcount += (size + 7) / 8; 575 } 576 break; 577 578 default: 579 abort (); 580 } 581 } 582 583 closure->fun (cif, rvalue, avalue, closure->user_data); 584 585 return cif->flags; 586 } 587