xref: /aosp_15_r20/external/libffi/src/avr32/ffi.c (revision 1fd5a2e1d639cd1ddf29dd0c484c123bbd850c21)
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