Home | History | Annotate | Download | only in cris
      1 /* -----------------------------------------------------------------------
      2    ffi.c - Copyright (c) 1998 Cygnus Solutions
      3            Copyright (c) 2004 Simon Posnjak
      4 	   Copyright (c) 2005 Axis Communications AB
      5 	   Copyright (C) 2007 Free Software Foundation, Inc.
      6 
      7    CRIS Foreign Function Interface
      8 
      9    Permission is hereby granted, free of charge, to any person obtaining
     10    a copy of this software and associated documentation files (the
     11    ``Software''), to deal in the Software without restriction, including
     12    without limitation the rights to use, copy, modify, merge, publish,
     13    distribute, sublicense, and/or sell copies of the Software, and to
     14    permit persons to whom the Software is furnished to do so, subject to
     15    the following conditions:
     16 
     17    The above copyright notice and this permission notice shall be included
     18    in all copies or substantial portions of the Software.
     19 
     20    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
     21    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     22    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     23    IN NO EVENT SHALL SIMON POSNJAK BE LIABLE FOR ANY CLAIM, DAMAGES OR
     24    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     25    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     26    OTHER DEALINGS IN THE SOFTWARE.
     27    ----------------------------------------------------------------------- */
     28 
     29 #include <ffi.h>
     30 #include <ffi_common.h>
     31 
     32 #define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
     33 
     34 static ffi_status
     35 initialize_aggregate_packed_struct (ffi_type * arg)
     36 {
     37   ffi_type **ptr;
     38 
     39   FFI_ASSERT (arg != NULL);
     40 
     41   FFI_ASSERT (arg->elements != NULL);
     42   FFI_ASSERT (arg->size == 0);
     43   FFI_ASSERT (arg->alignment == 0);
     44 
     45   ptr = &(arg->elements[0]);
     46 
     47   while ((*ptr) != NULL)
     48     {
     49       if (((*ptr)->size == 0)
     50 	  && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
     51 	return FFI_BAD_TYPEDEF;
     52 
     53       FFI_ASSERT (ffi_type_test ((*ptr)));
     54 
     55       arg->size += (*ptr)->size;
     56 
     57       arg->alignment = (arg->alignment > (*ptr)->alignment) ?
     58 	arg->alignment : (*ptr)->alignment;
     59 
     60       ptr++;
     61     }
     62 
     63   if (arg->size == 0)
     64     return FFI_BAD_TYPEDEF;
     65   else
     66     return FFI_OK;
     67 }
     68 
     69 int
     70 ffi_prep_args (char *stack, extended_cif * ecif)
     71 {
     72   unsigned int i;
     73   unsigned int struct_count = 0;
     74   void **p_argv;
     75   char *argp;
     76   ffi_type **p_arg;
     77 
     78   argp = stack;
     79 
     80   p_argv = ecif->avalue;
     81 
     82   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
     83        (i != 0); i--, p_arg++)
     84     {
     85       size_t z;
     86 
     87       switch ((*p_arg)->type)
     88 	{
     89 	case FFI_TYPE_STRUCT:
     90 	  {
     91 	    z = (*p_arg)->size;
     92 	    if (z <= 4)
     93 	      {
     94 		memcpy (argp, *p_argv, z);
     95 		z = 4;
     96 	      }
     97 	    else if (z <= 8)
     98 	      {
     99 		memcpy (argp, *p_argv, z);
    100 		z = 8;
    101 	      }
    102 	    else
    103 	      {
    104 		unsigned int uiLocOnStack;
    105 		z = sizeof (void *);
    106 		uiLocOnStack = 4 * ecif->cif->nargs + struct_count;
    107 		struct_count = struct_count + (*p_arg)->size;
    108 		*(unsigned int *) argp =
    109 		  (unsigned int) (UINT32 *) (stack + uiLocOnStack);
    110 		memcpy ((stack + uiLocOnStack), *p_argv, (*p_arg)->size);
    111 	      }
    112 	    break;
    113 	  }
    114 	default:
    115 	  z = (*p_arg)->size;
    116 	  if (z < sizeof (int))
    117 	    {
    118 	      switch ((*p_arg)->type)
    119 		{
    120 		case FFI_TYPE_SINT8:
    121 		  *(signed int *) argp = (signed int) *(SINT8 *) (*p_argv);
    122 		  break;
    123 
    124 		case FFI_TYPE_UINT8:
    125 		  *(unsigned int *) argp =
    126 		    (unsigned int) *(UINT8 *) (*p_argv);
    127 		  break;
    128 
    129 		case FFI_TYPE_SINT16:
    130 		  *(signed int *) argp = (signed int) *(SINT16 *) (*p_argv);
    131 		  break;
    132 
    133 		case FFI_TYPE_UINT16:
    134 		  *(unsigned int *) argp =
    135 		    (unsigned int) *(UINT16 *) (*p_argv);
    136 		  break;
    137 
    138 		default:
    139 		  FFI_ASSERT (0);
    140 		}
    141 	      z = sizeof (int);
    142 	    }
    143 	  else if (z == sizeof (int))
    144 	    *(unsigned int *) argp = (unsigned int) *(UINT32 *) (*p_argv);
    145 	  else
    146 	    memcpy (argp, *p_argv, z);
    147 	  break;
    148 	}
    149       p_argv++;
    150       argp += z;
    151     }
    152 
    153   return (struct_count);
    154 }
    155 
    156 ffi_status
    157 ffi_prep_cif (ffi_cif * cif,
    158 	      ffi_abi abi, unsigned int nargs,
    159 	      ffi_type * rtype, ffi_type ** atypes)
    160 {
    161   unsigned bytes = 0;
    162   unsigned int i;
    163   ffi_type **ptr;
    164 
    165   FFI_ASSERT (cif != NULL);
    166   FFI_ASSERT ((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI));
    167 
    168   cif->abi = abi;
    169   cif->arg_types = atypes;
    170   cif->nargs = nargs;
    171   cif->rtype = rtype;
    172 
    173   cif->flags = 0;
    174 
    175   if ((cif->rtype->size == 0)
    176       && (initialize_aggregate_packed_struct (cif->rtype) != FFI_OK))
    177     return FFI_BAD_TYPEDEF;
    178 
    179   FFI_ASSERT_VALID_TYPE (cif->rtype);
    180 
    181   for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
    182     {
    183       if (((*ptr)->size == 0)
    184 	  && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
    185 	return FFI_BAD_TYPEDEF;
    186 
    187       FFI_ASSERT_VALID_TYPE (*ptr);
    188 
    189       if (((*ptr)->alignment - 1) & bytes)
    190 	bytes = ALIGN (bytes, (*ptr)->alignment);
    191       if ((*ptr)->type == FFI_TYPE_STRUCT)
    192 	{
    193 	  if ((*ptr)->size > 8)
    194 	    {
    195 	      bytes += (*ptr)->size;
    196 	      bytes += sizeof (void *);
    197 	    }
    198 	  else
    199 	    {
    200 	      if ((*ptr)->size > 4)
    201 		bytes += 8;
    202 	      else
    203 		bytes += 4;
    204 	    }
    205 	}
    206       else
    207 	bytes += STACK_ARG_SIZE ((*ptr)->size);
    208     }
    209 
    210   cif->bytes = bytes;
    211 
    212   return ffi_prep_cif_machdep (cif);
    213 }
    214 
    215 ffi_status
    216 ffi_prep_cif_machdep (ffi_cif * cif)
    217 {
    218   switch (cif->rtype->type)
    219     {
    220     case FFI_TYPE_VOID:
    221     case FFI_TYPE_STRUCT:
    222     case FFI_TYPE_FLOAT:
    223     case FFI_TYPE_DOUBLE:
    224     case FFI_TYPE_SINT64:
    225     case FFI_TYPE_UINT64:
    226       cif->flags = (unsigned) cif->rtype->type;
    227       break;
    228 
    229     default:
    230       cif->flags = FFI_TYPE_INT;
    231       break;
    232     }
    233 
    234   return FFI_OK;
    235 }
    236 
    237 extern void ffi_call_SYSV (int (*)(char *, extended_cif *),
    238 			   extended_cif *,
    239 			   unsigned, unsigned, unsigned *, void (*fn) ())
    240      __attribute__ ((__visibility__ ("hidden")));
    241 
    242 void
    243 ffi_call (ffi_cif * cif, void (*fn) (), void *rvalue, void **avalue)
    244 {
    245   extended_cif ecif;
    246 
    247   ecif.cif = cif;
    248   ecif.avalue = avalue;
    249 
    250   if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
    251     {
    252       ecif.rvalue = alloca (cif->rtype->size);
    253     }
    254   else
    255     ecif.rvalue = rvalue;
    256 
    257   switch (cif->abi)
    258     {
    259     case FFI_SYSV:
    260       ffi_call_SYSV (ffi_prep_args, &ecif, cif->bytes,
    261 		     cif->flags, ecif.rvalue, fn);
    262       break;
    263     default:
    264       FFI_ASSERT (0);
    265       break;
    266     }
    267 }
    268 
    269 /* Because the following variables are not exported outside libffi, we
    270    mark them hidden.  */
    271 
    272 /* Assembly code for the jump stub.  */
    273 extern const char ffi_cris_trampoline_template[]
    274  __attribute__ ((__visibility__ ("hidden")));
    275 
    276 /* Offset into ffi_cris_trampoline_template of where to put the
    277    ffi_prep_closure_inner function.  */
    278 extern const int ffi_cris_trampoline_fn_offset
    279  __attribute__ ((__visibility__ ("hidden")));
    280 
    281 /* Offset into ffi_cris_trampoline_template of where to put the
    282    closure data.  */
    283 extern const int ffi_cris_trampoline_closure_offset
    284  __attribute__ ((__visibility__ ("hidden")));
    285 
    286 /* This function is sibling-called (jumped to) by the closure
    287    trampoline.  We get R10..R13 at PARAMS[0..3] and a copy of [SP] at
    288    PARAMS[4] to simplify handling of a straddling parameter.  A copy
    289    of R9 is at PARAMS[5] and SP at PARAMS[6].  These parameters are
    290    put at the appropriate place in CLOSURE which is then executed and
    291    the return value is passed back to the caller.  */
    292 
    293 static unsigned long long
    294 ffi_prep_closure_inner (void **params, ffi_closure* closure)
    295 {
    296   char *register_args = (char *) params;
    297   void *struct_ret = params[5];
    298   char *stack_args = params[6];
    299   char *ptr = register_args;
    300   ffi_cif *cif = closure->cif;
    301   ffi_type **arg_types = cif->arg_types;
    302 
    303   /* Max room needed is number of arguments as 64-bit values.  */
    304   void **avalue = alloca (closure->cif->nargs * sizeof(void *));
    305   int i;
    306   int doing_regs;
    307   long long llret = 0;
    308 
    309   /* Find the address of each argument.  */
    310   for (i = 0, doing_regs = 1; i < cif->nargs; i++)
    311     {
    312       /* Types up to and including 8 bytes go by-value.  */
    313       if (arg_types[i]->size <= 4)
    314 	{
    315 	  avalue[i] = ptr;
    316 	  ptr += 4;
    317 	}
    318       else if (arg_types[i]->size <= 8)
    319 	{
    320 	  avalue[i] = ptr;
    321 	  ptr += 8;
    322 	}
    323       else
    324 	{
    325 	  FFI_ASSERT (arg_types[i]->type == FFI_TYPE_STRUCT);
    326 
    327 	  /* Passed by-reference, so copy the pointer.  */
    328 	  avalue[i] = *(void **) ptr;
    329 	  ptr += 4;
    330 	}
    331 
    332       /* If we've handled more arguments than fit in registers, start
    333 	 looking at the those passed on the stack.  Step over the
    334 	 first one if we had a straddling parameter.  */
    335       if (doing_regs && ptr >= register_args + 4*4)
    336 	{
    337 	  ptr = stack_args + ((ptr > register_args + 4*4) ? 4 : 0);
    338 	  doing_regs = 0;
    339 	}
    340     }
    341 
    342   /* Invoke the closure.  */
    343   (closure->fun) (cif,
    344 
    345 		  cif->rtype->type == FFI_TYPE_STRUCT
    346 		  /* The caller allocated space for the return
    347 		     structure, and passed a pointer to this space in
    348 		     R9.  */
    349 		  ? struct_ret
    350 
    351 		  /* We take advantage of being able to ignore that
    352 		     the high part isn't set if the return value is
    353 		     not in R10:R11, but in R10 only.  */
    354 		  : (void *) &llret,
    355 
    356 		  avalue, closure->user_data);
    357 
    358   return llret;
    359 }
    360 
    361 /* API function: Prepare the trampoline.  */
    362 
    363 ffi_status
    364 ffi_prep_closure_loc (ffi_closure* closure,
    365 		      ffi_cif* cif,
    366 		      void (*fun)(ffi_cif *, void *, void **, void*),
    367 		      void *user_data,
    368 		      void *codeloc)
    369 {
    370   void *innerfn = ffi_prep_closure_inner;
    371   FFI_ASSERT (cif->abi == FFI_SYSV);
    372   closure->cif  = cif;
    373   closure->user_data = user_data;
    374   closure->fun  = fun;
    375   memcpy (closure->tramp, ffi_cris_trampoline_template,
    376 	  FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE);
    377   memcpy (closure->tramp + ffi_cris_trampoline_fn_offset,
    378 	  &innerfn, sizeof (void *));
    379   memcpy (closure->tramp + ffi_cris_trampoline_closure_offset,
    380 	  &codeloc, sizeof (void *));
    381 
    382   return FFI_OK;
    383 }
    384