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:	dhwbi	a2, 0
173	ihi	a2, 0
174	addi	a2, a2, 4
175	blt	a2, a3, 1b
176
177	retw
178
179END(ffi_cacheflush)
180
181/* ffi_trampoline is copied to the stack */
182
183ENTRY(ffi_trampoline)
184
185	entry	a1, 16 + (FFI_REGISTER_NARGS * 4) + (4 * 4)   # [ 0]
186	j	2f                                # [ 3]
187	.align	4                                 # [ 6]
1881:	.long	0                                 # [ 8]
1892:	l32r	a15, 1b                           # [12]
190	_mov 	a14, a0                           # [15]
191	callx0	a15                               # [18]
192                                                  # [21]
193END(ffi_trampoline)
194
195/*
196 * ffi_closure()
197 *
198 * a0:  closure + 21
199 * a14: return address (a0)
200 */
201
202ENTRY(ffi_closure_SYSV)
203
204	/* intentionally omitting entry here */
205
206	# restore return address (a0) and move pointer to closure to a10
207	addi	a10, a0, -21
208	mov	a0, a14
209
210	# allow up to 4 arguments as return values
211	addi	a11, a1, 4 * 4
212
213	# save up to 6 arguments to stack (allocated by entry below)
214	s32i	a2, a11,  0
215	s32i	a3, a11,  4
216	s32i	a4, a11,  8
217	s32i	a5, a11, 12
218	s32i	a6, a11, 16
219	s32i	a7, a11, 20
220
221	movi	a8, ffi_closure_SYSV_inner
222	mov	a12, a1
223	callx8	a8			# .._inner(*closure, **avalue, *rvalue)
224
225	# load up to four return arguments
226	l32i	a2, a1,  0
227	l32i	a3, a1,  4
228	l32i	a4, a1,  8
229	l32i	a5, a1, 12
230
231	# (sign-)extend return value
232	movi	a11, FFI_TYPE_UINT8
233	bne	a10, a11, 1f
234	extui	a2, a2, 0, 8
235	retw
236
2371:	movi	a11, FFI_TYPE_SINT8
238	bne	a10, a11, 1f
239	sext	a2, a2, 7
240	retw
241
2421:	movi	a11, FFI_TYPE_UINT16
243	bne	a10, a11, 1f
244	extui	a2, a2, 0, 16
245	retw
246
2471:	movi	a11, FFI_TYPE_SINT16
248	bne	a10, a11, 1f
249	sext	a2, a2, 15
250
2511:	retw
252
253END(ffi_closure_SYSV)
254