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