• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
51 extern void ffi_call_SYSV(void *rvalue, unsigned rsize, unsigned flags,
52 			  void(*fn)(void), unsigned nbytes, extended_cif*);
53 extern void ffi_closure_SYSV(void) FFI_HIDDEN;
54 
ffi_prep_cif_machdep(ffi_cif * cif)55 ffi_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 = FFI_ALIGN(cif->bytes, 16);
93 
94   return FFI_OK;
95 }
96 
ffi_prep_args(extended_cif * ecif,unsigned char * stack)97 void 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 
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)190 void 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(FFI_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 
225 extern void ffi_trampoline();
226 extern void ffi_cacheflush(void* start, void* end);
227 
228 ffi_status
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)229 ffi_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 
250 long FFI_HIDDEN
ffi_closure_SYSV_inner(ffi_closure * closure,void ** values,void * rvalue)251 ffi_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