2 * Copyright (c) 2013 Miodrag Vallat. <miod@openbsd.org>
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:
12 * The above copyright notice and this permission notice shall be included
13 * in all copies or substantial portions of the Software.
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.
25 * m88k Foreign Function Interface
27 * This file attempts to provide all the FFI entry points which can reliably
28 * be implemented in C.
30 * Only OpenBSD/m88k is currently supported; other platforms (such as
31 * Motorola's SysV/m88k) could be supported with the following tweaks:
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.
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
47 #include <ffi_common.h>
52 void ffi_call_OBSD (unsigned int, extended_cif
*, unsigned int, void *,
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 *,
59 void ffi_cacheflush_OBSD (unsigned int, unsigned int);
61 #define CIF_FLAGS_INT (1 << 0)
62 #define CIF_FLAGS_DINT (1 << 1)
65 * Foreign Function Interface API
68 /* ffi_prep_args is called by the assembly routine once stack space has
69 been allocated for the function's arguments. */
72 ffi_prep_args (void *stack
, extended_cif
*ecif
)
80 void *struct_value_ptr
;
82 regp
= (unsigned int *)stack
;
83 stackp
= (char *)(regp
+ 8);
86 if (ecif
->cif
->rtype
->type
== FFI_TYPE_STRUCT
88 struct_value_ptr
= ecif
->rvalue
;
90 struct_value_ptr
= NULL
;
92 p_argv
= ecif
->avalue
;
94 for (i
= ecif
->cif
->nargs
, p_arg
= ecif
->cif
->arg_types
; i
!= 0; i
--, p_arg
++)
101 a
= (*p_arg
)->alignment
;
104 * Figure out whether the argument can be passed through registers
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.
110 if (t
== FFI_TYPE_STRUCT
)
112 if (z
== sizeof (int) && a
== sizeof (int) && regused
< 8)
119 if (z
> sizeof (int) && regused
< 8 - 1)
121 /* align to an even register pair */
134 /* Enforce proper stack alignment of 64-bit types */
135 if (argp
== stackp
&& a
> sizeof (int))
137 stackp
= (char *) FFI_ALIGN(stackp
, a
);
144 *(signed int *) argp
= (signed int) *(SINT8
*) *p_argv
;
148 *(unsigned int *) argp
= (unsigned int) *(UINT8
*) *p_argv
;
151 case FFI_TYPE_SINT16
:
152 *(signed int *) argp
= (signed int) *(SINT16
*) *p_argv
;
155 case FFI_TYPE_UINT16
:
156 *(unsigned int *) argp
= (unsigned int) *(UINT16
*) *p_argv
;
161 case FFI_TYPE_UINT32
:
162 case FFI_TYPE_SINT32
:
163 case FFI_TYPE_POINTER
:
164 *(unsigned int *) argp
= *(unsigned int *) *p_argv
;
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
);
178 /* Align if necessary. */
179 if ((sizeof (int) - 1) & z
)
180 z
= FFI_ALIGN(z
, sizeof (int));
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)
188 regp
+= z
/ sizeof (int);
189 regused
+= z
/ sizeof (int);
195 return struct_value_ptr
;
198 /* Perform machine dependent cif processing */
200 ffi_prep_cif_machdep (ffi_cif
*cif
)
202 /* Set the return type flag */
203 switch (cif
->rtype
->type
)
209 case FFI_TYPE_STRUCT
:
210 if (cif
->rtype
->size
== sizeof (int) &&
211 cif
->rtype
->alignment
== sizeof (int))
212 cif
->flags
= CIF_FLAGS_INT
;
217 case FFI_TYPE_DOUBLE
:
218 case FFI_TYPE_SINT64
:
219 case FFI_TYPE_UINT64
:
220 cif
->flags
= CIF_FLAGS_DINT
;
224 cif
->flags
= CIF_FLAGS_INT
;
232 ffi_call (ffi_cif
*cif
, void (*fn
) (), void *rvalue
, void **avalue
)
237 ecif
.avalue
= avalue
;
239 /* If the return value is a struct and we don't have a return value
240 address then we need to make one. */
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
);
248 ecif
.rvalue
= rvalue
;
253 ffi_call_OBSD (cif
->bytes
, &ecif
, cif
->flags
, ecif
.rvalue
, fn
);
267 ffi_prep_closure_args_OBSD (ffi_cif
*cif
, void **avalue
, unsigned int *regp
,
273 unsigned int regused
;
280 for (i
= cif
->nargs
, p_arg
= cif
->arg_types
; i
!= 0; i
--, p_arg
++)
287 a
= (*p_arg
)->alignment
;
290 * Figure out whether the argument has been passed through registers
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.
296 if (t
== FFI_TYPE_STRUCT
)
298 if (z
== sizeof (int) && a
== sizeof (int) && regused
< 8)
305 if (z
> sizeof (int) && regused
< 8 - 1)
307 /* align to an even register pair */
320 /* Enforce proper stack alignment of 64-bit types */
321 if (argp
== stackp
&& a
> sizeof (int))
323 stackp
= (char *) FFI_ALIGN(stackp
, a
);
327 if (z
< sizeof (int) && t
!= FFI_TYPE_STRUCT
)
328 *p_argv
= (void *) (argp
+ sizeof (int) - z
);
330 *p_argv
= (void *) argp
;
332 /* Align if necessary */
333 if ((sizeof (int) - 1) & z
)
334 z
= FFI_ALIGN(z
, sizeof (int));
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)
342 regp
+= z
/ sizeof (int);
343 regused
+= z
/ sizeof (int);
351 ffi_closure_OBSD_inner (ffi_closure
*closure
, void *resp
, unsigned int *regp
,
358 arg_area
= (void**) alloca (cif
->nargs
* sizeof (void *));
360 ffi_prep_closure_args_OBSD(cif
, arg_area
, regp
, stackp
);
362 (closure
->fun
) (cif
, resp
, arg_area
, closure
->user_data
);
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
)
372 unsigned int *tramp
= (unsigned int *) codeloc
;
375 FFI_ASSERT (cif
->abi
== FFI_OBSD
);
377 if (cif
->rtype
->type
== FFI_TYPE_STRUCT
&& !cif
->flags
)
378 fn
= &ffi_closure_struct_OBSD
;
380 fn
= &ffi_closure_OBSD
;
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);
389 tramp
[3] = 0xf400c40a;
390 /* or %r13, %r13, %lo16(closure) */
391 tramp
[4] = 0x59ad0000 | ((unsigned int)closure
& 0xffff);
393 ffi_cacheflush_OBSD((unsigned int)codeloc
, FFI_TRAMPOLINE_SIZE
);
396 closure
->user_data
= user_data
;