1 /* ----------------------------------------------------------------------- 2 ffi.c 3 4 m68k Foreign Function Interface 5 ----------------------------------------------------------------------- */ 6 7 #include <ffi.h> 8 #include <ffi_common.h> 9 10 #include <stdlib.h> 11 #include <unistd.h> 12 #ifdef __rtems__ 13 void rtems_cache_flush_multiple_data_lines( const void *, size_t ); 14 #else 15 #include <sys/syscall.h> 16 #ifdef __MINT__ 17 #include <mint/mintbind.h> 18 #include <mint/ssystem.h> 19 #else 20 #include <asm/cachectl.h> 21 #endif 22 #endif 23 24 void ffi_call_SYSV (extended_cif *, 25 unsigned, unsigned, 26 void *, void (*fn) ()); 27 void *ffi_prep_args (void *stack, extended_cif *ecif); 28 void ffi_closure_SYSV (ffi_closure *); 29 void ffi_closure_struct_SYSV (ffi_closure *); 30 unsigned int ffi_closure_SYSV_inner (ffi_closure *closure, 31 void *resp, void *args); 32 33 /* ffi_prep_args is called by the assembly routine once stack space has 34 been allocated for the function's arguments. */ 35 36 void * 37 ffi_prep_args (void *stack, extended_cif *ecif) 38 { 39 unsigned int i; 40 void **p_argv; 41 char *argp; 42 ffi_type **p_arg; 43 void *struct_value_ptr; 44 45 argp = stack; 46 47 if ( 48 #ifdef __MINT__ 49 (ecif->cif->rtype->type == FFI_TYPE_LONGDOUBLE) || 50 #endif 51 (((ecif->cif->rtype->type == FFI_TYPE_STRUCT) 52 && !ecif->cif->flags))) 53 struct_value_ptr = ecif->rvalue; 54 else 55 struct_value_ptr = NULL; 56 57 p_argv = ecif->avalue; 58 59 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; 60 i != 0; 61 i--, p_arg++) 62 { 63 size_t z = (*p_arg)->size; 64 int type = (*p_arg)->type; 65 66 if (z < sizeof (int)) 67 { 68 switch (type) 69 { 70 case FFI_TYPE_SINT8: 71 *(signed int *) argp = (signed int) *(SINT8 *) *p_argv; 72 break; 73 74 case FFI_TYPE_UINT8: 75 *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv; 76 break; 77 78 case FFI_TYPE_SINT16: 79 *(signed int *) argp = (signed int) *(SINT16 *) *p_argv; 80 break; 81 82 case FFI_TYPE_UINT16: 83 *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv; 84 break; 85 86 case FFI_TYPE_STRUCT: 87 #ifdef __MINT__ 88 if (z == 1 || z == 2) 89 memcpy (argp + 2, *p_argv, z); 90 else 91 memcpy (argp, *p_argv, z); 92 #else 93 memcpy (argp + sizeof (int) - z, *p_argv, z); 94 #endif 95 break; 96 97 default: 98 FFI_ASSERT (0); 99 } 100 z = sizeof (int); 101 } 102 else 103 { 104 memcpy (argp, *p_argv, z); 105 106 /* Align if necessary. */ 107 if ((sizeof(int) - 1) & z) 108 z = ALIGN(z, sizeof(int)); 109 } 110 111 p_argv++; 112 argp += z; 113 } 114 115 return struct_value_ptr; 116 } 117 118 #define CIF_FLAGS_INT 1 119 #define CIF_FLAGS_DINT 2 120 #define CIF_FLAGS_FLOAT 4 121 #define CIF_FLAGS_DOUBLE 8 122 #define CIF_FLAGS_LDOUBLE 16 123 #define CIF_FLAGS_POINTER 32 124 #define CIF_FLAGS_STRUCT1 64 125 #define CIF_FLAGS_STRUCT2 128 126 #define CIF_FLAGS_SINT8 256 127 #define CIF_FLAGS_SINT16 512 128 129 /* Perform machine dependent cif processing */ 130 ffi_status 131 ffi_prep_cif_machdep (ffi_cif *cif) 132 { 133 /* Set the return type flag */ 134 switch (cif->rtype->type) 135 { 136 case FFI_TYPE_VOID: 137 cif->flags = 0; 138 break; 139 140 case FFI_TYPE_STRUCT: 141 if (cif->rtype->elements[0]->type == FFI_TYPE_STRUCT && 142 cif->rtype->elements[1]) 143 { 144 cif->flags = 0; 145 break; 146 } 147 148 switch (cif->rtype->size) 149 { 150 case 1: 151 #ifdef __MINT__ 152 cif->flags = CIF_FLAGS_STRUCT2; 153 #else 154 cif->flags = CIF_FLAGS_STRUCT1; 155 #endif 156 break; 157 case 2: 158 cif->flags = CIF_FLAGS_STRUCT2; 159 break; 160 #ifdef __MINT__ 161 case 3: 162 #endif 163 case 4: 164 cif->flags = CIF_FLAGS_INT; 165 break; 166 #ifdef __MINT__ 167 case 7: 168 #endif 169 case 8: 170 cif->flags = CIF_FLAGS_DINT; 171 break; 172 default: 173 cif->flags = 0; 174 break; 175 } 176 break; 177 178 case FFI_TYPE_FLOAT: 179 cif->flags = CIF_FLAGS_FLOAT; 180 break; 181 182 case FFI_TYPE_DOUBLE: 183 cif->flags = CIF_FLAGS_DOUBLE; 184 break; 185 186 #if (FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE) 187 case FFI_TYPE_LONGDOUBLE: 188 #ifdef __MINT__ 189 cif->flags = 0; 190 #else 191 cif->flags = CIF_FLAGS_LDOUBLE; 192 #endif 193 break; 194 #endif 195 196 case FFI_TYPE_POINTER: 197 cif->flags = CIF_FLAGS_POINTER; 198 break; 199 200 case FFI_TYPE_SINT64: 201 case FFI_TYPE_UINT64: 202 cif->flags = CIF_FLAGS_DINT; 203 break; 204 205 case FFI_TYPE_SINT16: 206 cif->flags = CIF_FLAGS_SINT16; 207 break; 208 209 case FFI_TYPE_SINT8: 210 cif->flags = CIF_FLAGS_SINT8; 211 break; 212 213 default: 214 cif->flags = CIF_FLAGS_INT; 215 break; 216 } 217 218 return FFI_OK; 219 } 220 221 void 222 ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue) 223 { 224 extended_cif ecif; 225 226 ecif.cif = cif; 227 ecif.avalue = avalue; 228 229 /* If the return value is a struct and we don't have a return value 230 address then we need to make one. */ 231 232 if (rvalue == NULL 233 && cif->rtype->type == FFI_TYPE_STRUCT 234 && cif->rtype->size > 8) 235 ecif.rvalue = alloca (cif->rtype->size); 236 else 237 ecif.rvalue = rvalue; 238 239 switch (cif->abi) 240 { 241 case FFI_SYSV: 242 ffi_call_SYSV (&ecif, cif->bytes, cif->flags, 243 ecif.rvalue, fn); 244 break; 245 246 default: 247 FFI_ASSERT (0); 248 break; 249 } 250 } 251 252 static void 253 ffi_prep_incoming_args_SYSV (char *stack, void **avalue, ffi_cif *cif) 254 { 255 unsigned int i; 256 void **p_argv; 257 char *argp; 258 ffi_type **p_arg; 259 260 argp = stack; 261 p_argv = avalue; 262 263 for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) 264 { 265 size_t z; 266 267 z = (*p_arg)->size; 268 #ifdef __MINT__ 269 if (cif->flags && 270 cif->rtype->type == FFI_TYPE_STRUCT && 271 (z == 1 || z == 2)) 272 { 273 *p_argv = (void *) (argp + 2); 274 275 z = 4; 276 } 277 else 278 if (cif->flags && 279 cif->rtype->type == FFI_TYPE_STRUCT && 280 (z == 3 || z == 4)) 281 { 282 *p_argv = (void *) (argp); 283 284 z = 4; 285 } 286 else 287 #endif 288 if (z <= 4) 289 { 290 *p_argv = (void *) (argp + 4 - z); 291 292 z = 4; 293 } 294 else 295 { 296 *p_argv = (void *) argp; 297 298 /* Align if necessary */ 299 if ((sizeof(int) - 1) & z) 300 z = ALIGN(z, sizeof(int)); 301 } 302 303 p_argv++; 304 argp += z; 305 } 306 } 307 308 unsigned int 309 ffi_closure_SYSV_inner (ffi_closure *closure, void *resp, void *args) 310 { 311 ffi_cif *cif; 312 void **arg_area; 313 314 cif = closure->cif; 315 arg_area = (void**) alloca (cif->nargs * sizeof (void *)); 316 317 ffi_prep_incoming_args_SYSV(args, arg_area, cif); 318 319 (closure->fun) (cif, resp, arg_area, closure->user_data); 320 321 return cif->flags; 322 } 323 324 ffi_status 325 ffi_prep_closure_loc (ffi_closure* closure, 326 ffi_cif* cif, 327 void (*fun)(ffi_cif*,void*,void**,void*), 328 void *user_data, 329 void *codeloc) 330 { 331 if (cif->abi != FFI_SYSV) 332 return FFI_BAD_ABI; 333 334 *(unsigned short *)closure->tramp = 0x207c; 335 *(void **)(closure->tramp + 2) = codeloc; 336 *(unsigned short *)(closure->tramp + 6) = 0x4ef9; 337 338 if ( 339 #ifdef __MINT__ 340 (cif->rtype->type == FFI_TYPE_LONGDOUBLE) || 341 #endif 342 (((cif->rtype->type == FFI_TYPE_STRUCT) 343 && !cif->flags))) 344 *(void **)(closure->tramp + 8) = ffi_closure_struct_SYSV; 345 else 346 *(void **)(closure->tramp + 8) = ffi_closure_SYSV; 347 348 #ifdef __rtems__ 349 rtems_cache_flush_multiple_data_lines( codeloc, FFI_TRAMPOLINE_SIZE ); 350 #elif defined(__MINT__) 351 Ssystem(S_FLUSHCACHE, codeloc, FFI_TRAMPOLINE_SIZE); 352 #else 353 syscall(SYS_cacheflush, codeloc, FLUSH_SCOPE_LINE, 354 FLUSH_CACHE_BOTH, FFI_TRAMPOLINE_SIZE); 355 #endif 356 357 closure->cif = cif; 358 closure->user_data = user_data; 359 closure->fun = fun; 360 361 return FFI_OK; 362 } 363