1/* -----------------------------------------------------------------------
2   sysv.S - Copyright (c) 2013 Tensilica, Inc.
3
4   XTENSA 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#define ENTRY(name) .text; .globl name; .type  name,@function; .align 4; name:
32#define END(name) .size name , . - name
33
34/* Assert that the table below is in sync with ffi.h.  */
35
36#if	   FFI_TYPE_UINT8 != 5          \
37        || FFI_TYPE_SINT8 != 6          \
38        || FFI_TYPE_UINT16 != 7         \
39        || FFI_TYPE_SINT16 != 8         \
40        || FFI_TYPE_UINT32 != 9         \
41        || FFI_TYPE_SINT32 != 10        \
42        || FFI_TYPE_UINT64 != 11
43#error "xtensa/sysv.S out of sync with ffi.h"
44#endif
45
46
47/* ffi_call_SYSV (rvalue, rbytes, flags, (*fnaddr)(), bytes, ecif)
48      void *rvalue;            a2
49      unsigned long rbytes;    a3
50      unsigned flags;          a4
51      void (*fnaddr)();        a5
52      unsigned long bytes;     a6
53      extended_cif* ecif)      a7
54*/
55
56ENTRY(ffi_call_SYSV)
57
58	entry	a1, 32              # 32 byte frame for using call8 below
59
60	mov	a10, a7             # a10(->arg0): ecif
61	sub	a11, a1, a6         # a11(->arg1): stack pointer
62	mov	a7, a1              # fp
63	movsp	a1, a11             # set new sp = old_sp - bytes
64
65	movi	a8, ffi_prep_args
66	callx8	a8                  # ffi_prep_args(ecif, stack)
67
68	# prepare to move stack pointer back up to 6 arguments
69	# note that 'bytes' is already aligned
70
71	movi	a10, 6*4
72	sub	a11, a6, a10
73	movgez	a6, a10, a11
74	add	a6, a1, a6
75
76
77	# we can pass up to 6 arguments in registers
78	# for simplicity, just load 6 arguments
79	# (the stack size is at least 32 bytes, so no risk to cross boundaries)
80
81	l32i	a10, a1, 0
82	l32i	a11, a1, 4
83	l32i	a12, a1, 8
84	l32i	a13, a1, 12
85	l32i	a14, a1, 16
86	l32i	a15, a1, 20
87
88	# move stack pointer
89
90	movsp	a1, a6
91
92	callx8	a5                  # (*fn)(args...)
93
94	# Handle return value(s)
95
96	beqz	a2, .Lexit
97
98	movi	a5, FFI_TYPE_STRUCT
99	bne	a4, a5, .Lstore
100	movi	a5, 16
101	blt	a5, a3, .Lexit
102
103	s32i	a10, a2, 0
104	blti	a3, 5, .Lexit
105	addi	a3, a3, -1
106	s32i	a11, a2, 4
107	blti	a3, 8, .Lexit
108	s32i	a12, a2, 8
109	blti	a3, 12, .Lexit
110	s32i	a13, a2, 12
111
112.Lexit:	retw
113
114.Lstore:
115	addi	a4, a4, -FFI_TYPE_UINT8
116	bgei	a4, 7, .Lexit	# should never happen
117	movi	a6, store_calls
118	add	a4, a4, a4
119	addx4	a6, a4, a6	# store_table + idx * 8
120	jx	a6
121
122	.align	8
123store_calls:
124	# UINT8
125	s8i	a10, a2, 0
126	retw
127
128	# SINT8
129	.align	8
130	s8i	a10, a2, 0
131	retw
132
133	# UINT16
134	.align	8
135	s16i	a10, a2, 0
136	retw
137
138	# SINT16
139	.align	8
140	s16i	a10, a2, 0
141	retw
142
143	# UINT32
144	.align	8
145	s32i	a10, a2, 0
146	retw
147
148	# SINT32
149	.align	8
150	s32i	a10, a2, 0
151	retw
152
153	# UINT64
154	.align	8
155	s32i	a10, a2, 0
156	s32i	a11, a2, 4
157	retw
158
159END(ffi_call_SYSV)
160
161
162/*
163 * void ffi_cacheflush (unsigned long start, unsigned long end)
164 */
165
166#define EXTRA_ARGS_SIZE	24
167
168ENTRY(ffi_cacheflush)
169
170	entry	a1, 16
171
1721:
173#if XCHAL_DCACHE_SIZE
174	dhwbi	a2, 0
175#endif
176#if XCHAL_ICACHE_SIZE
177	ihi	a2, 0
178#endif
179	addi	a2, a2, 4
180	blt	a2, a3, 1b
181
182	retw
183
184END(ffi_cacheflush)
185
186/* ffi_trampoline is copied to the stack */
187
188ENTRY(ffi_trampoline)
189
190	entry	a1, 16 + (FFI_REGISTER_NARGS * 4) + (4 * 4)   # [ 0]
191	j	2f                                # [ 3]
192	.align	4                                 # [ 6]
1931:	.long	0                                 # [ 8]
1942:	l32r	a15, 1b                           # [12]
195	_mov 	a14, a0                           # [15]
196	callx0	a15                               # [18]
197                                                  # [21]
198END(ffi_trampoline)
199
200/*
201 * ffi_closure()
202 *
203 * a0:  closure + 21
204 * a14: return address (a0)
205 */
206
207ENTRY(ffi_closure_SYSV)
208
209	/* intentionally omitting entry here */
210
211	# restore return address (a0) and move pointer to closure to a10
212	addi	a10, a0, -21
213	mov	a0, a14
214
215	# allow up to 4 arguments as return values
216	addi	a11, a1, 4 * 4
217
218	# save up to 6 arguments to stack (allocated by entry below)
219	s32i	a2, a11,  0
220	s32i	a3, a11,  4
221	s32i	a4, a11,  8
222	s32i	a5, a11, 12
223	s32i	a6, a11, 16
224	s32i	a7, a11, 20
225
226	movi	a8, ffi_closure_SYSV_inner
227	mov	a12, a1
228	callx8	a8			# .._inner(*closure, **avalue, *rvalue)
229
230	# load up to four return arguments
231	l32i	a2, a1,  0
232	l32i	a3, a1,  4
233	l32i	a4, a1,  8
234	l32i	a5, a1, 12
235
236	# (sign-)extend return value
237	movi	a11, FFI_TYPE_UINT8
238	bne	a10, a11, 1f
239	extui	a2, a2, 0, 8
240	retw
241
2421:	movi	a11, FFI_TYPE_SINT8
243	bne	a10, a11, 1f
244	sext	a2, a2, 7
245	retw
246
2471:	movi	a11, FFI_TYPE_UINT16
248	bne	a10, a11, 1f
249	extui	a2, a2, 0, 16
250	retw
251
2521:	movi	a11, FFI_TYPE_SINT16
253	bne	a10, a11, 1f
254	sext	a2, a2, 15
255
2561:	retw
257
258END(ffi_closure_SYSV)
259