ffi.c revision 38e2a2afbd627187790f89baa7673c4bbcaf8779
138e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com/* ----------------------------------------------------------------------- 238e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com ffi.c - Copyright (c) 2012 Alexandre K. I. de Mendonca <alexandre.keunecke@gmail.com> 338e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com 438e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com Blackfin Foreign Function Interface 538e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com 638e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com Permission is hereby granted, free of charge, to any person obtaining 738e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com a copy of this software and associated documentation files (the 838e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com ``Software''), to deal in the Software without restriction, including 938e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com without limitation the rights to use, copy, modify, merge, publish, 1038e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com distribute, sublicense, and/or sell copies of the Software, and to 1138e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com permit persons to whom the Software is furnished to do so, subject to 1238e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com the following conditions: 1338e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com 1438e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com The above copyright notice and this permission notice shall be included 1538e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com in all copies or substantial portions of the Software. 1638e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com 1738e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, 1838e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 1938e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 2038e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 2138e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 2238e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 2338e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 2438e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com DEALINGS IN THE SOFTWARE. 2538e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com ----------------------------------------------------------------------- */ 2638e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com#include <ffi.h> 2738e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com#include <ffi_common.h> 2838e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com 2938e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com#include <stdlib.h> 3038e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com#include <stdio.h> 3138e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com 3238e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com/* Maximum number of GPRs available for argument passing. */ 3338e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com#define MAX_GPRARGS 3 3438e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com 3538e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com/* 3638e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com * Return types 3738e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com */ 3838e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com#define FFIBFIN_RET_VOID 0 3938e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com#define FFIBFIN_RET_BYTE 1 4038e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com#define FFIBFIN_RET_HALFWORD 2 4138e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com#define FFIBFIN_RET_INT64 3 4238e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com#define FFIBFIN_RET_INT32 4 4338e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com 4438e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com/*====================================================================*/ 4538e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com/* PROTOTYPE * 4638e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com /*====================================================================*/ 4738e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.comvoid ffi_prep_args(unsigned char *, extended_cif *); 4838e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com 4938e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com/*====================================================================*/ 5038e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com/* Externals */ 5138e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com/* (Assembly) */ 5238e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com/*====================================================================*/ 5338e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com 5438e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.comextern void ffi_call_SYSV(unsigned, extended_cif *, void(*)(unsigned char *, extended_cif *), unsigned, void *, void(*fn)(void)); 5538e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com 5638e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com/*====================================================================*/ 5738e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com/* Implementation */ 5838e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com/* */ 5938e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com/*====================================================================*/ 6038e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com 6138e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com 6238e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com/* 6338e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com * This function calculates the return type (size) based on type. 6438e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com */ 6538e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com 6638e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.comffi_status ffi_prep_cif_machdep(ffi_cif *cif) 6738e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com{ 6838e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com /* --------------------------------------* 6938e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com * Return handling * 7038e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com * --------------------------------------*/ 7138e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com switch (cif->rtype->type) { 7238e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com case FFI_TYPE_VOID: 7338e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com cif->flags = FFIBFIN_RET_VOID; 7438e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com break; 7538e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com case FFI_TYPE_UINT16: 7638e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com case FFI_TYPE_SINT16: 7738e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com cif->flags = FFIBFIN_RET_HALFWORD; 7838e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com break; 7938e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com case FFI_TYPE_UINT8: 8038e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com cif->flags = FFIBFIN_RET_BYTE; 8138e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com break; 8238e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com case FFI_TYPE_INT: 8338e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com case FFI_TYPE_UINT32: 8438e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com case FFI_TYPE_SINT32: 8538e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com case FFI_TYPE_FLOAT: 8638e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com case FFI_TYPE_POINTER: 8738e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com case FFI_TYPE_SINT8: 8838e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com cif->flags = FFIBFIN_RET_INT32; 8938e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com break; 9038e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com case FFI_TYPE_SINT64: 9138e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com case FFI_TYPE_UINT64: 9238e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com case FFI_TYPE_DOUBLE: 9338e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com cif->flags = FFIBFIN_RET_INT64; 9438e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com break; 9538e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com case FFI_TYPE_STRUCT: 9638e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com if (cif->rtype->size <= 4){ 9738e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com cif->flags = FFIBFIN_RET_INT32; 9838e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com }else if (cif->rtype->size == 8){ 9938e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com cif->flags = FFIBFIN_RET_INT64; 10038e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com }else{ 10138e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com //it will return via a hidden pointer in P0 10238e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com cif->flags = FFIBFIN_RET_VOID; 10338e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com } 10438e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com break; 10538e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com default: 10638e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com FFI_ASSERT(0); 10738e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com break; 10838e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com } 10938e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com return FFI_OK; 11038e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com} 11138e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com 11238e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com/* 11338e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com * This will prepare the arguments and will call the assembly routine 11438e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com * cif = the call interface 11538e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com * fn = the function to be called 11638e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com * rvalue = the return value 11738e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com * avalue = the arguments 11838e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com */ 11938e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.comvoid ffi_call(ffi_cif *cif, void(*fn)(void), void *rvalue, void **avalue) 12038e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com{ 12138e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com int ret_type = cif->flags; 12238e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com extended_cif ecif; 12338e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com ecif.cif = cif; 12438e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com ecif.avalue = avalue; 12538e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com ecif.rvalue = rvalue; 12638e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com 12738e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com switch (cif->abi) { 12838e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com case FFI_SYSV: 12938e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com ffi_call_SYSV(cif->bytes, &ecif, ffi_prep_args, ret_type, ecif.rvalue, fn); 13038e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com break; 13138e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com default: 13238e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com FFI_ASSERT(0); 13338e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com break; 13438e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com } 13538e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com} 13638e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com 13738e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com 13838e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com/* 13938e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com* This function prepares the parameters (copies them from the ecif to the stack) 14038e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com* to call the function (ffi_prep_args is called by the assembly routine in file 14138e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com* sysv.S, which also calls the actual function) 14238e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com*/ 14338e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.comvoid ffi_prep_args(unsigned char *stack, extended_cif *ecif) 14438e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com{ 14538e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com register unsigned int i = 0; 14638e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com void **p_argv; 14738e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com unsigned char *argp; 14838e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com ffi_type **p_arg; 14938e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com argp = stack; 15038e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com p_argv = ecif->avalue; 15138e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; 15238e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com (i != 0); 15338e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com i--, p_arg++) { 15438e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com size_t z; 15538e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com z = (*p_arg)->size; 15638e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com if (z < sizeof(int)) { 15738e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com z = sizeof(int); 15838e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com switch ((*p_arg)->type) { 15938e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com case FFI_TYPE_SINT8: { 16038e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com signed char v = *(SINT8 *)(* p_argv); 16138e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com signed int t = v; 16238e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com *(signed int *) argp = t; 16338e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com } 16438e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com break; 16538e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com case FFI_TYPE_UINT8: { 16638e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com unsigned char v = *(UINT8 *)(* p_argv); 16738e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com unsigned int t = v; 16838e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com *(unsigned int *) argp = t; 16938e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com } 17038e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com break; 17138e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com case FFI_TYPE_SINT16: 17238e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com *(signed int *) argp = (signed int) * (SINT16 *)(* p_argv); 17338e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com break; 17438e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com case FFI_TYPE_UINT16: 17538e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com *(unsigned int *) argp = (unsigned int) * (UINT16 *)(* p_argv); 17638e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com break; 17738e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com case FFI_TYPE_STRUCT: 17838e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com memcpy(argp, *p_argv, (*p_arg)->size); 17938e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com break; 18038e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com default: 18138e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com FFI_ASSERT(0); 18238e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com break; 18338e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com } 18438e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com } else if (z == sizeof(int)) { 18538e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com *(unsigned int *) argp = (unsigned int) * (UINT32 *)(* p_argv); 18638e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com } else { 18738e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com memcpy(argp, *p_argv, z); 18838e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com } 18938e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com p_argv++; 19038e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com argp += z; 19138e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com } 19238e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com} 19338e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com 19438e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com 19538e2a2afbd627187790f89baa7673c4bbcaf8779doko@ubuntu.com 196