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 #include <sys/syscall.h>
13 #include <asm/cachectl.h>
14
15 void ffi_call_SYSV (extended_cif *,
16 unsigned, unsigned,
17 void *, void (*fn) ());
18 void *ffi_prep_args (void *stack, extended_cif *ecif);
19 void ffi_closure_SYSV (ffi_closure *);
20 void ffi_closure_struct_SYSV (ffi_closure *);
21 unsigned int ffi_closure_SYSV_inner (ffi_closure *closure,
22 void *resp, void *args);
23
24 /* ffi_prep_args is called by the assembly routine once stack space has
25 been allocated for the function's arguments. */
26
27 void *
ffi_prep_args(void * stack,extended_cif * ecif)28 ffi_prep_args (void *stack, extended_cif *ecif)
29 {
30 unsigned int i;
31 void **p_argv;
32 char *argp;
33 ffi_type **p_arg;
34 void *struct_value_ptr;
35
36 argp = stack;
37
38 if (ecif->cif->rtype->type == FFI_TYPE_STRUCT
39 && !ecif->cif->flags)
40 struct_value_ptr = ecif->rvalue;
41 else
42 struct_value_ptr = NULL;
43
44 p_argv = ecif->avalue;
45
46 for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
47 i != 0;
48 i--, p_arg++)
49 {
50 size_t z;
51
52 z = (*p_arg)->size;
53 if (z < sizeof (int))
54 {
55 switch ((*p_arg)->type)
56 {
57 case FFI_TYPE_SINT8:
58 *(signed int *) argp = (signed int) *(SINT8 *) *p_argv;
59 break;
60
61 case FFI_TYPE_UINT8:
62 *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv;
63 break;
64
65 case FFI_TYPE_SINT16:
66 *(signed int *) argp = (signed int) *(SINT16 *) *p_argv;
67 break;
68
69 case FFI_TYPE_UINT16:
70 *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv;
71 break;
72
73 case FFI_TYPE_STRUCT:
74 memcpy (argp + sizeof (int) - z, *p_argv, z);
75 break;
76
77 default:
78 FFI_ASSERT (0);
79 }
80 z = sizeof (int);
81 }
82 else
83 {
84 memcpy (argp, *p_argv, z);
85
86 /* Align if necessary. */
87 if ((sizeof(int) - 1) & z)
88 z = ALIGN(z, sizeof(int));
89 }
90
91 p_argv++;
92 argp += z;
93 }
94
95 return struct_value_ptr;
96 }
97
98 #define CIF_FLAGS_INT 1
99 #define CIF_FLAGS_DINT 2
100 #define CIF_FLAGS_FLOAT 4
101 #define CIF_FLAGS_DOUBLE 8
102 #define CIF_FLAGS_LDOUBLE 16
103 #define CIF_FLAGS_POINTER 32
104 #define CIF_FLAGS_STRUCT1 64
105 #define CIF_FLAGS_STRUCT2 128
106
107 /* Perform machine dependent cif processing */
108 ffi_status
ffi_prep_cif_machdep(ffi_cif * cif)109 ffi_prep_cif_machdep (ffi_cif *cif)
110 {
111 /* Set the return type flag */
112 switch (cif->rtype->type)
113 {
114 case FFI_TYPE_VOID:
115 cif->flags = 0;
116 break;
117
118 case FFI_TYPE_STRUCT:
119 switch (cif->rtype->size)
120 {
121 case 1:
122 cif->flags = CIF_FLAGS_STRUCT1;
123 break;
124 case 2:
125 cif->flags = CIF_FLAGS_STRUCT2;
126 break;
127 case 4:
128 cif->flags = CIF_FLAGS_INT;
129 break;
130 case 8:
131 cif->flags = CIF_FLAGS_DINT;
132 break;
133 default:
134 cif->flags = 0;
135 break;
136 }
137 break;
138
139 case FFI_TYPE_FLOAT:
140 cif->flags = CIF_FLAGS_FLOAT;
141 break;
142
143 case FFI_TYPE_DOUBLE:
144 cif->flags = CIF_FLAGS_DOUBLE;
145 break;
146
147 case FFI_TYPE_LONGDOUBLE:
148 cif->flags = CIF_FLAGS_LDOUBLE;
149 break;
150
151 case FFI_TYPE_POINTER:
152 cif->flags = CIF_FLAGS_POINTER;
153 break;
154
155 case FFI_TYPE_SINT64:
156 case FFI_TYPE_UINT64:
157 cif->flags = CIF_FLAGS_DINT;
158 break;
159
160 default:
161 cif->flags = CIF_FLAGS_INT;
162 break;
163 }
164
165 return FFI_OK;
166 }
167
168 void
ffi_call(ffi_cif * cif,void (* fn)(),void * rvalue,void ** avalue)169 ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue)
170 {
171 extended_cif ecif;
172
173 ecif.cif = cif;
174 ecif.avalue = avalue;
175
176 /* If the return value is a struct and we don't have a return value
177 address then we need to make one. */
178
179 if (rvalue == NULL
180 && cif->rtype->type == FFI_TYPE_STRUCT
181 && cif->rtype->size > 8)
182 ecif.rvalue = alloca (cif->rtype->size);
183 else
184 ecif.rvalue = rvalue;
185
186 switch (cif->abi)
187 {
188 case FFI_SYSV:
189 ffi_call_SYSV (&ecif, cif->bytes, cif->flags,
190 ecif.rvalue, fn);
191 break;
192
193 default:
194 FFI_ASSERT (0);
195 break;
196 }
197 }
198
199 static void
ffi_prep_incoming_args_SYSV(char * stack,void ** avalue,ffi_cif * cif)200 ffi_prep_incoming_args_SYSV (char *stack, void **avalue, ffi_cif *cif)
201 {
202 unsigned int i;
203 void **p_argv;
204 char *argp;
205 ffi_type **p_arg;
206
207 argp = stack;
208 p_argv = avalue;
209
210 for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
211 {
212 size_t z;
213
214 z = (*p_arg)->size;
215 if (z <= 4)
216 {
217 *p_argv = (void *) (argp + 4 - z);
218
219 z = 4;
220 }
221 else
222 {
223 *p_argv = (void *) argp;
224
225 /* Align if necessary */
226 if ((sizeof(int) - 1) & z)
227 z = ALIGN(z, sizeof(int));
228 }
229
230 p_argv++;
231 argp += z;
232 }
233 }
234
235 unsigned int
ffi_closure_SYSV_inner(ffi_closure * closure,void * resp,void * args)236 ffi_closure_SYSV_inner (ffi_closure *closure, void *resp, void *args)
237 {
238 ffi_cif *cif;
239 void **arg_area;
240
241 cif = closure->cif;
242 arg_area = (void**) alloca (cif->nargs * sizeof (void *));
243
244 ffi_prep_incoming_args_SYSV(args, arg_area, cif);
245
246 (closure->fun) (cif, resp, arg_area, closure->user_data);
247
248 return cif->flags;
249 }
250
251 ffi_status
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)252 ffi_prep_closure_loc (ffi_closure* closure,
253 ffi_cif* cif,
254 void (*fun)(ffi_cif*,void*,void**,void*),
255 void *user_data,
256 void *codeloc)
257 {
258 FFI_ASSERT (cif->abi == FFI_SYSV);
259
260 *(unsigned short *)closure->tramp = 0x207c;
261 *(void **)(closure->tramp + 2) = codeloc;
262 *(unsigned short *)(closure->tramp + 6) = 0x4ef9;
263 if (cif->rtype->type == FFI_TYPE_STRUCT
264 && !cif->flags)
265 *(void **)(closure->tramp + 8) = ffi_closure_struct_SYSV;
266 else
267 *(void **)(closure->tramp + 8) = ffi_closure_SYSV;
268
269 syscall(SYS_cacheflush, codeloc, FLUSH_SCOPE_LINE,
270 FLUSH_CACHE_BOTH, FFI_TRAMPOLINE_SIZE);
271
272 closure->cif = cif;
273 closure->user_data = user_data;
274 closure->fun = fun;
275
276 return FFI_OK;
277 }
278
279