1*1fd5a2e1SPrashanth Swaminathan /* -----------------------------------------------------------------------
2*1fd5a2e1SPrashanth Swaminathan ffi.c - Copyright (c) 2012, 2013 Xilinx, Inc
3*1fd5a2e1SPrashanth Swaminathan
4*1fd5a2e1SPrashanth Swaminathan MicroBlaze Foreign Function Interface
5*1fd5a2e1SPrashanth Swaminathan
6*1fd5a2e1SPrashanth Swaminathan Permission is hereby granted, free of charge, to any person obtaining
7*1fd5a2e1SPrashanth Swaminathan a copy of this software and associated documentation files (the
8*1fd5a2e1SPrashanth Swaminathan ``Software''), to deal in the Software without restriction, including
9*1fd5a2e1SPrashanth Swaminathan without limitation the rights to use, copy, modify, merge, publish,
10*1fd5a2e1SPrashanth Swaminathan distribute, sublicense, and/or sell copies of the Software, and to
11*1fd5a2e1SPrashanth Swaminathan permit persons to whom the Software is furnished to do so, subject to
12*1fd5a2e1SPrashanth Swaminathan the following conditions:
13*1fd5a2e1SPrashanth Swaminathan
14*1fd5a2e1SPrashanth Swaminathan The above copyright notice and this permission notice shall be included
15*1fd5a2e1SPrashanth Swaminathan in all copies or substantial portions of the Software.
16*1fd5a2e1SPrashanth Swaminathan
17*1fd5a2e1SPrashanth Swaminathan THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
18*1fd5a2e1SPrashanth Swaminathan EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19*1fd5a2e1SPrashanth Swaminathan MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20*1fd5a2e1SPrashanth Swaminathan NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21*1fd5a2e1SPrashanth Swaminathan HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22*1fd5a2e1SPrashanth Swaminathan WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23*1fd5a2e1SPrashanth Swaminathan OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24*1fd5a2e1SPrashanth Swaminathan DEALINGS IN THE SOFTWARE.
25*1fd5a2e1SPrashanth Swaminathan ----------------------------------------------------------------------- */
26*1fd5a2e1SPrashanth Swaminathan
27*1fd5a2e1SPrashanth Swaminathan #include <ffi.h>
28*1fd5a2e1SPrashanth Swaminathan #include <ffi_common.h>
29*1fd5a2e1SPrashanth Swaminathan
30*1fd5a2e1SPrashanth Swaminathan extern void ffi_call_SYSV(void (*)(void*, extended_cif*), extended_cif*,
31*1fd5a2e1SPrashanth Swaminathan unsigned int, unsigned int, unsigned int*, void (*fn)(void),
32*1fd5a2e1SPrashanth Swaminathan unsigned int, unsigned int);
33*1fd5a2e1SPrashanth Swaminathan
34*1fd5a2e1SPrashanth Swaminathan extern void ffi_closure_SYSV(void);
35*1fd5a2e1SPrashanth Swaminathan
36*1fd5a2e1SPrashanth Swaminathan #define WORD_SIZE sizeof(unsigned int)
37*1fd5a2e1SPrashanth Swaminathan #define ARGS_REGISTER_SIZE (WORD_SIZE * 6)
38*1fd5a2e1SPrashanth Swaminathan #define WORD_FFI_ALIGN(x) FFI_ALIGN(x, WORD_SIZE)
39*1fd5a2e1SPrashanth Swaminathan
40*1fd5a2e1SPrashanth Swaminathan /* ffi_prep_args is called by the assembly routine once stack space
41*1fd5a2e1SPrashanth Swaminathan has been allocated for the function's arguments */
ffi_prep_args(void * stack,extended_cif * ecif)42*1fd5a2e1SPrashanth Swaminathan void ffi_prep_args(void* stack, extended_cif* ecif)
43*1fd5a2e1SPrashanth Swaminathan {
44*1fd5a2e1SPrashanth Swaminathan unsigned int i;
45*1fd5a2e1SPrashanth Swaminathan ffi_type** p_arg;
46*1fd5a2e1SPrashanth Swaminathan void** p_argv;
47*1fd5a2e1SPrashanth Swaminathan void* stack_args_p = stack;
48*1fd5a2e1SPrashanth Swaminathan
49*1fd5a2e1SPrashanth Swaminathan if (ecif == NULL || ecif->cif == NULL) {
50*1fd5a2e1SPrashanth Swaminathan return; /* no description to prepare */
51*1fd5a2e1SPrashanth Swaminathan }
52*1fd5a2e1SPrashanth Swaminathan
53*1fd5a2e1SPrashanth Swaminathan p_argv = ecif->avalue;
54*1fd5a2e1SPrashanth Swaminathan
55*1fd5a2e1SPrashanth Swaminathan if ((ecif->cif->rtype != NULL) &&
56*1fd5a2e1SPrashanth Swaminathan (ecif->cif->rtype->type == FFI_TYPE_STRUCT))
57*1fd5a2e1SPrashanth Swaminathan {
58*1fd5a2e1SPrashanth Swaminathan /* if return type is a struct which is referenced on the stack/reg5,
59*1fd5a2e1SPrashanth Swaminathan * by a pointer. Stored the return value pointer in r5.
60*1fd5a2e1SPrashanth Swaminathan */
61*1fd5a2e1SPrashanth Swaminathan char* addr = stack_args_p;
62*1fd5a2e1SPrashanth Swaminathan memcpy(addr, &(ecif->rvalue), WORD_SIZE);
63*1fd5a2e1SPrashanth Swaminathan stack_args_p += WORD_SIZE;
64*1fd5a2e1SPrashanth Swaminathan }
65*1fd5a2e1SPrashanth Swaminathan
66*1fd5a2e1SPrashanth Swaminathan if (ecif->avalue == NULL) {
67*1fd5a2e1SPrashanth Swaminathan return; /* no arguments to prepare */
68*1fd5a2e1SPrashanth Swaminathan }
69*1fd5a2e1SPrashanth Swaminathan
70*1fd5a2e1SPrashanth Swaminathan for (i = 0, p_arg = ecif->cif->arg_types; i < ecif->cif->nargs;
71*1fd5a2e1SPrashanth Swaminathan i++, p_arg++)
72*1fd5a2e1SPrashanth Swaminathan {
73*1fd5a2e1SPrashanth Swaminathan size_t size = (*p_arg)->size;
74*1fd5a2e1SPrashanth Swaminathan int type = (*p_arg)->type;
75*1fd5a2e1SPrashanth Swaminathan void* value = p_argv[i];
76*1fd5a2e1SPrashanth Swaminathan char* addr = stack_args_p;
77*1fd5a2e1SPrashanth Swaminathan int aligned_size = WORD_FFI_ALIGN(size);
78*1fd5a2e1SPrashanth Swaminathan
79*1fd5a2e1SPrashanth Swaminathan /* force word alignment on the stack */
80*1fd5a2e1SPrashanth Swaminathan stack_args_p += aligned_size;
81*1fd5a2e1SPrashanth Swaminathan
82*1fd5a2e1SPrashanth Swaminathan switch (type)
83*1fd5a2e1SPrashanth Swaminathan {
84*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
85*1fd5a2e1SPrashanth Swaminathan *(unsigned int *)addr = (unsigned int)*(UINT8*)(value);
86*1fd5a2e1SPrashanth Swaminathan break;
87*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
88*1fd5a2e1SPrashanth Swaminathan *(signed int *)addr = (signed int)*(SINT8*)(value);
89*1fd5a2e1SPrashanth Swaminathan break;
90*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
91*1fd5a2e1SPrashanth Swaminathan *(unsigned int *)addr = (unsigned int)*(UINT16*)(value);
92*1fd5a2e1SPrashanth Swaminathan break;
93*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
94*1fd5a2e1SPrashanth Swaminathan *(signed int *)addr = (signed int)*(SINT16*)(value);
95*1fd5a2e1SPrashanth Swaminathan break;
96*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_STRUCT:
97*1fd5a2e1SPrashanth Swaminathan #if __BIG_ENDIAN__
98*1fd5a2e1SPrashanth Swaminathan /*
99*1fd5a2e1SPrashanth Swaminathan * MicroBlaze toolchain appears to emit:
100*1fd5a2e1SPrashanth Swaminathan * bsrli r5, r5, 8 (caller)
101*1fd5a2e1SPrashanth Swaminathan * ...
102*1fd5a2e1SPrashanth Swaminathan * <branch to callee>
103*1fd5a2e1SPrashanth Swaminathan * ...
104*1fd5a2e1SPrashanth Swaminathan * bslli r5, r5, 8 (callee)
105*1fd5a2e1SPrashanth Swaminathan *
106*1fd5a2e1SPrashanth Swaminathan * For structs like "struct a { uint8_t a[3]; };", when passed
107*1fd5a2e1SPrashanth Swaminathan * by value.
108*1fd5a2e1SPrashanth Swaminathan *
109*1fd5a2e1SPrashanth Swaminathan * Structs like "struct b { uint16_t a; };" are also expected
110*1fd5a2e1SPrashanth Swaminathan * to be packed strangely in registers.
111*1fd5a2e1SPrashanth Swaminathan *
112*1fd5a2e1SPrashanth Swaminathan * This appears to be because the microblaze toolchain expects
113*1fd5a2e1SPrashanth Swaminathan * "struct b == uint16_t", which is only any issue for big
114*1fd5a2e1SPrashanth Swaminathan * endian.
115*1fd5a2e1SPrashanth Swaminathan *
116*1fd5a2e1SPrashanth Swaminathan * The following is a work around for big-endian only, for the
117*1fd5a2e1SPrashanth Swaminathan * above mentioned case, it will re-align the contents of a
118*1fd5a2e1SPrashanth Swaminathan * <= 3-byte struct value.
119*1fd5a2e1SPrashanth Swaminathan */
120*1fd5a2e1SPrashanth Swaminathan if (size < WORD_SIZE)
121*1fd5a2e1SPrashanth Swaminathan {
122*1fd5a2e1SPrashanth Swaminathan memcpy (addr + (WORD_SIZE - size), value, size);
123*1fd5a2e1SPrashanth Swaminathan break;
124*1fd5a2e1SPrashanth Swaminathan }
125*1fd5a2e1SPrashanth Swaminathan #endif
126*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT32:
127*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT32:
128*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
129*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT64:
130*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT64:
131*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_DOUBLE:
132*1fd5a2e1SPrashanth Swaminathan default:
133*1fd5a2e1SPrashanth Swaminathan memcpy(addr, value, aligned_size);
134*1fd5a2e1SPrashanth Swaminathan }
135*1fd5a2e1SPrashanth Swaminathan }
136*1fd5a2e1SPrashanth Swaminathan }
137*1fd5a2e1SPrashanth Swaminathan
ffi_prep_cif_machdep(ffi_cif * cif)138*1fd5a2e1SPrashanth Swaminathan ffi_status ffi_prep_cif_machdep(ffi_cif* cif)
139*1fd5a2e1SPrashanth Swaminathan {
140*1fd5a2e1SPrashanth Swaminathan /* check ABI */
141*1fd5a2e1SPrashanth Swaminathan switch (cif->abi)
142*1fd5a2e1SPrashanth Swaminathan {
143*1fd5a2e1SPrashanth Swaminathan case FFI_SYSV:
144*1fd5a2e1SPrashanth Swaminathan break;
145*1fd5a2e1SPrashanth Swaminathan default:
146*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_ABI;
147*1fd5a2e1SPrashanth Swaminathan }
148*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
149*1fd5a2e1SPrashanth Swaminathan }
150*1fd5a2e1SPrashanth Swaminathan
ffi_call(ffi_cif * cif,void (* fn)(void),void * rvalue,void ** avalue)151*1fd5a2e1SPrashanth Swaminathan void ffi_call(ffi_cif* cif, void (*fn)(void), void* rvalue, void** avalue)
152*1fd5a2e1SPrashanth Swaminathan {
153*1fd5a2e1SPrashanth Swaminathan extended_cif ecif;
154*1fd5a2e1SPrashanth Swaminathan ecif.cif = cif;
155*1fd5a2e1SPrashanth Swaminathan ecif.avalue = avalue;
156*1fd5a2e1SPrashanth Swaminathan
157*1fd5a2e1SPrashanth Swaminathan /* If the return value is a struct and we don't have a return */
158*1fd5a2e1SPrashanth Swaminathan /* value address then we need to make one */
159*1fd5a2e1SPrashanth Swaminathan if ((rvalue == NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) {
160*1fd5a2e1SPrashanth Swaminathan ecif.rvalue = alloca(cif->rtype->size);
161*1fd5a2e1SPrashanth Swaminathan } else {
162*1fd5a2e1SPrashanth Swaminathan ecif.rvalue = rvalue;
163*1fd5a2e1SPrashanth Swaminathan }
164*1fd5a2e1SPrashanth Swaminathan
165*1fd5a2e1SPrashanth Swaminathan switch (cif->abi)
166*1fd5a2e1SPrashanth Swaminathan {
167*1fd5a2e1SPrashanth Swaminathan case FFI_SYSV:
168*1fd5a2e1SPrashanth Swaminathan ffi_call_SYSV(ffi_prep_args, &ecif, cif->bytes, cif->flags,
169*1fd5a2e1SPrashanth Swaminathan ecif.rvalue, fn, cif->rtype->type, cif->rtype->size);
170*1fd5a2e1SPrashanth Swaminathan break;
171*1fd5a2e1SPrashanth Swaminathan default:
172*1fd5a2e1SPrashanth Swaminathan FFI_ASSERT(0);
173*1fd5a2e1SPrashanth Swaminathan break;
174*1fd5a2e1SPrashanth Swaminathan }
175*1fd5a2e1SPrashanth Swaminathan }
176*1fd5a2e1SPrashanth Swaminathan
ffi_closure_call_SYSV(void * register_args,void * stack_args,ffi_closure * closure,void * rvalue,unsigned int * rtype,unsigned int * rsize)177*1fd5a2e1SPrashanth Swaminathan void ffi_closure_call_SYSV(void* register_args, void* stack_args,
178*1fd5a2e1SPrashanth Swaminathan ffi_closure* closure, void* rvalue,
179*1fd5a2e1SPrashanth Swaminathan unsigned int* rtype, unsigned int* rsize)
180*1fd5a2e1SPrashanth Swaminathan {
181*1fd5a2e1SPrashanth Swaminathan /* prepare arguments for closure call */
182*1fd5a2e1SPrashanth Swaminathan ffi_cif* cif = closure->cif;
183*1fd5a2e1SPrashanth Swaminathan ffi_type** arg_types = cif->arg_types;
184*1fd5a2e1SPrashanth Swaminathan
185*1fd5a2e1SPrashanth Swaminathan /* re-allocate data for the args. This needs to be done in order to keep
186*1fd5a2e1SPrashanth Swaminathan * multi-word objects (e.g. structs) in contiguous memory. Callers are not
187*1fd5a2e1SPrashanth Swaminathan * required to store the value of args in the lower 6 words in the stack
188*1fd5a2e1SPrashanth Swaminathan * (although they are allocated in the stack).
189*1fd5a2e1SPrashanth Swaminathan */
190*1fd5a2e1SPrashanth Swaminathan char* stackclone = alloca(cif->bytes);
191*1fd5a2e1SPrashanth Swaminathan void** avalue = alloca(cif->nargs * sizeof(void*));
192*1fd5a2e1SPrashanth Swaminathan void* struct_rvalue = NULL;
193*1fd5a2e1SPrashanth Swaminathan char* ptr = stackclone;
194*1fd5a2e1SPrashanth Swaminathan int i;
195*1fd5a2e1SPrashanth Swaminathan
196*1fd5a2e1SPrashanth Swaminathan /* copy registers into stack clone */
197*1fd5a2e1SPrashanth Swaminathan int registers_used = cif->bytes;
198*1fd5a2e1SPrashanth Swaminathan if (registers_used > ARGS_REGISTER_SIZE) {
199*1fd5a2e1SPrashanth Swaminathan registers_used = ARGS_REGISTER_SIZE;
200*1fd5a2e1SPrashanth Swaminathan }
201*1fd5a2e1SPrashanth Swaminathan memcpy(stackclone, register_args, registers_used);
202*1fd5a2e1SPrashanth Swaminathan
203*1fd5a2e1SPrashanth Swaminathan /* copy stack allocated args into stack clone */
204*1fd5a2e1SPrashanth Swaminathan if (cif->bytes > ARGS_REGISTER_SIZE) {
205*1fd5a2e1SPrashanth Swaminathan int stack_used = cif->bytes - ARGS_REGISTER_SIZE;
206*1fd5a2e1SPrashanth Swaminathan memcpy(stackclone + ARGS_REGISTER_SIZE, stack_args, stack_used);
207*1fd5a2e1SPrashanth Swaminathan }
208*1fd5a2e1SPrashanth Swaminathan
209*1fd5a2e1SPrashanth Swaminathan /* preserve struct type return pointer passing */
210*1fd5a2e1SPrashanth Swaminathan if ((cif->rtype != NULL) && (cif->rtype->type == FFI_TYPE_STRUCT)) {
211*1fd5a2e1SPrashanth Swaminathan struct_rvalue = *((void**)ptr);
212*1fd5a2e1SPrashanth Swaminathan ptr += WORD_SIZE;
213*1fd5a2e1SPrashanth Swaminathan }
214*1fd5a2e1SPrashanth Swaminathan
215*1fd5a2e1SPrashanth Swaminathan /* populate arg pointer list */
216*1fd5a2e1SPrashanth Swaminathan for (i = 0; i < cif->nargs; i++)
217*1fd5a2e1SPrashanth Swaminathan {
218*1fd5a2e1SPrashanth Swaminathan switch (arg_types[i]->type)
219*1fd5a2e1SPrashanth Swaminathan {
220*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT8:
221*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT8:
222*1fd5a2e1SPrashanth Swaminathan #ifdef __BIG_ENDIAN__
223*1fd5a2e1SPrashanth Swaminathan avalue[i] = ptr + 3;
224*1fd5a2e1SPrashanth Swaminathan #else
225*1fd5a2e1SPrashanth Swaminathan avalue[i] = ptr;
226*1fd5a2e1SPrashanth Swaminathan #endif
227*1fd5a2e1SPrashanth Swaminathan break;
228*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT16:
229*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT16:
230*1fd5a2e1SPrashanth Swaminathan #ifdef __BIG_ENDIAN__
231*1fd5a2e1SPrashanth Swaminathan avalue[i] = ptr + 2;
232*1fd5a2e1SPrashanth Swaminathan #else
233*1fd5a2e1SPrashanth Swaminathan avalue[i] = ptr;
234*1fd5a2e1SPrashanth Swaminathan #endif
235*1fd5a2e1SPrashanth Swaminathan break;
236*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_STRUCT:
237*1fd5a2e1SPrashanth Swaminathan #if __BIG_ENDIAN__
238*1fd5a2e1SPrashanth Swaminathan /*
239*1fd5a2e1SPrashanth Swaminathan * Work around strange ABI behaviour.
240*1fd5a2e1SPrashanth Swaminathan * (see info in ffi_prep_args)
241*1fd5a2e1SPrashanth Swaminathan */
242*1fd5a2e1SPrashanth Swaminathan if (arg_types[i]->size < WORD_SIZE)
243*1fd5a2e1SPrashanth Swaminathan {
244*1fd5a2e1SPrashanth Swaminathan memcpy (ptr, ptr + (WORD_SIZE - arg_types[i]->size), arg_types[i]->size);
245*1fd5a2e1SPrashanth Swaminathan }
246*1fd5a2e1SPrashanth Swaminathan #endif
247*1fd5a2e1SPrashanth Swaminathan avalue[i] = (void*)ptr;
248*1fd5a2e1SPrashanth Swaminathan break;
249*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT64:
250*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT64:
251*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_DOUBLE:
252*1fd5a2e1SPrashanth Swaminathan avalue[i] = ptr;
253*1fd5a2e1SPrashanth Swaminathan break;
254*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_SINT32:
255*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_UINT32:
256*1fd5a2e1SPrashanth Swaminathan case FFI_TYPE_FLOAT:
257*1fd5a2e1SPrashanth Swaminathan default:
258*1fd5a2e1SPrashanth Swaminathan /* default 4-byte argument */
259*1fd5a2e1SPrashanth Swaminathan avalue[i] = ptr;
260*1fd5a2e1SPrashanth Swaminathan break;
261*1fd5a2e1SPrashanth Swaminathan }
262*1fd5a2e1SPrashanth Swaminathan ptr += WORD_FFI_ALIGN(arg_types[i]->size);
263*1fd5a2e1SPrashanth Swaminathan }
264*1fd5a2e1SPrashanth Swaminathan
265*1fd5a2e1SPrashanth Swaminathan /* set the return type info passed back to the wrapper */
266*1fd5a2e1SPrashanth Swaminathan *rsize = cif->rtype->size;
267*1fd5a2e1SPrashanth Swaminathan *rtype = cif->rtype->type;
268*1fd5a2e1SPrashanth Swaminathan if (struct_rvalue != NULL) {
269*1fd5a2e1SPrashanth Swaminathan closure->fun(cif, struct_rvalue, avalue, closure->user_data);
270*1fd5a2e1SPrashanth Swaminathan /* copy struct return pointer value into function return value */
271*1fd5a2e1SPrashanth Swaminathan *((void**)rvalue) = struct_rvalue;
272*1fd5a2e1SPrashanth Swaminathan } else {
273*1fd5a2e1SPrashanth Swaminathan closure->fun(cif, rvalue, avalue, closure->user_data);
274*1fd5a2e1SPrashanth Swaminathan }
275*1fd5a2e1SPrashanth Swaminathan }
276*1fd5a2e1SPrashanth Swaminathan
ffi_prep_closure_loc(ffi_closure * closure,ffi_cif * cif,void (* fun)(ffi_cif *,void *,void **,void *),void * user_data,void * codeloc)277*1fd5a2e1SPrashanth Swaminathan ffi_status ffi_prep_closure_loc(
278*1fd5a2e1SPrashanth Swaminathan ffi_closure* closure, ffi_cif* cif,
279*1fd5a2e1SPrashanth Swaminathan void (*fun)(ffi_cif*, void*, void**, void*),
280*1fd5a2e1SPrashanth Swaminathan void* user_data, void* codeloc)
281*1fd5a2e1SPrashanth Swaminathan {
282*1fd5a2e1SPrashanth Swaminathan unsigned long* tramp = (unsigned long*)&(closure->tramp[0]);
283*1fd5a2e1SPrashanth Swaminathan unsigned long cls = (unsigned long)codeloc;
284*1fd5a2e1SPrashanth Swaminathan unsigned long fn = 0;
285*1fd5a2e1SPrashanth Swaminathan unsigned long fn_closure_call_sysv = (unsigned long)ffi_closure_call_SYSV;
286*1fd5a2e1SPrashanth Swaminathan
287*1fd5a2e1SPrashanth Swaminathan closure->cif = cif;
288*1fd5a2e1SPrashanth Swaminathan closure->fun = fun;
289*1fd5a2e1SPrashanth Swaminathan closure->user_data = user_data;
290*1fd5a2e1SPrashanth Swaminathan
291*1fd5a2e1SPrashanth Swaminathan switch (cif->abi)
292*1fd5a2e1SPrashanth Swaminathan {
293*1fd5a2e1SPrashanth Swaminathan case FFI_SYSV:
294*1fd5a2e1SPrashanth Swaminathan fn = (unsigned long)ffi_closure_SYSV;
295*1fd5a2e1SPrashanth Swaminathan
296*1fd5a2e1SPrashanth Swaminathan /* load r11 (temp) with fn */
297*1fd5a2e1SPrashanth Swaminathan /* imm fn(upper) */
298*1fd5a2e1SPrashanth Swaminathan tramp[0] = 0xb0000000 | ((fn >> 16) & 0xffff);
299*1fd5a2e1SPrashanth Swaminathan /* addik r11, r0, fn(lower) */
300*1fd5a2e1SPrashanth Swaminathan tramp[1] = 0x31600000 | (fn & 0xffff);
301*1fd5a2e1SPrashanth Swaminathan
302*1fd5a2e1SPrashanth Swaminathan /* load r12 (temp) with cls */
303*1fd5a2e1SPrashanth Swaminathan /* imm cls(upper) */
304*1fd5a2e1SPrashanth Swaminathan tramp[2] = 0xb0000000 | ((cls >> 16) & 0xffff);
305*1fd5a2e1SPrashanth Swaminathan /* addik r12, r0, cls(lower) */
306*1fd5a2e1SPrashanth Swaminathan tramp[3] = 0x31800000 | (cls & 0xffff);
307*1fd5a2e1SPrashanth Swaminathan
308*1fd5a2e1SPrashanth Swaminathan /* load r3 (temp) with ffi_closure_call_SYSV */
309*1fd5a2e1SPrashanth Swaminathan /* imm fn_closure_call_sysv(upper) */
310*1fd5a2e1SPrashanth Swaminathan tramp[4] = 0xb0000000 | ((fn_closure_call_sysv >> 16) & 0xffff);
311*1fd5a2e1SPrashanth Swaminathan /* addik r3, r0, fn_closure_call_sysv(lower) */
312*1fd5a2e1SPrashanth Swaminathan tramp[5] = 0x30600000 | (fn_closure_call_sysv & 0xffff);
313*1fd5a2e1SPrashanth Swaminathan /* branch/jump to address stored in r11 (fn) */
314*1fd5a2e1SPrashanth Swaminathan tramp[6] = 0x98085800; /* bra r11 */
315*1fd5a2e1SPrashanth Swaminathan
316*1fd5a2e1SPrashanth Swaminathan break;
317*1fd5a2e1SPrashanth Swaminathan default:
318*1fd5a2e1SPrashanth Swaminathan return FFI_BAD_ABI;
319*1fd5a2e1SPrashanth Swaminathan }
320*1fd5a2e1SPrashanth Swaminathan return FFI_OK;
321*1fd5a2e1SPrashanth Swaminathan }
322