1/* -----------------------------------------------------------------------
2   ffi_linux64.c - Copyright (C) 2013 IBM
3                   Copyright (C) 2011 Anthony Green
4                   Copyright (C) 2011 Kyle Moffett
5                   Copyright (C) 2008 Red Hat, Inc
6                   Copyright (C) 2007, 2008 Free Software Foundation, Inc
7                   Copyright (c) 1998 Geoffrey Keating
8
9   PowerPC Foreign Function Interface
10
11   Permission is hereby granted, free of charge, to any person obtaining
12   a copy of this software and associated documentation files (the
13   ``Software''), to deal in the Software without restriction, including
14   without limitation the rights to use, copy, modify, merge, publish,
15   distribute, sublicense, and/or sell copies of the Software, and to
16   permit persons to whom the Software is furnished to do so, subject to
17   the following conditions:
18
19   The above copyright notice and this permission notice shall be included
20   in all copies or substantial portions of the Software.
21
22   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
23   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25   IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
26   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
27   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28   OTHER DEALINGS IN THE SOFTWARE.
29   ----------------------------------------------------------------------- */
30
31#include "ffi.h"
32
33#ifdef POWERPC64
34#include "ffi_common.h"
35#include "ffi_powerpc.h"
36
37
38/* About the LINUX64 ABI.  */
39enum {
40  NUM_GPR_ARG_REGISTERS64 = 8,
41  NUM_FPR_ARG_REGISTERS64 = 13
42};
43enum { ASM_NEEDS_REGISTERS64 = 4 };
44
45
46#if HAVE_LONG_DOUBLE_VARIANT && FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
47/* Adjust size of ffi_type_longdouble.  */
48void FFI_HIDDEN
49ffi_prep_types_linux64 (ffi_abi abi)
50{
51  if ((abi & (FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128)) == FFI_LINUX)
52    {
53      ffi_type_longdouble.size = 8;
54      ffi_type_longdouble.alignment = 8;
55    }
56  else
57    {
58      ffi_type_longdouble.size = 16;
59      ffi_type_longdouble.alignment = 16;
60    }
61}
62#endif
63
64
65#if _CALL_ELF == 2
66static unsigned int
67discover_homogeneous_aggregate (const ffi_type *t, unsigned int *elnum)
68{
69  switch (t->type)
70    {
71    case FFI_TYPE_FLOAT:
72    case FFI_TYPE_DOUBLE:
73      *elnum = 1;
74      return (int) t->type;
75
76    case FFI_TYPE_STRUCT:;
77      {
78	unsigned int base_elt = 0, total_elnum = 0;
79	ffi_type **el = t->elements;
80	while (*el)
81	  {
82	    unsigned int el_elt, el_elnum = 0;
83	    el_elt = discover_homogeneous_aggregate (*el, &el_elnum);
84	    if (el_elt == 0
85		|| (base_elt && base_elt != el_elt))
86	      return 0;
87	    base_elt = el_elt;
88	    total_elnum += el_elnum;
89	    if (total_elnum > 8)
90	      return 0;
91	    el++;
92	  }
93	*elnum = total_elnum;
94	return base_elt;
95      }
96
97    default:
98      return 0;
99    }
100}
101#endif
102
103
104/* Perform machine dependent cif processing */
105static ffi_status
106ffi_prep_cif_linux64_core (ffi_cif *cif)
107{
108  ffi_type **ptr;
109  unsigned bytes;
110  unsigned i, fparg_count = 0, intarg_count = 0;
111  unsigned flags = cif->flags;
112#if _CALL_ELF == 2
113  unsigned int elt, elnum;
114#endif
115
116#if FFI_TYPE_LONGDOUBLE == FFI_TYPE_DOUBLE
117  /* If compiled without long double support..  */
118  if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
119    return FFI_BAD_ABI;
120#endif
121
122  /* The machine-independent calculation of cif->bytes doesn't work
123     for us.  Redo the calculation.  */
124#if _CALL_ELF == 2
125  /* Space for backchain, CR, LR, TOC and the asm's temp regs.  */
126  bytes = (4 + ASM_NEEDS_REGISTERS64) * sizeof (long);
127
128  /* Space for the general registers.  */
129  bytes += NUM_GPR_ARG_REGISTERS64 * sizeof (long);
130#else
131  /* Space for backchain, CR, LR, cc/ld doubleword, TOC and the asm's temp
132     regs.  */
133  bytes = (6 + ASM_NEEDS_REGISTERS64) * sizeof (long);
134
135  /* Space for the mandatory parm save area and general registers.  */
136  bytes += 2 * NUM_GPR_ARG_REGISTERS64 * sizeof (long);
137#endif
138
139  /* Return value handling.  */
140  switch (cif->rtype->type)
141    {
142#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
143    case FFI_TYPE_LONGDOUBLE:
144      if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
145	flags |= FLAG_RETURNS_128BITS;
146      /* Fall through.  */
147#endif
148    case FFI_TYPE_DOUBLE:
149      flags |= FLAG_RETURNS_64BITS;
150      /* Fall through.  */
151    case FFI_TYPE_FLOAT:
152      flags |= FLAG_RETURNS_FP;
153      break;
154
155    case FFI_TYPE_UINT128:
156      flags |= FLAG_RETURNS_128BITS;
157      /* Fall through.  */
158    case FFI_TYPE_UINT64:
159    case FFI_TYPE_SINT64:
160      flags |= FLAG_RETURNS_64BITS;
161      break;
162
163    case FFI_TYPE_STRUCT:
164#if _CALL_ELF == 2
165      elt = discover_homogeneous_aggregate (cif->rtype, &elnum);
166      if (elt)
167	{
168	  if (elt == FFI_TYPE_DOUBLE)
169	    flags |= FLAG_RETURNS_64BITS;
170	  flags |= FLAG_RETURNS_FP | FLAG_RETURNS_SMST;
171	  break;
172	}
173      if (cif->rtype->size <= 16)
174	{
175	  flags |= FLAG_RETURNS_SMST;
176	  break;
177	}
178#endif
179      intarg_count++;
180      flags |= FLAG_RETVAL_REFERENCE;
181      /* Fall through.  */
182    case FFI_TYPE_VOID:
183      flags |= FLAG_RETURNS_NOTHING;
184      break;
185
186    default:
187      /* Returns 32-bit integer, or similar.  Nothing to do here.  */
188      break;
189    }
190
191  for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
192    {
193      unsigned int align;
194
195      switch ((*ptr)->type)
196	{
197#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
198	case FFI_TYPE_LONGDOUBLE:
199	  if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
200	    {
201	      fparg_count++;
202	      intarg_count++;
203	    }
204	  /* Fall through.  */
205#endif
206	case FFI_TYPE_DOUBLE:
207	case FFI_TYPE_FLOAT:
208	  fparg_count++;
209	  intarg_count++;
210	  if (fparg_count > NUM_FPR_ARG_REGISTERS64)
211	    flags |= FLAG_ARG_NEEDS_PSAVE;
212	  break;
213
214	case FFI_TYPE_STRUCT:
215	  if ((cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0)
216	    {
217	      align = (*ptr)->alignment;
218	      if (align > 16)
219		align = 16;
220	      align = align / 8;
221	      if (align > 1)
222		intarg_count = ALIGN (intarg_count, align);
223	    }
224	  intarg_count += ((*ptr)->size + 7) / 8;
225#if _CALL_ELF == 2
226	  elt = discover_homogeneous_aggregate (*ptr, &elnum);
227	  if (elt)
228	    {
229	      fparg_count += elnum;
230	      if (fparg_count > NUM_FPR_ARG_REGISTERS64)
231		flags |= FLAG_ARG_NEEDS_PSAVE;
232	    }
233	  else
234#endif
235	    {
236	      if (intarg_count > NUM_GPR_ARG_REGISTERS64)
237		flags |= FLAG_ARG_NEEDS_PSAVE;
238	    }
239	  break;
240
241	case FFI_TYPE_POINTER:
242	case FFI_TYPE_UINT64:
243	case FFI_TYPE_SINT64:
244	case FFI_TYPE_INT:
245	case FFI_TYPE_UINT32:
246	case FFI_TYPE_SINT32:
247	case FFI_TYPE_UINT16:
248	case FFI_TYPE_SINT16:
249	case FFI_TYPE_UINT8:
250	case FFI_TYPE_SINT8:
251	  /* Everything else is passed as a 8-byte word in a GPR, either
252	     the object itself or a pointer to it.  */
253	  intarg_count++;
254	  if (intarg_count > NUM_GPR_ARG_REGISTERS64)
255	    flags |= FLAG_ARG_NEEDS_PSAVE;
256	  break;
257	default:
258	  FFI_ASSERT (0);
259	}
260    }
261
262  if (fparg_count != 0)
263    flags |= FLAG_FP_ARGUMENTS;
264  if (intarg_count > 4)
265    flags |= FLAG_4_GPR_ARGUMENTS;
266
267  /* Space for the FPR registers, if needed.  */
268  if (fparg_count != 0)
269    bytes += NUM_FPR_ARG_REGISTERS64 * sizeof (double);
270
271  /* Stack space.  */
272#if _CALL_ELF == 2
273  if ((flags & FLAG_ARG_NEEDS_PSAVE) != 0)
274    bytes += intarg_count * sizeof (long);
275#else
276  if (intarg_count > NUM_GPR_ARG_REGISTERS64)
277    bytes += (intarg_count - NUM_GPR_ARG_REGISTERS64) * sizeof (long);
278#endif
279
280  /* The stack space allocated needs to be a multiple of 16 bytes.  */
281  bytes = (bytes + 15) & ~0xF;
282
283  cif->flags = flags;
284  cif->bytes = bytes;
285
286  return FFI_OK;
287}
288
289ffi_status FFI_HIDDEN
290ffi_prep_cif_linux64 (ffi_cif *cif)
291{
292  if ((cif->abi & FFI_LINUX) != 0)
293    cif->nfixedargs = cif->nargs;
294#if _CALL_ELF != 2
295  else if (cif->abi == FFI_COMPAT_LINUX64)
296    {
297      /* This call is from old code.  Don't touch cif->nfixedargs
298	 since old code will be using a smaller cif.  */
299      cif->flags |= FLAG_COMPAT;
300      /* Translate to new abi value.  */
301      cif->abi = FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128;
302    }
303#endif
304  else
305    return FFI_BAD_ABI;
306  return ffi_prep_cif_linux64_core (cif);
307}
308
309ffi_status FFI_HIDDEN
310ffi_prep_cif_linux64_var (ffi_cif *cif,
311			  unsigned int nfixedargs,
312			  unsigned int ntotalargs MAYBE_UNUSED)
313{
314  if ((cif->abi & FFI_LINUX) != 0)
315    cif->nfixedargs = nfixedargs;
316#if _CALL_ELF != 2
317  else if (cif->abi == FFI_COMPAT_LINUX64)
318    {
319      /* This call is from old code.  Don't touch cif->nfixedargs
320	 since old code will be using a smaller cif.  */
321      cif->flags |= FLAG_COMPAT;
322      /* Translate to new abi value.  */
323      cif->abi = FFI_LINUX | FFI_LINUX_LONG_DOUBLE_128;
324    }
325#endif
326  else
327    return FFI_BAD_ABI;
328#if _CALL_ELF == 2
329  cif->flags |= FLAG_ARG_NEEDS_PSAVE;
330#endif
331  return ffi_prep_cif_linux64_core (cif);
332}
333
334
335/* ffi_prep_args64 is called by the assembly routine once stack space
336   has been allocated for the function's arguments.
337
338   The stack layout we want looks like this:
339
340   |   Ret addr from ffi_call_LINUX64	8bytes	|	higher addresses
341   |--------------------------------------------|
342   |   CR save area			8bytes	|
343   |--------------------------------------------|
344   |   Previous backchain pointer	8	|	stack pointer here
345   |--------------------------------------------|<+ <<<	on entry to
346   |   Saved r28-r31			4*8	| |	ffi_call_LINUX64
347   |--------------------------------------------| |
348   |   GPR registers r3-r10		8*8	| |
349   |--------------------------------------------| |
350   |   FPR registers f1-f13 (optional)	13*8	| |
351   |--------------------------------------------| |
352   |   Parameter save area		        | |
353   |--------------------------------------------| |
354   |   TOC save area			8	| |
355   |--------------------------------------------| |	stack	|
356   |   Linker doubleword		8	| |	grows	|
357   |--------------------------------------------| |	down	V
358   |   Compiler doubleword		8	| |
359   |--------------------------------------------| |	lower addresses
360   |   Space for callee's LR		8	| |
361   |--------------------------------------------| |
362   |   CR save area			8	| |
363   |--------------------------------------------| |	stack pointer here
364   |   Current backchain pointer	8	|-/	during
365   |--------------------------------------------|   <<<	ffi_call_LINUX64
366
367*/
368
369void FFI_HIDDEN
370ffi_prep_args64 (extended_cif *ecif, unsigned long *const stack)
371{
372  const unsigned long bytes = ecif->cif->bytes;
373  const unsigned long flags = ecif->cif->flags;
374
375  typedef union
376  {
377    char *c;
378    unsigned long *ul;
379    float *f;
380    double *d;
381    size_t p;
382  } valp;
383
384  /* 'stacktop' points at the previous backchain pointer.  */
385  valp stacktop;
386
387  /* 'next_arg' points at the space for gpr3, and grows upwards as
388     we use GPR registers, then continues at rest.  */
389  valp gpr_base;
390  valp gpr_end;
391  valp rest;
392  valp next_arg;
393
394  /* 'fpr_base' points at the space for fpr3, and grows upwards as
395     we use FPR registers.  */
396  valp fpr_base;
397  unsigned int fparg_count;
398
399  unsigned int i, words, nargs, nfixedargs;
400  ffi_type **ptr;
401  double double_tmp;
402  union
403  {
404    void **v;
405    char **c;
406    signed char **sc;
407    unsigned char **uc;
408    signed short **ss;
409    unsigned short **us;
410    signed int **si;
411    unsigned int **ui;
412    unsigned long **ul;
413    float **f;
414    double **d;
415  } p_argv;
416  unsigned long gprvalue;
417  unsigned long align;
418
419  stacktop.c = (char *) stack + bytes;
420  gpr_base.ul = stacktop.ul - ASM_NEEDS_REGISTERS64 - NUM_GPR_ARG_REGISTERS64;
421  gpr_end.ul = gpr_base.ul + NUM_GPR_ARG_REGISTERS64;
422#if _CALL_ELF == 2
423  rest.ul = stack + 4 + NUM_GPR_ARG_REGISTERS64;
424#else
425  rest.ul = stack + 6 + NUM_GPR_ARG_REGISTERS64;
426#endif
427  fpr_base.d = gpr_base.d - NUM_FPR_ARG_REGISTERS64;
428  fparg_count = 0;
429  next_arg.ul = gpr_base.ul;
430
431  /* Check that everything starts aligned properly.  */
432  FFI_ASSERT (((unsigned long) (char *) stack & 0xF) == 0);
433  FFI_ASSERT (((unsigned long) stacktop.c & 0xF) == 0);
434  FFI_ASSERT ((bytes & 0xF) == 0);
435
436  /* Deal with return values that are actually pass-by-reference.  */
437  if (flags & FLAG_RETVAL_REFERENCE)
438    *next_arg.ul++ = (unsigned long) (char *) ecif->rvalue;
439
440  /* Now for the arguments.  */
441  p_argv.v = ecif->avalue;
442  nargs = ecif->cif->nargs;
443#if _CALL_ELF != 2
444  nfixedargs = (unsigned) -1;
445  if ((flags & FLAG_COMPAT) == 0)
446#endif
447    nfixedargs = ecif->cif->nfixedargs;
448  for (ptr = ecif->cif->arg_types, i = 0;
449       i < nargs;
450       i++, ptr++, p_argv.v++)
451    {
452#if _CALL_ELF == 2
453      unsigned int elt, elnum;
454#endif
455
456      switch ((*ptr)->type)
457	{
458#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
459	case FFI_TYPE_LONGDOUBLE:
460	  if ((ecif->cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
461	    {
462	      double_tmp = (*p_argv.d)[0];
463	      if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
464		{
465		  *fpr_base.d++ = double_tmp;
466# if _CALL_ELF != 2
467		  if ((flags & FLAG_COMPAT) != 0)
468		    *next_arg.d = double_tmp;
469# endif
470		}
471	      else
472		*next_arg.d = double_tmp;
473	      if (++next_arg.ul == gpr_end.ul)
474		next_arg.ul = rest.ul;
475	      fparg_count++;
476	      double_tmp = (*p_argv.d)[1];
477	      if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
478		{
479		  *fpr_base.d++ = double_tmp;
480# if _CALL_ELF != 2
481		  if ((flags & FLAG_COMPAT) != 0)
482		    *next_arg.d = double_tmp;
483# endif
484		}
485	      else
486		*next_arg.d = double_tmp;
487	      if (++next_arg.ul == gpr_end.ul)
488		next_arg.ul = rest.ul;
489	      fparg_count++;
490	      FFI_ASSERT (__LDBL_MANT_DIG__ == 106);
491	      FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
492	      break;
493	    }
494	  /* Fall through.  */
495#endif
496	case FFI_TYPE_DOUBLE:
497	  double_tmp = **p_argv.d;
498	  if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
499	    {
500	      *fpr_base.d++ = double_tmp;
501#if _CALL_ELF != 2
502	      if ((flags & FLAG_COMPAT) != 0)
503		*next_arg.d = double_tmp;
504#endif
505	    }
506	  else
507	    *next_arg.d = double_tmp;
508	  if (++next_arg.ul == gpr_end.ul)
509	    next_arg.ul = rest.ul;
510	  fparg_count++;
511	  FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
512	  break;
513
514	case FFI_TYPE_FLOAT:
515	  double_tmp = **p_argv.f;
516	  if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
517	    {
518	      *fpr_base.d++ = double_tmp;
519#if _CALL_ELF != 2
520	      if ((flags & FLAG_COMPAT) != 0)
521		*next_arg.f = (float) double_tmp;
522#endif
523	    }
524	  else
525	    *next_arg.f = (float) double_tmp;
526	  if (++next_arg.ul == gpr_end.ul)
527	    next_arg.ul = rest.ul;
528	  fparg_count++;
529	  FFI_ASSERT (flags & FLAG_FP_ARGUMENTS);
530	  break;
531
532	case FFI_TYPE_STRUCT:
533	  if ((ecif->cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0)
534	    {
535	      align = (*ptr)->alignment;
536	      if (align > 16)
537		align = 16;
538	      if (align > 1)
539		next_arg.p = ALIGN (next_arg.p, align);
540	    }
541#if _CALL_ELF == 2
542	  elt = discover_homogeneous_aggregate (*ptr, &elnum);
543	  if (elt)
544	    {
545	      union {
546		void *v;
547		float *f;
548		double *d;
549	      } arg;
550
551	      arg.v = *p_argv.v;
552	      if (elt == FFI_TYPE_FLOAT)
553		{
554		  do
555		    {
556		      double_tmp = *arg.f++;
557		      if (fparg_count < NUM_FPR_ARG_REGISTERS64
558			  && i < nfixedargs)
559			*fpr_base.d++ = double_tmp;
560		      else
561			*next_arg.f = (float) double_tmp;
562		      if (++next_arg.f == gpr_end.f)
563			next_arg.f = rest.f;
564		      fparg_count++;
565		    }
566		  while (--elnum != 0);
567		  if ((next_arg.p & 3) != 0)
568		    {
569		      if (++next_arg.f == gpr_end.f)
570			next_arg.f = rest.f;
571		    }
572		}
573	      else
574		do
575		  {
576		    double_tmp = *arg.d++;
577		    if (fparg_count < NUM_FPR_ARG_REGISTERS64 && i < nfixedargs)
578		      *fpr_base.d++ = double_tmp;
579		    else
580		      *next_arg.d = double_tmp;
581		    if (++next_arg.d == gpr_end.d)
582		      next_arg.d = rest.d;
583		    fparg_count++;
584		  }
585		while (--elnum != 0);
586	    }
587	  else
588#endif
589	    {
590	      words = ((*ptr)->size + 7) / 8;
591	      if (next_arg.ul >= gpr_base.ul && next_arg.ul + words > gpr_end.ul)
592		{
593		  size_t first = gpr_end.c - next_arg.c;
594		  memcpy (next_arg.c, *p_argv.c, first);
595		  memcpy (rest.c, *p_argv.c + first, (*ptr)->size - first);
596		  next_arg.c = rest.c + words * 8 - first;
597		}
598	      else
599		{
600		  char *where = next_arg.c;
601
602#ifndef __LITTLE_ENDIAN__
603		  /* Structures with size less than eight bytes are passed
604		     left-padded.  */
605		  if ((*ptr)->size < 8)
606		    where += 8 - (*ptr)->size;
607#endif
608		  memcpy (where, *p_argv.c, (*ptr)->size);
609		  next_arg.ul += words;
610		  if (next_arg.ul == gpr_end.ul)
611		    next_arg.ul = rest.ul;
612		}
613	    }
614	  break;
615
616	case FFI_TYPE_UINT8:
617	  gprvalue = **p_argv.uc;
618	  goto putgpr;
619	case FFI_TYPE_SINT8:
620	  gprvalue = **p_argv.sc;
621	  goto putgpr;
622	case FFI_TYPE_UINT16:
623	  gprvalue = **p_argv.us;
624	  goto putgpr;
625	case FFI_TYPE_SINT16:
626	  gprvalue = **p_argv.ss;
627	  goto putgpr;
628	case FFI_TYPE_UINT32:
629	  gprvalue = **p_argv.ui;
630	  goto putgpr;
631	case FFI_TYPE_INT:
632	case FFI_TYPE_SINT32:
633	  gprvalue = **p_argv.si;
634	  goto putgpr;
635
636	case FFI_TYPE_UINT64:
637	case FFI_TYPE_SINT64:
638	case FFI_TYPE_POINTER:
639	  gprvalue = **p_argv.ul;
640	putgpr:
641	  *next_arg.ul++ = gprvalue;
642	  if (next_arg.ul == gpr_end.ul)
643	    next_arg.ul = rest.ul;
644	  break;
645	}
646    }
647
648  FFI_ASSERT (flags & FLAG_4_GPR_ARGUMENTS
649	      || (next_arg.ul >= gpr_base.ul
650		  && next_arg.ul <= gpr_base.ul + 4));
651}
652
653
654#if _CALL_ELF == 2
655#define MIN_CACHE_LINE_SIZE 8
656
657static void
658flush_icache (char *wraddr, char *xaddr, int size)
659{
660  int i;
661  for (i = 0; i < size; i += MIN_CACHE_LINE_SIZE)
662    __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;"
663		      : : "r" (xaddr + i), "r" (wraddr + i) : "memory");
664  __asm__ volatile ("icbi 0,%0;" "dcbf 0,%1;" "sync;" "isync;"
665		    : : "r"(xaddr + size - 1), "r"(wraddr + size - 1)
666		    : "memory");
667}
668#endif
669
670ffi_status
671ffi_prep_closure_loc_linux64 (ffi_closure *closure,
672			      ffi_cif *cif,
673			      void (*fun) (ffi_cif *, void *, void **, void *),
674			      void *user_data,
675			      void *codeloc)
676{
677#if _CALL_ELF == 2
678  unsigned int *tramp = (unsigned int *) &closure->tramp[0];
679
680  if (cif->abi < FFI_LINUX || cif->abi >= FFI_LAST_ABI)
681    return FFI_BAD_ABI;
682
683  tramp[0] = 0xe96c0018;	/* 0:	ld	11,2f-0b(12)	*/
684  tramp[1] = 0xe98c0010;	/*	ld	12,1f-0b(12)	*/
685  tramp[2] = 0x7d8903a6;	/*	mtctr	12		*/
686  tramp[3] = 0x4e800420;	/*	bctr			*/
687				/* 1:	.quad	function_addr	*/
688				/* 2:	.quad	context		*/
689  *(void **) &tramp[4] = (void *) ffi_closure_LINUX64;
690  *(void **) &tramp[6] = codeloc;
691  flush_icache ((char *)tramp, (char *)codeloc, FFI_TRAMPOLINE_SIZE);
692#else
693  void **tramp = (void **) &closure->tramp[0];
694
695  if (cif->abi < FFI_LINUX || cif->abi >= FFI_LAST_ABI)
696    return FFI_BAD_ABI;
697
698  /* Copy function address and TOC from ffi_closure_LINUX64.  */
699  memcpy (tramp, (char *) ffi_closure_LINUX64, 16);
700  tramp[2] = tramp[1];
701  tramp[1] = codeloc;
702#endif
703
704  closure->cif = cif;
705  closure->fun = fun;
706  closure->user_data = user_data;
707
708  return FFI_OK;
709}
710
711
712int FFI_HIDDEN
713ffi_closure_helper_LINUX64 (ffi_closure *closure, void *rvalue,
714			    unsigned long *pst, ffi_dblfl *pfr)
715{
716  /* rvalue is the pointer to space for return value in closure assembly */
717  /* pst is the pointer to parameter save area
718     (r3-r10 are stored into its first 8 slots by ffi_closure_LINUX64) */
719  /* pfr is the pointer to where f1-f13 are stored in ffi_closure_LINUX64 */
720
721  void **avalue;
722  ffi_type **arg_types;
723  unsigned long i, avn, nfixedargs;
724  ffi_cif *cif;
725  ffi_dblfl *end_pfr = pfr + NUM_FPR_ARG_REGISTERS64;
726  unsigned long align;
727
728  cif = closure->cif;
729  avalue = alloca (cif->nargs * sizeof (void *));
730
731  /* Copy the caller's structure return value address so that the
732     closure returns the data directly to the caller.  */
733  if (cif->rtype->type == FFI_TYPE_STRUCT
734      && (cif->flags & FLAG_RETURNS_SMST) == 0)
735    {
736      rvalue = (void *) *pst;
737      pst++;
738    }
739
740  i = 0;
741  avn = cif->nargs;
742#if _CALL_ELF != 2
743  nfixedargs = (unsigned) -1;
744  if ((cif->flags & FLAG_COMPAT) == 0)
745#endif
746    nfixedargs = cif->nfixedargs;
747  arg_types = cif->arg_types;
748
749  /* Grab the addresses of the arguments from the stack frame.  */
750  while (i < avn)
751    {
752      unsigned int elt, elnum;
753
754      switch (arg_types[i]->type)
755	{
756	case FFI_TYPE_SINT8:
757	case FFI_TYPE_UINT8:
758#ifndef __LITTLE_ENDIAN__
759	  avalue[i] = (char *) pst + 7;
760	  pst++;
761	  break;
762#endif
763
764	case FFI_TYPE_SINT16:
765	case FFI_TYPE_UINT16:
766#ifndef __LITTLE_ENDIAN__
767	  avalue[i] = (char *) pst + 6;
768	  pst++;
769	  break;
770#endif
771
772	case FFI_TYPE_SINT32:
773	case FFI_TYPE_UINT32:
774#ifndef __LITTLE_ENDIAN__
775	  avalue[i] = (char *) pst + 4;
776	  pst++;
777	  break;
778#endif
779
780	case FFI_TYPE_SINT64:
781	case FFI_TYPE_UINT64:
782	case FFI_TYPE_POINTER:
783	  avalue[i] = pst;
784	  pst++;
785	  break;
786
787	case FFI_TYPE_STRUCT:
788	  if ((cif->abi & FFI_LINUX_STRUCT_ALIGN) != 0)
789	    {
790	      align = arg_types[i]->alignment;
791	      if (align > 16)
792		align = 16;
793	      if (align > 1)
794		pst = (unsigned long *) ALIGN ((size_t) pst, align);
795	    }
796	  elt = 0;
797#if _CALL_ELF == 2
798	  elt = discover_homogeneous_aggregate (arg_types[i], &elnum);
799#endif
800	  if (elt)
801	    {
802	      union {
803		void *v;
804		unsigned long *ul;
805		float *f;
806		double *d;
807		size_t p;
808	      } to, from;
809
810	      /* Repackage the aggregate from its parts.  The
811		 aggregate size is not greater than the space taken by
812		 the registers so store back to the register/parameter
813		 save arrays.  */
814	      if (pfr + elnum <= end_pfr)
815		to.v = pfr;
816	      else
817		to.v = pst;
818
819	      avalue[i] = to.v;
820	      from.ul = pst;
821	      if (elt == FFI_TYPE_FLOAT)
822		{
823		  do
824		    {
825		      if (pfr < end_pfr && i < nfixedargs)
826			{
827			  *to.f = (float) pfr->d;
828			  pfr++;
829			}
830		      else
831			*to.f = *from.f;
832		      to.f++;
833		      from.f++;
834		    }
835		  while (--elnum != 0);
836		}
837	      else
838		{
839		  do
840		    {
841		      if (pfr < end_pfr && i < nfixedargs)
842			{
843			  *to.d = pfr->d;
844			  pfr++;
845			}
846		      else
847			*to.d = *from.d;
848		      to.d++;
849		      from.d++;
850		    }
851		  while (--elnum != 0);
852		}
853	    }
854	  else
855	    {
856#ifndef __LITTLE_ENDIAN__
857	      /* Structures with size less than eight bytes are passed
858		 left-padded.  */
859	      if (arg_types[i]->size < 8)
860		avalue[i] = (char *) pst + 8 - arg_types[i]->size;
861	      else
862#endif
863		avalue[i] = pst;
864	    }
865	  pst += (arg_types[i]->size + 7) / 8;
866	  break;
867
868#if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
869	case FFI_TYPE_LONGDOUBLE:
870	  if ((cif->abi & FFI_LINUX_LONG_DOUBLE_128) != 0)
871	    {
872	      if (pfr + 1 < end_pfr && i + 1 < nfixedargs)
873		{
874		  avalue[i] = pfr;
875		  pfr += 2;
876		}
877	      else
878		{
879		  if (pfr < end_pfr && i < nfixedargs)
880		    {
881		      /* Passed partly in f13 and partly on the stack.
882			 Move it all to the stack.  */
883		      *pst = *(unsigned long *) pfr;
884		      pfr++;
885		    }
886		  avalue[i] = pst;
887		}
888	      pst += 2;
889	      break;
890	    }
891	  /* Fall through.  */
892#endif
893	case FFI_TYPE_DOUBLE:
894	  /* On the outgoing stack all values are aligned to 8 */
895	  /* there are 13 64bit floating point registers */
896
897	  if (pfr < end_pfr && i < nfixedargs)
898	    {
899	      avalue[i] = pfr;
900	      pfr++;
901	    }
902	  else
903	    avalue[i] = pst;
904	  pst++;
905	  break;
906
907	case FFI_TYPE_FLOAT:
908	  if (pfr < end_pfr && i < nfixedargs)
909	    {
910	      /* Float values are stored as doubles in the
911		 ffi_closure_LINUX64 code.  Fix them here.  */
912	      pfr->f = (float) pfr->d;
913	      avalue[i] = pfr;
914	      pfr++;
915	    }
916	  else
917	    avalue[i] = pst;
918	  pst++;
919	  break;
920
921	default:
922	  FFI_ASSERT (0);
923	}
924
925      i++;
926    }
927
928
929  (closure->fun) (cif, rvalue, avalue, closure->user_data);
930
931  /* Tell ffi_closure_LINUX64 how to perform return type promotions.  */
932  if ((cif->flags & FLAG_RETURNS_SMST) != 0)
933    {
934      if ((cif->flags & FLAG_RETURNS_FP) == 0)
935	return FFI_V2_TYPE_SMALL_STRUCT + cif->rtype->size - 1;
936      else if ((cif->flags & FLAG_RETURNS_64BITS) != 0)
937	return FFI_V2_TYPE_DOUBLE_HOMOG;
938      else
939	return FFI_V2_TYPE_FLOAT_HOMOG;
940    }
941  return cif->rtype->type;
942}
943#endif
944