1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2012, 2013 Xilinx, Inc
3
4 MicroBlaze 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 extern void ffi_call_SYSV(void (*)(void*, extended_cif*), extended_cif*,
31 unsigned int, unsigned int, unsigned int*, void (*fn)(void),
32 unsigned int, unsigned int);
33
34 extern void ffi_closure_SYSV(void);
35
36 #define WORD_SIZE sizeof(unsigned int)
37 #define ARGS_REGISTER_SIZE (WORD_SIZE * 6)
38 #define WORD_FFI_ALIGN(x) FFI_ALIGN(x, WORD_SIZE)
39
40 /* ffi_prep_args is called by the assembly routine once stack space
41 has been allocated for the function's arguments */
ffi_prep_args(void * stack,extended_cif * ecif)42 void ffi_prep_args(void* stack, extended_cif* ecif)
43 {
44 unsigned int i;
45 ffi_type** p_arg;
46 void** p_argv;
47 void* stack_args_p = stack;
48
49 if (ecif == NULL || ecif->cif == NULL) {
50 return; /* no description to prepare */
51 }
52
53 p_argv = ecif->avalue;
54
55 if ((ecif->cif->rtype != NULL) &&
56 (ecif->cif->rtype->type == FFI_TYPE_STRUCT))
57 {
58 /* if return type is a struct which is referenced on the stack/reg5,
59 * by a pointer. Stored the return value pointer in r5.
60 */
61 char* addr = stack_args_p;
62 memcpy(addr, &(ecif->rvalue), WORD_SIZE);
63 stack_args_p += WORD_SIZE;
64 }
65
66 if (ecif->avalue == NULL) {
67 return; /* no arguments to prepare */
68 }
69
70 for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs;
71 i++, p_arg++)
72 {
73 size_t size = (*p_arg)->size;
74 int type = (*p_arg)->type;
75 void* value = p_argv[i];
76 char* addr = stack_args_p;
77 int aligned_size = WORD_FFI_ALIGN(size);
78
79 /* force word alignment on the stack */
80 stack_args_p += aligned_size;
81
82 switch (type)
83 {
84 case FFI_TYPE_UINT8:
85 *(unsigned int *)addr = (unsigned int)*(UINT8*)(value);
86 break;
87 case FFI_TYPE_SINT8:
88 *(signed int *)addr = (signed int)*(SINT8*)(value);
89 break;
90 case FFI_TYPE_UINT16:
91 *(unsigned int *)addr = (unsigned int)*(UINT16*)(value);
92 break;
93 case FFI_TYPE_SINT16:
94 *(signed int *)addr = (signed int)*(SINT16*)(value);
95 break;
96 case FFI_TYPE_STRUCT:
97 #if __BIG_ENDIAN__
98 /*
99 * MicroBlaze toolchain appears to emit:
100 * bsrli r5, r5, 8 (caller)
101 * ...
102 * <branch to callee>
103 * ...
104 * bslli r5, r5, 8 (callee)
105 *
106 * For structs like "struct a { uint8_t a[3]; };", when passed
107 * by value.
108 *
109 * Structs like "struct b { uint16_t a; };" are also expected
110 * to be packed strangely in registers.
111 *
112 * This appears to be because the microblaze toolchain expects
113 * "struct b == uint16_t", which is only any issue for big
114 * endian.
115 *
116 * The following is a work around for big-endian only, for the
117 * above mentioned case, it will re-align the contents of a
118 * <= 3-byte struct value.
119 */
120 if (size < WORD_SIZE)
121 {
122 memcpy (addr + (WORD_SIZE - size), value, size);
123 break;
124 }
125 #endif
126 case FFI_TYPE_SINT32:
127 case FFI_TYPE_UINT32:
128 case FFI_TYPE_FLOAT:
129 case FFI_TYPE_SINT64:
130 case FFI_TYPE_UINT64:
131 case FFI_TYPE_DOUBLE:
132 default:
133 memcpy(addr, value, aligned_size);
134 }
135 }
136 }
137
ffi_prep_cif_machdep(ffi_cif * cif)138 ffi_status ffi_prep_cif_machdep(ffi_cif* cif)
139 {
140 /* check ABI */
141 switch (cif->abi)
142 {
143 case FFI_SYSV:
144 break;
145 default:
146 return FFI_BAD_ABI;
147 }
148 return FFI_OK;
149 }
150
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)151 void ffi_call(ffi_cif* cif, void (*fn)(void), void* rvalue, void** avalue)
152 {
153 extended_cif ecif;
154 ecif.cif = cif;
155 ecif.avalue = avalue;
156
157 /* If the return value is a struct and we don't have a return */
158 /* value address then we need to make one */
159 if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) {
160 ecif.rvalue = alloca(cif->rtype->size);
161 } else {
162 ecif.rvalue = rvalue;
163 }
164
165 switch (cif->abi)
166 {
167 case FFI_SYSV:
168 ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags,
169 ecif.rvalue, fn, cif->rtype->type, cif->rtype->size);
170 break;
171 default:
172 FFI_ASSERT(0);
173 break;
174 }
175 }
176
ffi_closure_call_SYSV(void * register_args,void * stack_args,ffi_closure * closure,void * rvalue,unsigned int * rtype,unsigned int * rsize)177 void ffi_closure_call_SYSV(void* register_args, void* stack_args,
178 ffi_closure* closure, void* rvalue,
179 unsigned int* rtype, unsigned int* rsize)
180 {
181 /* prepare arguments for closure call */
182 ffi_cif* cif = closure->cif;
183 ffi_type** arg_types = cif->arg_types;
184
185 /* re-allocate data for the args. This needs to be done in order to keep
186 * multi-word objects (e.g. structs) in contiguous memory. Callers are not
187 * required to store the value of args in the lower 6 words in the stack
188 * (although they are allocated in the stack).
189 */
190 char* stackclone = alloca(cif->bytes);
191 void** avalue = alloca(cif->nargs * sizeof(void*));
192 void* struct_rvalue = NULL;
193 char* ptr = stackclone;
194 int i;
195
196 /* copy registers into stack clone */
197 int registers_used = cif->bytes;
198 if (registers_used > ARGS_REGISTER_SIZE) {
199 registers_used = ARGS_REGISTER_SIZE;
200 }
201 memcpy(stackclone, register_args, registers_used);
202
203 /* copy stack allocated args into stack clone */
204 if (cif->bytes > ARGS_REGISTER_SIZE) {
205 int stack_used = cif->bytes - ARGS_REGISTER_SIZE;
206 memcpy(stackclone + ARGS_REGISTER_SIZE, stack_args, stack_used);
207 }
208
209 /* preserve struct type return pointer passing */
210 if ((cif->rtype != NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) {
211 struct_rvalue = *((void**)ptr);
212 ptr += WORD_SIZE;
213 }
214
215 /* populate arg pointer list */
216 for (i = 0; i < cif->nargs; i++)
217 {
218 switch (arg_types[i]->type)
219 {
220 case FFI_TYPE_SINT8:
221 case FFI_TYPE_UINT8:
222 #ifdef __BIG_ENDIAN__
223 avalue[i] = ptr + 3;
224 #else
225 avalue[i] = ptr;
226 #endif
227 break;
228 case FFI_TYPE_SINT16:
229 case FFI_TYPE_UINT16:
230 #ifdef __BIG_ENDIAN__
231 avalue[i] = ptr + 2;
232 #else
233 avalue[i] = ptr;
234 #endif
235 break;
236 case FFI_TYPE_STRUCT:
237 #if __BIG_ENDIAN__
238 /*
239 * Work around strange ABI behaviour.
240 * (see info in ffi_prep_args)
241 */
242 if (arg_types[i]->size < WORD_SIZE)
243 {
244 memcpy (ptr, ptr + (WORD_SIZE - arg_types[i]->size), arg_types[i]->size);
245 }
246 #endif
247 avalue[i] = (void*)ptr;
248 break;
249 case FFI_TYPE_UINT64:
250 case FFI_TYPE_SINT64:
251 case FFI_TYPE_DOUBLE:
252 avalue[i] = ptr;
253 break;
254 case FFI_TYPE_SINT32:
255 case FFI_TYPE_UINT32:
256 case FFI_TYPE_FLOAT:
257 default:
258 /* default 4-byte argument */
259 avalue[i] = ptr;
260 break;
261 }
262 ptr += WORD_FFI_ALIGN(arg_types[i]->size);
263 }
264
265 /* set the return type info passed back to the wrapper */
266 *rsize = cif->rtype->size;
267 *rtype = cif->rtype->type;
268 if (struct_rvalue != NULL) {
269 closure->fun(cif, struct_rvalue, avalue, closure->user_data);
270 /* copy struct return pointer value into function return value */
271 *((void**)rvalue) = struct_rvalue;
272 } else {
273 closure->fun(cif, rvalue, avalue, closure->user_data);
274 }
275 }
276
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)277 ffi_status ffi_prep_closure_loc(
278 ffi_closure* closure, ffi_cif* cif,
279 void (*fun)(ffi_cif*, void*, void**, void*),
280 void* user_data, void* codeloc)
281 {
282 unsigned long* tramp = (unsigned long*)&(closure->tramp[0]);
283 unsigned long cls = (unsigned long)codeloc;
284 unsigned long fn = 0;
285 unsigned long fn_closure_call_sysv = (unsigned long)ffi_closure_call_SYSV;
286
287 closure->cif = cif;
288 closure->fun = fun;
289 closure->user_data = user_data;
290
291 switch (cif->abi)
292 {
293 case FFI_SYSV:
294 fn = (unsigned long)ffi_closure_SYSV;
295
296 /* load r11 (temp) with fn */
297 /* imm fn(upper) */
298 tramp[0] = 0xb0000000 | ((fn >> 16) & 0xffff);
299 /* addik r11, r0, fn(lower) */
300 tramp[1] = 0x31600000 | (fn & 0xffff);
301
302 /* load r12 (temp) with cls */
303 /* imm cls(upper) */
304 tramp[2] = 0xb0000000 | ((cls >> 16) & 0xffff);
305 /* addik r12, r0, cls(lower) */
306 tramp[3] = 0x31800000 | (cls & 0xffff);
307
308 /* load r3 (temp) with ffi_closure_call_SYSV */
309 /* imm fn_closure_call_sysv(upper) */
310 tramp[4] = 0xb0000000 | ((fn_closure_call_sysv >> 16) & 0xffff);
311 /* addik r3, r0, fn_closure_call_sysv(lower) */
312 tramp[5] = 0x30600000 | (fn_closure_call_sysv & 0xffff);
313 /* branch/jump to address stored in r11 (fn) */
314 tramp[6] = 0x98085800; /* bra r11 */
315
316 break;
317 default:
318 return FFI_BAD_ABI;
319 }
320 return FFI_OK;
321 }
322