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

     1  /* -----------------------------------------------------------------------
     2     ffi.c - Copyright (c) 2011  Anthony Green
     3             Copyright (c) 2009  Bradley Smith <brad@brad-smith.co.uk>
     4  
     5     AVR32 Foreign Function Interface
     6  
     7     Permission is hereby granted, free of charge, to any person obtaining
     8     a copy of this software and associated documentation files (the
     9     ``Software''), to deal in the Software without restriction, including
    10     without limitation the rights to use, copy, modify, merge, publish,
    11     distribute, sublicense, and/or sell copies of the Software, and to
    12     permit persons to whom the Software is furnished to do so, subject to
    13     the following conditions:
    14  
    15     The above copyright notice and this permission notice shall be included
    16     in all copies or substantial portions of the Software.
    17  
    18     THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
    19     EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
    20     MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
    21     NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
    22     HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
    23     WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    24     OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
    25     DEALINGS IN THE SOFTWARE.
    26     ----------------------------------------------------------------------- */
    27  
    28  #include <ffi.h>
    29  #include <ffi_common.h>
    30  
    31  #include <stdlib.h>
    32  #include <stdio.h>
    33  #include <unistd.h>
    34  #include <asm/unistd.h>
    35  
    36  /* #define DEBUG */
    37  
    38  extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
    39      unsigned int, unsigned int, unsigned int*, unsigned int,
    40      void (*fn)(void));
    41  extern void ffi_closure_SYSV (ffi_closure *);
    42  
    43  unsigned int pass_struct_on_stack(ffi_type *type)
    44  {
    45      if(type->type != FFI_TYPE_STRUCT)
    46          return 0;
    47  
    48      if(type->alignment < type->size &&
    49          !(type->size == 4 || type->size == 8) &&
    50          !(type->size == 8 && type->alignment >= 4))
    51          return 1;
    52  
    53      if(type->size == 3 || type->size == 5 || type->size == 6 ||
    54          type->size == 7)
    55          return 1;
    56  
    57      return 0;
    58  }
    59  
    60  /* ffi_prep_args is called by the assembly routine once stack space
    61   * has been allocated for the function's arguments
    62   *
    63   * This is annoyingly complex since we need to keep track of used
    64   * registers.
    65   */
    66  
    67  void ffi_prep_args(char *stack, extended_cif *ecif)
    68  {
    69      unsigned int i;
    70      void **p_argv;
    71      ffi_type **p_arg;
    72      char *reg_base = stack;
    73      char *stack_base = stack + 20;
    74      unsigned int stack_offset = 0;
    75      unsigned int reg_mask = 0;
    76  
    77      p_argv = ecif->avalue;
    78  
    79      /* If cif->flags is struct then we know it's not passed in registers */
    80      if(ecif->cif->flags == FFI_TYPE_STRUCT)
    81      {
    82          *(void**)reg_base = ecif->rvalue;
    83          reg_mask |= 1;
    84      }
    85  
    86      for(i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs;
    87          i++, p_arg++)
    88      {
    89          size_t z = (*p_arg)->size;
    90          int alignment = (*p_arg)->alignment;
    91          int type = (*p_arg)->type;
    92          char *addr = 0;
    93  
    94          if(z % 4 != 0)
    95              z += (4 - z % 4);
    96  
    97          if(reg_mask != 0x1f)
    98          {
    99              if(pass_struct_on_stack(*p_arg))
   100              {
   101                  addr = stack_base + stack_offset;
   102                  stack_offset += z;
   103              }
   104              else if(z == sizeof(int))
   105              {
   106                  char index = 0;
   107  
   108                  while((reg_mask >> index) & 1)
   109                      index++;
   110  
   111                  addr = reg_base + (index * 4);
   112                  reg_mask |= (1 << index);
   113              }
   114              else if(z == 2 * sizeof(int))
   115              {
   116                  if(!((reg_mask >> 1) & 1))
   117                  {
   118                      addr = reg_base + 4;
   119                      reg_mask |= (3 << 1);
   120                  }
   121                  else if(!((reg_mask >> 3) & 1))
   122                  {
   123                      addr = reg_base + 12;
   124                      reg_mask |= (3 << 3);
   125                  }
   126              }
   127          }
   128  
   129          if(!addr)
   130          {
   131              addr = stack_base + stack_offset;
   132              stack_offset += z;
   133          }
   134  
   135          if(type == FFI_TYPE_STRUCT && (*p_arg)->elements[1] == NULL)
   136              type = (*p_arg)->elements[0]->type;
   137  
   138          switch(type)
   139          {
   140          case FFI_TYPE_UINT8:
   141              *(unsigned int *)addr = (unsigned int)*(UINT8 *)(*p_argv);
   142              break;
   143          case FFI_TYPE_SINT8:
   144              *(signed int *)addr = (signed int)*(SINT8 *)(*p_argv);
   145              break;
   146          case FFI_TYPE_UINT16:
   147              *(unsigned int *)addr = (unsigned int)*(UINT16 *)(*p_argv);
   148              break;
   149          case FFI_TYPE_SINT16:
   150              *(signed int *)addr = (signed int)*(SINT16 *)(*p_argv);
   151              break;
   152          default:
   153              memcpy(addr, *p_argv, z);
   154          }
   155  
   156          p_argv++;
   157      }
   158  
   159  #ifdef DEBUG
   160      /* Debugging */
   161      for(i = 0; i < 5; i++)
   162      {
   163          if((reg_mask & (1 << i)) == 0)
   164              printf("r%d: (unused)\n", 12 - i);
   165          else
   166              printf("r%d: 0x%08x\n", 12 - i, ((unsigned int*)reg_base)[i]);
   167      }
   168  
   169      for(i = 0; i < stack_offset / 4; i++)
   170      {
   171          printf("sp+%d: 0x%08x\n", i*4, ((unsigned int*)stack_base)[i]);
   172      }
   173  #endif
   174  }
   175  
   176  /* Perform machine dependent cif processing */
   177  ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
   178  {
   179      /* Round the stack up to a multiple of 8 bytes.  This isn't needed
   180       * everywhere, but it is on some platforms, and it doesn't harm
   181       * anything when it isn't needed. */
   182      cif->bytes = (cif->bytes + 7) & ~7;
   183  
   184      /* Flag to indicate that he return value is in fact a struct */
   185      cif->rstruct_flag = 0;
   186  
   187      /* Set the return type flag */
   188      switch(cif->rtype->type)
   189      {
   190      case FFI_TYPE_SINT8:
   191      case FFI_TYPE_UINT8:
   192          cif->flags = (unsigned)FFI_TYPE_UINT8;
   193          break;
   194      case FFI_TYPE_SINT16:
   195      case FFI_TYPE_UINT16:
   196          cif->flags = (unsigned)FFI_TYPE_UINT16;
   197          break;
   198      case FFI_TYPE_FLOAT:
   199      case FFI_TYPE_SINT32:
   200      case FFI_TYPE_UINT32:
   201      case FFI_TYPE_POINTER:
   202          cif->flags = (unsigned)FFI_TYPE_UINT32;
   203          break;
   204      case FFI_TYPE_DOUBLE:
   205      case FFI_TYPE_SINT64:
   206      case FFI_TYPE_UINT64:
   207          cif->flags = (unsigned)FFI_TYPE_UINT64;
   208          break;
   209      case FFI_TYPE_STRUCT:
   210          cif->rstruct_flag = 1;
   211          if(!pass_struct_on_stack(cif->rtype))
   212          {
   213              if(cif->rtype->size <= 1)
   214                  cif->flags = (unsigned)FFI_TYPE_UINT8;
   215              else if(cif->rtype->size <= 2)
   216                  cif->flags = (unsigned)FFI_TYPE_UINT16;
   217              else if(cif->rtype->size <= 4)
   218                  cif->flags = (unsigned)FFI_TYPE_UINT32;
   219              else if(cif->rtype->size <= 8)
   220                  cif->flags = (unsigned)FFI_TYPE_UINT64;
   221              else
   222                  cif->flags = (unsigned)cif->rtype->type;
   223          }
   224          else
   225              cif->flags = (unsigned)cif->rtype->type;
   226          break;
   227      default:
   228          cif->flags = (unsigned)cif->rtype->type;
   229          break;
   230      }
   231  
   232      return FFI_OK;
   233  }
   234  
   235  void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
   236  {
   237      extended_cif ecif;
   238  
   239      unsigned int size = 0, i = 0;
   240      ffi_type **p_arg;
   241  
   242      ecif.cif = cif;
   243      ecif.avalue = avalue;
   244  
   245      for(i = 0, p_arg = cif->arg_types; i < cif->nargs; i++, p_arg++)
   246          size += (*p_arg)->size + (4 - (*p_arg)->size % 4);
   247  
   248      /* If the return value is a struct and we don't have a return value
   249       * address then we need to make one */
   250  
   251      /* If cif->flags is struct then it's not suitable for registers */
   252      if((rvalue == NULL) && (cif->flags == FFI_TYPE_STRUCT))
   253          ecif.rvalue = alloca(cif->rtype->size);
   254      else
   255          ecif.rvalue = rvalue;
   256  
   257      switch(cif->abi)
   258      {
   259      case FFI_SYSV:
   260          ffi_call_SYSV(ffi_prep_args, &ecif, size, cif->flags,
   261              ecif.rvalue, cif->rstruct_flag, fn);
   262          break;
   263      default:
   264          FFI_ASSERT(0);
   265          break;
   266      }
   267  }
   268  
   269  static void ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
   270      void **avalue, ffi_cif *cif)
   271  {
   272      register unsigned int i, reg_mask = 0;
   273      register void **p_argv;
   274      register ffi_type **p_arg;
   275      register char *reg_base = stack;
   276      register char *stack_base = stack + 20;
   277      register unsigned int stack_offset = 0;
   278  
   279  #ifdef DEBUG
   280      /* Debugging */
   281      for(i = 0; i < cif->nargs + 7; i++)
   282      {
   283          printf("sp+%d: 0x%08x\n", i*4, ((unsigned int*)stack)[i]);
   284      }
   285  #endif
   286  
   287      /* If cif->flags is struct then we know it's not passed in registers */
   288      if(cif->flags == FFI_TYPE_STRUCT)
   289      {
   290          *rvalue = *(void **)reg_base;
   291          reg_mask |= 1;
   292      }
   293  
   294      p_argv = avalue;
   295  
   296      for(i = 0, p_arg = cif->arg_types; i < cif->nargs; i++, p_arg++)
   297      {
   298          size_t z = (*p_arg)->size;
   299          int alignment = (*p_arg)->alignment;
   300  
   301          *p_argv = 0;
   302  
   303          if(z % 4 != 0)
   304              z += (4 - z % 4);
   305  
   306          if(reg_mask != 0x1f)
   307          {
   308              if(pass_struct_on_stack(*p_arg))
   309              {
   310                  *p_argv = (void*)stack_base + stack_offset;
   311                  stack_offset += z;
   312              }
   313              else if(z <= sizeof(int))
   314              {
   315                  char index = 0;
   316  
   317                  while((reg_mask >> index) & 1)
   318                      index++;
   319  
   320                  *p_argv = (void*)reg_base + (index * 4);
   321                  reg_mask |= (1 << index);
   322              }
   323              else if(z == 2 * sizeof(int))
   324              {
   325                  if(!((reg_mask >> 1) & 1))
   326                  {
   327                      *p_argv = (void*)reg_base + 4;
   328                      reg_mask |= (3 << 1);
   329                  }
   330                  else if(!((reg_mask >> 3) & 1))
   331                  {
   332                      *p_argv = (void*)reg_base + 12;
   333                      reg_mask |= (3 << 3);
   334                  }
   335              }
   336          }
   337  
   338          if(!*p_argv)
   339          {
   340              *p_argv = (void*)stack_base + stack_offset;
   341              stack_offset += z;
   342          }
   343  
   344          if((*p_arg)->type != FFI_TYPE_STRUCT ||
   345              (*p_arg)->elements[1] == NULL)
   346          {
   347              if(alignment == 1)
   348                  **(unsigned int**)p_argv <<= 24;
   349              else if(alignment == 2)
   350                  **(unsigned int**)p_argv <<= 16;
   351          }
   352  
   353          p_argv++;
   354      }
   355  
   356  #ifdef DEBUG
   357      /* Debugging */
   358      for(i = 0; i < cif->nargs; i++)
   359      {
   360          printf("sp+%d: 0x%08x\n", i*4, *(((unsigned int**)avalue)[i]));
   361      }
   362  #endif
   363  }
   364  
   365  /* This function is jumped to by the trampoline */
   366  
   367  unsigned int ffi_closure_SYSV_inner(ffi_closure *closure, void **respp,
   368      void *args)
   369  {
   370      ffi_cif *cif;
   371      void **arg_area;
   372      unsigned int i, size = 0;
   373      ffi_type **p_arg;
   374  
   375      cif = closure->cif;
   376  
   377      for(i = 0, p_arg = cif->arg_types; i < cif->nargs; i++, p_arg++)
   378          size += (*p_arg)->size + (4 - (*p_arg)->size % 4);
   379  
   380      arg_area = (void **)alloca(size);
   381  
   382      /* this call will initialize ARG_AREA, such that each element in that
   383       * array points to the corresponding value on the stack; and if the
   384       * function returns a structure, it will re-set RESP to point to the
   385       * structure return address. */
   386  
   387      ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
   388  
   389      (closure->fun)(cif, *respp, arg_area, closure->user_data);
   390  
   391      return cif->flags;
   392  }
   393  
   394  ffi_status ffi_prep_closure_loc(ffi_closure* closure, ffi_cif* cif,
   395      void (*fun)(ffi_cif*, void*, void**, void*), void *user_data,
   396      void *codeloc)
   397  {
   398      if (cif->abi != FFI_SYSV)
   399        return FFI_BAD_ABI;
   400  
   401      unsigned char *__tramp = (unsigned char*)(&closure->tramp[0]);
   402      unsigned int  __fun = (unsigned int)(&ffi_closure_SYSV);
   403      unsigned int  __ctx = (unsigned int)(codeloc);
   404      unsigned int  __rstruct_flag = (unsigned int)(cif->rstruct_flag);
   405      unsigned int  __inner = (unsigned int)(&ffi_closure_SYSV_inner);
   406      *(unsigned int*) &__tramp[0] = 0xebcd1f00;    /* pushm  r8-r12 */
   407      *(unsigned int*) &__tramp[4] = 0xfefc0010;    /* ld.w   r12, pc[16] */
   408      *(unsigned int*) &__tramp[8] = 0xfefb0010;    /* ld.w   r11, pc[16] */
   409      *(unsigned int*) &__tramp[12] = 0xfefa0010;   /* ld.w   r10, pc[16] */
   410      *(unsigned int*) &__tramp[16] = 0xfeff0010;   /* ld.w   pc, pc[16] */
   411      *(unsigned int*) &__tramp[20] = __ctx;
   412      *(unsigned int*) &__tramp[24] = __rstruct_flag;
   413      *(unsigned int*) &__tramp[28] = __inner;
   414      *(unsigned int*) &__tramp[32] = __fun;
   415      syscall(__NR_cacheflush, 0, (&__tramp[0]), 36);
   416  
   417      closure->cif = cif;
   418      closure->user_data = user_data;
   419      closure->fun  = fun;
   420  
   421      return FFI_OK;
   422  }
   423