• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -----------------------------------------------------------------------
2    ffi.c
3 
4    m68k Foreign Function Interface
5    ----------------------------------------------------------------------- */
6 
7 #include <ffi.h>
8 #include <ffi_common.h>
9 
10 #include <stdlib.h>
11 #include <unistd.h>
12 #ifdef __rtems__
13 void rtems_cache_flush_multiple_data_lines( const void *, size_t );
14 #else
15 #include <sys/syscall.h>
16 #ifdef __MINT__
17 #include <mint/mintbind.h>
18 #include <mint/ssystem.h>
19 #else
20 #include <asm/cachectl.h>
21 #endif
22 #endif
23 
24 void ffi_call_SYSV (extended_cif *,
25 		    unsigned, unsigned,
26 		    void *, void (*fn) ());
27 void *ffi_prep_args (void *stack, extended_cif *ecif);
28 void ffi_closure_SYSV (ffi_closure *);
29 void ffi_closure_struct_SYSV (ffi_closure *);
30 unsigned int ffi_closure_SYSV_inner (ffi_closure *closure,
31 				     void *resp, void *args);
32 
33 /* ffi_prep_args is called by the assembly routine once stack space has
34    been allocated for the function's arguments.  */
35 
36 void *
ffi_prep_args(void * stack,extended_cif * ecif)37 ffi_prep_args (void *stack, extended_cif *ecif)
38 {
39   unsigned int i;
40   void **p_argv;
41   char *argp;
42   ffi_type **p_arg;
43   void *struct_value_ptr;
44 
45   argp = stack;
46 
47   if (
48 #ifdef __MINT__
49       (ecif->cif->rtype->type == FFI_TYPE_LONGDOUBLE) ||
50 #endif
51       (((ecif->cif->rtype->type == FFI_TYPE_STRUCT)
52         && !ecif->cif->flags)))
53     struct_value_ptr = ecif->rvalue;
54   else
55     struct_value_ptr = NULL;
56 
57   p_argv = ecif->avalue;
58 
59   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
60        i != 0;
61        i--, p_arg++)
62     {
63       size_t z = (*p_arg)->size;
64       int type = (*p_arg)->type;
65 
66       if (z < sizeof (int))
67 	{
68 	  switch (type)
69 	    {
70 	    case FFI_TYPE_SINT8:
71 	      *(signed int *) argp = (signed int) *(SINT8 *) *p_argv;
72 	      break;
73 
74 	    case FFI_TYPE_UINT8:
75 	      *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv;
76 	      break;
77 
78 	    case FFI_TYPE_SINT16:
79 	      *(signed int *) argp = (signed int) *(SINT16 *) *p_argv;
80 	      break;
81 
82 	    case FFI_TYPE_UINT16:
83 	      *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv;
84 	      break;
85 
86 	    case FFI_TYPE_STRUCT:
87 #ifdef __MINT__
88 	      if (z == 1 || z == 2)
89 		memcpy (argp + 2, *p_argv, z);
90               else
91 		memcpy (argp, *p_argv, z);
92 #else
93 	      memcpy (argp + sizeof (int) - z, *p_argv, z);
94 #endif
95 	      break;
96 
97 	    default:
98 	      FFI_ASSERT (0);
99 	    }
100 	  z = sizeof (int);
101 	}
102       else
103 	{
104 	  memcpy (argp, *p_argv, z);
105 
106 	  /* Align if necessary.  */
107 	  if ((sizeof(int) - 1) & z)
108 	    z = ALIGN(z, sizeof(int));
109 	}
110 
111       p_argv++;
112       argp += z;
113     }
114 
115   return struct_value_ptr;
116 }
117 
118 #define CIF_FLAGS_INT		1
119 #define CIF_FLAGS_DINT		2
120 #define CIF_FLAGS_FLOAT		4
121 #define CIF_FLAGS_DOUBLE	8
122 #define CIF_FLAGS_LDOUBLE	16
123 #define CIF_FLAGS_POINTER	32
124 #define CIF_FLAGS_STRUCT1	64
125 #define CIF_FLAGS_STRUCT2	128
126 #define CIF_FLAGS_SINT8		256
127 #define CIF_FLAGS_SINT16	512
128 
129 /* Perform machine dependent cif processing */
130 ffi_status
ffi_prep_cif_machdep(ffi_cif * cif)131 ffi_prep_cif_machdep (ffi_cif *cif)
132 {
133   /* Set the return type flag */
134   switch (cif->rtype->type)
135     {
136     case FFI_TYPE_VOID:
137       cif->flags = 0;
138       break;
139 
140     case FFI_TYPE_STRUCT:
141       if (cif->rtype->elements[0]->type == FFI_TYPE_STRUCT &&
142           cif->rtype->elements[1])
143         {
144           cif->flags = 0;
145           break;
146         }
147 
148       switch (cif->rtype->size)
149 	{
150 	case 1:
151 #ifdef __MINT__
152 	  cif->flags = CIF_FLAGS_STRUCT2;
153 #else
154 	  cif->flags = CIF_FLAGS_STRUCT1;
155 #endif
156 	  break;
157 	case 2:
158 	  cif->flags = CIF_FLAGS_STRUCT2;
159 	  break;
160 #ifdef __MINT__
161 	case 3:
162 #endif
163 	case 4:
164 	  cif->flags = CIF_FLAGS_INT;
165 	  break;
166 #ifdef __MINT__
167 	case 7:
168 #endif
169 	case 8:
170 	  cif->flags = CIF_FLAGS_DINT;
171 	  break;
172 	default:
173 	  cif->flags = 0;
174 	  break;
175 	}
176       break;
177 
178     case FFI_TYPE_FLOAT:
179       cif->flags = CIF_FLAGS_FLOAT;
180       break;
181 
182     case FFI_TYPE_DOUBLE:
183       cif->flags = CIF_FLAGS_DOUBLE;
184       break;
185 
186 #if (FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE)
187     case FFI_TYPE_LONGDOUBLE:
188 #ifdef __MINT__
189       cif->flags = 0;
190 #else
191       cif->flags = CIF_FLAGS_LDOUBLE;
192 #endif
193       break;
194 #endif
195 
196     case FFI_TYPE_POINTER:
197       cif->flags = CIF_FLAGS_POINTER;
198       break;
199 
200     case FFI_TYPE_SINT64:
201     case FFI_TYPE_UINT64:
202       cif->flags = CIF_FLAGS_DINT;
203       break;
204 
205     case FFI_TYPE_SINT16:
206       cif->flags = CIF_FLAGS_SINT16;
207       break;
208 
209     case FFI_TYPE_SINT8:
210       cif->flags = CIF_FLAGS_SINT8;
211       break;
212 
213     default:
214       cif->flags = CIF_FLAGS_INT;
215       break;
216     }
217 
218   return FFI_OK;
219 }
220 
221 void
ffi_call(ffi_cif * cif,void (* fn)(),void * rvalue,void ** avalue)222 ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue)
223 {
224   extended_cif ecif;
225 
226   ecif.cif = cif;
227   ecif.avalue = avalue;
228 
229   /* If the return value is a struct and we don't have a return value
230      address then we need to make one.  */
231 
232   if (rvalue == NULL
233       && cif->rtype->type == FFI_TYPE_STRUCT
234       && cif->rtype->size > 8)
235     ecif.rvalue = alloca (cif->rtype->size);
236   else
237     ecif.rvalue = rvalue;
238 
239   switch (cif->abi)
240     {
241     case FFI_SYSV:
242       ffi_call_SYSV (&ecif, cif->bytes, cif->flags,
243 		     ecif.rvalue, fn);
244       break;
245 
246     default:
247       FFI_ASSERT (0);
248       break;
249     }
250 }
251 
252 static void
ffi_prep_incoming_args_SYSV(char * stack,void ** avalue,ffi_cif * cif)253 ffi_prep_incoming_args_SYSV (char *stack, void **avalue, ffi_cif *cif)
254 {
255   unsigned int i;
256   void **p_argv;
257   char *argp;
258   ffi_type **p_arg;
259 
260   argp = stack;
261   p_argv = avalue;
262 
263   for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
264     {
265       size_t z;
266 
267       z = (*p_arg)->size;
268 #ifdef __MINT__
269       if (cif->flags &&
270           cif->rtype->type == FFI_TYPE_STRUCT &&
271           (z == 1 || z == 2))
272  	{
273 	  *p_argv = (void *) (argp + 2);
274 
275 	  z = 4;
276 	}
277       else
278       if (cif->flags &&
279           cif->rtype->type == FFI_TYPE_STRUCT &&
280           (z == 3 || z == 4))
281  	{
282 	  *p_argv = (void *) (argp);
283 
284 	  z = 4;
285 	}
286       else
287 #endif
288       if (z <= 4)
289 	{
290 	  *p_argv = (void *) (argp + 4 - z);
291 
292 	  z = 4;
293 	}
294       else
295 	{
296 	  *p_argv = (void *) argp;
297 
298 	  /* Align if necessary */
299 	  if ((sizeof(int) - 1) & z)
300 	    z = ALIGN(z, sizeof(int));
301 	}
302 
303       p_argv++;
304       argp += z;
305     }
306 }
307 
308 unsigned int
ffi_closure_SYSV_inner(ffi_closure * closure,void * resp,void * args)309 ffi_closure_SYSV_inner (ffi_closure *closure, void *resp, void *args)
310 {
311   ffi_cif *cif;
312   void **arg_area;
313 
314   cif = closure->cif;
315   arg_area = (void**) alloca (cif->nargs * sizeof (void *));
316 
317   ffi_prep_incoming_args_SYSV(args, arg_area, cif);
318 
319   (closure->fun) (cif, resp, arg_area, closure->user_data);
320 
321   return cif->flags;
322 }
323 
324 ffi_status
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)325 ffi_prep_closure_loc (ffi_closure* closure,
326 		      ffi_cif* cif,
327 		      void (*fun)(ffi_cif*,void*,void**,void*),
328 		      void *user_data,
329 		      void *codeloc)
330 {
331   if (cif->abi != FFI_SYSV)
332     return FFI_BAD_ABI;
333 
334   *(unsigned short *)closure->tramp = 0x207c;
335   *(void **)(closure->tramp + 2) = codeloc;
336   *(unsigned short *)(closure->tramp + 6) = 0x4ef9;
337 
338   if (
339 #ifdef __MINT__
340       (cif->rtype->type == FFI_TYPE_LONGDOUBLE) ||
341 #endif
342       (((cif->rtype->type == FFI_TYPE_STRUCT)
343          && !cif->flags)))
344     *(void **)(closure->tramp + 8) = ffi_closure_struct_SYSV;
345   else
346     *(void **)(closure->tramp + 8) = ffi_closure_SYSV;
347 
348 #ifdef __rtems__
349   rtems_cache_flush_multiple_data_lines( codeloc, FFI_TRAMPOLINE_SIZE );
350 #elif defined(__MINT__)
351   Ssystem(S_FLUSHCACHE, codeloc, FFI_TRAMPOLINE_SIZE);
352 #else
353   syscall(SYS_cacheflush, codeloc, FLUSH_SCOPE_LINE,
354 	  FLUSH_CACHE_BOTH, FFI_TRAMPOLINE_SIZE);
355 #endif
356 
357   closure->cif  = cif;
358   closure->user_data = user_data;
359   closure->fun  = fun;
360 
361   return FFI_OK;
362 }
363