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