1/* -----------------------------------------------------------------------
2
3   sysv.S - Copyright (c) 2012 Alan Hourihane
4	    Copyright (c) 1998, 2012 Andreas Schwab
5	    Copyright (c) 2008 Red Hat, Inc.
6	    Copyright (c) 2012 Thorsten Glaser
7
8   m68k Foreign Function Interface
9
10   Permission is hereby granted, free of charge, to any person obtaining
11   a copy of this software and associated documentation files (the
12   ``Software''), to deal in the Software without restriction, including
13   without limitation the rights to use, copy, modify, merge, publish,
14   distribute, sublicense, and/or sell copies of the Software, and to
15   permit persons to whom the Software is furnished to do so, subject to
16   the following conditions:
17
18   The above copyright notice and this permission notice shall be included
19   in all copies or substantial portions of the Software.
20
21   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
22   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
27   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28   DEALINGS IN THE SOFTWARE.
29   ----------------------------------------------------------------------- */
30
31#define LIBFFI_ASM
32#include <fficonfig.h>
33#include <ffi.h>
34
35#ifdef HAVE_AS_CFI_PSEUDO_OP
36#define CFI_STARTPROC()		.cfi_startproc
37#define CFI_OFFSET(reg,off)	.cfi_offset	reg,off
38#define CFI_DEF_CFA(reg,off)	.cfi_def_cfa	reg,off
39#define CFI_ENDPROC()		.cfi_endproc
40#else
41#define CFI_STARTPROC()
42#define CFI_OFFSET(reg,off)
43#define CFI_DEF_CFA(reg,off)
44#define CFI_ENDPROC()
45#endif
46
47#ifdef __MINT__
48#define CALLFUNC(funcname) _ ## funcname
49#else
50#define CALLFUNC(funcname) funcname
51#endif
52
53	.text
54
55	.globl	CALLFUNC(ffi_call_SYSV)
56	.type	CALLFUNC(ffi_call_SYSV),@function
57	.align	4
58
59CALLFUNC(ffi_call_SYSV):
60	CFI_STARTPROC()
61	link	%fp,#0
62	CFI_OFFSET(14,-8)
63	CFI_DEF_CFA(14,8)
64	move.l	%d2,-(%sp)
65	CFI_OFFSET(2,-12)
66
67	| Make room for all of the new args.
68	sub.l	12(%fp),%sp
69
70	| Call ffi_prep_args
71	move.l	8(%fp),-(%sp)
72	pea	4(%sp)
73#if !defined __PIC__
74	jsr	CALLFUNC(ffi_prep_args)
75#else
76	bsr.l	CALLFUNC(ffi_prep_args@PLTPC)
77#endif
78	addq.l	#8,%sp
79
80	| Pass pointer to struct value, if any
81#ifdef __MINT__
82	move.l	%d0,%a1
83#else
84	move.l	%a0,%a1
85#endif
86
87	| Call the function
88	move.l	24(%fp),%a0
89	jsr	(%a0)
90
91	| Remove the space we pushed for the args
92	add.l	12(%fp),%sp
93
94	| Load the pointer to storage for the return value
95	move.l	20(%fp),%a1
96
97	| Load the return type code
98	move.l	16(%fp),%d2
99
100	| If the return value pointer is NULL, assume no return value.
101	| NOTE: On the mc68000, tst on an address register is not supported.
102#if !defined(__mc68020__) && !defined(__mc68030__) && !defined(__mc68040__) && !defined(__mc68060__) && !defined(__mcoldfire__)
103	cmp.w	#0, %a1
104#else
105	tst.l	%a1
106#endif
107	jbeq	noretval
108
109	btst	#0,%d2
110	jbeq	retlongint
111	move.l	%d0,(%a1)
112	jbra	epilogue
113
114retlongint:
115	btst	#1,%d2
116	jbeq	retfloat
117	move.l	%d0,(%a1)
118	move.l	%d1,4(%a1)
119	jbra	epilogue
120
121retfloat:
122	btst	#2,%d2
123	jbeq	retdouble
124#if defined(__MC68881__) || defined(__HAVE_68881__)
125	fmove.s	%fp0,(%a1)
126#else
127	move.l	%d0,(%a1)
128#endif
129	jbra	epilogue
130
131retdouble:
132	btst	#3,%d2
133	jbeq	retlongdouble
134#if defined(__MC68881__) || defined(__HAVE_68881__)
135	fmove.d	%fp0,(%a1)
136#else
137	move.l	%d0,(%a1)+
138	move.l	%d1,(%a1)
139#endif
140	jbra	epilogue
141
142retlongdouble:
143	btst	#4,%d2
144	jbeq	retpointer
145#if defined(__MC68881__) || defined(__HAVE_68881__)
146	fmove.x	%fp0,(%a1)
147#else
148	move.l	%d0,(%a1)+
149	move.l	%d1,(%a1)+
150	move.l	%d2,(%a1)
151#endif
152	jbra	epilogue
153
154retpointer:
155	btst	#5,%d2
156	jbeq	retstruct1
157#ifdef __MINT__
158	move.l	%d0,(%a1)
159#else
160	move.l	%a0,(%a1)
161#endif
162	jbra	epilogue
163
164retstruct1:
165	btst	#6,%d2
166	jbeq	retstruct2
167	move.b	%d0,(%a1)
168	jbra	epilogue
169
170retstruct2:
171	btst	#7,%d2
172	jbeq	retsint8
173	move.w	%d0,(%a1)
174	jbra	epilogue
175
176retsint8:
177	btst	#8,%d2
178	jbeq	retsint16
179	| NOTE: On the mc68000, extb is not supported. 8->16, then 16->32.
180#if !defined(__mc68020__) && !defined(__mc68030__) && !defined(__mc68040__) && !defined(__mc68060__) && !defined(__mcoldfire__)
181	ext.w	%d0
182	ext.l	%d0
183#else
184	extb.l	%d0
185#endif
186	move.l	%d0,(%a1)
187	jbra	epilogue
188
189retsint16:
190	btst	#9,%d2
191	jbeq	noretval
192	ext.l	%d0
193	move.l	%d0,(%a1)
194
195noretval:
196epilogue:
197	move.l	(%sp)+,%d2
198	unlk	%fp
199	rts
200	CFI_ENDPROC()
201	.size	CALLFUNC(ffi_call_SYSV),.-CALLFUNC(ffi_call_SYSV)
202
203	.globl	CALLFUNC(ffi_closure_SYSV)
204	.type	CALLFUNC(ffi_closure_SYSV), @function
205	.align	4
206
207CALLFUNC(ffi_closure_SYSV):
208	CFI_STARTPROC()
209	link	%fp,#-12
210	CFI_OFFSET(14,-8)
211	CFI_DEF_CFA(14,8)
212	move.l	%sp,-12(%fp)
213	pea	8(%fp)
214	pea	-12(%fp)
215	move.l	%a0,-(%sp)
216#if !defined __PIC__
217	jsr	CALLFUNC(ffi_closure_SYSV_inner)
218#else
219	bsr.l	CALLFUNC(ffi_closure_SYSV_inner@PLTPC)
220#endif
221
222	lsr.l	#1,%d0
223	jne	1f
224	jcc	.Lcls_epilogue
225	| CIF_FLAGS_INT
226	move.l	-12(%fp),%d0
227.Lcls_epilogue:
228	| no CIF_FLAGS_*
229	unlk	%fp
230	rts
2311:
232	lea	-12(%fp),%a0
233	lsr.l	#2,%d0
234	jne	1f
235	jcs	.Lcls_ret_float
236	| CIF_FLAGS_DINT
237	move.l	(%a0)+,%d0
238	move.l	(%a0),%d1
239	jra	.Lcls_epilogue
240.Lcls_ret_float:
241#if defined(__MC68881__) || defined(__HAVE_68881__)
242	fmove.s	(%a0),%fp0
243#else
244	move.l	(%a0),%d0
245#endif
246	jra	.Lcls_epilogue
2471:
248	lsr.l	#2,%d0
249	jne	1f
250	jcs	.Lcls_ret_ldouble
251	| CIF_FLAGS_DOUBLE
252#if defined(__MC68881__) || defined(__HAVE_68881__)
253	fmove.d	(%a0),%fp0
254#else
255	move.l	(%a0)+,%d0
256	move.l	(%a0),%d1
257#endif
258	jra	.Lcls_epilogue
259.Lcls_ret_ldouble:
260#if defined(__MC68881__) || defined(__HAVE_68881__)
261	fmove.x	(%a0),%fp0
262#else
263	move.l	(%a0)+,%d0
264	move.l	(%a0)+,%d1
265	move.l	(%a0),%d2
266#endif
267	jra	.Lcls_epilogue
2681:
269	lsr.l	#2,%d0
270	jne	1f
271	jcs	.Lcls_ret_struct1
272	| CIF_FLAGS_POINTER
273	move.l	(%a0),%a0
274	move.l	%a0,%d0
275	jra	.Lcls_epilogue
276.Lcls_ret_struct1:
277	move.b	(%a0),%d0
278	jra	.Lcls_epilogue
2791:
280	lsr.l	#2,%d0
281	jne	1f
282	jcs	.Lcls_ret_sint8
283	| CIF_FLAGS_STRUCT2
284	move.w	(%a0),%d0
285	jra	.Lcls_epilogue
286.Lcls_ret_sint8:
287	move.l	(%a0),%d0
288	| NOTE: On the mc68000, extb is not supported. 8->16, then 16->32.
289#if !defined(__mc68020__) && !defined(__mc68030__) && !defined(__mc68040__) && !defined(__mc68060__) && !defined(__mcoldfire__)
290	ext.w	%d0
291	ext.l	%d0
292#else
293	extb.l	%d0
294#endif
295	jra	.Lcls_epilogue
2961:
297	| CIF_FLAGS_SINT16
298	move.l	(%a0),%d0
299	ext.l	%d0
300	jra	.Lcls_epilogue
301	CFI_ENDPROC()
302
303	.size	CALLFUNC(ffi_closure_SYSV),.-CALLFUNC(ffi_closure_SYSV)
304
305	.globl	CALLFUNC(ffi_closure_struct_SYSV)
306	.type	CALLFUNC(ffi_closure_struct_SYSV), @function
307	.align	4
308
309CALLFUNC(ffi_closure_struct_SYSV):
310	CFI_STARTPROC()
311	link	%fp,#0
312	CFI_OFFSET(14,-8)
313	CFI_DEF_CFA(14,8)
314	move.l	%sp,-12(%fp)
315	pea	8(%fp)
316	move.l	%a1,-(%sp)
317	move.l	%a0,-(%sp)
318#if !defined __PIC__
319	jsr	CALLFUNC(ffi_closure_SYSV_inner)
320#else
321	bsr.l	CALLFUNC(ffi_closure_SYSV_inner@PLTPC)
322#endif
323	unlk	%fp
324	rts
325	CFI_ENDPROC()
326	.size	CALLFUNC(ffi_closure_struct_SYSV),.-CALLFUNC(ffi_closure_struct_SYSV)
327
328#if defined __ELF__ && defined __linux__
329	.section	.note.GNU-stack,"",@progbits
330#endif
331