1/* -----------------------------------------------------------------------
2   sysv.S - Copyright (c) 2012, 2013 Xilinx, Inc
3
4   MicroBlaze Foreign Function Interface
5
6   Permission is hereby granted, free of charge, to any person obtaining
7   a copy of this software and associated documentation files (the
8   ``Software''), to deal in the Software without restriction, including
9   without limitation the rights to use, copy, modify, merge, publish,
10   distribute, sublicense, and/or sell copies of the Software, and to
11   permit persons to whom the Software is furnished to do so, subject to
12   the following conditions:
13
14   The above copyright notice and this permission notice shall be included
15   in all copies or substantial portions of the Software.
16
17   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
18   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
21   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
22   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24   DEALINGS IN THE SOFTWARE.
25   ----------------------------------------------------------------------- */
26
27#define LIBFFI_ASM
28#include <fficonfig.h>
29#include <ffi.h>
30
31	/*
32	 * arg[0] (r5)  = ffi_prep_args,
33	 * arg[1] (r6)  = &ecif,
34	 * arg[2] (r7)  = cif->bytes,
35	 * arg[3] (r8)  = cif->flags,
36	 * arg[4] (r9)  = ecif.rvalue,
37	 * arg[5] (r10) = fn
38	 * arg[6] (sp[0]) = cif->rtype->type
39	 * arg[7] (sp[4]) = cif->rtype->size
40	 */
41	.text
42	.globl ffi_call_SYSV
43	.type ffi_call_SYSV, @function
44ffi_call_SYSV:
45	/* push callee saves */
46	addik r1, r1, -20
47	swi r19, r1, 0 /* Frame Pointer */
48	swi r20, r1, 4 /* PIC register */
49	swi r21, r1, 8 /* PIC register */
50	swi r22, r1, 12 /* save for locals */
51	swi r23, r1, 16 /* save for locals */
52
53	/* save the r5-r10 registers in the stack */
54	addik r1, r1, -24 /* increment sp to store 6x 32-bit words */
55	swi r5, r1, 0
56	swi r6, r1, 4
57	swi r7, r1, 8
58	swi r8, r1, 12
59	swi r9, r1, 16
60	swi r10, r1, 20
61
62	/* save function pointer */
63	addik r3, r5, 0 /* copy ffi_prep_args into r3 */
64	addik r22, r1, 0 /* save sp for unallocated args into r22 (callee-saved) */
65	addik r23, r10, 0 /* save function address into r23 (callee-saved) */
66
67	/* prepare stack with allocation for n (bytes = r7) args */
68	rsub r1, r7, r1 /* subtract bytes from sp */
69
70	/* prep args for ffi_prep_args call */
71	addik r5, r1, 0 /* store stack pointer into arg[0] */
72	/* r6 still holds ecif for arg[1] */
73
74	/* Call ffi_prep_args(stack, &ecif). */
75	addik r1, r1, -4
76	swi r15, r1, 0 /* store the link register in the frame */
77	brald r15, r3
78	nop /* branch has delay slot */
79	lwi r15, r1, 0
80	addik r1, r1, 4 /* restore the link register from the frame */
81	/* returns calling stack pointer location */
82
83	/* prepare args for fn call, prep_args populates them onto the stack */
84	lwi r5, r1, 0 /* arg[0] */
85	lwi r6, r1, 4 /* arg[1] */
86	lwi r7, r1, 8 /* arg[2] */
87	lwi r8, r1, 12 /* arg[3] */
88	lwi r9, r1, 16 /* arg[4] */
89	lwi r10, r1, 20 /* arg[5] */
90
91	/* call (fn) (...). */
92	addik r1, r1, -4
93	swi r15, r1, 0 /* store the link register in the frame */
94	brald r15, r23
95	nop /* branch has delay slot */
96	lwi r15, r1, 0
97	addik r1, r1, 4 /* restore the link register from the frame */
98
99	/* Remove the space we pushed for the args. */
100	addik r1, r22, 0 /* restore old SP */
101
102	/* restore this functions parameters */
103	lwi r5, r1, 0 /* arg[0] */
104	lwi r6, r1, 4 /* arg[1] */
105	lwi r7, r1, 8 /* arg[2] */
106	lwi r8, r1, 12 /* arg[3] */
107	lwi r9, r1, 16 /* arg[4] */
108	lwi r10, r1, 20 /* arg[5] */
109	addik r1, r1, 24 /* decrement sp to de-allocate 6x 32-bit words */
110
111	/* If the return value pointer is NULL, assume no return value. */
112	beqi r9, ffi_call_SYSV_end
113
114	lwi r22, r1, 48 /* get return type (20 for locals + 28 for arg[6]) */
115	lwi r23, r1, 52 /* get return size (20 for locals + 32 for arg[7])  */
116
117	/* Check if return type is actually a struct, do nothing */
118	rsubi r11, r22, FFI_TYPE_STRUCT
119	beqi r11, ffi_call_SYSV_end
120
121	/* Return 8bit */
122	rsubi r11, r23, 1
123	beqi r11, ffi_call_SYSV_store8
124
125	/* Return 16bit */
126	rsubi r11, r23, 2
127	beqi r11, ffi_call_SYSV_store16
128
129	/* Return 32bit */
130	rsubi r11, r23, 4
131	beqi r11, ffi_call_SYSV_store32
132
133	/* Return 64bit */
134	rsubi r11, r23, 8
135	beqi r11, ffi_call_SYSV_store64
136
137	/* Didn't match anything */
138	bri ffi_call_SYSV_end
139
140ffi_call_SYSV_store64:
141	swi r3, r9, 0 /* store word r3 into return value */
142	swi r4, r9, 4 /* store word r4 into return value */
143	bri ffi_call_SYSV_end
144
145ffi_call_SYSV_store32:
146	swi r3, r9, 0 /* store word r3 into return value */
147	bri ffi_call_SYSV_end
148
149ffi_call_SYSV_store16:
150#ifdef __BIG_ENDIAN__
151	shi r3, r9, 2 /* store half-word r3 into return value */
152#else
153	shi r3, r9, 0 /* store half-word r3 into return value */
154#endif
155	bri ffi_call_SYSV_end
156
157ffi_call_SYSV_store8:
158#ifdef __BIG_ENDIAN__
159	sbi r3, r9, 3 /* store byte r3 into return value */
160#else
161	sbi r3, r9, 0 /* store byte r3 into return value */
162#endif
163	bri ffi_call_SYSV_end
164
165ffi_call_SYSV_end:
166	/* callee restores */
167	lwi r19, r1, 0 /* frame pointer */
168	lwi r20, r1, 4 /* PIC register */
169	lwi r21, r1, 8 /* PIC register */
170	lwi r22, r1, 12
171	lwi r23, r1, 16
172	addik r1, r1, 20
173
174	/* return from sub-routine (with delay slot) */
175	rtsd r15, 8
176	nop
177
178	.size ffi_call_SYSV, . - ffi_call_SYSV
179
180/* ------------------------------------------------------------------------- */
181
182	/*
183	 * args passed into this function, are passed down to the callee.
184	 * this function is the target of the closure trampoline, as such r12 is
185	 * a pointer to the closure object.
186	 */
187	.text
188	.globl ffi_closure_SYSV
189	.type ffi_closure_SYSV, @function
190ffi_closure_SYSV:
191	/* push callee saves */
192	addik r11, r1, 28 /* save stack args start location (excluding regs/link) */
193	addik r1, r1, -12
194	swi r19, r1, 0 /* Frame Pointer */
195	swi r20, r1, 4 /* PIC register */
196	swi r21, r1, 8 /* PIC register */
197
198	/* store register args on stack */
199	addik r1, r1, -24
200	swi r5, r1, 0
201	swi r6, r1, 4
202	swi r7, r1, 8
203	swi r8, r1, 12
204	swi r9, r1, 16
205	swi r10, r1, 20
206
207	/* setup args */
208	addik r5, r1, 0 /* register_args */
209	addik r6, r11, 0 /* stack_args */
210	addik r7, r12, 0 /* closure object */
211	addik r1, r1, -8 /* allocate return value */
212	addik r8, r1, 0 /* void* rvalue */
213	addik r1, r1, -8 /* allocate for return type/size values */
214	addik r9, r1, 0 /* void* rtype */
215	addik r10, r1, 4 /* void* rsize */
216
217	/* call the wrap_call function */
218	addik r1, r1, -28 /* allocate args + link reg */
219	swi r15, r1, 0 /* store the link register in the frame */
220	brald r15, r3
221	nop /* branch has delay slot */
222	lwi r15, r1, 0
223	addik r1, r1, 28 /* restore the link register from the frame */
224
225ffi_closure_SYSV_prepare_return:
226	lwi r9, r1, 0 /* rtype */
227	lwi r10, r1, 4 /* rsize */
228	addik r1, r1, 8 /* de-allocate return info values */
229
230	/* Check if return type is actually a struct, store 4 bytes */
231	rsubi r11, r9, FFI_TYPE_STRUCT
232	beqi r11, ffi_closure_SYSV_store32
233
234	/* Return 8bit */
235	rsubi r11, r10, 1
236	beqi r11, ffi_closure_SYSV_store8
237
238	/* Return 16bit */
239	rsubi r11, r10, 2
240	beqi r11, ffi_closure_SYSV_store16
241
242	/* Return 32bit */
243	rsubi r11, r10, 4
244	beqi r11, ffi_closure_SYSV_store32
245
246	/* Return 64bit */
247	rsubi r11, r10, 8
248	beqi r11, ffi_closure_SYSV_store64
249
250	/* Didn't match anything */
251	bri ffi_closure_SYSV_end
252
253ffi_closure_SYSV_store64:
254	lwi r3, r1, 0 /* store word r3 into return value */
255	lwi r4, r1, 4 /* store word r4 into return value */
256	/* 64 bits == 2 words, no sign extend occurs */
257	bri ffi_closure_SYSV_end
258
259ffi_closure_SYSV_store32:
260	lwi r3, r1, 0 /* store word r3 into return value */
261	/* 32 bits == 1 word, no sign extend occurs */
262	bri ffi_closure_SYSV_end
263
264ffi_closure_SYSV_store16:
265#ifdef __BIG_ENDIAN__
266	lhui r3, r1, 2 /* store half-word r3 into return value */
267#else
268	lhui r3, r1, 0 /* store half-word r3 into return value */
269#endif
270	rsubi r11, r9, FFI_TYPE_SINT16
271	bnei r11, ffi_closure_SYSV_end
272	sext16 r3, r3 /* fix sign extend of sint8 */
273	bri ffi_closure_SYSV_end
274
275ffi_closure_SYSV_store8:
276#ifdef __BIG_ENDIAN__
277	lbui r3, r1, 3 /* store byte r3 into return value */
278#else
279	lbui r3, r1, 0 /* store byte r3 into return value */
280#endif
281	rsubi r11, r9, FFI_TYPE_SINT8
282	bnei r11, ffi_closure_SYSV_end
283	sext8 r3, r3 /* fix sign extend of sint8 */
284	bri ffi_closure_SYSV_end
285
286ffi_closure_SYSV_end:
287	addik r1, r1, 8 /* de-allocate return value */
288
289	/* de-allocate stored args */
290	addik r1, r1, 24
291
292	/* callee restores */
293	lwi r19, r1, 0 /* frame pointer */
294	lwi r20, r1, 4 /* PIC register */
295	lwi r21, r1, 8 /* PIC register */
296	addik r1, r1, 12
297
298	/* return from sub-routine (with delay slot) */
299	rtsd r15, 8
300	nop
301
302	.size ffi_closure_SYSV, . - ffi_closure_SYSV
303