OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libffi/] [src/] [avr32/] [ffi.c] - Blame information for rev 732

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.