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