1/* -----------------------------------------------------------------------
2   hpux32.S - Copyright (c) 2006 Free Software Foundation, Inc.
3	                (c) 2008 Red Hat, Inc.
4			(c) 2016 John David Anglin
5   based on src/pa/linux.S
6
7   HP-UX PA Foreign Function Interface
8
9   Permission is hereby granted, free of charge, to any person obtaining
10   a copy of this software and associated documentation files (the
11   ``Software''), to deal in the Software without restriction, including
12   without limitation the rights to use, copy, modify, merge, publish,
13   distribute, sublicense, and/or sell copies of the Software, and to
14   permit persons to whom the Software is furnished to do so, subject to
15   the following conditions:
16
17   The above copyright notice and this permission notice shall be included
18   in all copies or substantial portions of the Software.
19
20   THE SOFTWARE IS PROVIDED ``AS IS'', WITHOUT WARRANTY OF ANY KIND, EXPRESS
21   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22   MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23   IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR
24   OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25   ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26   OTHER DEALINGS IN THE SOFTWARE.
27   ----------------------------------------------------------------------- */
28
29#define LIBFFI_ASM
30#include <fficonfig.h>
31#include <ffi.h>
32
33	.LEVEL 1.1
34	.SPACE	$PRIVATE$
35	.IMPORT	$global$,DATA
36	.IMPORT	$$dyncall,MILLICODE
37	.SUBSPA	$DATA$
38	.align	4
39
40	/* void ffi_call_pa32(void (*)(char *, extended_cif *),
41			       extended_cif *ecif,
42			       unsigned bytes,
43			       unsigned flags,
44			       unsigned *rvalue,
45			       void (*fn)(void),
46			       ffi_go_closure *closure);
47	 */
48
49	.export	ffi_call_pa32,ENTRY,PRIV_LEV=3
50	.import	ffi_prep_args_pa32,CODE
51
52	.SPACE	$TEXT$
53	.SUBSPA $CODE$
54	.align	4
55
56L$FB1
57ffi_call_pa32
58	.proc
59	.callinfo	FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=4
60	.entry
61	stw	%rp, -20(%sp)
62	copy	%r3, %r1
63L$CFI11
64	copy	%sp, %r3
65L$CFI12
66
67	/* Setup the stack for calling prep_args...
68	   We want the stack to look like this:
69
70	   [ Previous stack                            ] <- %r3
71
72	   [ 64-bytes register save area               ] <- %r4
73
74	   [ Stack space for actual call, passed as    ] <- %arg0
75	   [     arg0 to ffi_prep_args_pa32           ]
76
77	   [ Stack for calling prep_args               ] <- %sp
78	 */
79
80	stwm	%r1, 64(%sp)
81	stw	%r4, 12(%r3)
82L$CFI13
83	copy	%sp, %r4
84
85	addl	%arg2, %r4, %arg0	; arg stack
86	stw	%arg3, -48(%r3)		; save flags we need it later
87
88	/* Call prep_args:
89	   %arg0(stack) -- set up above
90	   %arg1(ecif)  -- same as incoming param
91	   %arg2(bytes) -- same as incoming param */
92	bl	ffi_prep_args_pa32,%r2
93	ldo	64(%arg0), %sp
94	ldo	-64(%sp), %sp
95
96	/* now %sp should point where %arg0 was pointing.  */
97
98	/* Load the arguments that should be passed in registers
99	   The fp args are loaded by the prep_args function.  */
100	ldw	-36(%sp), %arg0
101	ldw	-40(%sp), %arg1
102	ldw	-44(%sp), %arg2
103	ldw	-48(%sp), %arg3
104
105	/* in case the function is going to return a structure
106	   we need to give it a place to put the result.  */
107	ldw	-52(%r3), %ret0		; %ret0 <- rvalue
108	ldw	-56(%r3), %r22		; %r22 <- function to call
109	ldw	-60(%r3), %ret1		; %ret1 <- closure
110	bl	$$dyncall, %r31		; Call the user function
111	copy	%r31, %rp
112
113	/* Prepare to store the result; we need to recover flags and rvalue.  */
114	ldw	-48(%r3), %r21		; r21 <- flags
115	ldw	-52(%r3), %r20		; r20 <- rvalue
116
117	/* Store the result according to the return type.  The most
118	   likely types should come first.  */
119
120L$checkint
121	comib,<>,n FFI_TYPE_INT, %r21, L$checkint8
122	b	L$done
123	stw	%ret0, 0(%r20)
124
125L$checkint8
126	comib,<>,n FFI_TYPE_UINT8, %r21, L$checkint16
127	b	L$done
128	stb	%ret0, 0(%r20)
129
130L$checkint16
131	comib,<>,n FFI_TYPE_UINT16, %r21, L$checkdbl
132	b	L$done
133	sth	%ret0, 0(%r20)
134
135L$checkdbl
136	comib,<>,n FFI_TYPE_DOUBLE, %r21, L$checkfloat
137	b	L$done
138	fstd	%fr4,0(%r20)
139
140L$checkfloat
141	comib,<>,n FFI_TYPE_FLOAT, %r21, L$checkll
142	b	L$done
143	fstw	%fr4L,0(%r20)
144
145L$checkll
146	comib,<>,n FFI_TYPE_UINT64, %r21, L$checksmst2
147	stw	%ret0, 0(%r20)
148	b	L$done
149	stw	%ret1, 4(%r20)
150
151L$checksmst2
152	comib,<>,n FFI_TYPE_SMALL_STRUCT2, %r21, L$checksmst3
153	/* 2-byte structs are returned in ret0 as ????xxyy.  */
154	extru	%ret0, 23, 8, %r22
155	stbs,ma	%r22, 1(%r20)
156	b	L$done
157	stb	%ret0, 0(%r20)
158
159L$checksmst3
160	comib,<>,n FFI_TYPE_SMALL_STRUCT3, %r21, L$checksmst4
161	/* 3-byte structs are returned in ret0 as ??xxyyzz.  */
162	extru	%ret0, 15, 8, %r22
163	stbs,ma	%r22, 1(%r20)
164	extru	%ret0, 23, 8, %r22
165	stbs,ma	%r22, 1(%r20)
166	b	L$done
167	stb	%ret0, 0(%r20)
168
169L$checksmst4
170	comib,<>,n FFI_TYPE_SMALL_STRUCT4, %r21, L$checksmst5
171	/* 4-byte structs are returned in ret0 as wwxxyyzz.  */
172	extru	%ret0, 7, 8, %r22
173	stbs,ma	%r22, 1(%r20)
174	extru	%ret0, 15, 8, %r22
175	stbs,ma	%r22, 1(%r20)
176	extru	%ret0, 23, 8, %r22
177	stbs,ma	%r22, 1(%r20)
178	b	L$done
179	stb	%ret0, 0(%r20)
180
181L$checksmst5
182	comib,<>,n FFI_TYPE_SMALL_STRUCT5, %r21, L$checksmst6
183	/* 5 byte values are returned right justified:
184	      ret0     ret1
185	   5: ??????aa bbccddee */
186	stbs,ma	%ret0, 1(%r20)
187	extru	%ret1, 7, 8, %r22
188	stbs,ma	%r22, 1(%r20)
189	extru	%ret1, 15, 8, %r22
190	stbs,ma	%r22, 1(%r20)
191	extru	%ret1, 23, 8, %r22
192	stbs,ma	%r22, 1(%r20)
193	b	L$done
194	stb	%ret1, 0(%r20)
195
196L$checksmst6
197	comib,<>,n FFI_TYPE_SMALL_STRUCT6, %r21, L$checksmst7
198	/* 6 byte values are returned right justified:
199	      ret0     ret1
200	   6: ????aabb ccddeeff */
201	extru	%ret0, 23, 8, %r22
202	stbs,ma	%r22, 1(%r20)
203	stbs,ma	%ret0, 1(%r20)
204	extru	%ret1, 7, 8, %r22
205	stbs,ma	%r22, 1(%r20)
206	extru	%ret1, 15, 8, %r22
207	stbs,ma	%r22, 1(%r20)
208	extru	%ret1, 23, 8, %r22
209	stbs,ma	%r22, 1(%r20)
210	b	L$done
211	stb	%ret1, 0(%r20)
212
213L$checksmst7
214	comib,<>,n FFI_TYPE_SMALL_STRUCT7, %r21, L$checksmst8
215	/* 7 byte values are returned right justified:
216	      ret0     ret1
217	   7: ??aabbcc ddeeffgg */
218	extru	%ret0, 15, 8, %r22
219	stbs,ma	%r22, 1(%r20)
220	extru	%ret0, 23, 8, %r22
221	stbs,ma	%r22, 1(%r20)
222	stbs,ma	%ret0, 1(%r20)
223	extru	%ret1, 7, 8, %r22
224	stbs,ma	%r22, 1(%r20)
225	extru	%ret1, 15, 8, %r22
226	stbs,ma	%r22, 1(%r20)
227	extru	%ret1, 23, 8, %r22
228	stbs,ma	%r22, 1(%r20)
229	b	L$done
230	stb	%ret1, 0(%r20)
231
232L$checksmst8
233	comib,<>,n FFI_TYPE_SMALL_STRUCT8, %r21, L$done
234	/* 8 byte values are returned right justified:
235	      ret0     ret1
236	   8: aabbccdd eeffgghh */
237	extru	%ret0, 7, 8, %r22
238	stbs,ma	%r22, 1(%r20)
239	extru	%ret0, 15, 8, %r22
240	stbs,ma	%r22, 1(%r20)
241	extru	%ret0, 23, 8, %r22
242	stbs,ma	%r22, 1(%r20)
243	stbs,ma	%ret0, 1(%r20)
244	extru	%ret1, 7, 8, %r22
245	stbs,ma	%r22, 1(%r20)
246	extru	%ret1, 15, 8, %r22
247	stbs,ma	%r22, 1(%r20)
248	extru	%ret1, 23, 8, %r22
249	stbs,ma	%r22, 1(%r20)
250	stb	%ret1, 0(%r20)
251
252L$done
253	/* all done, return */
254	copy	%r4, %sp	; pop arg stack
255	ldw	12(%r3), %r4
256	ldwm	-64(%sp), %r3	; .. and pop stack
257	ldw	-20(%sp), %rp
258	bv	%r0(%rp)
259	nop
260	.exit
261	.procend
262L$FE1
263
264	/* void ffi_closure_pa32(void);
265	   Called with closure argument in %r21 */
266
267	.SPACE $TEXT$
268	.SUBSPA $CODE$
269	.export ffi_closure_pa32,ENTRY,PRIV_LEV=3,RTNVAL=GR
270	.import ffi_closure_inner_pa32,CODE
271	.align 4
272L$FB2
273ffi_closure_pa32
274	.proc
275	.callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3
276	.entry
277
278	stw	%rp, -20(%sp)
279	copy	%r3, %r1
280L$CFI21
281	copy	%sp, %r3
282L$CFI22
283	stwm	%r1, 64(%sp)
284
285	/* Put arguments onto the stack and call ffi_closure_inner.  */
286	stw	%arg0, -36(%r3)
287	stw	%arg1, -40(%r3)
288	stw	%arg2, -44(%r3)
289	stw	%arg3, -48(%r3)
290
291	/* Closure type 0.  */
292	copy	%r21, %arg0
293	copy	%r0, %arg2
294	bl	ffi_closure_inner_pa32, %r2
295	copy    %r3, %arg1
296	ldwm	-64(%sp), %r3
297	ldw	-20(%sp), %rp
298	ldw	-36(%sp), %ret0
299	bv	%r0(%rp)
300	ldw	-40(%sp), %ret1
301	.exit
302	.procend
303L$FE2:
304
305	/* void ffi_go_closure_pa32(void);
306	   Called with closure argument in %ret1 */
307
308	.SPACE $TEXT$
309	.SUBSPA $CODE$
310	.export ffi_go_closure_pa32,ENTRY,PRIV_LEV=3,RTNVAL=GR
311	.import ffi_closure_inner_pa32,CODE
312	.align 4
313L$FB3
314ffi_go_closure_pa32
315	.proc
316	.callinfo FRAME=64,CALLS,SAVE_RP,SAVE_SP,ENTRY_GR=3
317	.entry
318
319	stw	%rp, -20(%sp)
320	copy	%r3, %r1
321L$CFI31
322	copy	%sp, %r3
323L$CFI32
324	stwm	%r1, 64(%sp)
325
326	/* Put arguments onto the stack and call ffi_closure_inner.  */
327	stw	%arg0, -36(%r3)
328	stw	%arg1, -40(%r3)
329	stw	%arg2, -44(%r3)
330	stw	%arg3, -48(%r3)
331
332	/* Closure type 1.  */
333	copy	%ret1, %arg0
334	ldi	1, %arg2
335	bl	ffi_closure_inner_pa32, %r2
336	copy    %r3, %arg1
337	ldwm	-64(%sp), %r3
338	ldw	-20(%sp), %rp
339	ldw	-36(%sp), %ret0
340	bv	%r0(%rp)
341	ldw	-40(%sp), %ret1
342	.exit
343	.procend
344L$FE3:
345
346	.SPACE $PRIVATE$
347	.SUBSPA $DATA$
348
349	.align 4
350	.EXPORT _GLOBAL__F_ffi_call_pa32,DATA
351_GLOBAL__F_ffi_call_pa32
352L$frame1:
353	.word   L$ECIE1-L$SCIE1 ;# Length of Common Information Entry
354L$SCIE1:
355	.word   0x0     ;# CIE Identifier Tag
356	.byte   0x1     ;# CIE Version
357	.ascii "\0"     ;# CIE Augmentation
358	.uleb128 0x1    ;# CIE Code Alignment Factor
359	.sleb128 4      ;# CIE Data Alignment Factor
360	.byte   0x2     ;# CIE RA Column
361	.byte   0xc     ;# DW_CFA_def_cfa
362	.uleb128 0x1e
363	.uleb128 0x0
364	.align 4
365L$ECIE1:
366L$SFDE1:
367	.word   L$EFDE1-L$ASFDE1        ;# FDE Length
368L$ASFDE1:
369	.word   L$ASFDE1-L$frame1       ;# FDE CIE offset
370	.word   L$FB1   ;# FDE initial location
371	.word   L$FE1-L$FB1     ;# FDE address range
372
373	.byte   0x4     ;# DW_CFA_advance_loc4
374	.word   L$CFI11-L$FB1
375	.byte	0x83	;# DW_CFA_offset, column 0x3
376	.uleb128 0x0
377	.byte   0x11    ;# DW_CFA_offset_extended_sf; save r2 at [r30-20]
378	.uleb128 0x2
379	.sleb128 -5
380
381	.byte   0x4     ;# DW_CFA_advance_loc4
382	.word   L$CFI12-L$CFI11
383	.byte   0xd     ;# DW_CFA_def_cfa_register = r3
384	.uleb128 0x3
385
386	.byte   0x4     ;# DW_CFA_advance_loc4
387	.word   L$CFI13-L$CFI12
388	.byte	0x84	;# DW_CFA_offset, column 0x4
389	.uleb128 0x3
390
391	.align 4
392L$EFDE1:
393
394L$SFDE2:
395	.word   L$EFDE2-L$ASFDE2        ;# FDE Length
396L$ASFDE2:
397	.word   L$ASFDE2-L$frame1       ;# FDE CIE offset
398	.word   L$FB2   ;# FDE initial location
399	.word   L$FE2-L$FB2     ;# FDE address range
400	.byte   0x4     ;# DW_CFA_advance_loc4
401	.word   L$CFI21-L$FB2
402	.byte   0x83    ;# DW_CFA_offset, column 0x3
403	.uleb128 0x0
404	.byte   0x11    ;# DW_CFA_offset_extended_sf
405	.uleb128 0x2
406	.sleb128 -5
407
408	.byte   0x4     ;# DW_CFA_advance_loc4
409	.word   L$CFI22-L$CFI21
410	.byte   0xd     ;# DW_CFA_def_cfa_register = r3
411	.uleb128 0x3
412
413	.align 4
414L$EFDE2:
415
416L$SFDE3:
417	.word   L$EFDE3-L$ASFDE3        ;# FDE Length
418L$ASFDE3:
419	.word   L$ASFDE3-L$frame1       ;# FDE CIE offset
420	.word   L$FB3   ;# FDE initial location
421	.word   L$FE3-L$FB3     ;# FDE address range
422	.byte   0x4     ;# DW_CFA_advance_loc4
423	.word   L$CFI31-L$FB3
424	.byte   0x83    ;# DW_CFA_offset, column 0x3
425	.uleb128 0x0
426	.byte   0x11    ;# DW_CFA_offset_extended_sf
427	.uleb128 0x2
428	.sleb128 -5
429
430	.byte   0x4     ;# DW_CFA_advance_loc4
431	.word   L$CFI32-L$CFI31
432	.byte   0xd     ;# DW_CFA_def_cfa_register = r3
433	.uleb128 0x3
434
435	.align 4
436L$EFDE3:
437