Back to index

plt-scheme  4.2.1
ffi.c
Go to the documentation of this file.
00001 /* -----------------------------------------------------------------------
00002    ffi.c
00003    
00004    m68k Foreign Function Interface 
00005    ----------------------------------------------------------------------- */
00006 
00007 #include <ffi.h>
00008 #include <ffi_common.h>
00009 
00010 #include <stdlib.h>
00011 #include <unistd.h>
00012 #include <sys/syscall.h>
00013 #include <asm/cachectl.h>
00014 
00015 void ffi_call_SYSV (extended_cif *,
00016                   unsigned, unsigned,
00017                   void *, void (*fn) ());
00018 void *ffi_prep_args (void *stack, extended_cif *ecif);
00019 void ffi_closure_SYSV (ffi_closure *);
00020 void ffi_closure_struct_SYSV (ffi_closure *);
00021 unsigned int ffi_closure_SYSV_inner (ffi_closure *closure,
00022                                  void *resp, void *args);
00023 
00024 /* ffi_prep_args is called by the assembly routine once stack space has
00025    been allocated for the function's arguments.  */
00026 
00027 void *
00028 ffi_prep_args (void *stack, extended_cif *ecif)
00029 {
00030   unsigned int i;
00031   void **p_argv;
00032   char *argp;
00033   ffi_type **p_arg;
00034   void *struct_value_ptr;
00035 
00036   argp = stack;
00037 
00038   if (ecif->cif->rtype->type == FFI_TYPE_STRUCT
00039       && !ecif->cif->flags)
00040     struct_value_ptr = ecif->rvalue;
00041   else
00042     struct_value_ptr = NULL;
00043 
00044   p_argv = ecif->avalue;
00045 
00046   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
00047        i != 0;
00048        i--, p_arg++)
00049     {
00050       size_t z;
00051 
00052       z = (*p_arg)->size;
00053       if (z < sizeof (int))
00054        {
00055          switch ((*p_arg)->type)
00056            {
00057            case FFI_TYPE_SINT8:
00058              *(signed int *) argp = (signed int) *(SINT8 *) *p_argv;
00059              break;
00060 
00061            case FFI_TYPE_UINT8:
00062              *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv;
00063              break;
00064 
00065            case FFI_TYPE_SINT16:
00066              *(signed int *) argp = (signed int) *(SINT16 *) *p_argv;
00067              break;
00068 
00069            case FFI_TYPE_UINT16:
00070              *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv;
00071              break;
00072 
00073            case FFI_TYPE_STRUCT:
00074              memcpy (argp + sizeof (int) - z, *p_argv, z);
00075              break;
00076 
00077            default:
00078              FFI_ASSERT (0);
00079            }
00080          z = sizeof (int);
00081        }
00082       else
00083        {
00084          memcpy (argp, *p_argv, z);
00085 
00086          /* Align if necessary.  */
00087          if ((sizeof(int) - 1) & z)
00088            z = ALIGN(z, sizeof(int));
00089        }
00090 
00091       p_argv++;
00092       argp += z;
00093     }
00094 
00095   return struct_value_ptr;
00096 }
00097 
00098 #define CIF_FLAGS_INT              1
00099 #define CIF_FLAGS_DINT             2
00100 #define CIF_FLAGS_FLOAT            4
00101 #define CIF_FLAGS_DOUBLE    8
00102 #define CIF_FLAGS_LDOUBLE   16
00103 #define CIF_FLAGS_POINTER   32
00104 #define CIF_FLAGS_STRUCT1   64
00105 #define CIF_FLAGS_STRUCT2   128
00106 
00107 /* Perform machine dependent cif processing */
00108 ffi_status
00109 ffi_prep_cif_machdep (ffi_cif *cif)
00110 {
00111   /* Set the return type flag */
00112   switch (cif->rtype->type)
00113     {
00114     case FFI_TYPE_VOID:
00115       cif->flags = 0;
00116       break;
00117 
00118     case FFI_TYPE_STRUCT:
00119       switch (cif->rtype->size)
00120        {
00121        case 1:
00122          cif->flags = CIF_FLAGS_STRUCT1;
00123          break;
00124        case 2:
00125          cif->flags = CIF_FLAGS_STRUCT2;
00126          break;
00127        case 4:
00128          cif->flags = CIF_FLAGS_INT;
00129          break;
00130        case 8:
00131          cif->flags = CIF_FLAGS_DINT;
00132          break;
00133        default:
00134          cif->flags = 0;
00135          break;
00136        }
00137       break;
00138 
00139     case FFI_TYPE_FLOAT:
00140       cif->flags = CIF_FLAGS_FLOAT;
00141       break;
00142 
00143     case FFI_TYPE_DOUBLE:
00144       cif->flags = CIF_FLAGS_DOUBLE;
00145       break;
00146 
00147     case FFI_TYPE_LONGDOUBLE:
00148       cif->flags = CIF_FLAGS_LDOUBLE;
00149       break;
00150 
00151     case FFI_TYPE_POINTER:
00152       cif->flags = CIF_FLAGS_POINTER;
00153       break;
00154 
00155     case FFI_TYPE_SINT64:
00156     case FFI_TYPE_UINT64:
00157       cif->flags = CIF_FLAGS_DINT;
00158       break;
00159 
00160     default:
00161       cif->flags = CIF_FLAGS_INT;
00162       break;
00163     }
00164 
00165   return FFI_OK;
00166 }
00167 
00168 void
00169 ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue)
00170 {
00171   extended_cif ecif;
00172 
00173   ecif.cif = cif;
00174   ecif.avalue = avalue;
00175 
00176   /* If the return value is a struct and we don't have a return value
00177      address then we need to make one.  */
00178 
00179   if (rvalue == NULL
00180       && cif->rtype->type == FFI_TYPE_STRUCT
00181       && cif->rtype->size > 8)
00182     ecif.rvalue = alloca (cif->rtype->size);
00183   else
00184     ecif.rvalue = rvalue;
00185 
00186   switch (cif->abi)
00187     {
00188     case FFI_SYSV:
00189       ffi_call_SYSV (&ecif, cif->bytes, cif->flags,
00190                    ecif.rvalue, fn);
00191       break;
00192 
00193     default:
00194       FFI_ASSERT (0);
00195       break;
00196     }
00197 }
00198 
00199 static void
00200 ffi_prep_incoming_args_SYSV (char *stack, void **avalue, ffi_cif *cif)
00201 {
00202   unsigned int i;
00203   void **p_argv;
00204   char *argp;
00205   ffi_type **p_arg;
00206 
00207   argp = stack;
00208   p_argv = avalue;
00209 
00210   for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
00211     {
00212       size_t z;
00213 
00214       z = (*p_arg)->size;
00215       if (z <= 4)
00216        {
00217          *p_argv = (void *) (argp + 4 - z);
00218 
00219          z = 4;
00220        }
00221       else
00222        {
00223          *p_argv = (void *) argp;
00224 
00225          /* Align if necessary */
00226          if ((sizeof(int) - 1) & z)
00227            z = ALIGN(z, sizeof(int));
00228        }
00229 
00230       p_argv++;
00231       argp += z;
00232     }
00233 }
00234 
00235 unsigned int
00236 ffi_closure_SYSV_inner (ffi_closure *closure, void *resp, void *args)
00237 {
00238   ffi_cif *cif;
00239   void **arg_area;
00240 
00241   cif = closure->cif;
00242   arg_area = (void**) alloca (cif->nargs * sizeof (void *));
00243 
00244   ffi_prep_incoming_args_SYSV(args, arg_area, cif);
00245 
00246   (closure->fun) (cif, resp, arg_area, closure->user_data);
00247 
00248   return cif->flags;
00249 }
00250 
00251 ffi_status
00252 ffi_prep_closure_loc (ffi_closure* closure,
00253                     ffi_cif* cif,
00254                     void (*fun)(ffi_cif*,void*,void**,void*),
00255                     void *user_data,
00256                     void *codeloc)
00257 {
00258   FFI_ASSERT (cif->abi == FFI_SYSV);
00259 
00260   *(unsigned short *)closure->tramp = 0x207c;
00261   *(void **)(closure->tramp + 2) = codeloc;
00262   *(unsigned short *)(closure->tramp + 6) = 0x4ef9;
00263   if (cif->rtype->type == FFI_TYPE_STRUCT
00264       && !cif->flags)
00265     *(void **)(closure->tramp + 8) = ffi_closure_struct_SYSV;
00266   else
00267     *(void **)(closure->tramp + 8) = ffi_closure_SYSV;
00268 
00269   syscall(SYS_cacheflush, codeloc, FLUSH_SCOPE_LINE,
00270          FLUSH_CACHE_BOTH, FFI_TRAMPOLINE_SIZE);
00271 
00272   closure->cif  = cif;
00273   closure->user_data = user_data;
00274   closure->fun  = fun;
00275 
00276   return FFI_OK;
00277 }
00278