OSDN Git Service

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