1/* -----------------------------------------------------------------------
2   ffi.c - Copyright (c) 1998 Cygnus Solutions
3           Copyright (c) 2004 Simon Posnjak
4	   Copyright (c) 2005 Axis Communications AB
5	   Copyright (C) 2007 Free Software Foundation, Inc.
6
7   CRIS Foreign Function Interface
8
9   Permission is hereby granted, free of charge, to any person obtaining
10   a copy of this software and associated documentation files (the
11   ``Software''), to deal in the Software without restriction, including
12   without limitation the rights to use, copy, modify, merge, publish,
13   distribute, sublicense, and/or sell copies of the Software, and to
14   permit persons to whom the Software is furnished to do so, subject to
15   the following conditions:
16
17   The above copyright notice and this permission notice shall be included
18   in all copies or substantial portions of the Software.
19
20   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
21   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23   IN NO EVENT SHALL SIMON POSNJAK BE LIABLE FOR ANY CLAIM, DAMAGES OR
24   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26   OTHER DEALINGS IN THE SOFTWARE.
27   ----------------------------------------------------------------------- */
28
29#include <ffi.h>
30#include <ffi_common.h>
31
32#define STACK_ARG_SIZE(x) ALIGN(x, FFI_SIZEOF_ARG)
33
34static ffi_status
35initialize_aggregate_packed_struct (ffi_type * arg)
36{
37  ffi_type **ptr;
38
39  FFI_ASSERT (arg != NULL);
40
41  FFI_ASSERT (arg->elements != NULL);
42  FFI_ASSERT (arg->size == 0);
43  FFI_ASSERT (arg->alignment == 0);
44
45  ptr = &(arg->elements[0]);
46
47  while ((*ptr) != NULL)
48    {
49      if (((*ptr)->size == 0)
50	  && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
51	return FFI_BAD_TYPEDEF;
52
53      FFI_ASSERT (ffi_type_test ((*ptr)));
54
55      arg->size += (*ptr)->size;
56
57      arg->alignment = (arg->alignment > (*ptr)->alignment) ?
58	arg->alignment : (*ptr)->alignment;
59
60      ptr++;
61    }
62
63  if (arg->size == 0)
64    return FFI_BAD_TYPEDEF;
65  else
66    return FFI_OK;
67}
68
69int
70ffi_prep_args (char *stack, extended_cif * ecif)
71{
72  unsigned int i;
73  unsigned int struct_count = 0;
74  void **p_argv;
75  char *argp;
76  ffi_type **p_arg;
77
78  argp = stack;
79
80  p_argv = ecif->avalue;
81
82  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
83       (i != 0); i--, p_arg++)
84    {
85      size_t z;
86
87      switch ((*p_arg)->type)
88	{
89	case FFI_TYPE_STRUCT:
90	  {
91	    z = (*p_arg)->size;
92	    if (z <= 4)
93	      {
94		memcpy (argp, *p_argv, z);
95		z = 4;
96	      }
97	    else if (z <= 8)
98	      {
99		memcpy (argp, *p_argv, z);
100		z = 8;
101	      }
102	    else
103	      {
104		unsigned int uiLocOnStack;
105		z = sizeof (void *);
106		uiLocOnStack = 4 * ecif->cif->nargs + struct_count;
107		struct_count = struct_count + (*p_arg)->size;
108		*(unsigned int *) argp =
109		  (unsigned int) (UINT32 *) (stack + uiLocOnStack);
110		memcpy ((stack + uiLocOnStack), *p_argv, (*p_arg)->size);
111	      }
112	    break;
113	  }
114	default:
115	  z = (*p_arg)->size;
116	  if (z < sizeof (int))
117	    {
118	      switch ((*p_arg)->type)
119		{
120		case FFI_TYPE_SINT8:
121		  *(signed int *) argp = (signed int) *(SINT8 *) (*p_argv);
122		  break;
123
124		case FFI_TYPE_UINT8:
125		  *(unsigned int *) argp =
126		    (unsigned int) *(UINT8 *) (*p_argv);
127		  break;
128
129		case FFI_TYPE_SINT16:
130		  *(signed int *) argp = (signed int) *(SINT16 *) (*p_argv);
131		  break;
132
133		case FFI_TYPE_UINT16:
134		  *(unsigned int *) argp =
135		    (unsigned int) *(UINT16 *) (*p_argv);
136		  break;
137
138		default:
139		  FFI_ASSERT (0);
140		}
141	      z = sizeof (int);
142	    }
143	  else if (z == sizeof (int))
144	    *(unsigned int *) argp = (unsigned int) *(UINT32 *) (*p_argv);
145	  else
146	    memcpy (argp, *p_argv, z);
147	  break;
148	}
149      p_argv++;
150      argp += z;
151    }
152
153  return (struct_count);
154}
155
156ffi_status
157ffi_prep_cif (ffi_cif * cif,
158	      ffi_abi abi, unsigned int nargs,
159	      ffi_type * rtype, ffi_type ** atypes)
160{
161  unsigned bytes = 0;
162  unsigned int i;
163  ffi_type **ptr;
164
165  FFI_ASSERT (cif != NULL);
166  FFI_ASSERT ((abi > FFI_FIRST_ABI) && (abi <= FFI_DEFAULT_ABI));
167
168  cif->abi = abi;
169  cif->arg_types = atypes;
170  cif->nargs = nargs;
171  cif->rtype = rtype;
172
173  cif->flags = 0;
174
175  if ((cif->rtype->size == 0)
176      && (initialize_aggregate_packed_struct (cif->rtype) != FFI_OK))
177    return FFI_BAD_TYPEDEF;
178
179  FFI_ASSERT_VALID_TYPE (cif->rtype);
180
181  for (ptr = cif->arg_types, i = cif->nargs; i > 0; i--, ptr++)
182    {
183      if (((*ptr)->size == 0)
184	  && (initialize_aggregate_packed_struct ((*ptr)) != FFI_OK))
185	return FFI_BAD_TYPEDEF;
186
187      FFI_ASSERT_VALID_TYPE (*ptr);
188
189      if (((*ptr)->alignment - 1) & bytes)
190	bytes = ALIGN (bytes, (*ptr)->alignment);
191      if ((*ptr)->type == FFI_TYPE_STRUCT)
192	{
193	  if ((*ptr)->size > 8)
194	    {
195	      bytes += (*ptr)->size;
196	      bytes += sizeof (void *);
197	    }
198	  else
199	    {
200	      if ((*ptr)->size > 4)
201		bytes += 8;
202	      else
203		bytes += 4;
204	    }
205	}
206      else
207	bytes += STACK_ARG_SIZE ((*ptr)->size);
208    }
209
210  cif->bytes = bytes;
211
212  return ffi_prep_cif_machdep (cif);
213}
214
215ffi_status
216ffi_prep_cif_machdep (ffi_cif * cif)
217{
218  switch (cif->rtype->type)
219    {
220    case FFI_TYPE_VOID:
221    case FFI_TYPE_STRUCT:
222    case FFI_TYPE_FLOAT:
223    case FFI_TYPE_DOUBLE:
224    case FFI_TYPE_SINT64:
225    case FFI_TYPE_UINT64:
226      cif->flags = (unsigned) cif->rtype->type;
227      break;
228
229    default:
230      cif->flags = FFI_TYPE_INT;
231      break;
232    }
233
234  return FFI_OK;
235}
236
237extern void ffi_call_SYSV (int (*)(char *, extended_cif *),
238			   extended_cif *,
239			   unsigned, unsigned, unsigned *, void (*fn) ())
240     __attribute__ ((__visibility__ ("hidden")));
241
242void
243ffi_call (ffi_cif * cif, void (*fn) (), void *rvalue, void **avalue)
244{
245  extended_cif ecif;
246
247  ecif.cif = cif;
248  ecif.avalue = avalue;
249
250  if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT))
251    {
252      ecif.rvalue = alloca (cif->rtype->size);
253    }
254  else
255    ecif.rvalue = rvalue;
256
257  switch (cif->abi)
258    {
259    case FFI_SYSV:
260      ffi_call_SYSV (ffi_prep_args, &ecif, cif->bytes,
261		     cif->flags, ecif.rvalue, fn);
262      break;
263    default:
264      FFI_ASSERT (0);
265      break;
266    }
267}
268
269/* Because the following variables are not exported outside libffi, we
270   mark them hidden.  */
271
272/* Assembly code for the jump stub.  */
273extern const char ffi_cris_trampoline_template[]
274 __attribute__ ((__visibility__ ("hidden")));
275
276/* Offset into ffi_cris_trampoline_template of where to put the
277   ffi_prep_closure_inner function.  */
278extern const int ffi_cris_trampoline_fn_offset
279 __attribute__ ((__visibility__ ("hidden")));
280
281/* Offset into ffi_cris_trampoline_template of where to put the
282   closure data.  */
283extern const int ffi_cris_trampoline_closure_offset
284 __attribute__ ((__visibility__ ("hidden")));
285
286/* This function is sibling-called (jumped to) by the closure
287   trampoline.  We get R10..R13 at PARAMS[0..3] and a copy of [SP] at
288   PARAMS[4] to simplify handling of a straddling parameter.  A copy
289   of R9 is at PARAMS[5] and SP at PARAMS[6].  These parameters are
290   put at the appropriate place in CLOSURE which is then executed and
291   the return value is passed back to the caller.  */
292
293static unsigned long long
294ffi_prep_closure_inner (void **params, ffi_closure* closure)
295{
296  char *register_args = (char *) params;
297  void *struct_ret = params[5];
298  char *stack_args = params[6];
299  char *ptr = register_args;
300  ffi_cif *cif = closure->cif;
301  ffi_type **arg_types = cif->arg_types;
302
303  /* Max room needed is number of arguments as 64-bit values.  */
304  void **avalue = alloca (closure->cif->nargs * sizeof(void *));
305  int i;
306  int doing_regs;
307  long long llret = 0;
308
309  /* Find the address of each argument.  */
310  for (i = 0, doing_regs = 1; i < cif->nargs; i++)
311    {
312      /* Types up to and including 8 bytes go by-value.  */
313      if (arg_types[i]->size <= 4)
314	{
315	  avalue[i] = ptr;
316	  ptr += 4;
317	}
318      else if (arg_types[i]->size <= 8)
319	{
320	  avalue[i] = ptr;
321	  ptr += 8;
322	}
323      else
324	{
325	  FFI_ASSERT (arg_types[i]->type == FFI_TYPE_STRUCT);
326
327	  /* Passed by-reference, so copy the pointer.  */
328	  avalue[i] = *(void **) ptr;
329	  ptr += 4;
330	}
331
332      /* If we've handled more arguments than fit in registers, start
333	 looking at the those passed on the stack.  Step over the
334	 first one if we had a straddling parameter.  */
335      if (doing_regs && ptr >= register_args + 4*4)
336	{
337	  ptr = stack_args + ((ptr > register_args + 4*4) ? 4 : 0);
338	  doing_regs = 0;
339	}
340    }
341
342  /* Invoke the closure.  */
343  (closure->fun) (cif,
344
345		  cif->rtype->type == FFI_TYPE_STRUCT
346		  /* The caller allocated space for the return
347		     structure, and passed a pointer to this space in
348		     R9.  */
349		  ? struct_ret
350
351		  /* We take advantage of being able to ignore that
352		     the high part isn't set if the return value is
353		     not in R10:R11, but in R10 only.  */
354		  : (void *) &llret,
355
356		  avalue, closure->user_data);
357
358  return llret;
359}
360
361/* API function: Prepare the trampoline.  */
362
363ffi_status
364ffi_prep_closure_loc (ffi_closure* closure,
365		      ffi_cif* cif,
366		      void (*fun)(ffi_cif *, void *, void **, void*),
367		      void *user_data,
368		      void *codeloc)
369{
370  void *innerfn = ffi_prep_closure_inner;
371  FFI_ASSERT (cif->abi == FFI_SYSV);
372  closure->cif  = cif;
373  closure->user_data = user_data;
374  closure->fun  = fun;
375  memcpy (closure->tramp, ffi_cris_trampoline_template,
376	  FFI_CRIS_TRAMPOLINE_CODE_PART_SIZE);
377  memcpy (closure->tramp + ffi_cris_trampoline_fn_offset,
378	  &innerfn, sizeof (void *));
379  memcpy (closure->tramp + ffi_cris_trampoline_closure_offset,
380	  &codeloc, sizeof (void *));
381
382  return FFI_OK;
383}
384