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, 2016 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#elif defined(__uClinux__) && defined(__ID_SHARED_LIBRARY__)
76	move.l  _current_shared_library_a5_offset_(%a5),%a0
77	move.l  CALLFUNC(ffi_prep_args@GOT)(%a0),%a0
78	jsr     (%a0)
79#elif defined(__mcoldfire__) && !defined(__mcfisab__) && !defined(__mcfisac__)
80	move.l  #_GLOBAL_OFFSET_TABLE_@GOTPC,%a0
81	lea     (-6,%pc,%a0),%a0
82	move.l  CALLFUNC(ffi_prep_args@GOT)(%a0),%a0
83	jsr     (%a0)
84#else
85	bsr.l	CALLFUNC(ffi_prep_args@PLTPC)
86#endif
87	addq.l	#8,%sp
88
89	| Pass pointer to struct value, if any
90#ifdef __MINT__
91	move.l	%d0,%a1
92#else
93	move.l	%a0,%a1
94#endif
95
96	| Call the function
97	move.l	24(%fp),%a0
98	jsr	(%a0)
99
100	| Remove the space we pushed for the args
101	add.l	12(%fp),%sp
102
103	| Load the pointer to storage for the return value
104	move.l	20(%fp),%a1
105
106	| Load the return type code
107	move.l	16(%fp),%d2
108
109	| If the return value pointer is NULL, assume no return value.
110	| NOTE: On the mc68000, tst on an address register is not supported.
111#if !defined(__mc68020__) && !defined(__mc68030__) && !defined(__mc68040__) && !defined(__mc68060__) && !defined(__mcoldfire__)
112	cmp.w	#0, %a1
113#else
114	tst.l	%a1
115#endif
116	jbeq	noretval
117
118	btst	#0,%d2
119	jbeq	retlongint
120	move.l	%d0,(%a1)
121	jbra	epilogue
122
123retlongint:
124	btst	#1,%d2
125	jbeq	retfloat
126	move.l	%d0,(%a1)
127	move.l	%d1,4(%a1)
128	jbra	epilogue
129
130retfloat:
131	btst	#2,%d2
132	jbeq	retdouble
133#if defined(__MC68881__) || defined(__HAVE_68881__)
134	fmove.s	%fp0,(%a1)
135#else
136	move.l	%d0,(%a1)
137#endif
138	jbra	epilogue
139
140retdouble:
141	btst	#3,%d2
142	jbeq	retlongdouble
143#if defined(__MC68881__) || defined(__HAVE_68881__)
144	fmove.d	%fp0,(%a1)
145#else
146	move.l	%d0,(%a1)+
147	move.l	%d1,(%a1)
148#endif
149	jbra	epilogue
150
151retlongdouble:
152	btst	#4,%d2
153	jbeq	retpointer
154#if defined(__MC68881__) || defined(__HAVE_68881__)
155	fmove.x	%fp0,(%a1)
156#else
157	move.l	%d0,(%a1)+
158	move.l	%d1,(%a1)+
159	move.l	%d2,(%a1)
160#endif
161	jbra	epilogue
162
163retpointer:
164	btst	#5,%d2
165	jbeq	retstruct1
166#ifdef __MINT__
167	move.l	%d0,(%a1)
168#else
169	move.l	%a0,(%a1)
170#endif
171	jbra	epilogue
172
173retstruct1:
174	btst	#6,%d2
175	jbeq	retstruct2
176	move.b	%d0,(%a1)
177	jbra	epilogue
178
179retstruct2:
180	btst	#7,%d2
181	jbeq	retsint8
182	move.w	%d0,(%a1)
183	jbra	epilogue
184
185retsint8:
186	btst	#8,%d2
187	jbeq	retsint16
188	| NOTE: On the mc68000, extb is not supported. 8->16, then 16->32.
189#if !defined(__mc68020__) && !defined(__mc68030__) && !defined(__mc68040__) && !defined(__mc68060__) && !defined(__mcoldfire__)
190	ext.w	%d0
191	ext.l	%d0
192#else
193	extb.l	%d0
194#endif
195	move.l	%d0,(%a1)
196	jbra	epilogue
197
198retsint16:
199	btst	#9,%d2
200	jbeq	noretval
201	ext.l	%d0
202	move.l	%d0,(%a1)
203
204noretval:
205epilogue:
206	move.l	(%sp)+,%d2
207	unlk	%fp
208	rts
209	CFI_ENDPROC()
210	.size	CALLFUNC(ffi_call_SYSV),.-CALLFUNC(ffi_call_SYSV)
211
212	.globl	CALLFUNC(ffi_closure_SYSV)
213	.type	CALLFUNC(ffi_closure_SYSV), @function
214	.align	4
215
216CALLFUNC(ffi_closure_SYSV):
217	CFI_STARTPROC()
218	link	%fp,#-12
219	CFI_OFFSET(14,-8)
220	CFI_DEF_CFA(14,8)
221	move.l	%sp,-12(%fp)
222	pea	8(%fp)
223	pea	-12(%fp)
224	move.l	%a0,-(%sp)
225#if !defined __PIC__
226	jsr	CALLFUNC(ffi_closure_SYSV_inner)
227#elif defined(__uClinux__) && defined(__ID_SHARED_LIBRARY__)
228	move.l  _current_shared_library_a5_offset_(%a5),%a0
229	move.l  CALLFUNC(ffi_closure_SYSV_inner@GOT)(%a0),%a0
230	jsr     (%a0)
231#elif defined(__mcoldfire__) && !defined(__mcfisab__) && !defined(__mcfisac__)
232	move.l  #_GLOBAL_OFFSET_TABLE_@GOTPC,%a0
233	lea     (-6,%pc,%a0),%a0
234	move.l  CALLFUNC(ffi_closure_SYSV_inner@GOT)(%a0),%a0
235	jsr     (%a0)
236#else
237	bsr.l	CALLFUNC(ffi_closure_SYSV_inner@PLTPC)
238#endif
239
240	lsr.l	#1,%d0
241	jne	1f
242	jcc	.Lcls_epilogue
243	| CIF_FLAGS_INT
244	move.l	-12(%fp),%d0
245.Lcls_epilogue:
246	| no CIF_FLAGS_*
247	unlk	%fp
248	rts
2491:
250	lea	-12(%fp),%a0
251	lsr.l	#2,%d0
252	jne	1f
253	jcs	.Lcls_ret_float
254	| CIF_FLAGS_DINT
255	move.l	(%a0)+,%d0
256	move.l	(%a0),%d1
257	jra	.Lcls_epilogue
258.Lcls_ret_float:
259#if defined(__MC68881__) || defined(__HAVE_68881__)
260	fmove.s	(%a0),%fp0
261#else
262	move.l	(%a0),%d0
263#endif
264	jra	.Lcls_epilogue
2651:
266	lsr.l	#2,%d0
267	jne	1f
268	jcs	.Lcls_ret_ldouble
269	| CIF_FLAGS_DOUBLE
270#if defined(__MC68881__) || defined(__HAVE_68881__)
271	fmove.d	(%a0),%fp0
272#else
273	move.l	(%a0)+,%d0
274	move.l	(%a0),%d1
275#endif
276	jra	.Lcls_epilogue
277.Lcls_ret_ldouble:
278#if defined(__MC68881__) || defined(__HAVE_68881__)
279	fmove.x	(%a0),%fp0
280#else
281	move.l	(%a0)+,%d0
282	move.l	(%a0)+,%d1
283	move.l	(%a0),%d2
284#endif
285	jra	.Lcls_epilogue
2861:
287	lsr.l	#2,%d0
288	jne	1f
289	jcs	.Lcls_ret_struct1
290	| CIF_FLAGS_POINTER
291	move.l	(%a0),%a0
292	move.l	%a0,%d0
293	jra	.Lcls_epilogue
294.Lcls_ret_struct1:
295	move.b	(%a0),%d0
296	jra	.Lcls_epilogue
2971:
298	lsr.l	#2,%d0
299	jne	1f
300	jcs	.Lcls_ret_sint8
301	| CIF_FLAGS_STRUCT2
302	move.w	(%a0),%d0
303	jra	.Lcls_epilogue
304.Lcls_ret_sint8:
305	move.l	(%a0),%d0
306	| NOTE: On the mc68000, extb is not supported. 8->16, then 16->32.
307#if !defined(__mc68020__) && !defined(__mc68030__) && !defined(__mc68040__) && !defined(__mc68060__) && !defined(__mcoldfire__)
308	ext.w	%d0
309	ext.l	%d0
310#else
311	extb.l	%d0
312#endif
313	jra	.Lcls_epilogue
3141:
315	| CIF_FLAGS_SINT16
316	move.l	(%a0),%d0
317	ext.l	%d0
318	jra	.Lcls_epilogue
319	CFI_ENDPROC()
320
321	.size	CALLFUNC(ffi_closure_SYSV),.-CALLFUNC(ffi_closure_SYSV)
322
323	.globl	CALLFUNC(ffi_closure_struct_SYSV)
324	.type	CALLFUNC(ffi_closure_struct_SYSV), @function
325	.align	4
326
327CALLFUNC(ffi_closure_struct_SYSV):
328	CFI_STARTPROC()
329	link	%fp,#0
330	CFI_OFFSET(14,-8)
331	CFI_DEF_CFA(14,8)
332	move.l	%sp,-12(%fp)
333	pea	8(%fp)
334	move.l	%a1,-(%sp)
335	move.l	%a0,-(%sp)
336#if !defined __PIC__
337	jsr	CALLFUNC(ffi_closure_SYSV_inner)
338#elif defined(__uClinux__) && defined(__ID_SHARED_LIBRARY__)
339	move.l  _current_shared_library_a5_offset_(%a5),%a0
340	move.l  CALLFUNC(ffi_closure_SYSV_inner@GOT)(%a0),%a0
341	jsr     (%a0)
342#elif defined(__mcoldfire__) && !defined(__mcfisab__) && !defined(__mcfisac__)
343	move.l  #_GLOBAL_OFFSET_TABLE_@GOTPC,%a0
344	lea     (-6,%pc,%a0),%a0
345	move.l  CALLFUNC(ffi_closure_SYSV_inner@GOT)(%a0),%a0
346	jsr     (%a0)
347#else
348	bsr.l	CALLFUNC(ffi_closure_SYSV_inner@PLTPC)
349#endif
350	unlk	%fp
351	rts
352	CFI_ENDPROC()
353	.size	CALLFUNC(ffi_closure_struct_SYSV),.-CALLFUNC(ffi_closure_struct_SYSV)
354
355#if defined __ELF__ && defined __linux__
356	.section	.note.GNU-stack,"",@progbits
357#endif
358