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

     1  /* libffi support for Altera Nios II.
     2  
     3     Copyright (c) 2013 Mentor Graphics.
     4  
     5     Permission is hereby granted, free of charge, to any person obtaining
     6     a copy of this software and associated documentation files (the
     7     ``Software''), to deal in the Software without restriction, including
     8     without limitation the rights to use, copy, modify, merge, publish,
     9     distribute, sublicense, and/or sell copies of the Software, and to
    10     permit persons to whom the Software is furnished to do so, subject to
    11     the following conditions:
    12     
    13     The above copyright notice and this permission notice shall be
    14     included in all copies or substantial portions of the Software.
    15     
    16     THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
    17     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    18     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
    19     IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
    20     CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
    21     TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
    22     SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
    23  
    24  
    25  #include <ffi.h>
    26  #include <ffi_common.h>
    27  
    28  #include <stdlib.h>
    29  
    30  /* The Nios II Processor Reference Handbook defines the procedure call
    31     ABI as follows.
    32  
    33     Arguments are passed as if a structure containing the types of
    34     the arguments were constructed.  The first 16 bytes are passed in r4
    35     through r7, the remainder on the stack.  The first 16 bytes of a function
    36     taking variable arguments are passed in r4-r7 in the same way.
    37  
    38     Return values of types up to 8 bytes are returned in r2 and r3.  For
    39     return values greater than 8 bytes, the caller must allocate memory for
    40     the result and pass the address as if it were argument 0.  
    41  
    42     While this isn't specified explicitly in the ABI documentation, GCC
    43     promotes integral arguments smaller than int size to 32 bits.
    44  
    45     Also of note, the ABI specifies that all structure objects are
    46     aligned to 32 bits even if all their fields have a smaller natural
    47     alignment.  See FFI_AGGREGATE_ALIGNMENT.  */
    48  
    49  
    50  /* Declare the assembly language hooks.  */
    51  
    52  extern UINT64 ffi_call_sysv (void (*) (char *, extended_cif *),
    53  			     extended_cif *,
    54  			     unsigned, 
    55  			     void (*fn) (void));
    56  extern void ffi_closure_sysv (void);
    57  
    58  /* Perform machine-dependent cif processing.  */
    59  
    60  ffi_status ffi_prep_cif_machdep (ffi_cif *cif)
    61  {
    62    /* We always want at least 16 bytes in the parameter block since it
    63       simplifies the low-level call function.  Also round the parameter
    64       block size up to a multiple of 4 bytes to preserve
    65       32-bit alignment of the stack pointer.  */
    66    if (cif->bytes < 16)
    67      cif->bytes = 16;
    68    else
    69      cif->bytes = (cif->bytes + 3) & ~3;
    70  
    71    return FFI_OK;
    72  }
    73  
    74  
    75  /* ffi_prep_args is called by the assembly routine to transfer arguments
    76     to the stack using the pointers in the ecif array.
    77     Note that the stack buffer is big enough to fit all the arguments,
    78     but the first 16 bytes will be copied to registers for the actual
    79     call.  */
    80  
    81  void ffi_prep_args (char *stack, extended_cif *ecif)
    82  {
    83    char *argp = stack;
    84    unsigned int i;
    85  
    86    /* The implicit return value pointer is passed as if it were a hidden
    87       first argument.  */
    88    if (ecif->cif->rtype->type == FFI_TYPE_STRUCT
    89        && ecif->cif->rtype->size > 8)
    90      {
    91        (*(void **) argp) = ecif->rvalue;
    92        argp += 4;
    93      }
    94  
    95    for (i = 0; i < ecif->cif->nargs; i++)
    96      {
    97        void *avalue = ecif->avalue[i];
    98        ffi_type *atype = ecif->cif->arg_types[i];
    99        size_t size = atype->size;
   100        size_t alignment = atype->alignment;
   101  
   102        /* Align argp as appropriate for the argument type.  */
   103        if ((alignment - 1) & (unsigned) argp)
   104  	argp = (char *) ALIGN (argp, alignment);
   105  
   106        /* Copy the argument, promoting integral types smaller than a
   107  	 word to word size.  */
   108        if (size < sizeof (int))
   109  	{
   110  	  size = sizeof (int);
   111  	  switch (atype->type)
   112  	    {
   113  	    case FFI_TYPE_SINT8:
   114  	      *(signed int *) argp = (signed int) *(SINT8 *) avalue;
   115  	      break;
   116  		  
   117  	    case FFI_TYPE_UINT8:
   118  	      *(unsigned int *) argp = (unsigned int) *(UINT8 *) avalue;
   119  	      break;
   120  		  
   121  	    case FFI_TYPE_SINT16:
   122  	      *(signed int *) argp = (signed int) *(SINT16 *) avalue;
   123  	      break;
   124  		  
   125  	    case FFI_TYPE_UINT16:
   126  	      *(unsigned int *) argp = (unsigned int) *(UINT16 *) avalue;
   127  	      break;
   128  
   129  	    case FFI_TYPE_STRUCT:
   130  	      memcpy (argp, avalue, atype->size);
   131  	      break;
   132  
   133  	    default:
   134  	      FFI_ASSERT(0);
   135  	    }
   136  	}
   137        else if (size == sizeof (int))
   138  	*(unsigned int *) argp = (unsigned int) *(UINT32 *) avalue;
   139        else
   140  	memcpy (argp, avalue, size);
   141        argp += size;
   142      }
   143  }
   144  
   145  
   146  /* Call FN using the prepared CIF.  RVALUE points to space allocated by
   147     the caller for the return value, and AVALUE is an array of argument
   148     pointers.  */
   149  
   150  void ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue)
   151  {
   152  
   153    extended_cif ecif;
   154    UINT64 result;
   155  
   156    /* If bigret is true, this is the case where a return value of larger
   157       than 8 bytes is handled by being passed by reference as an implicit
   158       argument.  */
   159    int bigret = (cif->rtype->type == FFI_TYPE_STRUCT
   160  		&& cif->rtype->size > 8);
   161  
   162    ecif.cif = cif;
   163    ecif.avalue = avalue;
   164  
   165    /* Allocate space for return value if this is the pass-by-reference case
   166       and the caller did not provide a buffer.  */
   167    if (rvalue == NULL && bigret)
   168      ecif.rvalue = alloca (cif->rtype->size);
   169    else
   170      ecif.rvalue = rvalue;
   171  
   172    result = ffi_call_sysv (ffi_prep_args, &ecif, cif->bytes, fn);
   173  
   174    /* Now result contains the 64 bit contents returned from fn in
   175       r2 and r3.  Copy the value of the appropriate size to the user-provided
   176       rvalue buffer.  */
   177    if (rvalue && !bigret)
   178      switch (cif->rtype->size)
   179        {
   180        case 1:
   181  	*(UINT8 *)rvalue = (UINT8) result;
   182  	break;
   183        case 2:
   184  	*(UINT16 *)rvalue = (UINT16) result;
   185  	break;
   186        case 4:
   187  	*(UINT32 *)rvalue = (UINT32) result;
   188  	break;
   189        case 8:
   190  	*(UINT64 *)rvalue = (UINT64) result;
   191  	break;
   192        default:
   193  	memcpy (rvalue, (void *)&result, cif->rtype->size);
   194  	break;
   195        }
   196  }
   197  
   198  /* This function is invoked from the closure trampoline to invoke
   199     CLOSURE with argument block ARGS.  Parse ARGS according to
   200     CLOSURE->cfi and invoke CLOSURE->fun.  */
   201  
   202  static UINT64
   203  ffi_closure_helper (unsigned char *args,
   204  		    ffi_closure *closure)
   205  {
   206    ffi_cif *cif = closure->cif;
   207    unsigned char *argp = args;
   208    void **parsed_args = alloca (cif->nargs * sizeof (void *));
   209    UINT64 result;
   210    void *retptr;
   211    unsigned int i;
   212  
   213    /* First figure out what to do about the return type.  If this is the
   214       big-structure-return case, the first arg is the hidden return buffer
   215       allocated by the caller.  */
   216    if (cif->rtype->type == FFI_TYPE_STRUCT
   217        && cif->rtype->size > 8)
   218      {
   219        retptr = *((void **) argp);
   220        argp += 4;
   221      }
   222    else
   223      retptr = (void *) &result;
   224  
   225    /* Fill in the array of argument pointers.  */
   226    for (i = 0; i < cif->nargs; i++)
   227      {
   228        size_t size = cif->arg_types[i]->size;
   229        size_t alignment = cif->arg_types[i]->alignment;
   230  
   231        /* Align argp as appropriate for the argument type.  */
   232        if ((alignment - 1) & (unsigned) argp)
   233  	argp = (char *) ALIGN (argp, alignment);
   234  
   235        /* Arguments smaller than an int are promoted to int.  */
   236        if (size < sizeof (int))
   237  	size = sizeof (int);
   238  
   239        /* Store the pointer.  */
   240        parsed_args[i] = argp;
   241        argp += size;
   242      }
   243  
   244    /* Call the user-supplied function.  */
   245    (closure->fun) (cif, retptr, parsed_args, closure->user_data);
   246    return result;
   247  }
   248  
   249  
   250  /* Initialize CLOSURE with a trampoline to call FUN with
   251     CIF and USER_DATA.  */
   252  ffi_status
   253  ffi_prep_closure_loc (ffi_closure* closure,
   254  		      ffi_cif* cif,
   255  		      void (*fun) (ffi_cif*, void*, void**, void*),
   256  		      void *user_data,
   257  		      void *codeloc)
   258  {
   259    unsigned int *tramp = (unsigned int *) &closure->tramp[0];
   260    int i;
   261  
   262    if (cif->abi != FFI_SYSV)
   263      return FFI_BAD_ABI;
   264  
   265    /* The trampoline looks like:
   266         movhi r8, %hi(ffi_closure_sysv)
   267         ori r8, r8, %lo(ffi_closure_sysv)
   268         movhi r9, %hi(ffi_closure_helper)
   269         ori r0, r9, %lo(ffi_closure_helper)
   270         movhi r10, %hi(closure)
   271         ori r10, r10, %lo(closure)
   272         jmp r8
   273       and then ffi_closure_sysv retrieves the closure pointer out of r10
   274       in addition to the arguments passed in the normal way for the call,
   275       and invokes ffi_closure_helper.  We encode the pointer to
   276       ffi_closure_helper in the trampoline because making a PIC call
   277       to it in ffi_closure_sysv would be messy (it would have to indirect
   278       through the GOT).  */
   279  
   280  #define HI(x) ((((unsigned int) (x)) >> 16) & 0xffff)
   281  #define LO(x) (((unsigned int) (x)) & 0xffff)
   282    tramp[0] = (0 << 27) | (8 << 22) | (HI (ffi_closure_sysv) << 6) | 0x34;
   283    tramp[1] = (8 << 27) | (8 << 22) | (LO (ffi_closure_sysv) << 6) | 0x14;
   284    tramp[2] = (0 << 27) | (9 << 22) | (HI (ffi_closure_helper) << 6) | 0x34;
   285    tramp[3] = (9 << 27) | (9 << 22) | (LO (ffi_closure_helper) << 6) | 0x14;
   286    tramp[4] = (0 << 27) | (10 << 22) | (HI (closure) << 6) | 0x34;
   287    tramp[5] = (10 << 27) | (10 << 22) | (LO (closure) << 6) | 0x14;
   288    tramp[6] = (8 << 27) | (0x0d << 11) | 0x3a;
   289  #undef HI
   290  #undef LO
   291  
   292    /* Flush the caches.
   293       See Example 9-4 in the Nios II Software Developer's Handbook.  */
   294    for (i = 0; i < 7; i++)
   295      asm volatile ("flushd 0(%0); flushi %0" :: "r"(tramp + i) : "memory");
   296    asm volatile ("flushp" ::: "memory");
   297  
   298    closure->cif = cif;
   299    closure->fun = fun;
   300    closure->user_data = user_data;
   301  
   302    return FFI_OK;
   303  }
   304