• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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