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