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".  */
41typedef 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.  */
46typedef 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
54struct 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
64static inline void *
65endian_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
91static size_t
92hfa_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
110static void
111hfa_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
132static void
133hfa_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
167static int
168hfa_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
223ffi_status
224ffi_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
274extern int ffi_call_unix (struct ia64_args *, PTR64, void (*)(void), UINT64);
275
276void
277ffi_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
406extern void ffi_closure_unix ();
407
408ffi_status
409ffi_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
450UINT64
451ffi_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