1 /* -----------------------------------------------------------------------
2    ffi.c - (c) 2016 John David Anglin
3 	   (c) 2011 Anthony Green
4            (c) 2008 Red Hat, Inc.
5 	   (c) 2006 Free Software Foundation, Inc.
6            (c) 2003-2004 Randolph Chung <tausq@debian.org>
7 
8    HPPA Foreign Function Interface
9    HP-UX PA ABI support
10 
11    Permission is hereby granted, free of charge, to any person obtaining
12    a copy of this software and associated documentation files (the
13    ``Software''), to deal in the Software without restriction, including
14    without limitation the rights to use, copy, modify, merge, publish,
15    distribute, sublicense, and/or sell copies of the Software, and to
16    permit persons to whom the Software is furnished to do so, subject to
17    the following conditions:
18 
19    The above copyright notice and this permission notice shall be included
20    in all copies or substantial portions of the Software.
21 
22    THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
23    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25    NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
26    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
27    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
29    DEALINGS IN THE SOFTWARE.
30    ----------------------------------------------------------------------- */
31 
32 #include <ffi.h>
33 #include <ffi_common.h>
34 
35 #include <stdlib.h>
36 #include <stdio.h>
37 
38 #define ROUND_UP(v, a)  (((size_t)(v) + (a) - 1) & ~((a) - 1))
39 
40 #define MIN_STACK_SIZE  64
41 #define FIRST_ARG_SLOT  9
42 #define DEBUG_LEVEL   0
43 
44 #define fldw(addr, fpreg) \
45   __asm__ volatile ("fldw 0(%0), %%" #fpreg "L" : : "r"(addr) : #fpreg)
46 #define fstw(fpreg, addr) \
47   __asm__ volatile ("fstw %%" #fpreg "L, 0(%0)" : : "r"(addr))
48 #define fldd(addr, fpreg) \
49   __asm__ volatile ("fldd 0(%0), %%" #fpreg : : "r"(addr) : #fpreg)
50 #define fstd(fpreg, addr) \
51   __asm__ volatile ("fstd %%" #fpreg "L, 0(%0)" : : "r"(addr))
52 
53 #define debug(lvl, x...) do { if (lvl <= DEBUG_LEVEL) { printf(x); } } while (0)
54 
55 static inline int
ffi_struct_type(ffi_type * t)56 ffi_struct_type (ffi_type *t)
57 {
58   size_t sz = t->size;
59 
60   /* Small structure results are passed in registers,
61      larger ones are passed by pointer.  Note that
62      small structures of size 2, 4 and 8 differ from
63      the corresponding integer types in that they have
64      different alignment requirements.  */
65 
66   if (sz <= 1)
67     return FFI_TYPE_UINT8;
68   else if (sz == 2)
69     return FFI_TYPE_SMALL_STRUCT2;
70   else if (sz == 3)
71     return FFI_TYPE_SMALL_STRUCT3;
72   else if (sz == 4)
73     return FFI_TYPE_SMALL_STRUCT4;
74   else if (sz == 5)
75     return FFI_TYPE_SMALL_STRUCT5;
76   else if (sz == 6)
77     return FFI_TYPE_SMALL_STRUCT6;
78   else if (sz == 7)
79     return FFI_TYPE_SMALL_STRUCT7;
80   else if (sz <= 8)
81     return FFI_TYPE_SMALL_STRUCT8;
82   else
83     return FFI_TYPE_STRUCT; /* else, we pass it by pointer.  */
84 }
85 
86 /* PA has a downward growing stack, which looks like this:
87 
88    Offset
89 	[ Variable args ]
90    SP = (4*(n+9))       arg word N
91    ...
92    SP-52                arg word 4
93 	[ Fixed args ]
94    SP-48                arg word 3
95    SP-44                arg word 2
96    SP-40                arg word 1
97    SP-36                arg word 0
98 	[ Frame marker ]
99    ...
100    SP-20                RP
101    SP-4                 previous SP
102 
103    The first four argument words on the stack are reserved for use by
104    the callee.  Instead, the general and floating registers replace
105    the first four argument slots.  Non FP arguments are passed solely
106    in the general registers.  FP arguments are passed in both general
107    and floating registers when using libffi.
108 
109    Non-FP 32-bit args are passed in gr26, gr25, gr24 and gr23.
110    Non-FP 64-bit args are passed in register pairs, starting
111    on an odd numbered register (i.e. r25+r26 and r23+r24).
112    FP 32-bit arguments are passed in fr4L, fr5L, fr6L and fr7L.
113    FP 64-bit arguments are passed in fr5 and fr7.
114 
115    The registers are allocated in the same manner as stack slots.
116    This allows the callee to save its arguments on the stack if
117    necessary:
118 
119    arg word 3 -> gr23 or fr7L
120    arg word 2 -> gr24 or fr6L or fr7R
121    arg word 1 -> gr25 or fr5L
122    arg word 0 -> gr26 or fr4L or fr5R
123 
124    Note that fr4R and fr6R are never used for arguments (i.e.,
125    doubles are not passed in fr4 or fr6).
126 
127    The rest of the arguments are passed on the stack starting at SP-52,
128    but 64-bit arguments need to be aligned to an 8-byte boundary
129 
130    This means we can have holes either in the register allocation,
131    or in the stack.  */
132 
133 /* ffi_prep_args is called by the assembly routine once stack space
134    has been allocated for the function's arguments
135 
136    The following code will put everything into the stack frame
137    (which was allocated by the asm routine), and on return
138    the asm routine will load the arguments that should be
139    passed by register into the appropriate registers
140 
141    NOTE: We load floating point args in this function... that means we
142    assume gcc will not mess with fp regs in here.  */
143 
144 void
ffi_prep_args_pa32(UINT32 * stack,extended_cif * ecif,unsigned bytes)145 ffi_prep_args_pa32 (UINT32 *stack, extended_cif *ecif, unsigned bytes)
146 {
147   register unsigned int i;
148   register ffi_type **p_arg;
149   register void **p_argv;
150   unsigned int slot = FIRST_ARG_SLOT;
151   char *dest_cpy;
152   size_t len;
153 
154   debug(1, "%s: stack = %p, ecif = %p, bytes = %u\n", __FUNCTION__, stack,
155 	ecif, bytes);
156 
157   p_arg = ecif->cif->arg_types;
158   p_argv = ecif->avalue;
159 
160   for (i = 0; i < ecif->cif->nargs; i++)
161     {
162       int type = (*p_arg)->type;
163 
164       switch (type)
165 	{
166 	case FFI_TYPE_SINT8:
167 	  *(SINT32 *)(stack - slot) = *(SINT8 *)(*p_argv);
168 	  break;
169 
170 	case FFI_TYPE_UINT8:
171 	  *(UINT32 *)(stack - slot) = *(UINT8 *)(*p_argv);
172 	  break;
173 
174 	case FFI_TYPE_SINT16:
175 	  *(SINT32 *)(stack - slot) = *(SINT16 *)(*p_argv);
176 	  break;
177 
178 	case FFI_TYPE_UINT16:
179 	  *(UINT32 *)(stack - slot) = *(UINT16 *)(*p_argv);
180 	  break;
181 
182 	case FFI_TYPE_UINT32:
183 	case FFI_TYPE_SINT32:
184 	case FFI_TYPE_POINTER:
185 	  debug(3, "Storing UINT32 %u in slot %u\n", *(UINT32 *)(*p_argv),
186 		slot);
187 	  *(UINT32 *)(stack - slot) = *(UINT32 *)(*p_argv);
188 	  break;
189 
190 	case FFI_TYPE_UINT64:
191 	case FFI_TYPE_SINT64:
192 	  /* Align slot for 64-bit type.  */
193 	  slot += (slot & 1) ? 1 : 2;
194 	  *(UINT64 *)(stack - slot) = *(UINT64 *)(*p_argv);
195 	  break;
196 
197 	case FFI_TYPE_FLOAT:
198 	  /* First 4 args go in fr4L - fr7L.  */
199 	  debug(3, "Storing UINT32(float) in slot %u\n", slot);
200 	  *(UINT32 *)(stack - slot) = *(UINT32 *)(*p_argv);
201 	  switch (slot - FIRST_ARG_SLOT)
202 	    {
203 	    /* First 4 args go in fr4L - fr7L.  */
204 	    case 0: fldw(stack - slot, fr4); break;
205 	    case 1: fldw(stack - slot, fr5); break;
206 	    case 2: fldw(stack - slot, fr6); break;
207 	    case 3: fldw(stack - slot, fr7); break;
208 	    }
209 	  break;
210 
211 	case FFI_TYPE_DOUBLE:
212 	  /* Align slot for 64-bit type.  */
213 	  slot += (slot & 1) ? 1 : 2;
214 	  debug(3, "Storing UINT64(double) at slot %u\n", slot);
215 	  *(UINT64 *)(stack - slot) = *(UINT64 *)(*p_argv);
216 	  switch (slot - FIRST_ARG_SLOT)
217 	    {
218 	      /* First 2 args go in fr5, fr7.  */
219 	      case 1: fldd(stack - slot, fr5); break;
220 	      case 3: fldd(stack - slot, fr7); break;
221 	    }
222 	  break;
223 
224 #ifdef PA_HPUX
225 	case FFI_TYPE_LONGDOUBLE:
226 	  /* Long doubles are passed in the same manner as structures
227 	     larger than 8 bytes.  */
228 	  *(UINT32 *)(stack - slot) = (UINT32)(*p_argv);
229 	  break;
230 #endif
231 
232 	case FFI_TYPE_STRUCT:
233 
234 	  /* Structs smaller or equal than 4 bytes are passed in one
235 	     register. Structs smaller or equal 8 bytes are passed in two
236 	     registers. Larger structures are passed by pointer.  */
237 
238 	  len = (*p_arg)->size;
239 	  if (len <= 4)
240 	    {
241 	      dest_cpy = (char *)(stack - slot) + 4 - len;
242 	      memcpy(dest_cpy, (char *)*p_argv, len);
243 	    }
244 	  else if (len <= 8)
245 	    {
246 	      slot += (slot & 1) ? 1 : 2;
247 	      dest_cpy = (char *)(stack - slot) + 8 - len;
248 	      memcpy(dest_cpy, (char *)*p_argv, len);
249 	    }
250 	  else
251 	    *(UINT32 *)(stack - slot) = (UINT32)(*p_argv);
252 	  break;
253 
254 	default:
255 	  FFI_ASSERT(0);
256 	}
257 
258       slot++;
259       p_arg++;
260       p_argv++;
261     }
262 
263   /* Make sure we didn't mess up and scribble on the stack.  */
264   {
265     unsigned int n;
266 
267     debug(5, "Stack setup:\n");
268     for (n = 0; n < (bytes + 3) / 4; n++)
269       {
270 	if ((n%4) == 0) { debug(5, "\n%08x: ", (unsigned int)(stack - n)); }
271 	debug(5, "%08x ", *(stack - n));
272       }
273     debug(5, "\n");
274   }
275 
276   FFI_ASSERT(slot * 4 <= bytes);
277 
278   return;
279 }
280 
281 static void
ffi_size_stack_pa32(ffi_cif * cif)282 ffi_size_stack_pa32 (ffi_cif *cif)
283 {
284   ffi_type **ptr;
285   int i;
286   int z = 0; /* # stack slots */
287 
288   for (ptr = cif->arg_types, i = 0; i < cif->nargs; ptr++, i++)
289     {
290       int type = (*ptr)->type;
291 
292       switch (type)
293 	{
294 	case FFI_TYPE_DOUBLE:
295 	case FFI_TYPE_UINT64:
296 	case FFI_TYPE_SINT64:
297 	  z += 2 + (z & 1); /* must start on even regs, so we may waste one */
298 	  break;
299 
300 #ifdef PA_HPUX
301 	case FFI_TYPE_LONGDOUBLE:
302 #endif
303 	case FFI_TYPE_STRUCT:
304 	  z += 1; /* pass by ptr, callee will copy */
305 	  break;
306 
307 	default: /* <= 32-bit values */
308 	  z++;
309 	}
310     }
311 
312   /* We can fit up to 6 args in the default 64-byte stack frame,
313      if we need more, we need more stack.  */
314   if (z <= 6)
315     cif->bytes = MIN_STACK_SIZE; /* min stack size */
316   else
317     cif->bytes = 64 + ROUND_UP((z - 6) * sizeof(UINT32), MIN_STACK_SIZE);
318 
319   debug(3, "Calculated stack size is %u bytes\n", cif->bytes);
320 }
321 
322 /* Perform machine dependent cif processing.  */
323 ffi_status
ffi_prep_cif_machdep(ffi_cif * cif)324 ffi_prep_cif_machdep (ffi_cif *cif)
325 {
326   /* Set the return type flag */
327   switch (cif->rtype->type)
328     {
329     case FFI_TYPE_VOID:
330     case FFI_TYPE_FLOAT:
331     case FFI_TYPE_DOUBLE:
332       cif->flags = (unsigned) cif->rtype->type;
333       break;
334 
335 #ifdef PA_HPUX
336     case FFI_TYPE_LONGDOUBLE:
337       /* Long doubles are treated like a structure.  */
338       cif->flags = FFI_TYPE_STRUCT;
339       break;
340 #endif
341 
342     case FFI_TYPE_STRUCT:
343       /* For the return type we have to check the size of the structures.
344 	 If the size is smaller or equal 4 bytes, the result is given back
345 	 in one register. If the size is smaller or equal 8 bytes than we
346 	 return the result in two registers. But if the size is bigger than
347 	 8 bytes, we work with pointers.  */
348       cif->flags = ffi_struct_type(cif->rtype);
349       break;
350 
351     case FFI_TYPE_UINT64:
352     case FFI_TYPE_SINT64:
353       cif->flags = FFI_TYPE_UINT64;
354       break;
355 
356     default:
357       cif->flags = FFI_TYPE_INT;
358       break;
359     }
360 
361   /* Lucky us, because of the unique PA ABI we get to do our
362      own stack sizing.  */
363   switch (cif->abi)
364     {
365     case FFI_PA32:
366       ffi_size_stack_pa32(cif);
367       break;
368 
369     default:
370       FFI_ASSERT(0);
371       break;
372     }
373 
374   return FFI_OK;
375 }
376 
377 extern void ffi_call_pa32 (void (*)(UINT32 *, extended_cif *, unsigned),
378 			   extended_cif *, unsigned, unsigned, unsigned *,
379 			   void (*fn)(void), void *closure);
380 
381 static void
ffi_call_int(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue,void * closure)382 ffi_call_int (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue,
383 	      void *closure)
384 {
385   extended_cif ecif;
386 
387   ecif.cif = cif;
388   ecif.avalue = avalue;
389 
390   /* If the return value is a struct and we don't have a return
391      value address then we need to make one.  */
392 
393   if (rvalue == NULL
394 #ifdef PA_HPUX
395       && (cif->rtype->type == FFI_TYPE_STRUCT
396 	  || cif->rtype->type == FFI_TYPE_LONGDOUBLE))
397 #else
398       && cif->rtype->type == FFI_TYPE_STRUCT)
399 #endif
400     {
401       ecif.rvalue = alloca(cif->rtype->size);
402     }
403   else
404     ecif.rvalue = rvalue;
405 
406 
407   switch (cif->abi)
408     {
409     case FFI_PA32:
410       debug(3, "Calling ffi_call_pa32: ecif=%p, bytes=%u, flags=%u, rvalue=%p, fn=%p\n", &ecif, cif->bytes, cif->flags, ecif.rvalue, (void *)fn);
411       ffi_call_pa32 (ffi_prep_args_pa32, &ecif, cif->bytes,
412 		     cif->flags, ecif.rvalue, fn, closure);
413       break;
414 
415     default:
416       FFI_ASSERT(0);
417       break;
418     }
419 }
420 
421 void
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)422 ffi_call (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
423 {
424   ffi_call_int (cif, fn, rvalue, avalue, NULL);
425 }
426 
427 void
ffi_call_go(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue,void * closure)428 ffi_call_go (ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue,
429 	     void *closure)
430 {
431   ffi_call_int (cif, fn, rvalue, avalue, closure);
432 }
433 
434 #if FFI_CLOSURES
435 /* This is more-or-less an inverse of ffi_call -- we have arguments on
436    the stack, and we need to fill them into a cif structure and invoke
437    the user function. This really ought to be in asm to make sure
438    the compiler doesn't do things we don't expect.  */
439 ffi_status
ffi_closure_inner_pa32(void * closure,UINT32 * stack,int closure_type)440 ffi_closure_inner_pa32 (void *closure, UINT32 *stack, int closure_type)
441 {
442   ffi_cif *cif;
443   void (*fun)(ffi_cif *,void *,void **,void *);
444   void *user_data;
445   void **avalue;
446   void *rvalue;
447   UINT32 ret[2]; /* function can return up to 64-bits in registers */
448   ffi_type **p_arg;
449   char *tmp;
450   int i, avn;
451   unsigned int slot = FIRST_ARG_SLOT;
452   register UINT32 r28 asm("r28");
453 
454   /* A non-zero closure type indicates a go closure.  */
455   if (closure_type)
456     {
457       cif = ((ffi_go_closure *)closure)->cif;
458       fun = ((ffi_go_closure *)closure)->fun;
459       user_data = closure;
460     }
461   else
462     {
463       cif = ((ffi_closure *)closure)->cif;
464       fun = ((ffi_closure *)closure)->fun;
465       user_data = ((ffi_closure *)closure)->user_data;
466     }
467 
468   /* If returning via structure, callee will write to our pointer.  */
469   if (cif->flags == FFI_TYPE_STRUCT)
470     rvalue = (void *)r28;
471   else
472     rvalue = &ret[0];
473 
474   avalue = (void **) alloca (cif->nargs * FFI_SIZEOF_ARG);
475   avn = cif->nargs;
476   p_arg = cif->arg_types;
477 
478   for (i = 0; i < avn; i++)
479     {
480       int type = (*p_arg)->type;
481 
482       switch (type)
483 	{
484 	case FFI_TYPE_SINT8:
485 	case FFI_TYPE_UINT8:
486 	case FFI_TYPE_SINT16:
487 	case FFI_TYPE_UINT16:
488 	case FFI_TYPE_SINT32:
489 	case FFI_TYPE_UINT32:
490 	case FFI_TYPE_POINTER:
491 	  avalue[i] = (char *)(stack - slot) + sizeof(UINT32) - (*p_arg)->size;
492 	  break;
493 
494 	case FFI_TYPE_SINT64:
495 	case FFI_TYPE_UINT64:
496 	  slot += (slot & 1) ? 1 : 2;
497 	  avalue[i] = (void *)(stack - slot);
498 	  break;
499 
500 	case FFI_TYPE_FLOAT:
501 #ifdef PA_LINUX
502 	  /* The closure call is indirect.  In Linux, floating point
503 	     arguments in indirect calls with a prototype are passed
504 	     in the floating point registers instead of the general
505 	     registers.  So, we need to replace what was previously
506 	     stored in the current slot with the value in the
507 	     corresponding floating point register.  */
508 	  switch (slot - FIRST_ARG_SLOT)
509 	    {
510 	    case 0: fstw(fr4, (void *)(stack - slot)); break;
511 	    case 1: fstw(fr5, (void *)(stack - slot)); break;
512 	    case 2: fstw(fr6, (void *)(stack - slot)); break;
513 	    case 3: fstw(fr7, (void *)(stack - slot)); break;
514 	    }
515 #endif
516 	  avalue[i] = (void *)(stack - slot);
517 	  break;
518 
519 	case FFI_TYPE_DOUBLE:
520 	  slot += (slot & 1) ? 1 : 2;
521 #ifdef PA_LINUX
522 	  /* See previous comment for FFI_TYPE_FLOAT.  */
523 	  switch (slot - FIRST_ARG_SLOT)
524 	    {
525 	    case 1: fstd(fr5, (void *)(stack - slot)); break;
526 	    case 3: fstd(fr7, (void *)(stack - slot)); break;
527 	    }
528 #endif
529 	  avalue[i] = (void *)(stack - slot);
530 	  break;
531 
532 #ifdef PA_HPUX
533 	case FFI_TYPE_LONGDOUBLE:
534 	  /* Long doubles are treated like a big structure.  */
535 	  avalue[i] = (void *) *(stack - slot);
536 	  break;
537 #endif
538 
539 	case FFI_TYPE_STRUCT:
540 	  /* Structs smaller or equal than 4 bytes are passed in one
541 	     register. Structs smaller or equal 8 bytes are passed in two
542 	     registers. Larger structures are passed by pointer.  */
543 	  if((*p_arg)->size <= 4)
544 	    {
545 	      avalue[i] = (void *)(stack - slot) + sizeof(UINT32) -
546 		(*p_arg)->size;
547 	    }
548 	  else if ((*p_arg)->size <= 8)
549 	    {
550 	      slot += (slot & 1) ? 1 : 2;
551 	      avalue[i] = (void *)(stack - slot) + sizeof(UINT64) -
552 		(*p_arg)->size;
553 	    }
554 	  else
555 	    avalue[i] = (void *) *(stack - slot);
556 	  break;
557 
558 	default:
559 	  FFI_ASSERT(0);
560 	}
561 
562       slot++;
563       p_arg++;
564     }
565 
566   /* Invoke the closure.  */
567   fun (cif, rvalue, avalue, user_data);
568 
569   debug(3, "after calling function, ret[0] = %08x, ret[1] = %08x\n", ret[0],
570 	ret[1]);
571 
572   /* Store the result using the lower 2 bytes of the flags.  */
573   switch (cif->flags)
574     {
575     case FFI_TYPE_UINT8:
576       *(stack - FIRST_ARG_SLOT) = (UINT8)(ret[0] >> 24);
577       break;
578     case FFI_TYPE_SINT8:
579       *(stack - FIRST_ARG_SLOT) = (SINT8)(ret[0] >> 24);
580       break;
581     case FFI_TYPE_UINT16:
582       *(stack - FIRST_ARG_SLOT) = (UINT16)(ret[0] >> 16);
583       break;
584     case FFI_TYPE_SINT16:
585       *(stack - FIRST_ARG_SLOT) = (SINT16)(ret[0] >> 16);
586       break;
587     case FFI_TYPE_INT:
588     case FFI_TYPE_SINT32:
589     case FFI_TYPE_UINT32:
590       *(stack - FIRST_ARG_SLOT) = ret[0];
591       break;
592     case FFI_TYPE_SINT64:
593     case FFI_TYPE_UINT64:
594       *(stack - FIRST_ARG_SLOT) = ret[0];
595       *(stack - FIRST_ARG_SLOT - 1) = ret[1];
596       break;
597 
598     case FFI_TYPE_DOUBLE:
599       fldd(rvalue, fr4);
600       break;
601 
602     case FFI_TYPE_FLOAT:
603       fldw(rvalue, fr4);
604       break;
605 
606     case FFI_TYPE_STRUCT:
607       /* Don't need a return value, done by caller.  */
608       break;
609 
610     case FFI_TYPE_SMALL_STRUCT2:
611     case FFI_TYPE_SMALL_STRUCT3:
612     case FFI_TYPE_SMALL_STRUCT4:
613       tmp = (void*)(stack -  FIRST_ARG_SLOT);
614       tmp += 4 - cif->rtype->size;
615       memcpy((void*)tmp, &ret[0], cif->rtype->size);
616       break;
617 
618     case FFI_TYPE_SMALL_STRUCT5:
619     case FFI_TYPE_SMALL_STRUCT6:
620     case FFI_TYPE_SMALL_STRUCT7:
621     case FFI_TYPE_SMALL_STRUCT8:
622       {
623 	unsigned int ret2[2];
624 	int off;
625 
626 	/* Right justify ret[0] and ret[1] */
627 	switch (cif->flags)
628 	  {
629 	    case FFI_TYPE_SMALL_STRUCT5: off = 3; break;
630 	    case FFI_TYPE_SMALL_STRUCT6: off = 2; break;
631 	    case FFI_TYPE_SMALL_STRUCT7: off = 1; break;
632 	    default: off = 0; break;
633 	  }
634 
635 	memset (ret2, 0, sizeof (ret2));
636 	memcpy ((char *)ret2 + off, ret, 8 - off);
637 
638 	*(stack - FIRST_ARG_SLOT) = ret2[0];
639 	*(stack - FIRST_ARG_SLOT - 1) = ret2[1];
640       }
641       break;
642 
643     case FFI_TYPE_POINTER:
644     case FFI_TYPE_VOID:
645       break;
646 
647     default:
648       debug(0, "assert with cif->flags: %d\n",cif->flags);
649       FFI_ASSERT(0);
650       break;
651     }
652   return FFI_OK;
653 }
654 
655 /* Fill in a closure to refer to the specified fun and user_data.
656    cif specifies the argument and result types for fun.
657    The cif must already be prep'ed.  */
658 
659 extern void ffi_go_closure_pa32(void);
660 extern void ffi_closure_pa32(void);
661 
662 ffi_status
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)663 ffi_prep_closure_loc (ffi_closure* closure,
664 		      ffi_cif* cif,
665 		      void (*fun)(ffi_cif*,void*,void**,void*),
666 		      void *user_data,
667 		      void *codeloc)
668 {
669   UINT32 *tramp = (UINT32 *)(closure->tramp);
670 #ifdef PA_HPUX
671   UINT32 *tmp;
672 #endif
673 
674   if (cif->abi != FFI_PA32)
675     return FFI_BAD_ABI;
676 
677   /* Make a small trampoline that will branch to our
678      handler function. Use PC-relative addressing.  */
679 
680 #ifdef PA_LINUX
681   tramp[0] = 0xeaa00000; /* b,l .+8,%r21        ; %r21 <- pc+8 */
682   tramp[1] = 0xd6a01c1e; /* depi 0,31,2,%r21    ; mask priv bits */
683   tramp[2] = 0x4aa10028; /* ldw 20(%r21),%r1    ; load plabel */
684   tramp[3] = 0x36b53ff1; /* ldo -8(%r21),%r21   ; get closure addr */
685   tramp[4] = 0x0c201096; /* ldw 0(%r1),%r22     ; address of handler */
686   tramp[5] = 0xeac0c000; /* bv%r0(%r22)         ; branch to handler */
687   tramp[6] = 0x0c281093; /* ldw 4(%r1),%r19     ; GP of handler */
688   tramp[7] = ((UINT32)(ffi_closure_pa32) & ~2);
689 
690   /* Flush d/icache -- have to flush up 2 two lines because of
691      alignment.  */
692   __asm__ volatile(
693 		   "fdc 0(%0)\n\t"
694 		   "fdc %1(%0)\n\t"
695 		   "fic 0(%%sr4, %0)\n\t"
696 		   "fic %1(%%sr4, %0)\n\t"
697 		   "sync\n\t"
698 		   "nop\n\t"
699 		   "nop\n\t"
700 		   "nop\n\t"
701 		   "nop\n\t"
702 		   "nop\n\t"
703 		   "nop\n\t"
704 		   "nop\n"
705 		   :
706 		   : "r"((unsigned long)tramp & ~31),
707 		     "r"(32 /* stride */)
708 		   : "memory");
709 #endif
710 
711 #ifdef PA_HPUX
712   tramp[0] = 0xeaa00000; /* b,l .+8,%r21        ; %r21 <- pc+8  */
713   tramp[1] = 0xd6a01c1e; /* depi 0,31,2,%r21    ; mask priv bits  */
714   tramp[2] = 0x4aa10038; /* ldw 28(%r21),%r1    ; load plabel  */
715   tramp[3] = 0x36b53ff1; /* ldo -8(%r21),%r21   ; get closure addr  */
716   tramp[4] = 0x0c201096; /* ldw 0(%r1),%r22     ; address of handler  */
717   tramp[5] = 0x02c010b4; /* ldsid (%r22),%r20   ; load space id  */
718   tramp[6] = 0x00141820; /* mtsp %r20,%sr0      ; into %sr0  */
719   tramp[7] = 0xe2c00000; /* be 0(%sr0,%r22)     ; branch to handler  */
720   tramp[8] = 0x0c281093; /* ldw 4(%r1),%r19     ; GP of handler  */
721   tramp[9] = ((UINT32)(ffi_closure_pa32) & ~2);
722 
723   /* Flush d/icache -- have to flush three lines because of alignment.  */
724   __asm__ volatile(
725 		   "copy %1,%0\n\t"
726 		   "fdc,m %2(%0)\n\t"
727 		   "fdc,m %2(%0)\n\t"
728 		   "fdc,m %2(%0)\n\t"
729 		   "ldsid (%1),%0\n\t"
730 		   "mtsp %0,%%sr0\n\t"
731 		   "copy %1,%0\n\t"
732 		   "fic,m %2(%%sr0,%0)\n\t"
733 		   "fic,m %2(%%sr0,%0)\n\t"
734 		   "fic,m %2(%%sr0,%0)\n\t"
735 		   "sync\n\t"
736 		   "nop\n\t"
737 		   "nop\n\t"
738 		   "nop\n\t"
739 		   "nop\n\t"
740 		   "nop\n\t"
741 		   "nop\n\t"
742 		   "nop\n"
743 		   : "=&r" ((unsigned long)tmp)
744 		   : "r" ((unsigned long)tramp & ~31),
745 		     "r" (32/* stride */)
746 		   : "memory");
747 #endif
748 
749   closure->cif  = cif;
750   closure->user_data = user_data;
751   closure->fun  = fun;
752 
753   return FFI_OK;
754 }
755 
756 #ifdef FFI_GO_CLOSURES
757 ffi_status
ffi_prep_go_closure(ffi_go_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *))758 ffi_prep_go_closure (ffi_go_closure *closure,
759 		     ffi_cif *cif,
760 		     void (*fun)(ffi_cif *, void *, void **, void *))
761 {
762   if (cif->abi != FFI_PA32)
763     return FFI_BAD_ABI;
764 
765   closure->tramp = &ffi_go_closure_pa32;
766   closure->cif = cif;
767   closure->fun = fun;
768 
769   return FFI_OK;
770 }
771 #endif /* FFI_GO_CLOSURES */
772 #endif
773