1457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/* -----------------------------------------------------------------------
2457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   ffi.c - Copyright (c) 2014 Sebastian Macke <sebastian@macke.de>
3457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
4457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   OpenRISC Foreign Function Interface
5457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
6457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   Permission is hereby granted, free of charge, to any person obtaining
7457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   a copy of this software and associated documentation files (the
8457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   ``Software''), to deal in the Software without restriction, including
9457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   without limitation the rights to use, copy, modify, merge, publish,
10457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   distribute, sublicense, and/or sell copies of the Software, and to
11457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   permit persons to whom the Software is furnished to do so, subject to
12457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   the following conditions:
13457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
14457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   The above copyright notice and this permission notice shall be included
15457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   in all copies or substantial portions of the Software.
16457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
17457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
18457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   DEALINGS IN THE SOFTWARE.
25457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   ----------------------------------------------------------------------- */
26457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
27457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#include <ffi.h>
28457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique#include "ffi_common.h"
29457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
30457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique/* ffi_prep_args is called by the assembly routine once stack space
31457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique   has been allocated for the function's arguments */
32457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
33457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piquevoid* ffi_prep_args(char *stack, extended_cif *ecif)
34457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique{
35457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  char *stacktemp = stack;
36457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  int i, s;
37457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  ffi_type **arg;
38457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  int count = 0;
39457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  int nfixedargs;
40457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
41457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  nfixedargs = ecif->cif->nfixedargs;
42457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  arg = ecif->cif->arg_types;
43457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  void **argv = ecif->avalue;
44457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
45457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  if (ecif->cif->rtype->type == FFI_TYPE_STRUCT)
46457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    {
47457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      *(void **) stack = ecif->rvalue;
48457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      stack += 4;
49457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      count = 4;
50457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    }
51457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  for(i=0; i<ecif->cif->nargs; i++)
52457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  {
53457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
54457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    /* variadic args are saved on stack */
55457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    if ((nfixedargs == 0) && (count < 24))
56457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      {
57457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        count = 24;
58457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        stack = stacktemp + 24;
59457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      }
60457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    nfixedargs--;
61457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
62457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    s = 4;
63457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    switch((*arg)->type)
64457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      {
65457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_STRUCT:
66457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        *(void **)stack = *argv;
67457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        break;
68457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
69457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_SINT8:
70457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        *(signed int *) stack = (signed int)*(SINT8 *)(* argv);
71457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        break;
72457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
73457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_UINT8:
74457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        *(unsigned int *) stack = (unsigned int)*(UINT8 *)(* argv);
75457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        break;
76457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
77457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_SINT16:
78457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        *(signed int *) stack = (signed int)*(SINT16 *)(* argv);
79457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        break;
80457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
81457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_UINT16:
82457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        *(unsigned int *) stack = (unsigned int)*(UINT16 *)(* argv);
83457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        break;
84457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
85457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_SINT32:
86457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_UINT32:
87457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_FLOAT:
88457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      case FFI_TYPE_POINTER:
89457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        *(int *)stack = *(int*)(*argv);
90457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        break;
91457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
92457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      default: /* 8 byte types */
93457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        if (count == 20) /* never split arguments */
94457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique          {
95457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique            stack += 4;
96457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique            count += 4;
97457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique          }
98457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        s = (*arg)->size;
99457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        memcpy(stack, *argv, s);
100457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        break;
101457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      }
102457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
103457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    stack += s;
104457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    count += s;
105457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    argv++;
106457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    arg++;
107457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  }
108457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  return stacktemp + ((count>24)?24:0);
109457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique}
110457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
111457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piqueextern void ffi_call_SYSV(unsigned,
112457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique                          extended_cif *,
113457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique                          void *(*)(int *, extended_cif *),
114457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique                          unsigned *,
115457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique                          void (*fn)(void),
116457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique                          unsigned);
117457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
118457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
119457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piquevoid ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
120457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique{
121457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  int i;
122457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  int size;
123457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  ffi_type **arg;
124457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
125457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  /* Calculate size to allocate on stack */
126457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
127457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  for(i = 0, arg = cif->arg_types, size=0; i < cif->nargs; i++, arg++)
128457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    {
129457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      if ((*arg)->type == FFI_TYPE_STRUCT)
130457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        size += 4;
131457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      else
132457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      if ((*arg)->size <= 4)
133457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        size += 4;
134457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      else
135457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        size += 8;
136457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    }
137457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
138457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  /* for variadic functions more space is needed on the stack */
139457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  if (cif->nargs != cif->nfixedargs)
140457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    size += 24;
141457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
142457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  if (cif->rtype->type == FFI_TYPE_STRUCT)
143457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    size += 4;
144457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
145457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
146457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  extended_cif ecif;
147457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  ecif.cif = cif;
148457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  ecif.avalue = avalue;
149457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  ecif.rvalue = rvalue;
150457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
151457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  switch (cif->abi)
152457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  {
153457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    case FFI_SYSV:
154457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      ffi_call_SYSV(size, &ecif, ffi_prep_args, rvalue, fn, cif->flags);
155457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      break;
156457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    default:
157457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      FFI_ASSERT(0);
158457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      break;
159457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  }
160457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique}
161457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
162457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
163457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piquevoid ffi_closure_SYSV(unsigned long r3, unsigned long r4, unsigned long r5,
164457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique                      unsigned long r6, unsigned long r7, unsigned long r8)
165457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique{
166457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  register int *sp __asm__ ("r17");
167457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  register int *r13 __asm__ ("r13");
168457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
169457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  ffi_closure* closure = (ffi_closure*) r13;
170457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  char *stack_args = sp;
171457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
172457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  /* Lay the register arguments down in a continuous chunk of memory.  */
173457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  unsigned register_args[6] =
174457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    { r3, r4, r5, r6, r7, r8 };
175457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
176457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  /* Pointer to a struct return value.  */
177457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  void *struct_rvalue = (void *) r3;
178457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
179457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  ffi_cif *cif = closure->cif;
180457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  ffi_type **arg_types = cif->arg_types;
181457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  void **avalue = alloca (cif->nargs * sizeof(void *));
182457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  char *ptr = (char *) register_args;
183457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  int count = 0;
184457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  int nfixedargs = cif->nfixedargs;
185457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  int i;
186457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
187457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  /* preserve struct type return pointer passing */
188457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
189457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  if ((cif->rtype != NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
190457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  {
191457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    ptr += 4;
192457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    count = 4;
193457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  }
194457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
195457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  /* Find the address of each argument.  */
196457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  for (i = 0; i < cif->nargs; i++)
197457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    {
198457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
199457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      /* variadic args are saved on stack */
200457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      if ((nfixedargs == 0) && (count < 24))
201457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        {
202457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique          ptr = stack_args;
203457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique          count = 24;
204457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        }
205457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      nfixedargs--;
206457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
207457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      switch (arg_types[i]->type)
208457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        {
209457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        case FFI_TYPE_SINT8:
210457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        case FFI_TYPE_UINT8:
211457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique          avalue[i] = ptr + 3;
212457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique          break;
213457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
214457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        case FFI_TYPE_SINT16:
215457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        case FFI_TYPE_UINT16:
216457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique          avalue[i] = ptr + 2;
217457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique          break;
218457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
219457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        case FFI_TYPE_SINT32:
220457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        case FFI_TYPE_UINT32:
221457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        case FFI_TYPE_FLOAT:
222457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        case FFI_TYPE_POINTER:
223457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique          avalue[i] = ptr;
224457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique          break;
225457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
226457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        case FFI_TYPE_STRUCT:
227457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique          avalue[i] = *(void**)ptr;
228457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique          break;
229457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
230457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        default:
231457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique          /* 8-byte values  */
232457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
233457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique          /* arguments are never splitted */
234457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique          if (ptr == &register_args[5])
235457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique            ptr = stack_args;
236457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique          avalue[i] = ptr;
237457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique          ptr += 4;
238457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique          count += 4;
239457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique          break;
240457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        }
241457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      ptr += 4;
242457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      count += 4;
243457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
244457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      /* If we've handled more arguments than fit in registers,
245457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         start looking at the those passed on the stack.  */
246457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
247457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      if (count == 24)
248457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        ptr = stack_args;
249457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    }
250457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
251457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  if (cif->rtype && (cif->rtype->type == FFI_TYPE_STRUCT))
252457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    {
253457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      (closure->fun) (cif, struct_rvalue, avalue, closure->user_data);
254457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    } else
255457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    {
256457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      long long rvalue;
257457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      (closure->fun) (cif, &rvalue, avalue, closure->user_data);
258457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique      if (cif->rtype)
259457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique        asm ("l.ori r12, %0, 0x0\n l.lwz r11, 0(r12)\n l.lwz r12, 4(r12)" : : "r" (&rvalue));
260457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    }
261457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique}
262457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
263457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
264457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piqueffi_status
265457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piqueffi_prep_closure_loc (ffi_closure* closure,
266457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique                      ffi_cif* cif,
267457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique                      void (*fun)(ffi_cif*,void*,void**,void*),
268457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique                      void *user_data,
269457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique                      void *codeloc)
270457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique{
271457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  unsigned short *tramp = (unsigned short *) closure->tramp;
272457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  unsigned long fn = (unsigned long) ffi_closure_SYSV;
273457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  unsigned long cls = (unsigned long) codeloc;
274457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
275457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  if (cif->abi != FFI_SYSV)
276457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    return FFI_BAD_ABI;
277457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
278457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  closure->cif = cif;
279457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  closure->user_data = user_data;
280457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  closure->fun = fun;
281457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
282457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  /* write pointers to temporary registers */
283457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  tramp[0] = (0x6 << 10) | (13 << 5); /* l.movhi r13, ... */
284457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  tramp[1] = cls >> 16;
285457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  tramp[2] = (0x2a << 10) | (13 << 5) | 13; /* l.ori r13, r13, ... */
286457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  tramp[3] = cls & 0xFFFF;
287457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
288457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  tramp[4] = (0x6 << 10) | (15 << 5); /* l.movhi r15, ... */
289457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  tramp[5] = fn >> 16;
290457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  tramp[6] = (0x2a << 10) | (15 << 5) | 15; /* l.ori r15, r15 ... */
291457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  tramp[7] = fn & 0xFFFF;
292457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
293457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  tramp[8] = (0x11 << 10); /* l.jr r15 */
294457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  tramp[9] = 15 << 11;
295457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
296457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  tramp[10] = (0x2a << 10) | (17 << 5) | 1; /* l.ori r17, r1, ... */
297457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  tramp[11] = 0x0;
298457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
299457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  return FFI_OK;
300457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique}
301457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
302457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
303457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piqueffi_status ffi_prep_cif_machdep (ffi_cif *cif)
304457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique{
305457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  cif->flags = 0;
306457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
307457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  /* structures are returned as pointers */
308457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  if (cif->rtype->type == FFI_TYPE_STRUCT)
309457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    cif->flags = FFI_TYPE_STRUCT;
310457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  else
311457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  if (cif->rtype->size > 4)
312457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique    cif->flags = FFI_TYPE_UINT64;
313457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
314457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  cif->nfixedargs = cif->nargs;
315457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
316457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  return FFI_OK;
317457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique}
318457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
319457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
320457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Piqueffi_status ffi_prep_cif_machdep_var(ffi_cif *cif,
321457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique         unsigned int nfixedargs, unsigned int ntotalargs)
322457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique{
323457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  ffi_status status;
324457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique
325457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  status = ffi_prep_cif_machdep (cif);
326457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  cif->nfixedargs = nfixedargs;
327457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique  return status;
328457ba79995d512b9e8c07061fe10d4cd88273b2Lloyd Pique}
329