OpenCores
URL https://opencores.org/ocsvn/openrisc/openrisc/trunk

Subversion Repositories openrisc

[/] [openrisc/] [trunk/] [gnu-dev/] [or1k-gcc/] [libffi/] [src/] [pa/] [ffi.c] - Blame information for rev 732

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 732 jeremybenn
/* -----------------------------------------------------------------------
2
   ffi.c - (c) 2003-2004 Randolph Chung <tausq@debian.org>
3
           (c) 2008 Red Hat, Inc.
4
 
5
   HPPA Foreign Function Interface
6
   HP-UX PA ABI support (c) 2006 Free Software Foundation, Inc.
7
 
8
   Permission is hereby granted, free of charge, to any person obtaining
9
   a copy of this software and associated documentation files (the
10
   ``Software''), to deal in the Software without restriction, including
11
   without limitation the rights to use, copy, modify, merge, publish,
12
   distribute, sublicense, and/or sell copies of the Software, and to
13
   permit persons to whom the Software is furnished to do so, subject to
14
   the following conditions:
15
 
16
   The above copyright notice and this permission notice shall be included
17
   in all copies or substantial portions of the Software.
18
 
19
   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
20
   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21
   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22
   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
23
   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
24
   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26
   DEALINGS IN THE SOFTWARE.
27
   ----------------------------------------------------------------------- */
28
 
29
#include <ffi.h>
30
#include <ffi_common.h>
31
 
32
#include <stdlib.h>
33
#include <stdio.h>
34
 
35
#define ROUND_UP(v, a)  (((size_t)(v) + (a) - 1) & ~((a) - 1))
36
 
37
#define MIN_STACK_SIZE  64
38
#define FIRST_ARG_SLOT  9
39
#define DEBUG_LEVEL   0
40
 
