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 *
endian_adjust(void * addr,size_t len)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
hfa_type_size(int type)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
hfa_type_load(fpreg * fpaddr,int type,void * addr)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
hfa_type_store(int type,void * addr,fpreg * fpaddr)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
hfa_element_type(ffi_type * type,int nested)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 static ffi_status
ffi_prep_cif_machdep_core(ffi_cif * cif)224 ffi_prep_cif_machdep_core(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 ffi_status
ffi_prep_cif_machdep(ffi_cif * cif)275 ffi_prep_cif_machdep(ffi_cif *cif)
276 {
277 cif->nfixedargs = cif->nargs;
278 return ffi_prep_cif_machdep_core(cif);
279 }
280
281 ffi_status
ffi_prep_cif_machdep_var(ffi_cif * cif,unsigned int nfixedargs,unsigned int ntotalargs MAYBE_UNUSED)282 ffi_prep_cif_machdep_var(ffi_cif *cif,
283 unsigned int nfixedargs,
284 unsigned int ntotalargs MAYBE_UNUSED)
285 {
286 cif->nfixedargs = nfixedargs;
287 return ffi_prep_cif_machdep_core(cif);
288 }
289
290 extern int ffi_call_unix (struct ia64_args *, PTR64, void (*)(void), UINT64);
291
292 void
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)293 ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
294 {
295 struct ia64_args *stack;
296 long i, avn, gpcount, fpcount;
297 ffi_type **p_arg;
298
299 FFI_ASSERT (cif->abi == FFI_UNIX);
300
301 /* If we have no spot for a return value, make one. */
302 if (rvalue == NULL && cif->rtype->type != FFI_TYPE_VOID)
303 rvalue = alloca (cif->rtype->size);
304
305 /* Allocate the stack frame. */
306 stack = alloca (cif->bytes);
307
308 gpcount = fpcount = 0;
309 avn = cif->nargs;
310 for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
311 {
312 switch ((*p_arg)->type)
313 {
314 case FFI_TYPE_SINT8:
315 stack->gp_regs[gpcount++] = *(SINT8 *)avalue[i];
316 break;
317 case FFI_TYPE_UINT8:
318 stack->gp_regs[gpcount++] = *(UINT8 *)avalue[i];
319 break;
320 case FFI_TYPE_SINT16:
321 stack->gp_regs[gpcount++] = *(SINT16 *)avalue[i];
322 break;
323 case FFI_TYPE_UINT16:
324 stack->gp_regs[gpcount++] = *(UINT16 *)avalue[i];
325 break;
326 case FFI_TYPE_SINT32:
327 stack->gp_regs[gpcount++] = *(SINT32 *)avalue[i];
328 break;
329 case FFI_TYPE_UINT32:
330 stack->gp_regs[gpcount++] = *(UINT32 *)avalue[i];
331 break;
332 case FFI_TYPE_SINT64:
333 case FFI_TYPE_UINT64:
334 stack->gp_regs[gpcount++] = *(UINT64 *)avalue[i];
335 break;
336
337 case FFI_TYPE_POINTER:
338 stack->gp_regs[gpcount++] = (UINT64)(PTR64) *(void **)avalue[i];
339 break;
340
341 case FFI_TYPE_FLOAT:
342 if (gpcount < 8 && fpcount < 8)
343 stf_spill (&stack->fp_regs[fpcount++], *(float *)avalue[i]);
344 {
345 UINT32 tmp;
346 memcpy (&tmp, avalue[i], sizeof (UINT32));
347 stack->gp_regs[gpcount++] = tmp;
348 }
349 break;
350
351 case FFI_TYPE_DOUBLE:
352 if (gpcount < 8 && fpcount < 8)
353 stf_spill (&stack->fp_regs[fpcount++], *(double *)avalue[i]);
354 memcpy (&stack->gp_regs[gpcount++], avalue[i], sizeof (UINT64));
355 break;
356
357 case FFI_TYPE_LONGDOUBLE:
358 if (gpcount & 1)
359 gpcount++;
360 if (LDBL_MANT_DIG == 64 && gpcount < 8 && fpcount < 8)
361 stf_spill (&stack->fp_regs[fpcount++], *(__float80 *)avalue[i]);
362 memcpy (&stack->gp_regs[gpcount], avalue[i], 16);
363 gpcount += 2;
364 break;
365
366 case FFI_TYPE_STRUCT:
367 {
368 size_t size = (*p_arg)->size;
369 size_t align = (*p_arg)->alignment;
370 int hfa_type = hfa_element_type (*p_arg, 0);
371
372 FFI_ASSERT (align <= 16);
373 if (align == 16 && (gpcount & 1))
374 gpcount++;
375
376 if (hfa_type != FFI_TYPE_VOID)
377 {
378 size_t hfa_size = hfa_type_size (hfa_type);
379 size_t offset = 0;
380 size_t gp_offset = gpcount * 8;
381
382 while (fpcount < 8
383 && offset < size
384 && gp_offset < 8 * 8)
385 {
386 hfa_type_load (&stack->fp_regs[fpcount], hfa_type,
387 avalue[i] + offset);
388 offset += hfa_size;
389 gp_offset += hfa_size;
390 fpcount += 1;
391 }
392 }
393
394 memcpy (&stack->gp_regs[gpcount], avalue[i], size);
395 gpcount += (size + 7) / 8;
396 }
397 break;
398
399 default:
400 abort ();
401 }
402 }
403
404 ffi_call_unix (stack, rvalue, fn, cif->flags);
405 }
406
407 /* Closures represent a pair consisting of a function pointer, and
408 some user data. A closure is invoked by reinterpreting the closure
409 as a function pointer, and branching to it. Thus we can make an
410 interpreted function callable as a C function: We turn the
411 interpreter itself, together with a pointer specifying the
412 interpreted procedure, into a closure.
413
414 For IA64, function pointer are already pairs consisting of a code
415 pointer, and a gp pointer. The latter is needed to access global
416 variables. Here we set up such a pair as the first two words of
417 the closure (in the "trampoline" area), but we replace the gp
418 pointer with a pointer to the closure itself. We also add the real
419 gp pointer to the closure. This allows the function entry code to
420 both retrieve the user data, and to restore the correct gp pointer. */
421
422 extern void ffi_closure_unix ();
423
424 ffi_status
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)425 ffi_prep_closure_loc (ffi_closure* closure,
426 ffi_cif* cif,
427 void (*fun)(ffi_cif*,void*,void**,void*),
428 void *user_data,
429 void *codeloc)
430 {
431 /* The layout of a function descriptor. A C function pointer really
432 points to one of these. */
433 struct ia64_fd
434 {
435 UINT64 code_pointer;
436 UINT64 gp;
437 };
438
439 struct ffi_ia64_trampoline_struct
440 {
441 UINT64 code_pointer; /* Pointer to ffi_closure_unix. */
442 UINT64 fake_gp; /* Pointer to closure, installed as gp. */
443 UINT64 real_gp; /* Real gp value. */
444 };
445
446 struct ffi_ia64_trampoline_struct *tramp;
447 struct ia64_fd *fd;
448
449 if (cif->abi != FFI_UNIX)
450 return FFI_BAD_ABI;
451
452 tramp = (struct ffi_ia64_trampoline_struct *)closure->tramp;
453 fd = (struct ia64_fd *)(void *)ffi_closure_unix;
454
455 tramp->code_pointer = fd->code_pointer;
456 tramp->real_gp = fd->gp;
457 tramp->fake_gp = (UINT64)(PTR64)codeloc;
458 closure->cif = cif;
459 closure->user_data = user_data;
460 closure->fun = fun;
461
462 return FFI_OK;
463 }
464
465
466 UINT64
ffi_closure_unix_inner(ffi_closure * closure,struct ia64_args * stack,void * rvalue,void * r8)467 ffi_closure_unix_inner (ffi_closure *closure, struct ia64_args *stack,
468 void *rvalue, void *r8)
469 {
470 ffi_cif *cif;
471 void **avalue;
472 ffi_type **p_arg;
473 long i, avn, gpcount, fpcount, nfixedargs;
474
475 cif = closure->cif;
476 avn = cif->nargs;
477 nfixedargs = cif->nfixedargs;
478 avalue = alloca (avn * sizeof (void *));
479
480 /* If the structure return value is passed in memory get that location
481 from r8 so as to pass the value directly back to the caller. */
482 if (cif->flags == FFI_TYPE_STRUCT)
483 rvalue = r8;
484
485 gpcount = fpcount = 0;
486 for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
487 {
488 int named = i < nfixedargs;
489 switch ((*p_arg)->type)
490 {
491 case FFI_TYPE_SINT8:
492 case FFI_TYPE_UINT8:
493 avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 1);
494 break;
495 case FFI_TYPE_SINT16:
496 case FFI_TYPE_UINT16:
497 avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 2);
498 break;
499 case FFI_TYPE_SINT32:
500 case FFI_TYPE_UINT32:
501 avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], 4);
502 break;
503 case FFI_TYPE_SINT64:
504 case FFI_TYPE_UINT64:
505 avalue[i] = &stack->gp_regs[gpcount++];
506 break;
507 case FFI_TYPE_POINTER:
508 avalue[i] = endian_adjust(&stack->gp_regs[gpcount++], sizeof(void*));
509 break;
510
511 case FFI_TYPE_FLOAT:
512 if (named && gpcount < 8 && fpcount < 8)
513 {
514 fpreg *addr = &stack->fp_regs[fpcount++];
515 float result;
516 avalue[i] = addr;
517 ldf_fill (result, addr);
518 *(float *)addr = result;
519 }
520 else
521 avalue[i] = endian_adjust(&stack->gp_regs[gpcount], 4);
522 gpcount++;
523 break;
524
525 case FFI_TYPE_DOUBLE:
526 if (named && gpcount < 8 && fpcount < 8)
527 {
528 fpreg *addr = &stack->fp_regs[fpcount++];
529 double result;
530 avalue[i] = addr;
531 ldf_fill (result, addr);
532 *(double *)addr = result;
533 }
534 else
535 avalue[i] = &stack->gp_regs[gpcount];
536 gpcount++;
537 break;
538
539 case FFI_TYPE_LONGDOUBLE:
540 if (gpcount & 1)
541 gpcount++;
542 if (LDBL_MANT_DIG == 64 && named && gpcount < 8 && fpcount < 8)
543 {
544 fpreg *addr = &stack->fp_regs[fpcount++];
545 __float80 result;
546 avalue[i] = addr;
547 ldf_fill (result, addr);
548 *(__float80 *)addr = result;
549 }
550 else
551 avalue[i] = &stack->gp_regs[gpcount];
552 gpcount += 2;
553 break;
554
555 case FFI_TYPE_STRUCT:
556 {
557 size_t size = (*p_arg)->size;
558 size_t align = (*p_arg)->alignment;
559 int hfa_type = hfa_element_type (*p_arg, 0);
560
561 FFI_ASSERT (align <= 16);
562 if (align == 16 && (gpcount & 1))
563 gpcount++;
564
565 if (hfa_type != FFI_TYPE_VOID)
566 {
567 size_t hfa_size = hfa_type_size (hfa_type);
568 size_t offset = 0;
569 size_t gp_offset = gpcount * 8;
570 void *addr = alloca (size);
571
572 avalue[i] = addr;
573
574 while (fpcount < 8
575 && offset < size
576 && gp_offset < 8 * 8)
577 {
578 hfa_type_store (hfa_type, addr + offset,
579 &stack->fp_regs[fpcount]);
580 offset += hfa_size;
581 gp_offset += hfa_size;
582 fpcount += 1;
583 }
584
585 if (offset < size)
586 memcpy (addr + offset, (char *)stack->gp_regs + gp_offset,
587 size - offset);
588 }
589 else
590 avalue[i] = &stack->gp_regs[gpcount];
591
592 gpcount += (size + 7) / 8;
593 }
594 break;
595
596 default:
597 abort ();
598 }
599 }
600
601 closure->fun (cif, rvalue, avalue, closure->user_data);
602
603 return cif->flags;
604 }
605