1 /* -----------------------------------------------------------------------
2    ffi.c - Copyright (c) 2012  Alexandre K. I. de Mendonca <alexandre.keunecke@gmail.com>
3 
4    Blackfin 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 #include <ffi.h>
27 #include <ffi_common.h>
28 
29 #include <stdlib.h>
30 #include <stdio.h>
31 
32 /* Maximum number of GPRs available for argument passing.  */
33 #define MAX_GPRARGS 3
34 
35 /*
36  * Return types
37  */
38 #define FFIBFIN_RET_VOID 0
39 #define FFIBFIN_RET_BYTE 1
40 #define FFIBFIN_RET_HALFWORD 2
41 #define FFIBFIN_RET_INT64 3
42 #define FFIBFIN_RET_INT32 4
43 
44 /*====================================================================*/
45 /*                          PROTOTYPE          *
46  /*====================================================================*/
47 void ffi_prep_args(unsigned char *, extended_cif *);
48 
49 /*====================================================================*/
50 /*                          Externals                                 */
51 /*                          (Assembly)                                */
52 /*====================================================================*/
53 
54 extern void ffi_call_SYSV(unsigned, extended_cif *, void(*)(unsigned char *, extended_cif *), unsigned, void *, void(*fn)(void));
55 
56 /*====================================================================*/
57 /*                          Implementation                            */
58 /*                                                            */
59 /*====================================================================*/
60 
61 
62 /*
63  * This function calculates the return type (size) based on type.
64  */
65 
ffi_prep_cif_machdep(ffi_cif * cif)66 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
67 {
68    /* --------------------------------------*
69     *   Return handling                *
70     * --------------------------------------*/
71    switch (cif->rtype->type) {
72       case FFI_TYPE_VOID:
73          cif->flags = FFIBFIN_RET_VOID;
74          break;
75       case FFI_TYPE_UINT16:
76       case FFI_TYPE_SINT16:
77          cif->flags = FFIBFIN_RET_HALFWORD;
78          break;
79       case FFI_TYPE_UINT8:
80          cif->flags = FFIBFIN_RET_BYTE;
81          break;
82       case FFI_TYPE_INT:
83       case FFI_TYPE_UINT32:
84       case FFI_TYPE_SINT32:
85       case FFI_TYPE_FLOAT:
86       case FFI_TYPE_POINTER:
87       case FFI_TYPE_SINT8:
88          cif->flags = FFIBFIN_RET_INT32;
89          break;
90       case FFI_TYPE_SINT64:
91       case FFI_TYPE_UINT64:
92       case FFI_TYPE_DOUBLE:
93           cif->flags = FFIBFIN_RET_INT64;
94           break;
95       case FFI_TYPE_STRUCT:
96          if (cif->rtype->size <= 4){
97         	 cif->flags = FFIBFIN_RET_INT32;
98          }else if (cif->rtype->size == 8){
99         	 cif->flags = FFIBFIN_RET_INT64;
100          }else{
101         	 //it will return via a hidden pointer in P0
102         	 cif->flags = FFIBFIN_RET_VOID;
103          }
104          break;
105       default:
106          FFI_ASSERT(0);
107          break;
108    }
109    return FFI_OK;
110 }
111 
112 /*
113  * This will prepare the arguments and will call the assembly routine
114  * cif = the call interface
115  * fn = the function to be called
116  * rvalue = the return value
117  * avalue = the arguments
118  */
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)119 void ffi_call(ffi_cif *cif, void(*fn)(void), void *rvalue, void **avalue)
120 {
121    int ret_type = cif->flags;
122    extended_cif ecif;
123    ecif.cif = cif;
124    ecif.avalue = avalue;
125    ecif.rvalue = rvalue;
126 
127    switch (cif->abi) {
128       case FFI_SYSV:
129          ffi_call_SYSV(cif->bytes, &ecif, ffi_prep_args, ret_type, ecif.rvalue, fn);
130          break;
131       default:
132          FFI_ASSERT(0);
133          break;
134    }
135 }
136 
137 
138 /*
139 * This function prepares the parameters (copies them from the ecif to the stack)
140 *  to call the function (ffi_prep_args is called by the assembly routine in file
141 *  sysv.S, which also calls the actual function)
142 */
ffi_prep_args(unsigned char * stack,extended_cif * ecif)143 void ffi_prep_args(unsigned char *stack, extended_cif *ecif)
144 {
145    register unsigned int i = 0;
146    void **p_argv;
147    unsigned char *argp;
148    ffi_type **p_arg;
149    argp = stack;
150    p_argv = ecif->avalue;
151    for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
152         (i != 0);
153         i--, p_arg++) {
154       size_t z;
155       z = (*p_arg)->size;
156       if (z < sizeof(int)) {
157          z = sizeof(int);
158          switch ((*p_arg)->type) {
159             case FFI_TYPE_SINT8: {
160                   signed char v = *(SINT8 *)(* p_argv);
161                   signed int t = v;
162                   *(signed int *) argp = t;
163                }
164                break;
165             case FFI_TYPE_UINT8: {
166                   unsigned char v = *(UINT8 *)(* p_argv);
167                   unsigned int t = v;
168                   *(unsigned int *) argp = t;
169                }
170                break;
171             case FFI_TYPE_SINT16:
172                *(signed int *) argp = (signed int) * (SINT16 *)(* p_argv);
173                break;
174             case FFI_TYPE_UINT16:
175                *(unsigned int *) argp = (unsigned int) * (UINT16 *)(* p_argv);
176                break;
177             case FFI_TYPE_STRUCT:
178                memcpy(argp, *p_argv, (*p_arg)->size);
179                break;
180             default:
181                FFI_ASSERT(0);
182                break;
183          }
184       } else if (z == sizeof(int)) {
185          *(unsigned int *) argp = (unsigned int) * (UINT32 *)(* p_argv);
186       } else {
187          memcpy(argp, *p_argv, z);
188       }
189       p_argv++;
190       argp += z;
191    }
192 }
193 
194 
195 
196