1 /* 2 * Copyright (c) 2013 Miodrag Vallat. <miod (at) openbsd.org> 3 * 4 * Permission is hereby granted, free of charge, to any person obtaining 5 * a copy of this software and associated documentation files (the 6 * ``Software''), to deal in the Software without restriction, including 7 * without limitation the rights to use, copy, modify, merge, publish, 8 * distribute, sublicense, and/or sell copies of the Software, and to 9 * permit persons to whom the Software is furnished to do so, subject to 10 * the following conditions: 11 * 12 * The above copyright notice and this permission notice shall be included 13 * in all copies or substantial portions of the Software. 14 * 15 * THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 */ 23 24 /* 25 * m88k Foreign Function Interface 26 * 27 * This file attempts to provide all the FFI entry points which can reliably 28 * be implemented in C. 29 * 30 * Only OpenBSD/m88k is currently supported; other platforms (such as 31 * Motorola's SysV/m88k) could be supported with the following tweaks: 32 * 33 * - non-OpenBSD systems use an `outgoing parameter area' as part of the 34 * 88BCS calling convention, which is not supported under OpenBSD from 35 * release 3.6 onwards. Supporting it should be as easy as taking it 36 * into account when adjusting the stack, in the assembly code. 37 * 38 * - the logic deciding whether a function argument gets passed through 39 * registers, or on the stack, has changed several times in OpenBSD in 40 * edge cases (especially for structs larger than 32 bytes being passed 41 * by value). The code below attemps to match the logic used by the 42 * system compiler of OpenBSD 5.3, i.e. gcc 3.3.6 with many m88k backend 43 * fixes. 44 */ 45 46 #include <ffi.h> 47 #include <ffi_common.h> 48 49 #include <stdlib.h> 50 #include <unistd.h> 51 52 void ffi_call_OBSD (unsigned int, extended_cif *, unsigned int, void *, 53 void (*fn) ()); 54 void *ffi_prep_args (void *, extended_cif *); 55 void ffi_closure_OBSD (ffi_closure *); 56 void ffi_closure_struct_OBSD (ffi_closure *); 57 unsigned int ffi_closure_OBSD_inner (ffi_closure *, void *, unsigned int *, 58 char *); 59 void ffi_cacheflush_OBSD (unsigned int, unsigned int); 60 61 #define CIF_FLAGS_INT (1 << 0) 62 #define CIF_FLAGS_DINT (1 << 1) 63 64 /* 65 * Foreign Function Interface API 66 */ 67 68 /* ffi_prep_args is called by the assembly routine once stack space has 69 been allocated for the function's arguments. */ 70 71 void * 72 ffi_prep_args (void *stack, extended_cif *ecif) 73 { 74 unsigned int i; 75 void **p_argv; 76 char *argp, *stackp; 77 unsigned int *regp; 78 unsigned int regused; 79 ffi_type **p_arg; 80 void *struct_value_ptr; 81 82 regp = (unsigned int *)stack; 83 stackp = (char *)(regp + 8); 84 regused = 0; 85 86 if (ecif->cif->rtype->type == FFI_TYPE_STRUCT 87 && !ecif->cif->flags) 88 struct_value_ptr = ecif->rvalue; 89 else 90 struct_value_ptr = NULL; 91 92 p_argv = ecif->avalue; 93 94 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i != 0; i--, p_arg++) 95 { 96 size_t z; 97 unsigned short t, a; 98 99 z = (*p_arg)->size; 100 t = (*p_arg)->type; 101 a = (*p_arg)->alignment; 102 103 /* 104 * Figure out whether the argument can be passed through registers 105 * or on the stack. 106 * The rule is that registers can only receive simple types not larger 107 * than 64 bits, or structs the exact size of a register and aligned to 108 * the size of a register. 109 */ 110 if (t == FFI_TYPE_STRUCT) 111 { 112 if (z == sizeof (int) && a == sizeof (int) && regused < 8) 113 argp = (char *)regp; 114 else 115 argp = stackp; 116 } 117 else 118 { 119 if (z > sizeof (int) && regused < 8 - 1) 120 { 121 /* align to an even register pair */ 122 if (regused & 1) 123 { 124 regp++; 125 regused++; 126 } 127 } 128 if (regused < 8) 129 argp = (char *)regp; 130 else 131 argp = stackp; 132 } 133 134 /* Enforce proper stack alignment of 64-bit types */ 135 if (argp == stackp && a > sizeof (int)) 136 { 137 stackp = (char *) ALIGN(stackp, a); 138 argp = stackp; 139 } 140 141 switch (t) 142 { 143 case FFI_TYPE_SINT8: 144 *(signed int *) argp = (signed int) *(SINT8 *) *p_argv; 145 break; 146 147 case FFI_TYPE_UINT8: 148 *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv; 149 break; 150 151 case FFI_TYPE_SINT16: 152 *(signed int *) argp = (signed int) *(SINT16 *) *p_argv; 153 break; 154 155 case FFI_TYPE_UINT16: 156 *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv; 157 break; 158 159 case FFI_TYPE_INT: 160 case FFI_TYPE_FLOAT: 161 case FFI_TYPE_UINT32: 162 case FFI_TYPE_SINT32: 163 case FFI_TYPE_POINTER: 164 *(unsigned int *) argp = *(unsigned int *) *p_argv; 165 break; 166 167 case FFI_TYPE_DOUBLE: 168 case FFI_TYPE_UINT64: 169 case FFI_TYPE_SINT64: 170 case FFI_TYPE_STRUCT: 171 memcpy (argp, *p_argv, z); 172 break; 173 174 default: 175 FFI_ASSERT (0); 176 } 177 178 /* Align if necessary. */ 179 if ((sizeof (int) - 1) & z) 180 z = ALIGN(z, sizeof (int)); 181 182 p_argv++; 183 184 /* Be careful, once all registers are filled, and about to continue 185 on stack, regp == stackp. Therefore the check for regused as well. */ 186 if (argp == (char *)regp && regused < 8) 187 { 188 regp += z / sizeof (int); 189 regused += z / sizeof (int); 190 } 191 else 192 stackp += z; 193 } 194 195 return struct_value_ptr; 196 } 197 198 /* Perform machine dependent cif processing */ 199 ffi_status 200 ffi_prep_cif_machdep (ffi_cif *cif) 201 { 202 /* Set the return type flag */ 203 switch (cif->rtype->type) 204 { 205 case FFI_TYPE_VOID: 206 cif->flags = 0; 207 break; 208 209 case FFI_TYPE_STRUCT: 210 if (cif->rtype->size == sizeof (int) && 211 cif->rtype->alignment == sizeof (int)) 212 cif->flags = CIF_FLAGS_INT; 213 else 214 cif->flags = 0; 215 break; 216 217 case FFI_TYPE_DOUBLE: 218 case FFI_TYPE_SINT64: 219 case FFI_TYPE_UINT64: 220 cif->flags = CIF_FLAGS_DINT; 221 break; 222 223 default: 224 cif->flags = CIF_FLAGS_INT; 225 break; 226 } 227 228 return FFI_OK; 229 } 230 231 void 232 ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue) 233 { 234 extended_cif ecif; 235 236 ecif.cif = cif; 237 ecif.avalue = avalue; 238 239 /* If the return value is a struct and we don't have a return value 240 address then we need to make one. */ 241 242 if (rvalue == NULL 243 && cif->rtype->type == FFI_TYPE_STRUCT 244 && (cif->rtype->size != sizeof (int) 245 || cif->rtype->alignment != sizeof (int))) 246 ecif.rvalue = alloca (cif->rtype->size); 247 else 248 ecif.rvalue = rvalue; 249 250 switch (cif->abi) 251 { 252 case FFI_OBSD: 253 ffi_call_OBSD (cif->bytes, &ecif, cif->flags, ecif.rvalue, fn); 254 break; 255 256 default: 257 FFI_ASSERT (0); 258 break; 259 } 260 } 261 262 /* 263 * Closure API 264 */ 265 266 static void 267 ffi_prep_closure_args_OBSD (ffi_cif *cif, void **avalue, unsigned int *regp, 268 char *stackp) 269 { 270 unsigned int i; 271 void **p_argv; 272 char *argp; 273 unsigned int regused; 274 ffi_type **p_arg; 275 276 regused = 0; 277 278 p_argv = avalue; 279 280 for (i = cif->nargs, p_arg = cif->arg_types; i != 0; i--, p_arg++) 281 { 282 size_t z; 283 unsigned short t, a; 284 285 z = (*p_arg)->size; 286 t = (*p_arg)->type; 287 a = (*p_arg)->alignment; 288 289 /* 290 * Figure out whether the argument has been passed through registers 291 * or on the stack. 292 * The rule is that registers can only receive simple types not larger 293 * than 64 bits, or structs the exact size of a register and aligned to 294 * the size of a register. 295 */ 296 if (t == FFI_TYPE_STRUCT) 297 { 298 if (z == sizeof (int) && a == sizeof (int) && regused < 8) 299 argp = (char *)regp; 300 else 301 argp = stackp; 302 } 303 else 304 { 305 if (z > sizeof (int) && regused < 8 - 1) 306 { 307 /* align to an even register pair */ 308 if (regused & 1) 309 { 310 regp++; 311 regused++; 312 } 313 } 314 if (regused < 8) 315 argp = (char *)regp; 316 else 317 argp = stackp; 318 } 319 320 /* Enforce proper stack alignment of 64-bit types */ 321 if (argp == stackp && a > sizeof (int)) 322 { 323 stackp = (char *) ALIGN(stackp, a); 324 argp = stackp; 325 } 326 327 if (z < sizeof (int) && t != FFI_TYPE_STRUCT) 328 *p_argv = (void *) (argp + sizeof (int) - z); 329 else 330 *p_argv = (void *) argp; 331 332 /* Align if necessary */ 333 if ((sizeof (int) - 1) & z) 334 z = ALIGN(z, sizeof (int)); 335 336 p_argv++; 337 338 /* Be careful, once all registers are exhausted, and about to fetch from 339 stack, regp == stackp. Therefore the check for regused as well. */ 340 if (argp == (char *)regp && regused < 8) 341 { 342 regp += z / sizeof (int); 343 regused += z / sizeof (int); 344 } 345 else 346 stackp += z; 347 } 348 } 349 350 unsigned int 351 ffi_closure_OBSD_inner (ffi_closure *closure, void *resp, unsigned int *regp, 352 char *stackp) 353 { 354 ffi_cif *cif; 355 void **arg_area; 356 357 cif = closure->cif; 358 arg_area = (void**) alloca (cif->nargs * sizeof (void *)); 359 360 ffi_prep_closure_args_OBSD(cif, arg_area, regp, stackp); 361 362 (closure->fun) (cif, resp, arg_area, closure->user_data); 363 364 return cif->flags; 365 } 366 367 ffi_status 368 ffi_prep_closure_loc (ffi_closure* closure, ffi_cif* cif, 369 void (*fun)(ffi_cif*,void*,void**,void*), 370 void *user_data, void *codeloc) 371 { 372 unsigned int *tramp = (unsigned int *) codeloc; 373 void *fn; 374 375 FFI_ASSERT (cif->abi == FFI_OBSD); 376 377 if (cif->rtype->type == FFI_TYPE_STRUCT && !cif->flags) 378 fn = &ffi_closure_struct_OBSD; 379 else 380 fn = &ffi_closure_OBSD; 381 382 /* or.u %r10, %r0, %hi16(fn) */ 383 tramp[0] = 0x5d400000 | (((unsigned int)fn) >> 16); 384 /* or.u %r13, %r0, %hi16(closure) */ 385 tramp[1] = 0x5da00000 | ((unsigned int)closure >> 16); 386 /* or %r10, %r10, %lo16(fn) */ 387 tramp[2] = 0x594a0000 | (((unsigned int)fn) & 0xffff); 388 /* jmp.n %r10 */ 389 tramp[3] = 0xf400c40a; 390 /* or %r13, %r13, %lo16(closure) */ 391 tramp[4] = 0x59ad0000 | ((unsigned int)closure & 0xffff); 392 393 ffi_cacheflush_OBSD((unsigned int)codeloc, FFI_TRAMPOLINE_SIZE); 394 395 closure->cif = cif; 396 closure->user_data = user_data; 397 closure->fun = fun; 398 399 return FFI_OK; 400 } 401