github.com/prattmic/llgo-embedded@v0.0.0-20150820070356-41cfecea0e1e/third_party/gofrontend/libffi/src/m88k/ffi.c (about)

     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 *) 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  }