github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/third_party/gofrontend/libffi/src/m68k/ffi.c (about)

     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  }