OSDN Git Service

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