(root)/
gcc-13.2.0/
libffi/
src/
csky/
ffi.c
       1  /* -----------------------------------------------------------------------
       2     ffi.c
       3  
       4     CSKY Foreign Function Interface
       5  
       6     Permission is hereby granted, free of charge, to any person obtaining
       7     a copy of this software and associated documentation files (the
       8     ``Software''), to deal in the Software without restriction, including
       9     without limitation the rights to use, copy, modify, merge, publish,
      10     distribute, sublicense, and/or sell copies of the Software, and to
      11     permit persons to whom the Software is furnished to do so, subject to
      12     the following conditions:
      13  
      14     The above copyright notice and this permission notice shall be included
      15     in all copies or substantial portions of the Software.
      16  
      17     THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
      18     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
      19     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
      20     NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
      21     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
      22     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      23     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
      24     DEALINGS IN THE SOFTWARE.
      25     ----------------------------------------------------------------------- */
      26  
      27  #include <ffi.h>
      28  #include <ffi_common.h>
      29  
      30  #include <stdlib.h>
      31  
      32  /* ffi_prep_args is called by the assembly routine once stack space
      33     has been allocated for the function's arguments
      34  */
      35  void ffi_prep_args(char *stack, extended_cif *ecif)
      36  {
      37   register unsigned int i;
      38   register void **p_argv;
      39   register char *argp;
      40   register ffi_type **p_arg;
      41  
      42   argp = stack;
      43  
      44   if ( ecif->cif->flags == FFI_TYPE_STRUCT ) {
      45    *(void **) argp = ecif->rvalue;
      46    argp += 4;
      47   }
      48  
      49   p_argv = ecif->avalue;
      50  
      51   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
      52     (i != 0);
      53     i--, p_arg++)
      54   {
      55    size_t z;
      56    size_t alignment;
      57  
      58    /* Align if necessary */
      59    alignment = (*p_arg)->alignment;
      60  #ifdef __CSKYABIV1__
      61    /*
      62     * Adapt ABIV1 bug.
      63     * If struct's size is larger than 8 bytes, then it always alignment as 4 bytes.
      64     */
      65    if (((*p_arg)->type == FFI_TYPE_STRUCT) && ((*p_arg)->size > 8) && (alignment == 8)) {
      66     alignment = 4;
      67    }
      68  #endif
      69  
      70    if ((alignment - 1) & (unsigned) argp) {
      71     argp = (char *) FFI_ALIGN(argp, alignment);
      72    }
      73  
      74    if ((*p_arg)->type == FFI_TYPE_STRUCT)
      75     argp = (char *) FFI_ALIGN(argp, 4);
      76  
      77    z = (*p_arg)->size;
      78    if (z < sizeof(int))
      79    {
      80     z = sizeof(int);
      81     switch ((*p_arg)->type)
      82     {
      83     case FFI_TYPE_SINT8:
      84      *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
      85      break;
      86  
      87     case FFI_TYPE_UINT8:
      88      *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
      89      break;
      90  
      91     case FFI_TYPE_SINT16:
      92      *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
      93      break;
      94  
      95     case FFI_TYPE_UINT16:
      96      *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
      97      break;
      98  
      99     case FFI_TYPE_STRUCT:
     100  #ifdef __CSKYBE__
     101      memcpy((argp + 4 - (*p_arg)->size), *p_argv, (*p_arg)->size);
     102  #else
     103      memcpy(argp, *p_argv, (*p_arg)->size);
     104  #endif
     105      break;
     106  
     107     default:
     108      FFI_ASSERT(0);
     109     }
     110    }
     111    else if (z == sizeof(int))
     112    {
     113     *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
     114    }
     115    else
     116    {
     117     memcpy(argp, *p_argv, z);
     118    }
     119    p_argv++;
     120    argp += z;
     121   }
     122  
     123   return;
     124  }
     125  
     126  /* Perform machine dependent cif processing */
     127  ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
     128  {
     129    /* Round the stack up to a multiple of 8 bytes.  This isn't needed
     130       everywhere, but it is on some platforms, and it doesn't hcsky anything
     131       when it isn't needed.  */
     132    cif->bytes = (cif->bytes + 7) & ~7;
     133  
     134    /* Set the return type flag */
     135    switch (cif->rtype->type)
     136      {
     137  
     138      case FFI_TYPE_DOUBLE:
     139      case FFI_TYPE_SINT64:
     140      case FFI_TYPE_UINT64:
     141        cif->flags = (unsigned) FFI_TYPE_SINT64;
     142        break;
     143  
     144      case FFI_TYPE_STRUCT:
     145        if (cif->rtype->size <= 4)
     146   /* A Composite Type not larger than 4 bytes is returned in r0.  */
     147   cif->flags = (unsigned)FFI_TYPE_INT;
     148        else if (cif->rtype->size <= 8)
     149   /* A Composite Type not larger than 8 bytes is returned in r0, r1.  */
     150   cif->flags = (unsigned)FFI_TYPE_SINT64;
     151        else
     152   /* A Composite Type larger than 8 bytes, or whose size cannot
     153      be determined statically ... is stored in memory at an
     154      address passed [in r0].  */
     155   cif->flags = (unsigned)FFI_TYPE_STRUCT;
     156        break;
     157  
     158      default:
     159        cif->flags = FFI_TYPE_INT;
     160        break;
     161      }
     162  
     163    return FFI_OK;
     164  }
     165  
     166  /* Perform machine dependent cif processing for variadic calls */
     167  ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
     168          unsigned int nfixedargs,
     169          unsigned int ntotalargs)
     170  {
     171    return ffi_prep_cif_machdep(cif);
     172  }
     173  
     174  /* Prototypes for assembly functions, in sysv.S */
     175  extern void ffi_call_SYSV (void (*fn)(void), extended_cif *, unsigned, unsigned, unsigned *);
     176  
     177  void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
     178  {
     179    extended_cif ecif;
     180  
     181    int small_struct = (cif->flags == FFI_TYPE_INT
     182          && cif->rtype->type == FFI_TYPE_STRUCT);
     183  
     184    ecif.cif = cif;
     185    ecif.avalue = avalue;
     186  
     187    unsigned int temp;
     188  
     189    /* If the return value is a struct and we don't have a return */
     190    /* value address then we need to make one          */
     191  
     192    if ((rvalue == NULL) &&
     193        (cif->flags == FFI_TYPE_STRUCT))
     194      {
     195        ecif.rvalue = alloca(cif->rtype->size);
     196      }
     197    else if (small_struct)
     198      ecif.rvalue = &temp;
     199    else
     200      ecif.rvalue = rvalue;
     201  
     202    switch (cif->abi)
     203      {
     204      case FFI_SYSV:
     205        ffi_call_SYSV (fn, &ecif, cif->bytes, cif->flags, ecif.rvalue);
     206        break;
     207  
     208      default:
     209        FFI_ASSERT(0);
     210        break;
     211      }
     212    if (small_struct)
     213  #ifdef __CSKYBE__
     214      memcpy (rvalue, ((unsigned char *)&temp + (4 - cif->rtype->size)), cif->rtype->size);
     215  #else
     216      memcpy (rvalue, &temp, cif->rtype->size);
     217  #endif
     218  }
     219  
     220  /** private members **/
     221  
     222  static void ffi_prep_incoming_args_SYSV (char *stack, void **ret,
     223        void** args, ffi_cif* cif);
     224  
     225  void ffi_closure_SYSV (ffi_closure *);
     226  
     227  /* This function is jumped to by the trampoline */
     228  
     229  unsigned int
     230  ffi_closure_SYSV_inner (closure, respp, args)
     231       ffi_closure *closure;
     232       void **respp;
     233       void *args;
     234  {
     235    // our various things...
     236    ffi_cif       *cif;
     237    void         **arg_area;
     238  
     239    cif         = closure->cif;
     240    arg_area    = (void**) alloca (cif->nargs * sizeof (void*));
     241  
     242    /* this call will initialize ARG_AREA, such that each
     243     * element in that array points to the corresponding
     244     * value on the stack; and if the function returns
     245     * a structure, it will re-set RESP to point to the
     246     * structure return address.  */
     247  
     248    ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
     249  
     250    (closure->fun) (cif, *respp, arg_area, closure->user_data);
     251  
     252  #ifdef __CSKYBE__
     253    if (cif->flags == FFI_TYPE_INT && cif->rtype->type == FFI_TYPE_STRUCT) {
     254        unsigned int tmp = 0;
     255        tmp = *(unsigned int *)(*respp);
     256        *(unsigned int *)(*respp) = (tmp >> ((4 - cif->rtype->size) * 8));
     257    }
     258  #endif
     259  
     260    return cif->flags;
     261  }
     262  
     263  
     264  static void
     265  ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
     266         void **avalue, ffi_cif *cif)
     267  {
     268    register unsigned int i;
     269    register void **p_argv;
     270    register char *argp;
     271    register ffi_type **p_arg;
     272  
     273    argp = stack;
     274  
     275    if ( cif->flags == FFI_TYPE_STRUCT ) {
     276      *rvalue = *(void **) argp;
     277      argp += 4;
     278    }
     279  
     280    p_argv = avalue;
     281  
     282    for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
     283      {
     284        size_t z;
     285        size_t alignment;
     286  
     287        alignment = (*p_arg)->alignment;
     288        if (alignment < 4)
     289   alignment = 4;
     290  
     291  #ifdef __CSKYABIV1__
     292        /*
     293         * Adapt ABIV1 bug.
     294         * If struct's size is larger than 8 bytes, then it always alignment as 4 bytes.
     295         */
     296        if (((*p_arg)->type == FFI_TYPE_STRUCT) && ((*p_arg)->size > 8) && (alignment == 8)) {
     297          alignment = 4;
     298        }
     299  #endif
     300  
     301        /* Align if necessary */
     302        if ((alignment - 1) & (unsigned) argp) {
     303   argp = (char *) FFI_ALIGN(argp, alignment);
     304        }
     305  
     306        z = (*p_arg)->size;
     307  
     308  #ifdef __CSKYBE__
     309        unsigned int tmp = 0;
     310        if ((*p_arg)->size < 4) {
     311          tmp = *(unsigned int *)argp;
     312          memcpy(argp, ((unsigned char *)&tmp + (4 - (*p_arg)->size)), (*p_arg)->size);
     313        }
     314  #else
     315        /* because we're little endian, this is what it turns into.   */
     316  #endif
     317        *p_argv = (void*) argp;
     318  
     319        p_argv++;
     320        argp += z;
     321      }
     322  
     323    return;
     324  }
     325  
     326  /* How to make a trampoline.  */
     327  
     328  extern unsigned char ffi_csky_trampoline[TRAMPOLINE_SIZE];
     329  
     330  /*
     331   * Since there is no __clear_cache in libgcc in csky toolchain.
     332   * define ffi_csky_cacheflush in sysv.S.
     333   * void ffi_csky_cacheflush(uint32 start_addr, uint32 size, int cache)
     334   */
     335  #define CACHEFLUSH_IN_FFI 1
     336  #if CACHEFLUSH_IN_FFI
     337  extern void ffi_csky_cacheflush(unsigned char *__tramp, unsigned int k,
     338    int i);
     339  #define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX)                              \
     340  ({ unsigned char *__tramp = (unsigned char*)(TRAMP);                    \
     341     unsigned int  __fun = (unsigned int)(FUN);                           \
     342     unsigned int  __ctx = (unsigned int)(CTX);                           \
     343     unsigned char *insns = (unsigned char *)(CTX);                       \
     344     memcpy (__tramp, ffi_csky_trampoline, TRAMPOLINE_SIZE);              \
     345     *(unsigned int*) &__tramp[TRAMPOLINE_SIZE] = __ctx;                  \
     346     *(unsigned int*) &__tramp[TRAMPOLINE_SIZE + 4] = __fun;              \
     347     ffi_csky_cacheflush(&__tramp[0], TRAMPOLINE_SIZE, 3); /* Clear data mapping.  */ \
     348     ffi_csky_cacheflush(insns, TRAMPOLINE_SIZE, 3);                       \
     349                                                   /* Clear instruction   \
     350                                                      mapping.  */        \
     351   })
     352  #else
     353  #define FFI_INIT_TRAMPOLINE(TRAMP,FUN,CTX)                              \
     354  ({ unsigned char *__tramp = (unsigned char*)(TRAMP);                    \
     355     unsigned int  __fun = (unsigned int)(FUN);                           \
     356     unsigned int  __ctx = (unsigned int)(CTX);                           \
     357     unsigned char *insns = (unsigned char *)(CTX);                       \
     358     memcpy (__tramp, ffi_csky_trampoline, TRAMPOLINE_SIZE);              \
     359     *(unsigned int*) &__tramp[TRAMPOLINE_SIZE] = __ctx;                  \
     360     *(unsigned int*) &__tramp[TRAMPOLINE_SIZE + 4] = __fun;              \
     361     __clear_cache((&__tramp[0]), (&__tramp[TRAMPOLINE_SIZE-1])); /* Clear data mapping.  */ \
     362     __clear_cache(insns, insns + TRAMPOLINE_SIZE);                       \
     363                                                   /* Clear instruction   \
     364                                                      mapping.  */        \
     365   })
     366  #endif
     367  
     368  /* the cif must already be prep'ed */
     369  
     370  ffi_status
     371  ffi_prep_closure_loc (ffi_closure* closure,
     372          ffi_cif* cif,
     373          void (*fun)(ffi_cif*,void*,void**,void*),
     374          void *user_data,
     375          void *codeloc)
     376  {
     377    void (*closure_func)(ffi_closure*) = NULL;
     378  
     379    if (cif->abi == FFI_SYSV)
     380      closure_func = &ffi_closure_SYSV;
     381    else
     382      return FFI_BAD_ABI;
     383  
     384    FFI_INIT_TRAMPOLINE (&closure->tramp[0], \
     385           closure_func,  \
     386           codeloc);
     387  
     388    closure->cif  = cif;
     389    closure->user_data = user_data;
     390    closure->fun  = fun;
     391  
     392    return FFI_OK;
     393  }
     394  
     395