1
/* -----------------------------------------------------------------------
2
ffi.c - Copyright (c) 2000 Software AG
4
S390 Foreign Function Interface
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:
14
The above copyright notice and this permission notice shall be included
15
in all copies or substantial portions of the Software.
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 THE AUTHOR 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
/*====================================================================*/
28
/*====================================================================*/
31
#include <ffi_common.h>
36
/*====================== End of Includes =============================*/
38
/*====================================================================*/
41
/*====================================================================*/
43
/* Maximum number of GPRs available for argument passing. */
46
/* Maximum number of FPRs available for argument passing. */
53
/* Round to multiple of 16. */
54
#define ROUND_SIZE(size) (((size) + 15) & ~15)
56
/* If these values change, sysv.S must be adapted! */
57
#define FFI390_RET_VOID 0
58
#define FFI390_RET_STRUCT 1
59
#define FFI390_RET_FLOAT 2
60
#define FFI390_RET_DOUBLE 3
61
#define FFI390_RET_INT32 4
62
#define FFI390_RET_INT64 5
64
/*===================== End of Defines ===============================*/
66
/*====================================================================*/
69
/*====================================================================*/
71
static void ffi_prep_args (unsigned char *, extended_cif *);
73
#if __GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ > 2)
74
__attribute__ ((visibility ("hidden")))
76
ffi_closure_helper_SYSV (ffi_closure *, unsigned long *,
77
unsigned long long *, unsigned long *);
79
/*====================== End of Prototypes ===========================*/
81
/*====================================================================*/
84
/*====================================================================*/
86
extern void ffi_call_SYSV(unsigned,
88
void (*)(unsigned char *, extended_cif *),
93
extern void ffi_closure_SYSV(void);
95
/*====================== End of Externals ============================*/
97
/*====================================================================*/
99
/* Name - ffi_check_struct_type. */
101
/* Function - Determine if a structure can be passed within a */
102
/* general purpose or floating point register. */
104
/*====================================================================*/
107
ffi_check_struct_type (ffi_type *arg)
109
size_t size = arg->size;
111
/* If the struct has just one element, look at that element
112
to find out whether to consider the struct as floating point. */
113
while (arg->type == FFI_TYPE_STRUCT
114
&& arg->elements[0] && !arg->elements[1])
115
arg = arg->elements[0];
117
/* Structs of size 1, 2, 4, and 8 are passed in registers,
118
just like the corresponding int/float types. */
122
return FFI_TYPE_UINT8;
125
return FFI_TYPE_UINT16;
128
if (arg->type == FFI_TYPE_FLOAT)
129
return FFI_TYPE_FLOAT;
131
return FFI_TYPE_UINT32;
134
if (arg->type == FFI_TYPE_DOUBLE)
135
return FFI_TYPE_DOUBLE;
137
return FFI_TYPE_UINT64;
143
/* Other structs are passed via a pointer to the data. */
144
return FFI_TYPE_POINTER;
147
/*======================== End of Routine ============================*/
149
/*====================================================================*/
151
/* Name - ffi_prep_args. */
153
/* Function - Prepare parameters for call to function. */
155
/* ffi_prep_args is called by the assembly routine once stack space */
156
/* has been allocated for the function's arguments. */
158
/*====================================================================*/
161
ffi_prep_args (unsigned char *stack, extended_cif *ecif)
163
/* The stack space will be filled with those areas:
165
FPR argument register save area (highest addresses)
166
GPR argument register save area
167
temporary struct copies
168
overflow argument area (lowest addresses)
170
We set up the following pointers:
172
p_fpr: bottom of the FPR area (growing upwards)
173
p_gpr: bottom of the GPR area (growing upwards)
174
p_ov: bottom of the overflow area (growing upwards)
175
p_struct: top of the struct copy area (growing downwards)
177
All areas are kept aligned to twice the word size. */
179
int gpr_off = ecif->cif->bytes;
180
int fpr_off = gpr_off + ROUND_SIZE (MAX_GPRARGS * sizeof (long));
182
unsigned long long *p_fpr = (unsigned long long *)(stack + fpr_off);
183
unsigned long *p_gpr = (unsigned long *)(stack + gpr_off);
184
unsigned char *p_struct = (unsigned char *)p_gpr;
185
unsigned long *p_ov = (unsigned long *)stack;
192
void **p_argv = ecif->avalue;
195
/* If we returning a structure then we set the first parameter register
196
to the address of where we are returning this structure. */
198
if (ecif->cif->flags == FFI390_RET_STRUCT)
199
p_gpr[n_gpr++] = (unsigned long) ecif->rvalue;
201
/* Now for the arguments. */
203
for (ptr = ecif->cif->arg_types, i = ecif->cif->nargs;
205
i--, ptr++, p_argv++)
208
int type = (*ptr)->type;
210
/* Check how a structure type is passed. */
211
if (type == FFI_TYPE_STRUCT)
213
type = ffi_check_struct_type (*ptr);
215
/* If we pass the struct via pointer, copy the data. */
216
if (type == FFI_TYPE_POINTER)
218
p_struct -= ROUND_SIZE ((*ptr)->size);
219
memcpy (p_struct, (char *)arg, (*ptr)->size);
224
/* Now handle all primitive int/pointer/float data types. */
227
case FFI_TYPE_DOUBLE:
228
if (n_fpr < MAX_FPRARGS)
229
p_fpr[n_fpr++] = *(unsigned long long *) arg;
232
p_ov[n_ov++] = *(unsigned long *) arg;
234
p_ov[n_ov++] = ((unsigned long *) arg)[0],
235
p_ov[n_ov++] = ((unsigned long *) arg)[1];
240
if (n_fpr < MAX_FPRARGS)
241
p_fpr[n_fpr++] = (long long) *(unsigned int *) arg << 32;
243
p_ov[n_ov++] = *(unsigned int *) arg;
246
case FFI_TYPE_POINTER:
247
if (n_gpr < MAX_GPRARGS)
248
p_gpr[n_gpr++] = (unsigned long)*(unsigned char **) arg;
250
p_ov[n_ov++] = (unsigned long)*(unsigned char **) arg;
253
case FFI_TYPE_UINT64:
254
case FFI_TYPE_SINT64:
256
if (n_gpr < MAX_GPRARGS)
257
p_gpr[n_gpr++] = *(unsigned long *) arg;
259
p_ov[n_ov++] = *(unsigned long *) arg;
261
if (n_gpr == MAX_GPRARGS-1)
263
if (n_gpr < MAX_GPRARGS)
264
p_gpr[n_gpr++] = ((unsigned long *) arg)[0],
265
p_gpr[n_gpr++] = ((unsigned long *) arg)[1];
267
p_ov[n_ov++] = ((unsigned long *) arg)[0],
268
p_ov[n_ov++] = ((unsigned long *) arg)[1];
272
case FFI_TYPE_UINT32:
273
if (n_gpr < MAX_GPRARGS)
274
p_gpr[n_gpr++] = *(unsigned int *) arg;
276
p_ov[n_ov++] = *(unsigned int *) arg;
280
case FFI_TYPE_SINT32:
281
if (n_gpr < MAX_GPRARGS)
282
p_gpr[n_gpr++] = *(signed int *) arg;
284
p_ov[n_ov++] = *(signed int *) arg;
287
case FFI_TYPE_UINT16:
288
if (n_gpr < MAX_GPRARGS)
289
p_gpr[n_gpr++] = *(unsigned short *) arg;
291
p_ov[n_ov++] = *(unsigned short *) arg;
294
case FFI_TYPE_SINT16:
295
if (n_gpr < MAX_GPRARGS)
296
p_gpr[n_gpr++] = *(signed short *) arg;
298
p_ov[n_ov++] = *(signed short *) arg;
302
if (n_gpr < MAX_GPRARGS)
303
p_gpr[n_gpr++] = *(unsigned char *) arg;
305
p_ov[n_ov++] = *(unsigned char *) arg;
309
if (n_gpr < MAX_GPRARGS)
310
p_gpr[n_gpr++] = *(signed char *) arg;
312
p_ov[n_ov++] = *(signed char *) arg;
322
/*======================== End of Routine ============================*/
324
/*====================================================================*/
326
/* Name - ffi_prep_cif_machdep. */
328
/* Function - Perform machine dependent CIF processing. */
330
/*====================================================================*/
333
ffi_prep_cif_machdep(ffi_cif *cif)
335
size_t struct_size = 0;
343
/* Determine return value handling. */
345
switch (cif->rtype->type)
349
cif->flags = FFI390_RET_VOID;
352
/* Structures are returned via a hidden pointer. */
353
case FFI_TYPE_STRUCT:
354
cif->flags = FFI390_RET_STRUCT;
355
n_gpr++; /* We need one GPR to pass the pointer. */
358
/* Floating point values are returned in fpr 0. */
360
cif->flags = FFI390_RET_FLOAT;
363
case FFI_TYPE_DOUBLE:
364
cif->flags = FFI390_RET_DOUBLE;
367
/* Integer values are returned in gpr 2 (and gpr 3
368
for 64-bit values on 31-bit machines). */
369
case FFI_TYPE_UINT64:
370
case FFI_TYPE_SINT64:
371
cif->flags = FFI390_RET_INT64;
374
case FFI_TYPE_POINTER:
376
case FFI_TYPE_UINT32:
377
case FFI_TYPE_SINT32:
378
case FFI_TYPE_UINT16:
379
case FFI_TYPE_SINT16:
382
/* These are to be extended to word size. */
384
cif->flags = FFI390_RET_INT64;
386
cif->flags = FFI390_RET_INT32;
395
/* Now for the arguments. */
397
for (ptr = cif->arg_types, i = cif->nargs;
401
int type = (*ptr)->type;
403
/* Check how a structure type is passed. */
404
if (type == FFI_TYPE_STRUCT)
406
type = ffi_check_struct_type (*ptr);
408
/* If we pass the struct via pointer, we must reserve space
409
to copy its data for proper call-by-value semantics. */
410
if (type == FFI_TYPE_POINTER)
411
struct_size += ROUND_SIZE ((*ptr)->size);
414
/* Now handle all primitive int/float data types. */
417
/* The first MAX_FPRARGS floating point arguments
418
go in FPRs, the rest overflow to the stack. */
420
case FFI_TYPE_DOUBLE:
421
if (n_fpr < MAX_FPRARGS)
424
n_ov += sizeof (double) / sizeof (long);
428
if (n_fpr < MAX_FPRARGS)
434
/* On 31-bit machines, 64-bit integers are passed in GPR pairs,
435
if one is still available, or else on the stack. If only one
436
register is free, skip the register (it won't be used for any
437
subsequent argument either). */
440
case FFI_TYPE_UINT64:
441
case FFI_TYPE_SINT64:
442
if (n_gpr == MAX_GPRARGS-1)
444
if (n_gpr < MAX_GPRARGS)
451
/* Everything else is passed in GPRs (until MAX_GPRARGS
452
have been used) or overflows to the stack. */
455
if (n_gpr < MAX_GPRARGS)
463
/* Total stack space as required for overflow arguments
464
and temporary structure copies. */
466
cif->bytes = ROUND_SIZE (n_ov * sizeof (long)) + struct_size;
471
/*======================== End of Routine ============================*/
473
/*====================================================================*/
475
/* Name - ffi_call. */
477
/* Function - Call the FFI routine. */
479
/*====================================================================*/
482
ffi_call(ffi_cif *cif,
487
int ret_type = cif->flags;
491
ecif.avalue = avalue;
492
ecif.rvalue = rvalue;
494
/* If we don't have a return value, we need to fake one. */
497
if (ret_type == FFI390_RET_STRUCT)
498
ecif.rvalue = alloca (cif->rtype->size);
500
ret_type = FFI390_RET_VOID;
506
ffi_call_SYSV (cif->bytes, &ecif, ffi_prep_args,
507
ret_type, ecif.rvalue, fn);
516
/*======================== End of Routine ============================*/
518
/*====================================================================*/
520
/* Name - ffi_closure_helper_SYSV. */
522
/* Function - Call a FFI closure target function. */
524
/*====================================================================*/
527
ffi_closure_helper_SYSV (ffi_closure *closure,
528
unsigned long *p_gpr,
529
unsigned long long *p_fpr,
532
unsigned long long ret_buffer;
534
void *rvalue = &ret_buffer;
545
/* Allocate buffer for argument list pointers. */
547
p_arg = avalue = alloca (closure->cif->nargs * sizeof (void *));
549
/* If we returning a structure, pass the structure address
550
directly to the target function. Otherwise, have the target
551
function store the return value to the GPR save area. */
553
if (closure->cif->flags == FFI390_RET_STRUCT)
554
rvalue = (void *) p_gpr[n_gpr++];
556
/* Now for the arguments. */
558
for (ptr = closure->cif->arg_types, i = closure->cif->nargs;
562
int deref_struct_pointer = 0;
563
int type = (*ptr)->type;
565
/* Check how a structure type is passed. */
566
if (type == FFI_TYPE_STRUCT)
568
type = ffi_check_struct_type (*ptr);
570
/* If we pass the struct via pointer, remember to
571
retrieve the pointer later. */
572
if (type == FFI_TYPE_POINTER)
573
deref_struct_pointer = 1;
576
/* Pointers are passed like UINTs of the same size. */
577
if (type == FFI_TYPE_POINTER)
579
type = FFI_TYPE_UINT64;
581
type = FFI_TYPE_UINT32;
584
/* Now handle all primitive int/float data types. */
587
case FFI_TYPE_DOUBLE:
588
if (n_fpr < MAX_FPRARGS)
589
*p_arg = &p_fpr[n_fpr++];
591
*p_arg = &p_ov[n_ov],
592
n_ov += sizeof (double) / sizeof (long);
596
if (n_fpr < MAX_FPRARGS)
597
*p_arg = &p_fpr[n_fpr++];
599
*p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4;
602
case FFI_TYPE_UINT64:
603
case FFI_TYPE_SINT64:
605
if (n_gpr < MAX_GPRARGS)
606
*p_arg = &p_gpr[n_gpr++];
608
*p_arg = &p_ov[n_ov++];
610
if (n_gpr == MAX_GPRARGS-1)
612
if (n_gpr < MAX_GPRARGS)
613
*p_arg = &p_gpr[n_gpr], n_gpr += 2;
615
*p_arg = &p_ov[n_ov], n_ov += 2;
620
case FFI_TYPE_UINT32:
621
case FFI_TYPE_SINT32:
622
if (n_gpr < MAX_GPRARGS)
623
*p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 4;
625
*p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 4;
628
case FFI_TYPE_UINT16:
629
case FFI_TYPE_SINT16:
630
if (n_gpr < MAX_GPRARGS)
631
*p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 2;
633
*p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 2;
638
if (n_gpr < MAX_GPRARGS)
639
*p_arg = (char *)&p_gpr[n_gpr++] + sizeof (long) - 1;
641
*p_arg = (char *)&p_ov[n_ov++] + sizeof (long) - 1;
649
/* If this is a struct passed via pointer, we need to
650
actually retrieve that pointer. */
651
if (deref_struct_pointer)
652
*p_arg = *(void **)*p_arg;
656
/* Call the target function. */
657
(closure->fun) (closure->cif, rvalue, avalue, closure->user_data);
659
/* Convert the return value. */
660
switch (closure->cif->rtype->type)
662
/* Void is easy, and so is struct. */
664
case FFI_TYPE_STRUCT:
667
/* Floating point values are returned in fpr 0. */
669
p_fpr[0] = (long long) *(unsigned int *) rvalue << 32;
672
case FFI_TYPE_DOUBLE:
673
p_fpr[0] = *(unsigned long long *) rvalue;
676
/* Integer values are returned in gpr 2 (and gpr 3
677
for 64-bit values on 31-bit machines). */
678
case FFI_TYPE_UINT64:
679
case FFI_TYPE_SINT64:
681
p_gpr[0] = *(unsigned long *) rvalue;
683
p_gpr[0] = ((unsigned long *) rvalue)[0],
684
p_gpr[1] = ((unsigned long *) rvalue)[1];
688
case FFI_TYPE_POINTER:
689
case FFI_TYPE_UINT32:
690
case FFI_TYPE_UINT16:
692
p_gpr[0] = *(unsigned long *) rvalue;
696
case FFI_TYPE_SINT32:
697
case FFI_TYPE_SINT16:
699
p_gpr[0] = *(signed long *) rvalue;
708
/*======================== End of Routine ============================*/
710
/*====================================================================*/
712
/* Name - ffi_prep_closure. */
714
/* Function - Prepare a FFI closure. */
716
/*====================================================================*/
719
ffi_prep_closure (ffi_closure *closure,
721
void (*fun) (ffi_cif *, void *, void **, void *),
724
FFI_ASSERT (cif->abi == FFI_SYSV);
727
*(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */
728
*(short *)&closure->tramp [2] = 0x9801; /* lm %r0,%r1,6(%r1) */
729
*(short *)&closure->tramp [4] = 0x1006;
730
*(short *)&closure->tramp [6] = 0x07f1; /* br %r1 */
731
*(long *)&closure->tramp [8] = (long)closure;
732
*(long *)&closure->tramp[12] = (long)&ffi_closure_SYSV;
734
*(short *)&closure->tramp [0] = 0x0d10; /* basr %r1,0 */
735
*(short *)&closure->tramp [2] = 0xeb01; /* lmg %r0,%r1,14(%r1) */
736
*(short *)&closure->tramp [4] = 0x100e;
737
*(short *)&closure->tramp [6] = 0x0004;
738
*(short *)&closure->tramp [8] = 0x07f1; /* br %r1 */
739
*(long *)&closure->tramp[16] = (long)closure;
740
*(long *)&closure->tramp[24] = (long)&ffi_closure_SYSV;
744
closure->user_data = user_data;
750
/*======================== End of Routine ============================*/