41
#define fldw(addr, fpreg) \
42
  __asm__ volatile ("fldw 0(%0), %%" #fpreg "L" : : "r"(addr) : #fpreg)
43
#define fstw(fpreg, addr) \
44
  __asm__ volatile ("fstw %%" #fpreg "L, 0(%0)" : : "r"(addr))
45
#define fldd(addr, fpreg) \
46
  __asm__ volatile ("fldd 0(%0), %%" #fpreg : : "r"(addr) : #fpreg)
47
#define fstd(fpreg, addr) \
48
  __asm__ volatile ("fstd %%" #fpreg "L, 0(%0)" : : "r"(addr))
49
 
50
#define debug(lvl, x...) do { if (lvl <= DEBUG_LEVEL) { printf(x); } } while (0)
51
 
52
static inline int ffi_struct_type(ffi_type *t)
53
{
54
  size_t sz = t->size;
55
 
56
  /* Small structure results are passed in registers,
57
     larger ones are passed by pointer.  Note that
58
     small structures of size 2, 4 and 8 differ from
59
     the corresponding integer types in that they have
60
     different alignment requirements.  */
61
 
62
  if (sz <= 1)
63
    return FFI_TYPE_UINT8;
64
  else if (sz == 2)
65
    return FFI_TYPE_SMALL_STRUCT2;
66
  else if (sz == 3)
67
    return FFI_TYPE_SMALL_STRUCT3;
68
  else if (sz == 4)
69
    return FFI_TYPE_SMALL_STRUCT4;
70
  else if (sz == 5)
71
    return FFI_TYPE_SMALL_STRUCT5;
72
  else if (sz == 6)
73
    return FFI_TYPE_SMALL_STRUCT6;
74
  else if (sz == 7)
75
    return FFI_TYPE_SMALL_STRUCT7;
76
  else if (sz <= 8)
77
    return FFI_TYPE_SMALL_STRUCT8;
78
  else
79
    return FFI_TYPE_STRUCT; /* else, we pass it by pointer.  */
80
}
81
 
82
/* PA has a downward growing stack, which looks like this:
83
 
84
   Offset
85
        [ Variable args ]
86
   SP = (4*(n+9))       arg word N
87
   ...
88
   SP-52                arg word 4
89
        [ Fixed args ]
90
   SP-48                arg word 3
91
   SP-44                arg word 2
92
   SP-40                arg word 1
93
   SP-36                arg word 0
94
        [ Frame marker ]
95
   ...
96
   SP-20                RP
97
   SP-4                 previous SP
98
 
99
   The first four argument words on the stack are reserved for use by
100
   the callee.  Instead, the general and floating registers replace
101
   the first four argument slots.  Non FP arguments are passed solely
102
   in the general registers.  FP arguments are passed in both general
103
   and floating registers when using libffi.
104
 
105
   Non-FP 32-bit args are passed in gr26, gr25, gr24 and gr23.
106
   Non-FP 64-bit args are passed in register pairs, starting
107
   on an odd numbered register (i.e. r25+r26 and r23+r24).
108
   FP 32-bit arguments are passed in fr4L, fr5L, fr6L and fr7L.
109
   FP 64-bit arguments are passed in fr5 and fr7.
110
 
111
   The registers are allocated in the same manner as stack slots.
112
   This allows the callee to save its arguments on the stack if
113
   necessary:
114
 
115
   arg word 3 -> gr23 or fr7L
116
   arg word 2 -> gr24 or fr6L or fr7R
117
   arg word 1 -> gr25 or fr5L
118
   arg word 0 -> gr26 or fr4L or fr5R
119
 
120
   Note that fr4R and fr6R are never used for arguments (i.e.,
121
   doubles are not passed in fr4 or fr6).
122
 
123
   The rest of the arguments are passed on the stack starting at SP-52,
124
   but 64-bit arguments need to be aligned to an 8-byte boundary
125
 
126
   This means we can have holes either in the register allocation,
127
   or in the stack.  */
128
 
129
/* ffi_prep_args is called by the assembly routine once stack space
130
   has been allocated for the function's arguments
131
 
132
   The following code will put everything into the stack frame
133
   (which was allocated by the asm routine), and on return
134
   the asm routine will load the arguments that should be
135
   passed by register into the appropriate registers
136
 
137
   NOTE: We load floating point args in this function... that means we
138
   assume gcc will not mess with fp regs in here.  */
139
 
140
void ffi_prep_args_pa32(UINT32 *stack, extended_cif *ecif, unsigned bytes)
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(stack - slot, fr4); break;
200
            case 1: fldw(stack - slot, fr5); break;
201
            case 2: fldw(stack - slot, fr6); break;
202
            case 3: fldw(stack - slot, 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(stack - slot, fr5); break;
215
              case 3: fldd(stack - slot, 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
extern void ffi_call_pa32(void (*)(UINT32 *, extended_cif *, unsigned),
371
                          extended_cif *, unsigned, unsigned, unsigned *,
372
                          void (*fn)(void));
373
 
374
void ffi_call(ffi_cif *cif, void (*fn)(void), void *rvalue, void **avalue)
375
{
376
  extended_cif ecif;
377
 
378
  ecif.cif = cif;
379
  ecif.avalue = avalue;
380
 
381
  /* If the return value is a struct and we don't have a return
382
     value address then we need to make one.  */
383
 
384
  if (rvalue == NULL
385
#ifdef PA_HPUX
386
      && (cif->rtype->type == FFI_TYPE_STRUCT
387
          || cif->rtype->type == FFI_TYPE_LONGDOUBLE))
388
#else
389
      && cif->rtype->type == FFI_TYPE_STRUCT)
390
#endif
391
    {
392
      ecif.rvalue = alloca(cif->rtype->size);
393
    }
394
  else
395
    ecif.rvalue = rvalue;
396
 
397
 
398
  switch (cif->abi)
399
    {
400
    case FFI_PA32:
401
      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);
402
      ffi_call_pa32(ffi_prep_args_pa32, &ecif, cif->bytes,
403
                     cif->flags, ecif.rvalue, fn);
404
      break;
405
 
406
    default:
407
      FFI_ASSERT(0);
408
      break;
409
    }
410
}
411
 
412
#if FFI_CLOSURES
413
/* This is more-or-less an inverse of ffi_call -- we have arguments on
414
   the stack, and we need to fill them into a cif structure and invoke
415
   the user function. This really ought to be in asm to make sure
416
   the compiler doesn't do things we don't expect.  */
417
ffi_status ffi_closure_inner_pa32(ffi_closure *closure, UINT32 *stack)
418
{
419
  ffi_cif *cif;
420
  void **avalue;
421
  void *rvalue;
422
  UINT32 ret[2]; /* function can return up to 64-bits in registers */
423
  ffi_type **p_arg;
424
  char *tmp;
425
  int i, avn;
426
  unsigned int slot = FIRST_ARG_SLOT;
427
  register UINT32 r28 asm("r28");
428
 
429
  cif = closure->cif;
430
 
431
  /* If returning via structure, callee will write to our pointer.  */
432
  if (cif->flags == FFI_TYPE_STRUCT)
433
    rvalue = (void *)r28;
434
  else
435
    rvalue = &ret[0];
436
 
437
  avalue = (void **)alloca(cif->nargs * FFI_SIZEOF_ARG);
438
  avn = cif->nargs;
439
  p_arg = cif->arg_types;
440
 
441
  for (i = 0; i < avn; i++)
442
    {
443
      int type = (*p_arg)->type;
444
 
445
      switch (type)
446
        {
447
        case FFI_TYPE_SINT8:
448
        case FFI_TYPE_UINT8:
449
        case FFI_TYPE_SINT16:
450
        case FFI_TYPE_UINT16:
451
        case FFI_TYPE_SINT32:
452
        case FFI_TYPE_UINT32:
453
        case FFI_TYPE_POINTER:
454
          avalue[i] = (char *)(stack - slot) + sizeof(UINT32) - (*p_arg)->size;
455
          break;
456
 
457
        case FFI_TYPE_SINT64:
458
        case FFI_TYPE_UINT64:
459
          slot += (slot & 1) ? 1 : 2;
460
          avalue[i] = (void *)(stack - slot);
461
          break;
462
 
463
        case FFI_TYPE_FLOAT:
464
#ifdef PA_LINUX
465
          /* The closure call is indirect.  In Linux, floating point
466
             arguments in indirect calls with a prototype are passed
467
             in the floating point registers instead of the general
468
             registers.  So, we need to replace what was previously
469
             stored in the current slot with the value in the
470
             corresponding floating point register.  */
471
          switch (slot - FIRST_ARG_SLOT)
472
            {
473
            case 0: fstw(fr4, (void *)(stack - slot)); break;
474
            case 1: fstw(fr5, (void *)(stack - slot)); break;
475
            case 2: fstw(fr6, (void *)(stack - slot)); break;
476
            case 3: fstw(fr7, (void *)(stack - slot)); break;
477
            }
478
#endif
479
          avalue[i] = (void *)(stack - slot);
480
          break;
481
 
482
        case FFI_TYPE_DOUBLE:
483
          slot += (slot & 1) ? 1 : 2;
484
#ifdef PA_LINUX
485
          /* See previous comment for FFI_TYPE_FLOAT.  */
486
          switch (slot - FIRST_ARG_SLOT)
487
            {
488
            case 1: fstd(fr5, (void *)(stack - slot)); break;
489
            case 3: fstd(fr7, (void *)(stack - slot)); break;
490
            }
491
#endif
492
          avalue[i] = (void *)(stack - slot);
493
          break;
494
 
495
#ifdef PA_HPUX
496
        case FFI_TYPE_LONGDOUBLE:
497
          /* Long doubles are treated like a big structure.  */
498
          avalue[i] = (void *) *(stack - slot);
499
          break;
500
#endif
501
 
502
        case FFI_TYPE_STRUCT:
503
          /* Structs smaller or equal than 4 bytes are passed in one
504
             register. Structs smaller or equal 8 bytes are passed in two
505
             registers. Larger structures are passed by pointer.  */
506
          if((*p_arg)->size <= 4)
507
            {
508
              avalue[i] = (void *)(stack - slot) + sizeof(UINT32) -
509
                (*p_arg)->size;
510
            }
511
          else if ((*p_arg)->size <= 8)
512
            {
513
              slot += (slot & 1) ? 1 : 2;
514
              avalue[i] = (void *)(stack - slot) + sizeof(UINT64) -
515
                (*p_arg)->size;
516
            }
517
          else
518
            avalue[i] = (void *) *(stack - slot);
519
          break;
520
 
521
        default:
522
          FFI_ASSERT(0);
523
        }
524
 
525
      slot++;
526
      p_arg++;
527
    }
528
 
529
  /* Invoke the closure.  */
530
  (closure->fun) (cif, rvalue, avalue, closure->user_data);
531
 
532
  debug(3, "after calling function, ret[0] = %08x, ret[1] = %08x\n", ret[0],
533
        ret[1]);
534
 
535
  /* Store the result using the lower 2 bytes of the flags.  */
536
  switch (cif->flags)
537
    {
538
    case FFI_TYPE_UINT8:
539
      *(stack - FIRST_ARG_SLOT) = (UINT8)(ret[0] >> 24);
540
      break;
541
    case FFI_TYPE_SINT8:
542
      *(stack - FIRST_ARG_SLOT) = (SINT8)(ret[0] >> 24);
543
      break;
544
    case FFI_TYPE_UINT16:
545
      *(stack - FIRST_ARG_SLOT) = (UINT16)(ret[0] >> 16);
546
      break;
547
    case FFI_TYPE_SINT16:
548
      *(stack - FIRST_ARG_SLOT) = (SINT16)(ret[0] >> 16);
549
      break;
550
    case FFI_TYPE_INT:
551
    case FFI_TYPE_SINT32:
552
    case FFI_TYPE_UINT32:
553
      *(stack - FIRST_ARG_SLOT) = ret[0];
554
      break;
555
    case FFI_TYPE_SINT64:
556
    case FFI_TYPE_UINT64:
557
      *(stack - FIRST_ARG_SLOT) = ret[0];
558
      *(stack - FIRST_ARG_SLOT - 1) = ret[1];
559
      break;
560
 
561
    case FFI_TYPE_DOUBLE:
562
      fldd(rvalue, fr4);
563
      break;
564
 
565
    case FFI_TYPE_FLOAT:
566
      fldw(rvalue, fr4);
567
      break;
568
 
569
    case FFI_TYPE_STRUCT:
570
      /* Don't need a return value, done by caller.  */
571
      break;
572
 
573
    case FFI_TYPE_SMALL_STRUCT2:
574
    case FFI_TYPE_SMALL_STRUCT3:
575
    case FFI_TYPE_SMALL_STRUCT4:
576
      tmp = (void*)(stack -  FIRST_ARG_SLOT);
577
      tmp += 4 - cif->rtype->size;
578
      memcpy((void*)tmp, &ret[0], cif->rtype->size);
579
      break;
580
 
581
    case FFI_TYPE_SMALL_STRUCT5:
582
    case FFI_TYPE_SMALL_STRUCT6:
583
    case FFI_TYPE_SMALL_STRUCT7:
584
    case FFI_TYPE_SMALL_STRUCT8:
585
      {
586
        unsigned int ret2[2];
587
        int off;
588
 
589
        /* Right justify ret[0] and ret[1] */
590
        switch (cif->flags)
591
          {
592
            case FFI_TYPE_SMALL_STRUCT5: off = 3; break;
593
            case FFI_TYPE_SMALL_STRUCT6: off = 2; break;
594
            case FFI_TYPE_SMALL_STRUCT7: off = 1; break;
595
            default: off = 0; break;
596
          }
597
 
598
        memset (ret2, 0, sizeof (ret2));
599
        memcpy ((char *)ret2 + off, ret, 8 - off);
600
 
601
        *(stack - FIRST_ARG_SLOT) = ret2[0];
602
        *(stack - FIRST_ARG_SLOT - 1) = ret2[1];
603
      }
604
      break;
605
 
606
    case FFI_TYPE_POINTER:
607
    case FFI_TYPE_VOID:
608
      break;
609
 
610
    default:
611
      debug(0, "assert with cif->flags: %d\n",cif->flags);
612
      FFI_ASSERT(0);
613
      break;
614
    }
615
  return FFI_OK;
616
}
617
 
618
/* Fill in a closure to refer to the specified fun and user_data.
619
   cif specifies the argument and result types for fun.
620
   The cif must already be prep'ed.  */
621
 
622
extern void ffi_closure_pa32(void);
623
 
624
ffi_status
625
ffi_prep_closure_loc (ffi_closure* closure,
626
                      ffi_cif* cif,
627
                      void (*fun)(ffi_cif*,void*,void**,void*),
628
                      void *user_data,
629
                      void *codeloc)
630
{
631
  UINT32 *tramp = (UINT32 *)(closure->tramp);
632
#ifdef PA_HPUX
633
  UINT32 *tmp;
634
#endif
635
 
636
  FFI_ASSERT (cif->abi == FFI_PA32);
637
 
638
  /* Make a small trampoline that will branch to our
639
     handler function. Use PC-relative addressing.  */
640
 
641
#ifdef PA_LINUX
642
  tramp[0] = 0xeaa00000; /* b,l .+8,%r21        ; %r21 <- pc+8 */
643
  tramp[1] = 0xd6a01c1e; /* depi 0,31,2,%r21    ; mask priv bits */
644
  tramp[2] = 0x4aa10028; /* ldw 20(%r21),%r1    ; load plabel */
645
  tramp[3] = 0x36b53ff1; /* ldo -8(%r21),%r21   ; get closure addr */
646
  tramp[4] = 0x0c201096; /* ldw 0(%r1),%r22     ; address of handler */
647
  tramp[5] = 0xeac0c000; /* bv%r0(%r22)         ; branch to handler */
648
  tramp[6] = 0x0c281093; /* ldw 4(%r1),%r19     ; GP of handler */
649
  tramp[7] = ((UINT32)(ffi_closure_pa32) & ~2);
650
 
651
  /* Flush d/icache -- have to flush up 2 two lines because of
652
     alignment.  */
653
  __asm__ volatile(
654
                   "fdc 0(%0)\n\t"
655
                   "fdc %1(%0)\n\t"
656
                   "fic 0(%%sr4, %0)\n\t"
657
                   "fic %1(%%sr4, %0)\n\t"
658
                   "sync\n\t"
659
                   "nop\n\t"
660
                   "nop\n\t"
661
                   "nop\n\t"
662
                   "nop\n\t"
663
                   "nop\n\t"
664
                   "nop\n\t"
665
                   "nop\n"
666
                   :
667
                   : "r"((unsigned long)tramp & ~31),
668
                     "r"(32 /* stride */)
669
                   : "memory");
670
#endif
671
 
672
#ifdef PA_HPUX
673
  tramp[0] = 0xeaa00000; /* b,l .+8,%r21        ; %r21 <- pc+8  */
674
  tramp[1] = 0xd6a01c1e; /* depi 0,31,2,%r21    ; mask priv bits  */
675
  tramp[2] = 0x4aa10038; /* ldw 28(%r21),%r1    ; load plabel  */
676
  tramp[3] = 0x36b53ff1; /* ldo -8(%r21),%r21   ; get closure addr  */
677
  tramp[4] = 0x0c201096; /* ldw 0(%r1),%r22     ; address of handler  */
678
  tramp[5] = 0x02c010b4; /* ldsid (%r22),%r20   ; load space id  */
679
  tramp[6] = 0x00141820; /* mtsp %r20,%sr0      ; into %sr0  */
680
  tramp[7] = 0xe2c00000; /* be 0(%sr0,%r22)     ; branch to handler  */
681
  tramp[8] = 0x0c281093; /* ldw 4(%r1),%r19     ; GP of handler  */
682
  tramp[9] = ((UINT32)(ffi_closure_pa32) & ~2);
683
 
684
  /* Flush d/icache -- have to flush three lines because of alignment.  */
685
  __asm__ volatile(
686
                   "copy %1,%0\n\t"
687
                   "fdc,m %2(%0)\n\t"
688
                   "fdc,m %2(%0)\n\t"
689
                   "fdc,m %2(%0)\n\t"
690
                   "ldsid (%1),%0\n\t"
691
                   "mtsp %0,%%sr0\n\t"
692
                   "copy %1,%0\n\t"
693
                   "fic,m %2(%%sr0,%0)\n\t"
694
                   "fic,m %2(%%sr0,%0)\n\t"
695
                   "fic,m %2(%%sr0,%0)\n\t"
696
                   "sync\n\t"
697
                   "nop\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"
704
                   : "=&r" ((unsigned long)tmp)
705
                   : "r" ((unsigned long)tramp & ~31),
706
                     "r" (32/* stride */)
707
                   : "memory");
708
#endif
709
 
710
  closure->cif  = cif;
711
  closure->user_data = user_data;
712
  closure->fun  = fun;
713
 
714
  return FFI_OK;
715
}
716
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.