1 /* -----------------------------------------------------------------------
2 ffi.c - Copyright (c) 2012, 2013 Xilinx, Inc
4 MicroBlaze Foreign Function Interface
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:
14 The above copyright notice and this permission notice shall be included
15 in all copies or substantial portions of the Software.
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 ----------------------------------------------------------------------- */
28 #include <ffi_common.h>
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);
34 extern void ffi_closure_SYSV(void);
36 #define WORD_SIZE sizeof(unsigned int)
37 #define ARGS_REGISTER_SIZE (WORD_SIZE * 6)
38 #define WORD_ALIGN(x) ALIGN(x, WORD_SIZE)
40 /* ffi_prep_args is called by the assembly routine once stack space
41 has been allocated for the function's arguments */
42 void ffi_prep_args(void* stack
, extended_cif
* ecif
)
47 void* stack_args_p
= stack
;
49 p_argv
= ecif
->avalue
;
51 if (ecif
== NULL
|| ecif
->cif
== NULL
) {
52 return; /* no description to prepare */
55 if ((ecif
->cif
->rtype
!= NULL
) &&
56 (ecif
->cif
->rtype
->type
== FFI_TYPE_STRUCT
))
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.
61 char* addr
= stack_args_p
;
62 memcpy(addr
, &(ecif
->rvalue
), WORD_SIZE
);
63 stack_args_p
+= WORD_SIZE
;
66 if (ecif
->avalue
== NULL
) {
67 return; /* no arguments to prepare */
70 for (i
= 0, p_arg
= ecif
->cif
->arg_types
; i
< ecif
->cif
->nargs
;
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_ALIGN(size
);
79 /* force word alignment on the stack */
80 stack_args_p
+= aligned_size
;
85 *(unsigned int *)addr
= (unsigned int)*(UINT8
*)(value
);
88 *(signed int *)addr
= (signed int)*(SINT8
*)(value
);
91 *(unsigned int *)addr
= (unsigned int)*(UINT16
*)(value
);
94 *(signed int *)addr
= (signed int)*(SINT16
*)(value
);
99 * MicroBlaze toolchain appears to emit:
100 * bsrli r5, r5, 8 (caller)
104 * bslli r5, r5, 8 (callee)
106 * For structs like "struct a { uint8_t a[3]; };", when passed
109 * Structs like "struct b { uint16_t a; };" are also expected
110 * to be packed strangely in registers.
112 * This appears to be because the microblaze toolchain expects
113 * "struct b == uint16_t", which is only any issue for big
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.
120 if (size
< WORD_SIZE
)
122 memcpy (addr
+ (WORD_SIZE
- size
), value
, size
);
126 case FFI_TYPE_SINT32
:
127 case FFI_TYPE_UINT32
:
129 case FFI_TYPE_SINT64
:
130 case FFI_TYPE_UINT64
:
131 case FFI_TYPE_DOUBLE
:
133 memcpy(addr
, value
, aligned_size
);
138 ffi_status
ffi_prep_cif_machdep(ffi_cif
* cif
)
151 void ffi_call(ffi_cif
* cif
, void (*fn
)(void), void* rvalue
, void** avalue
)
155 ecif
.avalue
= avalue
;
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
);
162 ecif
.rvalue
= rvalue
;
168 ffi_call_SYSV(ffi_prep_args
, &ecif
, cif
->bytes
, cif
->flags
,
169 ecif
.rvalue
, fn
, cif
->rtype
->type
, cif
->rtype
->size
);
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
)
181 /* prepare arguments for closure call */
182 ffi_cif
* cif
= closure
->cif
;
183 ffi_type
** arg_types
= cif
->arg_types
;
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).
190 char* stackclone
= alloca(cif
->bytes
);
191 void** avalue
= alloca(cif
->nargs
* sizeof(void*));
192 void* struct_rvalue
= NULL
;
193 char* ptr
= stackclone
;
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
;
201 memcpy(stackclone
, register_args
, registers_used
);
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
);
209 /* preserve struct type return pointer passing */
210 if ((cif
->rtype
!= NULL
) && (cif
->rtype
->type
== FFI_TYPE_STRUCT
)) {
211 struct_rvalue
= *((void**)ptr
);
215 /* populate arg pointer list */
216 for (i
= 0; i
< cif
->nargs
; i
++)
218 switch (arg_types
[i
]->type
)
222 #ifdef __BIG_ENDIAN__
228 case FFI_TYPE_SINT16
:
229 case FFI_TYPE_UINT16
:
230 #ifdef __BIG_ENDIAN__
236 case FFI_TYPE_STRUCT
:
239 * Work around strange ABI behaviour.
240 * (see info in ffi_prep_args)
242 if (arg_types
[i
]->size
< WORD_SIZE
)
244 memcpy (ptr
, ptr
+ (WORD_SIZE
- arg_types
[i
]->size
), arg_types
[i
]->size
);
247 avalue
[i
] = (void*)ptr
;
249 case FFI_TYPE_UINT64
:
250 case FFI_TYPE_SINT64
:
251 case FFI_TYPE_DOUBLE
:
254 case FFI_TYPE_SINT32
:
255 case FFI_TYPE_UINT32
:
258 /* default 4-byte argument */
262 ptr
+= WORD_ALIGN(arg_types
[i
]->size
);
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
;
273 closure
->fun(cif
, rvalue
, avalue
, closure
->user_data
);
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
)
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
;
289 closure
->user_data
= user_data
;
294 fn
= (unsigned long)ffi_closure_SYSV
;
296 /* load r11 (temp) with fn */
298 tramp
[0] = 0xb0000000 | ((fn
>> 16) & 0xffff);
299 /* addik r11, r0, fn(lower) */
300 tramp
[1] = 0x31600000 | (fn
& 0xffff);
302 /* load r12 (temp) with cls */
304 tramp
[2] = 0xb0000000 | ((cls
>> 16) & 0xffff);
305 /* addik r12, r0, cls(lower) */
306 tramp
[3] = 0x31800000 | (cls
& 0xffff);
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 */