1 /* -----------------------------------------------------------------------
2    ffi.c - Copyright (c) 2014 Sebastian Macke <sebastian@macke.de>
3 
4    OpenRISC 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,
18    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20    NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24    DEALINGS IN THE SOFTWARE.
25    ----------------------------------------------------------------------- */
26 
27 #include <ffi.h>
28 #include "ffi_common.h"
29 
30 /* ffi_prep_args is called by the assembly routine once stack space
31    has been allocated for the function's arguments */
32 
ffi_prep_args(char * stack,extended_cif * ecif)33 void* ffi_prep_args(char *stack, extended_cif *ecif)
34 {
35   char *stacktemp = stack;
36   int i, s;
37   ffi_type **arg;
38   int count = 0;
39   int nfixedargs;
40 
41   nfixedargs = ecif->cif->nfixedargs;
42   arg = ecif->cif->arg_types;
43   void **argv = ecif->avalue;
44 
45   if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
46     {
47       *(void **) stack = ecif->rvalue;
48       stack += 4;
49       count = 4;
50     }
51   for(i=0; i<ecif->cif->nargs; i++)
52   {
53 
54     /* variadic args are saved on stack */
55     if ((nfixedargs == 0) && (count < 24))
56       {
57         count = 24;
58         stack = stacktemp + 24;
59       }
60     nfixedargs--;
61 
62     s = 4;
63     switch((*arg)->type)
64       {
65       case FFI_TYPE_STRUCT:
66         *(void **)stack = *argv;
67         break;
68 
69       case FFI_TYPE_SINT8:
70         *(signed int *) stack = (signed int)*(SINT8 *)(* argv);
71         break;
72 
73       case FFI_TYPE_UINT8:
74         *(unsigned int *) stack = (unsigned int)*(UINT8 *)(* argv);
75         break;
76 
77       case FFI_TYPE_SINT16:
78         *(signed int *) stack = (signed int)*(SINT16 *)(* argv);
79         break;
80 
81       case FFI_TYPE_UINT16:
82         *(unsigned int *) stack = (unsigned int)*(UINT16 *)(* argv);
83         break;
84 
85       case FFI_TYPE_SINT32:
86       case FFI_TYPE_UINT32:
87       case FFI_TYPE_FLOAT:
88       case FFI_TYPE_POINTER:
89         *(int *)stack = *(int*)(*argv);
90         break;
91 
92       default: /* 8 byte types */
93         if (count == 20) /* never split arguments */
94           {
95             stack += 4;
96             count += 4;
97           }
98         s = (*arg)->size;
99         memcpy(stack, *argv, s);
100         break;
101       }
102 
103     stack += s;
104     count += s;
105     argv++;
106     arg++;
107   }
108   return stacktemp + ((count>24)?24:0);
109 }
110 
111 extern void ffi_call_SYSV(unsigned,
112                           extended_cif *,
113                           void *(*)(int *, extended_cif *),
114                           unsigned *,
115                           void (*fn)(void),
116                           unsigned);
117 
118 
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)119 void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
120 {
121   int i;
122   int size;
123   ffi_type **arg;
124 
125   /* Calculate size to allocate on stack */
126 
127   for(i = 0, arg = cif->arg_types, size=0; i < cif->nargs; i++, arg++)
128     {
129       if ((*arg)->type == FFI_TYPE_STRUCT)
130         size += 4;
131       else
132       if ((*arg)->size <= 4)
133         size += 4;
134       else
135         size += 8;
136     }
137 
138   /* for variadic functions more space is needed on the stack */
139   if (cif->nargs != cif->nfixedargs)
140     size += 24;
141 
142   if (cif->rtype->type == FFI_TYPE_STRUCT)
143     size += 4;
144 
145 
146   extended_cif ecif;
147   ecif.cif = cif;
148   ecif.avalue = avalue;
149   ecif.rvalue = rvalue;
150 
151   switch (cif->abi)
152   {
153     case FFI_SYSV:
154       ffi_call_SYSV(size, &ecif, ffi_prep_args, rvalue, fn, cif->flags);
155       break;
156     default:
157       FFI_ASSERT(0);
158       break;
159   }
160 }
161 
162 
ffi_closure_SYSV(unsigned long r3,unsigned long r4,unsigned long r5,unsigned long r6,unsigned long r7,unsigned long r8)163 void ffi_closure_SYSV(unsigned long r3, unsigned long r4, unsigned long r5,
164                       unsigned long r6, unsigned long r7, unsigned long r8)
165 {
166   register int *sp __asm__ ("r17");
167   register int *r13 __asm__ ("r13");
168 
169   ffi_closure* closure = (ffi_closure*) r13;
170   char *stack_args = sp;
171 
172   /* Lay the register arguments down in a continuous chunk of memory.  */
173   unsigned register_args[6] =
174     { r3, r4, r5, r6, r7, r8 };
175 
176   /* Pointer to a struct return value.  */
177   void *struct_rvalue = (void *) r3;
178 
179   ffi_cif *cif = closure->cif;
180   ffi_type **arg_types = cif->arg_types;
181   void **avalue = alloca (cif->nargs * sizeof(void *));
182   char *ptr = (char *) register_args;
183   int count = 0;
184   int nfixedargs = cif->nfixedargs;
185   int i;
186 
187   /* preserve struct type return pointer passing */
188 
189   if ((cif->rtype != NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
190   {
191     ptr += 4;
192     count = 4;
193   }
194 
195   /* Find the address of each argument.  */
196   for (i = 0; i < cif->nargs; i++)
197     {
198 
199       /* variadic args are saved on stack */
200       if ((nfixedargs == 0) && (count < 24))
201         {
202           ptr = stack_args;
203           count = 24;
204         }
205       nfixedargs--;
206 
207       switch (arg_types[i]->type)
208         {
209         case FFI_TYPE_SINT8:
210         case FFI_TYPE_UINT8:
211           avalue[i] = ptr + 3;
212           break;
213 
214         case FFI_TYPE_SINT16:
215         case FFI_TYPE_UINT16:
216           avalue[i] = ptr + 2;
217           break;
218 
219         case FFI_TYPE_SINT32:
220         case FFI_TYPE_UINT32:
221         case FFI_TYPE_FLOAT:
222         case FFI_TYPE_POINTER:
223           avalue[i] = ptr;
224           break;
225 
226         case FFI_TYPE_STRUCT:
227           avalue[i] = *(void**)ptr;
228           break;
229 
230         default:
231           /* 8-byte values  */
232 
233           /* arguments are never splitted */
234           if (ptr == &register_args[5])
235             ptr = stack_args;
236           avalue[i] = ptr;
237           ptr += 4;
238           count += 4;
239           break;
240         }
241       ptr += 4;
242       count += 4;
243 
244       /* If we've handled more arguments than fit in registers,
245          start looking at the those passed on the stack.  */
246 
247       if (count == 24)
248         ptr = stack_args;
249     }
250 
251   if (cif->rtype && (cif->rtype->type == FFI_TYPE_STRUCT))
252     {
253       (closure->fun) (cif, struct_rvalue, avalue, closure->user_data);
254     } else
255     {
256       long long rvalue;
257       (closure->fun) (cif, &rvalue, avalue, closure->user_data);
258       if (cif->rtype)
259         asm ("l.ori r12, %0, 0x0\n l.lwz r11, 0(r12)\n l.lwz r12, 4(r12)" : : "r" (&rvalue));
260     }
261 }
262 
263 
264 ffi_status
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)265 ffi_prep_closure_loc (ffi_closure* closure,
266                       ffi_cif* cif,
267                       void (*fun)(ffi_cif*,void*,void**,void*),
268                       void *user_data,
269                       void *codeloc)
270 {
271   unsigned short *tramp = (unsigned short *) closure->tramp;
272   unsigned long fn = (unsigned long) ffi_closure_SYSV;
273   unsigned long cls = (unsigned long) codeloc;
274 
275   if (cif->abi != FFI_SYSV)
276     return FFI_BAD_ABI;
277 
278   closure->cif = cif;
279   closure->user_data = user_data;
280   closure->fun = fun;
281 
282   /* write pointers to temporary registers */
283   tramp[0] = (0x6 << 10) | (13 << 5); /* l.movhi r13, ... */
284   tramp[1] = cls >> 16;
285   tramp[2] = (0x2a << 10) | (13 << 5) | 13; /* l.ori r13, r13, ... */
286   tramp[3] = cls & 0xFFFF;
287 
288   tramp[4] = (0x6 << 10) | (15 << 5); /* l.movhi r15, ... */
289   tramp[5] = fn >> 16;
290   tramp[6] = (0x2a << 10) | (15 << 5) | 15; /* l.ori r15, r15 ... */
291   tramp[7] = fn & 0xFFFF;
292 
293   tramp[8] = (0x11 << 10); /* l.jr r15 */
294   tramp[9] = 15 << 11;
295 
296   tramp[10] = (0x2a << 10) | (17 << 5) | 1; /* l.ori r17, r1, ... */
297   tramp[11] = 0x0;
298 
299   return FFI_OK;
300 }
301 
302 
ffi_prep_cif_machdep(ffi_cif * cif)303 ffi_status ffi_prep_cif_machdep (ffi_cif *cif)
304 {
305   cif->flags = 0;
306 
307   /* structures are returned as pointers */
308   if (cif->rtype->type == FFI_TYPE_STRUCT)
309     cif->flags = FFI_TYPE_STRUCT;
310   else
311   if (cif->rtype->size > 4)
312     cif->flags = FFI_TYPE_UINT64;
313 
314   cif->nfixedargs = cif->nargs;
315 
316   return FFI_OK;
317 }
318 
319 
ffi_prep_cif_machdep_var(ffi_cif * cif,unsigned int nfixedargs,unsigned int ntotalargs)320 ffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
321          unsigned int nfixedargs, unsigned int ntotalargs)
322 {
323   ffi_status status;
324 
325   status = ffi_prep_cif_machdep (cif);
326   cif->nfixedargs = nfixedargs;
327   return status;
328 }
329