Home | History | Annotate | Download | only in vax
      1 /*
      2  * Copyright (c) 2013 Miodrag Vallat.  <miod (at) openbsd.org>
      3  *
      4  * Permission is hereby granted, free of charge, to any person obtaining
      5  * a copy of this software and associated documentation files (the
      6  * ``Software''), to deal in the Software without restriction, including
      7  * without limitation the rights to use, copy, modify, merge, publish,
      8  * distribute, sublicense, and/or sell copies of the Software, and to
      9  * permit persons to whom the Software is furnished to do so, subject to
     10  * the following conditions:
     11  *
     12  * The above copyright notice and this permission notice shall be included
     13  * in all copies or substantial portions of the Software.
     14  *
     15  * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
     16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
     18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
     19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
     20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
     21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     22  */
     23 
     24 /*
     25  * vax Foreign Function Interface
     26  *
     27  * This file attempts to provide all the FFI entry points which can reliably
     28  * be implemented in C.
     29  */
     30 
     31 #include <ffi.h>
     32 #include <ffi_common.h>
     33 
     34 #include <stdlib.h>
     35 #include <unistd.h>
     36 
     37 #define CIF_FLAGS_CHAR		1	/* for struct only */
     38 #define CIF_FLAGS_SHORT		2	/* for struct only */
     39 #define CIF_FLAGS_INT		4
     40 #define CIF_FLAGS_DINT		8
     41 
     42 /*
     43  * Foreign Function Interface API
     44  */
     45 
     46 void ffi_call_elfbsd (extended_cif *, unsigned, unsigned, void *,
     47 		       void (*) ());
     48 void *ffi_prep_args (extended_cif *ecif, void *stack);
     49 
     50 void *
     51 ffi_prep_args (extended_cif *ecif, void *stack)
     52 {
     53   unsigned int i;
     54   void **p_argv;
     55   char *argp;
     56   ffi_type **p_arg;
     57   void *struct_value_ptr;
     58 
     59   argp = stack;
     60 
     61   if (ecif->cif->rtype->type == FFI_TYPE_STRUCT
     62       && !ecif->cif->flags)
     63     struct_value_ptr = ecif->rvalue;
     64   else
     65     struct_value_ptr = NULL;
     66 
     67   p_argv = ecif->avalue;
     68 
     69   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
     70        i != 0;
     71        i--, p_arg++)
     72     {
     73       size_t z;
     74 
     75       z = (*p_arg)->size;
     76       if (z < sizeof (int))
     77 	{
     78 	  switch ((*p_arg)->type)
     79 	    {
     80 	    case FFI_TYPE_SINT8:
     81 	      *(signed int *) argp = (signed int) *(SINT8 *) *p_argv;
     82 	      break;
     83 
     84 	    case FFI_TYPE_UINT8:
     85 	      *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv;
     86 	      break;
     87 
     88 	    case FFI_TYPE_SINT16:
     89 	      *(signed int *) argp = (signed int) *(SINT16 *) *p_argv;
     90 	      break;
     91 
     92 	    case FFI_TYPE_UINT16:
     93 	      *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv;
     94 	      break;
     95 
     96 	    case FFI_TYPE_STRUCT:
     97 	      memcpy (argp, *p_argv, z);
     98 	      break;
     99 
    100 	    default:
    101 	      FFI_ASSERT (0);
    102 	    }
    103 	  z = sizeof (int);
    104 	}
    105       else
    106 	{
    107 	  memcpy (argp, *p_argv, z);
    108 
    109 	  /* Align if necessary.  */
    110 	  if ((sizeof(int) - 1) & z)
    111 	    z = ALIGN(z, sizeof(int));
    112 	}
    113 
    114       p_argv++;
    115       argp += z;
    116     }
    117 
    118   return struct_value_ptr;
    119 }
    120 
    121 ffi_status
    122 ffi_prep_cif_machdep (ffi_cif *cif)
    123 {
    124   /* Set the return type flag */
    125   switch (cif->rtype->type)
    126     {
    127     case FFI_TYPE_VOID:
    128       cif->flags = 0;
    129       break;
    130 
    131     case FFI_TYPE_STRUCT:
    132       if (cif->rtype->elements[0]->type == FFI_TYPE_STRUCT &&
    133 	  cif->rtype->elements[1])
    134 	{
    135 	  cif->flags = 0;
    136 	  break;
    137 	}
    138 
    139       if (cif->rtype->size == sizeof (char))
    140 	cif->flags = CIF_FLAGS_CHAR;
    141       else if (cif->rtype->size == sizeof (short))
    142 	cif->flags = CIF_FLAGS_SHORT;
    143       else if (cif->rtype->size == sizeof (int))
    144 	cif->flags = CIF_FLAGS_INT;
    145       else if (cif->rtype->size == 2 * sizeof (int))
    146 	cif->flags = CIF_FLAGS_DINT;
    147       else
    148 	cif->flags = 0;
    149       break;
    150 
    151     default:
    152       if (cif->rtype->size <= sizeof (int))
    153 	cif->flags = CIF_FLAGS_INT;
    154       else
    155 	cif->flags = CIF_FLAGS_DINT;
    156       break;
    157     }
    158 
    159   return FFI_OK;
    160 }
    161 
    162 void
    163 ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue)
    164 {
    165   extended_cif ecif;
    166 
    167   ecif.cif = cif;
    168   ecif.avalue = avalue;
    169 
    170   /* If the return value is a struct and we don't have a return value
    171      address then we need to make one.  */
    172 
    173   if (rvalue == NULL
    174       && cif->rtype->type == FFI_TYPE_STRUCT
    175       && cif->flags == 0)
    176     ecif.rvalue = alloca (cif->rtype->size);
    177   else
    178     ecif.rvalue = rvalue;
    179 
    180   switch (cif->abi)
    181     {
    182     case FFI_ELFBSD:
    183       ffi_call_elfbsd (&ecif, cif->bytes, cif->flags, ecif.rvalue, fn);
    184       break;
    185 
    186     default:
    187       FFI_ASSERT (0);
    188       break;
    189     }
    190 }
    191 
    192 /*
    193  * Closure API
    194  */
    195 
    196 void ffi_closure_elfbsd (void);
    197 void ffi_closure_struct_elfbsd (void);
    198 unsigned int ffi_closure_elfbsd_inner (ffi_closure *, void *, char *);
    199 
    200 static void
    201 ffi_prep_closure_elfbsd (ffi_cif *cif, void **avalue, char *stackp)
    202 {
    203   unsigned int i;
    204   void **p_argv;
    205   ffi_type **p_arg;
    206 
    207   p_argv = avalue;
    208 
    209   for (i = cif->nargs, p_arg = cif->arg_types; i != 0; i--, p_arg++)
    210     {
    211       size_t z;
    212 
    213       z = (*p_arg)->size;
    214       *p_argv = stackp;
    215 
    216       /* Align if necessary */
    217       if ((sizeof (int) - 1) & z)
    218 	z = ALIGN(z, sizeof (int));
    219 
    220       p_argv++;
    221       stackp += z;
    222     }
    223 }
    224 
    225 unsigned int
    226 ffi_closure_elfbsd_inner (ffi_closure *closure, void *resp, char *stack)
    227 {
    228   ffi_cif *cif;
    229   void **arg_area;
    230 
    231   cif = closure->cif;
    232   arg_area = (void **) alloca (cif->nargs * sizeof (void *));
    233 
    234   ffi_prep_closure_elfbsd (cif, arg_area, stack);
    235 
    236   (closure->fun) (cif, resp, arg_area, closure->user_data);
    237 
    238   return cif->flags;
    239 }
    240 
    241 ffi_status
    242 ffi_prep_closure_loc (ffi_closure *closure, ffi_cif *cif,
    243 		      void (*fun)(ffi_cif *, void *, void **, void *),
    244 		      void *user_data, void *codeloc)
    245 {
    246   char *tramp = (char *) codeloc;
    247   void *fn;
    248 
    249   FFI_ASSERT (cif->abi == FFI_ELFBSD);
    250 
    251   /* entry mask */
    252   *(unsigned short *)(tramp + 0) = 0x0000;
    253   /* movl #closure, r0 */
    254   tramp[2] = 0xd0;
    255   tramp[3] = 0x8f;
    256   *(unsigned int *)(tramp + 4) = (unsigned int) closure;
    257   tramp[8] = 0x50;
    258 
    259   if (cif->rtype->type == FFI_TYPE_STRUCT
    260       && !cif->flags)
    261     fn = &ffi_closure_struct_elfbsd;
    262   else
    263     fn = &ffi_closure_elfbsd;
    264 
    265   /* jmpl #fn */
    266   tramp[9] = 0x17;
    267   tramp[10] = 0xef;
    268   *(unsigned int *)(tramp + 11) = (unsigned int)fn + 2 -
    269 				  (unsigned int)tramp - 9 - 6;
    270 
    271   closure->cif = cif;
    272   closure->user_data = user_data;
    273   closure->fun = fun;
    274 
    275   return FFI_OK;
    276 }
    277