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