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 #include <sys/syscall.h>
     13 #include <asm/cachectl.h>
     14 
     15 void ffi_call_SYSV (extended_cif *,
     16 		    unsigned, unsigned,
     17 		    void *, void (*fn) ());
     18 void *ffi_prep_args (void *stack, extended_cif *ecif);
     19 void ffi_closure_SYSV (ffi_closure *);
     20 void ffi_closure_struct_SYSV (ffi_closure *);
     21 unsigned int ffi_closure_SYSV_inner (ffi_closure *closure,
     22 				     void *resp, void *args);
     23 
     24 /* ffi_prep_args is called by the assembly routine once stack space has
     25    been allocated for the function's arguments.  */
     26 
     27 void *
     28 ffi_prep_args (void *stack, extended_cif *ecif)
     29 {
     30   unsigned int i;
     31   void **p_argv;
     32   char *argp;
     33   ffi_type **p_arg;
     34   void *struct_value_ptr;
     35 
     36   argp = stack;
     37 
     38   if (ecif->cif->rtype->type == FFI_TYPE_STRUCT
     39       && !ecif->cif->flags)
     40     struct_value_ptr = ecif->rvalue;
     41   else
     42     struct_value_ptr = NULL;
     43 
     44   p_argv = ecif->avalue;
     45 
     46   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
     47        i != 0;
     48        i--, p_arg++)
     49     {
     50       size_t z;
     51 
     52       z = (*p_arg)->size;
     53       if (z < sizeof (int))
     54 	{
     55 	  switch ((*p_arg)->type)
     56 	    {
     57 	    case FFI_TYPE_SINT8:
     58 	      *(signed int *) argp = (signed int) *(SINT8 *) *p_argv;
     59 	      break;
     60 
     61 	    case FFI_TYPE_UINT8:
     62 	      *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv;
     63 	      break;
     64 
     65 	    case FFI_TYPE_SINT16:
     66 	      *(signed int *) argp = (signed int) *(SINT16 *) *p_argv;
     67 	      break;
     68 
     69 	    case FFI_TYPE_UINT16:
     70 	      *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv;
     71 	      break;
     72 
     73 	    case FFI_TYPE_STRUCT:
     74 	      memcpy (argp + sizeof (int) - z, *p_argv, z);
     75 	      break;
     76 
     77 	    default:
     78 	      FFI_ASSERT (0);
     79 	    }
     80 	  z = sizeof (int);
     81 	}
     82       else
     83 	{
     84 	  memcpy (argp, *p_argv, z);
     85 
     86 	  /* Align if necessary.  */
     87 	  if ((sizeof(int) - 1) & z)
     88 	    z = ALIGN(z, sizeof(int));
     89 	}
     90 
     91       p_argv++;
     92       argp += z;
     93     }
     94 
     95   return struct_value_ptr;
     96 }
     97 
     98 #define CIF_FLAGS_INT		1
     99 #define CIF_FLAGS_DINT		2
    100 #define CIF_FLAGS_FLOAT		4
    101 #define CIF_FLAGS_DOUBLE	8
    102 #define CIF_FLAGS_LDOUBLE	16
    103 #define CIF_FLAGS_POINTER	32
    104 #define CIF_FLAGS_STRUCT1	64
    105 #define CIF_FLAGS_STRUCT2	128
    106 
    107 /* Perform machine dependent cif processing */
    108 ffi_status
    109 ffi_prep_cif_machdep (ffi_cif *cif)
    110 {
    111   /* Set the return type flag */
    112   switch (cif->rtype->type)
    113     {
    114     case FFI_TYPE_VOID:
    115       cif->flags = 0;
    116       break;
    117 
    118     case FFI_TYPE_STRUCT:
    119       switch (cif->rtype->size)
    120 	{
    121 	case 1:
    122 	  cif->flags = CIF_FLAGS_STRUCT1;
    123 	  break;
    124 	case 2:
    125 	  cif->flags = CIF_FLAGS_STRUCT2;
    126 	  break;
    127 	case 4:
    128 	  cif->flags = CIF_FLAGS_INT;
    129 	  break;
    130 	case 8:
    131 	  cif->flags = CIF_FLAGS_DINT;
    132 	  break;
    133 	default:
    134 	  cif->flags = 0;
    135 	  break;
    136 	}
    137       break;
    138 
    139     case FFI_TYPE_FLOAT:
    140       cif->flags = CIF_FLAGS_FLOAT;
    141       break;
    142 
    143     case FFI_TYPE_DOUBLE:
    144       cif->flags = CIF_FLAGS_DOUBLE;
    145       break;
    146 
    147     case FFI_TYPE_LONGDOUBLE:
    148       cif->flags = CIF_FLAGS_LDOUBLE;
    149       break;
    150 
    151     case FFI_TYPE_POINTER:
    152       cif->flags = CIF_FLAGS_POINTER;
    153       break;
    154 
    155     case FFI_TYPE_SINT64:
    156     case FFI_TYPE_UINT64:
    157       cif->flags = CIF_FLAGS_DINT;
    158       break;
    159 
    160     default:
    161       cif->flags = CIF_FLAGS_INT;
    162       break;
    163     }
    164 
    165   return FFI_OK;
    166 }
    167 
    168 void
    169 ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue)
    170 {
    171   extended_cif ecif;
    172 
    173   ecif.cif = cif;
    174   ecif.avalue = avalue;
    175 
    176   /* If the return value is a struct and we don't have a return value
    177      address then we need to make one.  */
    178 
    179   if (rvalue == NULL
    180       && cif->rtype->type == FFI_TYPE_STRUCT
    181       && cif->rtype->size > 8)
    182     ecif.rvalue = alloca (cif->rtype->size);
    183   else
    184     ecif.rvalue = rvalue;
    185 
    186   switch (cif->abi)
    187     {
    188     case FFI_SYSV:
    189       ffi_call_SYSV (&ecif, cif->bytes, cif->flags,
    190 		     ecif.rvalue, fn);
    191       break;
    192 
    193     default:
    194       FFI_ASSERT (0);
    195       break;
    196     }
    197 }
    198 
    199 static void
    200 ffi_prep_incoming_args_SYSV (char *stack, void **avalue, ffi_cif *cif)
    201 {
    202   unsigned int i;
    203   void **p_argv;
    204   char *argp;
    205   ffi_type **p_arg;
    206 
    207   argp = stack;
    208   p_argv = avalue;
    209 
    210   for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
    211     {
    212       size_t z;
    213 
    214       z = (*p_arg)->size;
    215       if (z <= 4)
    216 	{
    217 	  *p_argv = (void *) (argp + 4 - z);
    218 
    219 	  z = 4;
    220 	}
    221       else
    222 	{
    223 	  *p_argv = (void *) argp;
    224 
    225 	  /* Align if necessary */
    226 	  if ((sizeof(int) - 1) & z)
    227 	    z = ALIGN(z, sizeof(int));
    228 	}
    229 
    230       p_argv++;
    231       argp += z;
    232     }
    233 }
    234 
    235 unsigned int
    236 ffi_closure_SYSV_inner (ffi_closure *closure, void *resp, void *args)
    237 {
    238   ffi_cif *cif;
    239   void **arg_area;
    240 
    241   cif = closure->cif;
    242   arg_area = (void**) alloca (cif->nargs * sizeof (void *));
    243 
    244   ffi_prep_incoming_args_SYSV(args, arg_area, cif);
    245 
    246   (closure->fun) (cif, resp, arg_area, closure->user_data);
    247 
    248   return cif->flags;
    249 }
    250 
    251 ffi_status
    252 ffi_prep_closure_loc (ffi_closure* closure,
    253 		      ffi_cif* cif,
    254 		      void (*fun)(ffi_cif*,void*,void**,void*),
    255 		      void *user_data,
    256 		      void *codeloc)
    257 {
    258   FFI_ASSERT (cif->abi == FFI_SYSV);
    259 
    260   *(unsigned short *)closure->tramp = 0x207c;
    261   *(void **)(closure->tramp + 2) = codeloc;
    262   *(unsigned short *)(closure->tramp + 6) = 0x4ef9;
    263   if (cif->rtype->type == FFI_TYPE_STRUCT
    264       && !cif->flags)
    265     *(void **)(closure->tramp + 8) = ffi_closure_struct_SYSV;
    266   else
    267     *(void **)(closure->tramp + 8) = ffi_closure_SYSV;
    268 
    269   syscall(SYS_cacheflush, codeloc, FLUSH_SCOPE_LINE,
    270 	  FLUSH_CACHE_BOTH, FFI_TRAMPOLINE_SIZE);
    271 
    272   closure->cif  = cif;
    273   closure->user_data = user_data;
    274   closure->fun  = fun;
    275 
    276   return FFI_OK;
    277 }
    278 
    279