xref: /linux/tools/testing/selftests/arm64/gcs/gcs-stress-thread.S (revision c34e9ab9a612ee8b18273398ef75c207b01f516d)
1*05e6cfffSMark Brown// Program that loops for ever doing lots of recursions and system calls,
2*05e6cfffSMark Brown// intended to be used as part of a stress test for GCS context switching.
3*05e6cfffSMark Brown//
4*05e6cfffSMark Brown// Copyright 2015-2023 Arm Ltd
5*05e6cfffSMark Brown
6*05e6cfffSMark Brown#include <asm/unistd.h>
7*05e6cfffSMark Brown
8*05e6cfffSMark Brown#define sa_sz 32
9*05e6cfffSMark Brown#define sa_flags 8
10*05e6cfffSMark Brown#define sa_handler 0
11*05e6cfffSMark Brown#define sa_mask_sz 8
12*05e6cfffSMark Brown
13*05e6cfffSMark Brown#define si_code 8
14*05e6cfffSMark Brown
15*05e6cfffSMark Brown#define SIGINT 2
16*05e6cfffSMark Brown#define SIGABRT 6
17*05e6cfffSMark Brown#define SIGUSR1 10
18*05e6cfffSMark Brown#define SIGSEGV 11
19*05e6cfffSMark Brown#define SIGUSR2 12
20*05e6cfffSMark Brown#define SIGTERM 15
21*05e6cfffSMark Brown#define SEGV_CPERR 10
22*05e6cfffSMark Brown
23*05e6cfffSMark Brown#define SA_NODEFER 1073741824
24*05e6cfffSMark Brown#define SA_SIGINFO 4
25*05e6cfffSMark Brown#define ucontext_regs 184
26*05e6cfffSMark Brown
27*05e6cfffSMark Brown#define PR_SET_SHADOW_STACK_STATUS      75
28*05e6cfffSMark Brown# define PR_SHADOW_STACK_ENABLE         (1UL << 0)
29*05e6cfffSMark Brown
30*05e6cfffSMark Brown#define	GCSPR_EL0 S3_3_C2_C5_1
31*05e6cfffSMark Brown
32*05e6cfffSMark Brown.macro function name
33*05e6cfffSMark Brown	.macro endfunction
34*05e6cfffSMark Brown		.type \name, @function
35*05e6cfffSMark Brown		.purgem endfunction
36*05e6cfffSMark Brown	.endm
37*05e6cfffSMark Brown\name:
38*05e6cfffSMark Brown.endm
39*05e6cfffSMark Brown
40*05e6cfffSMark Brown// Print a single character x0 to stdout
41*05e6cfffSMark Brown// Clobbers x0-x2,x8
42*05e6cfffSMark Brownfunction putc
43*05e6cfffSMark Brown	str	x0, [sp, #-16]!
44*05e6cfffSMark Brown
45*05e6cfffSMark Brown	mov	x0, #1			// STDOUT_FILENO
46*05e6cfffSMark Brown	mov	x1, sp
47*05e6cfffSMark Brown	mov	x2, #1
48*05e6cfffSMark Brown	mov	x8, #__NR_write
49*05e6cfffSMark Brown	svc	#0
50*05e6cfffSMark Brown
51*05e6cfffSMark Brown	add	sp, sp, #16
52*05e6cfffSMark Brown	ret
53*05e6cfffSMark Brownendfunction
54*05e6cfffSMark Brown.globl	putc
55*05e6cfffSMark Brown
56*05e6cfffSMark Brown// Print a NUL-terminated string starting at address x0 to stdout
57*05e6cfffSMark Brown// Clobbers x0-x3,x8
58*05e6cfffSMark Brownfunction puts
59*05e6cfffSMark Brown	mov	x1, x0
60*05e6cfffSMark Brown
61*05e6cfffSMark Brown	mov	x2, #0
62*05e6cfffSMark Brown0:	ldrb	w3, [x0], #1
63*05e6cfffSMark Brown	cbz	w3, 1f
64*05e6cfffSMark Brown	add	x2, x2, #1
65*05e6cfffSMark Brown	b	0b
66*05e6cfffSMark Brown
67*05e6cfffSMark Brown1:	mov	w0, #1			// STDOUT_FILENO
68*05e6cfffSMark Brown	mov	x8, #__NR_write
69*05e6cfffSMark Brown	svc	#0
70*05e6cfffSMark Brown
71*05e6cfffSMark Brown	ret
72*05e6cfffSMark Brownendfunction
73*05e6cfffSMark Brown.globl	puts
74*05e6cfffSMark Brown
75*05e6cfffSMark Brown// Utility macro to print a literal string
76*05e6cfffSMark Brown// Clobbers x0-x4,x8
77*05e6cfffSMark Brown.macro puts string
78*05e6cfffSMark Brown	.pushsection .rodata.str1.1, "aMS", @progbits, 1
79*05e6cfffSMark Brown.L__puts_literal\@: .string "\string"
80*05e6cfffSMark Brown	.popsection
81*05e6cfffSMark Brown
82*05e6cfffSMark Brown	ldr	x0, =.L__puts_literal\@
83*05e6cfffSMark Brown	bl	puts
84*05e6cfffSMark Brown.endm
85*05e6cfffSMark Brown
86*05e6cfffSMark Brown// Print an unsigned decimal number x0 to stdout
87*05e6cfffSMark Brown// Clobbers x0-x4,x8
88*05e6cfffSMark Brownfunction putdec
89*05e6cfffSMark Brown	mov	x1, sp
90*05e6cfffSMark Brown	str	x30, [sp, #-32]!	// Result can't be > 20 digits
91*05e6cfffSMark Brown
92*05e6cfffSMark Brown	mov	x2, #0
93*05e6cfffSMark Brown	strb	w2, [x1, #-1]!		// Write the NUL terminator
94*05e6cfffSMark Brown
95*05e6cfffSMark Brown	mov	x2, #10
96*05e6cfffSMark Brown0:	udiv	x3, x0, x2		// div-mod loop to generate the digits
97*05e6cfffSMark Brown	msub	x0, x3, x2, x0
98*05e6cfffSMark Brown	add	w0, w0, #'0'
99*05e6cfffSMark Brown	strb	w0, [x1, #-1]!
100*05e6cfffSMark Brown	mov	x0, x3
101*05e6cfffSMark Brown	cbnz	x3, 0b
102*05e6cfffSMark Brown
103*05e6cfffSMark Brown	ldrb	w0, [x1]
104*05e6cfffSMark Brown	cbnz	w0, 1f
105*05e6cfffSMark Brown	mov	w0, #'0'		// Print "0" for 0, not ""
106*05e6cfffSMark Brown	strb	w0, [x1, #-1]!
107*05e6cfffSMark Brown
108*05e6cfffSMark Brown1:	mov	x0, x1
109*05e6cfffSMark Brown	bl	puts
110*05e6cfffSMark Brown
111*05e6cfffSMark Brown	ldr	x30, [sp], #32
112*05e6cfffSMark Brown	ret
113*05e6cfffSMark Brownendfunction
114*05e6cfffSMark Brown.globl	putdec
115*05e6cfffSMark Brown
116*05e6cfffSMark Brown// Print an unsigned decimal number x0 to stdout, followed by a newline
117*05e6cfffSMark Brown// Clobbers x0-x5,x8
118*05e6cfffSMark Brownfunction putdecn
119*05e6cfffSMark Brown	mov	x5, x30
120*05e6cfffSMark Brown
121*05e6cfffSMark Brown	bl	putdec
122*05e6cfffSMark Brown	mov	x0, #'\n'
123*05e6cfffSMark Brown	bl	putc
124*05e6cfffSMark Brown
125*05e6cfffSMark Brown	ret	x5
126*05e6cfffSMark Brownendfunction
127*05e6cfffSMark Brown.globl	putdecn
128*05e6cfffSMark Brown
129*05e6cfffSMark Brown// Fill x1 bytes starting at x0 with 0.
130*05e6cfffSMark Brown// Clobbers x1, x2.
131*05e6cfffSMark Brownfunction memclr
132*05e6cfffSMark Brown	mov	w2, #0
133*05e6cfffSMark Brownendfunction
134*05e6cfffSMark Brown.globl	memclr
135*05e6cfffSMark Brown	// fall through to memfill
136*05e6cfffSMark Brown
137*05e6cfffSMark Brown// Trivial memory fill: fill x1 bytes starting at address x0 with byte w2
138*05e6cfffSMark Brown// Clobbers x1
139*05e6cfffSMark Brownfunction memfill
140*05e6cfffSMark Brown	cmp	x1, #0
141*05e6cfffSMark Brown	b.eq	1f
142*05e6cfffSMark Brown
143*05e6cfffSMark Brown0:	strb	w2, [x0], #1
144*05e6cfffSMark Brown	subs	x1, x1, #1
145*05e6cfffSMark Brown	b.ne	0b
146*05e6cfffSMark Brown
147*05e6cfffSMark Brown1:	ret
148*05e6cfffSMark Brownendfunction
149*05e6cfffSMark Brown.globl	memfill
150*05e6cfffSMark Brown
151*05e6cfffSMark Brown// w0: signal number
152*05e6cfffSMark Brown// x1: sa_action
153*05e6cfffSMark Brown// w2: sa_flags
154*05e6cfffSMark Brown// Clobbers x0-x6,x8
155*05e6cfffSMark Brownfunction setsignal
156*05e6cfffSMark Brown	str	x30, [sp, #-((sa_sz + 15) / 16 * 16 + 16)]!
157*05e6cfffSMark Brown
158*05e6cfffSMark Brown	mov	w4, w0
159*05e6cfffSMark Brown	mov	x5, x1
160*05e6cfffSMark Brown	mov	w6, w2
161*05e6cfffSMark Brown
162*05e6cfffSMark Brown	add	x0, sp, #16
163*05e6cfffSMark Brown	mov	x1, #sa_sz
164*05e6cfffSMark Brown	bl	memclr
165*05e6cfffSMark Brown
166*05e6cfffSMark Brown	mov	w0, w4
167*05e6cfffSMark Brown	add	x1, sp, #16
168*05e6cfffSMark Brown	str	w6, [x1, #sa_flags]
169*05e6cfffSMark Brown	str	x5, [x1, #sa_handler]
170*05e6cfffSMark Brown	mov	x2, #0
171*05e6cfffSMark Brown	mov	x3, #sa_mask_sz
172*05e6cfffSMark Brown	mov	x8, #__NR_rt_sigaction
173*05e6cfffSMark Brown	svc	#0
174*05e6cfffSMark Brown
175*05e6cfffSMark Brown	cbz	w0, 1f
176*05e6cfffSMark Brown
177*05e6cfffSMark Brown	puts	"sigaction failure\n"
178*05e6cfffSMark Brown	b	abort
179*05e6cfffSMark Brown
180*05e6cfffSMark Brown1:	ldr	x30, [sp], #((sa_sz + 15) / 16 * 16 + 16)
181*05e6cfffSMark Brown	ret
182*05e6cfffSMark Brownendfunction
183*05e6cfffSMark Brown
184*05e6cfffSMark Brown
185*05e6cfffSMark Brownfunction tickle_handler
186*05e6cfffSMark Brown	// Perhaps collect GCSPR_EL0 here in future?
187*05e6cfffSMark Brown	ret
188*05e6cfffSMark Brownendfunction
189*05e6cfffSMark Brown
190*05e6cfffSMark Brownfunction terminate_handler
191*05e6cfffSMark Brown	mov	w21, w0
192*05e6cfffSMark Brown	mov	x20, x2
193*05e6cfffSMark Brown
194*05e6cfffSMark Brown	puts	"Terminated by signal "
195*05e6cfffSMark Brown	mov	w0, w21
196*05e6cfffSMark Brown	bl	putdec
197*05e6cfffSMark Brown	puts	", no error\n"
198*05e6cfffSMark Brown
199*05e6cfffSMark Brown	mov	x0, #0
200*05e6cfffSMark Brown	mov	x8, #__NR_exit
201*05e6cfffSMark Brown	svc	#0
202*05e6cfffSMark Brownendfunction
203*05e6cfffSMark Brown
204*05e6cfffSMark Brownfunction segv_handler
205*05e6cfffSMark Brown	// stash the siginfo_t *
206*05e6cfffSMark Brown	mov	x20, x1
207*05e6cfffSMark Brown
208*05e6cfffSMark Brown	// Disable GCS, we don't want additional faults logging things
209*05e6cfffSMark Brown	mov	x0, PR_SET_SHADOW_STACK_STATUS
210*05e6cfffSMark Brown	mov	x1, xzr
211*05e6cfffSMark Brown	mov	x2, xzr
212*05e6cfffSMark Brown	mov	x3, xzr
213*05e6cfffSMark Brown	mov	x4, xzr
214*05e6cfffSMark Brown	mov	x5, xzr
215*05e6cfffSMark Brown	mov	x8, #__NR_prctl
216*05e6cfffSMark Brown	svc	#0
217*05e6cfffSMark Brown
218*05e6cfffSMark Brown	puts	"Got SIGSEGV code "
219*05e6cfffSMark Brown
220*05e6cfffSMark Brown	ldr	x21, [x20, #si_code]
221*05e6cfffSMark Brown	mov	x0, x21
222*05e6cfffSMark Brown	bl	putdec
223*05e6cfffSMark Brown
224*05e6cfffSMark Brown	// GCS faults should have si_code SEGV_CPERR
225*05e6cfffSMark Brown	cmp	x21, #SEGV_CPERR
226*05e6cfffSMark Brown	bne	1f
227*05e6cfffSMark Brown
228*05e6cfffSMark Brown	puts	" (GCS violation)"
229*05e6cfffSMark Brown1:
230*05e6cfffSMark Brown	mov	x0, '\n'
231*05e6cfffSMark Brown	bl	putc
232*05e6cfffSMark Brown	b	abort
233*05e6cfffSMark Brownendfunction
234*05e6cfffSMark Brown
235*05e6cfffSMark Brown// Recurse x20 times
236*05e6cfffSMark Brown.macro recurse id
237*05e6cfffSMark Brownfunction recurse\id
238*05e6cfffSMark Brown	stp	x29, x30, [sp, #-16]!
239*05e6cfffSMark Brown	mov	x29, sp
240*05e6cfffSMark Brown
241*05e6cfffSMark Brown	cmp	x20, 0
242*05e6cfffSMark Brown	beq	1f
243*05e6cfffSMark Brown	sub	x20, x20, 1
244*05e6cfffSMark Brown	bl	recurse\id
245*05e6cfffSMark Brown
246*05e6cfffSMark Brown1:
247*05e6cfffSMark Brown	ldp	x29, x30, [sp], #16
248*05e6cfffSMark Brown
249*05e6cfffSMark Brown	// Do a syscall immediately prior to returning to try to provoke
250*05e6cfffSMark Brown	// scheduling and migration at a point where coherency issues
251*05e6cfffSMark Brown	// might trigger.
252*05e6cfffSMark Brown	mov	x8, #__NR_getpid
253*05e6cfffSMark Brown	svc	#0
254*05e6cfffSMark Brown
255*05e6cfffSMark Brown	ret
256*05e6cfffSMark Brownendfunction
257*05e6cfffSMark Brown.endm
258*05e6cfffSMark Brown
259*05e6cfffSMark Brown// Generate and use two copies so we're changing the GCS contents
260*05e6cfffSMark Brownrecurse 1
261*05e6cfffSMark Brownrecurse 2
262*05e6cfffSMark Brown
263*05e6cfffSMark Brown.globl _start
264*05e6cfffSMark Brownfunction _start
265*05e6cfffSMark Brown	// Run with GCS
266*05e6cfffSMark Brown	mov	x0, PR_SET_SHADOW_STACK_STATUS
267*05e6cfffSMark Brown	mov	x1, PR_SHADOW_STACK_ENABLE
268*05e6cfffSMark Brown	mov	x2, xzr
269*05e6cfffSMark Brown	mov	x3, xzr
270*05e6cfffSMark Brown	mov	x4, xzr
271*05e6cfffSMark Brown	mov	x5, xzr
272*05e6cfffSMark Brown	mov	x8, #__NR_prctl
273*05e6cfffSMark Brown	svc	#0
274*05e6cfffSMark Brown	cbz	x0, 1f
275*05e6cfffSMark Brown	puts	"Failed to enable GCS\n"
276*05e6cfffSMark Brown	b	abort
277*05e6cfffSMark Brown1:
278*05e6cfffSMark Brown
279*05e6cfffSMark Brown	mov	w0, #SIGTERM
280*05e6cfffSMark Brown	adr	x1, terminate_handler
281*05e6cfffSMark Brown	mov	w2, #SA_SIGINFO
282*05e6cfffSMark Brown	bl	setsignal
283*05e6cfffSMark Brown
284*05e6cfffSMark Brown	mov	w0, #SIGUSR1
285*05e6cfffSMark Brown	adr	x1, tickle_handler
286*05e6cfffSMark Brown	mov	w2, #SA_SIGINFO
287*05e6cfffSMark Brown	orr	w2, w2, #SA_NODEFER
288*05e6cfffSMark Brown	bl	setsignal
289*05e6cfffSMark Brown
290*05e6cfffSMark Brown	mov	w0, #SIGSEGV
291*05e6cfffSMark Brown	adr	x1, segv_handler
292*05e6cfffSMark Brown	mov	w2, #SA_SIGINFO
293*05e6cfffSMark Brown	orr	w2, w2, #SA_NODEFER
294*05e6cfffSMark Brown	bl	setsignal
295*05e6cfffSMark Brown
296*05e6cfffSMark Brown	puts	"Running\n"
297*05e6cfffSMark Brown
298*05e6cfffSMark Brownloop:
299*05e6cfffSMark Brown	// Small recursion depth so we're frequently flipping between
300*05e6cfffSMark Brown	// the two recursors and changing what's on the stack
301*05e6cfffSMark Brown	mov	x20, #5
302*05e6cfffSMark Brown	bl	recurse1
303*05e6cfffSMark Brown	mov	x20, #5
304*05e6cfffSMark Brown	bl	recurse2
305*05e6cfffSMark Brown	b	loop
306*05e6cfffSMark Brownendfunction
307*05e6cfffSMark Brown
308*05e6cfffSMark Brownabort:
309*05e6cfffSMark Brown	mov	x0, #255
310*05e6cfffSMark Brown	mov	x8, #__NR_exit
311*05e6cfffSMark Brown	svc	#0
312