Home | History | Annotate | Download | only in moxie
      1 /* -----------------------------------------------------------------------
      2    ffi.c - Copyright (C) 2012, 2013  Anthony Green
      3 
      4    Moxie 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 #include <stdlib.h>
     31 
     32 /* ffi_prep_args is called by the assembly routine once stack space
     33    has been allocated for the function's arguments */
     34 
     35 void *ffi_prep_args(char *stack, extended_cif *ecif)
     36 {
     37   register unsigned int i;
     38   register void **p_argv;
     39   register char *argp;
     40   register ffi_type **p_arg;
     41   register int count = 0;
     42 
     43   p_argv = ecif->avalue;
     44   argp = stack;
     45 
     46   if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
     47     {
     48       *(void **) argp = ecif->rvalue;
     49       argp += 4;
     50     }
     51 
     52   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
     53        (i != 0);
     54        i--, p_arg++)
     55     {
     56       size_t z;
     57 
     58       z = (*p_arg)->size;
     59 
     60       if ((*p_arg)->type == FFI_TYPE_STRUCT)
     61 	{
     62 	  z = sizeof(void*);
     63 	  *(void **) argp = *p_argv;
     64 	}
     65       else if (z < sizeof(int))
     66 	{
     67 	  z = sizeof(int);
     68 	  switch ((*p_arg)->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 	    default:
     87 	      FFI_ASSERT(0);
     88 	    }
     89 	}
     90       else if (z == sizeof(int))
     91 	{
     92 	  *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
     93 	}
     94       else
     95 	{
     96 	  memcpy(argp, *p_argv, z);
     97 	}
     98       p_argv++;
     99       argp += z;
    100       count += z;
    101     }
    102 
    103   return (stack + ((count > 24) ? 24 : ALIGN_DOWN(count, 8)));
    104 }
    105 
    106 /* Perform machine dependent cif processing */
    107 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
    108 {
    109   if (cif->rtype->type == FFI_TYPE_STRUCT)
    110     cif->flags = -1;
    111   else
    112     cif->flags = cif->rtype->size;
    113 
    114   cif->bytes = ALIGN (cif->bytes, 8);
    115 
    116   return FFI_OK;
    117 }
    118 
    119 extern void ffi_call_EABI(void *(*)(char *, extended_cif *),
    120 			  extended_cif *,
    121 			  unsigned, unsigned,
    122 			  unsigned *,
    123 			  void (*fn)(void));
    124 
    125 void ffi_call(ffi_cif *cif,
    126 	      void (*fn)(void),
    127 	      void *rvalue,
    128 	      void **avalue)
    129 {
    130   extended_cif ecif;
    131 
    132   ecif.cif = cif;
    133   ecif.avalue = avalue;
    134 
    135   /* If the return value is a struct and we don't have a return	*/
    136   /* value address then we need to make one		        */
    137 
    138   if ((rvalue == NULL) &&
    139       (cif->rtype->type == FFI_TYPE_STRUCT))
    140     {
    141       ecif.rvalue = alloca(cif->rtype->size);
    142     }
    143   else
    144     ecif.rvalue = rvalue;
    145 
    146   switch (cif->abi)
    147     {
    148     case FFI_EABI:
    149       ffi_call_EABI(ffi_prep_args, &ecif, cif->bytes,
    150 		    cif->flags, ecif.rvalue, fn);
    151       break;
    152     default:
    153       FFI_ASSERT(0);
    154       break;
    155     }
    156 }
    157 
    158 void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
    159 		       unsigned arg4, unsigned arg5, unsigned arg6)
    160 {
    161   /* This function is called by a trampoline.  The trampoline stows a
    162      pointer to the ffi_closure object in $r7.  We must save this
    163      pointer in a place that will persist while we do our work.  */
    164   register ffi_closure *creg __asm__ ("$r12");
    165   ffi_closure *closure = creg;
    166 
    167   /* Arguments that don't fit in registers are found on the stack
    168      at a fixed offset above the current frame pointer.  */
    169   register char *frame_pointer __asm__ ("$fp");
    170 
    171   /* Pointer to a struct return value.  */
    172   void *struct_rvalue = (void *) arg1;
    173 
    174   /* 6 words reserved for register args + 3 words from jsr */
    175   char *stack_args = frame_pointer + 9*4;
    176 
    177   /* Lay the register arguments down in a continuous chunk of memory.  */
    178   unsigned register_args[6] =
    179     { arg1, arg2, arg3, arg4, arg5, arg6 };
    180   char *register_args_ptr = (char *) register_args;
    181 
    182   ffi_cif *cif = closure->cif;
    183   ffi_type **arg_types = cif->arg_types;
    184   void **avalue = alloca (cif->nargs * sizeof(void *));
    185   char *ptr = (char *) register_args;
    186   int i;
    187 
    188   /* preserve struct type return pointer passing */
    189   if ((cif->rtype != NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) {
    190     ptr += 4;
    191     register_args_ptr = (char *)&register_args[1];
    192   }
    193 
    194   /* Find the address of each argument.  */
    195   for (i = 0; i < cif->nargs; i++)
    196     {
    197       switch (arg_types[i]->type)
    198 	{
    199 	case FFI_TYPE_SINT8:
    200 	case FFI_TYPE_UINT8:
    201 	  avalue[i] = ptr + 3;
    202 	  break;
    203 	case FFI_TYPE_SINT16:
    204 	case FFI_TYPE_UINT16:
    205 	  avalue[i] = ptr + 2;
    206 	  break;
    207 	case FFI_TYPE_SINT32:
    208 	case FFI_TYPE_UINT32:
    209 	case FFI_TYPE_FLOAT:
    210 	case FFI_TYPE_POINTER:
    211 	  avalue[i] = ptr;
    212 	  break;
    213 	case FFI_TYPE_STRUCT:
    214 	  avalue[i] = *(void**)ptr;
    215 	  break;
    216 	default:
    217 	  /* This is an 8-byte value.  */
    218 	  avalue[i] = ptr;
    219 	  ptr += 4;
    220 	  break;
    221 	}
    222       ptr += 4;
    223 
    224       /* If we've handled more arguments than fit in registers,
    225 	 start looking at the those passed on the stack.  */
    226       if (ptr == &register_args[6])
    227 	ptr = stack_args;
    228     }
    229 
    230   /* Invoke the closure.  */
    231   if (cif->rtype && (cif->rtype->type == FFI_TYPE_STRUCT))
    232     {
    233       (closure->fun) (cif, struct_rvalue, avalue, closure->user_data);
    234     }
    235   else
    236     {
    237       /* Allocate space for the return value and call the function.  */
    238       long long rvalue;
    239       (closure->fun) (cif, &rvalue, avalue, closure->user_data);
    240       asm ("mov $r12, %0\n ld.l $r0, ($r12)\n ldo.l $r1, 4($r12)" : : "r" (&rvalue));
    241     }
    242 }
    243 
    244 ffi_status
    245 ffi_prep_closure_loc (ffi_closure* closure,
    246 		      ffi_cif* cif,
    247 		      void (*fun)(ffi_cif*, void*, void**, void*),
    248 		      void *user_data,
    249 		      void *codeloc)
    250 {
    251   unsigned short *tramp = (unsigned short *) &closure->tramp[0];
    252   unsigned long fn = (long) ffi_closure_eabi;
    253   unsigned long cls = (long) codeloc;
    254 
    255   if (cif->abi != FFI_EABI)
    256     return FFI_BAD_ABI;
    257 
    258   fn = (unsigned long) ffi_closure_eabi;
    259 
    260   tramp[0] = 0x01e0; /* ldi.l $r7, .... */
    261   tramp[1] = cls >> 16;
    262   tramp[2] = cls & 0xffff;
    263   tramp[3] = 0x1a00; /* jmpa .... */
    264   tramp[4] = fn >> 16;
    265   tramp[5] = fn & 0xffff;
    266 
    267   closure->cif = cif;
    268   closure->fun = fun;
    269   closure->user_data = user_data;
    270 
    271   return FFI_OK;
    272 }
    273