1  /*
       2   * Copyright (c) 2013 Miodrag Vallat.  <miod@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 *) FFI_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 = FFI_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 *) FFI_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 = FFI_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  }