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 51extern void ffi_call_SYSV(void *rvalue, unsigned rsize, unsigned flags, 52 void(*fn)(void), unsigned nbytes, extended_cif*); 53extern void ffi_closure_SYSV(void) FFI_HIDDEN; 54 55ffi_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 = ALIGN(cif->bytes, 16); 93 94 return FFI_OK; 95} 96 97void 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 190void 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(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 225extern void ffi_trampoline(); 226extern void ffi_cacheflush(void* start, void* end); 227 228ffi_status 229ffi_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 250long FFI_HIDDEN 251ffi_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