• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -----------------------------------------------------------------------
2    ffi.c - Copyright (c) 2011, 2013 Anthony Green
3            Copyright (c) 1996, 2003-2004, 2007-2008 Red Hat, Inc.
4 
5    SPARC Foreign Function Interface
6 
7    Permission is hereby granted, free of charge, to any person obtaining
8    a copy of this software and associated documentation files (the
9    ``Software''), to deal in the Software without restriction, including
10    without limitation the rights to use, copy, modify, merge, publish,
11    distribute, sublicense, and/or sell copies of the Software, and to
12    permit persons to whom the Software is furnished to do so, subject to
13    the following conditions:
14 
15    The above copyright notice and this permission notice shall be included
16    in all copies or substantial portions of the Software.
17 
18    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
19    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21    NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25    DEALINGS IN THE SOFTWARE.
26    ----------------------------------------------------------------------- */
27 
28 #include <ffi.h>
29 #include <ffi_common.h>
30 #include <stdlib.h>
31 #include "internal.h"
32 
33 #ifndef SPARC64
34 
35 /* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
36    all further uses in this file will refer to the 128-bit type.  */
37 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
38 # if FFI_TYPE_LONGDOUBLE != 4
39 #  error FFI_TYPE_LONGDOUBLE out of date
40 # endif
41 #else
42 # undef FFI_TYPE_LONGDOUBLE
43 # define FFI_TYPE_LONGDOUBLE 4
44 #endif
45 
46 /* Perform machine dependent cif processing */
47 ffi_status FFI_HIDDEN
ffi_prep_cif_machdep(ffi_cif * cif)48 ffi_prep_cif_machdep(ffi_cif *cif)
49 {
50   ffi_type *rtype = cif->rtype;
51   int rtt = rtype->type;
52   size_t bytes;
53   int i, n, flags;
54 
55   /* Set the return type flag */
56   switch (rtt)
57     {
58     case FFI_TYPE_VOID:
59       flags = SPARC_RET_VOID;
60       break;
61     case FFI_TYPE_FLOAT:
62       flags = SPARC_RET_F_1;
63       break;
64     case FFI_TYPE_DOUBLE:
65       flags = SPARC_RET_F_2;
66       break;
67     case FFI_TYPE_LONGDOUBLE:
68     case FFI_TYPE_STRUCT:
69       flags = (rtype->size & 0xfff) << SPARC_SIZEMASK_SHIFT;
70       flags |= SPARC_RET_STRUCT;
71       break;
72     case FFI_TYPE_SINT8:
73       flags = SPARC_RET_SINT8;
74       break;
75     case FFI_TYPE_UINT8:
76       flags = SPARC_RET_UINT8;
77       break;
78     case FFI_TYPE_SINT16:
79       flags = SPARC_RET_SINT16;
80       break;
81     case FFI_TYPE_UINT16:
82       flags = SPARC_RET_UINT16;
83       break;
84     case FFI_TYPE_INT:
85     case FFI_TYPE_SINT32:
86     case FFI_TYPE_UINT32:
87     case FFI_TYPE_POINTER:
88       flags = SPARC_RET_UINT32;
89       break;
90     case FFI_TYPE_SINT64:
91     case FFI_TYPE_UINT64:
92       flags = SPARC_RET_INT64;
93       break;
94     case FFI_TYPE_COMPLEX:
95       rtt = rtype->elements[0]->type;
96       switch (rtt)
97 	{
98 	case FFI_TYPE_FLOAT:
99 	  flags = SPARC_RET_F_2;
100 	  break;
101 	case FFI_TYPE_DOUBLE:
102 	  flags = SPARC_RET_F_4;
103 	  break;
104 	case FFI_TYPE_LONGDOUBLE:
105 	  flags = SPARC_RET_F_8;
106 	  break;
107 	case FFI_TYPE_SINT64:
108 	case FFI_TYPE_UINT64:
109 	  flags = SPARC_RET_INT128;
110 	  break;
111 	case FFI_TYPE_INT:
112 	case FFI_TYPE_SINT32:
113 	case FFI_TYPE_UINT32:
114 	  flags = SPARC_RET_INT64;
115 	  break;
116 	case FFI_TYPE_SINT16:
117 	case FFI_TYPE_UINT16:
118 	  flags = SP_V8_RET_CPLX16;
119 	  break;
120 	case FFI_TYPE_SINT8:
121 	case FFI_TYPE_UINT8:
122 	  flags = SP_V8_RET_CPLX8;
123 	  break;
124 	default:
125 	  abort();
126 	}
127       break;
128     default:
129       abort();
130     }
131   cif->flags = flags;
132 
133   bytes = 0;
134   for (i = 0, n = cif->nargs; i < n; ++i)
135     {
136       ffi_type *ty = cif->arg_types[i];
137       size_t z = ty->size;
138       int tt = ty->type;
139 
140       switch (tt)
141 	{
142 	case FFI_TYPE_STRUCT:
143 	case FFI_TYPE_LONGDOUBLE:
144 	by_reference:
145 	  /* Passed by reference.  */
146 	  z = 4;
147 	  break;
148 
149 	case FFI_TYPE_COMPLEX:
150 	  tt = ty->elements[0]->type;
151 	  if (tt == FFI_TYPE_FLOAT || z > 8)
152 	    goto by_reference;
153 	  /* FALLTHRU */
154 
155 	default:
156 	  z = FFI_ALIGN(z, 4);
157 	}
158       bytes += z;
159     }
160 
161   /* Sparc call frames require that space is allocated for 6 args,
162      even if they aren't used. Make that space if necessary.  */
163   if (bytes < 6 * 4)
164     bytes = 6 * 4;
165 
166   /* The ABI always requires space for the struct return pointer.  */
167   bytes += 4;
168 
169   /* The stack must be 2 word aligned, so round bytes up appropriately. */
170   bytes = FFI_ALIGN(bytes, 2 * 4);
171 
172   /* Include the call frame to prep_args.  */
173   bytes += 4*16 + 4*8;
174   cif->bytes = bytes;
175 
176   return FFI_OK;
177 }
178 
179 extern void ffi_call_v8(ffi_cif *cif, void (*fn)(void), void *rvalue,
180 			void **avalue, size_t bytes, void *closure) FFI_HIDDEN;
181 
182 int FFI_HIDDEN
ffi_prep_args_v8(ffi_cif * cif,unsigned long * argp,void * rvalue,void ** avalue)183 ffi_prep_args_v8(ffi_cif *cif, unsigned long *argp, void *rvalue, void **avalue)
184 {
185   ffi_type **p_arg;
186   int flags = cif->flags;
187   int i, nargs;
188 
189   if (rvalue == NULL)
190     {
191       if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
192 	{
193 	  /* Since we pass the pointer to the callee, we need a value.
194 	     We allowed for this space in ffi_call, before ffi_call_v8
195 	     alloca'd the space.  */
196 	  rvalue = (char *)argp + cif->bytes;
197 	}
198       else
199 	{
200 	  /* Otherwise, we can ignore the return value.  */
201 	  flags = SPARC_RET_VOID;
202 	}
203     }
204 
205   /* This could only really be done when we are returning a structure.
206      However, the space is reserved so we can do it unconditionally.  */
207   *argp++ = (unsigned long)rvalue;
208 
209 #ifdef USING_PURIFY
210   /* Purify will probably complain in our assembly routine,
211      unless we zero out this memory. */
212   memset(argp, 0, 6*4);
213 #endif
214 
215   p_arg = cif->arg_types;
216   for (i = 0, nargs = cif->nargs; i < nargs; i++)
217     {
218       ffi_type *ty = p_arg[i];
219       void *a = avalue[i];
220       int tt = ty->type;
221       size_t z;
222 
223       switch (tt)
224 	{
225 	case FFI_TYPE_STRUCT:
226 	case FFI_TYPE_LONGDOUBLE:
227 	by_reference:
228 	  *argp++ = (unsigned long)a;
229 	  break;
230 
231 	case FFI_TYPE_DOUBLE:
232 	case FFI_TYPE_UINT64:
233 	case FFI_TYPE_SINT64:
234 	  memcpy(argp, a, 8);
235 	  argp += 2;
236 	  break;
237 
238 	case FFI_TYPE_INT:
239 	case FFI_TYPE_FLOAT:
240 	case FFI_TYPE_UINT32:
241 	case FFI_TYPE_SINT32:
242 	case FFI_TYPE_POINTER:
243 	  *argp++ = *(unsigned *)a;
244 	  break;
245 
246 	case FFI_TYPE_UINT8:
247 	  *argp++ = *(UINT8 *)a;
248 	  break;
249 	case FFI_TYPE_SINT8:
250 	  *argp++ = *(SINT8 *)a;
251 	  break;
252 	case FFI_TYPE_UINT16:
253 	  *argp++ = *(UINT16 *)a;
254 	  break;
255 	case FFI_TYPE_SINT16:
256 	  *argp++ = *(SINT16 *)a;
257 	  break;
258 
259         case FFI_TYPE_COMPLEX:
260 	  tt = ty->elements[0]->type;
261 	  z = ty->size;
262 	  if (tt == FFI_TYPE_FLOAT || z > 8)
263 	    goto by_reference;
264 	  if (z < 4)
265 	    {
266 	      memcpy((char *)argp + 4 - z, a, z);
267 	      argp++;
268 	    }
269 	  else
270 	    {
271 	      memcpy(argp, a, z);
272 	      argp += z / 4;
273 	    }
274 	  break;
275 
276 	default:
277 	  abort();
278 	}
279     }
280 
281   return flags;
282 }
283 
284 static void
ffi_call_int(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue,void * closure)285 ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
286 	      void **avalue, void *closure)
287 {
288   size_t bytes = cif->bytes;
289 
290   FFI_ASSERT (cif->abi == FFI_V8);
291 
292   /* If we've not got a return value, we need to create one if we've
293      got to pass the return value to the callee.  Otherwise ignore it.  */
294   if (rvalue == NULL
295       && (cif->flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
296     bytes += FFI_ALIGN (cif->rtype->size, 8);
297 
298   ffi_call_v8(cif, fn, rvalue, avalue, -bytes, closure);
299 }
300 
301 void
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)302 ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
303 {
304   ffi_call_int (cif, fn, rvalue, avalue, NULL);
305 }
306 
307 void
ffi_call_go(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue,void * closure)308 ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
309 	     void **avalue, void *closure)
310 {
311   ffi_call_int (cif, fn, rvalue, avalue, closure);
312 }
313 
314 #ifdef __GNUC__
315 static inline void
ffi_flush_icache(void * p)316 ffi_flush_icache (void *p)
317 {
318   /* SPARC v8 requires 5 instructions for flush to be visible */
319   asm volatile ("iflush	%0; iflush %0+8; nop; nop; nop; nop; nop"
320 		: : "r" (p) : "memory");
321 }
322 #else
323 extern void ffi_flush_icache (void *) FFI_HIDDEN;
324 #endif
325 
326 extern void ffi_closure_v8(void) FFI_HIDDEN;
327 extern void ffi_go_closure_v8(void) FFI_HIDDEN;
328 
329 ffi_status
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)330 ffi_prep_closure_loc (ffi_closure *closure,
331 		      ffi_cif *cif,
332 		      void (*fun)(ffi_cif*, void*, void**, void*),
333 		      void *user_data,
334 		      void *codeloc)
335 {
336   unsigned int *tramp = (unsigned int *) &closure->tramp[0];
337   unsigned long ctx = (unsigned long) closure;
338   unsigned long fn = (unsigned long) ffi_closure_v8;
339 
340   if (cif->abi != FFI_V8)
341     return FFI_BAD_ABI;
342 
343   tramp[0] = 0x03000000 | fn >> 10;	/* sethi %hi(fn), %g1	*/
344   tramp[1] = 0x05000000 | ctx >> 10;	/* sethi %hi(ctx), %g2	*/
345   tramp[2] = 0x81c06000 | (fn & 0x3ff);	/* jmp   %g1+%lo(fn)	*/
346   tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or    %g2, %lo(ctx)	*/
347 
348   closure->cif = cif;
349   closure->fun = fun;
350   closure->user_data = user_data;
351 
352   ffi_flush_icache (closure);
353 
354   return FFI_OK;
355 }
356 
357 ffi_status
ffi_prep_go_closure(ffi_go_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *))358 ffi_prep_go_closure (ffi_go_closure *closure, ffi_cif *cif,
359 		     void (*fun)(ffi_cif*, void*, void**, void*))
360 {
361   if (cif->abi != FFI_V8)
362     return FFI_BAD_ABI;
363 
364   closure->tramp = ffi_go_closure_v8;
365   closure->cif = cif;
366   closure->fun = fun;
367 
368   return FFI_OK;
369 }
370 
371 int FFI_HIDDEN
ffi_closure_sparc_inner_v8(ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * rvalue,unsigned long * argp)372 ffi_closure_sparc_inner_v8(ffi_cif *cif,
373 			   void (*fun)(ffi_cif*, void*, void**, void*),
374 			   void *user_data, void *rvalue,
375 			   unsigned long *argp)
376 {
377   ffi_type **arg_types;
378   void **avalue;
379   int i, nargs, flags;
380 
381   arg_types = cif->arg_types;
382   nargs = cif->nargs;
383   flags = cif->flags;
384   avalue = alloca(nargs * sizeof(void *));
385 
386   /* Copy the caller's structure return address so that the closure
387      returns the data directly to the caller.  Also install it so we
388      can return the address in %o0.  */
389   if ((flags & SPARC_FLAG_RET_MASK) == SPARC_RET_STRUCT)
390     {
391       void *new_rvalue = (void *)*argp;
392       *(void **)rvalue = new_rvalue;
393       rvalue = new_rvalue;
394     }
395 
396   /* Always skip the structure return address.  */
397   argp++;
398 
399   /* Grab the addresses of the arguments from the stack frame.  */
400   for (i = 0; i < nargs; i++)
401     {
402       ffi_type *ty = arg_types[i];
403       int tt = ty->type;
404       void *a = argp;
405       size_t z;
406 
407       switch (tt)
408 	{
409 	case FFI_TYPE_STRUCT:
410 	case FFI_TYPE_LONGDOUBLE:
411 	by_reference:
412 	  /* Straight copy of invisible reference.  */
413 	  a = (void *)*argp;
414 	  break;
415 
416 	case FFI_TYPE_DOUBLE:
417 	case FFI_TYPE_SINT64:
418 	case FFI_TYPE_UINT64:
419 	  if ((unsigned long)a & 7)
420 	    {
421 	      /* Align on a 8-byte boundary.  */
422 	      UINT64 *tmp = alloca(8);
423 	      *tmp = ((UINT64)argp[0] << 32) | argp[1];
424 	      a = tmp;
425 	    }
426 	  argp++;
427 	  break;
428 
429 	case FFI_TYPE_INT:
430 	case FFI_TYPE_FLOAT:
431 	case FFI_TYPE_UINT32:
432 	case FFI_TYPE_SINT32:
433 	case FFI_TYPE_POINTER:
434 	  break;
435         case FFI_TYPE_UINT16:
436         case FFI_TYPE_SINT16:
437 	  a += 2;
438 	  break;
439         case FFI_TYPE_UINT8:
440         case FFI_TYPE_SINT8:
441 	  a += 3;
442 	  break;
443 
444         case FFI_TYPE_COMPLEX:
445 	  tt = ty->elements[0]->type;
446 	  z = ty->size;
447 	  if (tt == FFI_TYPE_FLOAT || z > 8)
448 	    goto by_reference;
449 	  if (z < 4)
450 	    a += 4 - z;
451 	  else if (z > 4)
452 	    argp++;
453 	  break;
454 
455 	default:
456 	  abort();
457 	}
458       argp++;
459       avalue[i] = a;
460     }
461 
462   /* Invoke the closure.  */
463   fun (cif, rvalue, avalue, user_data);
464 
465   /* Tell ffi_closure_sparc how to perform return type promotions.  */
466   return flags;
467 }
468 #endif /* !SPARC64 */
469