xref: /aosp_15_r20/external/libffi/src/microblaze/ffi.c (revision 1fd5a2e1d639cd1ddf29dd0c484c123bbd850c21)
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