1/* -----------------------------------------------------------------------
2   ffi.c - Copyright (c) 2013 Tensilica, Inc.
3
4   XTENSA 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/*
31                                 |----------------------------------------|
32                                 |                                        |
33    on entry to ffi_call ---->   |----------------------------------------|
34                                 | caller stack frame for registers a0-a3 |
35                                 |----------------------------------------|
36                                 |                                        |
37                                 |         additional arguments           |
38    entry of the function --->   |----------------------------------------|
39                                 |    copy of function arguments a2-a7    |
40                                 | -  -  -  -  -  -  -  -  -  -  -  -  -  |
41                                 |                                        |
42
43    The area below the entry line becomes the new stack frame for the function.
44
45*/
46
47
48#define FFI_TYPE_STRUCT_REGS FFI_TYPE_LAST
49
50
51extern void ffi_call_SYSV(void *rvalue, unsigned rsize, unsigned flags,
52			  void(*fn)(void), unsigned nbytes, extended_cif*);
53extern void ffi_closure_SYSV(void) FFI_HIDDEN;
54
55ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
56{
57  switch(cif->rtype->type) {
58    case FFI_TYPE_SINT8:
59    case FFI_TYPE_UINT8:
60    case FFI_TYPE_SINT16:
61    case FFI_TYPE_UINT16:
62      cif->flags = cif->rtype->type;
63      break;
64    case FFI_TYPE_VOID:
65    case FFI_TYPE_FLOAT:
66      cif->flags = FFI_TYPE_UINT32;
67      break;
68    case FFI_TYPE_DOUBLE:
69    case FFI_TYPE_UINT64:
70    case FFI_TYPE_SINT64:
71      cif->flags = FFI_TYPE_UINT64; // cif->rtype->type;
72      break;
73    case FFI_TYPE_STRUCT:
74      cif->flags = FFI_TYPE_STRUCT; //_REGS;
75      /* Up to 16 bytes are returned in registers */
76      if (cif->rtype->size > 4 * 4) {
77        /* returned structure is referenced by a register; use 8 bytes
78           (including 4 bytes for potential additional alignment) */
79        cif->flags = FFI_TYPE_STRUCT;
80        cif->bytes += 8;
81      }
82      break;
83
84    default:
85      cif->flags = FFI_TYPE_UINT32;
86      break;
87  }
88
89  /* Round the stack up to a full 4 register frame, just in case
90     (we use this size in movsp). This way, it's also a  multiple of
91     8 bytes for 64-bit arguments.  */
92  cif->bytes = ALIGN(cif->bytes, 16);
93
94  return FFI_OK;
95}
96
97void ffi_prep_args(extended_cif *ecif, unsigned char* stack)
98{
99  unsigned int i;
100  unsigned long *addr;
101  ffi_type **ptr;
102
103  union {
104    void **v;
105    char **c;
106    signed char **sc;
107    unsigned char **uc;
108    signed short **ss;
109    unsigned short **us;
110    unsigned int **i;
111    long long **ll;
112    float **f;
113    double **d;
114  } p_argv;
115
116  /* Verify that everything is aligned up properly */
117  FFI_ASSERT (((unsigned long) stack & 0x7) == 0);
118
119  p_argv.v = ecif->avalue;
120  addr = (unsigned long*)stack;
121
122  /* structures with a size greater than 16 bytes are passed in memory */
123  if (ecif->cif->rtype->type == FFI_TYPE_STRUCT && ecif->cif->rtype->size > 16)
124  {
125    *addr++ = (unsigned long)ecif->rvalue;
126  }
127
128  for (i = ecif->cif->nargs, ptr = ecif->cif->arg_types;
129       i > 0;
130       i--, ptr++, p_argv.v++)
131  {
132    switch ((*ptr)->type)
133    {
134      case FFI_TYPE_SINT8:
135        *addr++ = **p_argv.sc;
136        break;
137      case FFI_TYPE_UINT8:
138        *addr++ = **p_argv.uc;
139        break;
140      case FFI_TYPE_SINT16:
141        *addr++ = **p_argv.ss;
142        break;
143      case FFI_TYPE_UINT16:
144        *addr++ = **p_argv.us;
145        break;
146      case FFI_TYPE_FLOAT:
147      case FFI_TYPE_INT:
148      case FFI_TYPE_UINT32:
149      case FFI_TYPE_SINT32:
150      case FFI_TYPE_POINTER:
151        *addr++ = **p_argv.i;
152        break;
153      case FFI_TYPE_DOUBLE:
154      case FFI_TYPE_UINT64:
155      case FFI_TYPE_SINT64:
156        if (((unsigned long)addr & 4) != 0)
157          addr++;
158        *(unsigned long long*)addr = **p_argv.ll;
159	addr += sizeof(unsigned long long) / sizeof (addr);
160        break;
161
162      case FFI_TYPE_STRUCT:
163      {
164        unsigned long offs;
165        unsigned long size;
166
167        if (((unsigned long)addr & 4) != 0 && (*ptr)->alignment > 4)
168          addr++;
169
170        offs = (unsigned long) addr - (unsigned long) stack;
171        size = (*ptr)->size;
172
173        /* Entire structure must fit the argument registers or referenced */
174        if (offs < FFI_REGISTER_NARGS * 4
175            && offs + size > FFI_REGISTER_NARGS * 4)
176          addr = (unsigned long*) (stack + FFI_REGISTER_NARGS * 4);
177
178        memcpy((char*) addr, *p_argv.c, size);
179        addr += (size + 3) / 4;
180        break;
181      }
182
183      default:
184        FFI_ASSERT(0);
185    }
186  }
187}
188
189
190void ffi_call(ffi_cif* cif, void(*fn)(void), void *rvalue, void **avalue)
191{
192  extended_cif ecif;
193  unsigned long rsize = cif->rtype->size;
194  int flags = cif->flags;
195  void *alloc = NULL;
196
197  ecif.cif = cif;
198  ecif.avalue = avalue;
199
200  /* Note that for structures that are returned in registers (size <= 16 bytes)
201     we allocate a temporary buffer and use memcpy to copy it to the final
202     destination. The reason is that the target address might be misaligned or
203     the length not a multiple of 4 bytes. Handling all those cases would be
204     very complex.  */
205
206  if (flags == FFI_TYPE_STRUCT && (rsize <= 16 || rvalue == NULL))
207  {
208    alloc = alloca(ALIGN(rsize, 4));
209    ecif.rvalue = alloc;
210  }
211  else
212  {
213    ecif.rvalue = rvalue;
214  }
215
216  if (cif->abi != FFI_SYSV)
217    FFI_ASSERT(0);
218
219  ffi_call_SYSV (ecif.rvalue, rsize, cif->flags, fn, cif->bytes, &ecif);
220
221  if (alloc != NULL && rvalue != NULL)
222    memcpy(rvalue, alloc, rsize);
223}
224
225extern void ffi_trampoline();
226extern void ffi_cacheflush(void* start, void* end);
227
228ffi_status
229ffi_prep_closure_loc (ffi_closure* closure,
230                      ffi_cif* cif,
231                      void (*fun)(ffi_cif*, void*, void**, void*),
232                      void *user_data,
233                      void *codeloc)
234{
235  /* copye trampoline to stack and patch 'ffi_closure_SYSV' pointer */
236  memcpy(closure->tramp, ffi_trampoline, FFI_TRAMPOLINE_SIZE);
237  *(unsigned int*)(&closure->tramp[8]) = (unsigned int)ffi_closure_SYSV;
238
239  // Do we have this function?
240  // __builtin___clear_cache(closer->tramp, closer->tramp + FFI_TRAMPOLINE_SIZE)
241  ffi_cacheflush(closure->tramp, closure->tramp + FFI_TRAMPOLINE_SIZE);
242
243  closure->cif = cif;
244  closure->fun = fun;
245  closure->user_data = user_data;
246  return FFI_OK;
247}
248
249
250long FFI_HIDDEN
251ffi_closure_SYSV_inner(ffi_closure *closure, void **values, void *rvalue)
252{
253  ffi_cif *cif;
254  ffi_type **arg_types;
255  void **avalue;
256  int i, areg;
257
258  cif = closure->cif;
259  if (cif->abi != FFI_SYSV)
260    return FFI_BAD_ABI;
261
262  areg = 0;
263
264  int rtype = cif->rtype->type;
265  if (rtype == FFI_TYPE_STRUCT && cif->rtype->size > 4 * 4)
266  {
267    rvalue = *values;
268    areg++;
269  }
270
271  cif = closure->cif;
272  arg_types = cif->arg_types;
273  avalue = alloca(cif->nargs * sizeof(void *));
274
275  for (i = 0; i < cif->nargs; i++)
276  {
277    if (arg_types[i]->alignment == 8 && (areg & 1) != 0)
278      areg++;
279
280    // skip the entry 16,a1 framework, add 16 bytes (4 registers)
281    if (areg == FFI_REGISTER_NARGS)
282      areg += 4;
283
284    if (arg_types[i]->type == FFI_TYPE_STRUCT)
285    {
286      int numregs = ((arg_types[i]->size + 3) & ~3) / 4;
287      if (areg < FFI_REGISTER_NARGS && areg + numregs > FFI_REGISTER_NARGS)
288        areg = FFI_REGISTER_NARGS + 4;
289    }
290
291    avalue[i] = &values[areg];
292    areg += (arg_types[i]->size + 3) / 4;
293  }
294
295  (closure->fun)(cif, rvalue, avalue, closure->user_data);
296
297  return rtype;
298}
299