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