• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* -----------------------------------------------------------------------
2    ffi.c - Copyright (c) 1996, 2003, 2004, 2007, 2008 Red Hat, Inc.
3 
4    SPARC 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 
33 /* ffi_prep_args is called by the assembly routine once stack space
34    has been allocated for the function's arguments */
35 
ffi_prep_args_v8(char * stack,extended_cif * ecif)36 void ffi_prep_args_v8(char *stack, extended_cif *ecif)
37 {
38   int i;
39   void **p_argv;
40   char *argp;
41   ffi_type **p_arg;
42 
43   /* Skip 16 words for the window save area */
44   argp = stack + 16*sizeof(int);
45 
46   /* This should only really be done when we are returning a structure,
47      however, it's faster just to do it all the time...
48 
49   if ( ecif->cif->rtype->type == FFI_TYPE_STRUCT ) */
50   *(int *) argp = (long)ecif->rvalue;
51 
52   /* And 1 word for the  structure return value. */
53   argp += sizeof(int);
54 
55 #ifdef USING_PURIFY
56   /* Purify will probably complain in our assembly routine, unless we
57      zero out this memory. */
58 
59   ((int*)argp)[0] = 0;
60   ((int*)argp)[1] = 0;
61   ((int*)argp)[2] = 0;
62   ((int*)argp)[3] = 0;
63   ((int*)argp)[4] = 0;
64   ((int*)argp)[5] = 0;
65 #endif
66 
67   p_argv = ecif->avalue;
68 
69   for (i = ecif->cif->nargs, p_arg = ecif->cif->arg_types; i; i--, p_arg++)
70     {
71       size_t z;
72 
73 	  if ((*p_arg)->type == FFI_TYPE_STRUCT
74 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
75 	      || (*p_arg)->type == FFI_TYPE_LONGDOUBLE
76 #endif
77 	      )
78 	    {
79 	      *(unsigned int *) argp = (unsigned long)(* p_argv);
80 	      z = sizeof(int);
81 	    }
82 	  else
83 	    {
84 	      z = (*p_arg)->size;
85 	      if (z < sizeof(int))
86 		{
87 		  z = sizeof(int);
88 		  switch ((*p_arg)->type)
89 		    {
90 		    case FFI_TYPE_SINT8:
91 		      *(signed int *) argp = *(SINT8 *)(* p_argv);
92 		      break;
93 
94 		    case FFI_TYPE_UINT8:
95 		      *(unsigned int *) argp = *(UINT8 *)(* p_argv);
96 		      break;
97 
98 		    case FFI_TYPE_SINT16:
99 		      *(signed int *) argp = *(SINT16 *)(* p_argv);
100 		      break;
101 
102 		    case FFI_TYPE_UINT16:
103 		      *(unsigned int *) argp = *(UINT16 *)(* p_argv);
104 		      break;
105 
106 		    default:
107 		      FFI_ASSERT(0);
108 		    }
109 		}
110 	      else
111 		{
112 		  memcpy(argp, *p_argv, z);
113 		}
114 	    }
115 	  p_argv++;
116 	  argp += z;
117     }
118 
119   return;
120 }
121 
ffi_prep_args_v9(char * stack,extended_cif * ecif)122 int ffi_prep_args_v9(char *stack, extended_cif *ecif)
123 {
124   int i, ret = 0;
125   int tmp;
126   void **p_argv;
127   char *argp;
128   ffi_type **p_arg;
129 
130   tmp = 0;
131 
132   /* Skip 16 words for the window save area */
133   argp = stack + 16*sizeof(long long);
134 
135 #ifdef USING_PURIFY
136   /* Purify will probably complain in our assembly routine, unless we
137      zero out this memory. */
138 
139   ((long long*)argp)[0] = 0;
140   ((long long*)argp)[1] = 0;
141   ((long long*)argp)[2] = 0;
142   ((long long*)argp)[3] = 0;
143   ((long long*)argp)[4] = 0;
144   ((long long*)argp)[5] = 0;
145 #endif
146 
147   p_argv = ecif->avalue;
148 
149   if (ecif->cif->rtype->type == FFI_TYPE_STRUCT &&
150       ecif->cif->rtype->size > 32)
151     {
152       *(unsigned long long *) argp = (unsigned long)ecif->rvalue;
153       argp += sizeof(long long);
154       tmp = 1;
155     }
156 
157   for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs;
158        i++, p_arg++)
159     {
160       size_t z;
161 
162       z = (*p_arg)->size;
163       switch ((*p_arg)->type)
164 	{
165 	case FFI_TYPE_STRUCT:
166 	  if (z > 16)
167 	    {
168 	      /* For structures larger than 16 bytes we pass reference.  */
169 	      *(unsigned long long *) argp = (unsigned long)* p_argv;
170 	      argp += sizeof(long long);
171 	      tmp++;
172 	      p_argv++;
173 	      continue;
174 	    }
175 	  /* FALLTHROUGH */
176 	case FFI_TYPE_FLOAT:
177 	case FFI_TYPE_DOUBLE:
178 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
179 	case FFI_TYPE_LONGDOUBLE:
180 #endif
181 	  ret = 1; /* We should promote into FP regs as well as integer.  */
182 	  break;
183 	}
184       if (z < sizeof(long long))
185 	{
186 	  switch ((*p_arg)->type)
187 	    {
188 	    case FFI_TYPE_SINT8:
189 	      *(signed long long *) argp = *(SINT8 *)(* p_argv);
190 	      break;
191 
192 	    case FFI_TYPE_UINT8:
193 	      *(unsigned long long *) argp = *(UINT8 *)(* p_argv);
194 	      break;
195 
196 	    case FFI_TYPE_SINT16:
197 	      *(signed long long *) argp = *(SINT16 *)(* p_argv);
198 	      break;
199 
200 	    case FFI_TYPE_UINT16:
201 	      *(unsigned long long *) argp = *(UINT16 *)(* p_argv);
202 	      break;
203 
204 	    case FFI_TYPE_SINT32:
205 	      *(signed long long *) argp = *(SINT32 *)(* p_argv);
206 	      break;
207 
208 	    case FFI_TYPE_UINT32:
209 	      *(unsigned long long *) argp = *(UINT32 *)(* p_argv);
210 	      break;
211 
212 	    case FFI_TYPE_FLOAT:
213 	      *(float *) (argp + 4) = *(FLOAT32 *)(* p_argv); /* Right justify */
214 	      break;
215 
216 	    case FFI_TYPE_STRUCT:
217 	      memcpy(argp, *p_argv, z);
218 	      break;
219 
220 	    default:
221 	      FFI_ASSERT(0);
222 	    }
223 	  z = sizeof(long long);
224 	  tmp++;
225 	}
226       else if (z == sizeof(long long))
227 	{
228 	  memcpy(argp, *p_argv, z);
229 	  z = sizeof(long long);
230 	  tmp++;
231 	}
232       else
233 	{
234 	  if ((tmp & 1) && (*p_arg)->alignment > 8)
235 	    {
236 	      tmp++;
237 	      argp += sizeof(long long);
238 	    }
239 	  memcpy(argp, *p_argv, z);
240 	  z = 2 * sizeof(long long);
241 	  tmp += 2;
242 	}
243       p_argv++;
244       argp += z;
245     }
246 
247   return ret;
248 }
249 
250 /* Perform machine dependent cif processing */
ffi_prep_cif_machdep(ffi_cif * cif)251 ffi_status ffi_prep_cif_machdep(ffi_cif *cif)
252 {
253   int wordsize;
254 
255   if (cif->abi != FFI_V9)
256     {
257       wordsize = 4;
258 
259       /* If we are returning a struct, this will already have been added.
260 	 Otherwise we need to add it because it's always got to be there! */
261 
262       if (cif->rtype->type != FFI_TYPE_STRUCT)
263 	cif->bytes += wordsize;
264 
265       /* sparc call frames require that space is allocated for 6 args,
266 	 even if they aren't used. Make that space if necessary. */
267 
268       if (cif->bytes < 4*6+4)
269 	cif->bytes = 4*6+4;
270     }
271   else
272     {
273       wordsize = 8;
274 
275       /* sparc call frames require that space is allocated for 6 args,
276 	 even if they aren't used. Make that space if necessary. */
277 
278       if (cif->bytes < 8*6)
279 	cif->bytes = 8*6;
280     }
281 
282   /* Adjust cif->bytes. to include 16 words for the window save area,
283      and maybe the struct/union return pointer area, */
284 
285   cif->bytes += 16 * wordsize;
286 
287   /* The stack must be 2 word aligned, so round bytes up
288      appropriately. */
289 
290   cif->bytes = ALIGN(cif->bytes, 2 * wordsize);
291 
292   /* Set the return type flag */
293   switch (cif->rtype->type)
294     {
295     case FFI_TYPE_VOID:
296     case FFI_TYPE_FLOAT:
297     case FFI_TYPE_DOUBLE:
298 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
299     case FFI_TYPE_LONGDOUBLE:
300 #endif
301       cif->flags = cif->rtype->type;
302       break;
303 
304     case FFI_TYPE_STRUCT:
305       if (cif->abi == FFI_V9 && cif->rtype->size > 32)
306 	cif->flags = FFI_TYPE_VOID;
307       else
308 	cif->flags = FFI_TYPE_STRUCT;
309       break;
310 
311     case FFI_TYPE_SINT64:
312     case FFI_TYPE_UINT64:
313       if (cif->abi != FFI_V9)
314 	{
315 	  cif->flags = FFI_TYPE_SINT64;
316 	  break;
317 	}
318       /* FALLTHROUGH */
319     default:
320       cif->flags = FFI_TYPE_INT;
321       break;
322     }
323   return FFI_OK;
324 }
325 
ffi_v9_layout_struct(ffi_type * arg,int off,char * ret,char * intg,char * flt)326 int ffi_v9_layout_struct(ffi_type *arg, int off, char *ret, char *intg, char *flt)
327 {
328   ffi_type **ptr = &arg->elements[0];
329 
330   while (*ptr != NULL)
331     {
332       if (off & ((*ptr)->alignment - 1))
333 	off = ALIGN(off, (*ptr)->alignment);
334 
335       switch ((*ptr)->type)
336 	{
337 	case FFI_TYPE_STRUCT:
338 	  off = ffi_v9_layout_struct(*ptr, off, ret, intg, flt);
339 	  off = ALIGN(off, FFI_SIZEOF_ARG);
340 	  break;
341 	case FFI_TYPE_FLOAT:
342 	case FFI_TYPE_DOUBLE:
343 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
344 	case FFI_TYPE_LONGDOUBLE:
345 #endif
346 	  memmove(ret + off, flt + off, (*ptr)->size);
347 	  off += (*ptr)->size;
348 	  break;
349 	default:
350 	  memmove(ret + off, intg + off, (*ptr)->size);
351 	  off += (*ptr)->size;
352 	  break;
353 	}
354       ptr++;
355     }
356   return off;
357 }
358 
359 
360 #ifdef SPARC64
361 extern int ffi_call_v9(void *, extended_cif *, unsigned,
362 		       unsigned, unsigned *, void (*fn)(void));
363 #else
364 extern int ffi_call_v8(void *, extended_cif *, unsigned,
365 		       unsigned, unsigned *, void (*fn)(void));
366 #endif
367 
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)368 void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
369 {
370   extended_cif ecif;
371   void *rval = rvalue;
372 
373   ecif.cif = cif;
374   ecif.avalue = avalue;
375 
376   /* If the return value is a struct and we don't have a return	*/
377   /* value address then we need to make one		        */
378 
379   ecif.rvalue = rvalue;
380   if (cif->rtype->type == FFI_TYPE_STRUCT)
381     {
382       if (cif->rtype->size <= 32)
383 	rval = alloca(64);
384       else
385 	{
386 	  rval = NULL;
387 	  if (rvalue == NULL)
388 	    ecif.rvalue = alloca(cif->rtype->size);
389 	}
390     }
391 
392   switch (cif->abi)
393     {
394     case FFI_V8:
395 #ifdef SPARC64
396       /* We don't yet support calling 32bit code from 64bit */
397       FFI_ASSERT(0);
398 #else
399       ffi_call_v8(ffi_prep_args_v8, &ecif, cif->bytes,
400 		  cif->flags, rvalue, fn);
401 #endif
402       break;
403     case FFI_V9:
404 #ifdef SPARC64
405       ffi_call_v9(ffi_prep_args_v9, &ecif, cif->bytes,
406 		  cif->flags, rval, fn);
407       if (rvalue && rval && cif->rtype->type == FFI_TYPE_STRUCT)
408 	ffi_v9_layout_struct(cif->rtype, 0, (char *)rvalue, (char *)rval, ((char *)rval)+32);
409 #else
410       /* And vice versa */
411       FFI_ASSERT(0);
412 #endif
413       break;
414     default:
415       FFI_ASSERT(0);
416       break;
417     }
418 
419 }
420 
421 
422 #ifdef SPARC64
423 extern void ffi_closure_v9(void);
424 #else
425 extern void ffi_closure_v8(void);
426 #endif
427 
428 ffi_status
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)429 ffi_prep_closure_loc (ffi_closure* closure,
430 		      ffi_cif* cif,
431 		      void (*fun)(ffi_cif*, void*, void**, void*),
432 		      void *user_data,
433 		      void *codeloc)
434 {
435   unsigned int *tramp = (unsigned int *) &closure->tramp[0];
436   unsigned long fn;
437 #ifdef SPARC64
438   /* Trampoline address is equal to the closure address.  We take advantage
439      of that to reduce the trampoline size by 8 bytes. */
440   FFI_ASSERT (cif->abi == FFI_V9);
441   fn = (unsigned long) ffi_closure_v9;
442   tramp[0] = 0x83414000;	/* rd	%pc, %g1	*/
443   tramp[1] = 0xca586010;	/* ldx	[%g1+16], %g5	*/
444   tramp[2] = 0x81c14000;	/* jmp	%g5		*/
445   tramp[3] = 0x01000000;	/* nop			*/
446   *((unsigned long *) &tramp[4]) = fn;
447 #else
448   unsigned long ctx = (unsigned long) codeloc;
449   FFI_ASSERT (cif->abi == FFI_V8);
450   fn = (unsigned long) ffi_closure_v8;
451   tramp[0] = 0x03000000 | fn >> 10;	/* sethi %hi(fn), %g1	*/
452   tramp[1] = 0x05000000 | ctx >> 10;	/* sethi %hi(ctx), %g2	*/
453   tramp[2] = 0x81c06000 | (fn & 0x3ff);	/* jmp   %g1+%lo(fn)	*/
454   tramp[3] = 0x8410a000 | (ctx & 0x3ff);/* or    %g2, %lo(ctx)	*/
455 #endif
456 
457   closure->cif = cif;
458   closure->fun = fun;
459   closure->user_data = user_data;
460 
461   /* Flush the Icache.  FIXME: alignment isn't certain, assume 8 bytes */
462 #ifdef SPARC64
463   asm volatile ("flush	%0" : : "r" (closure) : "memory");
464   asm volatile ("flush	%0" : : "r" (((char *) closure) + 8) : "memory");
465 #else
466   asm volatile ("iflush	%0" : : "r" (closure) : "memory");
467   asm volatile ("iflush	%0" : : "r" (((char *) closure) + 8) : "memory");
468 #endif
469 
470   return FFI_OK;
471 }
472 
473 int
ffi_closure_sparc_inner_v8(ffi_closure * closure,void * rvalue,unsigned long * gpr,unsigned long * scratch)474 ffi_closure_sparc_inner_v8(ffi_closure *closure,
475   void *rvalue, unsigned long *gpr, unsigned long *scratch)
476 {
477   ffi_cif *cif;
478   ffi_type **arg_types;
479   void **avalue;
480   int i, argn;
481 
482   cif = closure->cif;
483   arg_types = cif->arg_types;
484   avalue = alloca(cif->nargs * sizeof(void *));
485 
486   /* Copy the caller's structure return address so that the closure
487      returns the data directly to the caller.  */
488   if (cif->flags == FFI_TYPE_STRUCT
489 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
490       || cif->flags == FFI_TYPE_LONGDOUBLE
491 #endif
492      )
493     rvalue = (void *) gpr[0];
494 
495   /* Always skip the structure return address.  */
496   argn = 1;
497 
498   /* Grab the addresses of the arguments from the stack frame.  */
499   for (i = 0; i < cif->nargs; i++)
500     {
501       if (arg_types[i]->type == FFI_TYPE_STRUCT
502 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
503 	  || arg_types[i]->type == FFI_TYPE_LONGDOUBLE
504 #endif
505          )
506 	{
507 	  /* Straight copy of invisible reference.  */
508 	  avalue[i] = (void *)gpr[argn++];
509 	}
510       else if ((arg_types[i]->type == FFI_TYPE_DOUBLE
511 	       || arg_types[i]->type == FFI_TYPE_SINT64
512 	       || arg_types[i]->type == FFI_TYPE_UINT64)
513 	       /* gpr is 8-byte aligned.  */
514 	       && (argn % 2) != 0)
515 	{
516 	  /* Align on a 8-byte boundary.  */
517 	  scratch[0] = gpr[argn];
518 	  scratch[1] = gpr[argn+1];
519 	  avalue[i] = scratch;
520 	  scratch -= 2;
521 	  argn += 2;
522 	}
523       else
524 	{
525 	  /* Always right-justify.  */
526 	  argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
527 	  avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
528 	}
529     }
530 
531   /* Invoke the closure.  */
532   (closure->fun) (cif, rvalue, avalue, closure->user_data);
533 
534   /* Tell ffi_closure_sparc how to perform return type promotions.  */
535   return cif->rtype->type;
536 }
537 
538 int
ffi_closure_sparc_inner_v9(ffi_closure * closure,void * rvalue,unsigned long * gpr,double * fpr)539 ffi_closure_sparc_inner_v9(ffi_closure *closure,
540   void *rvalue, unsigned long *gpr, double *fpr)
541 {
542   ffi_cif *cif;
543   ffi_type **arg_types;
544   void **avalue;
545   int i, argn, fp_slot_max;
546 
547   cif = closure->cif;
548   arg_types = cif->arg_types;
549   avalue = alloca(cif->nargs * sizeof(void *));
550 
551   /* Copy the caller's structure return address so that the closure
552      returns the data directly to the caller.  */
553   if (cif->flags == FFI_TYPE_VOID
554       && cif->rtype->type == FFI_TYPE_STRUCT)
555     {
556       rvalue = (void *) gpr[0];
557       /* Skip the structure return address.  */
558       argn = 1;
559     }
560   else
561     argn = 0;
562 
563   fp_slot_max = 16 - argn;
564 
565   /* Grab the addresses of the arguments from the stack frame.  */
566   for (i = 0; i < cif->nargs; i++)
567     {
568       if (arg_types[i]->type == FFI_TYPE_STRUCT)
569 	{
570 	  if (arg_types[i]->size > 16)
571 	    {
572 	      /* Straight copy of invisible reference.  */
573 	      avalue[i] = (void *)gpr[argn++];
574 	    }
575 	  else
576 	    {
577 	      /* Left-justify.  */
578 	      ffi_v9_layout_struct(arg_types[i],
579 				   0,
580 				   (char *) &gpr[argn],
581 				   (char *) &gpr[argn],
582 				   (char *) &fpr[argn]);
583 	      avalue[i] = &gpr[argn];
584 	      argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
585 	    }
586 	}
587       else
588 	{
589 	  /* Right-justify.  */
590 	  argn += ALIGN(arg_types[i]->size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
591 
592 	  if (i < fp_slot_max
593 	      && (arg_types[i]->type == FFI_TYPE_FLOAT
594 		  || arg_types[i]->type == FFI_TYPE_DOUBLE
595 #if FFI_TYPE_LONGDOUBLE != FFI_TYPE_DOUBLE
596 		  || arg_types[i]->type == FFI_TYPE_LONGDOUBLE
597 #endif
598 		  ))
599 	    avalue[i] = ((char *) &fpr[argn]) - arg_types[i]->size;
600 	  else
601 	    avalue[i] = ((char *) &gpr[argn]) - arg_types[i]->size;
602 	}
603     }
604 
605   /* Invoke the closure.  */
606   (closure->fun) (cif, rvalue, avalue, closure->user_data);
607 
608   /* Tell ffi_closure_sparc how to perform return type promotions.  */
609   return cif->rtype->type;
610 }
611