OSDN Git Service

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