1*1fd5a2e1SPrashanth Swaminathan /* -----------------------------------------------------------------------
2*1fd5a2e1SPrashanth Swaminathan ffi.c - Copyright (c) 2013 Synopsys, Inc. (www.synopsys.com)
3*1fd5a2e1SPrashanth Swaminathan
4*1fd5a2e1SPrashanth Swaminathan ARC Foreign Function Interface
5*1fd5a2e1SPrashanth Swaminathan
6*1fd5a2e1SPrashanth Swaminathan Permission is hereby granted, free of charge, to any person obtaining
7*1fd5a2e1SPrashanth Swaminathan a copy of this software and associated documentation files (the
8*1fd5a2e1SPrashanth Swaminathan ``Software''), to deal in the Software without restriction, including
9*1fd5a2e1SPrashanth Swaminathan without limitation the rights to use, copy, modify, merge, publish,
10*1fd5a2e1SPrashanth Swaminathan distribute, sublicense, and/or sell copies of the Software, and to
11*1fd5a2e1SPrashanth Swaminathan permit persons to whom the Software is furnished to do so, subject to
12*1fd5a2e1SPrashanth Swaminathan the following conditions:
13*1fd5a2e1SPrashanth Swaminathan
14*1fd5a2e1SPrashanth Swaminathan The above copyright notice and this permission notice shall be included
15*1fd5a2e1SPrashanth Swaminathan in all copies or substantial portions of the Software.
16*1fd5a2e1SPrashanth Swaminathan
17*1fd5a2e1SPrashanth Swaminathan THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
18*1fd5a2e1SPrashanth Swaminathan OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19*1fd5a2e1SPrashanth Swaminathan MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20*1fd5a2e1SPrashanth Swaminathan IN NO EVENT SHALL RENESAS TECHNOLOGY BE LIABLE FOR ANY CLAIM, DAMAGES OR
21*1fd5a2e1SPrashanth Swaminathan OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22*1fd5a2e1SPrashanth Swaminathan ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23*1fd5a2e1SPrashanth Swaminathan OTHER DEALINGS IN THE SOFTWARE.
24*1fd5a2e1SPrashanth Swaminathan ----------------------------------------------------------------------- */
25*1fd5a2e1SPrashanth Swaminathan
26*1fd5a2e1SPrashanth Swaminathan #include <ffi.h>
27*1fd5a2e1SPrashanth Swaminathan #include <ffi_common.h>
28*1fd5a2e1SPrashanth Swaminathan
29*1fd5a2e1SPrashanth Swaminathan #include <stdlib.h>
30*1fd5a2e1SPrashanth Swaminathan #include <stdint.h>
31*1fd5a2e1SPrashanth Swaminathan
32*1fd5a2e1SPrashanth Swaminathan #include <sys/cachectl.h>
33*1fd5a2e1SPrashanth Swaminathan
34*1fd5a2e1SPrashanth Swaminathan /* for little endian ARC, the code is in fact stored as mixed endian for
35*1fd5a2e1SPrashanth Swaminathan performance reasons */
36*1fd5a2e1SPrashanth Swaminathan #if __BIG_ENDIAN__
37*1fd5a2e1SPrashanth Swaminathan #define CODE_ENDIAN(x) (x)
38*1fd5a2e1SPrashanth Swaminathan #else
39*1fd5a2e1SPrashanth Swaminathan #define CODE_ENDIAN(x) ( (((uint32_t) (x)) << 16) | (((uint32_t) (x)) >> 16))
40*1fd5a2e1SPrashanth Swaminathan #endif
41*1fd5a2e1SPrashanth Swaminathan
42*1fd5a2e1SPrashanth Swaminathan /* ffi_prep_args is called by the assembly routine once stack
43*1fd5a2e1SPrashanth Swaminathan space has been allocated for the function's arguments. */
44*1fd5a2e1SPrashanth Swaminathan
45*1fd5a2e1SPrashanth Swaminathan void
ffi_prep_args(char * stack,extended_cif * ecif)46*1fd5a2e1SPrashanth Swaminathan ffi_prep_args (char *stack, extended_cif * ecif)
47*1fd5a2e1SPrashanth Swaminathan {
48*1fd5a2e1SPrashanth Swaminathan unsigned int i;
49*1fd5a2e1SPrashanth Swaminathan void **p_argv;
50*1fd5a2e1SPrashanth Swaminathan char *argp;
51*1fd5a2e1SPrashanth Swaminathan ffi_type **p_arg;
52*1fd5a2e1SPrashanth Swaminathan
53*1fd5a2e1SPrashanth Swaminathan argp = stack;
54*1fd5a2e1SPrashanth Swaminathan
55*1fd5a2e1SPrashanth Swaminathan if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
56*1fd5a2e1SPrashanth Swaminathan {
57*1fd5a2e1SPrashanth Swaminathan *(void **) argp = ecif->rvalue;
58*1fd5a2e1SPrashanth Swaminathan argp += 4;
59*1fd5a2e1SPrashanth Swaminathan }
60*1fd5a2e1SPrashanth Swaminathan
61*1fd5a2e1SPrashanth Swaminathan p_argv = ecif->avalue;
62*1fd5a2e1SPrashanth Swaminathan
63*1fd5a2e1SPrashanth Swaminathan for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
64*1fd5a2e1SPrashanth Swaminathan (i != 0); i--, p_arg++)
65*1fd5a2e1SPrashanth Swaminathan {
66*1fd5a2e1SPrashanth Swaminathan size_t z;
67*1fd5a2e1SPrashanth Swaminathan int alignment;
68*1fd5a2e1SPrashanth Swaminathan
69*1fd5a2e1SPrashanth Swaminathan /* align alignment to 4 */
70*1fd5a2e1SPrashanth Swaminathan alignment = (((*p_arg)->alignment - 1) | 3) + 1;
71*1fd5a2e1SPrashanth Swaminathan
72*1fd5a2e1SPrashanth Swaminathan /* Align if necessary. */
73*1fd5a2e1SPrashanth Swaminathan if ((alignment - 1) & (unsigned) argp)
74*1fd5a2e1SPrashanth Swaminathan argp = (char *) FFI_ALIGN (argp, alignment);
75*1fd5a2e1SPrashanth Swaminathan
76*1fd5a2e1SPrashanth Swaminathan z = (*p_arg)->size;
77*1fd5a2e1SPrashanth Swaminathan if (z < sizeof (int))
78*1fd5a2e1SPrashanth Swaminathan {
79*1fd5a2e1SPrashanth Swaminathan z = sizeof (int);
80*1fd5a2e1SPrashanth Swaminathan
81*1fd5a2e1SPrashanth Swaminathan switch ((*p_arg)->type)
82*1fd5a2e1SPrashanth Swaminathan {
83*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
84*1fd5a2e1SPrashanth Swaminathan *(signed int *) argp = (signed int) *(SINT8 *) (*p_argv);
85*1fd5a2e1SPrashanth Swaminathan break;
86*1fd5a2e1SPrashanth Swaminathan
87*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
88*1fd5a2e1SPrashanth Swaminathan *(unsigned int *) argp = (unsigned int) *(UINT8 *) (*p_argv);
89*1fd5a2e1SPrashanth Swaminathan break;
90*1fd5a2e1SPrashanth Swaminathan
91*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
92*1fd5a2e1SPrashanth Swaminathan *(signed int *) argp = (signed int) *(SINT16 *) (*p_argv);
93*1fd5a2e1SPrashanth Swaminathan break;
94*1fd5a2e1SPrashanth Swaminathan
95*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
96*1fd5a2e1SPrashanth Swaminathan *(unsigned int *) argp = (unsigned int) *(UINT16 *) (*p_argv);
97*1fd5a2e1SPrashanth Swaminathan break;
98*1fd5a2e1SPrashanth Swaminathan
99*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_STRUCT:
100*1fd5a2e1SPrashanth Swaminathan memcpy (argp, *p_argv, (*p_arg)->size);
101*1fd5a2e1SPrashanth Swaminathan break;
102*1fd5a2e1SPrashanth Swaminathan
103*1fd5a2e1SPrashanth Swaminathan default:
104*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT (0);
105*1fd5a2e1SPrashanth Swaminathan }
106*1fd5a2e1SPrashanth Swaminathan }
107*1fd5a2e1SPrashanth Swaminathan else if (z == sizeof (int))
108*1fd5a2e1SPrashanth Swaminathan {
109*1fd5a2e1SPrashanth Swaminathan *(unsigned int *) argp = (unsigned int) *(UINT32 *) (*p_argv);
110*1fd5a2e1SPrashanth Swaminathan }
111*1fd5a2e1SPrashanth Swaminathan else
112*1fd5a2e1SPrashanth Swaminathan {
113*1fd5a2e1SPrashanth Swaminathan if ((*p_arg)->type == FFI_TYPE_STRUCT)
114*1fd5a2e1SPrashanth Swaminathan {
115*1fd5a2e1SPrashanth Swaminathan memcpy (argp, *p_argv, z);
116*1fd5a2e1SPrashanth Swaminathan }
117*1fd5a2e1SPrashanth Swaminathan else
118*1fd5a2e1SPrashanth Swaminathan {
119*1fd5a2e1SPrashanth Swaminathan /* Double or long long 64bit. */
120*1fd5a2e1SPrashanth Swaminathan memcpy (argp, *p_argv, z);
121*1fd5a2e1SPrashanth Swaminathan }
122*1fd5a2e1SPrashanth Swaminathan }
123*1fd5a2e1SPrashanth Swaminathan p_argv++;
124*1fd5a2e1SPrashanth Swaminathan argp += z;
125*1fd5a2e1SPrashanth Swaminathan }
126*1fd5a2e1SPrashanth Swaminathan
127*1fd5a2e1SPrashanth Swaminathan return;
128*1fd5a2e1SPrashanth Swaminathan }
129*1fd5a2e1SPrashanth Swaminathan
130*1fd5a2e1SPrashanth Swaminathan /* Perform machine dependent cif processing. */
131*1fd5a2e1SPrashanth Swaminathan ffi_status
ffi_prep_cif_machdep(ffi_cif * cif)132*1fd5a2e1SPrashanth Swaminathan ffi_prep_cif_machdep (ffi_cif * cif)
133*1fd5a2e1SPrashanth Swaminathan {
134*1fd5a2e1SPrashanth Swaminathan /* Set the return type flag. */
135*1fd5a2e1SPrashanth Swaminathan switch (cif->rtype->type)
136*1fd5a2e1SPrashanth Swaminathan {
137*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_VOID:
138*1fd5a2e1SPrashanth Swaminathan cif->flags = (unsigned) cif->rtype->type;
139*1fd5a2e1SPrashanth Swaminathan break;
140*1fd5a2e1SPrashanth Swaminathan
141*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_STRUCT:
142*1fd5a2e1SPrashanth Swaminathan cif->flags = (unsigned) cif->rtype->type;
143*1fd5a2e1SPrashanth Swaminathan break;
144*1fd5a2e1SPrashanth Swaminathan
145*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT64:
146*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT64:
147*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_DOUBLE:
148*1fd5a2e1SPrashanth Swaminathan cif->flags = FFI_TYPE_DOUBLE;
149*1fd5a2e1SPrashanth Swaminathan break;
150*1fd5a2e1SPrashanth Swaminathan
151*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
152*1fd5a2e1SPrashanth Swaminathan default:
153*1fd5a2e1SPrashanth Swaminathan cif->flags = FFI_TYPE_INT;
154*1fd5a2e1SPrashanth Swaminathan break;
155*1fd5a2e1SPrashanth Swaminathan }
156*1fd5a2e1SPrashanth Swaminathan
157*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
158*1fd5a2e1SPrashanth Swaminathan }
159*1fd5a2e1SPrashanth Swaminathan
160*1fd5a2e1SPrashanth Swaminathan extern void ffi_call_ARCompact (void (*)(char *, extended_cif *),
161*1fd5a2e1SPrashanth Swaminathan extended_cif *, unsigned, unsigned,
162*1fd5a2e1SPrashanth Swaminathan unsigned *, void (*fn) (void));
163*1fd5a2e1SPrashanth Swaminathan
164*1fd5a2e1SPrashanth Swaminathan void
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)165*1fd5a2e1SPrashanth Swaminathan ffi_call (ffi_cif * cif, void (*fn) (void), void *rvalue, void **avalue)
166*1fd5a2e1SPrashanth Swaminathan {
167*1fd5a2e1SPrashanth Swaminathan extended_cif ecif;
168*1fd5a2e1SPrashanth Swaminathan
169*1fd5a2e1SPrashanth Swaminathan ecif.cif = cif;
170*1fd5a2e1SPrashanth Swaminathan ecif.avalue = avalue;
171*1fd5a2e1SPrashanth Swaminathan
172*1fd5a2e1SPrashanth Swaminathan /* If the return value is a struct and we don't have
173*1fd5a2e1SPrashanth Swaminathan a return value address then we need to make one. */
174*1fd5a2e1SPrashanth Swaminathan if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
175*1fd5a2e1SPrashanth Swaminathan {
176*1fd5a2e1SPrashanth Swaminathan ecif.rvalue = alloca (cif->rtype->size);
177*1fd5a2e1SPrashanth Swaminathan }
178*1fd5a2e1SPrashanth Swaminathan else
179*1fd5a2e1SPrashanth Swaminathan ecif.rvalue = rvalue;
180*1fd5a2e1SPrashanth Swaminathan
181*1fd5a2e1SPrashanth Swaminathan switch (cif->abi)
182*1fd5a2e1SPrashanth Swaminathan {
183*1fd5a2e1SPrashanth Swaminathan case FFI_ARCOMPACT:
184*1fd5a2e1SPrashanth Swaminathan ffi_call_ARCompact (ffi_prep_args, &ecif, cif->bytes,
185*1fd5a2e1SPrashanth Swaminathan cif->flags, ecif.rvalue, fn);
186*1fd5a2e1SPrashanth Swaminathan break;
187*1fd5a2e1SPrashanth Swaminathan
188*1fd5a2e1SPrashanth Swaminathan default:
189*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT (0);
190*1fd5a2e1SPrashanth Swaminathan break;
191*1fd5a2e1SPrashanth Swaminathan }
192*1fd5a2e1SPrashanth Swaminathan }
193*1fd5a2e1SPrashanth Swaminathan
194*1fd5a2e1SPrashanth Swaminathan int
ffi_closure_inner_ARCompact(ffi_closure * closure,void * rvalue,ffi_arg * args)195*1fd5a2e1SPrashanth Swaminathan ffi_closure_inner_ARCompact (ffi_closure * closure, void *rvalue,
196*1fd5a2e1SPrashanth Swaminathan ffi_arg * args)
197*1fd5a2e1SPrashanth Swaminathan {
198*1fd5a2e1SPrashanth Swaminathan void **arg_area, **p_argv;
199*1fd5a2e1SPrashanth Swaminathan ffi_cif *cif = closure->cif;
200*1fd5a2e1SPrashanth Swaminathan char *argp = (char *) args;
201*1fd5a2e1SPrashanth Swaminathan ffi_type **p_argt;
202*1fd5a2e1SPrashanth Swaminathan int i;
203*1fd5a2e1SPrashanth Swaminathan
204*1fd5a2e1SPrashanth Swaminathan arg_area = (void **) alloca (cif->nargs * sizeof (void *));
205*1fd5a2e1SPrashanth Swaminathan
206*1fd5a2e1SPrashanth Swaminathan /* handle hidden argument */
207*1fd5a2e1SPrashanth Swaminathan if (cif->flags == FFI_TYPE_STRUCT)
208*1fd5a2e1SPrashanth Swaminathan {
209*1fd5a2e1SPrashanth Swaminathan rvalue = *(void **) argp;
210*1fd5a2e1SPrashanth Swaminathan argp += 4;
211*1fd5a2e1SPrashanth Swaminathan }
212*1fd5a2e1SPrashanth Swaminathan
213*1fd5a2e1SPrashanth Swaminathan p_argv = arg_area;
214*1fd5a2e1SPrashanth Swaminathan
215*1fd5a2e1SPrashanth Swaminathan for (i = 0, p_argt = cif->arg_types; i < cif->nargs;
216*1fd5a2e1SPrashanth Swaminathan i++, p_argt++, p_argv++)
217*1fd5a2e1SPrashanth Swaminathan {
218*1fd5a2e1SPrashanth Swaminathan size_t z;
219*1fd5a2e1SPrashanth Swaminathan int alignment;
220*1fd5a2e1SPrashanth Swaminathan
221*1fd5a2e1SPrashanth Swaminathan /* align alignment to 4 */
222*1fd5a2e1SPrashanth Swaminathan alignment = (((*p_argt)->alignment - 1) | 3) + 1;
223*1fd5a2e1SPrashanth Swaminathan
224*1fd5a2e1SPrashanth Swaminathan /* Align if necessary. */
225*1fd5a2e1SPrashanth Swaminathan if ((alignment - 1) & (unsigned) argp)
226*1fd5a2e1SPrashanth Swaminathan argp = (char *) FFI_ALIGN (argp, alignment);
227*1fd5a2e1SPrashanth Swaminathan
228*1fd5a2e1SPrashanth Swaminathan z = (*p_argt)->size;
229*1fd5a2e1SPrashanth Swaminathan *p_argv = (void *) argp;
230*1fd5a2e1SPrashanth Swaminathan argp += z;
231*1fd5a2e1SPrashanth Swaminathan }
232*1fd5a2e1SPrashanth Swaminathan
233*1fd5a2e1SPrashanth Swaminathan (closure->fun) (cif, rvalue, arg_area, closure->user_data);
234*1fd5a2e1SPrashanth Swaminathan
235*1fd5a2e1SPrashanth Swaminathan return cif->flags;
236*1fd5a2e1SPrashanth Swaminathan }
237*1fd5a2e1SPrashanth Swaminathan
238*1fd5a2e1SPrashanth Swaminathan extern void ffi_closure_ARCompact (void);
239*1fd5a2e1SPrashanth Swaminathan
240*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)241*1fd5a2e1SPrashanth Swaminathan ffi_prep_closure_loc (ffi_closure * closure, ffi_cif * cif,
242*1fd5a2e1SPrashanth Swaminathan void (*fun) (ffi_cif *, void *, void **, void *),
243*1fd5a2e1SPrashanth Swaminathan void *user_data, void *codeloc)
244*1fd5a2e1SPrashanth Swaminathan {
245*1fd5a2e1SPrashanth Swaminathan uint32_t *tramp = (uint32_t *) & (closure->tramp[0]);
246*1fd5a2e1SPrashanth Swaminathan
247*1fd5a2e1SPrashanth Swaminathan switch (cif->abi)
248*1fd5a2e1SPrashanth Swaminathan {
249*1fd5a2e1SPrashanth Swaminathan case FFI_ARCOMPACT:
250*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT (tramp == codeloc);
251*1fd5a2e1SPrashanth Swaminathan tramp[0] = CODE_ENDIAN (0x200a1fc0); /* mov r8, pcl */
252*1fd5a2e1SPrashanth Swaminathan tramp[1] = CODE_ENDIAN (0x20200f80); /* j [long imm] */
253*1fd5a2e1SPrashanth Swaminathan tramp[2] = CODE_ENDIAN (ffi_closure_ARCompact);
254*1fd5a2e1SPrashanth Swaminathan break;
255*1fd5a2e1SPrashanth Swaminathan
256*1fd5a2e1SPrashanth Swaminathan default:
257*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_ABI;
258*1fd5a2e1SPrashanth Swaminathan }
259*1fd5a2e1SPrashanth Swaminathan
260*1fd5a2e1SPrashanth Swaminathan closure->cif = cif;
261*1fd5a2e1SPrashanth Swaminathan closure->fun = fun;
262*1fd5a2e1SPrashanth Swaminathan closure->user_data = user_data;
263*1fd5a2e1SPrashanth Swaminathan cacheflush (codeloc, FFI_TRAMPOLINE_SIZE, BCACHE);
264*1fd5a2e1SPrashanth Swaminathan
265*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
266*1fd5a2e1SPrashanth Swaminathan }
267