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 *
      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
      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
     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
     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
     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
     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
     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
     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
     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
     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
     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  }