1 /* -----------------------------------------------------------------------
2    ffi.c - Copyright (c) 2012  Anthony Green
3 	   Copyright (c) 1998, 2001, 2007, 2008  Red Hat, Inc.
4 
5    Alpha 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 /* Force FFI_TYPE_LONGDOUBLE to be different than FFI_TYPE_DOUBLE;
34    all further uses in this file will refer to the 128-bit type.  */
35 #if defined(__LONG_DOUBLE_128__)
36 # if FFI_TYPE_LONGDOUBLE != 4
37 #  error FFI_TYPE_LONGDOUBLE out of date
38 # endif
39 #else
40 # undef FFI_TYPE_LONGDOUBLE
41 # define FFI_TYPE_LONGDOUBLE 4
42 #endif
43 
44 extern void ffi_call_osf(void *stack, void *frame, unsigned flags,
45 			 void *raddr, void (*fn)(void), void *closure)
46 	FFI_HIDDEN;
47 extern void ffi_closure_osf(void) FFI_HIDDEN;
48 extern void ffi_go_closure_osf(void) FFI_HIDDEN;
49 
50 /* Promote a float value to its in-register double representation.
51    Unlike actually casting to double, this does not trap on NaN.  */
lds(void * ptr)52 static inline UINT64 lds(void *ptr)
53 {
54   UINT64 ret;
55   asm("lds %0,%1" : "=f"(ret) : "m"(*(UINT32 *)ptr));
56   return ret;
57 }
58 
59 /* And the reverse.  */
sts(void * ptr,UINT64 val)60 static inline void sts(void *ptr, UINT64 val)
61 {
62   asm("sts %1,%0" : "=m"(*(UINT32 *)ptr) : "f"(val));
63 }
64 
65 ffi_status FFI_HIDDEN
ffi_prep_cif_machdep(ffi_cif * cif)66 ffi_prep_cif_machdep(ffi_cif *cif)
67 {
68   size_t bytes = 0;
69   int flags, i, avn;
70   ffi_type *rtype, *itype;
71 
72   if (cif->abi != FFI_OSF)
73     return FFI_BAD_ABI;
74 
75   /* Compute the size of the argument area.  */
76   for (i = 0, avn = cif->nargs; i < avn; i++)
77     {
78       itype = cif->arg_types[i];
79       switch (itype->type)
80 	{
81 	case FFI_TYPE_INT:
82 	case FFI_TYPE_SINT8:
83 	case FFI_TYPE_UINT8:
84 	case FFI_TYPE_SINT16:
85 	case FFI_TYPE_UINT16:
86 	case FFI_TYPE_SINT32:
87 	case FFI_TYPE_UINT32:
88 	case FFI_TYPE_SINT64:
89 	case FFI_TYPE_UINT64:
90 	case FFI_TYPE_POINTER:
91 	case FFI_TYPE_FLOAT:
92 	case FFI_TYPE_DOUBLE:
93 	case FFI_TYPE_LONGDOUBLE:
94 	  /* All take one 8 byte slot.  */
95 	  bytes += 8;
96 	  break;
97 
98 	case FFI_TYPE_VOID:
99 	case FFI_TYPE_STRUCT:
100 	  /* Passed by value in N slots.  */
101 	  bytes += FFI_ALIGN(itype->size, FFI_SIZEOF_ARG);
102 	  break;
103 
104 	case FFI_TYPE_COMPLEX:
105 	  /* _Complex long double passed by reference; others in 2 slots.  */
106 	  if (itype->elements[0]->type == FFI_TYPE_LONGDOUBLE)
107 	    bytes += 8;
108 	  else
109 	    bytes += 16;
110 	  break;
111 
112 	default:
113 	  abort();
114 	}
115     }
116 
117   /* Set the return type flag */
118   rtype = cif->rtype;
119   switch (rtype->type)
120     {
121     case FFI_TYPE_VOID:
122       flags = ALPHA_FLAGS(ALPHA_ST_VOID, ALPHA_LD_VOID);
123       break;
124     case FFI_TYPE_INT:
125     case FFI_TYPE_UINT32:
126     case FFI_TYPE_SINT32:
127       flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT32);
128       break;
129     case FFI_TYPE_FLOAT:
130       flags = ALPHA_FLAGS(ALPHA_ST_FLOAT, ALPHA_LD_FLOAT);
131       break;
132     case FFI_TYPE_DOUBLE:
133       flags = ALPHA_FLAGS(ALPHA_ST_DOUBLE, ALPHA_LD_DOUBLE);
134       break;
135     case FFI_TYPE_UINT8:
136       flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_UINT8);
137       break;
138     case FFI_TYPE_SINT8:
139       flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_SINT8);
140       break;
141     case FFI_TYPE_UINT16:
142       flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_UINT16);
143       break;
144     case FFI_TYPE_SINT16:
145       flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_SINT16);
146       break;
147     case FFI_TYPE_UINT64:
148     case FFI_TYPE_SINT64:
149     case FFI_TYPE_POINTER:
150       flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT64);
151       break;
152     case FFI_TYPE_LONGDOUBLE:
153     case FFI_TYPE_STRUCT:
154       /* Passed in memory, with a hidden pointer.  */
155       flags = ALPHA_RET_IN_MEM;
156       break;
157     case FFI_TYPE_COMPLEX:
158       itype = rtype->elements[0];
159       switch (itype->type)
160 	{
161 	case FFI_TYPE_FLOAT:
162 	  flags = ALPHA_FLAGS(ALPHA_ST_CPLXF, ALPHA_LD_CPLXF);
163 	  break;
164 	case FFI_TYPE_DOUBLE:
165 	  flags = ALPHA_FLAGS(ALPHA_ST_CPLXD, ALPHA_LD_CPLXD);
166 	  break;
167 	default:
168 	  if (rtype->size <= 8)
169 	    flags = ALPHA_FLAGS(ALPHA_ST_INT, ALPHA_LD_INT64);
170 	  else
171 	    flags = ALPHA_RET_IN_MEM;
172 	  break;
173 	}
174       break;
175     default:
176       abort();
177     }
178   cif->flags = flags;
179 
180   /* Include the hidden structure pointer in args requirement.  */
181   if (flags == ALPHA_RET_IN_MEM)
182     bytes += 8;
183   /* Minimum size is 6 slots, so that ffi_call_osf can pop them.  */
184   if (bytes < 6*8)
185     bytes = 6*8;
186   cif->bytes = bytes;
187 
188   return FFI_OK;
189 }
190 
191 static unsigned long
extend_basic_type(void * valp,int type,int argn)192 extend_basic_type(void *valp, int type, int argn)
193 {
194   switch (type)
195     {
196     case FFI_TYPE_SINT8:
197       return *(SINT8 *)valp;
198     case FFI_TYPE_UINT8:
199       return *(UINT8 *)valp;
200     case FFI_TYPE_SINT16:
201       return *(SINT16 *)valp;
202     case FFI_TYPE_UINT16:
203       return *(UINT16 *)valp;
204 
205     case FFI_TYPE_FLOAT:
206       if (argn < 6)
207 	return lds(valp);
208       /* FALLTHRU */
209 
210     case FFI_TYPE_INT:
211     case FFI_TYPE_SINT32:
212     case FFI_TYPE_UINT32:
213       /* Note that unsigned 32-bit quantities are sign extended.  */
214       return *(SINT32 *)valp;
215 
216     case FFI_TYPE_SINT64:
217     case FFI_TYPE_UINT64:
218     case FFI_TYPE_POINTER:
219     case FFI_TYPE_DOUBLE:
220       return *(UINT64 *)valp;
221 
222     default:
223       abort();
224     }
225 }
226 
227 static void
ffi_call_int(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue,void * closure)228 ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue,
229 	      void **avalue, void *closure)
230 {
231   unsigned long *argp;
232   long i, avn, argn, flags = cif->flags;
233   ffi_type **arg_types;
234   void *frame;
235 
236   /* If the return value is a struct and we don't have a return
237      value address then we need to make one.  */
238   if (rvalue == NULL && flags == ALPHA_RET_IN_MEM)
239     rvalue = alloca(cif->rtype->size);
240 
241   /* Allocate the space for the arguments, plus 4 words of temp
242      space for ffi_call_osf.  */
243   argp = frame = alloca(cif->bytes + 4*FFI_SIZEOF_ARG);
244   frame += cif->bytes;
245 
246   argn = 0;
247   if (flags == ALPHA_RET_IN_MEM)
248     argp[argn++] = (unsigned long)rvalue;
249 
250   avn = cif->nargs;
251   arg_types = cif->arg_types;
252 
253   for (i = 0, avn = cif->nargs; i < avn; i++)
254     {
255       ffi_type *ty = arg_types[i];
256       void *valp = avalue[i];
257       int type = ty->type;
258       size_t size;
259 
260       switch (type)
261 	{
262 	case FFI_TYPE_INT:
263 	case FFI_TYPE_SINT8:
264 	case FFI_TYPE_UINT8:
265 	case FFI_TYPE_SINT16:
266 	case FFI_TYPE_UINT16:
267 	case FFI_TYPE_SINT32:
268 	case FFI_TYPE_UINT32:
269 	case FFI_TYPE_SINT64:
270 	case FFI_TYPE_UINT64:
271 	case FFI_TYPE_POINTER:
272 	case FFI_TYPE_FLOAT:
273 	case FFI_TYPE_DOUBLE:
274 	  argp[argn] = extend_basic_type(valp, type, argn);
275 	  argn++;
276 	  break;
277 
278 	case FFI_TYPE_LONGDOUBLE:
279 	by_reference:
280 	  /* Note that 128-bit long double is passed by reference.  */
281 	  argp[argn++] = (unsigned long)valp;
282 	  break;
283 
284 	case FFI_TYPE_VOID:
285 	case FFI_TYPE_STRUCT:
286 	  size = ty->size;
287 	  memcpy(argp + argn, valp, size);
288 	  argn += FFI_ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
289 	  break;
290 
291 	case FFI_TYPE_COMPLEX:
292 	  type = ty->elements[0]->type;
293 	  if (type == FFI_TYPE_LONGDOUBLE)
294 	    goto by_reference;
295 
296 	  /* Most complex types passed as two separate arguments.  */
297 	  size = ty->elements[0]->size;
298 	  argp[argn] = extend_basic_type(valp, type, argn);
299 	  argp[argn + 1] = extend_basic_type(valp + size, type, argn + 1);
300 	  argn += 2;
301 	  break;
302 
303 	default:
304 	  abort();
305 	}
306     }
307 
308   flags = (flags >> ALPHA_ST_SHIFT) & 0xff;
309   ffi_call_osf(argp, frame, flags, rvalue, fn, closure);
310 }
311 
312 void
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)313 ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
314 {
315   ffi_call_int(cif, fn, rvalue, avalue, NULL);
316 }
317 
318 void
ffi_call_go(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue,void * closure)319 ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue,
320 	     void **avalue, void *closure)
321 {
322   ffi_call_int(cif, fn, rvalue, avalue, closure);
323 }
324 
325 ffi_status
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)326 ffi_prep_closure_loc (ffi_closure* closure,
327 		      ffi_cif* cif,
328 		      void (*fun)(ffi_cif*, void*, void**, void*),
329 		      void *user_data,
330 		      void *codeloc)
331 {
332   unsigned int *tramp;
333 
334   if (cif->abi != FFI_OSF)
335     return FFI_BAD_ABI;
336 
337   tramp = (unsigned int *) &closure->tramp[0];
338   tramp[0] = 0x47fb0401;	/* mov $27,$1		*/
339   tramp[1] = 0xa77b0010;	/* ldq $27,16($27)	*/
340   tramp[2] = 0x6bfb0000;	/* jmp $31,($27),0	*/
341   tramp[3] = 0x47ff041f;	/* nop			*/
342   *(void **) &tramp[4] = ffi_closure_osf;
343 
344   closure->cif = cif;
345   closure->fun = fun;
346   closure->user_data = user_data;
347 
348   /* Flush the Icache.
349 
350      Tru64 UNIX as doesn't understand the imb mnemonic, so use call_pal
351      instead, since both Compaq as and gas can handle it.
352 
353      0x86 is PAL_imb in Tru64 UNIX <alpha/pal.h>.  */
354   asm volatile ("call_pal 0x86" : : : "memory");
355 
356   return FFI_OK;
357 }
358 
359 ffi_status
ffi_prep_go_closure(ffi_go_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *))360 ffi_prep_go_closure (ffi_go_closure* closure,
361 		     ffi_cif* cif,
362 		     void (*fun)(ffi_cif*, void*, void**, void*))
363 {
364   if (cif->abi != FFI_OSF)
365     return FFI_BAD_ABI;
366 
367   closure->tramp = (void *)ffi_go_closure_osf;
368   closure->cif = cif;
369   closure->fun = fun;
370 
371   return FFI_OK;
372 }
373 
374 long FFI_HIDDEN
ffi_closure_osf_inner(ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * rvalue,unsigned long * argp)375 ffi_closure_osf_inner (ffi_cif *cif,
376 		       void (*fun)(ffi_cif*, void*, void**, void*),
377 		       void *user_data,
378 		       void *rvalue, unsigned long *argp)
379 {
380   void **avalue;
381   ffi_type **arg_types;
382   long i, avn, argn, flags;
383 
384   avalue = alloca(cif->nargs * sizeof(void *));
385   flags = cif->flags;
386   argn = 0;
387 
388   /* Copy the caller's structure return address to that the closure
389      returns the data directly to the caller.  */
390   if (flags == ALPHA_RET_IN_MEM)
391     {
392       rvalue = (void *) argp[0];
393       argn = 1;
394     }
395 
396   arg_types = cif->arg_types;
397 
398   /* Grab the addresses of the arguments from the stack frame.  */
399   for (i = 0, avn = cif->nargs; i < avn; i++)
400     {
401       ffi_type *ty = arg_types[i];
402       int type = ty->type;
403       void *valp = &argp[argn];
404       size_t size;
405 
406       switch (type)
407 	{
408 	case FFI_TYPE_INT:
409 	case FFI_TYPE_SINT8:
410 	case FFI_TYPE_UINT8:
411 	case FFI_TYPE_SINT16:
412 	case FFI_TYPE_UINT16:
413 	case FFI_TYPE_SINT32:
414 	case FFI_TYPE_UINT32:
415 	case FFI_TYPE_SINT64:
416 	case FFI_TYPE_UINT64:
417 	case FFI_TYPE_POINTER:
418 	  argn += 1;
419 	  break;
420 
421 	case FFI_TYPE_VOID:
422 	case FFI_TYPE_STRUCT:
423 	  size = ty->size;
424 	  argn += FFI_ALIGN(size, FFI_SIZEOF_ARG) / FFI_SIZEOF_ARG;
425 	  break;
426 
427 	case FFI_TYPE_FLOAT:
428 	  /* Floats coming from registers need conversion from double
429 	     back to float format.  */
430 	  if (argn < 6)
431 	    {
432 	      valp = &argp[argn - 6];
433 	      sts(valp, argp[argn - 6]);
434 	    }
435 	  argn += 1;
436 	  break;
437 
438 	case FFI_TYPE_DOUBLE:
439 	  if (argn < 6)
440 	    valp = &argp[argn - 6];
441 	  argn += 1;
442 	  break;
443 
444 	case FFI_TYPE_LONGDOUBLE:
445 	by_reference:
446 	  /* 128-bit long double is passed by reference.  */
447 	  valp = (void *)argp[argn];
448 	  argn += 1;
449 	  break;
450 
451 	case FFI_TYPE_COMPLEX:
452 	  type = ty->elements[0]->type;
453 	  switch (type)
454 	    {
455 	    case FFI_TYPE_SINT64:
456 	    case FFI_TYPE_UINT64:
457 	      /* Passed as separate arguments, but they wind up sequential.  */
458 	      break;
459 
460 	    case FFI_TYPE_INT:
461 	    case FFI_TYPE_SINT8:
462 	    case FFI_TYPE_UINT8:
463 	    case FFI_TYPE_SINT16:
464 	    case FFI_TYPE_UINT16:
465 	    case FFI_TYPE_SINT32:
466 	    case FFI_TYPE_UINT32:
467 	      /* Passed as separate arguments.  Disjoint, but there's room
468 		 enough in one slot to hold the pair.  */
469 	      size = ty->elements[0]->size;
470 	      memcpy(valp + size, valp + 8, size);
471 	      break;
472 
473 	    case FFI_TYPE_FLOAT:
474 	      /* Passed as separate arguments.  Disjoint, and each piece
475 		 may need conversion back to float.  */
476 	      if (argn < 6)
477 		{
478 		  valp = &argp[argn - 6];
479 		  sts(valp, argp[argn - 6]);
480 		}
481 	      if (argn + 1 < 6)
482 		sts(valp + 4, argp[argn + 1 - 6]);
483 	      else
484 		*(UINT32 *)(valp + 4) = argp[argn + 1];
485 	      break;
486 
487 	    case FFI_TYPE_DOUBLE:
488 	      /* Passed as separate arguments.  Only disjoint if one part
489 		 is in fp regs and the other is on the stack.  */
490 	      if (argn < 5)
491 		valp = &argp[argn - 6];
492 	      else if (argn == 5)
493 		{
494 		  valp = alloca(16);
495 		  ((UINT64 *)valp)[0] = argp[5 - 6];
496 		  ((UINT64 *)valp)[1] = argp[6];
497 		}
498 	      break;
499 
500 	    case FFI_TYPE_LONGDOUBLE:
501 	      goto by_reference;
502 
503 	    default:
504 	      abort();
505 	    }
506 	  argn += 2;
507 	  break;
508 
509 	default:
510 	  abort ();
511 	}
512 
513       avalue[i] = valp;
514     }
515 
516   /* Invoke the closure.  */
517   fun (cif, rvalue, avalue, user_data);
518 
519   /* Tell ffi_closure_osf how to perform return type promotions.  */
520   return (flags >> ALPHA_LD_SHIFT) & 0xff;
521 }
522