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

     1  /* -----------------------------------------------------------------------
     2     ffi.c - Copyright (c) 2013 Tensilica, Inc.
     3  
     4     XTENSA Foreign Function Interface
     5  
     6     Permission is hereby granted, free of charge, to any person obtaining
     7     a copy of this software and associated documentation files (the
     8     ``Software''), to deal in the Software without restriction, including
     9     without limitation the rights to use, copy, modify, merge, publish,
    10     distribute, sublicense, and/or sell copies of the Software, and to
    11     permit persons to whom the Software is furnished to do so, subject to
    12     the following conditions:
    13  
    14     The above copyright notice and this permission notice shall be included
    15     in all copies or substantial portions of the Software.
    16  
    17     THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
    18     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    19     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    20     NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    21     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    22     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    23     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    24     DEALINGS IN THE SOFTWARE.
    25     ----------------------------------------------------------------------- */
    26  
    27  #include <ffi.h>
    28  #include <ffi_common.h>
    29  
    30  /*
    31                                   |----------------------------------------|
    32                                   |                                        |
    33      on entry to ffi_call ---->   |----------------------------------------|
    34                                   | caller stack frame for registers a0-a3 |
    35                                   |----------------------------------------|
    36                                   |                                        |
    37                                   |         additional arguments           |
    38      entry of the function --->   |----------------------------------------|
    39                                   |    copy of function arguments a2-a7    |
    40                                   | -  -  -  -  -  -  -  -  -  -  -  -  -  |
    41                                   |                                        |
    42  
    43      The area below the entry line becomes the new stack frame for the function.
    44  
    45  */
    46  
    47  
    48  #define FFI_TYPE_STRUCT_REGS FFI_TYPE_LAST
    49  
    50  
    51  extern void ffi_call_SYSV(void *rvalue, unsigned rsize, unsigned flags,
    52  			  void(*fn)(void), unsigned nbytes, extended_cif*);
    53  extern void ffi_closure_SYSV(void) FFI_HIDDEN;
    54  
    55  ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
    56  {
    57    switch(cif->rtype->type) {
    58      case FFI_TYPE_SINT8:
    59      case FFI_TYPE_UINT8:
    60      case FFI_TYPE_SINT16:
    61      case FFI_TYPE_UINT16:
    62        cif->flags = cif->rtype->type;
    63        break;
    64      case FFI_TYPE_VOID:
    65      case FFI_TYPE_FLOAT:
    66        cif->flags = FFI_TYPE_UINT32;
    67        break;
    68      case FFI_TYPE_DOUBLE:
    69      case FFI_TYPE_UINT64:
    70      case FFI_TYPE_SINT64:
    71        cif->flags = FFI_TYPE_UINT64; // cif->rtype->type;
    72        break;
    73      case FFI_TYPE_STRUCT:
    74        cif->flags = FFI_TYPE_STRUCT; //_REGS;
    75        /* Up to 16 bytes are returned in registers */
    76        if (cif->rtype->size > 4 * 4) {
    77          /* returned structure is referenced by a register; use 8 bytes
    78             (including 4 bytes for potential additional alignment) */
    79          cif->flags = FFI_TYPE_STRUCT;	
    80          cif->bytes += 8;
    81        }
    82        break;
    83  
    84      default:
    85        cif->flags = FFI_TYPE_UINT32;
    86        break;
    87    }
    88  
    89    /* Round the stack up to a full 4 register frame, just in case
    90       (we use this size in movsp). This way, it's also a  multiple of
    91       8 bytes for 64-bit arguments.  */
    92    cif->bytes = ALIGN(cif->bytes, 16);
    93  
    94    return FFI_OK;
    95  }
    96  
    97  void ffi_prep_args(extended_cif *ecif, unsigned char* stack)
    98  {
    99    unsigned int i;
   100    unsigned long *addr;
   101    ffi_type **ptr;
   102  
   103    union {
   104      void **v;
   105      char **c;
   106      signed char **sc;
   107      unsigned char **uc;
   108      signed short **ss;
   109      unsigned short **us;
   110      unsigned int **i;
   111      long long **ll;
   112      float **f;
   113      double **d;
   114    } p_argv;
   115  
   116    /* Verify that everything is aligned up properly */
   117    FFI_ASSERT (((unsigned long) stack & 0x7) == 0);
   118  
   119    p_argv.v = ecif->avalue;
   120    addr = (unsigned long*)stack;
   121  
   122    /* structures with a size greater than 16 bytes are passed in memory */
   123    if (ecif->cif->rtype->type == FFI_TYPE_STRUCT && ecif->cif->rtype->size > 16)
   124    {
   125      *addr++ = (unsigned long)ecif->rvalue;
   126    }
   127  
   128    for (i = ecif->cif->nargs, ptr = ecif->cif->arg_types;
   129         i > 0;
   130         i--, ptr++, p_argv.v++)
   131    {
   132      switch ((*ptr)->type)
   133      {
   134        case FFI_TYPE_SINT8:
   135          *addr++ = **p_argv.sc;
   136          break;
   137        case FFI_TYPE_UINT8:
   138          *addr++ = **p_argv.uc;
   139          break;
   140        case FFI_TYPE_SINT16:
   141          *addr++ = **p_argv.ss;
   142          break;
   143        case FFI_TYPE_UINT16:
   144          *addr++ = **p_argv.us;
   145          break;
   146        case FFI_TYPE_FLOAT:
   147        case FFI_TYPE_INT:
   148        case FFI_TYPE_UINT32:
   149        case FFI_TYPE_SINT32:
   150        case FFI_TYPE_POINTER:
   151          *addr++ = **p_argv.i;
   152          break;
   153        case FFI_TYPE_DOUBLE:
   154        case FFI_TYPE_UINT64:
   155        case FFI_TYPE_SINT64:
   156          if (((unsigned long)addr & 4) != 0)
   157            addr++;
   158          *(unsigned long long*)addr = **p_argv.ll;
   159  	addr += sizeof(unsigned long long) / sizeof (addr);
   160          break;
   161  
   162        case FFI_TYPE_STRUCT:
   163        {
   164          unsigned long offs;
   165          unsigned long size;
   166  
   167          if (((unsigned long)addr & 4) != 0 && (*ptr)->alignment > 4)
   168            addr++;
   169  
   170          offs = (unsigned long) addr - (unsigned long) stack;
   171          size = (*ptr)->size;
   172  
   173          /* Entire structure must fit the argument registers or referenced */
   174          if (offs < FFI_REGISTER_NARGS * 4
   175              && offs + size > FFI_REGISTER_NARGS * 4)
   176            addr = (unsigned long*) (stack + FFI_REGISTER_NARGS * 4);
   177  
   178          memcpy((char*) addr, *p_argv.c, size);
   179          addr += (size + 3) / 4;
   180          break;
   181        }
   182  
   183        default:
   184          FFI_ASSERT(0);
   185      }
   186    }
   187  }
   188  
   189  
   190  void ffi_call(ffi_cif* cif, void(*fn)(void), void *rvalue, void **avalue)
   191  {
   192    extended_cif ecif;
   193    unsigned long rsize = cif->rtype->size;
   194    int flags = cif->flags;
   195    void *alloc = NULL;
   196  
   197    ecif.cif = cif;
   198    ecif.avalue = avalue;
   199  
   200    /* Note that for structures that are returned in registers (size <= 16 bytes)
   201       we allocate a temporary buffer and use memcpy to copy it to the final 
   202       destination. The reason is that the target address might be misaligned or
   203       the length not a multiple of 4 bytes. Handling all those cases would be
   204       very complex.  */
   205  
   206    if (flags == FFI_TYPE_STRUCT && (rsize <= 16 || rvalue == NULL))
   207    {
   208      alloc = alloca(ALIGN(rsize, 4));
   209      ecif.rvalue = alloc;
   210    }
   211    else
   212    {
   213      ecif.rvalue = rvalue;
   214    }
   215  
   216    if (cif->abi != FFI_SYSV)
   217      FFI_ASSERT(0);
   218  
   219    ffi_call_SYSV (ecif.rvalue, rsize, cif->flags, fn, cif->bytes, &ecif);
   220  
   221    if (alloc != NULL && rvalue != NULL)
   222      memcpy(rvalue, alloc, rsize);
   223  }
   224  
   225  extern void ffi_trampoline();
   226  extern void ffi_cacheflush(void* start, void* end);
   227  
   228  ffi_status
   229  ffi_prep_closure_loc (ffi_closure* closure,
   230                        ffi_cif* cif,
   231                        void (*fun)(ffi_cif*, void*, void**, void*),
   232                        void *user_data,
   233                        void *codeloc)
   234  {
   235    /* copye trampoline to stack and patch 'ffi_closure_SYSV' pointer */
   236    memcpy(closure->tramp, ffi_trampoline, FFI_TRAMPOLINE_SIZE);
   237    *(unsigned int*)(&closure->tramp[8]) = (unsigned int)ffi_closure_SYSV;
   238  
   239    // Do we have this function?
   240    // __builtin___clear_cache(closer->tramp, closer->tramp + FFI_TRAMPOLINE_SIZE)
   241    ffi_cacheflush(closure->tramp, closure->tramp + FFI_TRAMPOLINE_SIZE);
   242  
   243    closure->cif = cif;
   244    closure->fun = fun;
   245    closure->user_data = user_data;
   246    return FFI_OK; 
   247  }
   248  
   249  
   250  long FFI_HIDDEN
   251  ffi_closure_SYSV_inner(ffi_closure *closure, void **values, void *rvalue)
   252  {
   253    ffi_cif *cif;
   254    ffi_type **arg_types;
   255    void **avalue;
   256    int i, areg;
   257  
   258    cif = closure->cif;
   259    if (cif->abi != FFI_SYSV)
   260      return FFI_BAD_ABI;
   261  
   262    areg = 0;
   263  
   264    int rtype = cif->rtype->type;
   265    if (rtype == FFI_TYPE_STRUCT && cif->rtype->size > 4 * 4)
   266    {
   267      rvalue = *values;
   268      areg++;
   269    }
   270  
   271    cif = closure->cif; 
   272    arg_types = cif->arg_types;
   273    avalue = alloca(cif->nargs * sizeof(void *));
   274  
   275    for (i = 0; i < cif->nargs; i++)
   276    {
   277      if (arg_types[i]->alignment == 8 && (areg & 1) != 0)
   278        areg++;
   279  
   280      // skip the entry 16,a1 framework, add 16 bytes (4 registers)
   281      if (areg == FFI_REGISTER_NARGS)
   282        areg += 4;
   283  
   284      if (arg_types[i]->type == FFI_TYPE_STRUCT)
   285      {
   286        int numregs = ((arg_types[i]->size + 3) & ~3) / 4;
   287        if (areg < FFI_REGISTER_NARGS && areg + numregs > FFI_REGISTER_NARGS)
   288          areg = FFI_REGISTER_NARGS + 4;
   289      }
   290  
   291      avalue[i] = &values[areg];
   292      areg += (arg_types[i]->size + 3) / 4;
   293    }
   294  
   295    (closure->fun)(cif, rvalue, avalue, closure->user_data);
   296  
   297    return rtype;
   298  }