Home | History | Annotate | Download | only in m68k
      1 /* -----------------------------------------------------------------------
      2    ffi.c
      3 
      4    m68k Foreign Function Interface
      5    ----------------------------------------------------------------------- */
      6 
      7 #include <ffi.h>
      8 #include <ffi_common.h>
      9 
     10 #include <stdlib.h>
     11 #include <unistd.h>
     12 #ifdef __rtems__
     13 void rtems_cache_flush_multiple_data_lines( const void *, size_t );
     14 #else
     15 #include <sys/syscall.h>
     16 #ifdef __MINT__
     17 #include <mint/mintbind.h>
     18 #include <mint/ssystem.h>
     19 #else
     20 #include <asm/cachectl.h>
     21 #endif
     22 #endif
     23 
     24 void ffi_call_SYSV (extended_cif *,
     25 		    unsigned, unsigned,
     26 		    void *, void (*fn) ());
     27 void *ffi_prep_args (void *stack, extended_cif *ecif);
     28 void ffi_closure_SYSV (ffi_closure *);
     29 void ffi_closure_struct_SYSV (ffi_closure *);
     30 unsigned int ffi_closure_SYSV_inner (ffi_closure *closure,
     31 				     void *resp, void *args);
     32 
     33 /* ffi_prep_args is called by the assembly routine once stack space has
     34    been allocated for the function's arguments.  */
     35 
     36 void *
     37 ffi_prep_args (void *stack, extended_cif *ecif)
     38 {
     39   unsigned int i;
     40   void **p_argv;
     41   char *argp;
     42   ffi_type **p_arg;
     43   void *struct_value_ptr;
     44 
     45   argp = stack;
     46 
     47   if (
     48 #ifdef __MINT__
     49       (ecif->cif->rtype->type == FFI_TYPE_LONGDOUBLE) ||
     50 #endif
     51       (((ecif->cif->rtype->type == FFI_TYPE_STRUCT)
     52         && !ecif->cif->flags)))
     53     struct_value_ptr = ecif->rvalue;
     54   else
     55     struct_value_ptr = NULL;
     56 
     57   p_argv = ecif->avalue;
     58 
     59   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
     60        i != 0;
     61        i--, p_arg++)
     62     {
     63       size_t z = (*p_arg)->size;
     64       int type = (*p_arg)->type;
     65 
     66       if (z < sizeof (int))
     67 	{
     68 	  switch (type)
     69 	    {
     70 	    case FFI_TYPE_SINT8:
     71 	      *(signed int *) argp = (signed int) *(SINT8 *) *p_argv;
     72 	      break;
     73 
     74 	    case FFI_TYPE_UINT8:
     75 	      *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv;
     76 	      break;
     77 
     78 	    case FFI_TYPE_SINT16:
     79 	      *(signed int *) argp = (signed int) *(SINT16 *) *p_argv;
     80 	      break;
     81 
     82 	    case FFI_TYPE_UINT16:
     83 	      *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv;
     84 	      break;
     85 
     86 	    case FFI_TYPE_STRUCT:
     87 #ifdef __MINT__
     88 	      if (z == 1 || z == 2)
     89 		memcpy (argp + 2, *p_argv, z);
     90               else
     91 		memcpy (argp, *p_argv, z);
     92 #else
     93 	      memcpy (argp + sizeof (int) - z, *p_argv, z);
     94 #endif
     95 	      break;
     96 
     97 	    default:
     98 	      FFI_ASSERT (0);
     99 	    }
    100 	  z = sizeof (int);
    101 	}
    102       else
    103 	{
    104 	  memcpy (argp, *p_argv, z);
    105 
    106 	  /* Align if necessary.  */
    107 	  if ((sizeof(int) - 1) & z)
    108 	    z = ALIGN(z, sizeof(int));
    109 	}
    110 
    111       p_argv++;
    112       argp += z;
    113     }
    114 
    115   return struct_value_ptr;
    116 }
    117 
    118 #define CIF_FLAGS_INT		1
    119 #define CIF_FLAGS_DINT		2
    120 #define CIF_FLAGS_FLOAT		4
    121 #define CIF_FLAGS_DOUBLE	8
    122 #define CIF_FLAGS_LDOUBLE	16
    123 #define CIF_FLAGS_POINTER	32
    124 #define CIF_FLAGS_STRUCT1	64
    125 #define CIF_FLAGS_STRUCT2	128
    126 #define CIF_FLAGS_SINT8		256
    127 #define CIF_FLAGS_SINT16	512
    128 
    129 /* Perform machine dependent cif processing */
    130 ffi_status
    131 ffi_prep_cif_machdep (ffi_cif *cif)
    132 {
    133   /* Set the return type flag */
    134   switch (cif->rtype->type)
    135     {
    136     case FFI_TYPE_VOID:
    137       cif->flags = 0;
    138       break;
    139 
    140     case FFI_TYPE_STRUCT:
    141       if (cif->rtype->elements[0]->type == FFI_TYPE_STRUCT &&
    142           cif->rtype->elements[1])
    143         {
    144           cif->flags = 0;
    145           break;
    146         }
    147 
    148       switch (cif->rtype->size)
    149 	{
    150 	case 1:
    151 #ifdef __MINT__
    152 	  cif->flags = CIF_FLAGS_STRUCT2;
    153 #else
    154 	  cif->flags = CIF_FLAGS_STRUCT1;
    155 #endif
    156 	  break;
    157 	case 2:
    158 	  cif->flags = CIF_FLAGS_STRUCT2;
    159 	  break;
    160 #ifdef __MINT__
    161 	case 3:
    162 #endif
    163 	case 4:
    164 	  cif->flags = CIF_FLAGS_INT;
    165 	  break;
    166 #ifdef __MINT__
    167 	case 7:
    168 #endif
    169 	case 8:
    170 	  cif->flags = CIF_FLAGS_DINT;
    171 	  break;
    172 	default:
    173 	  cif->flags = 0;
    174 	  break;
    175 	}
    176       break;
    177 
    178     case FFI_TYPE_FLOAT:
    179       cif->flags = CIF_FLAGS_FLOAT;
    180       break;
    181 
    182     case FFI_TYPE_DOUBLE:
    183       cif->flags = CIF_FLAGS_DOUBLE;
    184       break;
    185 
    186 #if (FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE)
    187     case FFI_TYPE_LONGDOUBLE:
    188 #ifdef __MINT__
    189       cif->flags = 0;
    190 #else
    191       cif->flags = CIF_FLAGS_LDOUBLE;
    192 #endif
    193       break;
    194 #endif
    195 
    196     case FFI_TYPE_POINTER:
    197       cif->flags = CIF_FLAGS_POINTER;
    198       break;
    199 
    200     case FFI_TYPE_SINT64:
    201     case FFI_TYPE_UINT64:
    202       cif->flags = CIF_FLAGS_DINT;
    203       break;
    204 
    205     case FFI_TYPE_SINT16:
    206       cif->flags = CIF_FLAGS_SINT16;
    207       break;
    208 
    209     case FFI_TYPE_SINT8:
    210       cif->flags = CIF_FLAGS_SINT8;
    211       break;
    212 
    213     default:
    214       cif->flags = CIF_FLAGS_INT;
    215       break;
    216     }
    217 
    218   return FFI_OK;
    219 }
    220 
    221 void
    222 ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue)
    223 {
    224   extended_cif ecif;
    225 
    226   ecif.cif = cif;
    227   ecif.avalue = avalue;
    228 
    229   /* If the return value is a struct and we don't have a return value
    230      address then we need to make one.  */
    231 
    232   if (rvalue == NULL
    233       && cif->rtype->type == FFI_TYPE_STRUCT
    234       && cif->rtype->size > 8)
    235     ecif.rvalue = alloca (cif->rtype->size);
    236   else
    237     ecif.rvalue = rvalue;
    238 
    239   switch (cif->abi)
    240     {
    241     case FFI_SYSV:
    242       ffi_call_SYSV (&ecif, cif->bytes, cif->flags,
    243 		     ecif.rvalue, fn);
    244       break;
    245 
    246     default:
    247       FFI_ASSERT (0);
    248       break;
    249     }
    250 }
    251 
    252 static void
    253 ffi_prep_incoming_args_SYSV (char *stack, void **avalue, ffi_cif *cif)
    254 {
    255   unsigned int i;
    256   void **p_argv;
    257   char *argp;
    258   ffi_type **p_arg;
    259 
    260   argp = stack;
    261   p_argv = avalue;
    262 
    263   for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
    264     {
    265       size_t z;
    266 
    267       z = (*p_arg)->size;
    268 #ifdef __MINT__
    269       if (cif->flags &&
    270           cif->rtype->type == FFI_TYPE_STRUCT &&
    271           (z == 1 || z == 2))
    272  	{
    273 	  *p_argv = (void *) (argp + 2);
    274 
    275 	  z = 4;
    276 	}
    277       else
    278       if (cif->flags &&
    279           cif->rtype->type == FFI_TYPE_STRUCT &&
    280           (z == 3 || z == 4))
    281  	{
    282 	  *p_argv = (void *) (argp);
    283 
    284 	  z = 4;
    285 	}
    286       else
    287 #endif
    288       if (z <= 4)
    289 	{
    290 	  *p_argv = (void *) (argp + 4 - z);
    291 
    292 	  z = 4;
    293 	}
    294       else
    295 	{
    296 	  *p_argv = (void *) argp;
    297 
    298 	  /* Align if necessary */
    299 	  if ((sizeof(int) - 1) & z)
    300 	    z = ALIGN(z, sizeof(int));
    301 	}
    302 
    303       p_argv++;
    304       argp += z;
    305     }
    306 }
    307 
    308 unsigned int
    309 ffi_closure_SYSV_inner (ffi_closure *closure, void *resp, void *args)
    310 {
    311   ffi_cif *cif;
    312   void **arg_area;
    313 
    314   cif = closure->cif;
    315   arg_area = (void**) alloca (cif->nargs * sizeof (void *));
    316 
    317   ffi_prep_incoming_args_SYSV(args, arg_area, cif);
    318 
    319   (closure->fun) (cif, resp, arg_area, closure->user_data);
    320 
    321   return cif->flags;
    322 }
    323 
    324 ffi_status
    325 ffi_prep_closure_loc (ffi_closure* closure,
    326 		      ffi_cif* cif,
    327 		      void (*fun)(ffi_cif*,void*,void**,void*),
    328 		      void *user_data,
    329 		      void *codeloc)
    330 {
    331   if (cif->abi != FFI_SYSV)
    332     return FFI_BAD_ABI;
    333 
    334   *(unsigned short *)closure->tramp = 0x207c;
    335   *(void **)(closure->tramp + 2) = codeloc;
    336   *(unsigned short *)(closure->tramp + 6) = 0x4ef9;
    337 
    338   if (
    339 #ifdef __MINT__
    340       (cif->rtype->type == FFI_TYPE_LONGDOUBLE) ||
    341 #endif
    342       (((cif->rtype->type == FFI_TYPE_STRUCT)
    343          && !cif->flags)))
    344     *(void **)(closure->tramp + 8) = ffi_closure_struct_SYSV;
    345   else
    346     *(void **)(closure->tramp + 8) = ffi_closure_SYSV;
    347 
    348 #ifdef __rtems__
    349   rtems_cache_flush_multiple_data_lines( codeloc, FFI_TRAMPOLINE_SIZE );
    350 #elif defined(__MINT__)
    351   Ssystem(S_FLUSHCACHE, codeloc, FFI_TRAMPOLINE_SIZE);
    352 #else
    353   syscall(SYS_cacheflush, codeloc, FLUSH_SCOPE_LINE,
    354 	  FLUSH_CACHE_BOTH, FFI_TRAMPOLINE_SIZE);
    355 #endif
    356 
    357   closure->cif  = cif;
    358   closure->user_data = user_data;
    359   closure->fun  = fun;
    360 
    361   return FFI_OK;
    362 }
    363