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

     1  /* -----------------------------------------------------------------------
     2     ffi.c - Copyright (c) 2014 Sebastian Macke <sebastian@macke.de>
     3  
     4     OpenRISC 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  /* ffi_prep_args is called by the assembly routine once stack space
    31     has been allocated for the function's arguments */
    32  
    33  void* ffi_prep_args(char *stack, extended_cif *ecif)
    34  {
    35    char *stacktemp = stack;
    36    int i, s;
    37    ffi_type **arg;
    38    int count = 0;
    39    int nfixedargs;
    40    
    41    nfixedargs = ecif->cif->nfixedargs;
    42    arg = ecif->cif->arg_types;
    43    void **argv = ecif->avalue;
    44  
    45    if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
    46      {
    47        *(void **) stack = ecif->rvalue;
    48        stack += 4;
    49        count = 4;
    50      } 
    51    for(i=0; i<ecif->cif->nargs; i++)
    52    {
    53  
    54      /* variadic args are saved on stack */
    55      if ((nfixedargs == 0) && (count < 24))
    56        {
    57          count = 24;
    58          stack = stacktemp + 24;        
    59        }
    60      nfixedargs--;
    61  
    62      s = 4;
    63      switch((*arg)->type) 
    64        {
    65        case FFI_TYPE_STRUCT:
    66          *(void **)stack = *argv;
    67          break;
    68  
    69        case FFI_TYPE_SINT8:
    70          *(signed int *) stack = (signed int)*(SINT8 *)(* argv);
    71          break;
    72  
    73        case FFI_TYPE_UINT8:
    74          *(unsigned int *) stack = (unsigned int)*(UINT8 *)(* argv);
    75          break;
    76  
    77        case FFI_TYPE_SINT16:
    78          *(signed int *) stack = (signed int)*(SINT16 *)(* argv);
    79          break;
    80  
    81        case FFI_TYPE_UINT16:
    82          *(unsigned int *) stack = (unsigned int)*(UINT16 *)(* argv);
    83          break;
    84  
    85        case FFI_TYPE_SINT32:
    86        case FFI_TYPE_UINT32:
    87        case FFI_TYPE_FLOAT:
    88        case FFI_TYPE_POINTER:
    89          *(int *)stack = *(int*)(*argv);
    90          break;
    91  
    92        default: /* 8 byte types */
    93          if (count == 20) /* never split arguments */
    94            {
    95              stack += 4;
    96              count += 4;
    97            }  
    98          s = (*arg)->size;
    99          memcpy(stack, *argv, s);
   100          break;
   101        }
   102  
   103      stack += s;
   104      count += s;
   105      argv++;
   106      arg++;
   107    }
   108    return stacktemp + ((count>24)?24:0);
   109  }
   110  
   111  extern void ffi_call_SYSV(unsigned,
   112                            extended_cif *,
   113                            void *(*)(int *, extended_cif *),
   114                            unsigned *,
   115                            void (*fn)(void),
   116                            unsigned);
   117  
   118  
   119  void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
   120  {
   121    int i;
   122    int size;
   123    ffi_type **arg;
   124  
   125    /* Calculate size to allocate on stack */
   126  
   127    for(i = 0, arg = cif->arg_types, size=0; i < cif->nargs; i++, arg++)
   128      {
   129        if ((*arg)->type == FFI_TYPE_STRUCT)
   130          size += 4;
   131        else
   132        if ((*arg)->size <= 4)
   133          size += 4;
   134        else
   135          size += 8;
   136      }
   137  
   138    /* for variadic functions more space is needed on the stack */
   139    if (cif->nargs != cif->nfixedargs)
   140      size += 24;
   141  
   142    if (cif->rtype->type == FFI_TYPE_STRUCT)
   143      size += 4;
   144  
   145  
   146    extended_cif ecif;
   147    ecif.cif = cif;
   148    ecif.avalue = avalue;
   149    ecif.rvalue = rvalue;
   150  
   151    switch (cif->abi) 
   152    {
   153      case FFI_SYSV:
   154        ffi_call_SYSV(size, &ecif, ffi_prep_args, rvalue, fn, cif->flags);
   155        break;
   156      default:
   157        FFI_ASSERT(0);
   158        break;
   159    }
   160  }
   161  
   162  
   163  void ffi_closure_SYSV(unsigned long r3, unsigned long r4, unsigned long r5, 
   164                        unsigned long r6, unsigned long r7, unsigned long r8)
   165  {
   166    register int *sp __asm__ ("r17");
   167    register int *r13 __asm__ ("r13");
   168  
   169    ffi_closure* closure = (ffi_closure*) r13;
   170    char *stack_args = sp;
   171  
   172    /* Lay the register arguments down in a continuous chunk of memory.  */
   173    unsigned register_args[6] =
   174      { r3, r4, r5, r6, r7, r8 };
   175  
   176    /* Pointer to a struct return value.  */
   177    void *struct_rvalue = (void *) r3;
   178  
   179    ffi_cif *cif = closure->cif;
   180    ffi_type **arg_types = cif->arg_types;
   181    void **avalue = alloca (cif->nargs * sizeof(void *));
   182    char *ptr = (char *) register_args;
   183    int count = 0;
   184    int nfixedargs = cif->nfixedargs;
   185    int i;
   186  
   187    /* preserve struct type return pointer passing */
   188  
   189    if ((cif->rtype != NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) 
   190    {
   191      ptr += 4;
   192      count = 4;
   193    }
   194  
   195    /* Find the address of each argument.  */
   196    for (i = 0; i < cif->nargs; i++)
   197      {
   198  
   199        /* variadic args are saved on stack */
   200        if ((nfixedargs == 0) && (count < 24))
   201          {
   202            ptr = stack_args;
   203            count = 24;
   204          }
   205        nfixedargs--;
   206  
   207        switch (arg_types[i]->type)
   208          {
   209          case FFI_TYPE_SINT8:
   210          case FFI_TYPE_UINT8:
   211            avalue[i] = ptr + 3;
   212            break;
   213  
   214          case FFI_TYPE_SINT16:
   215          case FFI_TYPE_UINT16:
   216            avalue[i] = ptr + 2;
   217            break;
   218  
   219          case FFI_TYPE_SINT32:
   220          case FFI_TYPE_UINT32:
   221          case FFI_TYPE_FLOAT:
   222          case FFI_TYPE_POINTER:
   223            avalue[i] = ptr;
   224            break;
   225  
   226          case FFI_TYPE_STRUCT:
   227            avalue[i] = *(void**)ptr;
   228            break;
   229  
   230          default:
   231            /* 8-byte values  */
   232  
   233            /* arguments are never splitted */
   234            if (ptr == &register_args[5])
   235              ptr = stack_args;
   236            avalue[i] = ptr;
   237            ptr += 4;
   238            count += 4;
   239            break;
   240          }
   241        ptr += 4;
   242        count += 4;
   243  
   244        /* If we've handled more arguments than fit in registers,
   245           start looking at the those passed on the stack.  */
   246  
   247        if (count == 24)
   248          ptr = stack_args;
   249      }
   250  
   251    if (cif->rtype && (cif->rtype->type == FFI_TYPE_STRUCT))
   252      {
   253        (closure->fun) (cif, struct_rvalue, avalue, closure->user_data);
   254      } else
   255      {
   256        long long rvalue;
   257        (closure->fun) (cif, &rvalue, avalue, closure->user_data);
   258        if (cif->rtype)
   259          asm ("l.ori r12, %0, 0x0\n l.lwz r11, 0(r12)\n l.lwz r12, 4(r12)" : : "r" (&rvalue));      
   260      }
   261  }
   262  
   263  
   264  ffi_status
   265  ffi_prep_closure_loc (ffi_closure* closure,
   266                        ffi_cif* cif,
   267                        void (*fun)(ffi_cif*,void*,void**,void*),
   268                        void *user_data,
   269                        void *codeloc)
   270  {
   271    unsigned short *tramp = (unsigned short *) closure->tramp;
   272    unsigned long fn = (unsigned long) ffi_closure_SYSV;
   273    unsigned long cls = (unsigned long) codeloc;
   274  
   275    if (cif->abi != FFI_SYSV)
   276      return FFI_BAD_ABI;
   277  
   278    closure->cif = cif;
   279    closure->user_data = user_data;
   280    closure->fun = fun;
   281  
   282    /* write pointers to temporary registers */
   283    tramp[0] = (0x6 << 10) | (13 << 5); /* l.movhi r13, ... */
   284    tramp[1] = cls >> 16;
   285    tramp[2] = (0x2a << 10) | (13 << 5) | 13; /* l.ori r13, r13, ... */
   286    tramp[3] = cls & 0xFFFF;
   287  
   288    tramp[4] = (0x6 << 10) | (15 << 5); /* l.movhi r15, ... */
   289    tramp[5] = fn >> 16;
   290    tramp[6] = (0x2a << 10) | (15 << 5) | 15; /* l.ori r15, r15 ... */
   291    tramp[7] = fn & 0xFFFF;
   292  
   293    tramp[8] = (0x11 << 10); /* l.jr r15 */
   294    tramp[9] = 15 << 11;
   295  
   296    tramp[10] = (0x2a << 10) | (17 << 5) | 1; /* l.ori r17, r1, ... */
   297    tramp[11] = 0x0;
   298  
   299    return FFI_OK;
   300  }
   301  
   302  
   303  ffi_status ffi_prep_cif_machdep (ffi_cif *cif)
   304  {
   305    cif->flags = 0;
   306  	
   307    /* structures are returned as pointers */
   308    if (cif->rtype->type == FFI_TYPE_STRUCT)
   309      cif->flags = FFI_TYPE_STRUCT;
   310    else 
   311    if (cif->rtype->size > 4)
   312      cif->flags = FFI_TYPE_UINT64;
   313  
   314    cif->nfixedargs = cif->nargs;
   315  
   316    return FFI_OK;
   317  }
   318  
   319  
   320  ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
   321           unsigned int nfixedargs, unsigned int ntotalargs)
   322  {
   323    ffi_status status;
   324  
   325    status = ffi_prep_cif_machdep (cif);
   326    cif->nfixedargs = nfixedargs;
   327    return status;
   328  }