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