1*1fd5a2e1SPrashanth Swaminathan /* -----------------------------------------------------------------------
2*1fd5a2e1SPrashanth Swaminathan ffi.c - Copyright (C) 2012, 2013, 2018 Anthony Green
3*1fd5a2e1SPrashanth Swaminathan
4*1fd5a2e1SPrashanth Swaminathan Moxie 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,
18*1fd5a2e1SPrashanth Swaminathan EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19*1fd5a2e1SPrashanth Swaminathan MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20*1fd5a2e1SPrashanth Swaminathan NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21*1fd5a2e1SPrashanth Swaminathan HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22*1fd5a2e1SPrashanth Swaminathan WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23*1fd5a2e1SPrashanth Swaminathan OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24*1fd5a2e1SPrashanth Swaminathan DEALINGS IN THE SOFTWARE.
25*1fd5a2e1SPrashanth Swaminathan ----------------------------------------------------------------------- */
26*1fd5a2e1SPrashanth Swaminathan
27*1fd5a2e1SPrashanth Swaminathan #include <ffi.h>
28*1fd5a2e1SPrashanth Swaminathan #include <ffi_common.h>
29*1fd5a2e1SPrashanth Swaminathan
30*1fd5a2e1SPrashanth Swaminathan #include <stdlib.h>
31*1fd5a2e1SPrashanth Swaminathan
32*1fd5a2e1SPrashanth Swaminathan /* ffi_prep_args is called by the assembly routine once stack space
33*1fd5a2e1SPrashanth Swaminathan has been allocated for the function's arguments */
34*1fd5a2e1SPrashanth Swaminathan
ffi_prep_args(char * stack,extended_cif * ecif)35*1fd5a2e1SPrashanth Swaminathan void *ffi_prep_args(char *stack, extended_cif *ecif)
36*1fd5a2e1SPrashanth Swaminathan {
37*1fd5a2e1SPrashanth Swaminathan register unsigned int i;
38*1fd5a2e1SPrashanth Swaminathan register void **p_argv;
39*1fd5a2e1SPrashanth Swaminathan register char *argp;
40*1fd5a2e1SPrashanth Swaminathan register ffi_type **p_arg;
41*1fd5a2e1SPrashanth Swaminathan register int count = 0;
42*1fd5a2e1SPrashanth Swaminathan
43*1fd5a2e1SPrashanth Swaminathan p_argv = ecif->avalue;
44*1fd5a2e1SPrashanth Swaminathan argp = stack;
45*1fd5a2e1SPrashanth Swaminathan
46*1fd5a2e1SPrashanth Swaminathan if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
47*1fd5a2e1SPrashanth Swaminathan {
48*1fd5a2e1SPrashanth Swaminathan *(void **) argp = ecif->rvalue;
49*1fd5a2e1SPrashanth Swaminathan argp += 4;
50*1fd5a2e1SPrashanth Swaminathan }
51*1fd5a2e1SPrashanth Swaminathan
52*1fd5a2e1SPrashanth Swaminathan for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
53*1fd5a2e1SPrashanth Swaminathan (i != 0);
54*1fd5a2e1SPrashanth Swaminathan i--, p_arg++)
55*1fd5a2e1SPrashanth Swaminathan {
56*1fd5a2e1SPrashanth Swaminathan size_t z;
57*1fd5a2e1SPrashanth Swaminathan
58*1fd5a2e1SPrashanth Swaminathan z = (*p_arg)->size;
59*1fd5a2e1SPrashanth Swaminathan
60*1fd5a2e1SPrashanth Swaminathan if ((*p_arg)->type == FFI_TYPE_STRUCT)
61*1fd5a2e1SPrashanth Swaminathan {
62*1fd5a2e1SPrashanth Swaminathan z = sizeof(void*);
63*1fd5a2e1SPrashanth Swaminathan *(void **) argp = *p_argv;
64*1fd5a2e1SPrashanth Swaminathan }
65*1fd5a2e1SPrashanth Swaminathan else if (z < sizeof(int))
66*1fd5a2e1SPrashanth Swaminathan {
67*1fd5a2e1SPrashanth Swaminathan z = sizeof(int);
68*1fd5a2e1SPrashanth Swaminathan switch ((*p_arg)->type)
69*1fd5a2e1SPrashanth Swaminathan {
70*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
71*1fd5a2e1SPrashanth Swaminathan *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
72*1fd5a2e1SPrashanth Swaminathan break;
73*1fd5a2e1SPrashanth Swaminathan
74*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
75*1fd5a2e1SPrashanth Swaminathan *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
76*1fd5a2e1SPrashanth Swaminathan break;
77*1fd5a2e1SPrashanth Swaminathan
78*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
79*1fd5a2e1SPrashanth Swaminathan *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
80*1fd5a2e1SPrashanth Swaminathan break;
81*1fd5a2e1SPrashanth Swaminathan
82*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
83*1fd5a2e1SPrashanth Swaminathan *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
84*1fd5a2e1SPrashanth Swaminathan break;
85*1fd5a2e1SPrashanth Swaminathan
86*1fd5a2e1SPrashanth Swaminathan default:
87*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT(0);
88*1fd5a2e1SPrashanth Swaminathan }
89*1fd5a2e1SPrashanth Swaminathan }
90*1fd5a2e1SPrashanth Swaminathan else if (z == sizeof(int))
91*1fd5a2e1SPrashanth Swaminathan {
92*1fd5a2e1SPrashanth Swaminathan *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
93*1fd5a2e1SPrashanth Swaminathan }
94*1fd5a2e1SPrashanth Swaminathan else
95*1fd5a2e1SPrashanth Swaminathan {
96*1fd5a2e1SPrashanth Swaminathan memcpy(argp, *p_argv, z);
97*1fd5a2e1SPrashanth Swaminathan }
98*1fd5a2e1SPrashanth Swaminathan p_argv++;
99*1fd5a2e1SPrashanth Swaminathan argp += z;
100*1fd5a2e1SPrashanth Swaminathan count += z;
101*1fd5a2e1SPrashanth Swaminathan }
102*1fd5a2e1SPrashanth Swaminathan
103*1fd5a2e1SPrashanth Swaminathan return (stack + ((count > 24) ? 24 : FFI_ALIGN_DOWN(count, 8)));
104*1fd5a2e1SPrashanth Swaminathan }
105*1fd5a2e1SPrashanth Swaminathan
106*1fd5a2e1SPrashanth Swaminathan /* Perform machine dependent cif processing */
ffi_prep_cif_machdep(ffi_cif * cif)107*1fd5a2e1SPrashanth Swaminathan ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
108*1fd5a2e1SPrashanth Swaminathan {
109*1fd5a2e1SPrashanth Swaminathan if (cif->rtype->type == FFI_TYPE_STRUCT)
110*1fd5a2e1SPrashanth Swaminathan cif->flags = -1;
111*1fd5a2e1SPrashanth Swaminathan else
112*1fd5a2e1SPrashanth Swaminathan cif->flags = cif->rtype->size;
113*1fd5a2e1SPrashanth Swaminathan
114*1fd5a2e1SPrashanth Swaminathan cif->bytes = FFI_ALIGN (cif->bytes, 8);
115*1fd5a2e1SPrashanth Swaminathan
116*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
117*1fd5a2e1SPrashanth Swaminathan }
118*1fd5a2e1SPrashanth Swaminathan
119*1fd5a2e1SPrashanth Swaminathan extern void ffi_call_EABI(void *(*)(char *, extended_cif *),
120*1fd5a2e1SPrashanth Swaminathan extended_cif *,
121*1fd5a2e1SPrashanth Swaminathan unsigned, unsigned,
122*1fd5a2e1SPrashanth Swaminathan unsigned *,
123*1fd5a2e1SPrashanth Swaminathan void (*fn)(void));
124*1fd5a2e1SPrashanth Swaminathan
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)125*1fd5a2e1SPrashanth Swaminathan void ffi_call(ffi_cif *cif,
126*1fd5a2e1SPrashanth Swaminathan void (*fn)(void),
127*1fd5a2e1SPrashanth Swaminathan void *rvalue,
128*1fd5a2e1SPrashanth Swaminathan void **avalue)
129*1fd5a2e1SPrashanth Swaminathan {
130*1fd5a2e1SPrashanth Swaminathan extended_cif ecif;
131*1fd5a2e1SPrashanth Swaminathan
132*1fd5a2e1SPrashanth Swaminathan ecif.cif = cif;
133*1fd5a2e1SPrashanth Swaminathan ecif.avalue = avalue;
134*1fd5a2e1SPrashanth Swaminathan
135*1fd5a2e1SPrashanth Swaminathan /* If the return value is a struct and we don't have a return */
136*1fd5a2e1SPrashanth Swaminathan /* value address then we need to make one */
137*1fd5a2e1SPrashanth Swaminathan
138*1fd5a2e1SPrashanth Swaminathan if ((rvalue == NULL) &&
139*1fd5a2e1SPrashanth Swaminathan (cif->rtype->type == FFI_TYPE_STRUCT))
140*1fd5a2e1SPrashanth Swaminathan {
141*1fd5a2e1SPrashanth Swaminathan ecif.rvalue = alloca(cif->rtype->size);
142*1fd5a2e1SPrashanth Swaminathan }
143*1fd5a2e1SPrashanth Swaminathan else
144*1fd5a2e1SPrashanth Swaminathan ecif.rvalue = rvalue;
145*1fd5a2e1SPrashanth Swaminathan
146*1fd5a2e1SPrashanth Swaminathan switch (cif->abi)
147*1fd5a2e1SPrashanth Swaminathan {
148*1fd5a2e1SPrashanth Swaminathan case FFI_EABI:
149*1fd5a2e1SPrashanth Swaminathan ffi_call_EABI(ffi_prep_args, &ecif, cif->bytes,
150*1fd5a2e1SPrashanth Swaminathan cif->flags, ecif.rvalue, fn);
151*1fd5a2e1SPrashanth Swaminathan break;
152*1fd5a2e1SPrashanth Swaminathan default:
153*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT(0);
154*1fd5a2e1SPrashanth Swaminathan break;
155*1fd5a2e1SPrashanth Swaminathan }
156*1fd5a2e1SPrashanth Swaminathan }
157*1fd5a2e1SPrashanth Swaminathan
ffi_closure_eabi(unsigned arg1,unsigned arg2,unsigned arg3,unsigned arg4,unsigned arg5,unsigned arg6)158*1fd5a2e1SPrashanth Swaminathan void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
159*1fd5a2e1SPrashanth Swaminathan unsigned arg4, unsigned arg5, unsigned arg6)
160*1fd5a2e1SPrashanth Swaminathan {
161*1fd5a2e1SPrashanth Swaminathan /* This function is called by a trampoline. The trampoline stows a
162*1fd5a2e1SPrashanth Swaminathan pointer to the ffi_closure object in $r12. We must save this
163*1fd5a2e1SPrashanth Swaminathan pointer in a place that will persist while we do our work. */
164*1fd5a2e1SPrashanth Swaminathan register ffi_closure *creg __asm__ ("$r12");
165*1fd5a2e1SPrashanth Swaminathan ffi_closure *closure = creg;
166*1fd5a2e1SPrashanth Swaminathan
167*1fd5a2e1SPrashanth Swaminathan /* Arguments that don't fit in registers are found on the stack
168*1fd5a2e1SPrashanth Swaminathan at a fixed offset above the current frame pointer. */
169*1fd5a2e1SPrashanth Swaminathan register char *frame_pointer __asm__ ("$fp");
170*1fd5a2e1SPrashanth Swaminathan
171*1fd5a2e1SPrashanth Swaminathan /* Pointer to a struct return value. */
172*1fd5a2e1SPrashanth Swaminathan void *struct_rvalue = (void *) arg1;
173*1fd5a2e1SPrashanth Swaminathan
174*1fd5a2e1SPrashanth Swaminathan /* 6 words reserved for register args + 3 words from jsr */
175*1fd5a2e1SPrashanth Swaminathan char *stack_args = frame_pointer + 9*4;
176*1fd5a2e1SPrashanth Swaminathan
177*1fd5a2e1SPrashanth Swaminathan /* Lay the register arguments down in a continuous chunk of memory. */
178*1fd5a2e1SPrashanth Swaminathan unsigned register_args[6] =
179*1fd5a2e1SPrashanth Swaminathan { arg1, arg2, arg3, arg4, arg5, arg6 };
180*1fd5a2e1SPrashanth Swaminathan char *register_args_ptr = (char *) register_args;
181*1fd5a2e1SPrashanth Swaminathan
182*1fd5a2e1SPrashanth Swaminathan ffi_cif *cif = closure->cif;
183*1fd5a2e1SPrashanth Swaminathan ffi_type **arg_types = cif->arg_types;
184*1fd5a2e1SPrashanth Swaminathan void **avalue = alloca (cif->nargs * sizeof(void *));
185*1fd5a2e1SPrashanth Swaminathan char *ptr = (char *) register_args;
186*1fd5a2e1SPrashanth Swaminathan int i;
187*1fd5a2e1SPrashanth Swaminathan
188*1fd5a2e1SPrashanth Swaminathan /* preserve struct type return pointer passing */
189*1fd5a2e1SPrashanth Swaminathan if ((cif->rtype != NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) {
190*1fd5a2e1SPrashanth Swaminathan ptr += 4;
191*1fd5a2e1SPrashanth Swaminathan register_args_ptr = (char *)®ister_args[1];
192*1fd5a2e1SPrashanth Swaminathan }
193*1fd5a2e1SPrashanth Swaminathan
194*1fd5a2e1SPrashanth Swaminathan /* Find the address of each argument. */
195*1fd5a2e1SPrashanth Swaminathan for (i = 0; i < cif->nargs; i++)
196*1fd5a2e1SPrashanth Swaminathan {
197*1fd5a2e1SPrashanth Swaminathan switch (arg_types[i]->type)
198*1fd5a2e1SPrashanth Swaminathan {
199*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
200*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
201*1fd5a2e1SPrashanth Swaminathan avalue[i] = ptr + 3;
202*1fd5a2e1SPrashanth Swaminathan break;
203*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
204*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
205*1fd5a2e1SPrashanth Swaminathan avalue[i] = ptr + 2;
206*1fd5a2e1SPrashanth Swaminathan break;
207*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT32:
208*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT32:
209*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
210*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_POINTER:
211*1fd5a2e1SPrashanth Swaminathan avalue[i] = ptr;
212*1fd5a2e1SPrashanth Swaminathan break;
213*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_STRUCT:
214*1fd5a2e1SPrashanth Swaminathan avalue[i] = *(void**)ptr;
215*1fd5a2e1SPrashanth Swaminathan break;
216*1fd5a2e1SPrashanth Swaminathan default:
217*1fd5a2e1SPrashanth Swaminathan /* This is an 8-byte value. */
218*1fd5a2e1SPrashanth Swaminathan if (ptr == (char *) ®ister_args[5])
219*1fd5a2e1SPrashanth Swaminathan {
220*1fd5a2e1SPrashanth Swaminathan /* The value is split across two locations */
221*1fd5a2e1SPrashanth Swaminathan unsigned *ip = alloca(8);
222*1fd5a2e1SPrashanth Swaminathan avalue[i] = ip;
223*1fd5a2e1SPrashanth Swaminathan ip[0] = *(unsigned *) ptr;
224*1fd5a2e1SPrashanth Swaminathan ip[1] = *(unsigned *) stack_args;
225*1fd5a2e1SPrashanth Swaminathan }
226*1fd5a2e1SPrashanth Swaminathan else
227*1fd5a2e1SPrashanth Swaminathan {
228*1fd5a2e1SPrashanth Swaminathan avalue[i] = ptr;
229*1fd5a2e1SPrashanth Swaminathan }
230*1fd5a2e1SPrashanth Swaminathan ptr += 4;
231*1fd5a2e1SPrashanth Swaminathan break;
232*1fd5a2e1SPrashanth Swaminathan }
233*1fd5a2e1SPrashanth Swaminathan ptr += 4;
234*1fd5a2e1SPrashanth Swaminathan
235*1fd5a2e1SPrashanth Swaminathan /* If we've handled more arguments than fit in registers,
236*1fd5a2e1SPrashanth Swaminathan start looking at the those passed on the stack. */
237*1fd5a2e1SPrashanth Swaminathan if (ptr == (char *) ®ister_args[6])
238*1fd5a2e1SPrashanth Swaminathan ptr = stack_args;
239*1fd5a2e1SPrashanth Swaminathan else if (ptr == (char *) ®ister_args[7])
240*1fd5a2e1SPrashanth Swaminathan ptr = stack_args + 4;
241*1fd5a2e1SPrashanth Swaminathan }
242*1fd5a2e1SPrashanth Swaminathan
243*1fd5a2e1SPrashanth Swaminathan /* Invoke the closure. */
244*1fd5a2e1SPrashanth Swaminathan if (cif->rtype && (cif->rtype->type == FFI_TYPE_STRUCT))
245*1fd5a2e1SPrashanth Swaminathan {
246*1fd5a2e1SPrashanth Swaminathan (closure->fun) (cif, struct_rvalue, avalue, closure->user_data);
247*1fd5a2e1SPrashanth Swaminathan }
248*1fd5a2e1SPrashanth Swaminathan else
249*1fd5a2e1SPrashanth Swaminathan {
250*1fd5a2e1SPrashanth Swaminathan /* Allocate space for the return value and call the function. */
251*1fd5a2e1SPrashanth Swaminathan long long rvalue;
252*1fd5a2e1SPrashanth Swaminathan (closure->fun) (cif, &rvalue, avalue, closure->user_data);
253*1fd5a2e1SPrashanth Swaminathan asm ("mov $r12, %0\n ld.l $r0, ($r12)\n ldo.l $r1, 4($r12)" : : "r" (&rvalue));
254*1fd5a2e1SPrashanth Swaminathan }
255*1fd5a2e1SPrashanth Swaminathan }
256*1fd5a2e1SPrashanth Swaminathan
257*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)258*1fd5a2e1SPrashanth Swaminathan ffi_prep_closure_loc (ffi_closure* closure,
259*1fd5a2e1SPrashanth Swaminathan ffi_cif* cif,
260*1fd5a2e1SPrashanth Swaminathan void (*fun)(ffi_cif*, void*, void**, void*),
261*1fd5a2e1SPrashanth Swaminathan void *user_data,
262*1fd5a2e1SPrashanth Swaminathan void *codeloc)
263*1fd5a2e1SPrashanth Swaminathan {
264*1fd5a2e1SPrashanth Swaminathan unsigned short *tramp = (unsigned short *) &closure->tramp[0];
265*1fd5a2e1SPrashanth Swaminathan unsigned long fn = (long) ffi_closure_eabi;
266*1fd5a2e1SPrashanth Swaminathan unsigned long cls = (long) codeloc;
267*1fd5a2e1SPrashanth Swaminathan
268*1fd5a2e1SPrashanth Swaminathan if (cif->abi != FFI_EABI)
269*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_ABI;
270*1fd5a2e1SPrashanth Swaminathan
271*1fd5a2e1SPrashanth Swaminathan fn = (unsigned long) ffi_closure_eabi;
272*1fd5a2e1SPrashanth Swaminathan
273*1fd5a2e1SPrashanth Swaminathan tramp[0] = 0x01e0; /* ldi.l $r12, .... */
274*1fd5a2e1SPrashanth Swaminathan tramp[1] = cls >> 16;
275*1fd5a2e1SPrashanth Swaminathan tramp[2] = cls & 0xffff;
276*1fd5a2e1SPrashanth Swaminathan tramp[3] = 0x1a00; /* jmpa .... */
277*1fd5a2e1SPrashanth Swaminathan tramp[4] = fn >> 16;
278*1fd5a2e1SPrashanth Swaminathan tramp[5] = fn & 0xffff;
279*1fd5a2e1SPrashanth Swaminathan
280*1fd5a2e1SPrashanth Swaminathan closure->cif = cif;
281*1fd5a2e1SPrashanth Swaminathan closure->fun = fun;
282*1fd5a2e1SPrashanth Swaminathan closure->user_data = user_data;
283*1fd5a2e1SPrashanth Swaminathan
284*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
285*1fd5a2e1SPrashanth Swaminathan }
286