1/* -----------------------------------------------------------------------
2   linux.S - (c) 2003-2004 Randolph Chung <tausq@debian.org>
3	     (c) 2008 Red Hat, Inc.
4	     (c) 2016 John David Anglin
5
6   HPPA Foreign Function Interface
7
8   Permission is hereby granted, free of charge, to any person obtaining
9   a copy of this software and associated documentation files (the
10   ``Software''), to deal in the Software without restriction, including
11   without limitation the rights to use, copy, modify, merge, publish,
12   distribute, sublicense, and/or sell copies of the Software, and to
13   permit persons to whom the Software is furnished to do so, subject to
14   the following conditions:
15
16   The above copyright notice and this permission notice shall be included
17   in all copies or substantial portions of the Software.
18
19   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
20   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22   IN NO EVENT SHALL RENESAS TECHNOLOGY BE LIABLE FOR ANY CLAIM, DAMAGES OR
23   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
24   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
25   OTHER DEALINGS IN THE SOFTWARE.
26   ----------------------------------------------------------------------- */
27
28#define LIBFFI_ASM
29#include <fficonfig.h>
30#include <ffi.h>
31
32	.text
33	.level 1.1
34	.align 4
35
36	/* void ffi_call_pa32(void (*)(char *, extended_cif *),
37			       extended_cif *ecif,
38			       unsigned bytes,
39			       unsigned flags,
40			       unsigned *rvalue,
41			       void (*fn)(void),
42			       ffi_go_closure *closure);
43	 */
44
45	.export ffi_call_pa32,code
46	.import ffi_prep_args_pa32,code
47
48	.type ffi_call_pa32, @function
49	.cfi_startproc
50ffi_call_pa32:
51	.proc
52	.callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=4
53	.entry
54	stw %rp, -20(%sp)
55	copy %r3, %r1
56        .cfi_offset 2, -20
57        .cfi_register 3, 1
58
59	copy %sp, %r3
60	.cfi_def_cfa_register 3
61
62	/* Setup the stack for calling prep_args...
63	   We want the stack to look like this:
64
65	   [ Previous stack                            ] <- %r3
66
67	   [ 64-bytes register save area               ] <- %r4
68
69	   [ Stack space for actual call, passed as    ] <- %arg0
70	   [     arg0 to ffi_prep_args_pa32           ]
71
72	   [ Stack for calling prep_args               ] <- %sp
73	 */
74
75	stwm %r1, 64(%sp)
76	.cfi_offset 3, 0
77	stw %r4, 12(%r3)
78	copy %sp, %r4
79
80	addl %arg2, %r4, %arg0      /* arg stack */
81	stw %arg3, -48(%r3)         /* save flags; we need it later */
82
83	/* Call prep_args:
84	   %arg0(stack) -- set up above
85	   %arg1(ecif) -- same as incoming param
86	   %arg2(bytes) -- same as incoming param */
87	bl ffi_prep_args_pa32,%r2
88	ldo 64(%arg0), %sp
89	ldo -64(%sp), %sp
90
91	/* now %sp should point where %arg0 was pointing.  */
92
93	/* Load the arguments that should be passed in registers
94	   The fp args were loaded by the prep_args function.  */
95	ldw -36(%sp), %arg0
96	ldw -40(%sp), %arg1
97	ldw -44(%sp), %arg2
98	ldw -48(%sp), %arg3
99
100	/* in case the function is going to return a structure
101	   we need to give it a place to put the result.  */
102	ldw -52(%r3), %ret0                     /* %ret0 <- rvalue */
103	ldw -56(%r3), %r22                      /* %r22 <- function to call */
104	ldw -60(%r3), %ret1                     /* %ret1 <- closure */
105	bl $$dyncall, %r31                      /* Call the user function */
106	copy %r31, %rp
107
108	/* Prepare to store the result; we need to recover flags and rvalue.  */
109	ldw -48(%r3), %r21                      /* r21 <- flags */
110	ldw -52(%r3), %r20                      /* r20 <- rvalue */
111
112	/* Store the result according to the return type.  */
113
114.Lcheckint:
115	comib,<>,n FFI_TYPE_INT, %r21, .Lcheckint8
116	b	.Ldone
117	stw	%ret0, 0(%r20)
118
119.Lcheckint8:
120	comib,<>,n FFI_TYPE_UINT8, %r21, .Lcheckint16
121	b	.Ldone
122	stb	%ret0, 0(%r20)
123
124.Lcheckint16:
125	comib,<>,n FFI_TYPE_UINT16, %r21, .Lcheckdbl
126	b	.Ldone
127	sth	%ret0, 0(%r20)
128
129.Lcheckdbl:
130	comib,<>,n FFI_TYPE_DOUBLE, %r21, .Lcheckfloat
131	b	.Ldone
132	fstd	%fr4,0(%r20)
133
134.Lcheckfloat:
135	comib,<>,n FFI_TYPE_FLOAT, %r21, .Lcheckll
136	b	.Ldone
137	fstw	%fr4L,0(%r20)
138
139.Lcheckll:
140	comib,<>,n FFI_TYPE_UINT64, %r21, .Lchecksmst2
141	stw	%ret0, 0(%r20)
142	b	.Ldone
143	stw	%ret1, 4(%r20)
144
145.Lchecksmst2:
146	comib,<>,n FFI_TYPE_SMALL_STRUCT2, %r21, .Lchecksmst3
147	/* 2-byte structs are returned in ret0 as ????xxyy.  */
148	extru	%ret0, 23, 8, %r22
149	stbs,ma	%r22, 1(%r20)
150	b	.Ldone
151	stb	%ret0, 0(%r20)
152
153.Lchecksmst3:
154	comib,<>,n FFI_TYPE_SMALL_STRUCT3, %r21, .Lchecksmst4
155	/* 3-byte structs are returned in ret0 as ??xxyyzz.  */
156	extru	%ret0, 15, 8, %r22
157	stbs,ma	%r22, 1(%r20)
158	extru	%ret0, 23, 8, %r22
159	stbs,ma	%r22, 1(%r20)
160	b	.Ldone
161	stb	%ret0, 0(%r20)
162
163.Lchecksmst4:
164	comib,<>,n FFI_TYPE_SMALL_STRUCT4, %r21, .Lchecksmst5
165	/* 4-byte structs are returned in ret0 as wwxxyyzz.  */
166	extru	%ret0, 7, 8, %r22
167	stbs,ma	%r22, 1(%r20)
168	extru	%ret0, 15, 8, %r22
169	stbs,ma	%r22, 1(%r20)
170	extru	%ret0, 23, 8, %r22
171	stbs,ma	%r22, 1(%r20)
172	b	.Ldone
173	stb	%ret0, 0(%r20)
174
175.Lchecksmst5:
176	comib,<>,n FFI_TYPE_SMALL_STRUCT5, %r21, .Lchecksmst6
177	/* 5 byte values are returned right justified:
178	      ret0     ret1
179	   5: ??????aa bbccddee */
180	stbs,ma	%ret0, 1(%r20)
181	extru	%ret1, 7, 8, %r22
182	stbs,ma	%r22, 1(%r20)
183	extru	%ret1, 15, 8, %r22
184	stbs,ma	%r22, 1(%r20)
185	extru	%ret1, 23, 8, %r22
186	stbs,ma	%r22, 1(%r20)
187	b	.Ldone
188	stb	%ret1, 0(%r20)
189
190.Lchecksmst6:
191	comib,<>,n FFI_TYPE_SMALL_STRUCT6, %r21, .Lchecksmst7
192	/* 6 byte values are returned right justified:
193	      ret0     ret1
194	   6: ????aabb ccddeeff */
195	extru	%ret0, 23, 8, %r22
196	stbs,ma	%r22, 1(%r20)
197	stbs,ma	%ret0, 1(%r20)
198	extru	%ret1, 7, 8, %r22
199	stbs,ma	%r22, 1(%r20)
200	extru	%ret1, 15, 8, %r22
201	stbs,ma	%r22, 1(%r20)
202	extru	%ret1, 23, 8, %r22
203	stbs,ma	%r22, 1(%r20)
204	b	.Ldone
205	stb	%ret1, 0(%r20)
206
207.Lchecksmst7:
208	comib,<>,n FFI_TYPE_SMALL_STRUCT7, %r21, .Lchecksmst8
209	/* 7 byte values are returned right justified:
210	      ret0     ret1
211	   7: ??aabbcc ddeeffgg */
212	extru	%ret0, 15, 8, %r22
213	stbs,ma	%r22, 1(%r20)
214	extru	%ret0, 23, 8, %r22
215	stbs,ma	%r22, 1(%r20)
216	stbs,ma	%ret0, 1(%r20)
217	extru	%ret1, 7, 8, %r22
218	stbs,ma	%r22, 1(%r20)
219	extru	%ret1, 15, 8, %r22
220	stbs,ma	%r22, 1(%r20)
221	extru	%ret1, 23, 8, %r22
222	stbs,ma	%r22, 1(%r20)
223	b	.Ldone
224	stb	%ret1, 0(%r20)
225
226.Lchecksmst8:
227	comib,<>,n FFI_TYPE_SMALL_STRUCT8, %r21, .Ldone
228	/* 8 byte values are returned right justified:
229	      ret0     ret1
230	   8: aabbccdd eeffgghh */
231	extru	%ret0, 7, 8, %r22
232	stbs,ma	%r22, 1(%r20)
233	extru	%ret0, 15, 8, %r22
234	stbs,ma	%r22, 1(%r20)
235	extru	%ret0, 23, 8, %r22
236	stbs,ma	%r22, 1(%r20)
237	stbs,ma	%ret0, 1(%r20)
238	extru	%ret1, 7, 8, %r22
239	stbs,ma	%r22, 1(%r20)
240	extru	%ret1, 15, 8, %r22
241	stbs,ma	%r22, 1(%r20)
242	extru	%ret1, 23, 8, %r22
243	stbs,ma	%r22, 1(%r20)
244	stb	%ret1, 0(%r20)
245
246.Ldone:
247	/* all done, return */
248	copy %r4, %sp                           /* pop arg stack */
249	ldw 12(%r3), %r4
250	ldwm -64(%sp), %r3                      /* .. and pop stack */
251	ldw -20(%sp), %rp
252	bv %r0(%rp)
253	nop
254	.exit
255	.procend
256	.cfi_endproc
257
258	/* void ffi_closure_pa32(void);
259	   Called with ffi_closure argument in %r21.  */
260	.export ffi_closure_pa32,code
261	.import ffi_closure_inner_pa32,code
262	.type ffi_closure_pa32, @function
263	.cfi_startproc
264ffi_closure_pa32:
265	.proc
266	.callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3
267	.entry
268
269	stw %rp, -20(%sp)
270	copy %r3, %r1
271	.cfi_offset 2, -20
272	.cfi_register 3, 1
273	copy %sp, %r3
274	.cfi_def_cfa_register 3
275	stwm %r1, 64(%sp)
276	.cfi_offset 3, 0
277
278	/* Put arguments onto the stack and call ffi_closure_inner.  */
279	stw %arg0, -36(%r3)
280	stw %arg1, -40(%r3)
281	stw %arg2, -44(%r3)
282	stw %arg3, -48(%r3)
283
284	/* Closure type 0.  */
285	copy %r21, %arg0
286	copy %r0, %arg2
287	bl ffi_closure_inner_pa32, %r2
288	copy %r3, %arg1
289
290	ldwm -64(%sp), %r3
291	ldw -20(%sp), %rp
292	ldw -36(%sp), %ret0
293	bv %r0(%r2)
294	ldw -40(%sp), %ret1
295
296	.exit
297	.procend
298	.cfi_endproc
299
300	/* void ffi_go_closure_pa32(void);
301	   Called with ffi_go_closure argument in %ret1.  */
302	.export ffi_go_closure_pa32,code
303	.import ffi_closure_inner_pa32,code
304	.type ffi_go_closure_pa32, @function
305	.cfi_startproc
306ffi_go_closure_pa32:
307	.proc
308	.callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3
309	.entry
310
311	stw %rp, -20(%sp)
312	copy %r3, %r1
313	.cfi_offset 2, -20
314	.cfi_register 3, 1
315	copy %sp, %r3
316	.cfi_def_cfa_register 3
317	stwm %r1, 64(%sp)
318	.cfi_offset 3, 0
319
320	/* Put arguments onto the stack and call ffi_closure_inner.  */
321	stw %arg0, -36(%r3)
322	stw %arg1, -40(%r3)
323	stw %arg2, -44(%r3)
324	stw %arg3, -48(%r3)
325
326	/* Closure type 1.  */
327	copy %ret1, %arg0
328	ldi 1, %arg2
329	bl ffi_closure_inner_pa32, %r2
330	copy %r3, %arg1
331
332	ldwm -64(%sp), %r3
333	ldw -20(%sp), %rp
334	ldw -36(%sp), %ret0
335	bv %r0(%r2)
336	ldw -40(%sp), %ret1
337
338	.exit
339	.procend
340	.cfi_endproc
341