Add moxie support. Release 3.0.12.
[platform/upstream/libffi.git] / src / moxie / ffi.c
1 /* -----------------------------------------------------------------------
2    ffi.c - Copyright (C) 2012, 2013  Anthony Green
3    
4    Moxie 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 #include <stdlib.h>
31
32 /* ffi_prep_args is called by the assembly routine once stack space
33    has been allocated for the function's arguments */
34
35 void *ffi_prep_args(char *stack, extended_cif *ecif)
36 {
37   register unsigned int i;
38   register void **p_argv;
39   register char *argp;
40   register ffi_type **p_arg;
41   register int count = 0;
42
43   p_argv = ecif->avalue;
44   argp = stack;
45
46   if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
47     {
48       *(void **) argp = ecif->rvalue;
49       argp += 4;
50     }
51
52   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
53        (i != 0);
54        i--, p_arg++)
55     {
56       size_t z;
57       
58       z = (*p_arg)->size;
59
60       if ((*p_arg)->type == FFI_TYPE_STRUCT)
61         {
62           z = sizeof(void*);
63           *(void **) argp = *p_argv;
64         } 
65       else if (z < sizeof(int))
66         {
67           z = sizeof(int);
68           switch ((*p_arg)->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             default:
87               FFI_ASSERT(0);
88             }
89         }
90       else if (z == sizeof(int))
91         {
92           *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
93         }
94       else
95         {
96           memcpy(argp, *p_argv, z);
97         }
98       p_argv++;
99       argp += z;
100       count += z;
101     }
102
103   return (stack + ((count > 24) ? 24 : ALIGN_DOWN(count, 8)));
104 }
105
106 /* Perform machine dependent cif processing */
107 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
108 {
109   if (cif->rtype->type == FFI_TYPE_STRUCT)
110     cif->flags = -1;
111   else
112     cif->flags = cif->rtype->size;
113
114   cif->bytes = ALIGN (cif->bytes, 8);
115
116   return FFI_OK;
117 }
118
119 extern void ffi_call_EABI(void *(*)(char *, extended_cif *), 
120                           extended_cif *, 
121                           unsigned, unsigned, 
122                           unsigned *, 
123                           void (*fn)(void));
124
125 void ffi_call(ffi_cif *cif, 
126               void (*fn)(void), 
127               void *rvalue, 
128               void **avalue)
129 {
130   extended_cif ecif;
131
132   ecif.cif = cif;
133   ecif.avalue = avalue;
134   
135   /* If the return value is a struct and we don't have a return */
136   /* value address then we need to make one                     */
137
138   if ((rvalue == NULL) && 
139       (cif->rtype->type == FFI_TYPE_STRUCT))
140     {
141       ecif.rvalue = alloca(cif->rtype->size);
142     }
143   else
144     ecif.rvalue = rvalue;
145
146   switch (cif->abi) 
147     {
148     case FFI_EABI:
149       ffi_call_EABI(ffi_prep_args, &ecif, cif->bytes, 
150                     cif->flags, ecif.rvalue, fn);
151       break;
152     default:
153       FFI_ASSERT(0);
154       break;
155     }
156 }
157
158 void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
159                        unsigned arg4, unsigned arg5, unsigned arg6)
160 {
161   /* This function is called by a trampoline.  The trampoline stows a
162      pointer to the ffi_closure object in $r7.  We must save this
163      pointer in a place that will persist while we do our work.  */
164   register ffi_closure *creg __asm__ ("$r12");
165   ffi_closure *closure = creg;
166
167   /* Arguments that don't fit in registers are found on the stack
168      at a fixed offset above the current frame pointer.  */
169   register char *frame_pointer __asm__ ("$fp");
170
171   /* Pointer to a struct return value.  */
172   void *struct_rvalue = (void *) arg1;
173
174   /* 6 words reserved for register args + 3 words from jsr */
175   char *stack_args = frame_pointer + 9*4; 
176
177   /* Lay the register arguments down in a continuous chunk of memory.  */
178   unsigned register_args[6] =
179     { arg1, arg2, arg3, arg4, arg5, arg6 };
180   char *register_args_ptr = (char *) register_args;
181
182   ffi_cif *cif = closure->cif;
183   ffi_type **arg_types = cif->arg_types;
184   void **avalue = alloca (cif->nargs * sizeof(void *));
185   char *ptr = (char *) register_args;
186   int i;
187
188   /* preserve struct type return pointer passing */
189   if ((cif->rtype != NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) {
190     ptr += 4;
191     register_args_ptr = (char *)&register_args[1];
192   }
193
194   /* Find the address of each argument.  */
195   for (i = 0; i < cif->nargs; i++)
196     {
197       switch (arg_types[i]->type)
198         {
199         case FFI_TYPE_SINT8:
200         case FFI_TYPE_UINT8:
201           avalue[i] = ptr + 3;
202           break;
203         case FFI_TYPE_SINT16:
204         case FFI_TYPE_UINT16:
205           avalue[i] = ptr + 2;
206           break;
207         case FFI_TYPE_SINT32:
208         case FFI_TYPE_UINT32:
209         case FFI_TYPE_FLOAT:
210         case FFI_TYPE_POINTER:
211           avalue[i] = ptr;
212           break;
213         case FFI_TYPE_STRUCT:
214           avalue[i] = *(void**)ptr;
215           break;
216         default:
217           /* This is an 8-byte value.  */
218           avalue[i] = ptr;
219           ptr += 4;
220           break;
221         }
222       ptr += 4;
223
224       /* If we've handled more arguments than fit in registers,
225          start looking at the those passed on the stack.  */
226       if (ptr == &register_args[6])
227         ptr = stack_args;
228     }
229
230   /* Invoke the closure.  */
231   if (cif->rtype && (cif->rtype->type == FFI_TYPE_STRUCT))
232     {
233       (closure->fun) (cif, struct_rvalue, avalue, closure->user_data);
234     }
235   else
236     {
237       /* Allocate space for the return value and call the function.  */
238       long long rvalue;
239       (closure->fun) (cif, &rvalue, avalue, closure->user_data);
240       asm ("mov $r12, %0\n ld.l $r0, ($r12)\n ldo.l $r1, 4($r12)" : : "r" (&rvalue));
241     }
242 }
243
244 ffi_status
245 ffi_prep_closure_loc (ffi_closure* closure,
246                       ffi_cif* cif,
247                       void (*fun)(ffi_cif*, void*, void**, void*),
248                       void *user_data,
249                       void *codeloc)
250 {
251   unsigned short *tramp = (unsigned short *) &closure->tramp[0];
252   unsigned long fn = (long) ffi_closure_eabi;
253   unsigned long cls = (long) codeloc;
254
255   if (cif->abi != FFI_EABI)
256     return FFI_BAD_ABI;
257
258   fn = (unsigned long) ffi_closure_eabi;
259
260   tramp[0] = 0x01e0; /* ldi.l $r7, .... */
261   tramp[1] = cls >> 16;
262   tramp[2] = cls & 0xffff;
263   tramp[3] = 0x1a00; /* jmpa .... */
264   tramp[4] = fn >> 16;
265   tramp[5] = fn & 0xffff;
266
267   closure->cif = cif;
268   closure->fun = fun;
269   closure->user_data = user_data;
270
271   return FFI_OK;
272 }