]>
Commit | Line | Data |
---|---|---|
63e5e3e0 | 1 | /* ----------------------------------------------------------------------- |
7446546a AH |
2 | ffi.c - Copyright (c) 1996, 2007, 2008 Red Hat, Inc. |
3 | Copyright (c) 2008 David Daney | |
63e5e3e0 AG |
4 | |
5 | MIPS Foreign Function Interface | |
6 | ||
63e5e3e0 AG |
7 | Permission is hereby granted, free of charge, to any person obtaining |
8 | a copy of this software and associated documentation files (the | |
9 | ``Software''), to deal in the Software without restriction, including | |
10 | without limitation the rights to use, copy, modify, merge, publish, | |
11 | distribute, sublicense, and/or sell copies of the Software, and to | |
12 | permit persons to whom the Software is furnished to do so, subject to | |
13 | the following conditions: | |
14 | ||
15 | The above copyright notice and this permission notice shall be included | |
16 | in all copies or substantial portions of the Software. | |
17 | ||
5f933ef0 AH |
18 | THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, |
19 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | |
20 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | |
21 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT | |
22 | HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, | |
23 | WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | |
25 | DEALINGS IN THE SOFTWARE. | |
63e5e3e0 AG |
26 | ----------------------------------------------------------------------- */ |
27 | ||
28 | #include <ffi.h> | |
29 | #include <ffi_common.h> | |
30 | ||
31 | #include <stdlib.h> | |
32 | ||
7446546a AH |
33 | #ifdef __GNUC__ |
34 | # if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 3)) | |
35 | # define USE__BUILTIN___CLEAR_CACHE 1 | |
36 | # endif | |
37 | #endif | |
38 | ||
39 | #ifndef USE__BUILTIN___CLEAR_CACHE | |
40 | #include <sys/cachectl.h> | |
41 | #endif | |
42 | ||
89d9d98a DD |
43 | #ifdef FFI_DEBUG |
44 | # define FFI_MIPS_STOP_HERE() ffi_stop_here() | |
45 | #else | |
46 | # define FFI_MIPS_STOP_HERE() do {} while(0) | |
47 | #endif | |
48 | ||
49 | #ifdef FFI_MIPS_N32 | |
63e5e3e0 AG |
50 | #define FIX_ARGP \ |
51 | FFI_ASSERT(argp <= &stack[bytes]); \ | |
52 | if (argp == &stack[bytes]) \ | |
53 | { \ | |
54 | argp = stack; \ | |
89d9d98a | 55 | FFI_MIPS_STOP_HERE(); \ |
63e5e3e0 AG |
56 | } |
57 | #else | |
58 | #define FIX_ARGP | |
59 | #endif | |
60 | ||
61 | ||
62 | /* ffi_prep_args is called by the assembly routine once stack space | |
63 | has been allocated for the function's arguments */ | |
64 | ||
65 | static void ffi_prep_args(char *stack, | |
66 | extended_cif *ecif, | |
67 | int bytes, | |
68 | int flags) | |
69 | { | |
8a39029d TS |
70 | int i; |
71 | void **p_argv; | |
72 | char *argp; | |
73 | ffi_type **p_arg; | |
63e5e3e0 | 74 | |
89d9d98a | 75 | #ifdef FFI_MIPS_N32 |
63e5e3e0 AG |
76 | /* If more than 8 double words are used, the remainder go |
77 | on the stack. We reorder stuff on the stack here to | |
78 | support this easily. */ | |
8a39029d TS |
79 | if (bytes > 8 * sizeof(ffi_arg)) |
80 | argp = &stack[bytes - (8 * sizeof(ffi_arg))]; | |
63e5e3e0 AG |
81 | else |
82 | argp = stack; | |
83 | #else | |
84 | argp = stack; | |
85 | #endif | |
86 | ||
87 | memset(stack, 0, bytes); | |
88 | ||
89d9d98a | 89 | #ifdef FFI_MIPS_N32 |
63e5e3e0 AG |
90 | if ( ecif->cif->rstruct_flag != 0 ) |
91 | #else | |
92 | if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) | |
93 | #endif | |
94 | { | |
1450eb7a AT |
95 | *(ffi_arg *) argp = (ffi_arg) ecif->rvalue; |
96 | argp += sizeof(ffi_arg); | |
63e5e3e0 AG |
97 | FIX_ARGP; |
98 | } | |
99 | ||
63e5e3e0 AG |
100 | p_argv = ecif->avalue; |
101 | ||
5cbf8c8d | 102 | for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs; i++, p_arg++) |
63e5e3e0 AG |
103 | { |
104 | size_t z; | |
8a39029d | 105 | unsigned int a; |
63e5e3e0 | 106 | |
8a39029d | 107 | /* Align if necessary. */ |
39dca114 | 108 | a = (*p_arg)->alignment; |
8a39029d TS |
109 | if (a < sizeof(ffi_arg)) |
110 | a = sizeof(ffi_arg); | |
39dca114 | 111 | |
89d9d98a | 112 | if ((a - 1) & (unsigned long) argp) |
8a39029d TS |
113 | { |
114 | argp = (char *) ALIGN(argp, a); | |
115 | FIX_ARGP; | |
116 | } | |
63e5e3e0 | 117 | |
8a39029d TS |
118 | z = (*p_arg)->size; |
119 | if (z <= sizeof(ffi_arg)) | |
120 | { | |
89d9d98a | 121 | int type = (*p_arg)->type; |
8a39029d | 122 | z = sizeof(ffi_arg); |
63e5e3e0 | 123 | |
89d9d98a DD |
124 | /* The size of a pointer depends on the ABI */ |
125 | if (type == FFI_TYPE_POINTER) | |
5cbf8c8d DD |
126 | type = (ecif->cif->abi == FFI_N64 |
127 | || ecif->cif->abi == FFI_N64_SOFT_FLOAT) | |
128 | ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32; | |
89d9d98a | 129 | |
5cbf8c8d DD |
130 | if (i < 8 && (ecif->cif->abi == FFI_N32_SOFT_FLOAT |
131 | || ecif->cif->abi == FFI_N64_SOFT_FLOAT)) | |
132 | { | |
133 | switch (type) | |
134 | { | |
135 | case FFI_TYPE_FLOAT: | |
136 | type = FFI_TYPE_UINT32; | |
137 | break; | |
138 | case FFI_TYPE_DOUBLE: | |
139 | type = FFI_TYPE_UINT64; | |
140 | break; | |
141 | default: | |
142 | break; | |
143 | } | |
144 | } | |
89d9d98a | 145 | switch (type) |
63e5e3e0 | 146 | { |
8a39029d TS |
147 | case FFI_TYPE_SINT8: |
148 | *(ffi_arg *)argp = *(SINT8 *)(* p_argv); | |
149 | break; | |
63e5e3e0 | 150 | |
8a39029d TS |
151 | case FFI_TYPE_UINT8: |
152 | *(ffi_arg *)argp = *(UINT8 *)(* p_argv); | |
153 | break; | |
63e5e3e0 | 154 | |
8a39029d TS |
155 | case FFI_TYPE_SINT16: |
156 | *(ffi_arg *)argp = *(SINT16 *)(* p_argv); | |
157 | break; | |
63e5e3e0 | 158 | |
8a39029d TS |
159 | case FFI_TYPE_UINT16: |
160 | *(ffi_arg *)argp = *(UINT16 *)(* p_argv); | |
161 | break; | |
63e5e3e0 | 162 | |
8a39029d TS |
163 | case FFI_TYPE_SINT32: |
164 | *(ffi_arg *)argp = *(SINT32 *)(* p_argv); | |
165 | break; | |
63e5e3e0 | 166 | |
8a39029d | 167 | case FFI_TYPE_UINT32: |
8a39029d TS |
168 | *(ffi_arg *)argp = *(UINT32 *)(* p_argv); |
169 | break; | |
170 | ||
171 | /* This can only happen with 64bit slots. */ | |
172 | case FFI_TYPE_FLOAT: | |
173 | *(float *) argp = *(float *)(* p_argv); | |
174 | break; | |
175 | ||
89d9d98a | 176 | /* Handle structures. */ |
8a39029d TS |
177 | default: |
178 | memcpy(argp, *p_argv, (*p_arg)->size); | |
179 | break; | |
63e5e3e0 | 180 | } |
8a39029d TS |
181 | } |
182 | else | |
183 | { | |
89d9d98a | 184 | #ifdef FFI_MIPS_O32 |
8a39029d | 185 | memcpy(argp, *p_argv, z); |
63e5e3e0 | 186 | #else |
8a39029d | 187 | { |
89d9d98a DD |
188 | unsigned long end = (unsigned long) argp + z; |
189 | unsigned long cap = (unsigned long) stack + bytes; | |
8a39029d TS |
190 | |
191 | /* Check if the data will fit within the register space. | |
192 | Handle it if it doesn't. */ | |
193 | ||
194 | if (end <= cap) | |
195 | memcpy(argp, *p_argv, z); | |
196 | else | |
63e5e3e0 | 197 | { |
89d9d98a | 198 | unsigned long portion = cap - (unsigned long)argp; |
8a39029d TS |
199 | |
200 | memcpy(argp, *p_argv, portion); | |
201 | argp = stack; | |
89d9d98a DD |
202 | z -= portion; |
203 | memcpy(argp, (void*)((unsigned long)(*p_argv) + portion), | |
204 | z); | |
63e5e3e0 | 205 | } |
8a39029d | 206 | } |
63e5e3e0 | 207 | #endif |
8a39029d TS |
208 | } |
209 | p_argv++; | |
210 | argp += z; | |
211 | FIX_ARGP; | |
63e5e3e0 | 212 | } |
63e5e3e0 AG |
213 | } |
214 | ||
89d9d98a | 215 | #ifdef FFI_MIPS_N32 |
63e5e3e0 AG |
216 | |
217 | /* The n32 spec says that if "a chunk consists solely of a double | |
218 | float field (but not a double, which is part of a union), it | |
219 | is passed in a floating point register. Any other chunk is | |
220 | passed in an integer register". This code traverses structure | |
221 | definitions and generates the appropriate flags. */ | |
222 | ||
89d9d98a | 223 | static unsigned |
5cbf8c8d DD |
224 | calc_n32_struct_flags(int soft_float, ffi_type *arg, |
225 | unsigned *loc, unsigned *arg_reg) | |
63e5e3e0 AG |
226 | { |
227 | unsigned flags = 0; | |
228 | unsigned index = 0; | |
229 | ||
230 | ffi_type *e; | |
231 | ||
5cbf8c8d DD |
232 | if (soft_float) |
233 | return 0; | |
234 | ||
89d9d98a | 235 | while ((e = arg->elements[index])) |
63e5e3e0 | 236 | { |
89d9d98a DD |
237 | /* Align this object. */ |
238 | *loc = ALIGN(*loc, e->alignment); | |
63e5e3e0 AG |
239 | if (e->type == FFI_TYPE_DOUBLE) |
240 | { | |
89d9d98a DD |
241 | /* Already aligned to FFI_SIZEOF_ARG. */ |
242 | *arg_reg = *loc / FFI_SIZEOF_ARG; | |
243 | if (*arg_reg > 7) | |
244 | break; | |
245 | flags += (FFI_TYPE_DOUBLE << (*arg_reg * FFI_FLAG_BITS)); | |
246 | *loc += e->size; | |
63e5e3e0 | 247 | } |
63e5e3e0 | 248 | else |
89d9d98a | 249 | *loc += e->size; |
63e5e3e0 AG |
250 | index++; |
251 | } | |
89d9d98a DD |
252 | /* Next Argument register at alignment of FFI_SIZEOF_ARG. */ |
253 | *arg_reg = ALIGN(*loc, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; | |
63e5e3e0 AG |
254 | |
255 | return flags; | |
256 | } | |
257 | ||
89d9d98a | 258 | static unsigned |
5cbf8c8d | 259 | calc_n32_return_struct_flags(int soft_float, ffi_type *arg) |
63e5e3e0 AG |
260 | { |
261 | unsigned flags = 0; | |
63e5e3e0 AG |
262 | unsigned small = FFI_TYPE_SMALLSTRUCT; |
263 | ffi_type *e; | |
264 | ||
265 | /* Returning structures under n32 is a tricky thing. | |
266 | A struct with only one or two floating point fields | |
267 | is returned in $f0 (and $f2 if necessary). Any other | |
268 | struct results at most 128 bits are returned in $2 | |
269 | (the first 64 bits) and $3 (remainder, if necessary). | |
270 | Larger structs are handled normally. */ | |
271 | ||
272 | if (arg->size > 16) | |
273 | return 0; | |
274 | ||
275 | if (arg->size > 8) | |
276 | small = FFI_TYPE_SMALLSTRUCT2; | |
277 | ||
278 | e = arg->elements[0]; | |
5cbf8c8d | 279 | |
63e5e3e0 | 280 | if (e->type == FFI_TYPE_DOUBLE) |
89d9d98a | 281 | flags = FFI_TYPE_DOUBLE; |
63e5e3e0 | 282 | else if (e->type == FFI_TYPE_FLOAT) |
89d9d98a | 283 | flags = FFI_TYPE_FLOAT; |
63e5e3e0 AG |
284 | |
285 | if (flags && (e = arg->elements[1])) | |
286 | { | |
287 | if (e->type == FFI_TYPE_DOUBLE) | |
89d9d98a | 288 | flags += FFI_TYPE_DOUBLE << FFI_FLAG_BITS; |
63e5e3e0 | 289 | else if (e->type == FFI_TYPE_FLOAT) |
89d9d98a | 290 | flags += FFI_TYPE_FLOAT << FFI_FLAG_BITS; |
63e5e3e0 AG |
291 | else |
292 | return small; | |
293 | ||
294 | if (flags && (arg->elements[2])) | |
295 | { | |
296 | /* There are three arguments and the first two are | |
297 | floats! This must be passed the old way. */ | |
298 | return small; | |
299 | } | |
5cbf8c8d DD |
300 | if (soft_float) |
301 | flags += FFI_TYPE_STRUCT_SOFT; | |
63e5e3e0 AG |
302 | } |
303 | else | |
304 | if (!flags) | |
305 | return small; | |
306 | ||
307 | return flags; | |
308 | } | |
309 | ||
310 | #endif | |
311 | ||
312 | /* Perform machine dependent cif processing */ | |
313 | ffi_status ffi_prep_cif_machdep(ffi_cif *cif) | |
314 | { | |
315 | cif->flags = 0; | |
316 | ||
89d9d98a | 317 | #ifdef FFI_MIPS_O32 |
39dca114 DD |
318 | /* Set the flags necessary for O32 processing. FFI_O32_SOFT_FLOAT |
319 | * does not have special handling for floating point args. | |
320 | */ | |
63e5e3e0 | 321 | |
39dca114 | 322 | if (cif->rtype->type != FFI_TYPE_STRUCT && cif->abi == FFI_O32) |
63e5e3e0 AG |
323 | { |
324 | if (cif->nargs > 0) | |
325 | { | |
326 | switch ((cif->arg_types)[0]->type) | |
327 | { | |
328 | case FFI_TYPE_FLOAT: | |
329 | case FFI_TYPE_DOUBLE: | |
330 | cif->flags += (cif->arg_types)[0]->type; | |
331 | break; | |
332 | ||
333 | default: | |
334 | break; | |
335 | } | |
336 | ||
337 | if (cif->nargs > 1) | |
338 | { | |
339 | /* Only handle the second argument if the first | |
340 | is a float or double. */ | |
341 | if (cif->flags) | |
342 | { | |
343 | switch ((cif->arg_types)[1]->type) | |
344 | { | |
345 | case FFI_TYPE_FLOAT: | |
346 | case FFI_TYPE_DOUBLE: | |
347 | cif->flags += (cif->arg_types)[1]->type << FFI_FLAG_BITS; | |
348 | break; | |
349 | ||
350 | default: | |
351 | break; | |
352 | } | |
353 | } | |
354 | } | |
355 | } | |
356 | } | |
357 | ||
358 | /* Set the return type flag */ | |
b790003a | 359 | |
39dca114 DD |
360 | if (cif->abi == FFI_O32_SOFT_FLOAT) |
361 | { | |
362 | switch (cif->rtype->type) | |
363 | { | |
364 | case FFI_TYPE_VOID: | |
365 | case FFI_TYPE_STRUCT: | |
366 | cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2); | |
367 | break; | |
368 | ||
369 | case FFI_TYPE_SINT64: | |
370 | case FFI_TYPE_UINT64: | |
371 | case FFI_TYPE_DOUBLE: | |
372 | cif->flags += FFI_TYPE_UINT64 << (FFI_FLAG_BITS * 2); | |
373 | break; | |
63e5e3e0 | 374 | |
39dca114 DD |
375 | case FFI_TYPE_FLOAT: |
376 | default: | |
377 | cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 2); | |
378 | break; | |
379 | } | |
380 | } | |
381 | else | |
382 | { | |
383 | /* FFI_O32 */ | |
384 | switch (cif->rtype->type) | |
385 | { | |
386 | case FFI_TYPE_VOID: | |
387 | case FFI_TYPE_STRUCT: | |
388 | case FFI_TYPE_FLOAT: | |
389 | case FFI_TYPE_DOUBLE: | |
390 | cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 2); | |
391 | break; | |
392 | ||
393 | case FFI_TYPE_SINT64: | |
394 | case FFI_TYPE_UINT64: | |
395 | cif->flags += FFI_TYPE_UINT64 << (FFI_FLAG_BITS * 2); | |
396 | break; | |
397 | ||
398 | default: | |
399 | cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 2); | |
400 | break; | |
401 | } | |
63e5e3e0 AG |
402 | } |
403 | #endif | |
404 | ||
89d9d98a | 405 | #ifdef FFI_MIPS_N32 |
63e5e3e0 AG |
406 | /* Set the flags necessary for N32 processing */ |
407 | { | |
5cbf8c8d | 408 | int type; |
89d9d98a DD |
409 | unsigned arg_reg = 0; |
410 | unsigned loc = 0; | |
63e5e3e0 AG |
411 | unsigned count = (cif->nargs < 8) ? cif->nargs : 8; |
412 | unsigned index = 0; | |
413 | ||
414 | unsigned struct_flags = 0; | |
5cbf8c8d DD |
415 | int soft_float = (cif->abi == FFI_N32_SOFT_FLOAT |
416 | || cif->abi == FFI_N64_SOFT_FLOAT); | |
63e5e3e0 AG |
417 | |
418 | if (cif->rtype->type == FFI_TYPE_STRUCT) | |
419 | { | |
5cbf8c8d | 420 | struct_flags = calc_n32_return_struct_flags(soft_float, cif->rtype); |
63e5e3e0 AG |
421 | |
422 | if (struct_flags == 0) | |
423 | { | |
424 | /* This means that the structure is being passed as | |
425 | a hidden argument */ | |
426 | ||
89d9d98a | 427 | arg_reg = 1; |
63e5e3e0 AG |
428 | count = (cif->nargs < 7) ? cif->nargs : 7; |
429 | ||
430 | cif->rstruct_flag = !0; | |
431 | } | |
432 | else | |
433 | cif->rstruct_flag = 0; | |
434 | } | |
435 | else | |
436 | cif->rstruct_flag = 0; | |
437 | ||
89d9d98a | 438 | while (count-- > 0 && arg_reg < 8) |
63e5e3e0 | 439 | { |
5cbf8c8d DD |
440 | type = (cif->arg_types)[index]->type; |
441 | if (soft_float) | |
442 | { | |
443 | switch (type) | |
444 | { | |
445 | case FFI_TYPE_FLOAT: | |
446 | type = FFI_TYPE_UINT32; | |
447 | break; | |
448 | case FFI_TYPE_DOUBLE: | |
449 | type = FFI_TYPE_UINT64; | |
450 | break; | |
451 | default: | |
452 | break; | |
453 | } | |
454 | } | |
455 | switch (type) | |
63e5e3e0 AG |
456 | { |
457 | case FFI_TYPE_FLOAT: | |
458 | case FFI_TYPE_DOUBLE: | |
89d9d98a DD |
459 | cif->flags += |
460 | ((cif->arg_types)[index]->type << (arg_reg * FFI_FLAG_BITS)); | |
461 | arg_reg++; | |
63e5e3e0 | 462 | break; |
89d9d98a DD |
463 | case FFI_TYPE_LONGDOUBLE: |
464 | /* Align it. */ | |
465 | arg_reg = ALIGN(arg_reg, 2); | |
466 | /* Treat it as two adjacent doubles. */ | |
5cbf8c8d DD |
467 | if (soft_float) |
468 | { | |
469 | arg_reg += 2; | |
470 | } | |
471 | else | |
472 | { | |
473 | cif->flags += | |
474 | (FFI_TYPE_DOUBLE << (arg_reg * FFI_FLAG_BITS)); | |
475 | arg_reg++; | |
476 | cif->flags += | |
477 | (FFI_TYPE_DOUBLE << (arg_reg * FFI_FLAG_BITS)); | |
478 | arg_reg++; | |
479 | } | |
89d9d98a | 480 | break; |
63e5e3e0 AG |
481 | |
482 | case FFI_TYPE_STRUCT: | |
89d9d98a | 483 | loc = arg_reg * FFI_SIZEOF_ARG; |
5cbf8c8d DD |
484 | cif->flags += calc_n32_struct_flags(soft_float, |
485 | (cif->arg_types)[index], | |
89d9d98a | 486 | &loc, &arg_reg); |
63e5e3e0 AG |
487 | break; |
488 | ||
489 | default: | |
89d9d98a DD |
490 | arg_reg++; |
491 | break; | |
63e5e3e0 AG |
492 | } |
493 | ||
494 | index++; | |
495 | } | |
496 | ||
497 | /* Set the return type flag */ | |
498 | switch (cif->rtype->type) | |
499 | { | |
500 | case FFI_TYPE_STRUCT: | |
501 | { | |
502 | if (struct_flags == 0) | |
503 | { | |
504 | /* The structure is returned through a hidden | |
505 | first argument. Do nothing, 'cause FFI_TYPE_VOID | |
506 | is 0 */ | |
507 | } | |
508 | else | |
509 | { | |
510 | /* The structure is returned via some tricky | |
511 | mechanism */ | |
512 | cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8); | |
513 | cif->flags += struct_flags << (4 + (FFI_FLAG_BITS * 8)); | |
514 | } | |
515 | break; | |
516 | } | |
517 | ||
518 | case FFI_TYPE_VOID: | |
519 | /* Do nothing, 'cause FFI_TYPE_VOID is 0 */ | |
520 | break; | |
5cbf8c8d DD |
521 | |
522 | case FFI_TYPE_POINTER: | |
523 | if (cif->abi == FFI_N32_SOFT_FLOAT || cif->abi == FFI_N32) | |
524 | cif->flags += FFI_TYPE_SINT32 << (FFI_FLAG_BITS * 8); | |
525 | else | |
526 | cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8); | |
527 | break; | |
528 | ||
63e5e3e0 | 529 | case FFI_TYPE_FLOAT: |
5cbf8c8d DD |
530 | if (soft_float) |
531 | { | |
532 | cif->flags += FFI_TYPE_SINT32 << (FFI_FLAG_BITS * 8); | |
533 | break; | |
534 | } | |
535 | /* else fall through */ | |
63e5e3e0 | 536 | case FFI_TYPE_DOUBLE: |
5cbf8c8d DD |
537 | if (soft_float) |
538 | cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8); | |
539 | else | |
540 | cif->flags += cif->rtype->type << (FFI_FLAG_BITS * 8); | |
63e5e3e0 | 541 | break; |
5cbf8c8d | 542 | |
3875b6d7 DD |
543 | case FFI_TYPE_LONGDOUBLE: |
544 | /* Long double is returned as if it were a struct containing | |
545 | two doubles. */ | |
5cbf8c8d DD |
546 | if (soft_float) |
547 | { | |
548 | cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8); | |
549 | cif->flags += FFI_TYPE_SMALLSTRUCT2 << (4 + (FFI_FLAG_BITS * 8)); | |
550 | } | |
551 | else | |
552 | { | |
553 | cif->flags += FFI_TYPE_STRUCT << (FFI_FLAG_BITS * 8); | |
554 | cif->flags += (FFI_TYPE_DOUBLE | |
555 | + (FFI_TYPE_DOUBLE << FFI_FLAG_BITS)) | |
556 | << (4 + (FFI_FLAG_BITS * 8)); | |
557 | } | |
3875b6d7 | 558 | break; |
63e5e3e0 AG |
559 | default: |
560 | cif->flags += FFI_TYPE_INT << (FFI_FLAG_BITS * 8); | |
561 | break; | |
562 | } | |
563 | } | |
564 | #endif | |
565 | ||
566 | return FFI_OK; | |
567 | } | |
568 | ||
569 | /* Low level routine for calling O32 functions */ | |
570 | extern int ffi_call_O32(void (*)(char *, extended_cif *, int, int), | |
571 | extended_cif *, unsigned, | |
7446546a | 572 | unsigned, unsigned *, void (*)(void)); |
63e5e3e0 AG |
573 | |
574 | /* Low level routine for calling N32 functions */ | |
575 | extern int ffi_call_N32(void (*)(char *, extended_cif *, int, int), | |
576 | extended_cif *, unsigned, | |
5cbf8c8d | 577 | unsigned, void *, void (*)(void)); |
63e5e3e0 | 578 | |
7446546a | 579 | void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue) |
63e5e3e0 AG |
580 | { |
581 | extended_cif ecif; | |
582 | ||
583 | ecif.cif = cif; | |
584 | ecif.avalue = avalue; | |
585 | ||
586 | /* If the return value is a struct and we don't have a return */ | |
587 | /* value address then we need to make one */ | |
588 | ||
589 | if ((rvalue == NULL) && | |
590 | (cif->rtype->type == FFI_TYPE_STRUCT)) | |
591 | ecif.rvalue = alloca(cif->rtype->size); | |
592 | else | |
593 | ecif.rvalue = rvalue; | |
594 | ||
595 | switch (cif->abi) | |
596 | { | |
89d9d98a | 597 | #ifdef FFI_MIPS_O32 |
63e5e3e0 | 598 | case FFI_O32: |
39dca114 | 599 | case FFI_O32_SOFT_FLOAT: |
63e5e3e0 AG |
600 | ffi_call_O32(ffi_prep_args, &ecif, cif->bytes, |
601 | cif->flags, ecif.rvalue, fn); | |
602 | break; | |
603 | #endif | |
604 | ||
89d9d98a | 605 | #ifdef FFI_MIPS_N32 |
63e5e3e0 | 606 | case FFI_N32: |
5cbf8c8d | 607 | case FFI_N32_SOFT_FLOAT: |
89d9d98a | 608 | case FFI_N64: |
5cbf8c8d | 609 | case FFI_N64_SOFT_FLOAT: |
89d9d98a DD |
610 | { |
611 | int copy_rvalue = 0; | |
5cbf8c8d DD |
612 | int copy_offset = 0; |
613 | char *rvalue_copy = ecif.rvalue; | |
89d9d98a DD |
614 | if (cif->rtype->type == FFI_TYPE_STRUCT && cif->rtype->size < 16) |
615 | { | |
616 | /* For structures smaller than 16 bytes we clobber memory | |
617 | in 8 byte increments. Make a copy so we don't clobber | |
618 | the callers memory outside of the struct bounds. */ | |
619 | rvalue_copy = alloca(16); | |
620 | copy_rvalue = 1; | |
621 | } | |
5cbf8c8d DD |
622 | else if (cif->rtype->type == FFI_TYPE_FLOAT |
623 | && (cif->abi == FFI_N64_SOFT_FLOAT | |
624 | || cif->abi == FFI_N32_SOFT_FLOAT)) | |
625 | { | |
626 | rvalue_copy = alloca (8); | |
627 | copy_rvalue = 1; | |
c4205f77 | 628 | #if defined(__MIPSEB__) || defined(_MIPSEB) |
5cbf8c8d DD |
629 | copy_offset = 4; |
630 | #endif | |
631 | } | |
89d9d98a DD |
632 | ffi_call_N32(ffi_prep_args, &ecif, cif->bytes, |
633 | cif->flags, rvalue_copy, fn); | |
634 | if (copy_rvalue) | |
5cbf8c8d | 635 | memcpy(ecif.rvalue, rvalue_copy + copy_offset, cif->rtype->size); |
89d9d98a | 636 | } |
63e5e3e0 AG |
637 | break; |
638 | #endif | |
639 | ||
640 | default: | |
641 | FFI_ASSERT(0); | |
642 | break; | |
643 | } | |
644 | } | |
b790003a | 645 | |
89d9d98a | 646 | #if FFI_CLOSURES |
b790003a CM |
647 | #if defined(FFI_MIPS_O32) |
648 | extern void ffi_closure_O32(void); | |
89d9d98a DD |
649 | #else |
650 | extern void ffi_closure_N32(void); | |
b790003a CM |
651 | #endif /* FFI_MIPS_O32 */ |
652 | ||
653 | ffi_status | |
18fa3240 AO |
654 | ffi_prep_closure_loc (ffi_closure *closure, |
655 | ffi_cif *cif, | |
656 | void (*fun)(ffi_cif*,void*,void**,void*), | |
657 | void *user_data, | |
658 | void *codeloc) | |
b790003a CM |
659 | { |
660 | unsigned int *tramp = (unsigned int *) &closure->tramp[0]; | |
89d9d98a | 661 | void * fn; |
433e6a8c | 662 | char *clear_location = (char *) codeloc; |
b790003a CM |
663 | |
664 | #if defined(FFI_MIPS_O32) | |
39dca114 | 665 | FFI_ASSERT(cif->abi == FFI_O32 || cif->abi == FFI_O32_SOFT_FLOAT); |
89d9d98a | 666 | fn = ffi_closure_O32; |
b790003a | 667 | #else /* FFI_MIPS_N32 */ |
89d9d98a DD |
668 | FFI_ASSERT(cif->abi == FFI_N32 || cif->abi == FFI_N64); |
669 | fn = ffi_closure_N32; | |
b790003a CM |
670 | #endif /* FFI_MIPS_O32 */ |
671 | ||
89d9d98a DD |
672 | #if defined(FFI_MIPS_O32) || (_MIPS_SIM ==_ABIN32) |
673 | /* lui $25,high(fn) */ | |
674 | tramp[0] = 0x3c190000 | ((unsigned)fn >> 16); | |
675 | /* ori $25,low(fn) */ | |
676 | tramp[1] = 0x37390000 | ((unsigned)fn & 0xffff); | |
677 | /* lui $12,high(codeloc) */ | |
678 | tramp[2] = 0x3c0c0000 | ((unsigned)codeloc >> 16); | |
679 | /* jr $25 */ | |
680 | tramp[3] = 0x03200008; | |
681 | /* ori $12,low(codeloc) */ | |
682 | tramp[4] = 0x358c0000 | ((unsigned)codeloc & 0xffff); | |
683 | #else | |
684 | /* N64 has a somewhat larger trampoline. */ | |
685 | /* lui $25,high(fn) */ | |
686 | tramp[0] = 0x3c190000 | ((unsigned long)fn >> 48); | |
687 | /* lui $12,high(codeloc) */ | |
688 | tramp[1] = 0x3c0c0000 | ((unsigned long)codeloc >> 48); | |
689 | /* ori $25,mid-high(fn) */ | |
690 | tramp[2] = 0x37390000 | (((unsigned long)fn >> 32 ) & 0xffff); | |
691 | /* ori $12,mid-high(codeloc) */ | |
692 | tramp[3] = 0x358c0000 | (((unsigned long)codeloc >> 32) & 0xffff); | |
693 | /* dsll $25,$25,16 */ | |
694 | tramp[4] = 0x0019cc38; | |
695 | /* dsll $12,$12,16 */ | |
696 | tramp[5] = 0x000c6438; | |
697 | /* ori $25,mid-low(fn) */ | |
698 | tramp[6] = 0x37390000 | (((unsigned long)fn >> 16 ) & 0xffff); | |
699 | /* ori $12,mid-low(codeloc) */ | |
700 | tramp[7] = 0x358c0000 | (((unsigned long)codeloc >> 16) & 0xffff); | |
701 | /* dsll $25,$25,16 */ | |
702 | tramp[8] = 0x0019cc38; | |
703 | /* dsll $12,$12,16 */ | |
704 | tramp[9] = 0x000c6438; | |
705 | /* ori $25,low(fn) */ | |
706 | tramp[10] = 0x37390000 | ((unsigned long)fn & 0xffff); | |
707 | /* jr $25 */ | |
708 | tramp[11] = 0x03200008; | |
709 | /* ori $12,low(codeloc) */ | |
710 | tramp[12] = 0x358c0000 | ((unsigned long)codeloc & 0xffff); | |
711 | ||
712 | #endif | |
b790003a CM |
713 | |
714 | closure->cif = cif; | |
715 | closure->fun = fun; | |
716 | closure->user_data = user_data; | |
717 | ||
7446546a | 718 | #ifdef USE__BUILTIN___CLEAR_CACHE |
433e6a8c | 719 | __builtin___clear_cache(clear_location, clear_location + FFI_TRAMPOLINE_SIZE); |
7446546a AH |
720 | #else |
721 | cacheflush (clear_location, FFI_TRAMPOLINE_SIZE, ICACHE); | |
722 | #endif | |
b790003a CM |
723 | return FFI_OK; |
724 | } | |
725 | ||
726 | /* | |
727 | * Decodes the arguments to a function, which will be stored on the | |
728 | * stack. AR is the pointer to the beginning of the integer arguments | |
729 | * (and, depending upon the arguments, some floating-point arguments | |
730 | * as well). FPR is a pointer to the area where floating point | |
731 | * registers have been saved, if any. | |
732 | * | |
733 | * RVALUE is the location where the function return value will be | |
734 | * stored. CLOSURE is the prepared closure to invoke. | |
735 | * | |
736 | * This function should only be called from assembly, which is in | |
737 | * turn called from a trampoline. | |
738 | * | |
739 | * Returns the function return type. | |
740 | * | |
741 | * Based on the similar routine for sparc. | |
742 | */ | |
743 | int | |
744 | ffi_closure_mips_inner_O32 (ffi_closure *closure, | |
8a39029d | 745 | void *rvalue, ffi_arg *ar, |
b790003a CM |
746 | double *fpr) |
747 | { | |
748 | ffi_cif *cif; | |
8a39029d TS |
749 | void **avaluep; |
750 | ffi_arg *avalue; | |
b790003a CM |
751 | ffi_type **arg_types; |
752 | int i, avn, argn, seen_int; | |
753 | ||
754 | cif = closure->cif; | |
8a39029d TS |
755 | avalue = alloca (cif->nargs * sizeof (ffi_arg)); |
756 | avaluep = alloca (cif->nargs * sizeof (ffi_arg)); | |
b790003a | 757 | |
39dca114 | 758 | seen_int = (cif->abi == FFI_O32_SOFT_FLOAT); |
b790003a CM |
759 | argn = 0; |
760 | ||
39dca114 | 761 | if ((cif->flags >> (FFI_FLAG_BITS * 2)) == FFI_TYPE_STRUCT) |
b790003a | 762 | { |
89d9d98a | 763 | rvalue = (void *)(UINT32)ar[0]; |
b790003a CM |
764 | argn = 1; |
765 | } | |
766 | ||
767 | i = 0; | |
768 | avn = cif->nargs; | |
769 | arg_types = cif->arg_types; | |
770 | ||
771 | while (i < avn) | |
772 | { | |
773 | if (i < 2 && !seen_int && | |
774 | (arg_types[i]->type == FFI_TYPE_FLOAT || | |
c4205f77 FE |
775 | arg_types[i]->type == FFI_TYPE_DOUBLE || |
776 | arg_types[i]->type == FFI_TYPE_LONGDOUBLE)) | |
b790003a | 777 | { |
c4205f77 | 778 | #if defined(__MIPSEB__) || defined(_MIPSEB) |
8a39029d TS |
779 | if (arg_types[i]->type == FFI_TYPE_FLOAT) |
780 | avaluep[i] = ((char *) &fpr[i]) + sizeof (float); | |
781 | else | |
782 | #endif | |
783 | avaluep[i] = (char *) &fpr[i]; | |
b790003a CM |
784 | } |
785 | else | |
786 | { | |
39dca114 | 787 | if (arg_types[i]->alignment == 8 && (argn & 0x1)) |
b790003a | 788 | argn++; |
8a39029d TS |
789 | switch (arg_types[i]->type) |
790 | { | |
791 | case FFI_TYPE_SINT8: | |
792 | avaluep[i] = &avalue[i]; | |
793 | *(SINT8 *) &avalue[i] = (SINT8) ar[argn]; | |
794 | break; | |
795 | ||
796 | case FFI_TYPE_UINT8: | |
797 | avaluep[i] = &avalue[i]; | |
798 | *(UINT8 *) &avalue[i] = (UINT8) ar[argn]; | |
799 | break; | |
800 | ||
801 | case FFI_TYPE_SINT16: | |
802 | avaluep[i] = &avalue[i]; | |
803 | *(SINT16 *) &avalue[i] = (SINT16) ar[argn]; | |
804 | break; | |
805 | ||
806 | case FFI_TYPE_UINT16: | |
807 | avaluep[i] = &avalue[i]; | |
808 | *(UINT16 *) &avalue[i] = (UINT16) ar[argn]; | |
809 | break; | |
810 | ||
811 | default: | |
812 | avaluep[i] = (char *) &ar[argn]; | |
813 | break; | |
814 | } | |
b790003a CM |
815 | seen_int = 1; |
816 | } | |
817 | argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG; | |
818 | i++; | |
819 | } | |
820 | ||
821 | /* Invoke the closure. */ | |
8a39029d | 822 | (closure->fun) (cif, rvalue, avaluep, closure->user_data); |
b790003a | 823 | |
39dca114 DD |
824 | if (cif->abi == FFI_O32_SOFT_FLOAT) |
825 | { | |
826 | switch (cif->rtype->type) | |
827 | { | |
828 | case FFI_TYPE_FLOAT: | |
829 | return FFI_TYPE_INT; | |
830 | case FFI_TYPE_DOUBLE: | |
831 | return FFI_TYPE_UINT64; | |
832 | default: | |
833 | return cif->rtype->type; | |
834 | } | |
835 | } | |
836 | else | |
837 | { | |
838 | return cif->rtype->type; | |
839 | } | |
b790003a CM |
840 | } |
841 | ||
89d9d98a DD |
842 | #if defined(FFI_MIPS_N32) |
843 | ||
844 | static void | |
845 | copy_struct_N32(char *target, unsigned offset, ffi_abi abi, ffi_type *type, | |
846 | int argn, unsigned arg_offset, ffi_arg *ar, | |
5cbf8c8d | 847 | ffi_arg *fpr, int soft_float) |
89d9d98a DD |
848 | { |
849 | ffi_type **elt_typep = type->elements; | |
850 | while(*elt_typep) | |
851 | { | |
852 | ffi_type *elt_type = *elt_typep; | |
853 | unsigned o; | |
854 | char *tp; | |
855 | char *argp; | |
856 | char *fpp; | |
857 | ||
858 | o = ALIGN(offset, elt_type->alignment); | |
859 | arg_offset += o - offset; | |
860 | offset = o; | |
861 | argn += arg_offset / sizeof(ffi_arg); | |
862 | arg_offset = arg_offset % sizeof(ffi_arg); | |
863 | ||
864 | argp = (char *)(ar + argn); | |
865 | fpp = (char *)(argn >= 8 ? ar + argn : fpr + argn); | |
866 | ||
867 | tp = target + offset; | |
868 | ||
5cbf8c8d | 869 | if (elt_type->type == FFI_TYPE_DOUBLE && !soft_float) |
89d9d98a DD |
870 | *(double *)tp = *(double *)fpp; |
871 | else | |
872 | memcpy(tp, argp + arg_offset, elt_type->size); | |
873 | ||
874 | offset += elt_type->size; | |
875 | arg_offset += elt_type->size; | |
876 | elt_typep++; | |
877 | argn += arg_offset / sizeof(ffi_arg); | |
878 | arg_offset = arg_offset % sizeof(ffi_arg); | |
879 | } | |
880 | } | |
881 | ||
882 | /* | |
883 | * Decodes the arguments to a function, which will be stored on the | |
884 | * stack. AR is the pointer to the beginning of the integer | |
885 | * arguments. FPR is a pointer to the area where floating point | |
886 | * registers have been saved. | |
887 | * | |
888 | * RVALUE is the location where the function return value will be | |
889 | * stored. CLOSURE is the prepared closure to invoke. | |
890 | * | |
891 | * This function should only be called from assembly, which is in | |
892 | * turn called from a trampoline. | |
893 | * | |
894 | * Returns the function return flags. | |
895 | * | |
896 | */ | |
897 | int | |
898 | ffi_closure_mips_inner_N32 (ffi_closure *closure, | |
899 | void *rvalue, ffi_arg *ar, | |
900 | ffi_arg *fpr) | |
901 | { | |
902 | ffi_cif *cif; | |
903 | void **avaluep; | |
904 | ffi_arg *avalue; | |
905 | ffi_type **arg_types; | |
906 | int i, avn, argn; | |
5cbf8c8d DD |
907 | int soft_float; |
908 | ffi_arg *argp; | |
89d9d98a DD |
909 | |
910 | cif = closure->cif; | |
5cbf8c8d DD |
911 | soft_float = cif->abi == FFI_N64_SOFT_FLOAT |
912 | || cif->abi == FFI_N32_SOFT_FLOAT; | |
89d9d98a DD |
913 | avalue = alloca (cif->nargs * sizeof (ffi_arg)); |
914 | avaluep = alloca (cif->nargs * sizeof (ffi_arg)); | |
915 | ||
916 | argn = 0; | |
917 | ||
918 | if (cif->rstruct_flag) | |
919 | { | |
920 | #if _MIPS_SIM==_ABIN32 | |
921 | rvalue = (void *)(UINT32)ar[0]; | |
922 | #else /* N64 */ | |
923 | rvalue = (void *)ar[0]; | |
924 | #endif | |
925 | argn = 1; | |
926 | } | |
927 | ||
928 | i = 0; | |
929 | avn = cif->nargs; | |
930 | arg_types = cif->arg_types; | |
931 | ||
932 | while (i < avn) | |
933 | { | |
934 | if (arg_types[i]->type == FFI_TYPE_FLOAT | |
c4205f77 FE |
935 | || arg_types[i]->type == FFI_TYPE_DOUBLE |
936 | || arg_types[i]->type == FFI_TYPE_LONGDOUBLE) | |
89d9d98a | 937 | { |
5cbf8c8d | 938 | argp = (argn >= 8 || soft_float) ? ar + argn : fpr + argn; |
c4205f77 FE |
939 | if ((arg_types[i]->type == FFI_TYPE_LONGDOUBLE) && ((unsigned)argp & (arg_types[i]->alignment-1))) |
940 | { | |
941 | argp=(ffi_arg*)ALIGN(argp,arg_types[i]->alignment); | |
942 | argn++; | |
943 | } | |
944 | #if defined(__MIPSEB__) || defined(_MIPSEB) | |
89d9d98a DD |
945 | if (arg_types[i]->type == FFI_TYPE_FLOAT && argn < 8) |
946 | avaluep[i] = ((char *) argp) + sizeof (float); | |
947 | else | |
948 | #endif | |
949 | avaluep[i] = (char *) argp; | |
950 | } | |
951 | else | |
952 | { | |
953 | unsigned type = arg_types[i]->type; | |
954 | ||
955 | if (arg_types[i]->alignment > sizeof(ffi_arg)) | |
956 | argn = ALIGN(argn, arg_types[i]->alignment / sizeof(ffi_arg)); | |
957 | ||
5cbf8c8d | 958 | argp = ar + argn; |
89d9d98a DD |
959 | |
960 | /* The size of a pointer depends on the ABI */ | |
961 | if (type == FFI_TYPE_POINTER) | |
5cbf8c8d DD |
962 | type = (cif->abi == FFI_N64 || cif->abi == FFI_N64_SOFT_FLOAT) |
963 | ? FFI_TYPE_SINT64 : FFI_TYPE_SINT32; | |
964 | ||
965 | if (soft_float && type == FFI_TYPE_FLOAT) | |
966 | type = FFI_TYPE_UINT32; | |
89d9d98a DD |
967 | |
968 | switch (type) | |
969 | { | |
970 | case FFI_TYPE_SINT8: | |
971 | avaluep[i] = &avalue[i]; | |
972 | *(SINT8 *) &avalue[i] = (SINT8) *argp; | |
973 | break; | |
974 | ||
975 | case FFI_TYPE_UINT8: | |
976 | avaluep[i] = &avalue[i]; | |
977 | *(UINT8 *) &avalue[i] = (UINT8) *argp; | |
978 | break; | |
979 | ||
980 | case FFI_TYPE_SINT16: | |
981 | avaluep[i] = &avalue[i]; | |
982 | *(SINT16 *) &avalue[i] = (SINT16) *argp; | |
983 | break; | |
984 | ||
985 | case FFI_TYPE_UINT16: | |
986 | avaluep[i] = &avalue[i]; | |
987 | *(UINT16 *) &avalue[i] = (UINT16) *argp; | |
988 | break; | |
989 | ||
990 | case FFI_TYPE_SINT32: | |
991 | avaluep[i] = &avalue[i]; | |
992 | *(SINT32 *) &avalue[i] = (SINT32) *argp; | |
993 | break; | |
994 | ||
995 | case FFI_TYPE_UINT32: | |
996 | avaluep[i] = &avalue[i]; | |
997 | *(UINT32 *) &avalue[i] = (UINT32) *argp; | |
998 | break; | |
999 | ||
1000 | case FFI_TYPE_STRUCT: | |
1001 | if (argn < 8) | |
1002 | { | |
1003 | /* Allocate space for the struct as at least part of | |
1004 | it was passed in registers. */ | |
1005 | avaluep[i] = alloca(arg_types[i]->size); | |
1006 | copy_struct_N32(avaluep[i], 0, cif->abi, arg_types[i], | |
5cbf8c8d | 1007 | argn, 0, ar, fpr, soft_float); |
89d9d98a DD |
1008 | |
1009 | break; | |
1010 | } | |
1011 | /* Else fall through. */ | |
1012 | default: | |
1013 | avaluep[i] = (char *) argp; | |
1014 | break; | |
1015 | } | |
1016 | } | |
1017 | argn += ALIGN(arg_types[i]->size, sizeof(ffi_arg)) / sizeof(ffi_arg); | |
1018 | i++; | |
1019 | } | |
1020 | ||
1021 | /* Invoke the closure. */ | |
1022 | (closure->fun) (cif, rvalue, avaluep, closure->user_data); | |
1023 | ||
1024 | return cif->flags >> (FFI_FLAG_BITS * 8); | |
1025 | } | |
1026 | ||
1027 | #endif /* FFI_MIPS_N32 */ | |
1028 | ||
b790003a | 1029 | #endif /* FFI_CLOSURES */ |