Home | History | Annotate | Download | only in or1k
      1 /* -----------------------------------------------------------------------
      2    ffi.c - Copyright (c) 2014 Sebastian Macke <sebastian (at) 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 }
    329