1*1fd5a2e1SPrashanth Swaminathan /* -----------------------------------------------------------------------
2*1fd5a2e1SPrashanth Swaminathan ffi.c - Copyright (c) 2011 Anthony Green
3*1fd5a2e1SPrashanth Swaminathan Copyright (c) 2009 Bradley Smith <[email protected]>
4*1fd5a2e1SPrashanth Swaminathan
5*1fd5a2e1SPrashanth Swaminathan AVR32 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 #include <stdio.h>
33*1fd5a2e1SPrashanth Swaminathan #include <unistd.h>
34*1fd5a2e1SPrashanth Swaminathan #include <asm/unistd.h>
35*1fd5a2e1SPrashanth Swaminathan
36*1fd5a2e1SPrashanth Swaminathan /* #define DEBUG */
37*1fd5a2e1SPrashanth Swaminathan
38*1fd5a2e1SPrashanth Swaminathan extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
39*1fd5a2e1SPrashanth Swaminathan unsigned int, unsigned int, unsigned int*, unsigned int,
40*1fd5a2e1SPrashanth Swaminathan void (*fn)(void));
41*1fd5a2e1SPrashanth Swaminathan extern void ffi_closure_SYSV (ffi_closure *);
42*1fd5a2e1SPrashanth Swaminathan
pass_struct_on_stack(ffi_type * type)43*1fd5a2e1SPrashanth Swaminathan unsigned int pass_struct_on_stack(ffi_type *type)
44*1fd5a2e1SPrashanth Swaminathan {
45*1fd5a2e1SPrashanth Swaminathan if(type->type != FFI_TYPE_STRUCT)
46*1fd5a2e1SPrashanth Swaminathan return 0;
47*1fd5a2e1SPrashanth Swaminathan
48*1fd5a2e1SPrashanth Swaminathan if(type->alignment < type->size &&
49*1fd5a2e1SPrashanth Swaminathan !(type->size == 4 || type->size == 8) &&
50*1fd5a2e1SPrashanth Swaminathan !(type->size == 8 && type->alignment >= 4))
51*1fd5a2e1SPrashanth Swaminathan return 1;
52*1fd5a2e1SPrashanth Swaminathan
53*1fd5a2e1SPrashanth Swaminathan if(type->size == 3 || type->size == 5 || type->size == 6 ||
54*1fd5a2e1SPrashanth Swaminathan type->size == 7)
55*1fd5a2e1SPrashanth Swaminathan return 1;
56*1fd5a2e1SPrashanth Swaminathan
57*1fd5a2e1SPrashanth Swaminathan return 0;
58*1fd5a2e1SPrashanth Swaminathan }
59*1fd5a2e1SPrashanth Swaminathan
60*1fd5a2e1SPrashanth Swaminathan /* ffi_prep_args is called by the assembly routine once stack space
61*1fd5a2e1SPrashanth Swaminathan * has been allocated for the function's arguments
62*1fd5a2e1SPrashanth Swaminathan *
63*1fd5a2e1SPrashanth Swaminathan * This is annoyingly complex since we need to keep track of used
64*1fd5a2e1SPrashanth Swaminathan * registers.
65*1fd5a2e1SPrashanth Swaminathan */
66*1fd5a2e1SPrashanth Swaminathan
ffi_prep_args(char * stack,extended_cif * ecif)67*1fd5a2e1SPrashanth Swaminathan void ffi_prep_args(char *stack, extended_cif *ecif)
68*1fd5a2e1SPrashanth Swaminathan {
69*1fd5a2e1SPrashanth Swaminathan unsigned int i;
70*1fd5a2e1SPrashanth Swaminathan void **p_argv;
71*1fd5a2e1SPrashanth Swaminathan ffi_type **p_arg;
72*1fd5a2e1SPrashanth Swaminathan char *reg_base = stack;
73*1fd5a2e1SPrashanth Swaminathan char *stack_base = stack + 20;
74*1fd5a2e1SPrashanth Swaminathan unsigned int stack_offset = 0;
75*1fd5a2e1SPrashanth Swaminathan unsigned int reg_mask = 0;
76*1fd5a2e1SPrashanth Swaminathan
77*1fd5a2e1SPrashanth Swaminathan p_argv = ecif->avalue;
78*1fd5a2e1SPrashanth Swaminathan
79*1fd5a2e1SPrashanth Swaminathan /* If cif->flags is struct then we know it's not passed in registers */
80*1fd5a2e1SPrashanth Swaminathan if(ecif->cif->flags == FFI_TYPE_STRUCT)
81*1fd5a2e1SPrashanth Swaminathan {
82*1fd5a2e1SPrashanth Swaminathan *(void**)reg_base = ecif->rvalue;
83*1fd5a2e1SPrashanth Swaminathan reg_mask |= 1;
84*1fd5a2e1SPrashanth Swaminathan }
85*1fd5a2e1SPrashanth Swaminathan
86*1fd5a2e1SPrashanth Swaminathan for(i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs;
87*1fd5a2e1SPrashanth Swaminathan i++, p_arg++)
88*1fd5a2e1SPrashanth Swaminathan {
89*1fd5a2e1SPrashanth Swaminathan size_t z = (*p_arg)->size;
90*1fd5a2e1SPrashanth Swaminathan int alignment = (*p_arg)->alignment;
91*1fd5a2e1SPrashanth Swaminathan int type = (*p_arg)->type;
92*1fd5a2e1SPrashanth Swaminathan char *addr = 0;
93*1fd5a2e1SPrashanth Swaminathan
94*1fd5a2e1SPrashanth Swaminathan if(z % 4 != 0)
95*1fd5a2e1SPrashanth Swaminathan z += (4 - z % 4);
96*1fd5a2e1SPrashanth Swaminathan
97*1fd5a2e1SPrashanth Swaminathan if(reg_mask != 0x1f)
98*1fd5a2e1SPrashanth Swaminathan {
99*1fd5a2e1SPrashanth Swaminathan if(pass_struct_on_stack(*p_arg))
100*1fd5a2e1SPrashanth Swaminathan {
101*1fd5a2e1SPrashanth Swaminathan addr = stack_base + stack_offset;
102*1fd5a2e1SPrashanth Swaminathan stack_offset += z;
103*1fd5a2e1SPrashanth Swaminathan }
104*1fd5a2e1SPrashanth Swaminathan else if(z == sizeof(int))
105*1fd5a2e1SPrashanth Swaminathan {
106*1fd5a2e1SPrashanth Swaminathan char index = 0;
107*1fd5a2e1SPrashanth Swaminathan
108*1fd5a2e1SPrashanth Swaminathan while((reg_mask >> index) & 1)
109*1fd5a2e1SPrashanth Swaminathan index++;
110*1fd5a2e1SPrashanth Swaminathan
111*1fd5a2e1SPrashanth Swaminathan addr = reg_base + (index * 4);
112*1fd5a2e1SPrashanth Swaminathan reg_mask |= (1 << index);
113*1fd5a2e1SPrashanth Swaminathan }
114*1fd5a2e1SPrashanth Swaminathan else if(z == 2 * sizeof(int))
115*1fd5a2e1SPrashanth Swaminathan {
116*1fd5a2e1SPrashanth Swaminathan if(!((reg_mask >> 1) & 1))
117*1fd5a2e1SPrashanth Swaminathan {
118*1fd5a2e1SPrashanth Swaminathan addr = reg_base + 4;
119*1fd5a2e1SPrashanth Swaminathan reg_mask |= (3 << 1);
120*1fd5a2e1SPrashanth Swaminathan }
121*1fd5a2e1SPrashanth Swaminathan else if(!((reg_mask >> 3) & 1))
122*1fd5a2e1SPrashanth Swaminathan {
123*1fd5a2e1SPrashanth Swaminathan addr = reg_base + 12;
124*1fd5a2e1SPrashanth Swaminathan reg_mask |= (3 << 3);
125*1fd5a2e1SPrashanth Swaminathan }
126*1fd5a2e1SPrashanth Swaminathan }
127*1fd5a2e1SPrashanth Swaminathan }
128*1fd5a2e1SPrashanth Swaminathan
129*1fd5a2e1SPrashanth Swaminathan if(!addr)
130*1fd5a2e1SPrashanth Swaminathan {
131*1fd5a2e1SPrashanth Swaminathan addr = stack_base + stack_offset;
132*1fd5a2e1SPrashanth Swaminathan stack_offset += z;
133*1fd5a2e1SPrashanth Swaminathan }
134*1fd5a2e1SPrashanth Swaminathan
135*1fd5a2e1SPrashanth Swaminathan if(type == FFI_TYPE_STRUCT && (*p_arg)->elements[1] == NULL)
136*1fd5a2e1SPrashanth Swaminathan type = (*p_arg)->elements[0]->type;
137*1fd5a2e1SPrashanth Swaminathan
138*1fd5a2e1SPrashanth Swaminathan switch(type)
139*1fd5a2e1SPrashanth Swaminathan {
140*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
141*1fd5a2e1SPrashanth Swaminathan *(unsigned int *)addr = (unsigned int)*(UINT8 *)(*p_argv);
142*1fd5a2e1SPrashanth Swaminathan break;
143*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
144*1fd5a2e1SPrashanth Swaminathan *(signed int *)addr = (signed int)*(SINT8 *)(*p_argv);
145*1fd5a2e1SPrashanth Swaminathan break;
146*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
147*1fd5a2e1SPrashanth Swaminathan *(unsigned int *)addr = (unsigned int)*(UINT16 *)(*p_argv);
148*1fd5a2e1SPrashanth Swaminathan break;
149*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
150*1fd5a2e1SPrashanth Swaminathan *(signed int *)addr = (signed int)*(SINT16 *)(*p_argv);
151*1fd5a2e1SPrashanth Swaminathan break;
152*1fd5a2e1SPrashanth Swaminathan default:
153*1fd5a2e1SPrashanth Swaminathan memcpy(addr, *p_argv, z);
154*1fd5a2e1SPrashanth Swaminathan }
155*1fd5a2e1SPrashanth Swaminathan
156*1fd5a2e1SPrashanth Swaminathan p_argv++;
157*1fd5a2e1SPrashanth Swaminathan }
158*1fd5a2e1SPrashanth Swaminathan
159*1fd5a2e1SPrashanth Swaminathan #ifdef DEBUG
160*1fd5a2e1SPrashanth Swaminathan /* Debugging */
161*1fd5a2e1SPrashanth Swaminathan for(i = 0; i < 5; i++)
162*1fd5a2e1SPrashanth Swaminathan {
163*1fd5a2e1SPrashanth Swaminathan if((reg_mask & (1 << i)) == 0)
164*1fd5a2e1SPrashanth Swaminathan printf("r%d: (unused)\n", 12 - i);
165*1fd5a2e1SPrashanth Swaminathan else
166*1fd5a2e1SPrashanth Swaminathan printf("r%d: 0x%08x\n", 12 - i, ((unsigned int*)reg_base)[i]);
167*1fd5a2e1SPrashanth Swaminathan }
168*1fd5a2e1SPrashanth Swaminathan
169*1fd5a2e1SPrashanth Swaminathan for(i = 0; i < stack_offset / 4; i++)
170*1fd5a2e1SPrashanth Swaminathan {
171*1fd5a2e1SPrashanth Swaminathan printf("sp+%d: 0x%08x\n", i*4, ((unsigned int*)stack_base)[i]);
172*1fd5a2e1SPrashanth Swaminathan }
173*1fd5a2e1SPrashanth Swaminathan #endif
174*1fd5a2e1SPrashanth Swaminathan }
175*1fd5a2e1SPrashanth Swaminathan
176*1fd5a2e1SPrashanth Swaminathan /* Perform machine dependent cif processing */
ffi_prep_cif_machdep(ffi_cif * cif)177*1fd5a2e1SPrashanth Swaminathan ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
178*1fd5a2e1SPrashanth Swaminathan {
179*1fd5a2e1SPrashanth Swaminathan /* Round the stack up to a multiple of 8 bytes. This isn't needed
180*1fd5a2e1SPrashanth Swaminathan * everywhere, but it is on some platforms, and it doesn't harm
181*1fd5a2e1SPrashanth Swaminathan * anything when it isn't needed. */
182*1fd5a2e1SPrashanth Swaminathan cif->bytes = (cif->bytes + 7) & ~7;
183*1fd5a2e1SPrashanth Swaminathan
184*1fd5a2e1SPrashanth Swaminathan /* Flag to indicate that he return value is in fact a struct */
185*1fd5a2e1SPrashanth Swaminathan cif->rstruct_flag = 0;
186*1fd5a2e1SPrashanth Swaminathan
187*1fd5a2e1SPrashanth Swaminathan /* Set the return type flag */
188*1fd5a2e1SPrashanth Swaminathan switch(cif->rtype->type)
189*1fd5a2e1SPrashanth Swaminathan {
190*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
191*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
192*1fd5a2e1SPrashanth Swaminathan cif->flags = (unsigned)FFI_TYPE_UINT8;
193*1fd5a2e1SPrashanth Swaminathan break;
194*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
195*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
196*1fd5a2e1SPrashanth Swaminathan cif->flags = (unsigned)FFI_TYPE_UINT16;
197*1fd5a2e1SPrashanth Swaminathan break;
198*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
199*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT32:
200*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT32:
201*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_POINTER:
202*1fd5a2e1SPrashanth Swaminathan cif->flags = (unsigned)FFI_TYPE_UINT32;
203*1fd5a2e1SPrashanth Swaminathan break;
204*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_DOUBLE:
205*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT64:
206*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT64:
207*1fd5a2e1SPrashanth Swaminathan cif->flags = (unsigned)FFI_TYPE_UINT64;
208*1fd5a2e1SPrashanth Swaminathan break;
209*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_STRUCT:
210*1fd5a2e1SPrashanth Swaminathan cif->rstruct_flag = 1;
211*1fd5a2e1SPrashanth Swaminathan if(!pass_struct_on_stack(cif->rtype))
212*1fd5a2e1SPrashanth Swaminathan {
213*1fd5a2e1SPrashanth Swaminathan if(cif->rtype->size <= 1)
214*1fd5a2e1SPrashanth Swaminathan cif->flags = (unsigned)FFI_TYPE_UINT8;
215*1fd5a2e1SPrashanth Swaminathan else if(cif->rtype->size <= 2)
216*1fd5a2e1SPrashanth Swaminathan cif->flags = (unsigned)FFI_TYPE_UINT16;
217*1fd5a2e1SPrashanth Swaminathan else if(cif->rtype->size <= 4)
218*1fd5a2e1SPrashanth Swaminathan cif->flags = (unsigned)FFI_TYPE_UINT32;
219*1fd5a2e1SPrashanth Swaminathan else if(cif->rtype->size <= 8)
220*1fd5a2e1SPrashanth Swaminathan cif->flags = (unsigned)FFI_TYPE_UINT64;
221*1fd5a2e1SPrashanth Swaminathan else
222*1fd5a2e1SPrashanth Swaminathan cif->flags = (unsigned)cif->rtype->type;
223*1fd5a2e1SPrashanth Swaminathan }
224*1fd5a2e1SPrashanth Swaminathan else
225*1fd5a2e1SPrashanth Swaminathan cif->flags = (unsigned)cif->rtype->type;
226*1fd5a2e1SPrashanth Swaminathan break;
227*1fd5a2e1SPrashanth Swaminathan default:
228*1fd5a2e1SPrashanth Swaminathan cif->flags = (unsigned)cif->rtype->type;
229*1fd5a2e1SPrashanth Swaminathan break;
230*1fd5a2e1SPrashanth Swaminathan }
231*1fd5a2e1SPrashanth Swaminathan
232*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
233*1fd5a2e1SPrashanth Swaminathan }
234*1fd5a2e1SPrashanth Swaminathan
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)235*1fd5a2e1SPrashanth Swaminathan void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
236*1fd5a2e1SPrashanth Swaminathan {
237*1fd5a2e1SPrashanth Swaminathan extended_cif ecif;
238*1fd5a2e1SPrashanth Swaminathan
239*1fd5a2e1SPrashanth Swaminathan unsigned int size = 0, i = 0;
240*1fd5a2e1SPrashanth Swaminathan ffi_type **p_arg;
241*1fd5a2e1SPrashanth Swaminathan
242*1fd5a2e1SPrashanth Swaminathan ecif.cif = cif;
243*1fd5a2e1SPrashanth Swaminathan ecif.avalue = avalue;
244*1fd5a2e1SPrashanth Swaminathan
245*1fd5a2e1SPrashanth Swaminathan for(i = 0, p_arg = cif->arg_types; i < cif->nargs; i++, p_arg++)
246*1fd5a2e1SPrashanth Swaminathan size += (*p_arg)->size + (4 - (*p_arg)->size % 4);
247*1fd5a2e1SPrashanth Swaminathan
248*1fd5a2e1SPrashanth Swaminathan /* If the return value is a struct and we don't have a return value
249*1fd5a2e1SPrashanth Swaminathan * address then we need to make one */
250*1fd5a2e1SPrashanth Swaminathan
251*1fd5a2e1SPrashanth Swaminathan /* If cif->flags is struct then it's not suitable for registers */
252*1fd5a2e1SPrashanth Swaminathan if((rvalue == NULL) && (cif->flags == FFI_TYPE_STRUCT))
253*1fd5a2e1SPrashanth Swaminathan ecif.rvalue = alloca(cif->rtype->size);
254*1fd5a2e1SPrashanth Swaminathan else
255*1fd5a2e1SPrashanth Swaminathan ecif.rvalue = rvalue;
256*1fd5a2e1SPrashanth Swaminathan
257*1fd5a2e1SPrashanth Swaminathan switch(cif->abi)
258*1fd5a2e1SPrashanth Swaminathan {
259*1fd5a2e1SPrashanth Swaminathan case FFI_SYSV:
260*1fd5a2e1SPrashanth Swaminathan ffi_call_SYSV(ffi_prep_args, &ecif, size, cif->flags,
261*1fd5a2e1SPrashanth Swaminathan ecif.rvalue, cif->rstruct_flag, fn);
262*1fd5a2e1SPrashanth Swaminathan break;
263*1fd5a2e1SPrashanth Swaminathan default:
264*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT(0);
265*1fd5a2e1SPrashanth Swaminathan break;
266*1fd5a2e1SPrashanth Swaminathan }
267*1fd5a2e1SPrashanth Swaminathan }
268*1fd5a2e1SPrashanth Swaminathan
ffi_prep_incoming_args_SYSV(char * stack,void ** rvalue,void ** avalue,ffi_cif * cif)269*1fd5a2e1SPrashanth Swaminathan static void ffi_prep_incoming_args_SYSV(char *stack, void **rvalue,
270*1fd5a2e1SPrashanth Swaminathan void **avalue, ffi_cif *cif)
271*1fd5a2e1SPrashanth Swaminathan {
272*1fd5a2e1SPrashanth Swaminathan register unsigned int i, reg_mask = 0;
273*1fd5a2e1SPrashanth Swaminathan register void **p_argv;
274*1fd5a2e1SPrashanth Swaminathan register ffi_type **p_arg;
275*1fd5a2e1SPrashanth Swaminathan register char *reg_base = stack;
276*1fd5a2e1SPrashanth Swaminathan register char *stack_base = stack + 20;
277*1fd5a2e1SPrashanth Swaminathan register unsigned int stack_offset = 0;
278*1fd5a2e1SPrashanth Swaminathan
279*1fd5a2e1SPrashanth Swaminathan #ifdef DEBUG
280*1fd5a2e1SPrashanth Swaminathan /* Debugging */
281*1fd5a2e1SPrashanth Swaminathan for(i = 0; i < cif->nargs + 7; i++)
282*1fd5a2e1SPrashanth Swaminathan {
283*1fd5a2e1SPrashanth Swaminathan printf("sp+%d: 0x%08x\n", i*4, ((unsigned int*)stack)[i]);
284*1fd5a2e1SPrashanth Swaminathan }
285*1fd5a2e1SPrashanth Swaminathan #endif
286*1fd5a2e1SPrashanth Swaminathan
287*1fd5a2e1SPrashanth Swaminathan /* If cif->flags is struct then we know it's not passed in registers */
288*1fd5a2e1SPrashanth Swaminathan if(cif->flags == FFI_TYPE_STRUCT)
289*1fd5a2e1SPrashanth Swaminathan {
290*1fd5a2e1SPrashanth Swaminathan *rvalue = *(void **)reg_base;
291*1fd5a2e1SPrashanth Swaminathan reg_mask |= 1;
292*1fd5a2e1SPrashanth Swaminathan }
293*1fd5a2e1SPrashanth Swaminathan
294*1fd5a2e1SPrashanth Swaminathan p_argv = avalue;
295*1fd5a2e1SPrashanth Swaminathan
296*1fd5a2e1SPrashanth Swaminathan for(i = 0, p_arg = cif->arg_types; i < cif->nargs; i++, p_arg++)
297*1fd5a2e1SPrashanth Swaminathan {
298*1fd5a2e1SPrashanth Swaminathan size_t z = (*p_arg)->size;
299*1fd5a2e1SPrashanth Swaminathan int alignment = (*p_arg)->alignment;
300*1fd5a2e1SPrashanth Swaminathan
301*1fd5a2e1SPrashanth Swaminathan *p_argv = 0;
302*1fd5a2e1SPrashanth Swaminathan
303*1fd5a2e1SPrashanth Swaminathan if(z % 4 != 0)
304*1fd5a2e1SPrashanth Swaminathan z += (4 - z % 4);
305*1fd5a2e1SPrashanth Swaminathan
306*1fd5a2e1SPrashanth Swaminathan if(reg_mask != 0x1f)
307*1fd5a2e1SPrashanth Swaminathan {
308*1fd5a2e1SPrashanth Swaminathan if(pass_struct_on_stack(*p_arg))
309*1fd5a2e1SPrashanth Swaminathan {
310*1fd5a2e1SPrashanth Swaminathan *p_argv = (void*)stack_base + stack_offset;
311*1fd5a2e1SPrashanth Swaminathan stack_offset += z;
312*1fd5a2e1SPrashanth Swaminathan }
313*1fd5a2e1SPrashanth Swaminathan else if(z <= sizeof(int))
314*1fd5a2e1SPrashanth Swaminathan {
315*1fd5a2e1SPrashanth Swaminathan char index = 0;
316*1fd5a2e1SPrashanth Swaminathan
317*1fd5a2e1SPrashanth Swaminathan while((reg_mask >> index) & 1)
318*1fd5a2e1SPrashanth Swaminathan index++;
319*1fd5a2e1SPrashanth Swaminathan
320*1fd5a2e1SPrashanth Swaminathan *p_argv = (void*)reg_base + (index * 4);
321*1fd5a2e1SPrashanth Swaminathan reg_mask |= (1 << index);
322*1fd5a2e1SPrashanth Swaminathan }
323*1fd5a2e1SPrashanth Swaminathan else if(z == 2 * sizeof(int))
324*1fd5a2e1SPrashanth Swaminathan {
325*1fd5a2e1SPrashanth Swaminathan if(!((reg_mask >> 1) & 1))
326*1fd5a2e1SPrashanth Swaminathan {
327*1fd5a2e1SPrashanth Swaminathan *p_argv = (void*)reg_base + 4;
328*1fd5a2e1SPrashanth Swaminathan reg_mask |= (3 << 1);
329*1fd5a2e1SPrashanth Swaminathan }
330*1fd5a2e1SPrashanth Swaminathan else if(!((reg_mask >> 3) & 1))
331*1fd5a2e1SPrashanth Swaminathan {
332*1fd5a2e1SPrashanth Swaminathan *p_argv = (void*)reg_base + 12;
333*1fd5a2e1SPrashanth Swaminathan reg_mask |= (3 << 3);
334*1fd5a2e1SPrashanth Swaminathan }
335*1fd5a2e1SPrashanth Swaminathan }
336*1fd5a2e1SPrashanth Swaminathan }
337*1fd5a2e1SPrashanth Swaminathan
338*1fd5a2e1SPrashanth Swaminathan if(!*p_argv)
339*1fd5a2e1SPrashanth Swaminathan {
340*1fd5a2e1SPrashanth Swaminathan *p_argv = (void*)stack_base + stack_offset;
341*1fd5a2e1SPrashanth Swaminathan stack_offset += z;
342*1fd5a2e1SPrashanth Swaminathan }
343*1fd5a2e1SPrashanth Swaminathan
344*1fd5a2e1SPrashanth Swaminathan if((*p_arg)->type != FFI_TYPE_STRUCT ||
345*1fd5a2e1SPrashanth Swaminathan (*p_arg)->elements[1] == NULL)
346*1fd5a2e1SPrashanth Swaminathan {
347*1fd5a2e1SPrashanth Swaminathan if(alignment == 1)
348*1fd5a2e1SPrashanth Swaminathan **(unsigned int**)p_argv <<= 24;
349*1fd5a2e1SPrashanth Swaminathan else if(alignment == 2)
350*1fd5a2e1SPrashanth Swaminathan **(unsigned int**)p_argv <<= 16;
351*1fd5a2e1SPrashanth Swaminathan }
352*1fd5a2e1SPrashanth Swaminathan
353*1fd5a2e1SPrashanth Swaminathan p_argv++;
354*1fd5a2e1SPrashanth Swaminathan }
355*1fd5a2e1SPrashanth Swaminathan
356*1fd5a2e1SPrashanth Swaminathan #ifdef DEBUG
357*1fd5a2e1SPrashanth Swaminathan /* Debugging */
358*1fd5a2e1SPrashanth Swaminathan for(i = 0; i < cif->nargs; i++)
359*1fd5a2e1SPrashanth Swaminathan {
360*1fd5a2e1SPrashanth Swaminathan printf("sp+%d: 0x%08x\n", i*4, *(((unsigned int**)avalue)[i]));
361*1fd5a2e1SPrashanth Swaminathan }
362*1fd5a2e1SPrashanth Swaminathan #endif
363*1fd5a2e1SPrashanth Swaminathan }
364*1fd5a2e1SPrashanth Swaminathan
365*1fd5a2e1SPrashanth Swaminathan /* This function is jumped to by the trampoline */
366*1fd5a2e1SPrashanth Swaminathan
ffi_closure_SYSV_inner(ffi_closure * closure,void ** respp,void * args)367*1fd5a2e1SPrashanth Swaminathan unsigned int ffi_closure_SYSV_inner(ffi_closure *closure, void **respp,
368*1fd5a2e1SPrashanth Swaminathan void *args)
369*1fd5a2e1SPrashanth Swaminathan {
370*1fd5a2e1SPrashanth Swaminathan ffi_cif *cif;
371*1fd5a2e1SPrashanth Swaminathan void **arg_area;
372*1fd5a2e1SPrashanth Swaminathan unsigned int i, size = 0;
373*1fd5a2e1SPrashanth Swaminathan ffi_type **p_arg;
374*1fd5a2e1SPrashanth Swaminathan
375*1fd5a2e1SPrashanth Swaminathan cif = closure->cif;
376*1fd5a2e1SPrashanth Swaminathan
377*1fd5a2e1SPrashanth Swaminathan for(i = 0, p_arg = cif->arg_types; i < cif->nargs; i++, p_arg++)
378*1fd5a2e1SPrashanth Swaminathan size += (*p_arg)->size + (4 - (*p_arg)->size % 4);
379*1fd5a2e1SPrashanth Swaminathan
380*1fd5a2e1SPrashanth Swaminathan arg_area = (void **)alloca(size);
381*1fd5a2e1SPrashanth Swaminathan
382*1fd5a2e1SPrashanth Swaminathan /* this call will initialize ARG_AREA, such that each element in that
383*1fd5a2e1SPrashanth Swaminathan * array points to the corresponding value on the stack; and if the
384*1fd5a2e1SPrashanth Swaminathan * function returns a structure, it will re-set RESP to point to the
385*1fd5a2e1SPrashanth Swaminathan * structure return address. */
386*1fd5a2e1SPrashanth Swaminathan
387*1fd5a2e1SPrashanth Swaminathan ffi_prep_incoming_args_SYSV(args, respp, arg_area, cif);
388*1fd5a2e1SPrashanth Swaminathan
389*1fd5a2e1SPrashanth Swaminathan (closure->fun)(cif, *respp, arg_area, closure->user_data);
390*1fd5a2e1SPrashanth Swaminathan
391*1fd5a2e1SPrashanth Swaminathan return cif->flags;
392*1fd5a2e1SPrashanth Swaminathan }
393*1fd5a2e1SPrashanth Swaminathan
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)394*1fd5a2e1SPrashanth Swaminathan ffi_status ffi_prep_closure_loc(ffi_closure* closure, ffi_cif* cif,
395*1fd5a2e1SPrashanth Swaminathan void (*fun)(ffi_cif*, void*, void**, void*), void *user_data,
396*1fd5a2e1SPrashanth Swaminathan void *codeloc)
397*1fd5a2e1SPrashanth Swaminathan {
398*1fd5a2e1SPrashanth Swaminathan if (cif->abi != FFI_SYSV)
399*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_ABI;
400*1fd5a2e1SPrashanth Swaminathan
401*1fd5a2e1SPrashanth Swaminathan unsigned char *__tramp = (unsigned char*)(&closure->tramp[0]);
402*1fd5a2e1SPrashanth Swaminathan unsigned int __fun = (unsigned int)(&ffi_closure_SYSV);
403*1fd5a2e1SPrashanth Swaminathan unsigned int __ctx = (unsigned int)(codeloc);
404*1fd5a2e1SPrashanth Swaminathan unsigned int __rstruct_flag = (unsigned int)(cif->rstruct_flag);
405*1fd5a2e1SPrashanth Swaminathan unsigned int __inner = (unsigned int)(&ffi_closure_SYSV_inner);
406*1fd5a2e1SPrashanth Swaminathan *(unsigned int*) &__tramp[0] = 0xebcd1f00; /* pushm r8-r12 */
407*1fd5a2e1SPrashanth Swaminathan *(unsigned int*) &__tramp[4] = 0xfefc0010; /* ld.w r12, pc[16] */
408*1fd5a2e1SPrashanth Swaminathan *(unsigned int*) &__tramp[8] = 0xfefb0010; /* ld.w r11, pc[16] */
409*1fd5a2e1SPrashanth Swaminathan *(unsigned int*) &__tramp[12] = 0xfefa0010; /* ld.w r10, pc[16] */
410*1fd5a2e1SPrashanth Swaminathan *(unsigned int*) &__tramp[16] = 0xfeff0010; /* ld.w pc, pc[16] */
411*1fd5a2e1SPrashanth Swaminathan *(unsigned int*) &__tramp[20] = __ctx;
412*1fd5a2e1SPrashanth Swaminathan *(unsigned int*) &__tramp[24] = __rstruct_flag;
413*1fd5a2e1SPrashanth Swaminathan *(unsigned int*) &__tramp[28] = __inner;
414*1fd5a2e1SPrashanth Swaminathan *(unsigned int*) &__tramp[32] = __fun;
415*1fd5a2e1SPrashanth Swaminathan syscall(__NR_cacheflush, 0, (&__tramp[0]), 36);
416*1fd5a2e1SPrashanth Swaminathan
417*1fd5a2e1SPrashanth Swaminathan closure->cif = cif;
418*1fd5a2e1SPrashanth Swaminathan closure->user_data = user_data;
419*1fd5a2e1SPrashanth Swaminathan closure->fun = fun;
420*1fd5a2e1SPrashanth Swaminathan
421*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
422*1fd5a2e1SPrashanth Swaminathan }
423*1fd5a2e1SPrashanth Swaminathan
424