(root)/
gcc-13.2.0/
libffi/
src/
nios2/
ffi.c
       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 *) FFI_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 *) FFI_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