1457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/* -----------------------------------------------------------------------
2457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   ffi.c - Copyright (c) 2012  Alexandre K. I. de Mendonca <alexandre.keunecke@gmail.com>,
3457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique							   Paulo Pizarro <paulo.pizarro@gmail.com>
4457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
5457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   Blackfin Foreign Function Interface
6457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
7457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   Permission is hereby granted, free of charge, to any person obtaining
8457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   a copy of this software and associated documentation files (the
9457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   ``Software''), to deal in the Software without restriction, including
10457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   without limitation the rights to use, copy, modify, merge, publish,
11457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   distribute, sublicense, and/or sell copies of the Software, and to
12457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   permit persons to whom the Software is furnished to do so, subject to
13457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   the following conditions:
14457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
15457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   The above copyright notice and this permission notice shall be included
16457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   in all copies or substantial portions of the Software.
17457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
18457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
19457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   DEALINGS IN THE SOFTWARE.
26457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   ----------------------------------------------------------------------- */
27457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#include <ffi.h>
28457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#include <ffi_common.h>
29457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
30457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#include <stdlib.h>
31457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#include <stdio.h>
32457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
33457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/* Maximum number of GPRs available for argument passing.  */
34457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#define MAX_GPRARGS 3
35457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
36457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/*
37457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique * Return types
38457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique */
39457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#define FFIBFIN_RET_VOID 0
40457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#define FFIBFIN_RET_BYTE 1
41457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#define FFIBFIN_RET_HALFWORD 2
42457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#define FFIBFIN_RET_INT64 3
43457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#define FFIBFIN_RET_INT32 4
44457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
45457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/*====================================================================*/
46457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/*                          PROTOTYPE          *
47457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique /*====================================================================*/
48457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piquevoid ffi_prep_args(unsigned char *, extended_cif *);
49457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
50457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/*====================================================================*/
51457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/*                          Externals                                 */
52457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/*                          (Assembly)                                */
53457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/*====================================================================*/
54457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
55457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piqueextern void ffi_call_SYSV(unsigned, extended_cif *, void(*)(unsigned char *, extended_cif *), unsigned, void *, void(*fn)(void));
56457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
57457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/*====================================================================*/
58457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/*                          Implementation                            */
59457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/*                                                            */
60457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/*====================================================================*/
61457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
62457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
63457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/*
64457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique * This function calculates the return type (size) based on type.
65457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique */
66457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
67457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piqueffi_status ffi_prep_cif_machdep(ffi_cif *cif)
68457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique{
69457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   /* --------------------------------------*
70457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    *   Return handling                *
71457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    * --------------------------------------*/
72457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   switch (cif->rtype->type) {
73457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_VOID:
74457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         cif->flags = FFIBFIN_RET_VOID;
75457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         break;
76457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_UINT16:
77457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_SINT16:
78457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         cif->flags = FFIBFIN_RET_HALFWORD;
79457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         break;
80457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_UINT8:
81457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         cif->flags = FFIBFIN_RET_BYTE;
82457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         break;
83457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_INT:
84457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_UINT32:
85457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_SINT32:
86457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_FLOAT:
87457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_POINTER:
88457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_SINT8:
89457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         cif->flags = FFIBFIN_RET_INT32;
90457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         break;
91457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_SINT64:
92457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_UINT64:
93457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_DOUBLE:
94457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique          cif->flags = FFIBFIN_RET_INT64;
95457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique          break;
96457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_STRUCT:
97457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         if (cif->rtype->size <= 4){
98457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        	 cif->flags = FFIBFIN_RET_INT32;
99457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         }else if (cif->rtype->size == 8){
100457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        	 cif->flags = FFIBFIN_RET_INT64;
101457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         }else{
102457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        	 //it will return via a hidden pointer in P0
103457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        	 cif->flags = FFIBFIN_RET_VOID;
104457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         }
105457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         break;
106457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      default:
107457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         FFI_ASSERT(0);
108457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         break;
109457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   }
110457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   return FFI_OK;
111457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique}
112457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
113457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/*
114457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique * This will prepare the arguments and will call the assembly routine
115457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique * cif = the call interface
116457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique * fn = the function to be called
117457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique * rvalue = the return value
118457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique * avalue = the arguments
119457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique */
120457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piquevoid ffi_call(ffi_cif *cif, void(*fn)(void), void *rvalue, void **avalue)
121457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique{
122457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   int ret_type = cif->flags;
123457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   extended_cif ecif;
124457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   ecif.cif = cif;
125457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   ecif.avalue = avalue;
126457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   ecif.rvalue = rvalue;
127457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
128457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   switch (cif->abi) {
129457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_SYSV:
130457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         ffi_call_SYSV(cif->bytes, &ecif, ffi_prep_args, ret_type, ecif.rvalue, fn);
131457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         break;
132457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      default:
133457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         FFI_ASSERT(0);
134457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         break;
135457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   }
136457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique}
137457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
138457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
139457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/*
140457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique* This function prepares the parameters (copies them from the ecif to the stack)
141457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique*  to call the function (ffi_prep_args is called by the assembly routine in file
142457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique*  sysv.S, which also calls the actual function)
143457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique*/
144457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piquevoid ffi_prep_args(unsigned char *stack, extended_cif *ecif)
145457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique{
146457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   register unsigned int i = 0;
147457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   void **p_argv;
148457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   unsigned char *argp;
149457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   ffi_type **p_arg;
150457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   argp = stack;
151457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   p_argv = ecif->avalue;
152457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
153457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        (i != 0);
154457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        i--, p_arg++) {
155457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      size_t z;
156457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      z = (*p_arg)->size;
157457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      if (z < sizeof(int)) {
158457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         z = sizeof(int);
159457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         switch ((*p_arg)->type) {
160457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique            case FFI_TYPE_SINT8: {
161457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique                  signed char v = *(SINT8 *)(* p_argv);
162457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique                  signed int t = v;
163457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique                  *(signed int *) argp = t;
164457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique               }
165457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique               break;
166457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique            case FFI_TYPE_UINT8: {
167457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique                  unsigned char v = *(UINT8 *)(* p_argv);
168457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique                  unsigned int t = v;
169457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique                  *(unsigned int *) argp = t;
170457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique               }
171457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique               break;
172457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique            case FFI_TYPE_SINT16:
173457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique               *(signed int *) argp = (signed int) * (SINT16 *)(* p_argv);
174457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique               break;
175457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique            case FFI_TYPE_UINT16:
176457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique               *(unsigned int *) argp = (unsigned int) * (UINT16 *)(* p_argv);
177457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique               break;
178457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique            case FFI_TYPE_STRUCT:
179457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique               memcpy(argp, *p_argv, (*p_arg)->size);
180457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique               break;
181457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique            default:
182457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique               FFI_ASSERT(0);
183457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique               break;
184457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         }
185457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      } else if (z == sizeof(int)) {
186457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         *(unsigned int *) argp = (unsigned int) * (UINT32 *)(* p_argv);
187457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      } else {
188457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         memcpy(argp, *p_argv, z);
189457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      }
190457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      p_argv++;
191457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      argp += z;
192457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   }
193457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique}
194457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
195457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
196457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
197