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