1/* setjmp for PowerPC64.
2   Copyright (C) 1995-2021 Free Software Foundation, Inc.
3   This file is part of the GNU C Library.
4
5   The GNU C Library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9
10   The GNU C Library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14
15   You should have received a copy of the GNU Lesser General Public
16   License along with the GNU C Library; if not, see
17   <https://www.gnu.org/licenses/>.  */
18
19#include <sysdep.h>
20#include <stap-probe.h>
21#define _ASM
22#ifdef __NO_VMX__
23#include <novmxsetjmp.h>
24#else
25#include <jmpbuf-offsets.h>
26#endif
27
28#ifndef __NO_VMX__
29	.section	".toc","aw"
30.LC__dl_hwcap:
31# ifdef SHARED
32#  if IS_IN (rtld)
33	/* Inside ld.so we use the local alias to avoid runtime GOT
34	   relocations.  */
35	.tc _rtld_local_ro[TC],_rtld_local_ro
36#  else
37	.tc _rtld_global_ro[TC],_rtld_global_ro
38#  endif
39# else
40	.tc _dl_hwcap[TC],_dl_hwcap
41# endif
42	.section ".text"
43#endif
44
45	.machine	"altivec"
46ENTRY (setjmp_symbol)
47	CALL_MCOUNT 1
48	li r4,1			/* Set second argument to 1.  */
49	b JUMPTARGET (GLUE(__sigsetjmp_symbol,_ent))
50END (setjmp_symbol)
51
52#if defined SHARED && !IS_IN (rtld) && !defined __NO_VMX__
53/* When called from within libc we need a special version of _setjmp
54   that saves r2 since the call won't go via a plt call stub.  See
55   bugz #269.  __GI__setjmp is used in csu/libc-start.c when
56   HAVE_CLEANUP_JMP_BUF is defined.  */
57ENTRY (__GI__setjmp)
58	std r2,FRAME_TOC_SAVE(r1)		/* Save the callers TOC in the save area.  */
59	CALL_MCOUNT 1
60	li r4,0			/* Set second argument to 0.  */
61	b JUMPTARGET (GLUE(__sigsetjmp_symbol,_ent))
62END (__GI__setjmp)
63#endif
64
65ENTRY (_setjmp_symbol)
66	CALL_MCOUNT 1
67	li r4,0			/* Set second argument to 0.  */
68	b JUMPTARGET (GLUE(__sigsetjmp_symbol,_ent))
69END (_setjmp_symbol)
70libc_hidden_def (_setjmp_symbol)
71
72ENTRY (__sigsetjmp_symbol)
73	CALL_MCOUNT 2
74JUMPTARGET(GLUE(__sigsetjmp_symbol,_ent)):
75#ifdef PTR_MANGLE
76	mr   r5, r1
77	PTR_MANGLE (r5, r6)
78	std  r5,(JB_GPR1*8)(3)
79#else
80	std  r1,(JB_GPR1*8)(3)
81#endif
82	mflr r0
83#if defined SHARED && !IS_IN (rtld)
84	ld   r5,FRAME_TOC_SAVE(r1)	/* Retrieve the callers TOC.  */
85	std  r5,(JB_GPR2*8)(3)
86#else
87	std  r2,(JB_GPR2*8)(3)
88#endif
89	/* setjmp probe expects longjmp first argument (8@3), second argument
90	   (-4@4), and target address (8@0), respectively.  */
91	LIBC_PROBE (setjmp, 3, 8@3, -4@4, 8@0)
92	std  r14,((JB_GPRS+0)*8)(3)
93	stfd fp14,((JB_FPRS+0)*8)(3)
94#ifdef PTR_MANGLE
95	PTR_MANGLE2 (r0, r6)
96#endif
97	std  r0,(JB_LR*8)(3)
98	std  r15,((JB_GPRS+1)*8)(3)
99	stfd fp15,((JB_FPRS+1)*8)(3)
100	mfcr r0
101	std  r16,((JB_GPRS+2)*8)(3)
102	stfd fp16,((JB_FPRS+2)*8)(3)
103	stw  r0,((JB_CR*8)+4)(3)	/* 32-bit CR.  */
104	std  r17,((JB_GPRS+3)*8)(3)
105	stfd fp17,((JB_FPRS+3)*8)(3)
106	std  r18,((JB_GPRS+4)*8)(3)
107	stfd fp18,((JB_FPRS+4)*8)(3)
108	std  r19,((JB_GPRS+5)*8)(3)
109	stfd fp19,((JB_FPRS+5)*8)(3)
110	std  r20,((JB_GPRS+6)*8)(3)
111	stfd fp20,((JB_FPRS+6)*8)(3)
112	std  r21,((JB_GPRS+7)*8)(3)
113	stfd fp21,((JB_FPRS+7)*8)(3)
114	std  r22,((JB_GPRS+8)*8)(3)
115	stfd fp22,((JB_FPRS+8)*8)(3)
116	std  r23,((JB_GPRS+9)*8)(3)
117	stfd fp23,((JB_FPRS+9)*8)(3)
118	std  r24,((JB_GPRS+10)*8)(3)
119	stfd fp24,((JB_FPRS+10)*8)(3)
120	std  r25,((JB_GPRS+11)*8)(3)
121	stfd fp25,((JB_FPRS+11)*8)(3)
122	std  r26,((JB_GPRS+12)*8)(3)
123	stfd fp26,((JB_FPRS+12)*8)(3)
124	std  r27,((JB_GPRS+13)*8)(3)
125	stfd fp27,((JB_FPRS+13)*8)(3)
126	std  r28,((JB_GPRS+14)*8)(3)
127	stfd fp28,((JB_FPRS+14)*8)(3)
128	std  r29,((JB_GPRS+15)*8)(3)
129	stfd fp29,((JB_FPRS+15)*8)(3)
130	std  r30,((JB_GPRS+16)*8)(3)
131	stfd fp30,((JB_FPRS+16)*8)(3)
132	std  r31,((JB_GPRS+17)*8)(3)
133	stfd fp31,((JB_FPRS+17)*8)(3)
134#ifndef __NO_VMX__
135	ld    r6,.LC__dl_hwcap@toc(r2)
136# ifdef SHARED
137	/* Load _rtld-global._dl_hwcap.  */
138	ld    r6,RTLD_GLOBAL_RO_DL_HWCAP_OFFSET(r6)
139# else
140	ld    r6,0(r6) /* Load extern _dl_hwcap.  */
141# endif
142	andis.  r6,r6,(PPC_FEATURE_HAS_ALTIVEC >> 16)
143	beq	L(no_vmx)
144	la	r5,((JB_VRS)*8)(3)
145	andi.	r6,r5,0xf
146	mfspr	r0,VRSAVE
147	stw	r0,((JB_VRSAVE)*8)(3)	/* 32-bit VRSAVE.  */
148	addi	r6,r5,16
149	beq+	L(aligned_save_vmx)
150
151	lvsr	v0,0,r5
152	lvsl	v1,0,r5
153	addi	r6,r5,-16
154
155# define save_misaligned_vmx(savevr,prevvr,shiftvr,tmpvr,savegpr,addgpr) \
156	addi	addgpr,addgpr,32;					 \
157	vperm	tmpvr,prevvr,savevr,shiftvr;				 \
158	stvx	tmpvr,0,savegpr
159
160	/*
161	 * We have to be careful not to corrupt the data below v20 and
162	 * above v31. To keep things simple we just rotate both ends in
163	 * the opposite direction to our main permute so we can use
164	 * the common macro.
165	 */
166
167	/* load and rotate data below v20 */
168	lvx	v2,0,r5
169	vperm	v2,v2,v2,v1
170	save_misaligned_vmx(v20,v2,v0,v3,r5,r6)
171	save_misaligned_vmx(v21,v20,v0,v3,r6,r5)
172	save_misaligned_vmx(v22,v21,v0,v3,r5,r6)
173	save_misaligned_vmx(v23,v22,v0,v3,r6,r5)
174	save_misaligned_vmx(v24,v23,v0,v3,r5,r6)
175	save_misaligned_vmx(v25,v24,v0,v3,r6,r5)
176	save_misaligned_vmx(v26,v25,v0,v3,r5,r6)
177	save_misaligned_vmx(v27,v26,v0,v3,r6,r5)
178	save_misaligned_vmx(v28,v27,v0,v3,r5,r6)
179	save_misaligned_vmx(v29,v28,v0,v3,r6,r5)
180	save_misaligned_vmx(v30,v29,v0,v3,r5,r6)
181	save_misaligned_vmx(v31,v30,v0,v3,r6,r5)
182	/* load and rotate data above v31 */
183	lvx	v2,0,r6
184	vperm	v2,v2,v2,v1
185	save_misaligned_vmx(v2,v31,v0,v3,r5,r6)
186
187	b	L(no_vmx)
188
189L(aligned_save_vmx):
190	stvx	20,0,r5
191	addi	r5,r5,32
192	stvx	21,0,r6
193	addi	r6,r6,32
194	stvx	22,0,r5
195	addi	r5,r5,32
196	stvx	23,0,r6
197	addi	r6,r6,32
198	stvx	24,0,r5
199	addi	r5,r5,32
200	stvx	25,0,r6
201	addi	r6,r6,32
202	stvx	26,0,r5
203	addi	r5,r5,32
204	stvx	27,0,r6
205	addi	r6,r6,32
206	stvx	28,0,r5
207	addi	r5,r5,32
208	stvx	29,0,r6
209	addi	r6,r6,32
210	stvx	30,0,r5
211	stvx	31,0,r6
212L(no_vmx):
213#else
214	li	r6,0
215#endif
216#if IS_IN (rtld)
217	li	r3,0
218	blr
219#elif defined SHARED
220	b	JUMPTARGET (NOTOC (__sigjmp_save_symbol))
221#else
222	mflr	r0
223	std	r0,FRAME_LR_SAVE(r1)
224	stdu	r1,-FRAME_MIN_SIZE(r1)
225	cfi_adjust_cfa_offset(FRAME_MIN_SIZE)
226	cfi_offset(lr,FRAME_LR_SAVE)
227	bl	JUMPTARGET (__sigjmp_save_symbol)
228	nop
229	ld	r0,FRAME_MIN_SIZE+FRAME_LR_SAVE(r1)
230	addi	r1,r1,FRAME_MIN_SIZE
231	mtlr	r0
232	blr
233#endif
234END (__sigsetjmp_symbol)
235
236#if defined SHARED && !IS_IN (rtld) && !defined __NO_VMX__
237/* When called from within libc we need a special version of __sigsetjmp
238   that saves r2 since the call won't go via a plt call stub.  See
239   bugz #269.  */
240ENTRY (__GI___sigsetjmp)
241	std r2,FRAME_TOC_SAVE(r1) /* Save the callers TOC in the save area.  */
242	CALL_MCOUNT 1
243	b JUMPTARGET (GLUE(__sigsetjmp_symbol,_ent))
244END (__GI___sigsetjmp)
245#endif
246