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