1/* -----------------------------------------------------------------------
2   ffi.c - Copyright (C) 2004  Anthony Green
3   Copyright (C) 2007  Free Software Foundation, Inc.
4	   Copyright (C) 2008  Red Hat, Inc.
5
6   FR-V Foreign Function Interface
7
8   Permission is hereby granted, free of charge, to any person obtaining
9   a copy of this software and associated documentation files (the
10   ``Software''), to deal in the Software without restriction, including
11   without limitation the rights to use, copy, modify, merge, publish,
12   distribute, sublicense, and/or sell copies of the Software, and to
13   permit persons to whom the Software is furnished to do so, subject to
14   the following conditions:
15
16   The above copyright notice and this permission notice shall be included
17   in all copies or substantial portions of the Software.
18
19   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
20   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26   DEALINGS IN THE SOFTWARE.
27   ----------------------------------------------------------------------- */
28
29#include <ffi.h>
30#include <ffi_common.h>
31
32#include <stdlib.h>
33
34/* ffi_prep_args is called by the assembly routine once stack space
35   has been allocated for the function's arguments */
36
37void *ffi_prep_args(char *stack, extended_cif *ecif)
38{
39  register unsigned int i;
40  register void **p_argv;
41  register char *argp;
42  register ffi_type **p_arg;
43  register int count = 0;
44
45  p_argv = ecif->avalue;
46  argp = stack;
47
48  for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types;
49       (i != 0);
50       i--, p_arg++)
51    {
52      size_t z;
53
54      z = (*p_arg)->size;
55
56      if ((*p_arg)->type == FFI_TYPE_STRUCT)
57	{
58	  z = sizeof(void*);
59	  *(void **) argp = *p_argv;
60	}
61      /*      if ((*p_arg)->type == FFI_TYPE_FLOAT)
62	{
63	  if (count > 24)
64	    {
65	      // This is going on the stack.  Turn it into a double.
66	      *(double *) argp = (double) *(float*)(* p_argv);
67	      z = sizeof(double);
68	    }
69	  else
70	    *(void **) argp = *(void **)(* p_argv);
71	}  */
72      else if (z < sizeof(int))
73	{
74	  z = sizeof(int);
75	  switch ((*p_arg)->type)
76	    {
77	    case FFI_TYPE_SINT8:
78	      *(signed int *) argp = (signed int)*(SINT8 *)(* p_argv);
79	      break;
80
81	    case FFI_TYPE_UINT8:
82	      *(unsigned int *) argp = (unsigned int)*(UINT8 *)(* p_argv);
83	      break;
84
85	    case FFI_TYPE_SINT16:
86	      *(signed int *) argp = (signed int)*(SINT16 *)(* p_argv);
87	      break;
88
89	    case FFI_TYPE_UINT16:
90	      *(unsigned int *) argp = (unsigned int)*(UINT16 *)(* p_argv);
91	      break;
92
93	    default:
94	      FFI_ASSERT(0);
95	    }
96	}
97      else if (z == sizeof(int))
98	{
99	  *(unsigned int *) argp = (unsigned int)*(UINT32 *)(* p_argv);
100	}
101      else
102	{
103	  memcpy(argp, *p_argv, z);
104	}
105      p_argv++;
106      argp += z;
107      count += z;
108    }
109
110  return (stack + ((count > 24) ? 24 : ALIGN_DOWN(count, 8)));
111}
112
113/* Perform machine dependent cif processing */
114ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
115{
116  if (cif->rtype->type == FFI_TYPE_STRUCT)
117    cif->flags = -1;
118  else
119    cif->flags = cif->rtype->size;
120
121  cif->bytes = ALIGN (cif->bytes, 8);
122
123  return FFI_OK;
124}
125
126extern void ffi_call_EABI(void *(*)(char *, extended_cif *),
127			  extended_cif *,
128			  unsigned, unsigned,
129			  unsigned *,
130			  void (*fn)(void));
131
132void ffi_call(ffi_cif *cif,
133	      void (*fn)(void),
134	      void *rvalue,
135	      void **avalue)
136{
137  extended_cif ecif;
138
139  ecif.cif = cif;
140  ecif.avalue = avalue;
141
142  /* If the return value is a struct and we don't have a return	*/
143  /* value address then we need to make one		        */
144
145  if ((rvalue == NULL) &&
146      (cif->rtype->type == FFI_TYPE_STRUCT))
147    {
148      ecif.rvalue = alloca(cif->rtype->size);
149    }
150  else
151    ecif.rvalue = rvalue;
152
153
154  switch (cif->abi)
155    {
156    case FFI_EABI:
157      ffi_call_EABI(ffi_prep_args, &ecif, cif->bytes,
158		    cif->flags, ecif.rvalue, fn);
159      break;
160    default:
161      FFI_ASSERT(0);
162      break;
163    }
164}
165
166void ffi_closure_eabi (unsigned arg1, unsigned arg2, unsigned arg3,
167		       unsigned arg4, unsigned arg5, unsigned arg6)
168{
169  /* This function is called by a trampoline.  The trampoline stows a
170     pointer to the ffi_closure object in gr7.  We must save this
171     pointer in a place that will persist while we do our work.  */
172  register ffi_closure *creg __asm__ ("gr7");
173  ffi_closure *closure = creg;
174
175  /* Arguments that don't fit in registers are found on the stack
176     at a fixed offset above the current frame pointer.  */
177  register char *frame_pointer __asm__ ("fp");
178  char *stack_args = frame_pointer + 16;
179
180  /* Lay the register arguments down in a continuous chunk of memory.  */
181  unsigned register_args[6] =
182    { arg1, arg2, arg3, arg4, arg5, arg6 };
183
184  ffi_cif *cif = closure->cif;
185  ffi_type **arg_types = cif->arg_types;
186  void **avalue = alloca (cif->nargs * sizeof(void *));
187  char *ptr = (char *) register_args;
188  int i;
189
190  /* Find the address of each argument.  */
191  for (i = 0; i < cif->nargs; i++)
192    {
193      switch (arg_types[i]->type)
194	{
195	case FFI_TYPE_SINT8:
196	case FFI_TYPE_UINT8:
197	  avalue[i] = ptr + 3;
198	  break;
199	case FFI_TYPE_SINT16:
200	case FFI_TYPE_UINT16:
201	  avalue[i] = ptr + 2;
202	  break;
203	case FFI_TYPE_SINT32:
204	case FFI_TYPE_UINT32:
205	case FFI_TYPE_FLOAT:
206	  avalue[i] = ptr;
207	  break;
208	case FFI_TYPE_STRUCT:
209	  avalue[i] = *(void**)ptr;
210	  break;
211	default:
212	  /* This is an 8-byte value.  */
213	  avalue[i] = ptr;
214	  ptr += 4;
215	  break;
216	}
217      ptr += 4;
218
219      /* If we've handled more arguments than fit in registers,
220	 start looking at the those passed on the stack.  */
221      if (ptr == ((char *)register_args + (6*4)))
222	ptr = stack_args;
223    }
224
225  /* Invoke the closure.  */
226  if (cif->rtype->type == FFI_TYPE_STRUCT)
227    {
228      /* The caller allocates space for the return structure, and
229       passes a pointer to this space in gr3.  Use this value directly
230       as the return value.  */
231      register void *return_struct_ptr __asm__("gr3");
232      (closure->fun) (cif, return_struct_ptr, avalue, closure->user_data);
233    }
234  else
235    {
236      /* Allocate space for the return value and call the function.  */
237      long long rvalue;
238      (closure->fun) (cif, &rvalue, avalue, closure->user_data);
239
240      /* Functions return 4-byte or smaller results in gr8.  8-byte
241	 values also use gr9.  We fill the both, even for small return
242	 values, just to avoid a branch.  */
243      asm ("ldi  @(%0, #0), gr8" : : "r" (&rvalue));
244      asm ("ldi  @(%0, #0), gr9" : : "r" (&((int *) &rvalue)[1]));
245    }
246}
247
248ffi_status
249ffi_prep_closure_loc (ffi_closure* closure,
250		      ffi_cif* cif,
251		      void (*fun)(ffi_cif*, void*, void**, void*),
252		      void *user_data,
253		      void *codeloc)
254{
255  unsigned int *tramp = (unsigned int *) &closure->tramp[0];
256  unsigned long fn = (long) ffi_closure_eabi;
257  unsigned long cls = (long) codeloc;
258#ifdef __FRV_FDPIC__
259  register void *got __asm__("gr15");
260#endif
261  int i;
262
263  fn = (unsigned long) ffi_closure_eabi;
264
265#ifdef __FRV_FDPIC__
266  tramp[0] = &((unsigned int *)codeloc)[2];
267  tramp[1] = got;
268  tramp[2] = 0x8cfc0000 + (fn  & 0xffff); /* setlos lo(fn), gr6    */
269  tramp[3] = 0x8efc0000 + (cls & 0xffff); /* setlos lo(cls), gr7   */
270  tramp[4] = 0x8cf80000 + (fn  >> 16);	  /* sethi hi(fn), gr6     */
271  tramp[5] = 0x8ef80000 + (cls >> 16);    /* sethi hi(cls), gr7    */
272  tramp[6] = 0x9cc86000;                  /* ldi @(gr6, #0), gr14  */
273  tramp[7] = 0x8030e000;                  /* jmpl @(gr14, gr0)     */
274#else
275  tramp[0] = 0x8cfc0000 + (fn  & 0xffff); /* setlos lo(fn), gr6    */
276  tramp[1] = 0x8efc0000 + (cls & 0xffff); /* setlos lo(cls), gr7   */
277  tramp[2] = 0x8cf80000 + (fn  >> 16);	  /* sethi hi(fn), gr6     */
278  tramp[3] = 0x8ef80000 + (cls >> 16);    /* sethi hi(cls), gr7    */
279  tramp[4] = 0x80300006;                  /* jmpl @(gr0, gr6)      */
280#endif
281
282  closure->cif = cif;
283  closure->fun = fun;
284  closure->user_data = user_data;
285
286  /* Cache flushing.  */
287  for (i = 0; i < FFI_TRAMPOLINE_SIZE; i++)
288    __asm__ volatile ("dcf @(%0,%1)\n\tici @(%2,%1)" :: "r" (tramp), "r" (i),
289		      "r" (codeloc));
290
291  return FFI_OK;
292}
293