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
33void* 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
111extern void ffi_call_SYSV(unsigned,
112                          extended_cif *,
113                          void *(*)(int *, extended_cif *),
114                          unsigned *,
115                          void (*fn)(void),
116                          unsigned);
117
118
119void 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
163void 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
264ffi_status
265ffi_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
303ffi_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
320ffi_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