Home | History | Annotate | Download | only in m88k
      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  * m88k 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  * Only OpenBSD/m88k is currently supported; other platforms (such as
     31  * Motorola's SysV/m88k) could be supported with the following tweaks:
     32  *
     33  * - non-OpenBSD systems use an `outgoing parameter area' as part of the
     34  *   88BCS calling convention, which is not supported under OpenBSD from
     35  *   release 3.6 onwards.  Supporting it should be as easy as taking it
     36  *   into account when adjusting the stack, in the assembly code.
     37  *
     38  * - the logic deciding whether a function argument gets passed through
     39  *   registers, or on the stack, has changed several times in OpenBSD in
     40  *   edge cases (especially for structs larger than 32 bytes being passed
     41  *   by value). The code below attemps to match the logic used by the
     42  *   system compiler of OpenBSD 5.3, i.e. gcc 3.3.6 with many m88k backend
     43  *   fixes.
     44  */
     45 
     46 #include <ffi.h>
     47 #include <ffi_common.h>
     48 
     49 #include <stdlib.h>
     50 #include <unistd.h>
     51 
     52 void ffi_call_OBSD (unsigned int, extended_cif *, unsigned int, void *,
     53 		    void (*fn) ());
     54 void *ffi_prep_args (void *, extended_cif *);
     55 void ffi_closure_OBSD (ffi_closure *);
     56 void ffi_closure_struct_OBSD (ffi_closure *);
     57 unsigned int ffi_closure_OBSD_inner (ffi_closure *, void *, unsigned int *,
     58 				     char *);
     59 void ffi_cacheflush_OBSD (unsigned int, unsigned int);
     60 
     61 #define CIF_FLAGS_INT		(1 << 0)
     62 #define CIF_FLAGS_DINT		(1 << 1)
     63 
     64 /*
     65  * Foreign Function Interface API
     66  */
     67 
     68 /* ffi_prep_args is called by the assembly routine once stack space has
     69    been allocated for the function's arguments.  */
     70 
     71 void *
     72 ffi_prep_args (void *stack, extended_cif *ecif)
     73 {
     74   unsigned int i;
     75   void **p_argv;
     76   char *argp, *stackp;
     77   unsigned int *regp;
     78   unsigned int regused;
     79   ffi_type **p_arg;
     80   void *struct_value_ptr;
     81 
     82   regp = (unsigned int *)stack;
     83   stackp = (char *)(regp + 8);
     84   regused = 0;
     85 
     86   if (ecif->cif->rtype->type == FFI_TYPE_STRUCT
     87       && !ecif->cif->flags)
     88     struct_value_ptr = ecif->rvalue;
     89   else
     90     struct_value_ptr = NULL;
     91 
     92   p_argv = ecif->avalue;
     93 
     94   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i != 0; i--, p_arg++)
     95     {
     96       size_t z;
     97       unsigned short t, a;
     98 
     99       z = (*p_arg)->size;
    100       t = (*p_arg)->type;
    101       a = (*p_arg)->alignment;
    102 
    103       /*
    104        * Figure out whether the argument can be passed through registers
    105        * or on the stack.
    106        * The rule is that registers can only receive simple types not larger
    107        * than 64 bits, or structs the exact size of a register and aligned to
    108        * the size of a register.
    109        */
    110       if (t == FFI_TYPE_STRUCT)
    111 	{
    112 	  if (z == sizeof (int) && a == sizeof (int) && regused < 8)
    113 	    argp = (char *)regp;
    114 	  else
    115 	    argp = stackp;
    116 	}
    117       else
    118 	{
    119 	  if (z > sizeof (int) && regused < 8 - 1)
    120 	    {
    121 	      /* align to an even register pair */
    122 	      if (regused & 1)
    123 		{
    124 		  regp++;
    125 		  regused++;
    126 		}
    127 	    }
    128 	  if (regused < 8)
    129 	    argp = (char *)regp;
    130 	  else
    131 	    argp = stackp;
    132 	}
    133 
    134       /* Enforce proper stack alignment of 64-bit types */
    135       if (argp == stackp && a > sizeof (int))
    136 	{
    137 	  stackp = (char *) ALIGN(stackp, a);
    138 	  argp = stackp;
    139 	}
    140 
    141       switch (t)
    142 	{
    143 	case FFI_TYPE_SINT8:
    144 	  *(signed int *) argp = (signed int) *(SINT8 *) *p_argv;
    145 	  break;
    146 
    147 	case FFI_TYPE_UINT8:
    148 	  *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv;
    149 	  break;
    150 
    151 	case FFI_TYPE_SINT16:
    152 	  *(signed int *) argp = (signed int) *(SINT16 *) *p_argv;
    153 	  break;
    154 
    155 	case FFI_TYPE_UINT16:
    156 	  *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv;
    157 	  break;
    158 
    159 	case FFI_TYPE_INT:
    160 	case FFI_TYPE_FLOAT:
    161 	case FFI_TYPE_UINT32:
    162 	case FFI_TYPE_SINT32:
    163 	case FFI_TYPE_POINTER:
    164 	  *(unsigned int *) argp = *(unsigned int *) *p_argv;
    165 	  break;
    166 
    167 	case FFI_TYPE_DOUBLE:
    168 	case FFI_TYPE_UINT64:
    169 	case FFI_TYPE_SINT64:
    170 	case FFI_TYPE_STRUCT:
    171 	  memcpy (argp, *p_argv, z);
    172 	  break;
    173 
    174 	default:
    175 	  FFI_ASSERT (0);
    176 	}
    177 
    178       /* Align if necessary.  */
    179       if ((sizeof (int) - 1) & z)
    180 	z = ALIGN(z, sizeof (int));
    181 
    182       p_argv++;
    183 
    184       /* Be careful, once all registers are filled, and about to continue
    185          on stack, regp == stackp.  Therefore the check for regused as well. */
    186       if (argp == (char *)regp && regused < 8)
    187 	{
    188 	  regp += z / sizeof (int);
    189 	  regused += z / sizeof (int);
    190 	}
    191       else
    192 	stackp += z;
    193     }
    194 
    195   return struct_value_ptr;
    196 }
    197 
    198 /* Perform machine dependent cif processing */
    199 ffi_status
    200 ffi_prep_cif_machdep (ffi_cif *cif)
    201 {
    202   /* Set the return type flag */
    203   switch (cif->rtype->type)
    204     {
    205     case FFI_TYPE_VOID:
    206       cif->flags = 0;
    207       break;
    208 
    209     case FFI_TYPE_STRUCT:
    210       if (cif->rtype->size == sizeof (int) &&
    211 	  cif->rtype->alignment == sizeof (int))
    212 	cif->flags = CIF_FLAGS_INT;
    213       else
    214 	cif->flags = 0;
    215       break;
    216 
    217     case FFI_TYPE_DOUBLE:
    218     case FFI_TYPE_SINT64:
    219     case FFI_TYPE_UINT64:
    220       cif->flags = CIF_FLAGS_DINT;
    221       break;
    222 
    223     default:
    224       cif->flags = CIF_FLAGS_INT;
    225       break;
    226     }
    227 
    228   return FFI_OK;
    229 }
    230 
    231 void
    232 ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue)
    233 {
    234   extended_cif ecif;
    235 
    236   ecif.cif = cif;
    237   ecif.avalue = avalue;
    238 
    239   /* If the return value is a struct and we don't have a return value
    240      address then we need to make one.  */
    241 
    242   if (rvalue == NULL
    243       && cif->rtype->type == FFI_TYPE_STRUCT
    244       && (cif->rtype->size != sizeof (int)
    245 	  || cif->rtype->alignment != sizeof (int)))
    246     ecif.rvalue = alloca (cif->rtype->size);
    247   else
    248     ecif.rvalue = rvalue;
    249 
    250   switch (cif->abi)
    251     {
    252     case FFI_OBSD:
    253       ffi_call_OBSD (cif->bytes, &ecif, cif->flags, ecif.rvalue, fn);
    254       break;
    255 
    256     default:
    257       FFI_ASSERT (0);
    258       break;
    259     }
    260 }
    261 
    262 /*
    263  * Closure API
    264  */
    265 
    266 static void
    267 ffi_prep_closure_args_OBSD (ffi_cif *cif, void **avalue, unsigned int *regp,
    268 			    char *stackp)
    269 {
    270   unsigned int i;
    271   void **p_argv;
    272   char *argp;
    273   unsigned int regused;
    274   ffi_type **p_arg;
    275 
    276   regused = 0;
    277 
    278   p_argv = avalue;
    279 
    280   for (i = cif->nargs, p_arg = cif->arg_types; i != 0; i--, p_arg++)
    281     {
    282       size_t z;
    283       unsigned short t, a;
    284 
    285       z = (*p_arg)->size;
    286       t = (*p_arg)->type;
    287       a = (*p_arg)->alignment;
    288 
    289       /*
    290        * Figure out whether the argument has been passed through registers
    291        * or on the stack.
    292        * The rule is that registers can only receive simple types not larger
    293        * than 64 bits, or structs the exact size of a register and aligned to
    294        * the size of a register.
    295        */
    296       if (t == FFI_TYPE_STRUCT)
    297 	{
    298 	  if (z == sizeof (int) && a == sizeof (int) && regused < 8)
    299 	    argp = (char *)regp;
    300 	  else
    301 	    argp = stackp;
    302 	}
    303       else
    304 	{
    305 	  if (z > sizeof (int) && regused < 8 - 1)
    306 	    {
    307 	      /* align to an even register pair */
    308 	      if (regused & 1)
    309 		{
    310 		  regp++;
    311 		  regused++;
    312 		}
    313 	    }
    314 	  if (regused < 8)
    315 	    argp = (char *)regp;
    316 	  else
    317 	    argp = stackp;
    318 	}
    319 
    320       /* Enforce proper stack alignment of 64-bit types */
    321       if (argp == stackp && a > sizeof (int))
    322 	{
    323 	  stackp = (char *) ALIGN(stackp, a);
    324 	  argp = stackp;
    325 	}
    326 
    327       if (z < sizeof (int) && t != FFI_TYPE_STRUCT)
    328 	*p_argv = (void *) (argp + sizeof (int) - z);
    329       else
    330 	*p_argv = (void *) argp;
    331 
    332       /* Align if necessary */
    333       if ((sizeof (int) - 1) & z)
    334 	z = ALIGN(z, sizeof (int));
    335 
    336       p_argv++;
    337 
    338       /* Be careful, once all registers are exhausted, and about to fetch from
    339 	 stack, regp == stackp.  Therefore the check for regused as well. */
    340       if (argp == (char *)regp && regused < 8)
    341 	{
    342 	  regp += z / sizeof (int);
    343 	  regused += z / sizeof (int);
    344 	}
    345       else
    346 	stackp += z;
    347     }
    348 }
    349 
    350 unsigned int
    351 ffi_closure_OBSD_inner (ffi_closure *closure, void *resp, unsigned int *regp,
    352 			char *stackp)
    353 {
    354   ffi_cif *cif;
    355   void **arg_area;
    356 
    357   cif = closure->cif;
    358   arg_area = (void**) alloca (cif->nargs * sizeof (void *));
    359 
    360   ffi_prep_closure_args_OBSD(cif, arg_area, regp, stackp);
    361 
    362   (closure->fun) (cif, resp, arg_area, closure->user_data);
    363 
    364   return cif->flags;
    365 }
    366 
    367 ffi_status
    368 ffi_prep_closure_loc (ffi_closure* closure, ffi_cif* cif,
    369 		      void (*fun)(ffi_cif*,void*,void**,void*),
    370 		      void *user_data, void *codeloc)
    371 {
    372   unsigned int *tramp = (unsigned int *) codeloc;
    373   void *fn;
    374 
    375   FFI_ASSERT (cif->abi == FFI_OBSD);
    376 
    377   if (cif->rtype->type == FFI_TYPE_STRUCT && !cif->flags)
    378     fn = &ffi_closure_struct_OBSD;
    379   else
    380     fn = &ffi_closure_OBSD;
    381 
    382   /* or.u %r10, %r0, %hi16(fn) */
    383   tramp[0] = 0x5d400000 | (((unsigned int)fn) >> 16);
    384   /* or.u %r13, %r0, %hi16(closure) */
    385   tramp[1] = 0x5da00000 | ((unsigned int)closure >> 16);
    386   /* or %r10, %r10, %lo16(fn) */
    387   tramp[2] = 0x594a0000 | (((unsigned int)fn) & 0xffff);
    388   /* jmp.n %r10 */
    389   tramp[3] = 0xf400c40a;
    390   /* or %r13, %r13, %lo16(closure) */
    391   tramp[4] = 0x59ad0000 | ((unsigned int)closure & 0xffff);
    392 
    393   ffi_cacheflush_OBSD((unsigned int)codeloc, FFI_TRAMPOLINE_SIZE);
    394 
    395   closure->cif  = cif;
    396   closure->user_data = user_data;
    397   closure->fun  = fun;
    398 
    399   return FFI_OK;
    400 }
    401