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 30extern 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 34extern void ffi_closure_SYSV(void); 35 36#define WORD_SIZE sizeof(unsigned int) 37#define ARGS_REGISTER_SIZE (WORD_SIZE * 6) 38#define WORD_ALIGN(x) 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 */ 42void 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 p_argv = ecif->avalue; 50 51 if (ecif == NULL || ecif->cif == NULL) { 52 return; /* no description to prepare */ 53 } 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_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 138ffi_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 151void 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 177void 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_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 277ffi_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