• 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 #include <sys/syscall.h>
13 #include <asm/cachectl.h>
14 
15 void ffi_call_SYSV (extended_cif *,
16 		    unsigned, unsigned,
17 		    void *, void (*fn) ());
18 void *ffi_prep_args (void *stack, extended_cif *ecif);
19 void ffi_closure_SYSV (ffi_closure *);
20 void ffi_closure_struct_SYSV (ffi_closure *);
21 unsigned int ffi_closure_SYSV_inner (ffi_closure *closure,
22 				     void *resp, void *args);
23 
24 /* ffi_prep_args is called by the assembly routine once stack space has
25    been allocated for the function's arguments.  */
26 
27 void *
ffi_prep_args(void * stack,extended_cif * ecif)28 ffi_prep_args (void *stack, extended_cif *ecif)
29 {
30   unsigned int i;
31   void **p_argv;
32   char *argp;
33   ffi_type **p_arg;
34   void *struct_value_ptr;
35 
36   argp = stack;
37 
38   if (ecif->cif->rtype->type == FFI_TYPE_STRUCT
39       && !ecif->cif->flags)
40     struct_value_ptr = ecif->rvalue;
41   else
42     struct_value_ptr = NULL;
43 
44   p_argv = ecif->avalue;
45 
46   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
47        i != 0;
48        i--, p_arg++)
49     {
50       size_t z;
51 
52       z = (*p_arg)->size;
53       if (z < sizeof (int))
54 	{
55 	  switch ((*p_arg)->type)
56 	    {
57 	    case FFI_TYPE_SINT8:
58 	      *(signed int *) argp = (signed int) *(SINT8 *) *p_argv;
59 	      break;
60 
61 	    case FFI_TYPE_UINT8:
62 	      *(unsigned int *) argp = (unsigned int) *(UINT8 *) *p_argv;
63 	      break;
64 
65 	    case FFI_TYPE_SINT16:
66 	      *(signed int *) argp = (signed int) *(SINT16 *) *p_argv;
67 	      break;
68 
69 	    case FFI_TYPE_UINT16:
70 	      *(unsigned int *) argp = (unsigned int) *(UINT16 *) *p_argv;
71 	      break;
72 
73 	    case FFI_TYPE_STRUCT:
74 	      memcpy (argp + sizeof (int) - z, *p_argv, z);
75 	      break;
76 
77 	    default:
78 	      FFI_ASSERT (0);
79 	    }
80 	  z = sizeof (int);
81 	}
82       else
83 	{
84 	  memcpy (argp, *p_argv, z);
85 
86 	  /* Align if necessary.  */
87 	  if ((sizeof(int) - 1) & z)
88 	    z = ALIGN(z, sizeof(int));
89 	}
90 
91       p_argv++;
92       argp += z;
93     }
94 
95   return struct_value_ptr;
96 }
97 
98 #define CIF_FLAGS_INT		1
99 #define CIF_FLAGS_DINT		2
100 #define CIF_FLAGS_FLOAT		4
101 #define CIF_FLAGS_DOUBLE	8
102 #define CIF_FLAGS_LDOUBLE	16
103 #define CIF_FLAGS_POINTER	32
104 #define CIF_FLAGS_STRUCT1	64
105 #define CIF_FLAGS_STRUCT2	128
106 
107 /* Perform machine dependent cif processing */
108 ffi_status
ffi_prep_cif_machdep(ffi_cif * cif)109 ffi_prep_cif_machdep (ffi_cif *cif)
110 {
111   /* Set the return type flag */
112   switch (cif->rtype->type)
113     {
114     case FFI_TYPE_VOID:
115       cif->flags = 0;
116       break;
117 
118     case FFI_TYPE_STRUCT:
119       switch (cif->rtype->size)
120 	{
121 	case 1:
122 	  cif->flags = CIF_FLAGS_STRUCT1;
123 	  break;
124 	case 2:
125 	  cif->flags = CIF_FLAGS_STRUCT2;
126 	  break;
127 	case 4:
128 	  cif->flags = CIF_FLAGS_INT;
129 	  break;
130 	case 8:
131 	  cif->flags = CIF_FLAGS_DINT;
132 	  break;
133 	default:
134 	  cif->flags = 0;
135 	  break;
136 	}
137       break;
138 
139     case FFI_TYPE_FLOAT:
140       cif->flags = CIF_FLAGS_FLOAT;
141       break;
142 
143     case FFI_TYPE_DOUBLE:
144       cif->flags = CIF_FLAGS_DOUBLE;
145       break;
146 
147     case FFI_TYPE_LONGDOUBLE:
148       cif->flags = CIF_FLAGS_LDOUBLE;
149       break;
150 
151     case FFI_TYPE_POINTER:
152       cif->flags = CIF_FLAGS_POINTER;
153       break;
154 
155     case FFI_TYPE_SINT64:
156     case FFI_TYPE_UINT64:
157       cif->flags = CIF_FLAGS_DINT;
158       break;
159 
160     default:
161       cif->flags = CIF_FLAGS_INT;
162       break;
163     }
164 
165   return FFI_OK;
166 }
167 
168 void
ffi_call(ffi_cif * cif,void (* fn)(),void * rvalue,void ** avalue)169 ffi_call (ffi_cif *cif, void (*fn) (), void *rvalue, void **avalue)
170 {
171   extended_cif ecif;
172 
173   ecif.cif = cif;
174   ecif.avalue = avalue;
175 
176   /* If the return value is a struct and we don't have a return value
177      address then we need to make one.  */
178 
179   if (rvalue == NULL
180       && cif->rtype->type == FFI_TYPE_STRUCT
181       && cif->rtype->size > 8)
182     ecif.rvalue = alloca (cif->rtype->size);
183   else
184     ecif.rvalue = rvalue;
185 
186   switch (cif->abi)
187     {
188     case FFI_SYSV:
189       ffi_call_SYSV (&ecif, cif->bytes, cif->flags,
190 		     ecif.rvalue, fn);
191       break;
192 
193     default:
194       FFI_ASSERT (0);
195       break;
196     }
197 }
198 
199 static void
ffi_prep_incoming_args_SYSV(char * stack,void ** avalue,ffi_cif * cif)200 ffi_prep_incoming_args_SYSV (char *stack, void **avalue, ffi_cif *cif)
201 {
202   unsigned int i;
203   void **p_argv;
204   char *argp;
205   ffi_type **p_arg;
206 
207   argp = stack;
208   p_argv = avalue;
209 
210   for (i = cif->nargs, p_arg = cif->arg_types; (i != 0); i--, p_arg++)
211     {
212       size_t z;
213 
214       z = (*p_arg)->size;
215       if (z <= 4)
216 	{
217 	  *p_argv = (void *) (argp + 4 - z);
218 
219 	  z = 4;
220 	}
221       else
222 	{
223 	  *p_argv = (void *) argp;
224 
225 	  /* Align if necessary */
226 	  if ((sizeof(int) - 1) & z)
227 	    z = ALIGN(z, sizeof(int));
228 	}
229 
230       p_argv++;
231       argp += z;
232     }
233 }
234 
235 unsigned int
ffi_closure_SYSV_inner(ffi_closure * closure,void * resp,void * args)236 ffi_closure_SYSV_inner (ffi_closure *closure, void *resp, void *args)
237 {
238   ffi_cif *cif;
239   void **arg_area;
240 
241   cif = closure->cif;
242   arg_area = (void**) alloca (cif->nargs * sizeof (void *));
243 
244   ffi_prep_incoming_args_SYSV(args, arg_area, cif);
245 
246   (closure->fun) (cif, resp, arg_area, closure->user_data);
247 
248   return cif->flags;
249 }
250 
251 ffi_status
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)252 ffi_prep_closure_loc (ffi_closure* closure,
253 		      ffi_cif* cif,
254 		      void (*fun)(ffi_cif*,void*,void**,void*),
255 		      void *user_data,
256 		      void *codeloc)
257 {
258   FFI_ASSERT (cif->abi == FFI_SYSV);
259 
260   *(unsigned short *)closure->tramp = 0x207c;
261   *(void **)(closure->tramp + 2) = codeloc;
262   *(unsigned short *)(closure->tramp + 6) = 0x4ef9;
263   if (cif->rtype->type == FFI_TYPE_STRUCT
264       && !cif->flags)
265     *(void **)(closure->tramp + 8) = ffi_closure_struct_SYSV;
266   else
267     *(void **)(closure->tramp + 8) = ffi_closure_SYSV;
268 
269   syscall(SYS_cacheflush, codeloc, FLUSH_SCOPE_LINE,
270 	  FLUSH_CACHE_BOTH, FFI_TRAMPOLINE_SIZE);
271 
272   closure->cif  = cif;
273   closure->user_data = user_data;
274   closure->fun  = fun;
275 
276   return FFI_OK;
277 }
278 
279