111
|
1 /* -----------------------------------------------------------------------
|
|
2 ffi.c - Copyright (c) 2013 Synopsys, Inc. (www.synopsys.com)
|
|
3
|
|
4 ARC 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, EXPRESS
|
|
18 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
19 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
20 IN NO EVENT SHALL RENESAS TECHNOLOGY BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
21 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
22 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
23 OTHER DEALINGS IN THE SOFTWARE.
|
|
24 ----------------------------------------------------------------------- */
|
|
25
|
|
26 #include <ffi.h>
|
|
27 #include <ffi_common.h>
|
|
28
|
|
29 #include <stdlib.h>
|
|
30 #include <stdint.h>
|
|
31
|
|
32 #include <sys/cachectl.h>
|
|
33
|
|
34 /* for little endian ARC, the code is in fact stored as mixed endian for
|
|
35 performance reasons */
|
|
36 #if __BIG_ENDIAN__
|
|
37 #define CODE_ENDIAN(x) (x)
|
|
38 #else
|
|
39 #define CODE_ENDIAN(x) ( (((uint32_t) (x)) << 16) | (((uint32_t) (x)) >> 16))
|
|
40 #endif
|
|
41
|
|
42 /* ffi_prep_args is called by the assembly routine once stack
|
|
43 space has been allocated for the function's arguments. */
|
|
44
|
|
45 void
|
|
46 ffi_prep_args (char *stack, extended_cif * ecif)
|
|
47 {
|
|
48 unsigned int i;
|
|
49 int tmp;
|
|
50 void **p_argv;
|
|
51 char *argp;
|
|
52 ffi_type **p_arg;
|
|
53
|
|
54 tmp = 0;
|
|
55 argp = stack;
|
|
56
|
|
57 if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
|
|
58 {
|
|
59 *(void **) argp = ecif->rvalue;
|
|
60 argp += 4;
|
|
61 }
|
|
62
|
|
63 p_argv = ecif->avalue;
|
|
64
|
|
65 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
|
|
66 (i != 0); i--, p_arg++)
|
|
67 {
|
|
68 size_t z;
|
|
69 int alignment;
|
|
70
|
|
71 /* align alignment to 4 */
|
|
72 alignment = (((*p_arg)->alignment - 1) | 3) + 1;
|
|
73
|
|
74 /* Align if necessary. */
|
|
75 if ((alignment - 1) & (unsigned) argp)
|
|
76 argp = (char *) ALIGN (argp, alignment);
|
|
77
|
|
78 z = (*p_arg)->size;
|
|
79 if (z < sizeof (int))
|
|
80 {
|
|
81 z = sizeof (int);
|
|
82
|
|
83 switch ((*p_arg)->type)
|
|
84 {
|
|
85 case FFI_TYPE_SINT8:
|
|
86 *(signed int *) argp = (signed int) *(SINT8 *) (*p_argv);
|
|
87 break;
|
|
88
|
|
89 case FFI_TYPE_UINT8:
|
|
90 *(unsigned int *) argp = (unsigned int) *(UINT8 *) (*p_argv);
|
|
91 break;
|
|
92
|
|
93 case FFI_TYPE_SINT16:
|
|
94 *(signed int *) argp = (signed int) *(SINT16 *) (*p_argv);
|
|
95 break;
|
|
96
|
|
97 case FFI_TYPE_UINT16:
|
|
98 *(unsigned int *) argp = (unsigned int) *(UINT16 *) (*p_argv);
|
|
99 break;
|
|
100
|
|
101 case FFI_TYPE_STRUCT:
|
|
102 memcpy (argp, *p_argv, (*p_arg)->size);
|
|
103 break;
|
|
104
|
|
105 default:
|
|
106 FFI_ASSERT (0);
|
|
107 }
|
|
108 }
|
|
109 else if (z == sizeof (int))
|
|
110 {
|
|
111 *(unsigned int *) argp = (unsigned int) *(UINT32 *) (*p_argv);
|
|
112 }
|
|
113 else
|
|
114 {
|
|
115 if ((*p_arg)->type == FFI_TYPE_STRUCT)
|
|
116 {
|
|
117 memcpy (argp, *p_argv, z);
|
|
118 }
|
|
119 else
|
|
120 {
|
|
121 /* Double or long long 64bit. */
|
|
122 memcpy (argp, *p_argv, z);
|
|
123 }
|
|
124 }
|
|
125 p_argv++;
|
|
126 argp += z;
|
|
127 }
|
|
128
|
|
129 return;
|
|
130 }
|
|
131
|
|
132 /* Perform machine dependent cif processing. */
|
|
133 ffi_status
|
|
134 ffi_prep_cif_machdep (ffi_cif * cif)
|
|
135 {
|
|
136 /* Set the return type flag. */
|
|
137 switch (cif->rtype->type)
|
|
138 {
|
|
139 case FFI_TYPE_VOID:
|
|
140 cif->flags = (unsigned) cif->rtype->type;
|
|
141 break;
|
|
142
|
|
143 case FFI_TYPE_STRUCT:
|
|
144 cif->flags = (unsigned) cif->rtype->type;
|
|
145 break;
|
|
146
|
|
147 case FFI_TYPE_SINT64:
|
|
148 case FFI_TYPE_UINT64:
|
|
149 case FFI_TYPE_DOUBLE:
|
|
150 cif->flags = FFI_TYPE_DOUBLE;
|
|
151 break;
|
|
152
|
|
153 case FFI_TYPE_FLOAT:
|
|
154 default:
|
|
155 cif->flags = FFI_TYPE_INT;
|
|
156 break;
|
|
157 }
|
|
158
|
|
159 return FFI_OK;
|
|
160 }
|
|
161
|
|
162 extern void ffi_call_ARCompact (void (*)(char *, extended_cif *),
|
|
163 extended_cif *, unsigned, unsigned,
|
|
164 unsigned *, void (*fn) (void));
|
|
165
|
|
166 void
|
|
167 ffi_call (ffi_cif * cif, void (*fn) (void), void *rvalue, void **avalue)
|
|
168 {
|
|
169 extended_cif ecif;
|
|
170
|
|
171 ecif.cif = cif;
|
|
172 ecif.avalue = avalue;
|
|
173
|
|
174 /* If the return value is a struct and we don't have
|
|
175 a return value address then we need to make one. */
|
|
176 if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
|
|
177 {
|
|
178 ecif.rvalue = alloca (cif->rtype->size);
|
|
179 }
|
|
180 else
|
|
181 ecif.rvalue = rvalue;
|
|
182
|
|
183 switch (cif->abi)
|
|
184 {
|
|
185 case FFI_ARCOMPACT:
|
|
186 ffi_call_ARCompact (ffi_prep_args, &ecif, cif->bytes,
|
|
187 cif->flags, ecif.rvalue, fn);
|
|
188 break;
|
|
189
|
|
190 default:
|
|
191 FFI_ASSERT (0);
|
|
192 break;
|
|
193 }
|
|
194 }
|
|
195
|
|
196 int
|
|
197 ffi_closure_inner_ARCompact (ffi_closure * closure, void *rvalue,
|
|
198 ffi_arg * args)
|
|
199 {
|
|
200 void **arg_area, **p_argv;
|
|
201 ffi_cif *cif = closure->cif;
|
|
202 char *argp = (char *) args;
|
|
203 ffi_type **p_argt;
|
|
204 int i;
|
|
205
|
|
206 arg_area = (void **) alloca (cif->nargs * sizeof (void *));
|
|
207
|
|
208 /* handle hidden argument */
|
|
209 if (cif->flags == FFI_TYPE_STRUCT)
|
|
210 {
|
|
211 rvalue = *(void **) argp;
|
|
212 argp += 4;
|
|
213 }
|
|
214
|
|
215 p_argv = arg_area;
|
|
216
|
|
217 for (i = 0, p_argt = cif->arg_types; i < cif->nargs;
|
|
218 i++, p_argt++, p_argv++)
|
|
219 {
|
|
220 size_t z;
|
|
221 int alignment;
|
|
222
|
|
223 /* align alignment to 4 */
|
|
224 alignment = (((*p_argt)->alignment - 1) | 3) + 1;
|
|
225
|
|
226 /* Align if necessary. */
|
|
227 if ((alignment - 1) & (unsigned) argp)
|
|
228 argp = (char *) ALIGN (argp, alignment);
|
|
229
|
|
230 z = (*p_argt)->size;
|
|
231 *p_argv = (void *) argp;
|
|
232 argp += z;
|
|
233 }
|
|
234
|
|
235 (closure->fun) (cif, rvalue, arg_area, closure->user_data);
|
|
236
|
|
237 return cif->flags;
|
|
238 }
|
|
239
|
|
240 extern void ffi_closure_ARCompact (void);
|
|
241
|
|
242 ffi_status
|
|
243 ffi_prep_closure_loc (ffi_closure * closure, ffi_cif * cif,
|
|
244 void (*fun) (ffi_cif *, void *, void **, void *),
|
|
245 void *user_data, void *codeloc)
|
|
246 {
|
|
247 uint32_t *tramp = (uint32_t *) & (closure->tramp[0]);
|
|
248
|
|
249 switch (cif->abi)
|
|
250 {
|
|
251 case FFI_ARCOMPACT:
|
|
252 FFI_ASSERT (tramp == codeloc);
|
|
253 tramp[0] = CODE_ENDIAN (0x200a1fc0); /* mov r8, pcl */
|
|
254 tramp[1] = CODE_ENDIAN (0x20200f80); /* j [long imm] */
|
|
255 tramp[2] = CODE_ENDIAN (ffi_closure_ARCompact);
|
|
256 break;
|
|
257
|
|
258 default:
|
|
259 return FFI_BAD_ABI;
|
|
260 }
|
|
261
|
|
262 closure->cif = cif;
|
|
263 closure->fun = fun;
|
|
264 closure->user_data = user_data;
|
|
265 cacheflush (codeloc, FFI_TRAMPOLINE_SIZE, BCACHE);
|
|
266
|
|
267 return FFI_OK;
|
|
268 }
|