xref: /aosp_15_r20/external/libffi/src/arc/ffi.c (revision 1fd5a2e1d639cd1ddf29dd0c484c123bbd850c21)
1*1fd5a2e1SPrashanth Swaminathan /* -----------------------------------------------------------------------
2*1fd5a2e1SPrashanth Swaminathan    ffi.c - Copyright (c) 2013  Synopsys, Inc. (www.synopsys.com)
3*1fd5a2e1SPrashanth Swaminathan 
4*1fd5a2e1SPrashanth Swaminathan    ARC Foreign Function Interface
5*1fd5a2e1SPrashanth Swaminathan 
6*1fd5a2e1SPrashanth Swaminathan    Permission is hereby granted, free of charge, to any person obtaining
7*1fd5a2e1SPrashanth Swaminathan    a copy of this software and associated documentation files (the
8*1fd5a2e1SPrashanth Swaminathan    ``Software''), to deal in the Software without restriction, including
9*1fd5a2e1SPrashanth Swaminathan    without limitation the rights to use, copy, modify, merge, publish,
10*1fd5a2e1SPrashanth Swaminathan    distribute, sublicense, and/or sell copies of the Software, and to
11*1fd5a2e1SPrashanth Swaminathan    permit persons to whom the Software is furnished to do so, subject to
12*1fd5a2e1SPrashanth Swaminathan    the following conditions:
13*1fd5a2e1SPrashanth Swaminathan 
14*1fd5a2e1SPrashanth Swaminathan    The above copyright notice and this permission notice shall be included
15*1fd5a2e1SPrashanth Swaminathan    in all copies or substantial portions of the Software.
16*1fd5a2e1SPrashanth Swaminathan 
17*1fd5a2e1SPrashanth Swaminathan    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
18*1fd5a2e1SPrashanth Swaminathan    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19*1fd5a2e1SPrashanth Swaminathan    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
20*1fd5a2e1SPrashanth Swaminathan    IN NO EVENT SHALL RENESAS TECHNOLOGY BE LIABLE FOR ANY CLAIM, DAMAGES OR
21*1fd5a2e1SPrashanth Swaminathan    OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
22*1fd5a2e1SPrashanth Swaminathan    ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23*1fd5a2e1SPrashanth Swaminathan    OTHER DEALINGS IN THE SOFTWARE.
24*1fd5a2e1SPrashanth Swaminathan    ----------------------------------------------------------------------- */
25*1fd5a2e1SPrashanth Swaminathan 
26*1fd5a2e1SPrashanth Swaminathan #include <ffi.h>
27*1fd5a2e1SPrashanth Swaminathan #include <ffi_common.h>
28*1fd5a2e1SPrashanth Swaminathan 
29*1fd5a2e1SPrashanth Swaminathan #include <stdlib.h>
30*1fd5a2e1SPrashanth Swaminathan #include <stdint.h>
31*1fd5a2e1SPrashanth Swaminathan 
32*1fd5a2e1SPrashanth Swaminathan #include <sys/cachectl.h>
33*1fd5a2e1SPrashanth Swaminathan 
34*1fd5a2e1SPrashanth Swaminathan /* for little endian ARC, the code is in fact stored as mixed endian for
35*1fd5a2e1SPrashanth Swaminathan    performance reasons */
36*1fd5a2e1SPrashanth Swaminathan #if __BIG_ENDIAN__
37*1fd5a2e1SPrashanth Swaminathan #define CODE_ENDIAN(x) (x)
38*1fd5a2e1SPrashanth Swaminathan #else
39*1fd5a2e1SPrashanth Swaminathan #define CODE_ENDIAN(x) ( (((uint32_t) (x)) << 16) | (((uint32_t) (x)) >> 16))
40*1fd5a2e1SPrashanth Swaminathan #endif
41*1fd5a2e1SPrashanth Swaminathan 
42*1fd5a2e1SPrashanth Swaminathan /* ffi_prep_args is called by the assembly routine once stack
43*1fd5a2e1SPrashanth Swaminathan    space has been allocated for the function's arguments.  */
44*1fd5a2e1SPrashanth Swaminathan 
45*1fd5a2e1SPrashanth Swaminathan void
ffi_prep_args(char * stack,extended_cif * ecif)46*1fd5a2e1SPrashanth Swaminathan ffi_prep_args (char *stack, extended_cif * ecif)
47*1fd5a2e1SPrashanth Swaminathan {
48*1fd5a2e1SPrashanth Swaminathan   unsigned int i;
49*1fd5a2e1SPrashanth Swaminathan   void **p_argv;
50*1fd5a2e1SPrashanth Swaminathan   char *argp;
51*1fd5a2e1SPrashanth Swaminathan   ffi_type **p_arg;
52*1fd5a2e1SPrashanth Swaminathan 
53*1fd5a2e1SPrashanth Swaminathan   argp = stack;
54*1fd5a2e1SPrashanth Swaminathan 
55*1fd5a2e1SPrashanth Swaminathan   if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
56*1fd5a2e1SPrashanth Swaminathan     {
57*1fd5a2e1SPrashanth Swaminathan       *(void **) argp = ecif->rvalue;
58*1fd5a2e1SPrashanth Swaminathan       argp += 4;
59*1fd5a2e1SPrashanth Swaminathan     }
60*1fd5a2e1SPrashanth Swaminathan 
61*1fd5a2e1SPrashanth Swaminathan   p_argv = ecif->avalue;
62*1fd5a2e1SPrashanth Swaminathan 
63*1fd5a2e1SPrashanth Swaminathan   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
64*1fd5a2e1SPrashanth Swaminathan        (i != 0); i--, p_arg++)
65*1fd5a2e1SPrashanth Swaminathan     {
66*1fd5a2e1SPrashanth Swaminathan       size_t z;
67*1fd5a2e1SPrashanth Swaminathan       int alignment;
68*1fd5a2e1SPrashanth Swaminathan 
69*1fd5a2e1SPrashanth Swaminathan       /* align alignment to 4 */
70*1fd5a2e1SPrashanth Swaminathan       alignment = (((*p_arg)->alignment - 1) | 3) + 1;
71*1fd5a2e1SPrashanth Swaminathan 
72*1fd5a2e1SPrashanth Swaminathan       /* Align if necessary.  */
73*1fd5a2e1SPrashanth Swaminathan       if ((alignment - 1) & (unsigned) argp)
74*1fd5a2e1SPrashanth Swaminathan 	argp = (char *) FFI_ALIGN (argp, alignment);
75*1fd5a2e1SPrashanth Swaminathan 
76*1fd5a2e1SPrashanth Swaminathan       z = (*p_arg)->size;
77*1fd5a2e1SPrashanth Swaminathan       if (z < sizeof (int))
78*1fd5a2e1SPrashanth Swaminathan 	{
79*1fd5a2e1SPrashanth Swaminathan 	  z = sizeof (int);
80*1fd5a2e1SPrashanth Swaminathan 
81*1fd5a2e1SPrashanth Swaminathan 	  switch ((*p_arg)->type)
82*1fd5a2e1SPrashanth Swaminathan 	    {
83*1fd5a2e1SPrashanth Swaminathan 	    case FFI_TYPE_SINT8:
84*1fd5a2e1SPrashanth Swaminathan 	      *(signed int *) argp = (signed int) *(SINT8 *) (*p_argv);
85*1fd5a2e1SPrashanth Swaminathan 	      break;
86*1fd5a2e1SPrashanth Swaminathan 
87*1fd5a2e1SPrashanth Swaminathan 	    case FFI_TYPE_UINT8:
88*1fd5a2e1SPrashanth Swaminathan 	      *(unsigned int *) argp = (unsigned int) *(UINT8 *) (*p_argv);
89*1fd5a2e1SPrashanth Swaminathan 	      break;
90*1fd5a2e1SPrashanth Swaminathan 
91*1fd5a2e1SPrashanth Swaminathan 	    case FFI_TYPE_SINT16:
92*1fd5a2e1SPrashanth Swaminathan 	      *(signed int *) argp = (signed int) *(SINT16 *) (*p_argv);
93*1fd5a2e1SPrashanth Swaminathan 	      break;
94*1fd5a2e1SPrashanth Swaminathan 
95*1fd5a2e1SPrashanth Swaminathan 	    case FFI_TYPE_UINT16:
96*1fd5a2e1SPrashanth Swaminathan 	      *(unsigned int *) argp = (unsigned int) *(UINT16 *) (*p_argv);
97*1fd5a2e1SPrashanth Swaminathan 	      break;
98*1fd5a2e1SPrashanth Swaminathan 
99*1fd5a2e1SPrashanth Swaminathan 	    case FFI_TYPE_STRUCT:
100*1fd5a2e1SPrashanth Swaminathan 	      memcpy (argp, *p_argv, (*p_arg)->size);
101*1fd5a2e1SPrashanth Swaminathan 	      break;
102*1fd5a2e1SPrashanth Swaminathan 
103*1fd5a2e1SPrashanth Swaminathan 	    default:
104*1fd5a2e1SPrashanth Swaminathan 	      FFI_ASSERT (0);
105*1fd5a2e1SPrashanth Swaminathan 	    }
106*1fd5a2e1SPrashanth Swaminathan 	}
107*1fd5a2e1SPrashanth Swaminathan       else if (z == sizeof (int))
108*1fd5a2e1SPrashanth Swaminathan 	{
109*1fd5a2e1SPrashanth Swaminathan 	  *(unsigned int *) argp = (unsigned int) *(UINT32 *) (*p_argv);
110*1fd5a2e1SPrashanth Swaminathan 	}
111*1fd5a2e1SPrashanth Swaminathan       else
112*1fd5a2e1SPrashanth Swaminathan 	{
113*1fd5a2e1SPrashanth Swaminathan 	  if ((*p_arg)->type == FFI_TYPE_STRUCT)
114*1fd5a2e1SPrashanth Swaminathan 	    {
115*1fd5a2e1SPrashanth Swaminathan 	      memcpy (argp, *p_argv, z);
116*1fd5a2e1SPrashanth Swaminathan 	    }
117*1fd5a2e1SPrashanth Swaminathan 	  else
118*1fd5a2e1SPrashanth Swaminathan 	    {
119*1fd5a2e1SPrashanth Swaminathan 	      /* Double or long long 64bit.  */
120*1fd5a2e1SPrashanth Swaminathan 	      memcpy (argp, *p_argv, z);
121*1fd5a2e1SPrashanth Swaminathan 	    }
122*1fd5a2e1SPrashanth Swaminathan 	}
123*1fd5a2e1SPrashanth Swaminathan       p_argv++;
124*1fd5a2e1SPrashanth Swaminathan       argp += z;
125*1fd5a2e1SPrashanth Swaminathan     }
126*1fd5a2e1SPrashanth Swaminathan 
127*1fd5a2e1SPrashanth Swaminathan   return;
128*1fd5a2e1SPrashanth Swaminathan }
129*1fd5a2e1SPrashanth Swaminathan 
130*1fd5a2e1SPrashanth Swaminathan /* Perform machine dependent cif processing.  */
131*1fd5a2e1SPrashanth Swaminathan ffi_status
ffi_prep_cif_machdep(ffi_cif * cif)132*1fd5a2e1SPrashanth Swaminathan ffi_prep_cif_machdep (ffi_cif * cif)
133*1fd5a2e1SPrashanth Swaminathan {
134*1fd5a2e1SPrashanth Swaminathan   /* Set the return type flag.  */
135*1fd5a2e1SPrashanth Swaminathan   switch (cif->rtype->type)
136*1fd5a2e1SPrashanth Swaminathan     {
137*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_VOID:
138*1fd5a2e1SPrashanth Swaminathan       cif->flags = (unsigned) cif->rtype->type;
139*1fd5a2e1SPrashanth Swaminathan       break;
140*1fd5a2e1SPrashanth Swaminathan 
141*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_STRUCT:
142*1fd5a2e1SPrashanth Swaminathan       cif->flags = (unsigned) cif->rtype->type;
143*1fd5a2e1SPrashanth Swaminathan       break;
144*1fd5a2e1SPrashanth Swaminathan 
145*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_SINT64:
146*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_UINT64:
147*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_DOUBLE:
148*1fd5a2e1SPrashanth Swaminathan       cif->flags = FFI_TYPE_DOUBLE;
149*1fd5a2e1SPrashanth Swaminathan       break;
150*1fd5a2e1SPrashanth Swaminathan 
151*1fd5a2e1SPrashanth Swaminathan     case FFI_TYPE_FLOAT:
152*1fd5a2e1SPrashanth Swaminathan     default:
153*1fd5a2e1SPrashanth Swaminathan       cif->flags = FFI_TYPE_INT;
154*1fd5a2e1SPrashanth Swaminathan       break;
155*1fd5a2e1SPrashanth Swaminathan     }
156*1fd5a2e1SPrashanth Swaminathan 
157*1fd5a2e1SPrashanth Swaminathan   return FFI_OK;
158*1fd5a2e1SPrashanth Swaminathan }
159*1fd5a2e1SPrashanth Swaminathan 
160*1fd5a2e1SPrashanth Swaminathan extern void ffi_call_ARCompact (void (*)(char *, extended_cif *),
161*1fd5a2e1SPrashanth Swaminathan 				extended_cif *, unsigned, unsigned,
162*1fd5a2e1SPrashanth Swaminathan 				unsigned *, void (*fn) (void));
163*1fd5a2e1SPrashanth Swaminathan 
164*1fd5a2e1SPrashanth Swaminathan void
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)165*1fd5a2e1SPrashanth Swaminathan ffi_call (ffi_cif * cif, void (*fn) (void), void *rvalue, void **avalue)
166*1fd5a2e1SPrashanth Swaminathan {
167*1fd5a2e1SPrashanth Swaminathan   extended_cif ecif;
168*1fd5a2e1SPrashanth Swaminathan 
169*1fd5a2e1SPrashanth Swaminathan   ecif.cif = cif;
170*1fd5a2e1SPrashanth Swaminathan   ecif.avalue = avalue;
171*1fd5a2e1SPrashanth Swaminathan 
172*1fd5a2e1SPrashanth Swaminathan   /* If the return value is a struct and we don't have
173*1fd5a2e1SPrashanth Swaminathan      a return value address then we need to make one.  */
174*1fd5a2e1SPrashanth Swaminathan   if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
175*1fd5a2e1SPrashanth Swaminathan     {
176*1fd5a2e1SPrashanth Swaminathan       ecif.rvalue = alloca (cif->rtype->size);
177*1fd5a2e1SPrashanth Swaminathan     }
178*1fd5a2e1SPrashanth Swaminathan   else
179*1fd5a2e1SPrashanth Swaminathan     ecif.rvalue = rvalue;
180*1fd5a2e1SPrashanth Swaminathan 
181*1fd5a2e1SPrashanth Swaminathan   switch (cif->abi)
182*1fd5a2e1SPrashanth Swaminathan     {
183*1fd5a2e1SPrashanth Swaminathan     case FFI_ARCOMPACT:
184*1fd5a2e1SPrashanth Swaminathan       ffi_call_ARCompact (ffi_prep_args, &ecif, cif->bytes,
185*1fd5a2e1SPrashanth Swaminathan 			  cif->flags, ecif.rvalue, fn);
186*1fd5a2e1SPrashanth Swaminathan       break;
187*1fd5a2e1SPrashanth Swaminathan 
188*1fd5a2e1SPrashanth Swaminathan     default:
189*1fd5a2e1SPrashanth Swaminathan       FFI_ASSERT (0);
190*1fd5a2e1SPrashanth Swaminathan       break;
191*1fd5a2e1SPrashanth Swaminathan     }
192*1fd5a2e1SPrashanth Swaminathan }
193*1fd5a2e1SPrashanth Swaminathan 
194*1fd5a2e1SPrashanth Swaminathan int
ffi_closure_inner_ARCompact(ffi_closure * closure,void * rvalue,ffi_arg * args)195*1fd5a2e1SPrashanth Swaminathan ffi_closure_inner_ARCompact (ffi_closure * closure, void *rvalue,
196*1fd5a2e1SPrashanth Swaminathan 			     ffi_arg * args)
197*1fd5a2e1SPrashanth Swaminathan {
198*1fd5a2e1SPrashanth Swaminathan   void **arg_area, **p_argv;
199*1fd5a2e1SPrashanth Swaminathan   ffi_cif *cif = closure->cif;
200*1fd5a2e1SPrashanth Swaminathan   char *argp = (char *) args;
201*1fd5a2e1SPrashanth Swaminathan   ffi_type **p_argt;
202*1fd5a2e1SPrashanth Swaminathan   int i;
203*1fd5a2e1SPrashanth Swaminathan 
204*1fd5a2e1SPrashanth Swaminathan   arg_area = (void **) alloca (cif->nargs * sizeof (void *));
205*1fd5a2e1SPrashanth Swaminathan 
206*1fd5a2e1SPrashanth Swaminathan   /* handle hidden argument */
207*1fd5a2e1SPrashanth Swaminathan   if (cif->flags == FFI_TYPE_STRUCT)
208*1fd5a2e1SPrashanth Swaminathan     {
209*1fd5a2e1SPrashanth Swaminathan       rvalue = *(void **) argp;
210*1fd5a2e1SPrashanth Swaminathan       argp += 4;
211*1fd5a2e1SPrashanth Swaminathan     }
212*1fd5a2e1SPrashanth Swaminathan 
213*1fd5a2e1SPrashanth Swaminathan   p_argv = arg_area;
214*1fd5a2e1SPrashanth Swaminathan 
215*1fd5a2e1SPrashanth Swaminathan   for (i = 0, p_argt = cif->arg_types; i < cif->nargs;
216*1fd5a2e1SPrashanth Swaminathan        i++, p_argt++, p_argv++)
217*1fd5a2e1SPrashanth Swaminathan     {
218*1fd5a2e1SPrashanth Swaminathan       size_t z;
219*1fd5a2e1SPrashanth Swaminathan       int alignment;
220*1fd5a2e1SPrashanth Swaminathan 
221*1fd5a2e1SPrashanth Swaminathan       /* align alignment to 4 */
222*1fd5a2e1SPrashanth Swaminathan       alignment = (((*p_argt)->alignment - 1) | 3) + 1;
223*1fd5a2e1SPrashanth Swaminathan 
224*1fd5a2e1SPrashanth Swaminathan       /* Align if necessary.  */
225*1fd5a2e1SPrashanth Swaminathan       if ((alignment - 1) & (unsigned) argp)
226*1fd5a2e1SPrashanth Swaminathan 	argp = (char *) FFI_ALIGN (argp, alignment);
227*1fd5a2e1SPrashanth Swaminathan 
228*1fd5a2e1SPrashanth Swaminathan       z = (*p_argt)->size;
229*1fd5a2e1SPrashanth Swaminathan       *p_argv = (void *) argp;
230*1fd5a2e1SPrashanth Swaminathan       argp += z;
231*1fd5a2e1SPrashanth Swaminathan     }
232*1fd5a2e1SPrashanth Swaminathan 
233*1fd5a2e1SPrashanth Swaminathan   (closure->fun) (cif, rvalue, arg_area, closure->user_data);
234*1fd5a2e1SPrashanth Swaminathan 
235*1fd5a2e1SPrashanth Swaminathan   return cif->flags;
236*1fd5a2e1SPrashanth Swaminathan }
237*1fd5a2e1SPrashanth Swaminathan 
238*1fd5a2e1SPrashanth Swaminathan extern void ffi_closure_ARCompact (void);
239*1fd5a2e1SPrashanth Swaminathan 
240*1fd5a2e1SPrashanth Swaminathan ffi_status
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)241*1fd5a2e1SPrashanth Swaminathan ffi_prep_closure_loc (ffi_closure * closure, ffi_cif * cif,
242*1fd5a2e1SPrashanth Swaminathan 		      void (*fun) (ffi_cif *, void *, void **, void *),
243*1fd5a2e1SPrashanth Swaminathan 		      void *user_data, void *codeloc)
244*1fd5a2e1SPrashanth Swaminathan {
245*1fd5a2e1SPrashanth Swaminathan   uint32_t *tramp = (uint32_t *) & (closure->tramp[0]);
246*1fd5a2e1SPrashanth Swaminathan 
247*1fd5a2e1SPrashanth Swaminathan   switch (cif->abi)
248*1fd5a2e1SPrashanth Swaminathan     {
249*1fd5a2e1SPrashanth Swaminathan     case FFI_ARCOMPACT:
250*1fd5a2e1SPrashanth Swaminathan       FFI_ASSERT (tramp == codeloc);
251*1fd5a2e1SPrashanth Swaminathan       tramp[0] = CODE_ENDIAN (0x200a1fc0);	/* mov r8, pcl  */
252*1fd5a2e1SPrashanth Swaminathan       tramp[1] = CODE_ENDIAN (0x20200f80);	/* j [long imm] */
253*1fd5a2e1SPrashanth Swaminathan       tramp[2] = CODE_ENDIAN (ffi_closure_ARCompact);
254*1fd5a2e1SPrashanth Swaminathan       break;
255*1fd5a2e1SPrashanth Swaminathan 
256*1fd5a2e1SPrashanth Swaminathan     default:
257*1fd5a2e1SPrashanth Swaminathan       return FFI_BAD_ABI;
258*1fd5a2e1SPrashanth Swaminathan     }
259*1fd5a2e1SPrashanth Swaminathan 
260*1fd5a2e1SPrashanth Swaminathan   closure->cif = cif;
261*1fd5a2e1SPrashanth Swaminathan   closure->fun = fun;
262*1fd5a2e1SPrashanth Swaminathan   closure->user_data = user_data;
263*1fd5a2e1SPrashanth Swaminathan   cacheflush (codeloc, FFI_TRAMPOLINE_SIZE, BCACHE);
264*1fd5a2e1SPrashanth Swaminathan 
265*1fd5a2e1SPrashanth Swaminathan   return FFI_OK;
266*1fd5a2e1SPrashanth Swaminathan }
267