diff options
Diffstat (limited to 'libffi/src/m68k/ffi.c')
-rw-r--r-- | libffi/src/m68k/ffi.c | 214 |
1 files changed, 158 insertions, 56 deletions
diff --git a/libffi/src/m68k/ffi.c b/libffi/src/m68k/ffi.c index 55f3a988bc4..600cf20527f 100644 --- a/libffi/src/m68k/ffi.c +++ b/libffi/src/m68k/ffi.c @@ -8,11 +8,23 @@ #include <ffi_common.h> #include <stdlib.h> +#include <unistd.h> +#include <sys/syscall.h> +#include <asm/cachectl.h> + +void ffi_call_SYSV (extended_cif *, + unsigned, unsigned, + void *, void (*fn) ()); +void *ffi_prep_args (void *stack, extended_cif *ecif); +void ffi_closure_SYSV (ffi_closure *); +void ffi_closure_struct_SYSV (ffi_closure *); +unsigned int ffi_closure_SYSV_inner (ffi_closure *closure, + void *resp, void *args); /* ffi_prep_args is called by the assembly routine once stack space has been allocated for the function's arguments. */ -static void * +void * ffi_prep_args (void *stack, extended_cif *ecif) { unsigned int i; @@ -24,7 +36,7 @@ ffi_prep_args (void *stack, extended_cif *ecif) argp = stack; if (ecif->cif->rtype->type == FFI_TYPE_STRUCT - && ecif->cif->rtype->size > 8) + && !ecif->cif->flags) struct_value_ptr = ecif->rvalue; else struct_value_ptr = NULL; @@ -37,44 +49,47 @@ ffi_prep_args (void *stack, extended_cif *ecif) { size_t z; - /* Align if necessary. */ - if (((*p_arg)->alignment - 1) & (unsigned) argp) - argp = (char *) ALIGN (argp, (*p_arg)->alignment); - - z = (*p_arg)->size; - if (z < sizeof (int)) + z = (*p_arg)->size; + if (z < sizeof (int)) + { + switch ((*p_arg)->type) { - switch ((*p_arg)->type) - { - case FFI_TYPE_SINT8: - *(signed int *) argp = (signed int) *(SINT8 *) *p_argv; - break; - - case FFI_TYPE_UINT8: - *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv; - break; - - case FFI_TYPE_SINT16: - *(signed int *) argp = (signed int) *(SINT16 *) *p_argv; - break; - - case FFI_TYPE_UINT16: - *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv; - break; - - case FFI_TYPE_STRUCT: - memcpy (argp + sizeof (int) - z, *p_argv, z); - break; - - default: - FFI_ASSERT (0); - } - z = sizeof (int); + case FFI_TYPE_SINT8: + *(signed int *) argp = (signed int) *(SINT8 *) *p_argv; + break; + + case FFI_TYPE_UINT8: + *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv; + break; + + case FFI_TYPE_SINT16: + *(signed int *) argp = (signed int) *(SINT16 *) *p_argv; + break; + + case FFI_TYPE_UINT16: + *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv; + break; + + case FFI_TYPE_STRUCT: + memcpy (argp + sizeof (int) - z, *p_argv, z); + break; + + default: + FFI_ASSERT (0); } - else - memcpy (argp, *p_argv, z); - p_argv++; - argp += z; + z = sizeof (int); + } + else + { + memcpy (argp, *p_argv, z); + + /* Align if necessary. */ + if ((sizeof(int) - 1) & z) + z = ALIGN(z, sizeof(int)); + } + + p_argv++; + argp += z; } return struct_value_ptr; @@ -86,7 +101,8 @@ ffi_prep_args (void *stack, extended_cif *ecif) #define CIF_FLAGS_DOUBLE 8 #define CIF_FLAGS_LDOUBLE 16 #define CIF_FLAGS_POINTER 32 -#define CIF_FLAGS_STRUCT 64 +#define CIF_FLAGS_STRUCT1 64 +#define CIF_FLAGS_STRUCT2 128 /* Perform machine dependent cif processing */ ffi_status @@ -100,12 +116,24 @@ ffi_prep_cif_machdep (ffi_cif *cif) break; case FFI_TYPE_STRUCT: - if (cif->rtype->size > 4 && cif->rtype->size <= 8) - cif->flags = CIF_FLAGS_DINT; - else if (cif->rtype->size <= 4) - cif->flags = CIF_FLAGS_STRUCT; - else - cif->flags = 0; + switch (cif->rtype->size) + { + case 1: + cif->flags = CIF_FLAGS_STRUCT1; + break; + case 2: + cif->flags = CIF_FLAGS_STRUCT2; + break; + case 4: + cif->flags = CIF_FLAGS_INT; + break; + case 8: + cif->flags = CIF_FLAGS_DINT; + break; + default: + cif->flags = 0; + break; + } break; case FFI_TYPE_FLOAT: @@ -137,11 +165,6 @@ ffi_prep_cif_machdep (ffi_cif *cif) return FFI_OK; } -extern void ffi_call_SYSV (void *(*) (void *, extended_cif *), - extended_cif *, - unsigned, unsigned, unsigned, - void *, void (*fn) ()); - void ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue) { @@ -149,7 +172,7 @@ ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue) ecif.cif = cif; ecif.avalue = avalue; - + /* If the return value is a struct and we don't have a return value address then we need to make one. */ @@ -159,13 +182,11 @@ ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue) ecif.rvalue = alloca (cif->rtype->size); else ecif.rvalue = rvalue; - - - switch (cif->abi) + + switch (cif->abi) { case FFI_SYSV: - ffi_call_SYSV (ffi_prep_args, &ecif, cif->bytes, - cif->flags, cif->rtype->size * 8, + ffi_call_SYSV (&ecif, cif->bytes, cif->flags, ecif.rvalue, fn); break; @@ -174,3 +195,84 @@ ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue) break; } } + +static void +ffi_prep_incoming_args_SYSV (char *stack, void **avalue, ffi_cif *cif) +{ + unsigned int i; + void **p_argv; + char *argp; + ffi_type **p_arg; + + argp = stack; + p_argv = avalue; + + for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++) + { + size_t z; + + z = (*p_arg)->size; + if (z <= 4) + { + *p_argv = (void *) (argp + 4 - z); + + z = 4; + } + else + { + *p_argv = (void *) argp; + + /* Align if necessary */ + if ((sizeof(int) - 1) & z) + z = ALIGN(z, sizeof(int)); + } + + p_argv++; + argp += z; + } +} + +unsigned int +ffi_closure_SYSV_inner (ffi_closure *closure, void *resp, void *args) +{ + ffi_cif *cif; + void **arg_area; + + cif = closure->cif; + arg_area = (void**) alloca (cif->nargs * sizeof (void *)); + + ffi_prep_incoming_args_SYSV(args, arg_area, cif); + + (closure->fun) (cif, resp, arg_area, closure->user_data); + + return cif->flags; +} + +ffi_status +ffi_prep_closure_loc (ffi_closure* closure, + ffi_cif* cif, + void (*fun)(ffi_cif*,void*,void**,void*), + void *user_data, + void *codeloc) +{ + FFI_ASSERT (cif->abi == FFI_SYSV); + + *(unsigned short *)closure->tramp = 0x207c; + *(void **)(closure->tramp + 2) = codeloc; + *(unsigned short *)(closure->tramp + 6) = 0x4ef9; + if (cif->rtype->type == FFI_TYPE_STRUCT + && !cif->flags) + *(void **)(closure->tramp + 8) = ffi_closure_struct_SYSV; + else + *(void **)(closure->tramp + 8) = ffi_closure_SYSV; + + syscall(SYS_cacheflush, codeloc, FLUSH_SCOPE_LINE, + FLUSH_CACHE_BOTH, FFI_TRAMPOLINE_SIZE); + + closure->cif = cif; + closure->user_data = user_data; + closure->fun = fun; + + return FFI_OK; +} + |