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
38extern void ffi_call_SYSV(void (*)(char *, extended_cif *), extended_cif *,
39    unsigned int, unsigned int, unsigned int*, unsigned int,
40    void (*fn)(void));
41extern void ffi_closure_SYSV (ffi_closure *);
42
43unsigned 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
67void 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 */
177ffi_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
235void 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
269static 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
367unsigned 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
394ffi_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