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
35void *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 */
107ffi_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
119extern void ffi_call_EABI(void *(*)(char *, extended_cif *),
120			  extended_cif *,
121			  unsigned, unsigned,
122			  unsigned *,
123			  void (*fn)(void));
124
125void 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
158void 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
244ffi_status
245ffi_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}
273