xref: /OK3568_Linux_fs/kernel/tools/testing/selftests/arm64/fp/fpsimd-test.S (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun// SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun// Copyright (C) 2015-2019 ARM Limited.
3*4882a593Smuzhiyun// Original author: Dave Martin <Dave.Martin@arm.com>
4*4882a593Smuzhiyun//
5*4882a593Smuzhiyun// Simple FPSIMD context switch test
6*4882a593Smuzhiyun// Repeatedly writes unique test patterns into each FPSIMD register
7*4882a593Smuzhiyun// and reads them back to verify integrity.
8*4882a593Smuzhiyun//
9*4882a593Smuzhiyun// for x in `seq 1 NR_CPUS`; do fpsimd-test & pids=$pids\ $! ; done
10*4882a593Smuzhiyun// (leave it running for as long as you want...)
11*4882a593Smuzhiyun// kill $pids
12*4882a593Smuzhiyun
13*4882a593Smuzhiyun#include <asm/unistd.h>
14*4882a593Smuzhiyun#include "assembler.h"
15*4882a593Smuzhiyun#include "asm-offsets.h"
16*4882a593Smuzhiyun
17*4882a593Smuzhiyun#define NVR	32
18*4882a593Smuzhiyun#define MAXVL_B	(128 / 8)
19*4882a593Smuzhiyun
20*4882a593Smuzhiyun.macro _vldr Vn:req, Xt:req
21*4882a593Smuzhiyun	ld1	{v\Vn\().2d}, [x\Xt]
22*4882a593Smuzhiyun.endm
23*4882a593Smuzhiyun
24*4882a593Smuzhiyun.macro _vstr Vn:req, Xt:req
25*4882a593Smuzhiyun	st1	{v\Vn\().2d}, [x\Xt]
26*4882a593Smuzhiyun.endm
27*4882a593Smuzhiyun
28*4882a593Smuzhiyun// Generate accessor functions to read/write programmatically selected
29*4882a593Smuzhiyun// FPSIMD registers.
30*4882a593Smuzhiyun// x0 is the register index to access
31*4882a593Smuzhiyun// x1 is the memory address to read from (getv,setp) or store to (setv,setp)
32*4882a593Smuzhiyun// All clobber x0-x2
33*4882a593Smuzhiyundefine_accessor setv, NVR, _vldr
34*4882a593Smuzhiyundefine_accessor getv, NVR, _vstr
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun// Print a single character x0 to stdout
37*4882a593Smuzhiyun// Clobbers x0-x2,x8
38*4882a593Smuzhiyunfunction putc
39*4882a593Smuzhiyun	str	x0, [sp, #-16]!
40*4882a593Smuzhiyun
41*4882a593Smuzhiyun	mov	x0, #1			// STDOUT_FILENO
42*4882a593Smuzhiyun	mov	x1, sp
43*4882a593Smuzhiyun	mov	x2, #1
44*4882a593Smuzhiyun	mov	x8, #__NR_write
45*4882a593Smuzhiyun	svc	#0
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun	add	sp, sp, #16
48*4882a593Smuzhiyun	ret
49*4882a593Smuzhiyunendfunction
50*4882a593Smuzhiyun
51*4882a593Smuzhiyun// Print a NUL-terminated string starting at address x0 to stdout
52*4882a593Smuzhiyun// Clobbers x0-x3,x8
53*4882a593Smuzhiyunfunction puts
54*4882a593Smuzhiyun	mov	x1, x0
55*4882a593Smuzhiyun
56*4882a593Smuzhiyun	mov	x2, #0
57*4882a593Smuzhiyun0:	ldrb	w3, [x0], #1
58*4882a593Smuzhiyun	cbz	w3, 1f
59*4882a593Smuzhiyun	add	x2, x2, #1
60*4882a593Smuzhiyun	b	0b
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun1:	mov	w0, #1			// STDOUT_FILENO
63*4882a593Smuzhiyun	mov	x8, #__NR_write
64*4882a593Smuzhiyun	svc	#0
65*4882a593Smuzhiyun
66*4882a593Smuzhiyun	ret
67*4882a593Smuzhiyunendfunction
68*4882a593Smuzhiyun
69*4882a593Smuzhiyun// Utility macro to print a literal string
70*4882a593Smuzhiyun// Clobbers x0-x4,x8
71*4882a593Smuzhiyun.macro puts string
72*4882a593Smuzhiyun	.pushsection .rodata.str1.1, "aMS", 1
73*4882a593Smuzhiyun.L__puts_literal\@: .string "\string"
74*4882a593Smuzhiyun	.popsection
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun	ldr	x0, =.L__puts_literal\@
77*4882a593Smuzhiyun	bl	puts
78*4882a593Smuzhiyun.endm
79*4882a593Smuzhiyun
80*4882a593Smuzhiyun// Print an unsigned decimal number x0 to stdout
81*4882a593Smuzhiyun// Clobbers x0-x4,x8
82*4882a593Smuzhiyunfunction putdec
83*4882a593Smuzhiyun	mov	x1, sp
84*4882a593Smuzhiyun	str	x30, [sp, #-32]!	// Result can't be > 20 digits
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun	mov	x2, #0
87*4882a593Smuzhiyun	strb	w2, [x1, #-1]!		// Write the NUL terminator
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun	mov	x2, #10
90*4882a593Smuzhiyun0:	udiv	x3, x0, x2		// div-mod loop to generate the digits
91*4882a593Smuzhiyun	msub	x0, x3, x2, x0
92*4882a593Smuzhiyun	add	w0, w0, #'0'
93*4882a593Smuzhiyun	strb	w0, [x1, #-1]!
94*4882a593Smuzhiyun	mov	x0, x3
95*4882a593Smuzhiyun	cbnz	x3, 0b
96*4882a593Smuzhiyun
97*4882a593Smuzhiyun	ldrb	w0, [x1]
98*4882a593Smuzhiyun	cbnz	w0, 1f
99*4882a593Smuzhiyun	mov	w0, #'0'		// Print "0" for 0, not ""
100*4882a593Smuzhiyun	strb	w0, [x1, #-1]!
101*4882a593Smuzhiyun
102*4882a593Smuzhiyun1:	mov	x0, x1
103*4882a593Smuzhiyun	bl	puts
104*4882a593Smuzhiyun
105*4882a593Smuzhiyun	ldr	x30, [sp], #32
106*4882a593Smuzhiyun	ret
107*4882a593Smuzhiyunendfunction
108*4882a593Smuzhiyun
109*4882a593Smuzhiyun// Print an unsigned decimal number x0 to stdout, followed by a newline
110*4882a593Smuzhiyun// Clobbers x0-x5,x8
111*4882a593Smuzhiyunfunction putdecn
112*4882a593Smuzhiyun	mov	x5, x30
113*4882a593Smuzhiyun
114*4882a593Smuzhiyun	bl	putdec
115*4882a593Smuzhiyun	mov	x0, #'\n'
116*4882a593Smuzhiyun	bl	putc
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun	ret	x5
119*4882a593Smuzhiyunendfunction
120*4882a593Smuzhiyun
121*4882a593Smuzhiyun
122*4882a593Smuzhiyun// Clobbers x0-x3,x8
123*4882a593Smuzhiyunfunction puthexb
124*4882a593Smuzhiyun	str	x30, [sp, #-0x10]!
125*4882a593Smuzhiyun
126*4882a593Smuzhiyun	mov	w3, w0
127*4882a593Smuzhiyun	lsr	w0, w0, #4
128*4882a593Smuzhiyun	bl	puthexnibble
129*4882a593Smuzhiyun	mov	w0, w3
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun	ldr	x30, [sp], #0x10
132*4882a593Smuzhiyun	// fall through to puthexnibble
133*4882a593Smuzhiyunendfunction
134*4882a593Smuzhiyun// Clobbers x0-x2,x8
135*4882a593Smuzhiyunfunction puthexnibble
136*4882a593Smuzhiyun	and	w0, w0, #0xf
137*4882a593Smuzhiyun	cmp	w0, #10
138*4882a593Smuzhiyun	blo	1f
139*4882a593Smuzhiyun	add	w0, w0, #'a' - ('9' + 1)
140*4882a593Smuzhiyun1:	add	w0, w0, #'0'
141*4882a593Smuzhiyun	b	putc
142*4882a593Smuzhiyunendfunction
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun// x0=data in, x1=size in, clobbers x0-x5,x8
145*4882a593Smuzhiyunfunction dumphex
146*4882a593Smuzhiyun	str	x30, [sp, #-0x10]!
147*4882a593Smuzhiyun
148*4882a593Smuzhiyun	mov	x4, x0
149*4882a593Smuzhiyun	mov	x5, x1
150*4882a593Smuzhiyun
151*4882a593Smuzhiyun0:	subs	x5, x5, #1
152*4882a593Smuzhiyun	b.lo	1f
153*4882a593Smuzhiyun	ldrb	w0, [x4], #1
154*4882a593Smuzhiyun	bl	puthexb
155*4882a593Smuzhiyun	b	0b
156*4882a593Smuzhiyun
157*4882a593Smuzhiyun1:	ldr	x30, [sp], #0x10
158*4882a593Smuzhiyun	ret
159*4882a593Smuzhiyunendfunction
160*4882a593Smuzhiyun
161*4882a593Smuzhiyun// Declare some storate space to shadow the SVE register contents:
162*4882a593Smuzhiyun.pushsection .text
163*4882a593Smuzhiyun.data
164*4882a593Smuzhiyun.align 4
165*4882a593Smuzhiyunvref:
166*4882a593Smuzhiyun	.space	MAXVL_B * NVR
167*4882a593Smuzhiyunscratch:
168*4882a593Smuzhiyun	.space	MAXVL_B
169*4882a593Smuzhiyun.popsection
170*4882a593Smuzhiyun
171*4882a593Smuzhiyun// Trivial memory copy: copy x2 bytes, starting at address x1, to address x0.
172*4882a593Smuzhiyun// Clobbers x0-x3
173*4882a593Smuzhiyunfunction memcpy
174*4882a593Smuzhiyun	cmp	x2, #0
175*4882a593Smuzhiyun	b.eq	1f
176*4882a593Smuzhiyun0:	ldrb	w3, [x1], #1
177*4882a593Smuzhiyun	strb	w3, [x0], #1
178*4882a593Smuzhiyun	subs	x2, x2, #1
179*4882a593Smuzhiyun	b.ne	0b
180*4882a593Smuzhiyun1:	ret
181*4882a593Smuzhiyunendfunction
182*4882a593Smuzhiyun
183*4882a593Smuzhiyun// Generate a test pattern for storage in SVE registers
184*4882a593Smuzhiyun// x0: pid	(16 bits)
185*4882a593Smuzhiyun// x1: register number (6 bits)
186*4882a593Smuzhiyun// x2: generation (4 bits)
187*4882a593Smuzhiyunfunction pattern
188*4882a593Smuzhiyun	orr	w1, w0, w1, lsl #16
189*4882a593Smuzhiyun	orr	w2, w1, w2, lsl #28
190*4882a593Smuzhiyun
191*4882a593Smuzhiyun	ldr	x0, =scratch
192*4882a593Smuzhiyun	mov	w1, #MAXVL_B / 4
193*4882a593Smuzhiyun
194*4882a593Smuzhiyun0:	str	w2, [x0], #4
195*4882a593Smuzhiyun	add	w2, w2, #(1 << 22)
196*4882a593Smuzhiyun	subs	w1, w1, #1
197*4882a593Smuzhiyun	bne	0b
198*4882a593Smuzhiyun
199*4882a593Smuzhiyun	ret
200*4882a593Smuzhiyunendfunction
201*4882a593Smuzhiyun
202*4882a593Smuzhiyun// Get the address of shadow data for FPSIMD V-register V<xn>
203*4882a593Smuzhiyun.macro _adrv xd, xn, nrtmp
204*4882a593Smuzhiyun	ldr	\xd, =vref
205*4882a593Smuzhiyun	mov	x\nrtmp, #16
206*4882a593Smuzhiyun	madd	\xd, x\nrtmp, \xn, \xd
207*4882a593Smuzhiyun.endm
208*4882a593Smuzhiyun
209*4882a593Smuzhiyun// Set up test pattern in a FPSIMD V-register
210*4882a593Smuzhiyun// x0: pid
211*4882a593Smuzhiyun// x1: register number
212*4882a593Smuzhiyun// x2: generation
213*4882a593Smuzhiyunfunction setup_vreg
214*4882a593Smuzhiyun	mov	x4, x30
215*4882a593Smuzhiyun
216*4882a593Smuzhiyun	mov	x6, x1
217*4882a593Smuzhiyun	bl	pattern
218*4882a593Smuzhiyun	_adrv	x0, x6, 2
219*4882a593Smuzhiyun	mov	x5, x0
220*4882a593Smuzhiyun	ldr	x1, =scratch
221*4882a593Smuzhiyun	bl	memcpy
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun	mov	x0, x6
224*4882a593Smuzhiyun	mov	x1, x5
225*4882a593Smuzhiyun	bl	setv
226*4882a593Smuzhiyun
227*4882a593Smuzhiyun	ret	x4
228*4882a593Smuzhiyunendfunction
229*4882a593Smuzhiyun
230*4882a593Smuzhiyun// Fill x1 bytes starting at x0 with 0xae (for canary purposes)
231*4882a593Smuzhiyun// Clobbers x1, x2.
232*4882a593Smuzhiyunfunction memfill_ae
233*4882a593Smuzhiyun	mov	w2, #0xae
234*4882a593Smuzhiyun	b	memfill
235*4882a593Smuzhiyunendfunction
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun// Fill x1 bytes starting at x0 with 0.
238*4882a593Smuzhiyun// Clobbers x1, x2.
239*4882a593Smuzhiyunfunction memclr
240*4882a593Smuzhiyun	mov	w2, #0
241*4882a593Smuzhiyunendfunction
242*4882a593Smuzhiyun	// fall through to memfill
243*4882a593Smuzhiyun
244*4882a593Smuzhiyun// Trivial memory fill: fill x1 bytes starting at address x0 with byte w2
245*4882a593Smuzhiyun// Clobbers x1
246*4882a593Smuzhiyunfunction memfill
247*4882a593Smuzhiyun	cmp	x1, #0
248*4882a593Smuzhiyun	b.eq	1f
249*4882a593Smuzhiyun
250*4882a593Smuzhiyun0:	strb	w2, [x0], #1
251*4882a593Smuzhiyun	subs	x1, x1, #1
252*4882a593Smuzhiyun	b.ne	0b
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun1:	ret
255*4882a593Smuzhiyunendfunction
256*4882a593Smuzhiyun
257*4882a593Smuzhiyun// Trivial memory compare: compare x2 bytes starting at address x0 with
258*4882a593Smuzhiyun// bytes starting at address x1.
259*4882a593Smuzhiyun// Returns only if all bytes match; otherwise, the program is aborted.
260*4882a593Smuzhiyun// Clobbers x0-x5.
261*4882a593Smuzhiyunfunction memcmp
262*4882a593Smuzhiyun	cbz	x2, 1f
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun	mov	x5, #0
265*4882a593Smuzhiyun0:	ldrb	w3, [x0, x5]
266*4882a593Smuzhiyun	ldrb	w4, [x1, x5]
267*4882a593Smuzhiyun	add	x5, x5, #1
268*4882a593Smuzhiyun	cmp	w3, w4
269*4882a593Smuzhiyun	b.ne	barf
270*4882a593Smuzhiyun	subs	x2, x2, #1
271*4882a593Smuzhiyun	b.ne	0b
272*4882a593Smuzhiyun
273*4882a593Smuzhiyun1:	ret
274*4882a593Smuzhiyunendfunction
275*4882a593Smuzhiyun
276*4882a593Smuzhiyun// Verify that a FPSIMD V-register matches its shadow in memory, else abort
277*4882a593Smuzhiyun// x0: reg number
278*4882a593Smuzhiyun// Clobbers x0-x5.
279*4882a593Smuzhiyunfunction check_vreg
280*4882a593Smuzhiyun	mov	x3, x30
281*4882a593Smuzhiyun
282*4882a593Smuzhiyun	_adrv	x5, x0, 6
283*4882a593Smuzhiyun	mov	x4, x0
284*4882a593Smuzhiyun	ldr	x7, =scratch
285*4882a593Smuzhiyun
286*4882a593Smuzhiyun	mov	x0, x7
287*4882a593Smuzhiyun	mov	x1, x6
288*4882a593Smuzhiyun	bl	memfill_ae
289*4882a593Smuzhiyun
290*4882a593Smuzhiyun	mov	x0, x4
291*4882a593Smuzhiyun	mov	x1, x7
292*4882a593Smuzhiyun	bl	getv
293*4882a593Smuzhiyun
294*4882a593Smuzhiyun	mov	x0, x5
295*4882a593Smuzhiyun	mov	x1, x7
296*4882a593Smuzhiyun	mov	x2, x6
297*4882a593Smuzhiyun	mov	x30, x3
298*4882a593Smuzhiyun	b	memcmp
299*4882a593Smuzhiyunendfunction
300*4882a593Smuzhiyun
301*4882a593Smuzhiyun// Any SVE register modified here can cause corruption in the main
302*4882a593Smuzhiyun// thread -- but *only* the registers modified here.
303*4882a593Smuzhiyunfunction irritator_handler
304*4882a593Smuzhiyun	// Increment the irritation signal count (x23):
305*4882a593Smuzhiyun	ldr	x0, [x2, #ucontext_regs + 8 * 23]
306*4882a593Smuzhiyun	add	x0, x0, #1
307*4882a593Smuzhiyun	str	x0, [x2, #ucontext_regs + 8 * 23]
308*4882a593Smuzhiyun
309*4882a593Smuzhiyun	// Corrupt some random V-regs
310*4882a593Smuzhiyun	adr	x0, .text + (irritator_handler - .text) / 16 * 16
311*4882a593Smuzhiyun	movi	v0.8b, #7
312*4882a593Smuzhiyun	movi	v9.16b, #9
313*4882a593Smuzhiyun	movi	v31.8b, #31
314*4882a593Smuzhiyun
315*4882a593Smuzhiyun	ret
316*4882a593Smuzhiyunendfunction
317*4882a593Smuzhiyun
318*4882a593Smuzhiyunfunction terminate_handler
319*4882a593Smuzhiyun	mov	w21, w0
320*4882a593Smuzhiyun	mov	x20, x2
321*4882a593Smuzhiyun
322*4882a593Smuzhiyun	puts	"Terminated by signal "
323*4882a593Smuzhiyun	mov	w0, w21
324*4882a593Smuzhiyun	bl	putdec
325*4882a593Smuzhiyun	puts	", no error, iterations="
326*4882a593Smuzhiyun	ldr	x0, [x20, #ucontext_regs + 8 * 22]
327*4882a593Smuzhiyun	bl	putdec
328*4882a593Smuzhiyun	puts	", signals="
329*4882a593Smuzhiyun	ldr	x0, [x20, #ucontext_regs + 8 * 23]
330*4882a593Smuzhiyun	bl	putdecn
331*4882a593Smuzhiyun
332*4882a593Smuzhiyun	mov	x0, #0
333*4882a593Smuzhiyun	mov	x8, #__NR_exit
334*4882a593Smuzhiyun	svc	#0
335*4882a593Smuzhiyunendfunction
336*4882a593Smuzhiyun
337*4882a593Smuzhiyun// w0: signal number
338*4882a593Smuzhiyun// x1: sa_action
339*4882a593Smuzhiyun// w2: sa_flags
340*4882a593Smuzhiyun// Clobbers x0-x6,x8
341*4882a593Smuzhiyunfunction setsignal
342*4882a593Smuzhiyun	str	x30, [sp, #-((sa_sz + 15) / 16 * 16 + 16)]!
343*4882a593Smuzhiyun
344*4882a593Smuzhiyun	mov	w4, w0
345*4882a593Smuzhiyun	mov	x5, x1
346*4882a593Smuzhiyun	mov	w6, w2
347*4882a593Smuzhiyun
348*4882a593Smuzhiyun	add	x0, sp, #16
349*4882a593Smuzhiyun	mov	x1, #sa_sz
350*4882a593Smuzhiyun	bl	memclr
351*4882a593Smuzhiyun
352*4882a593Smuzhiyun	mov	w0, w4
353*4882a593Smuzhiyun	add	x1, sp, #16
354*4882a593Smuzhiyun	str	w6, [x1, #sa_flags]
355*4882a593Smuzhiyun	str	x5, [x1, #sa_handler]
356*4882a593Smuzhiyun	mov	x2, #0
357*4882a593Smuzhiyun	mov	x3, #sa_mask_sz
358*4882a593Smuzhiyun	mov	x8, #__NR_rt_sigaction
359*4882a593Smuzhiyun	svc	#0
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun	cbz	w0, 1f
362*4882a593Smuzhiyun
363*4882a593Smuzhiyun	puts	"sigaction failure\n"
364*4882a593Smuzhiyun	b	.Labort
365*4882a593Smuzhiyun
366*4882a593Smuzhiyun1:	ldr	x30, [sp], #((sa_sz + 15) / 16 * 16 + 16)
367*4882a593Smuzhiyun	ret
368*4882a593Smuzhiyunendfunction
369*4882a593Smuzhiyun
370*4882a593Smuzhiyun// Main program entry point
371*4882a593Smuzhiyun.globl _start
372*4882a593Smuzhiyunfunction _start
373*4882a593Smuzhiyun_start:
374*4882a593Smuzhiyun	// Sanity-check and report the vector length
375*4882a593Smuzhiyun
376*4882a593Smuzhiyun	mov	x19, #128
377*4882a593Smuzhiyun	cmp	x19, #128
378*4882a593Smuzhiyun	b.lo	1f
379*4882a593Smuzhiyun	cmp	x19, #2048
380*4882a593Smuzhiyun	b.hi	1f
381*4882a593Smuzhiyun	tst	x19, #(8 - 1)
382*4882a593Smuzhiyun	b.eq	2f
383*4882a593Smuzhiyun
384*4882a593Smuzhiyun1:	puts	"Bad vector length: "
385*4882a593Smuzhiyun	mov	x0, x19
386*4882a593Smuzhiyun	bl	putdecn
387*4882a593Smuzhiyun	b	.Labort
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun2:	puts	"Vector length:\t"
390*4882a593Smuzhiyun	mov	x0, x19
391*4882a593Smuzhiyun	bl	putdec
392*4882a593Smuzhiyun	puts	" bits\n"
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun	// Obtain our PID, to ensure test pattern uniqueness between processes
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun	mov	x8, #__NR_getpid
397*4882a593Smuzhiyun	svc	#0
398*4882a593Smuzhiyun	mov	x20, x0
399*4882a593Smuzhiyun
400*4882a593Smuzhiyun	puts	"PID:\t"
401*4882a593Smuzhiyun	mov	x0, x20
402*4882a593Smuzhiyun	bl	putdecn
403*4882a593Smuzhiyun
404*4882a593Smuzhiyun	mov	x23, #0		// Irritation signal count
405*4882a593Smuzhiyun
406*4882a593Smuzhiyun	mov	w0, #SIGINT
407*4882a593Smuzhiyun	adr	x1, terminate_handler
408*4882a593Smuzhiyun	mov	w2, #SA_SIGINFO
409*4882a593Smuzhiyun	bl	setsignal
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun	mov	w0, #SIGTERM
412*4882a593Smuzhiyun	adr	x1, terminate_handler
413*4882a593Smuzhiyun	mov	w2, #SA_SIGINFO
414*4882a593Smuzhiyun	bl	setsignal
415*4882a593Smuzhiyun
416*4882a593Smuzhiyun	mov	w0, #SIGUSR1
417*4882a593Smuzhiyun	adr	x1, irritator_handler
418*4882a593Smuzhiyun	mov	w2, #SA_SIGINFO
419*4882a593Smuzhiyun	orr	w2, w2, #SA_NODEFER
420*4882a593Smuzhiyun	bl	setsignal
421*4882a593Smuzhiyun
422*4882a593Smuzhiyun	mov	x22, #0		// generation number, increments per iteration
423*4882a593Smuzhiyun.Ltest_loop:
424*4882a593Smuzhiyun
425*4882a593Smuzhiyun	mov	x21, #0		// Set up V-regs & shadow with test pattern
426*4882a593Smuzhiyun0:	mov	x0, x20
427*4882a593Smuzhiyun	mov	x1, x21
428*4882a593Smuzhiyun	and	x2, x22, #0xf
429*4882a593Smuzhiyun	bl	setup_vreg
430*4882a593Smuzhiyun	add	x21, x21, #1
431*4882a593Smuzhiyun	cmp	x21, #NVR
432*4882a593Smuzhiyun	b.lo	0b
433*4882a593Smuzhiyun
434*4882a593Smuzhiyun// Can't do this when SVE state is volatile across SVC:
435*4882a593Smuzhiyun	mov	x8, #__NR_sched_yield	// Encourage preemption
436*4882a593Smuzhiyun	svc	#0
437*4882a593Smuzhiyun
438*4882a593Smuzhiyun	mov	x21, #0
439*4882a593Smuzhiyun0:	mov	x0, x21
440*4882a593Smuzhiyun	bl	check_vreg
441*4882a593Smuzhiyun	add	x21, x21, #1
442*4882a593Smuzhiyun	cmp	x21, #NVR
443*4882a593Smuzhiyun	b.lo	0b
444*4882a593Smuzhiyun
445*4882a593Smuzhiyun	add	x22, x22, #1
446*4882a593Smuzhiyun	b	.Ltest_loop
447*4882a593Smuzhiyun
448*4882a593Smuzhiyun.Labort:
449*4882a593Smuzhiyun	mov	x0, #0
450*4882a593Smuzhiyun	mov	x1, #SIGABRT
451*4882a593Smuzhiyun	mov	x8, #__NR_kill
452*4882a593Smuzhiyun	svc	#0
453*4882a593Smuzhiyunendfunction
454*4882a593Smuzhiyun
455*4882a593Smuzhiyunfunction barf
456*4882a593Smuzhiyun	mov	x10, x0	// expected data
457*4882a593Smuzhiyun	mov	x11, x1	// actual data
458*4882a593Smuzhiyun	mov	x12, x2	// data size
459*4882a593Smuzhiyun
460*4882a593Smuzhiyun	puts	"Mistatch: PID="
461*4882a593Smuzhiyun	mov	x0, x20
462*4882a593Smuzhiyun	bl	putdec
463*4882a593Smuzhiyun	puts	", iteration="
464*4882a593Smuzhiyun	mov	x0, x22
465*4882a593Smuzhiyun	bl	putdec
466*4882a593Smuzhiyun	puts	", reg="
467*4882a593Smuzhiyun	mov	x0, x21
468*4882a593Smuzhiyun	bl	putdecn
469*4882a593Smuzhiyun	puts	"\tExpected ["
470*4882a593Smuzhiyun	mov	x0, x10
471*4882a593Smuzhiyun	mov	x1, x12
472*4882a593Smuzhiyun	bl	dumphex
473*4882a593Smuzhiyun	puts	"]\n\tGot      ["
474*4882a593Smuzhiyun	mov	x0, x11
475*4882a593Smuzhiyun	mov	x1, x12
476*4882a593Smuzhiyun	bl	dumphex
477*4882a593Smuzhiyun	puts	"]\n"
478*4882a593Smuzhiyun
479*4882a593Smuzhiyun	mov	x8, #__NR_exit
480*4882a593Smuzhiyun	mov	x1, #1
481*4882a593Smuzhiyun	svc	#0
482*4882a593Smuzhiyunendfunction
483