Home | History | Annotate | Download | only in sh64
      1 /* -----------------------------------------------------------------------
      2    ffi.c - Copyright (c) 2003, 2004, 2006, 2007, 2012 Kaz Kojima
      3            Copyright (c) 2008 Anthony Green
      4 
      5    SuperH SHmedia 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 
     33 #define NGREGARG 8
     34 #define NFREGARG 12
     35 
     36 static int
     37 return_type (ffi_type *arg)
     38 {
     39 
     40   if (arg->type != FFI_TYPE_STRUCT)
     41     return arg->type;
     42 
     43   /* gcc uses r2 if the result can be packed in on register.  */
     44   if (arg->size <= sizeof (UINT8))
     45     return FFI_TYPE_UINT8;
     46   else if (arg->size <= sizeof (UINT16))
     47     return FFI_TYPE_UINT16;
     48   else if (arg->size <= sizeof (UINT32))
     49     return FFI_TYPE_UINT32;
     50   else if (arg->size <= sizeof (UINT64))
     51     return FFI_TYPE_UINT64;
     52 
     53   return FFI_TYPE_STRUCT;
     54 }
     55 
     56 /* ffi_prep_args is called by the assembly routine once stack space
     57    has been allocated for the function's arguments */
     58 
     59 void ffi_prep_args(char *stack, extended_cif *ecif)
     60 {
     61   register unsigned int i;
     62   register unsigned int avn;
     63   register void **p_argv;
     64   register char *argp;
     65   register ffi_type **p_arg;
     66 
     67   argp = stack;
     68 
     69   if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
     70     {
     71       *(void **) argp = ecif->rvalue;
     72       argp += sizeof (UINT64);
     73     }
     74 
     75   avn = ecif->cif->nargs;
     76   p_argv = ecif->avalue;
     77 
     78   for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
     79     {
     80       size_t z;
     81       int align;
     82 
     83       z = (*p_arg)->size;
     84       align = (*p_arg)->alignment;
     85       if (z < sizeof (UINT32))
     86 	{
     87 	  switch ((*p_arg)->type)
     88 	    {
     89 	    case FFI_TYPE_SINT8:
     90 	      *(SINT64 *) argp = (SINT64) *(SINT8 *)(*p_argv);
     91 	      break;
     92 
     93 	    case FFI_TYPE_UINT8:
     94 	      *(UINT64 *) argp = (UINT64) *(UINT8 *)(*p_argv);
     95 	      break;
     96 
     97 	    case FFI_TYPE_SINT16:
     98 	      *(SINT64 *) argp = (SINT64) *(SINT16 *)(*p_argv);
     99 	      break;
    100 
    101 	    case FFI_TYPE_UINT16:
    102 	      *(UINT64 *) argp = (UINT64) *(UINT16 *)(*p_argv);
    103 	      break;
    104 
    105 	    case FFI_TYPE_STRUCT:
    106 	      memcpy (argp, *p_argv, z);
    107 	      break;
    108 
    109 	    default:
    110 	      FFI_ASSERT(0);
    111 	    }
    112 	  argp += sizeof (UINT64);
    113 	}
    114       else if (z == sizeof (UINT32) && align == sizeof (UINT32))
    115 	{
    116 	  switch ((*p_arg)->type)
    117 	    {
    118 	    case FFI_TYPE_INT:
    119 	    case FFI_TYPE_SINT32:
    120 	      *(SINT64 *) argp = (SINT64) *(SINT32 *) (*p_argv);
    121 	      break;
    122 
    123 	    case FFI_TYPE_FLOAT:
    124 	    case FFI_TYPE_POINTER:
    125 	    case FFI_TYPE_UINT32:
    126 	    case FFI_TYPE_STRUCT:
    127 	      *(UINT64 *) argp = (UINT64) *(UINT32 *) (*p_argv);
    128 	      break;
    129 
    130 	    default:
    131 	      FFI_ASSERT(0);
    132 	      break;
    133 	    }
    134 	  argp += sizeof (UINT64);
    135 	}
    136       else if (z == sizeof (UINT64)
    137 	       && align == sizeof (UINT64)
    138 	       && ((int) *p_argv & (sizeof (UINT64) - 1)) == 0)
    139 	{
    140 	  *(UINT64 *) argp = *(UINT64 *) (*p_argv);
    141 	  argp += sizeof (UINT64);
    142 	}
    143       else
    144 	{
    145 	  int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
    146 
    147 	  memcpy (argp, *p_argv, z);
    148 	  argp += n * sizeof (UINT64);
    149 	}
    150     }
    151 
    152   return;
    153 }
    154 
    155 /* Perform machine dependent cif processing */
    156 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
    157 {
    158   int i, j;
    159   int size, type;
    160   int n, m;
    161   int greg;
    162   int freg;
    163   int fpair = -1;
    164 
    165   greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0);
    166   freg = 0;
    167   cif->flags2 = 0;
    168 
    169   for (i = j = 0; i < cif->nargs; i++)
    170     {
    171       type = (cif->arg_types)[i]->type;
    172       switch (type)
    173 	{
    174 	case FFI_TYPE_FLOAT:
    175 	  greg++;
    176 	  cif->bytes += sizeof (UINT64) - sizeof (float);
    177 	  if (freg >= NFREGARG - 1)
    178 	    continue;
    179 	  if (fpair < 0)
    180 	    {
    181 	      fpair = freg;
    182 	      freg += 2;
    183 	    }
    184 	  else
    185 	    fpair = -1;
    186 	  cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
    187 	  break;
    188 
    189 	case FFI_TYPE_DOUBLE:
    190 	  if (greg++ >= NGREGARG && (freg + 1) >= NFREGARG)
    191 	    continue;
    192 	  if ((freg + 1) < NFREGARG)
    193 	    {
    194 	      freg += 2;
    195 	      cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
    196 	    }
    197 	  else
    198 	    cif->flags2 += FFI_TYPE_INT << (2 * j++);
    199 	  break;
    200 
    201 	default:
    202 	  size = (cif->arg_types)[i]->size;
    203 	  if (size < sizeof (UINT64))
    204 	    cif->bytes += sizeof (UINT64) - size;
    205 	  n = (size + sizeof (UINT64) - 1) / sizeof (UINT64);
    206 	  if (greg >= NGREGARG)
    207 	    continue;
    208 	  else if (greg + n - 1 >= NGREGARG)
    209 	    greg = NGREGARG;
    210 	  else
    211 	    greg += n;
    212 	  for (m = 0; m < n; m++)
    213 	    cif->flags2 += FFI_TYPE_INT << (2 * j++);
    214 	  break;
    215 	}
    216     }
    217 
    218   /* Set the return type flag */
    219   switch (cif->rtype->type)
    220     {
    221     case FFI_TYPE_STRUCT:
    222       cif->flags = return_type (cif->rtype);
    223       break;
    224 
    225     case FFI_TYPE_VOID:
    226     case FFI_TYPE_FLOAT:
    227     case FFI_TYPE_DOUBLE:
    228     case FFI_TYPE_SINT64:
    229     case FFI_TYPE_UINT64:
    230       cif->flags = cif->rtype->type;
    231       break;
    232 
    233     default:
    234       cif->flags = FFI_TYPE_INT;
    235       break;
    236     }
    237 
    238   return FFI_OK;
    239 }
    240 
    241 /*@-declundef@*/
    242 /*@-exportheader@*/
    243 extern void ffi_call_SYSV(void (*)(char *, extended_cif *),
    244 			  /*@out@*/ extended_cif *,
    245 			  unsigned, unsigned, long long,
    246 			  /*@out@*/ unsigned *,
    247 			  void (*fn)(void));
    248 /*@=declundef@*/
    249 /*@=exportheader@*/
    250 
    251 void ffi_call(/*@dependent@*/ ffi_cif *cif,
    252 	      void (*fn)(void),
    253 	      /*@out@*/ void *rvalue,
    254 	      /*@dependent@*/ void **avalue)
    255 {
    256   extended_cif ecif;
    257   UINT64 trvalue;
    258 
    259   ecif.cif = cif;
    260   ecif.avalue = avalue;
    261 
    262   /* If the return value is a struct and we don't have a return	*/
    263   /* value address then we need to make one		        */
    264 
    265   if (cif->rtype->type == FFI_TYPE_STRUCT
    266       && return_type (cif->rtype) != FFI_TYPE_STRUCT)
    267     ecif.rvalue = &trvalue;
    268   else if ((rvalue == NULL) &&
    269       (cif->rtype->type == FFI_TYPE_STRUCT))
    270     {
    271       ecif.rvalue = alloca(cif->rtype->size);
    272     }
    273   else
    274     ecif.rvalue = rvalue;
    275 
    276   switch (cif->abi)
    277     {
    278     case FFI_SYSV:
    279       ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, cif->flags2,
    280 		    ecif.rvalue, fn);
    281       break;
    282     default:
    283       FFI_ASSERT(0);
    284       break;
    285     }
    286 
    287   if (rvalue
    288       && cif->rtype->type == FFI_TYPE_STRUCT
    289       && return_type (cif->rtype) != FFI_TYPE_STRUCT)
    290     memcpy (rvalue, &trvalue, cif->rtype->size);
    291 }
    292 
    293 extern void ffi_closure_SYSV (void);
    294 extern void __ic_invalidate (void *line);
    295 
    296 ffi_status
    297 ffi_prep_closure_loc (ffi_closure *closure,
    298 		      ffi_cif *cif,
    299 		      void (*fun)(ffi_cif*, void*, void**, void*),
    300 		      void *user_data,
    301 		      void *codeloc)
    302 {
    303   unsigned int *tramp;
    304 
    305   if (cif->abi != FFI_SYSV)
    306     return FFI_BAD_ABI;
    307 
    308   tramp = (unsigned int *) &closure->tramp[0];
    309   /* Since ffi_closure is an aligned object, the ffi trampoline is
    310      called as an SHcompact code.  Sigh.
    311      SHcompact part:
    312      mova @(1,pc),r0; add #1,r0; jmp @r0; nop;
    313      SHmedia part:
    314      movi fnaddr >> 16,r1; shori fnaddr,r1; ptabs/l r1,tr0
    315      movi cxt >> 16,r1; shori cxt,r1; blink tr0,r63  */
    316 #ifdef __LITTLE_ENDIAN__
    317   tramp[0] = 0x7001c701;
    318   tramp[1] = 0x0009402b;
    319 #else
    320   tramp[0] = 0xc7017001;
    321   tramp[1] = 0x402b0009;
    322 #endif
    323   tramp[2] = 0xcc000010 | (((UINT32) ffi_closure_SYSV) >> 16) << 10;
    324   tramp[3] = 0xc8000010 | (((UINT32) ffi_closure_SYSV) & 0xffff) << 10;
    325   tramp[4] = 0x6bf10600;
    326   tramp[5] = 0xcc000010 | (((UINT32) codeloc) >> 16) << 10;
    327   tramp[6] = 0xc8000010 | (((UINT32) codeloc) & 0xffff) << 10;
    328   tramp[7] = 0x4401fff0;
    329 
    330   closure->cif = cif;
    331   closure->fun = fun;
    332   closure->user_data = user_data;
    333 
    334   /* Flush the icache.  */
    335   asm volatile ("ocbwb %0,0; synco; icbi %1,0; synci" : : "r" (tramp),
    336 		"r"(codeloc));
    337 
    338   return FFI_OK;
    339 }
    340 
    341 /* Basically the trampoline invokes ffi_closure_SYSV, and on
    342  * entry, r3 holds the address of the closure.
    343  * After storing the registers that could possibly contain
    344  * parameters to be passed into the stack frame and setting
    345  * up space for a return value, ffi_closure_SYSV invokes the
    346  * following helper function to do most of the work.
    347  */
    348 
    349 int
    350 ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue,
    351 			 UINT64 *pgr, UINT64 *pfr, UINT64 *pst)
    352 {
    353   void **avalue;
    354   ffi_type **p_arg;
    355   int i, avn;
    356   int greg, freg;
    357   ffi_cif *cif;
    358   int fpair = -1;
    359 
    360   cif = closure->cif;
    361   avalue = alloca (cif->nargs * sizeof (void *));
    362 
    363   /* Copy the caller's structure return value address so that the closure
    364      returns the data directly to the caller.  */
    365   if (return_type (cif->rtype) == FFI_TYPE_STRUCT)
    366     {
    367       rvalue = (UINT64 *) *pgr;
    368       greg = 1;
    369     }
    370   else
    371     greg = 0;
    372 
    373   freg = 0;
    374   cif = closure->cif;
    375   avn = cif->nargs;
    376 
    377   /* Grab the addresses of the arguments from the stack frame.  */
    378   for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
    379     {
    380       size_t z;
    381       void *p;
    382 
    383       z = (*p_arg)->size;
    384       if (z < sizeof (UINT32))
    385 	{
    386 	  p = pgr + greg++;
    387 
    388 	  switch ((*p_arg)->type)
    389 	    {
    390 	    case FFI_TYPE_SINT8:
    391 	    case FFI_TYPE_UINT8:
    392 	    case FFI_TYPE_SINT16:
    393 	    case FFI_TYPE_UINT16:
    394 	    case FFI_TYPE_STRUCT:
    395 #ifdef __LITTLE_ENDIAN__
    396 	      avalue[i] = p;
    397 #else
    398 	      avalue[i] = ((char *) p) + sizeof (UINT32) - z;
    399 #endif
    400 	      break;
    401 
    402 	    default:
    403 	      FFI_ASSERT(0);
    404 	    }
    405 	}
    406       else if (z == sizeof (UINT32))
    407 	{
    408 	  if ((*p_arg)->type == FFI_TYPE_FLOAT)
    409 	    {
    410 	      if (freg < NFREGARG - 1)
    411 		{
    412 		  if (fpair >= 0)
    413 		    {
    414 		      avalue[i] = (UINT32 *) pfr + fpair;
    415 		      fpair = -1;
    416 		    }
    417 		  else
    418 		    {
    419 #ifdef __LITTLE_ENDIAN__
    420 		      fpair = freg;
    421 		      avalue[i] = (UINT32 *) pfr + (1 ^ freg);
    422 #else
    423 		      fpair = 1 ^ freg;
    424 		      avalue[i] = (UINT32 *) pfr + freg;
    425 #endif
    426 		      freg += 2;
    427 		    }
    428 		}
    429 	      else
    430 #ifdef __LITTLE_ENDIAN__
    431 		avalue[i] = pgr + greg;
    432 #else
    433 		avalue[i] = (UINT32 *) (pgr + greg) + 1;
    434 #endif
    435 	    }
    436 	  else
    437 #ifdef __LITTLE_ENDIAN__
    438 	    avalue[i] = pgr + greg;
    439 #else
    440 	    avalue[i] = (UINT32 *) (pgr + greg) + 1;
    441 #endif
    442 	  greg++;
    443 	}
    444       else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
    445 	{
    446 	  if (freg + 1 >= NFREGARG)
    447 	    avalue[i] = pgr + greg;
    448 	  else
    449 	    {
    450 	      avalue[i] = pfr + (freg >> 1);
    451 	      freg += 2;
    452 	    }
    453 	  greg++;
    454 	}
    455       else
    456 	{
    457 	  int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
    458 
    459 	  avalue[i] = pgr + greg;
    460 	  greg += n;
    461 	}
    462     }
    463 
    464   (closure->fun) (cif, rvalue, avalue, closure->user_data);
    465 
    466   /* Tell ffi_closure_SYSV how to perform return type promotions.  */
    467   return return_type (cif->rtype);
    468 }
    469 
    470