1baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com/* libffi support for Altera Nios II.
2baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
3baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   Copyright (c) 2013 Mentor Graphics.
4baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
5baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   Permission is hereby granted, free of charge, to any person obtaining
6baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   a copy of this software and associated documentation files (the
7baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   ``Software''), to deal in the Software without restriction, including
8baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   without limitation the rights to use, copy, modify, merge, publish,
9baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   distribute, sublicense, and/or sell copies of the Software, and to
10baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   permit persons to whom the Software is furnished to do so, subject to
11baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   the following conditions:
12baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
13baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   The above copyright notice and this permission notice shall be
14baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   included in all copies or substantial portions of the Software.
15baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
16baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
17baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.  */
23baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
24baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
25baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#include <ffi.h>
26baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#include <ffi_common.h>
27baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
28baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#include <stdlib.h>
29baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
30baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com/* The Nios II Processor Reference Handbook defines the procedure call
31baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   ABI as follows.
32baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
33baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   Arguments are passed as if a structure containing the types of
34baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   the arguments were constructed.  The first 16 bytes are passed in r4
35baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   through r7, the remainder on the stack.  The first 16 bytes of a function
36baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   taking variable arguments are passed in r4-r7 in the same way.
37baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
38baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   Return values of types up to 8 bytes are returned in r2 and r3.  For
39baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   return values greater than 8 bytes, the caller must allocate memory for
40baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   the result and pass the address as if it were argument 0.
41baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
42baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   While this isn't specified explicitly in the ABI documentation, GCC
43baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   promotes integral arguments smaller than int size to 32 bits.
44baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
45baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   Also of note, the ABI specifies that all structure objects are
46baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   aligned to 32 bits even if all their fields have a smaller natural
47baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   alignment.  See FFI_AGGREGATE_ALIGNMENT.  */
48baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
49baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
50baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com/* Declare the assembly language hooks.  */
51baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
52baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comextern UINT64 ffi_call_sysv (void (*) (char *, extended_cif *),
53baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			     extended_cif *,
54baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			     unsigned,
55baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com			     void (*fn) (void));
56baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comextern void ffi_closure_sysv (void);
57baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
58baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com/* Perform machine-dependent cif processing.  */
59baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
60baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comffi_status ffi_prep_cif_machdep (ffi_cif *cif)
61baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com{
62baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* We always want at least 16 bytes in the parameter block since it
63baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     simplifies the low-level call function.  Also round the parameter
64baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     block size up to a multiple of 4 bytes to preserve
65baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     32-bit alignment of the stack pointer.  */
66baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  if (cif->bytes < 16)
67baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    cif->bytes = 16;
68baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  else
69baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    cif->bytes = (cif->bytes + 3) & ~3;
70baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
71baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  return FFI_OK;
72baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com}
73baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
74baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
75baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com/* ffi_prep_args is called by the assembly routine to transfer arguments
76baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   to the stack using the pointers in the ecif array.
77baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   Note that the stack buffer is big enough to fit all the arguments,
78baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   but the first 16 bytes will be copied to registers for the actual
79baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   call.  */
80baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
81baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comvoid ffi_prep_args (char *stack, extended_cif *ecif)
82baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com{
83baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  char *argp = stack;
84baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  unsigned int i;
85baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
86baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* The implicit return value pointer is passed as if it were a hidden
87baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     first argument.  */
88baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  if (ecif->cif->rtype->type == FFI_TYPE_STRUCT
89baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      && ecif->cif->rtype->size > 8)
90baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    {
91baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      (*(void **) argp) = ecif->rvalue;
92baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      argp += 4;
93baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    }
94baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
95baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  for (i = 0; i < ecif->cif->nargs; i++)
96baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    {
97baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      void *avalue = ecif->avalue[i];
98baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      ffi_type *atype = ecif->cif->arg_types[i];
99baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      size_t size = atype->size;
100baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      size_t alignment = atype->alignment;
101baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
102baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      /* Align argp as appropriate for the argument type.  */
103baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      if ((alignment - 1) & (unsigned) argp)
104baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	argp = (char *) ALIGN (argp, alignment);
105baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
106baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      /* Copy the argument, promoting integral types smaller than a
107baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	 word to word size.  */
108baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      if (size < sizeof (int))
109baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	{
110baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  size = sizeof (int);
111baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	  switch (atype->type)
112baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    {
113baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    case FFI_TYPE_SINT8:
114baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      *(signed int *) argp = (signed int) *(SINT8 *) avalue;
115baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      break;
116baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
117baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    case FFI_TYPE_UINT8:
118baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      *(unsigned int *) argp = (unsigned int) *(UINT8 *) avalue;
119baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      break;
120baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
121baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    case FFI_TYPE_SINT16:
122baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      *(signed int *) argp = (signed int) *(SINT16 *) avalue;
123baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      break;
124baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
125baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    case FFI_TYPE_UINT16:
126baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      *(unsigned int *) argp = (unsigned int) *(UINT16 *) avalue;
127baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      break;
128baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
129baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    case FFI_TYPE_STRUCT:
130baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      memcpy (argp, avalue, atype->size);
131baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      break;
132baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
133baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    default:
134baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	      FFI_ASSERT(0);
135baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	    }
136baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	}
137baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      else if (size == sizeof (int))
138baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	*(unsigned int *) argp = (unsigned int) *(UINT32 *) avalue;
139baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      else
140baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	memcpy (argp, avalue, size);
141baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      argp += size;
142baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    }
143baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com}
144baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
145baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
146baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com/* Call FN using the prepared CIF.  RVALUE points to space allocated by
147baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   the caller for the return value, and AVALUE is an array of argument
148baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   pointers.  */
149baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
150baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comvoid ffi_call (ffi_cif *cif, void (*fn) (void), void *rvalue, void **avalue)
151baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com{
152baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
153baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  extended_cif ecif;
154baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  UINT64 result;
155baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
156baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* If bigret is true, this is the case where a return value of larger
157baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     than 8 bytes is handled by being passed by reference as an implicit
158baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     argument.  */
159baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  int bigret = (cif->rtype->type == FFI_TYPE_STRUCT
160baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		&& cif->rtype->size > 8);
161baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
162baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  ecif.cif = cif;
163baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  ecif.avalue = avalue;
164baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
165baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* Allocate space for return value if this is the pass-by-reference case
166baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     and the caller did not provide a buffer.  */
167baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  if (rvalue == NULL && bigret)
168baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    ecif.rvalue = alloca (cif->rtype->size);
169baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  else
170baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    ecif.rvalue = rvalue;
171baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
172baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  result = ffi_call_sysv (ffi_prep_args, &ecif, cif->bytes, fn);
173baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
174baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* Now result contains the 64 bit contents returned from fn in
175baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     r2 and r3.  Copy the value of the appropriate size to the user-provided
176baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     rvalue buffer.  */
177baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  if (rvalue && !bigret)
178baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    switch (cif->rtype->size)
179baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      {
180baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      case 1:
181baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	*(UINT8 *)rvalue = (UINT8) result;
182baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	break;
183baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      case 2:
184baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	*(UINT16 *)rvalue = (UINT16) result;
185baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	break;
186baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      case 4:
187baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	*(UINT32 *)rvalue = (UINT32) result;
188baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	break;
189baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      case 8:
190baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	*(UINT64 *)rvalue = (UINT64) result;
191baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	break;
192baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      default:
193baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	memcpy (rvalue, (void *)&result, cif->rtype->size);
194baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	break;
195baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      }
196baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com}
197baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
198baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com/* This function is invoked from the closure trampoline to invoke
199baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   CLOSURE with argument block ARGS.  Parse ARGS according to
200baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   CLOSURE->cfi and invoke CLOSURE->fun.  */
201baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
202baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comstatic UINT64
203baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comffi_closure_helper (unsigned char *args,
204baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		    ffi_closure *closure)
205baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com{
206baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  ffi_cif *cif = closure->cif;
207baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  unsigned char *argp = args;
208baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  void **parsed_args = alloca (cif->nargs * sizeof (void *));
209baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  UINT64 result;
210baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  void *retptr;
211baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  unsigned int i;
212baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
213baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* First figure out what to do about the return type.  If this is the
214baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     big-structure-return case, the first arg is the hidden return buffer
215baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     allocated by the caller.  */
216baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  if (cif->rtype->type == FFI_TYPE_STRUCT
217baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      && cif->rtype->size > 8)
218baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    {
219baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      retptr = *((void **) argp);
220baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      argp += 4;
221baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    }
222baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  else
223baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    retptr = (void *) &result;
224baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
225baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* Fill in the array of argument pointers.  */
226baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  for (i = 0; i < cif->nargs; i++)
227baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    {
228baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      size_t size = cif->arg_types[i]->size;
229baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      size_t alignment = cif->arg_types[i]->alignment;
230baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
231baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      /* Align argp as appropriate for the argument type.  */
232baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      if ((alignment - 1) & (unsigned) argp)
233baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	argp = (char *) ALIGN (argp, alignment);
234baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
235baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      /* Arguments smaller than an int are promoted to int.  */
236baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      if (size < sizeof (int))
237baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com	size = sizeof (int);
238baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
239baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      /* Store the pointer.  */
240baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      parsed_args[i] = argp;
241baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com      argp += size;
242baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    }
243baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
244baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* Call the user-supplied function.  */
245baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  (closure->fun) (cif, retptr, parsed_args, closure->user_data);
246baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  return result;
247baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com}
248baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
249baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
250baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com/* Initialize CLOSURE with a trampoline to call FUN with
251baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com   CIF and USER_DATA.  */
252baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comffi_status
253baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.comffi_prep_closure_loc (ffi_closure* closure,
254baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      ffi_cif* cif,
255baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      void (*fun) (ffi_cif*, void*, void**, void*),
256baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      void *user_data,
257baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com		      void *codeloc)
258baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com{
259baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  unsigned int *tramp = (unsigned int *) &closure->tramp[0];
260baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  int i;
261baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
262baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  if (cif->abi != FFI_SYSV)
263baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    return FFI_BAD_ABI;
264baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
265baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* The trampoline looks like:
266baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com       movhi r8, %hi(ffi_closure_sysv)
267baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com       ori r8, r8, %lo(ffi_closure_sysv)
268baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com       movhi r9, %hi(ffi_closure_helper)
269baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com       ori r0, r9, %lo(ffi_closure_helper)
270baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com       movhi r10, %hi(closure)
271baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com       ori r10, r10, %lo(closure)
272baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com       jmp r8
273baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     and then ffi_closure_sysv retrieves the closure pointer out of r10
274baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     in addition to the arguments passed in the normal way for the call,
275baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     and invokes ffi_closure_helper.  We encode the pointer to
276baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     ffi_closure_helper in the trampoline because making a PIC call
277baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     to it in ffi_closure_sysv would be messy (it would have to indirect
278baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     through the GOT).  */
279baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
280baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#define HI(x) ((((unsigned int) (x)) >> 16) & 0xffff)
281baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#define LO(x) (((unsigned int) (x)) & 0xffff)
282baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  tramp[0] = (0 << 27) | (8 << 22) | (HI (ffi_closure_sysv) << 6) | 0x34;
283baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  tramp[1] = (8 << 27) | (8 << 22) | (LO (ffi_closure_sysv) << 6) | 0x14;
284baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  tramp[2] = (0 << 27) | (9 << 22) | (HI (ffi_closure_helper) << 6) | 0x34;
285baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  tramp[3] = (9 << 27) | (9 << 22) | (LO (ffi_closure_helper) << 6) | 0x14;
286baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  tramp[4] = (0 << 27) | (10 << 22) | (HI (closure) << 6) | 0x34;
287baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  tramp[5] = (10 << 27) | (10 << 22) | (LO (closure) << 6) | 0x14;
288baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  tramp[6] = (8 << 27) | (0x0d << 11) | 0x3a;
289baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#undef HI
290baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com#undef LO
291baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
292baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  /* Flush the caches.
293baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com     See Example 9-4 in the Nios II Software Developer's Handbook.  */
294baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  for (i = 0; i < 7; i++)
295baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com    asm volatile ("flushd 0(%0); flushi %0" :: "r"(tramp + i) : "memory");
296baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  asm volatile ("flushp" ::: "memory");
297baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
298baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  closure->cif = cif;
299baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  closure->fun = fun;
300baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  closure->user_data = user_data;
301baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
302baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com  return FFI_OK;
303baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com}
304baa84b827b80380ff181757e2997e5648e69b1e4doko@ubuntu.com
305