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