1*1fd5a2e1SPrashanth Swaminathan /* -----------------------------------------------------------------------
2*1fd5a2e1SPrashanth Swaminathan ffi.c - Copyright (C) 2013 IBM
3*1fd5a2e1SPrashanth Swaminathan Copyright (C) 2011 Anthony Green
4*1fd5a2e1SPrashanth Swaminathan Copyright (C) 2011 Kyle Moffett
5*1fd5a2e1SPrashanth Swaminathan Copyright (C) 2008 Red Hat, Inc
6*1fd5a2e1SPrashanth Swaminathan Copyright (C) 2007, 2008 Free Software Foundation, Inc
7*1fd5a2e1SPrashanth Swaminathan Copyright (c) 1998 Geoffrey Keating
8*1fd5a2e1SPrashanth Swaminathan
9*1fd5a2e1SPrashanth Swaminathan PowerPC Foreign Function Interface
10*1fd5a2e1SPrashanth Swaminathan
11*1fd5a2e1SPrashanth Swaminathan Permission is hereby granted, free of charge, to any person obtaining
12*1fd5a2e1SPrashanth Swaminathan a copy of this software and associated documentation files (the
13*1fd5a2e1SPrashanth Swaminathan ``Software''), to deal in the Software without restriction, including
14*1fd5a2e1SPrashanth Swaminathan without limitation the rights to use, copy, modify, merge, publish,
15*1fd5a2e1SPrashanth Swaminathan distribute, sublicense, and/or sell copies of the Software, and to
16*1fd5a2e1SPrashanth Swaminathan permit persons to whom the Software is furnished to do so, subject to
17*1fd5a2e1SPrashanth Swaminathan the following conditions:
18*1fd5a2e1SPrashanth Swaminathan
19*1fd5a2e1SPrashanth Swaminathan The above copyright notice and this permission notice shall be included
20*1fd5a2e1SPrashanth Swaminathan in all copies or substantial portions of the Software.
21*1fd5a2e1SPrashanth Swaminathan
22*1fd5a2e1SPrashanth Swaminathan THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
23*1fd5a2e1SPrashanth Swaminathan OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24*1fd5a2e1SPrashanth Swaminathan MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
25*1fd5a2e1SPrashanth Swaminathan IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
26*1fd5a2e1SPrashanth Swaminathan OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
27*1fd5a2e1SPrashanth Swaminathan ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28*1fd5a2e1SPrashanth Swaminathan OTHER DEALINGS IN THE SOFTWARE.
29*1fd5a2e1SPrashanth Swaminathan ----------------------------------------------------------------------- */
30*1fd5a2e1SPrashanth Swaminathan
31*1fd5a2e1SPrashanth Swaminathan #include "ffi.h"
32*1fd5a2e1SPrashanth Swaminathan #include "ffi_common.h"
33*1fd5a2e1SPrashanth Swaminathan #include "ffi_powerpc.h"
34*1fd5a2e1SPrashanth Swaminathan
35*1fd5a2e1SPrashanth Swaminathan #if HAVE_LONG_DOUBLE_VARIANT
36*1fd5a2e1SPrashanth Swaminathan /* Adjust ffi_type_longdouble. */
37*1fd5a2e1SPrashanth Swaminathan void FFI_HIDDEN
ffi_prep_types(ffi_abi abi)38*1fd5a2e1SPrashanth Swaminathan ffi_prep_types (ffi_abi abi)
39*1fd5a2e1SPrashanth Swaminathan {
40*1fd5a2e1SPrashanth Swaminathan # if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
41*1fd5a2e1SPrashanth Swaminathan # ifdef POWERPC64
42*1fd5a2e1SPrashanth Swaminathan ffi_prep_types_linux64 (abi);
43*1fd5a2e1SPrashanth Swaminathan # else
44*1fd5a2e1SPrashanth Swaminathan ffi_prep_types_sysv (abi);
45*1fd5a2e1SPrashanth Swaminathan # endif
46*1fd5a2e1SPrashanth Swaminathan # endif
47*1fd5a2e1SPrashanth Swaminathan }
48*1fd5a2e1SPrashanth Swaminathan #endif
49*1fd5a2e1SPrashanth Swaminathan
50*1fd5a2e1SPrashanth Swaminathan /* Perform machine dependent cif processing */
51*1fd5a2e1SPrashanth Swaminathan ffi_status FFI_HIDDEN
ffi_prep_cif_machdep(ffi_cif * cif)52*1fd5a2e1SPrashanth Swaminathan ffi_prep_cif_machdep (ffi_cif *cif)
53*1fd5a2e1SPrashanth Swaminathan {
54*1fd5a2e1SPrashanth Swaminathan #ifdef POWERPC64
55*1fd5a2e1SPrashanth Swaminathan return ffi_prep_cif_linux64 (cif);
56*1fd5a2e1SPrashanth Swaminathan #else
57*1fd5a2e1SPrashanth Swaminathan return ffi_prep_cif_sysv (cif);
58*1fd5a2e1SPrashanth Swaminathan #endif
59*1fd5a2e1SPrashanth Swaminathan }
60*1fd5a2e1SPrashanth Swaminathan
61*1fd5a2e1SPrashanth Swaminathan ffi_status FFI_HIDDEN
ffi_prep_cif_machdep_var(ffi_cif * cif,unsigned int nfixedargs MAYBE_UNUSED,unsigned int ntotalargs MAYBE_UNUSED)62*1fd5a2e1SPrashanth Swaminathan ffi_prep_cif_machdep_var (ffi_cif *cif,
63*1fd5a2e1SPrashanth Swaminathan unsigned int nfixedargs MAYBE_UNUSED,
64*1fd5a2e1SPrashanth Swaminathan unsigned int ntotalargs MAYBE_UNUSED)
65*1fd5a2e1SPrashanth Swaminathan {
66*1fd5a2e1SPrashanth Swaminathan #ifdef POWERPC64
67*1fd5a2e1SPrashanth Swaminathan return ffi_prep_cif_linux64_var (cif, nfixedargs, ntotalargs);
68*1fd5a2e1SPrashanth Swaminathan #else
69*1fd5a2e1SPrashanth Swaminathan return ffi_prep_cif_sysv (cif);
70*1fd5a2e1SPrashanth Swaminathan #endif
71*1fd5a2e1SPrashanth Swaminathan }
72*1fd5a2e1SPrashanth Swaminathan
73*1fd5a2e1SPrashanth Swaminathan static void
ffi_call_int(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue,void * closure)74*1fd5a2e1SPrashanth Swaminathan ffi_call_int (ffi_cif *cif,
75*1fd5a2e1SPrashanth Swaminathan void (*fn) (void),
76*1fd5a2e1SPrashanth Swaminathan void *rvalue,
77*1fd5a2e1SPrashanth Swaminathan void **avalue,
78*1fd5a2e1SPrashanth Swaminathan void *closure)
79*1fd5a2e1SPrashanth Swaminathan {
80*1fd5a2e1SPrashanth Swaminathan /* The final SYSV ABI says that structures smaller or equal 8 bytes
81*1fd5a2e1SPrashanth Swaminathan are returned in r3/r4. A draft ABI used by linux instead returns
82*1fd5a2e1SPrashanth Swaminathan them in memory.
83*1fd5a2e1SPrashanth Swaminathan
84*1fd5a2e1SPrashanth Swaminathan We bounce-buffer SYSV small struct return values so that sysv.S
85*1fd5a2e1SPrashanth Swaminathan can write r3 and r4 to memory without worrying about struct size.
86*1fd5a2e1SPrashanth Swaminathan
87*1fd5a2e1SPrashanth Swaminathan For ELFv2 ABI, use a bounce buffer for homogeneous structs too,
88*1fd5a2e1SPrashanth Swaminathan for similar reasons. This bounce buffer must be aligned to 16
89*1fd5a2e1SPrashanth Swaminathan bytes for use with homogeneous structs of vectors (float128). */
90*1fd5a2e1SPrashanth Swaminathan float128 smst_buffer[8];
91*1fd5a2e1SPrashanth Swaminathan extended_cif ecif;
92*1fd5a2e1SPrashanth Swaminathan
93*1fd5a2e1SPrashanth Swaminathan ecif.cif = cif;
94*1fd5a2e1SPrashanth Swaminathan ecif.avalue = avalue;
95*1fd5a2e1SPrashanth Swaminathan
96*1fd5a2e1SPrashanth Swaminathan ecif.rvalue = rvalue;
97*1fd5a2e1SPrashanth Swaminathan if ((cif->flags & FLAG_RETURNS_SMST) != 0)
98*1fd5a2e1SPrashanth Swaminathan ecif.rvalue = smst_buffer;
99*1fd5a2e1SPrashanth Swaminathan /* Ensure that we have a valid struct return value.
100*1fd5a2e1SPrashanth Swaminathan FIXME: Isn't this just papering over a user problem? */
101*1fd5a2e1SPrashanth Swaminathan else if (!rvalue && cif->rtype->type == FFI_TYPE_STRUCT)
102*1fd5a2e1SPrashanth Swaminathan ecif.rvalue = alloca (cif->rtype->size);
103*1fd5a2e1SPrashanth Swaminathan
104*1fd5a2e1SPrashanth Swaminathan #ifdef POWERPC64
105*1fd5a2e1SPrashanth Swaminathan ffi_call_LINUX64 (&ecif, fn, ecif.rvalue, cif->flags, closure,
106*1fd5a2e1SPrashanth Swaminathan -(long) cif->bytes);
107*1fd5a2e1SPrashanth Swaminathan #else
108*1fd5a2e1SPrashanth Swaminathan ffi_call_SYSV (&ecif, fn, ecif.rvalue, cif->flags, closure, -cif->bytes);
109*1fd5a2e1SPrashanth Swaminathan #endif
110*1fd5a2e1SPrashanth Swaminathan
111*1fd5a2e1SPrashanth Swaminathan /* Check for a bounce-buffered return value */
112*1fd5a2e1SPrashanth Swaminathan if (rvalue && ecif.rvalue == smst_buffer)
113*1fd5a2e1SPrashanth Swaminathan {
114*1fd5a2e1SPrashanth Swaminathan unsigned int rsize = cif->rtype->size;
115*1fd5a2e1SPrashanth Swaminathan #ifndef __LITTLE_ENDIAN__
116*1fd5a2e1SPrashanth Swaminathan /* The SYSV ABI returns a structure of up to 4 bytes in size
117*1fd5a2e1SPrashanth Swaminathan left-padded in r3. */
118*1fd5a2e1SPrashanth Swaminathan # ifndef POWERPC64
119*1fd5a2e1SPrashanth Swaminathan if (rsize <= 4)
120*1fd5a2e1SPrashanth Swaminathan memcpy (rvalue, (char *) smst_buffer + 4 - rsize, rsize);
121*1fd5a2e1SPrashanth Swaminathan else
122*1fd5a2e1SPrashanth Swaminathan # endif
123*1fd5a2e1SPrashanth Swaminathan /* The SYSV ABI returns a structure of up to 8 bytes in size
124*1fd5a2e1SPrashanth Swaminathan left-padded in r3/r4, and the ELFv2 ABI similarly returns a
125*1fd5a2e1SPrashanth Swaminathan structure of up to 8 bytes in size left-padded in r3. But
126*1fd5a2e1SPrashanth Swaminathan note that a structure of a single float is not paddded. */
127*1fd5a2e1SPrashanth Swaminathan if (rsize <= 8 && (cif->flags & FLAG_RETURNS_FP) == 0)
128*1fd5a2e1SPrashanth Swaminathan memcpy (rvalue, (char *) smst_buffer + 8 - rsize, rsize);
129*1fd5a2e1SPrashanth Swaminathan else
130*1fd5a2e1SPrashanth Swaminathan #endif
131*1fd5a2e1SPrashanth Swaminathan memcpy (rvalue, smst_buffer, rsize);
132*1fd5a2e1SPrashanth Swaminathan }
133*1fd5a2e1SPrashanth Swaminathan }
134*1fd5a2e1SPrashanth Swaminathan
135*1fd5a2e1SPrashanth Swaminathan void
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)136*1fd5a2e1SPrashanth Swaminathan ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue)
137*1fd5a2e1SPrashanth Swaminathan {
138*1fd5a2e1SPrashanth Swaminathan ffi_call_int (cif, fn, rvalue, avalue, NULL);
139*1fd5a2e1SPrashanth Swaminathan }
140*1fd5a2e1SPrashanth Swaminathan
141*1fd5a2e1SPrashanth Swaminathan void
ffi_call_go(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue,void * closure)142*1fd5a2e1SPrashanth Swaminathan ffi_call_go (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue,
143*1fd5a2e1SPrashanth Swaminathan void *closure)
144*1fd5a2e1SPrashanth Swaminathan {
145*1fd5a2e1SPrashanth Swaminathan ffi_call_int (cif, fn, rvalue, avalue, closure);
146*1fd5a2e1SPrashanth Swaminathan }
147*1fd5a2e1SPrashanth Swaminathan
148*1fd5a2e1SPrashanth Swaminathan ffi_status
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)149*1fd5a2e1SPrashanth Swaminathan ffi_prep_closure_loc (ffi_closure *closure,
150*1fd5a2e1SPrashanth Swaminathan ffi_cif *cif,
151*1fd5a2e1SPrashanth Swaminathan void (*fun) (ffi_cif *, void *, void **, void *),
152*1fd5a2e1SPrashanth Swaminathan void *user_data,
153*1fd5a2e1SPrashanth Swaminathan void *codeloc)
154*1fd5a2e1SPrashanth Swaminathan {
155*1fd5a2e1SPrashanth Swaminathan #ifdef POWERPC64
156*1fd5a2e1SPrashanth Swaminathan return ffi_prep_closure_loc_linux64 (closure, cif, fun, user_data, codeloc);
157*1fd5a2e1SPrashanth Swaminathan #else
158*1fd5a2e1SPrashanth Swaminathan return ffi_prep_closure_loc_sysv (closure, cif, fun, user_data, codeloc);
159*1fd5a2e1SPrashanth Swaminathan #endif
160*1fd5a2e1SPrashanth Swaminathan }
161*1fd5a2e1SPrashanth Swaminathan
162*1fd5a2e1SPrashanth Swaminathan ffi_status
ffi_prep_go_closure(ffi_go_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *))163*1fd5a2e1SPrashanth Swaminathan ffi_prep_go_closure (ffi_go_closure *closure,
164*1fd5a2e1SPrashanth Swaminathan ffi_cif *cif,
165*1fd5a2e1SPrashanth Swaminathan void (*fun) (ffi_cif *, void *, void **, void *))
166*1fd5a2e1SPrashanth Swaminathan {
167*1fd5a2e1SPrashanth Swaminathan #ifdef POWERPC64
168*1fd5a2e1SPrashanth Swaminathan closure->tramp = ffi_go_closure_linux64;
169*1fd5a2e1SPrashanth Swaminathan #else
170*1fd5a2e1SPrashanth Swaminathan closure->tramp = ffi_go_closure_sysv;
171*1fd5a2e1SPrashanth Swaminathan #endif
172*1fd5a2e1SPrashanth Swaminathan closure->cif = cif;
173*1fd5a2e1SPrashanth Swaminathan closure->fun = fun;
174*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
175*1fd5a2e1SPrashanth Swaminathan }
176