1/* -----------------------------------------------------------------------
2   sysv.h - Copyright (c) 2003 Jakub Jelinek <jakub@redhat.com>
3	    Copyright (c) 2008 Red Hat, Inc.
4
5   PowerPC64 Assembly glue.
6
7   Permission is hereby granted, free of charge, to any person obtaining
8   a copy of this software and associated documentation files (the
9   ``Software''), to deal in the Software without restriction, including
10   without limitation the rights to use, copy, modify, merge, publish,
11   distribute, sublicense, and/or sell copies of the Software, and to
12   permit persons to whom the Software is furnished to do so, subject to
13   the following conditions:
14
15   The above copyright notice and this permission notice shall be included
16   in all copies or substantial portions of the Software.
17
18   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND,
19   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21   NONINFRINGEMENT.  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
22   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
23   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25   DEALINGS IN THE SOFTWARE.
26   ----------------------------------------------------------------------- */
27
28#define LIBFFI_ASM
29#include <fficonfig.h>
30#include <ffi.h>
31
32#ifdef POWERPC64
33	.hidden	ffi_call_LINUX64
34	.globl	ffi_call_LINUX64
35# if _CALL_ELF == 2
36	.text
37ffi_call_LINUX64:
38	addis	%r2, %r12, .TOC.-ffi_call_LINUX64@ha
39	addi	%r2, %r2, .TOC.-ffi_call_LINUX64@l
40	.localentry ffi_call_LINUX64, . - ffi_call_LINUX64
41# else
42	.section	".opd","aw"
43	.align	3
44ffi_call_LINUX64:
45#  ifdef _CALL_LINUX
46	.quad	.L.ffi_call_LINUX64,.TOC.@tocbase,0
47	.type	ffi_call_LINUX64,@function
48	.text
49.L.ffi_call_LINUX64:
50#  else
51	.hidden	.ffi_call_LINUX64
52	.globl	.ffi_call_LINUX64
53	.quad	.ffi_call_LINUX64,.TOC.@tocbase,0
54	.size	ffi_call_LINUX64,24
55	.type	.ffi_call_LINUX64,@function
56	.text
57.ffi_call_LINUX64:
58#  endif
59# endif
60.LFB1:
61	mflr	%r0
62	std	%r28, -32(%r1)
63	std	%r29, -24(%r1)
64	std	%r30, -16(%r1)
65	std	%r31, -8(%r1)
66	std	%r0, 16(%r1)
67
68	mr	%r28, %r1	/* our AP.  */
69.LCFI0:
70	stdux	%r1, %r1, %r4
71	mr	%r31, %r5	/* flags, */
72	mr	%r30, %r6	/* rvalue, */
73	mr	%r29, %r7	/* function address.  */
74/* Save toc pointer, not for the ffi_prep_args64 call, but for the later
75   bctrl function call.  */
76# if _CALL_ELF == 2
77	std	%r2, 24(%r1)
78# else
79	std	%r2, 40(%r1)
80# endif
81
82	/* Call ffi_prep_args64.  */
83	mr	%r4, %r1
84# if defined _CALL_LINUX || _CALL_ELF == 2
85	bl	ffi_prep_args64
86# else
87	bl	.ffi_prep_args64
88# endif
89
90# if _CALL_ELF == 2
91	mr	%r12, %r29
92# else
93	ld	%r12, 0(%r29)
94	ld	%r2, 8(%r29)
95	ld	%r11, 16(%r29)
96# endif
97	/* Now do the call.  */
98	/* Set up cr1 with bits 4-7 of the flags.  */
99	mtcrf	0x40, %r31
100
101	/* Get the address to call into CTR.  */
102	mtctr	%r12
103	/* Load all those argument registers.  */
104	ld	%r3, -32-(8*8)(%r28)
105	ld	%r4, -32-(7*8)(%r28)
106	ld	%r5, -32-(6*8)(%r28)
107	ld	%r6, -32-(5*8)(%r28)
108	bf-	5, 1f
109	ld	%r7, -32-(4*8)(%r28)
110	ld	%r8, -32-(3*8)(%r28)
111	ld	%r9, -32-(2*8)(%r28)
112	ld	%r10, -32-(1*8)(%r28)
1131:
114
115	/* Load all the FP registers.  */
116	bf-	6, 2f
117	lfd	%f1, -32-(21*8)(%r28)
118	lfd	%f2, -32-(20*8)(%r28)
119	lfd	%f3, -32-(19*8)(%r28)
120	lfd	%f4, -32-(18*8)(%r28)
121	lfd	%f5, -32-(17*8)(%r28)
122	lfd	%f6, -32-(16*8)(%r28)
123	lfd	%f7, -32-(15*8)(%r28)
124	lfd	%f8, -32-(14*8)(%r28)
125	lfd	%f9, -32-(13*8)(%r28)
126	lfd	%f10, -32-(12*8)(%r28)
127	lfd	%f11, -32-(11*8)(%r28)
128	lfd	%f12, -32-(10*8)(%r28)
129	lfd	%f13, -32-(9*8)(%r28)
1302:
131
132	/* Make the call.  */
133	bctrl
134
135	/* This must follow the call immediately, the unwinder
136	   uses this to find out if r2 has been saved or not.  */
137# if _CALL_ELF == 2
138	ld	%r2, 24(%r1)
139# else
140	ld	%r2, 40(%r1)
141# endif
142
143	/* Now, deal with the return value.  */
144	mtcrf	0x01, %r31
145	bt	31, .Lstruct_return_value
146	bt	30, .Ldone_return_value
147	bt	29, .Lfp_return_value
148	std	%r3, 0(%r30)
149	/* Fall through...  */
150
151.Ldone_return_value:
152	/* Restore the registers we used and return.  */
153	mr	%r1, %r28
154	ld	%r0, 16(%r28)
155	ld	%r28, -32(%r28)
156	mtlr	%r0
157	ld	%r29, -24(%r1)
158	ld	%r30, -16(%r1)
159	ld	%r31, -8(%r1)
160	blr
161
162.Lfp_return_value:
163	bf	28, .Lfloat_return_value
164	stfd	%f1, 0(%r30)
165	mtcrf	0x02, %r31 /* cr6  */
166	bf	27, .Ldone_return_value
167	stfd	%f2, 8(%r30)
168	b	.Ldone_return_value
169.Lfloat_return_value:
170	stfs	%f1, 0(%r30)
171	b	.Ldone_return_value
172
173.Lstruct_return_value:
174	bf	29, .Lsmall_struct
175	bf	28, .Lfloat_homog_return_value
176	stfd	%f1, 0(%r30)
177	stfd	%f2, 8(%r30)
178	stfd	%f3, 16(%r30)
179	stfd	%f4, 24(%r30)
180	stfd	%f5, 32(%r30)
181	stfd	%f6, 40(%r30)
182	stfd	%f7, 48(%r30)
183	stfd	%f8, 56(%r30)
184	b	.Ldone_return_value
185
186.Lfloat_homog_return_value:
187	stfs	%f1, 0(%r30)
188	stfs	%f2, 4(%r30)
189	stfs	%f3, 8(%r30)
190	stfs	%f4, 12(%r30)
191	stfs	%f5, 16(%r30)
192	stfs	%f6, 20(%r30)
193	stfs	%f7, 24(%r30)
194	stfs	%f8, 28(%r30)
195	b	.Ldone_return_value
196
197.Lsmall_struct:
198	std	%r3, 0(%r30)
199	std	%r4, 8(%r30)
200	b	.Ldone_return_value
201
202.LFE1:
203	.long	0
204	.byte	0,12,0,1,128,4,0,0
205# if _CALL_ELF == 2
206	.size	ffi_call_LINUX64,.-ffi_call_LINUX64
207# else
208#  ifdef _CALL_LINUX
209	.size	ffi_call_LINUX64,.-.L.ffi_call_LINUX64
210#  else
211	.size	.ffi_call_LINUX64,.-.ffi_call_LINUX64
212#  endif
213# endif
214
215	.section	.eh_frame,EH_FRAME_FLAGS,@progbits
216.Lframe1:
217	.4byte	.LECIE1-.LSCIE1	 # Length of Common Information Entry
218.LSCIE1:
219	.4byte	0x0	 # CIE Identifier Tag
220	.byte	0x1	 # CIE Version
221	.ascii "zR\0"	 # CIE Augmentation
222	.uleb128 0x1	 # CIE Code Alignment Factor
223	.sleb128 -8	 # CIE Data Alignment Factor
224	.byte	0x41	 # CIE RA Column
225	.uleb128 0x1	 # Augmentation size
226	.byte	0x14	 # FDE Encoding (pcrel udata8)
227	.byte	0xc	 # DW_CFA_def_cfa
228	.uleb128 0x1
229	.uleb128 0x0
230	.align 3
231.LECIE1:
232.LSFDE1:
233	.4byte	.LEFDE1-.LASFDE1	 # FDE Length
234.LASFDE1:
235	.4byte	.LASFDE1-.Lframe1	 # FDE CIE offset
236	.8byte	.LFB1-.	 # FDE initial location
237	.8byte	.LFE1-.LFB1	 # FDE address range
238	.uleb128 0x0	 # Augmentation size
239	.byte	0x2	 # DW_CFA_advance_loc1
240	.byte	.LCFI0-.LFB1
241	.byte	0xd	 # DW_CFA_def_cfa_register
242	.uleb128 0x1c
243	.byte	0x11	 # DW_CFA_offset_extended_sf
244	.uleb128 0x41
245	.sleb128 -2
246	.byte	0x9f	 # DW_CFA_offset, column 0x1f
247	.uleb128 0x1
248	.byte	0x9e	 # DW_CFA_offset, column 0x1e
249	.uleb128 0x2
250	.byte	0x9d	 # DW_CFA_offset, column 0x1d
251	.uleb128 0x3
252	.byte	0x9c	 # DW_CFA_offset, column 0x1c
253	.uleb128 0x4
254	.align 3
255.LEFDE1:
256
257#endif
258
259#if (defined __ELF__ && defined __linux__) || _CALL_ELF == 2
260	.section	.note.GNU-stack,"",@progbits
261#endif
262