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