111
|
1 /* -----------------------------------------------------------------------
|
|
2 ffi.c
|
|
3
|
|
4 m68k Foreign Function Interface
|
|
5 ----------------------------------------------------------------------- */
|
|
6
|
|
7 #include <ffi.h>
|
|
8 #include <ffi_common.h>
|
|
9
|
|
10 #include <stdlib.h>
|
|
11 #include <unistd.h>
|
|
12 #ifdef __rtems__
|
|
13 void rtems_cache_flush_multiple_data_lines( const void *, size_t );
|
|
14 #else
|
|
15 #include <sys/syscall.h>
|
|
16 #ifdef __MINT__
|
|
17 #include <mint/mintbind.h>
|
|
18 #include <mint/ssystem.h>
|
|
19 #else
|
|
20 #include <asm/cachectl.h>
|
|
21 #endif
|
|
22 #endif
|
|
23
|
|
24 void ffi_call_SYSV (extended_cif *,
|
|
25 unsigned, unsigned,
|
|
26 void *, void (*fn) ());
|
|
27 void *ffi_prep_args (void *stack, extended_cif *ecif);
|
|
28 void ffi_closure_SYSV (ffi_closure *);
|
|
29 void ffi_closure_struct_SYSV (ffi_closure *);
|
|
30 unsigned int ffi_closure_SYSV_inner (ffi_closure *closure,
|
|
31 void *resp, void *args);
|
|
32
|
|
33 /* ffi_prep_args is called by the assembly routine once stack space has
|
|
34 been allocated for the function's arguments. */
|
|
35
|
|
36 void *
|
|
37 ffi_prep_args (void *stack, extended_cif *ecif)
|
|
38 {
|
|
39 unsigned int i;
|
|
40 void **p_argv;
|
|
41 char *argp;
|
|
42 ffi_type **p_arg;
|
|
43 void *struct_value_ptr;
|
|
44
|
|
45 argp = stack;
|
|
46
|
|
47 if (
|
|
48 #ifdef __MINT__
|
|
49 (ecif->cif->rtype->type == FFI_TYPE_LONGDOUBLE) ||
|
|
50 #endif
|
|
51 (((ecif->cif->rtype->type == FFI_TYPE_STRUCT)
|
|
52 && !ecif->cif->flags)))
|
|
53 struct_value_ptr = ecif->rvalue;
|
|
54 else
|
|
55 struct_value_ptr = NULL;
|
|
56
|
|
57 p_argv = ecif->avalue;
|
|
58
|
|
59 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
|
|
60 i != 0;
|
|
61 i--, p_arg++)
|
|
62 {
|
|
63 size_t z = (*p_arg)->size;
|
|
64 int type = (*p_arg)->type;
|
|
65
|
|
66 if (z < sizeof (int))
|
|
67 {
|
|
68 switch (type)
|
|
69 {
|
|
70 case FFI_TYPE_SINT8:
|
|
71 *(signed int *) argp = (signed int) *(SINT8 *) *p_argv;
|
|
72 break;
|
|
73
|
|
74 case FFI_TYPE_UINT8:
|
|
75 *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv;
|
|
76 break;
|
|
77
|
|
78 case FFI_TYPE_SINT16:
|
|
79 *(signed int *) argp = (signed int) *(SINT16 *) *p_argv;
|
|
80 break;
|
|
81
|
|
82 case FFI_TYPE_UINT16:
|
|
83 *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv;
|
|
84 break;
|
|
85
|
|
86 case FFI_TYPE_STRUCT:
|
|
87 #ifdef __MINT__
|
|
88 if (z == 1 || z == 2)
|
|
89 memcpy (argp + 2, *p_argv, z);
|
|
90 else
|
|
91 memcpy (argp, *p_argv, z);
|
|
92 #else
|
|
93 memcpy (argp + sizeof (int) - z, *p_argv, z);
|
|
94 #endif
|
|
95 break;
|
|
96
|
|
97 default:
|
|
98 FFI_ASSERT (0);
|
|
99 }
|
|
100 z = sizeof (int);
|
|
101 }
|
|
102 else
|
|
103 {
|
|
104 memcpy (argp, *p_argv, z);
|
|
105
|
|
106 /* Align if necessary. */
|
|
107 if ((sizeof(int) - 1) & z)
|
|
108 z = ALIGN(z, sizeof(int));
|
|
109 }
|
|
110
|
|
111 p_argv++;
|
|
112 argp += z;
|
|
113 }
|
|
114
|
|
115 return struct_value_ptr;
|
|
116 }
|
|
117
|
|
118 #define CIF_FLAGS_INT 1
|
|
119 #define CIF_FLAGS_DINT 2
|
|
120 #define CIF_FLAGS_FLOAT 4
|
|
121 #define CIF_FLAGS_DOUBLE 8
|
|
122 #define CIF_FLAGS_LDOUBLE 16
|
|
123 #define CIF_FLAGS_POINTER 32
|
|
124 #define CIF_FLAGS_STRUCT1 64
|
|
125 #define CIF_FLAGS_STRUCT2 128
|
|
126 #define CIF_FLAGS_SINT8 256
|
|
127 #define CIF_FLAGS_SINT16 512
|
|
128
|
|
129 /* Perform machine dependent cif processing */
|
|
130 ffi_status
|
|
131 ffi_prep_cif_machdep (ffi_cif *cif)
|
|
132 {
|
|
133 /* Set the return type flag */
|
|
134 switch (cif->rtype->type)
|
|
135 {
|
|
136 case FFI_TYPE_VOID:
|
|
137 cif->flags = 0;
|
|
138 break;
|
|
139
|
|
140 case FFI_TYPE_STRUCT:
|
|
141 if (cif->rtype->elements[0]->type == FFI_TYPE_STRUCT &&
|
|
142 cif->rtype->elements[1])
|
|
143 {
|
|
144 cif->flags = 0;
|
|
145 break;
|
|
146 }
|
|
147
|
|
148 switch (cif->rtype->size)
|
|
149 {
|
|
150 case 1:
|
|
151 #ifdef __MINT__
|
|
152 cif->flags = CIF_FLAGS_STRUCT2;
|
|
153 #else
|
|
154 cif->flags = CIF_FLAGS_STRUCT1;
|
|
155 #endif
|
|
156 break;
|
|
157 case 2:
|
|
158 cif->flags = CIF_FLAGS_STRUCT2;
|
|
159 break;
|
|
160 #ifdef __MINT__
|
|
161 case 3:
|
|
162 #endif
|
|
163 case 4:
|
|
164 cif->flags = CIF_FLAGS_INT;
|
|
165 break;
|
|
166 #ifdef __MINT__
|
|
167 case 7:
|
|
168 #endif
|
|
169 case 8:
|
|
170 cif->flags = CIF_FLAGS_DINT;
|
|
171 break;
|
|
172 default:
|
|
173 cif->flags = 0;
|
|
174 break;
|
|
175 }
|
|
176 break;
|
|
177
|
|
178 case FFI_TYPE_FLOAT:
|
|
179 cif->flags = CIF_FLAGS_FLOAT;
|
|
180 break;
|
|
181
|
|
182 case FFI_TYPE_DOUBLE:
|
|
183 cif->flags = CIF_FLAGS_DOUBLE;
|
|
184 break;
|
|
185
|
|
186 #if (FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE)
|
|
187 case FFI_TYPE_LONGDOUBLE:
|
|
188 #ifdef __MINT__
|
|
189 cif->flags = 0;
|
|
190 #else
|
|
191 cif->flags = CIF_FLAGS_LDOUBLE;
|
|
192 #endif
|
|
193 break;
|
|
194 #endif
|
|
195
|
|
196 case FFI_TYPE_POINTER:
|
|
197 cif->flags = CIF_FLAGS_POINTER;
|
|
198 break;
|
|
199
|
|
200 case FFI_TYPE_SINT64:
|
|
201 case FFI_TYPE_UINT64:
|
|
202 cif->flags = CIF_FLAGS_DINT;
|
|
203 break;
|
|
204
|
|
205 case FFI_TYPE_SINT16:
|
|
206 cif->flags = CIF_FLAGS_SINT16;
|
|
207 break;
|
|
208
|
|
209 case FFI_TYPE_SINT8:
|
|
210 cif->flags = CIF_FLAGS_SINT8;
|
|
211 break;
|
|
212
|
|
213 default:
|
|
214 cif->flags = CIF_FLAGS_INT;
|
|
215 break;
|
|
216 }
|
|
217
|
|
218 return FFI_OK;
|
|
219 }
|
|
220
|
|
221 void
|
|
222 ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue)
|
|
223 {
|
|
224 extended_cif ecif;
|
|
225
|
|
226 ecif.cif = cif;
|
|
227 ecif.avalue = avalue;
|
|
228
|
|
229 /* If the return value is a struct and we don't have a return value
|
|
230 address then we need to make one. */
|
|
231
|
|
232 if (rvalue == NULL
|
|
233 && cif->rtype->type == FFI_TYPE_STRUCT
|
|
234 && cif->rtype->size > 8)
|
|
235 ecif.rvalue = alloca (cif->rtype->size);
|
|
236 else
|
|
237 ecif.rvalue = rvalue;
|
|
238
|
|
239 switch (cif->abi)
|
|
240 {
|
|
241 case FFI_SYSV:
|
|
242 ffi_call_SYSV (&ecif, cif->bytes, cif->flags,
|
|
243 ecif.rvalue, fn);
|
|
244 break;
|
|
245
|
|
246 default:
|
|
247 FFI_ASSERT (0);
|
|
248 break;
|
|
249 }
|
|
250 }
|
|
251
|
|
252 static void
|
|
253 ffi_prep_incoming_args_SYSV (char *stack, void **avalue, ffi_cif *cif)
|
|
254 {
|
|
255 unsigned int i;
|
|
256 void **p_argv;
|
|
257 char *argp;
|
|
258 ffi_type **p_arg;
|
|
259
|
|
260 argp = stack;
|
|
261 p_argv = avalue;
|
|
262
|
|
263 for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
|
|
264 {
|
|
265 size_t z;
|
|
266
|
|
267 z = (*p_arg)->size;
|
|
268 #ifdef __MINT__
|
|
269 if (cif->flags &&
|
|
270 cif->rtype->type == FFI_TYPE_STRUCT &&
|
|
271 (z == 1 || z == 2))
|
|
272 {
|
|
273 *p_argv = (void *) (argp + 2);
|
|
274
|
|
275 z = 4;
|
|
276 }
|
|
277 else
|
|
278 if (cif->flags &&
|
|
279 cif->rtype->type == FFI_TYPE_STRUCT &&
|
|
280 (z == 3 || z == 4))
|
|
281 {
|
|
282 *p_argv = (void *) (argp);
|
|
283
|
|
284 z = 4;
|
|
285 }
|
|
286 else
|
|
287 #endif
|
|
288 if (z <= 4)
|
|
289 {
|
|
290 *p_argv = (void *) (argp + 4 - z);
|
|
291
|
|
292 z = 4;
|
|
293 }
|
|
294 else
|
|
295 {
|
|
296 *p_argv = (void *) argp;
|
|
297
|
|
298 /* Align if necessary */
|
|
299 if ((sizeof(int) - 1) & z)
|
|
300 z = ALIGN(z, sizeof(int));
|
|
301 }
|
|
302
|
|
303 p_argv++;
|
|
304 argp += z;
|
|
305 }
|
|
306 }
|
|
307
|
|
308 unsigned int
|
|
309 ffi_closure_SYSV_inner (ffi_closure *closure, void *resp, void *args)
|
|
310 {
|
|
311 ffi_cif *cif;
|
|
312 void **arg_area;
|
|
313
|
|
314 cif = closure->cif;
|
|
315 arg_area = (void**) alloca (cif->nargs * sizeof (void *));
|
|
316
|
|
317 ffi_prep_incoming_args_SYSV(args, arg_area, cif);
|
|
318
|
|
319 (closure->fun) (cif, resp, arg_area, closure->user_data);
|
|
320
|
|
321 return cif->flags;
|
|
322 }
|
|
323
|
|
324 ffi_status
|
|
325 ffi_prep_closure_loc (ffi_closure* closure,
|
|
326 ffi_cif* cif,
|
|
327 void (*fun)(ffi_cif*,void*,void**,void*),
|
|
328 void *user_data,
|
|
329 void *codeloc)
|
|
330 {
|
|
331 if (cif->abi != FFI_SYSV)
|
|
332 return FFI_BAD_ABI;
|
|
333
|
|
334 *(unsigned short *)closure->tramp = 0x207c;
|
|
335 *(void **)(closure->tramp + 2) = codeloc;
|
|
336 *(unsigned short *)(closure->tramp + 6) = 0x4ef9;
|
|
337
|
|
338 if (
|
|
339 #ifdef __MINT__
|
|
340 (cif->rtype->type == FFI_TYPE_LONGDOUBLE) ||
|
|
341 #endif
|
|
342 (((cif->rtype->type == FFI_TYPE_STRUCT)
|
|
343 && !cif->flags)))
|
|
344 *(void **)(closure->tramp + 8) = ffi_closure_struct_SYSV;
|
|
345 else
|
|
346 *(void **)(closure->tramp + 8) = ffi_closure_SYSV;
|
|
347
|
|
348 #ifdef __rtems__
|
|
349 rtems_cache_flush_multiple_data_lines( codeloc, FFI_TRAMPOLINE_SIZE );
|
|
350 #elif defined(__MINT__)
|
|
351 Ssystem(S_FLUSHCACHE, codeloc, FFI_TRAMPOLINE_SIZE);
|
|
352 #else
|
|
353 syscall(SYS_cacheflush, codeloc, FLUSH_SCOPE_LINE,
|
|
354 FLUSH_CACHE_BOTH, FFI_TRAMPOLINE_SIZE);
|
|
355 #endif
|
|
356
|
|
357 closure->cif = cif;
|
|
358 closure->user_data = user_data;
|
|
359 closure->fun = fun;
|
|
360
|
|
361 return FFI_OK;
|
|
362 }
|