1*1fd5a2e1SPrashanth Swaminathan /* -----------------------------------------------------------------------
2*1fd5a2e1SPrashanth Swaminathan ffi.c - Copyright (c) 2003, 2004, 2006, 2007, 2012 Kaz Kojima
3*1fd5a2e1SPrashanth Swaminathan Copyright (c) 2008 Anthony Green
4*1fd5a2e1SPrashanth Swaminathan
5*1fd5a2e1SPrashanth Swaminathan SuperH SHmedia Foreign Function Interface
6*1fd5a2e1SPrashanth Swaminathan
7*1fd5a2e1SPrashanth Swaminathan Permission is hereby granted, free of charge, to any person obtaining
8*1fd5a2e1SPrashanth Swaminathan a copy of this software and associated documentation files (the
9*1fd5a2e1SPrashanth Swaminathan ``Software''), to deal in the Software without restriction, including
10*1fd5a2e1SPrashanth Swaminathan without limitation the rights to use, copy, modify, merge, publish,
11*1fd5a2e1SPrashanth Swaminathan distribute, sublicense, and/or sell copies of the Software, and to
12*1fd5a2e1SPrashanth Swaminathan permit persons to whom the Software is furnished to do so, subject to
13*1fd5a2e1SPrashanth Swaminathan the following conditions:
14*1fd5a2e1SPrashanth Swaminathan
15*1fd5a2e1SPrashanth Swaminathan The above copyright notice and this permission notice shall be included
16*1fd5a2e1SPrashanth Swaminathan in all copies or substantial portions of the Software.
17*1fd5a2e1SPrashanth Swaminathan
18*1fd5a2e1SPrashanth Swaminathan THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
19*1fd5a2e1SPrashanth Swaminathan EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20*1fd5a2e1SPrashanth Swaminathan MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21*1fd5a2e1SPrashanth Swaminathan NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22*1fd5a2e1SPrashanth Swaminathan HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23*1fd5a2e1SPrashanth Swaminathan WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24*1fd5a2e1SPrashanth Swaminathan OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25*1fd5a2e1SPrashanth Swaminathan DEALINGS IN THE SOFTWARE.
26*1fd5a2e1SPrashanth Swaminathan ----------------------------------------------------------------------- */
27*1fd5a2e1SPrashanth Swaminathan
28*1fd5a2e1SPrashanth Swaminathan #include <ffi.h>
29*1fd5a2e1SPrashanth Swaminathan #include <ffi_common.h>
30*1fd5a2e1SPrashanth Swaminathan
31*1fd5a2e1SPrashanth Swaminathan #include <stdlib.h>
32*1fd5a2e1SPrashanth Swaminathan
33*1fd5a2e1SPrashanth Swaminathan #define NGREGARG 8
34*1fd5a2e1SPrashanth Swaminathan #define NFREGARG 12
35*1fd5a2e1SPrashanth Swaminathan
36*1fd5a2e1SPrashanth Swaminathan static int
return_type(ffi_type * arg)37*1fd5a2e1SPrashanth Swaminathan return_type (ffi_type *arg)
38*1fd5a2e1SPrashanth Swaminathan {
39*1fd5a2e1SPrashanth Swaminathan
40*1fd5a2e1SPrashanth Swaminathan if (arg->type != FFI_TYPE_STRUCT)
41*1fd5a2e1SPrashanth Swaminathan return arg->type;
42*1fd5a2e1SPrashanth Swaminathan
43*1fd5a2e1SPrashanth Swaminathan /* gcc uses r2 if the result can be packed in on register. */
44*1fd5a2e1SPrashanth Swaminathan if (arg->size <= sizeof (UINT8))
45*1fd5a2e1SPrashanth Swaminathan return FFI_TYPE_UINT8;
46*1fd5a2e1SPrashanth Swaminathan else if (arg->size <= sizeof (UINT16))
47*1fd5a2e1SPrashanth Swaminathan return FFI_TYPE_UINT16;
48*1fd5a2e1SPrashanth Swaminathan else if (arg->size <= sizeof (UINT32))
49*1fd5a2e1SPrashanth Swaminathan return FFI_TYPE_UINT32;
50*1fd5a2e1SPrashanth Swaminathan else if (arg->size <= sizeof (UINT64))
51*1fd5a2e1SPrashanth Swaminathan return FFI_TYPE_UINT64;
52*1fd5a2e1SPrashanth Swaminathan
53*1fd5a2e1SPrashanth Swaminathan return FFI_TYPE_STRUCT;
54*1fd5a2e1SPrashanth Swaminathan }
55*1fd5a2e1SPrashanth Swaminathan
56*1fd5a2e1SPrashanth Swaminathan /* ffi_prep_args is called by the assembly routine once stack space
57*1fd5a2e1SPrashanth Swaminathan has been allocated for the function's arguments */
58*1fd5a2e1SPrashanth Swaminathan
ffi_prep_args(char * stack,extended_cif * ecif)59*1fd5a2e1SPrashanth Swaminathan void ffi_prep_args(char *stack, extended_cif *ecif)
60*1fd5a2e1SPrashanth Swaminathan {
61*1fd5a2e1SPrashanth Swaminathan register unsigned int i;
62*1fd5a2e1SPrashanth Swaminathan register unsigned int avn;
63*1fd5a2e1SPrashanth Swaminathan register void **p_argv;
64*1fd5a2e1SPrashanth Swaminathan register char *argp;
65*1fd5a2e1SPrashanth Swaminathan register ffi_type **p_arg;
66*1fd5a2e1SPrashanth Swaminathan
67*1fd5a2e1SPrashanth Swaminathan argp = stack;
68*1fd5a2e1SPrashanth Swaminathan
69*1fd5a2e1SPrashanth Swaminathan if (return_type (ecif->cif->rtype) == FFI_TYPE_STRUCT)
70*1fd5a2e1SPrashanth Swaminathan {
71*1fd5a2e1SPrashanth Swaminathan *(void **) argp = ecif->rvalue;
72*1fd5a2e1SPrashanth Swaminathan argp += sizeof (UINT64);
73*1fd5a2e1SPrashanth Swaminathan }
74*1fd5a2e1SPrashanth Swaminathan
75*1fd5a2e1SPrashanth Swaminathan avn = ecif->cif->nargs;
76*1fd5a2e1SPrashanth Swaminathan p_argv = ecif->avalue;
77*1fd5a2e1SPrashanth Swaminathan
78*1fd5a2e1SPrashanth Swaminathan for (i = 0, p_arg = ecif->cif->arg_types; i < avn; i++, p_arg++, p_argv++)
79*1fd5a2e1SPrashanth Swaminathan {
80*1fd5a2e1SPrashanth Swaminathan size_t z;
81*1fd5a2e1SPrashanth Swaminathan int align;
82*1fd5a2e1SPrashanth Swaminathan
83*1fd5a2e1SPrashanth Swaminathan z = (*p_arg)->size;
84*1fd5a2e1SPrashanth Swaminathan align = (*p_arg)->alignment;
85*1fd5a2e1SPrashanth Swaminathan if (z < sizeof (UINT32))
86*1fd5a2e1SPrashanth Swaminathan {
87*1fd5a2e1SPrashanth Swaminathan switch ((*p_arg)->type)
88*1fd5a2e1SPrashanth Swaminathan {
89*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
90*1fd5a2e1SPrashanth Swaminathan *(SINT64 *) argp = (SINT64) *(SINT8 *)(*p_argv);
91*1fd5a2e1SPrashanth Swaminathan break;
92*1fd5a2e1SPrashanth Swaminathan
93*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
94*1fd5a2e1SPrashanth Swaminathan *(UINT64 *) argp = (UINT64) *(UINT8 *)(*p_argv);
95*1fd5a2e1SPrashanth Swaminathan break;
96*1fd5a2e1SPrashanth Swaminathan
97*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
98*1fd5a2e1SPrashanth Swaminathan *(SINT64 *) argp = (SINT64) *(SINT16 *)(*p_argv);
99*1fd5a2e1SPrashanth Swaminathan break;
100*1fd5a2e1SPrashanth Swaminathan
101*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
102*1fd5a2e1SPrashanth Swaminathan *(UINT64 *) argp = (UINT64) *(UINT16 *)(*p_argv);
103*1fd5a2e1SPrashanth Swaminathan break;
104*1fd5a2e1SPrashanth Swaminathan
105*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_STRUCT:
106*1fd5a2e1SPrashanth Swaminathan memcpy (argp, *p_argv, z);
107*1fd5a2e1SPrashanth Swaminathan break;
108*1fd5a2e1SPrashanth Swaminathan
109*1fd5a2e1SPrashanth Swaminathan default:
110*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT(0);
111*1fd5a2e1SPrashanth Swaminathan }
112*1fd5a2e1SPrashanth Swaminathan argp += sizeof (UINT64);
113*1fd5a2e1SPrashanth Swaminathan }
114*1fd5a2e1SPrashanth Swaminathan else if (z == sizeof (UINT32) && align == sizeof (UINT32))
115*1fd5a2e1SPrashanth Swaminathan {
116*1fd5a2e1SPrashanth Swaminathan switch ((*p_arg)->type)
117*1fd5a2e1SPrashanth Swaminathan {
118*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_INT:
119*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT32:
120*1fd5a2e1SPrashanth Swaminathan *(SINT64 *) argp = (SINT64) *(SINT32 *) (*p_argv);
121*1fd5a2e1SPrashanth Swaminathan break;
122*1fd5a2e1SPrashanth Swaminathan
123*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
124*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_POINTER:
125*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT32:
126*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_STRUCT:
127*1fd5a2e1SPrashanth Swaminathan *(UINT64 *) argp = (UINT64) *(UINT32 *) (*p_argv);
128*1fd5a2e1SPrashanth Swaminathan break;
129*1fd5a2e1SPrashanth Swaminathan
130*1fd5a2e1SPrashanth Swaminathan default:
131*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT(0);
132*1fd5a2e1SPrashanth Swaminathan break;
133*1fd5a2e1SPrashanth Swaminathan }
134*1fd5a2e1SPrashanth Swaminathan argp += sizeof (UINT64);
135*1fd5a2e1SPrashanth Swaminathan }
136*1fd5a2e1SPrashanth Swaminathan else if (z == sizeof (UINT64)
137*1fd5a2e1SPrashanth Swaminathan && align == sizeof (UINT64)
138*1fd5a2e1SPrashanth Swaminathan && ((int) *p_argv & (sizeof (UINT64) - 1)) == 0)
139*1fd5a2e1SPrashanth Swaminathan {
140*1fd5a2e1SPrashanth Swaminathan *(UINT64 *) argp = *(UINT64 *) (*p_argv);
141*1fd5a2e1SPrashanth Swaminathan argp += sizeof (UINT64);
142*1fd5a2e1SPrashanth Swaminathan }
143*1fd5a2e1SPrashanth Swaminathan else
144*1fd5a2e1SPrashanth Swaminathan {
145*1fd5a2e1SPrashanth Swaminathan int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
146*1fd5a2e1SPrashanth Swaminathan
147*1fd5a2e1SPrashanth Swaminathan memcpy (argp, *p_argv, z);
148*1fd5a2e1SPrashanth Swaminathan argp += n * sizeof (UINT64);
149*1fd5a2e1SPrashanth Swaminathan }
150*1fd5a2e1SPrashanth Swaminathan }
151*1fd5a2e1SPrashanth Swaminathan
152*1fd5a2e1SPrashanth Swaminathan return;
153*1fd5a2e1SPrashanth Swaminathan }
154*1fd5a2e1SPrashanth Swaminathan
155*1fd5a2e1SPrashanth Swaminathan /* Perform machine dependent cif processing */
ffi_prep_cif_machdep(ffi_cif * cif)156*1fd5a2e1SPrashanth Swaminathan ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
157*1fd5a2e1SPrashanth Swaminathan {
158*1fd5a2e1SPrashanth Swaminathan int i, j;
159*1fd5a2e1SPrashanth Swaminathan int size, type;
160*1fd5a2e1SPrashanth Swaminathan int n, m;
161*1fd5a2e1SPrashanth Swaminathan int greg;
162*1fd5a2e1SPrashanth Swaminathan int freg;
163*1fd5a2e1SPrashanth Swaminathan int fpair = -1;
164*1fd5a2e1SPrashanth Swaminathan
165*1fd5a2e1SPrashanth Swaminathan greg = (return_type (cif->rtype) == FFI_TYPE_STRUCT ? 1 : 0);
166*1fd5a2e1SPrashanth Swaminathan freg = 0;
167*1fd5a2e1SPrashanth Swaminathan cif->flags2 = 0;
168*1fd5a2e1SPrashanth Swaminathan
169*1fd5a2e1SPrashanth Swaminathan for (i = j = 0; i < cif->nargs; i++)
170*1fd5a2e1SPrashanth Swaminathan {
171*1fd5a2e1SPrashanth Swaminathan type = (cif->arg_types)[i]->type;
172*1fd5a2e1SPrashanth Swaminathan switch (type)
173*1fd5a2e1SPrashanth Swaminathan {
174*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
175*1fd5a2e1SPrashanth Swaminathan greg++;
176*1fd5a2e1SPrashanth Swaminathan cif->bytes += sizeof (UINT64) - sizeof (float);
177*1fd5a2e1SPrashanth Swaminathan if (freg >= NFREGARG - 1)
178*1fd5a2e1SPrashanth Swaminathan continue;
179*1fd5a2e1SPrashanth Swaminathan if (fpair < 0)
180*1fd5a2e1SPrashanth Swaminathan {
181*1fd5a2e1SPrashanth Swaminathan fpair = freg;
182*1fd5a2e1SPrashanth Swaminathan freg += 2;
183*1fd5a2e1SPrashanth Swaminathan }
184*1fd5a2e1SPrashanth Swaminathan else
185*1fd5a2e1SPrashanth Swaminathan fpair = -1;
186*1fd5a2e1SPrashanth Swaminathan cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
187*1fd5a2e1SPrashanth Swaminathan break;
188*1fd5a2e1SPrashanth Swaminathan
189*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_DOUBLE:
190*1fd5a2e1SPrashanth Swaminathan if (greg++ >= NGREGARG && (freg + 1) >= NFREGARG)
191*1fd5a2e1SPrashanth Swaminathan continue;
192*1fd5a2e1SPrashanth Swaminathan if ((freg + 1) < NFREGARG)
193*1fd5a2e1SPrashanth Swaminathan {
194*1fd5a2e1SPrashanth Swaminathan freg += 2;
195*1fd5a2e1SPrashanth Swaminathan cif->flags2 += ((cif->arg_types)[i]->type) << (2 * j++);
196*1fd5a2e1SPrashanth Swaminathan }
197*1fd5a2e1SPrashanth Swaminathan else
198*1fd5a2e1SPrashanth Swaminathan cif->flags2 += FFI_TYPE_INT << (2 * j++);
199*1fd5a2e1SPrashanth Swaminathan break;
200*1fd5a2e1SPrashanth Swaminathan
201*1fd5a2e1SPrashanth Swaminathan default:
202*1fd5a2e1SPrashanth Swaminathan size = (cif->arg_types)[i]->size;
203*1fd5a2e1SPrashanth Swaminathan if (size < sizeof (UINT64))
204*1fd5a2e1SPrashanth Swaminathan cif->bytes += sizeof (UINT64) - size;
205*1fd5a2e1SPrashanth Swaminathan n = (size + sizeof (UINT64) - 1) / sizeof (UINT64);
206*1fd5a2e1SPrashanth Swaminathan if (greg >= NGREGARG)
207*1fd5a2e1SPrashanth Swaminathan continue;
208*1fd5a2e1SPrashanth Swaminathan else if (greg + n - 1 >= NGREGARG)
209*1fd5a2e1SPrashanth Swaminathan greg = NGREGARG;
210*1fd5a2e1SPrashanth Swaminathan else
211*1fd5a2e1SPrashanth Swaminathan greg += n;
212*1fd5a2e1SPrashanth Swaminathan for (m = 0; m < n; m++)
213*1fd5a2e1SPrashanth Swaminathan cif->flags2 += FFI_TYPE_INT << (2 * j++);
214*1fd5a2e1SPrashanth Swaminathan break;
215*1fd5a2e1SPrashanth Swaminathan }
216*1fd5a2e1SPrashanth Swaminathan }
217*1fd5a2e1SPrashanth Swaminathan
218*1fd5a2e1SPrashanth Swaminathan /* Set the return type flag */
219*1fd5a2e1SPrashanth Swaminathan switch (cif->rtype->type)
220*1fd5a2e1SPrashanth Swaminathan {
221*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_STRUCT:
222*1fd5a2e1SPrashanth Swaminathan cif->flags = return_type (cif->rtype);
223*1fd5a2e1SPrashanth Swaminathan break;
224*1fd5a2e1SPrashanth Swaminathan
225*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_VOID:
226*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
227*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_DOUBLE:
228*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT64:
229*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT64:
230*1fd5a2e1SPrashanth Swaminathan cif->flags = cif->rtype->type;
231*1fd5a2e1SPrashanth Swaminathan break;
232*1fd5a2e1SPrashanth Swaminathan
233*1fd5a2e1SPrashanth Swaminathan default:
234*1fd5a2e1SPrashanth Swaminathan cif->flags = FFI_TYPE_INT;
235*1fd5a2e1SPrashanth Swaminathan break;
236*1fd5a2e1SPrashanth Swaminathan }
237*1fd5a2e1SPrashanth Swaminathan
238*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
239*1fd5a2e1SPrashanth Swaminathan }
240*1fd5a2e1SPrashanth Swaminathan
241*1fd5a2e1SPrashanth Swaminathan /*@-declundef@*/
242*1fd5a2e1SPrashanth Swaminathan /*@-exportheader@*/
243*1fd5a2e1SPrashanth Swaminathan extern void ffi_call_SYSV(void (*)(char *, extended_cif *),
244*1fd5a2e1SPrashanth Swaminathan /*@out@*/ extended_cif *,
245*1fd5a2e1SPrashanth Swaminathan unsigned, unsigned, long long,
246*1fd5a2e1SPrashanth Swaminathan /*@out@*/ unsigned *,
247*1fd5a2e1SPrashanth Swaminathan void (*fn)(void));
248*1fd5a2e1SPrashanth Swaminathan /*@=declundef@*/
249*1fd5a2e1SPrashanth Swaminathan /*@=exportheader@*/
250*1fd5a2e1SPrashanth Swaminathan
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)251*1fd5a2e1SPrashanth Swaminathan void ffi_call(/*@dependent@*/ ffi_cif *cif,
252*1fd5a2e1SPrashanth Swaminathan void (*fn)(void),
253*1fd5a2e1SPrashanth Swaminathan /*@out@*/ void *rvalue,
254*1fd5a2e1SPrashanth Swaminathan /*@dependent@*/ void **avalue)
255*1fd5a2e1SPrashanth Swaminathan {
256*1fd5a2e1SPrashanth Swaminathan extended_cif ecif;
257*1fd5a2e1SPrashanth Swaminathan UINT64 trvalue;
258*1fd5a2e1SPrashanth Swaminathan
259*1fd5a2e1SPrashanth Swaminathan ecif.cif = cif;
260*1fd5a2e1SPrashanth Swaminathan ecif.avalue = avalue;
261*1fd5a2e1SPrashanth Swaminathan
262*1fd5a2e1SPrashanth Swaminathan /* If the return value is a struct and we don't have a return */
263*1fd5a2e1SPrashanth Swaminathan /* value address then we need to make one */
264*1fd5a2e1SPrashanth Swaminathan
265*1fd5a2e1SPrashanth Swaminathan if (cif->rtype->type == FFI_TYPE_STRUCT
266*1fd5a2e1SPrashanth Swaminathan && return_type (cif->rtype) != FFI_TYPE_STRUCT)
267*1fd5a2e1SPrashanth Swaminathan ecif.rvalue = &trvalue;
268*1fd5a2e1SPrashanth Swaminathan else if ((rvalue == NULL) &&
269*1fd5a2e1SPrashanth Swaminathan (cif->rtype->type == FFI_TYPE_STRUCT))
270*1fd5a2e1SPrashanth Swaminathan {
271*1fd5a2e1SPrashanth Swaminathan ecif.rvalue = alloca(cif->rtype->size);
272*1fd5a2e1SPrashanth Swaminathan }
273*1fd5a2e1SPrashanth Swaminathan else
274*1fd5a2e1SPrashanth Swaminathan ecif.rvalue = rvalue;
275*1fd5a2e1SPrashanth Swaminathan
276*1fd5a2e1SPrashanth Swaminathan switch (cif->abi)
277*1fd5a2e1SPrashanth Swaminathan {
278*1fd5a2e1SPrashanth Swaminathan case FFI_SYSV:
279*1fd5a2e1SPrashanth Swaminathan ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags, cif->flags2,
280*1fd5a2e1SPrashanth Swaminathan ecif.rvalue, fn);
281*1fd5a2e1SPrashanth Swaminathan break;
282*1fd5a2e1SPrashanth Swaminathan default:
283*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT(0);
284*1fd5a2e1SPrashanth Swaminathan break;
285*1fd5a2e1SPrashanth Swaminathan }
286*1fd5a2e1SPrashanth Swaminathan
287*1fd5a2e1SPrashanth Swaminathan if (rvalue
288*1fd5a2e1SPrashanth Swaminathan && cif->rtype->type == FFI_TYPE_STRUCT
289*1fd5a2e1SPrashanth Swaminathan && return_type (cif->rtype) != FFI_TYPE_STRUCT)
290*1fd5a2e1SPrashanth Swaminathan memcpy (rvalue, &trvalue, cif->rtype->size);
291*1fd5a2e1SPrashanth Swaminathan }
292*1fd5a2e1SPrashanth Swaminathan
293*1fd5a2e1SPrashanth Swaminathan extern void ffi_closure_SYSV (void);
294*1fd5a2e1SPrashanth Swaminathan extern void __ic_invalidate (void *line);
295*1fd5a2e1SPrashanth Swaminathan
296*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)297*1fd5a2e1SPrashanth Swaminathan ffi_prep_closure_loc (ffi_closure *closure,
298*1fd5a2e1SPrashanth Swaminathan ffi_cif *cif,
299*1fd5a2e1SPrashanth Swaminathan void (*fun)(ffi_cif*, void*, void**, void*),
300*1fd5a2e1SPrashanth Swaminathan void *user_data,
301*1fd5a2e1SPrashanth Swaminathan void *codeloc)
302*1fd5a2e1SPrashanth Swaminathan {
303*1fd5a2e1SPrashanth Swaminathan unsigned int *tramp;
304*1fd5a2e1SPrashanth Swaminathan
305*1fd5a2e1SPrashanth Swaminathan if (cif->abi != FFI_SYSV)
306*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_ABI;
307*1fd5a2e1SPrashanth Swaminathan
308*1fd5a2e1SPrashanth Swaminathan tramp = (unsigned int *) &closure->tramp[0];
309*1fd5a2e1SPrashanth Swaminathan /* Since ffi_closure is an aligned object, the ffi trampoline is
310*1fd5a2e1SPrashanth Swaminathan called as an SHcompact code. Sigh.
311*1fd5a2e1SPrashanth Swaminathan SHcompact part:
312*1fd5a2e1SPrashanth Swaminathan mova @(1,pc),r0; add #1,r0; jmp @r0; nop;
313*1fd5a2e1SPrashanth Swaminathan SHmedia part:
314*1fd5a2e1SPrashanth Swaminathan movi fnaddr >> 16,r1; shori fnaddr,r1; ptabs/l r1,tr0
315*1fd5a2e1SPrashanth Swaminathan movi cxt >> 16,r1; shori cxt,r1; blink tr0,r63 */
316*1fd5a2e1SPrashanth Swaminathan #ifdef __LITTLE_ENDIAN__
317*1fd5a2e1SPrashanth Swaminathan tramp[0] = 0x7001c701;
318*1fd5a2e1SPrashanth Swaminathan tramp[1] = 0x0009402b;
319*1fd5a2e1SPrashanth Swaminathan #else
320*1fd5a2e1SPrashanth Swaminathan tramp[0] = 0xc7017001;
321*1fd5a2e1SPrashanth Swaminathan tramp[1] = 0x402b0009;
322*1fd5a2e1SPrashanth Swaminathan #endif
323*1fd5a2e1SPrashanth Swaminathan tramp[2] = 0xcc000010 | (((UINT32) ffi_closure_SYSV) >> 16) << 10;
324*1fd5a2e1SPrashanth Swaminathan tramp[3] = 0xc8000010 | (((UINT32) ffi_closure_SYSV) & 0xffff) << 10;
325*1fd5a2e1SPrashanth Swaminathan tramp[4] = 0x6bf10600;
326*1fd5a2e1SPrashanth Swaminathan tramp[5] = 0xcc000010 | (((UINT32) codeloc) >> 16) << 10;
327*1fd5a2e1SPrashanth Swaminathan tramp[6] = 0xc8000010 | (((UINT32) codeloc) & 0xffff) << 10;
328*1fd5a2e1SPrashanth Swaminathan tramp[7] = 0x4401fff0;
329*1fd5a2e1SPrashanth Swaminathan
330*1fd5a2e1SPrashanth Swaminathan closure->cif = cif;
331*1fd5a2e1SPrashanth Swaminathan closure->fun = fun;
332*1fd5a2e1SPrashanth Swaminathan closure->user_data = user_data;
333*1fd5a2e1SPrashanth Swaminathan
334*1fd5a2e1SPrashanth Swaminathan /* Flush the icache. */
335*1fd5a2e1SPrashanth Swaminathan asm volatile ("ocbwb %0,0; synco; icbi %1,0; synci" : : "r" (tramp),
336*1fd5a2e1SPrashanth Swaminathan "r"(codeloc));
337*1fd5a2e1SPrashanth Swaminathan
338*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
339*1fd5a2e1SPrashanth Swaminathan }
340*1fd5a2e1SPrashanth Swaminathan
341*1fd5a2e1SPrashanth Swaminathan /* Basically the trampoline invokes ffi_closure_SYSV, and on
342*1fd5a2e1SPrashanth Swaminathan * entry, r3 holds the address of the closure.
343*1fd5a2e1SPrashanth Swaminathan * After storing the registers that could possibly contain
344*1fd5a2e1SPrashanth Swaminathan * parameters to be passed into the stack frame and setting
345*1fd5a2e1SPrashanth Swaminathan * up space for a return value, ffi_closure_SYSV invokes the
346*1fd5a2e1SPrashanth Swaminathan * following helper function to do most of the work.
347*1fd5a2e1SPrashanth Swaminathan */
348*1fd5a2e1SPrashanth Swaminathan
349*1fd5a2e1SPrashanth Swaminathan int
ffi_closure_helper_SYSV(ffi_closure * closure,UINT64 * rvalue,UINT64 * pgr,UINT64 * pfr,UINT64 * pst)350*1fd5a2e1SPrashanth Swaminathan ffi_closure_helper_SYSV (ffi_closure *closure, UINT64 *rvalue,
351*1fd5a2e1SPrashanth Swaminathan UINT64 *pgr, UINT64 *pfr, UINT64 *pst)
352*1fd5a2e1SPrashanth Swaminathan {
353*1fd5a2e1SPrashanth Swaminathan void **avalue;
354*1fd5a2e1SPrashanth Swaminathan ffi_type **p_arg;
355*1fd5a2e1SPrashanth Swaminathan int i, avn;
356*1fd5a2e1SPrashanth Swaminathan int greg, freg;
357*1fd5a2e1SPrashanth Swaminathan ffi_cif *cif;
358*1fd5a2e1SPrashanth Swaminathan int fpair = -1;
359*1fd5a2e1SPrashanth Swaminathan
360*1fd5a2e1SPrashanth Swaminathan cif = closure->cif;
361*1fd5a2e1SPrashanth Swaminathan avalue = alloca (cif->nargs * sizeof (void *));
362*1fd5a2e1SPrashanth Swaminathan
363*1fd5a2e1SPrashanth Swaminathan /* Copy the caller's structure return value address so that the closure
364*1fd5a2e1SPrashanth Swaminathan returns the data directly to the caller. */
365*1fd5a2e1SPrashanth Swaminathan if (return_type (cif->rtype) == FFI_TYPE_STRUCT)
366*1fd5a2e1SPrashanth Swaminathan {
367*1fd5a2e1SPrashanth Swaminathan rvalue = (UINT64 *) *pgr;
368*1fd5a2e1SPrashanth Swaminathan greg = 1;
369*1fd5a2e1SPrashanth Swaminathan }
370*1fd5a2e1SPrashanth Swaminathan else
371*1fd5a2e1SPrashanth Swaminathan greg = 0;
372*1fd5a2e1SPrashanth Swaminathan
373*1fd5a2e1SPrashanth Swaminathan freg = 0;
374*1fd5a2e1SPrashanth Swaminathan cif = closure->cif;
375*1fd5a2e1SPrashanth Swaminathan avn = cif->nargs;
376*1fd5a2e1SPrashanth Swaminathan
377*1fd5a2e1SPrashanth Swaminathan /* Grab the addresses of the arguments from the stack frame. */
378*1fd5a2e1SPrashanth Swaminathan for (i = 0, p_arg = cif->arg_types; i < avn; i++, p_arg++)
379*1fd5a2e1SPrashanth Swaminathan {
380*1fd5a2e1SPrashanth Swaminathan size_t z;
381*1fd5a2e1SPrashanth Swaminathan void *p;
382*1fd5a2e1SPrashanth Swaminathan
383*1fd5a2e1SPrashanth Swaminathan z = (*p_arg)->size;
384*1fd5a2e1SPrashanth Swaminathan if (z < sizeof (UINT32))
385*1fd5a2e1SPrashanth Swaminathan {
386*1fd5a2e1SPrashanth Swaminathan p = pgr + greg++;
387*1fd5a2e1SPrashanth Swaminathan
388*1fd5a2e1SPrashanth Swaminathan switch ((*p_arg)->type)
389*1fd5a2e1SPrashanth Swaminathan {
390*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
391*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
392*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
393*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
394*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_STRUCT:
395*1fd5a2e1SPrashanth Swaminathan #ifdef __LITTLE_ENDIAN__
396*1fd5a2e1SPrashanth Swaminathan avalue[i] = p;
397*1fd5a2e1SPrashanth Swaminathan #else
398*1fd5a2e1SPrashanth Swaminathan avalue[i] = ((char *) p) + sizeof (UINT32) - z;
399*1fd5a2e1SPrashanth Swaminathan #endif
400*1fd5a2e1SPrashanth Swaminathan break;
401*1fd5a2e1SPrashanth Swaminathan
402*1fd5a2e1SPrashanth Swaminathan default:
403*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT(0);
404*1fd5a2e1SPrashanth Swaminathan }
405*1fd5a2e1SPrashanth Swaminathan }
406*1fd5a2e1SPrashanth Swaminathan else if (z == sizeof (UINT32))
407*1fd5a2e1SPrashanth Swaminathan {
408*1fd5a2e1SPrashanth Swaminathan if ((*p_arg)->type == FFI_TYPE_FLOAT)
409*1fd5a2e1SPrashanth Swaminathan {
410*1fd5a2e1SPrashanth Swaminathan if (freg < NFREGARG - 1)
411*1fd5a2e1SPrashanth Swaminathan {
412*1fd5a2e1SPrashanth Swaminathan if (fpair >= 0)
413*1fd5a2e1SPrashanth Swaminathan {
414*1fd5a2e1SPrashanth Swaminathan avalue[i] = (UINT32 *) pfr + fpair;
415*1fd5a2e1SPrashanth Swaminathan fpair = -1;
416*1fd5a2e1SPrashanth Swaminathan }
417*1fd5a2e1SPrashanth Swaminathan else
418*1fd5a2e1SPrashanth Swaminathan {
419*1fd5a2e1SPrashanth Swaminathan #ifdef __LITTLE_ENDIAN__
420*1fd5a2e1SPrashanth Swaminathan fpair = freg;
421*1fd5a2e1SPrashanth Swaminathan avalue[i] = (UINT32 *) pfr + (1 ^ freg);
422*1fd5a2e1SPrashanth Swaminathan #else
423*1fd5a2e1SPrashanth Swaminathan fpair = 1 ^ freg;
424*1fd5a2e1SPrashanth Swaminathan avalue[i] = (UINT32 *) pfr + freg;
425*1fd5a2e1SPrashanth Swaminathan #endif
426*1fd5a2e1SPrashanth Swaminathan freg += 2;
427*1fd5a2e1SPrashanth Swaminathan }
428*1fd5a2e1SPrashanth Swaminathan }
429*1fd5a2e1SPrashanth Swaminathan else
430*1fd5a2e1SPrashanth Swaminathan #ifdef __LITTLE_ENDIAN__
431*1fd5a2e1SPrashanth Swaminathan avalue[i] = pgr + greg;
432*1fd5a2e1SPrashanth Swaminathan #else
433*1fd5a2e1SPrashanth Swaminathan avalue[i] = (UINT32 *) (pgr + greg) + 1;
434*1fd5a2e1SPrashanth Swaminathan #endif
435*1fd5a2e1SPrashanth Swaminathan }
436*1fd5a2e1SPrashanth Swaminathan else
437*1fd5a2e1SPrashanth Swaminathan #ifdef __LITTLE_ENDIAN__
438*1fd5a2e1SPrashanth Swaminathan avalue[i] = pgr + greg;
439*1fd5a2e1SPrashanth Swaminathan #else
440*1fd5a2e1SPrashanth Swaminathan avalue[i] = (UINT32 *) (pgr + greg) + 1;
441*1fd5a2e1SPrashanth Swaminathan #endif
442*1fd5a2e1SPrashanth Swaminathan greg++;
443*1fd5a2e1SPrashanth Swaminathan }
444*1fd5a2e1SPrashanth Swaminathan else if ((*p_arg)->type == FFI_TYPE_DOUBLE)
445*1fd5a2e1SPrashanth Swaminathan {
446*1fd5a2e1SPrashanth Swaminathan if (freg + 1 >= NFREGARG)
447*1fd5a2e1SPrashanth Swaminathan avalue[i] = pgr + greg;
448*1fd5a2e1SPrashanth Swaminathan else
449*1fd5a2e1SPrashanth Swaminathan {
450*1fd5a2e1SPrashanth Swaminathan avalue[i] = pfr + (freg >> 1);
451*1fd5a2e1SPrashanth Swaminathan freg += 2;
452*1fd5a2e1SPrashanth Swaminathan }
453*1fd5a2e1SPrashanth Swaminathan greg++;
454*1fd5a2e1SPrashanth Swaminathan }
455*1fd5a2e1SPrashanth Swaminathan else
456*1fd5a2e1SPrashanth Swaminathan {
457*1fd5a2e1SPrashanth Swaminathan int n = (z + sizeof (UINT64) - 1) / sizeof (UINT64);
458*1fd5a2e1SPrashanth Swaminathan
459*1fd5a2e1SPrashanth Swaminathan avalue[i] = pgr + greg;
460*1fd5a2e1SPrashanth Swaminathan greg += n;
461*1fd5a2e1SPrashanth Swaminathan }
462*1fd5a2e1SPrashanth Swaminathan }
463*1fd5a2e1SPrashanth Swaminathan
464*1fd5a2e1SPrashanth Swaminathan (closure->fun) (cif, rvalue, avalue, closure->user_data);
465*1fd5a2e1SPrashanth Swaminathan
466*1fd5a2e1SPrashanth Swaminathan /* Tell ffi_closure_SYSV how to perform return type promotions. */
467*1fd5a2e1SPrashanth Swaminathan return return_type (cif->rtype);
468*1fd5a2e1SPrashanth Swaminathan }
469*1fd5a2e1SPrashanth Swaminathan
470