xref: /linux/tools/testing/selftests/arm64/fp/fpsimd-test.S (revision 694e2803fece8d066bd85ce8607c630ce2b69859)
1// SPDX-License-Identifier: GPL-2.0-only
2// Copyright (C) 2015-2019 ARM Limited.
3// Original author: Dave Martin <Dave.Martin@arm.com>
4//
5// Simple FPSIMD context switch test
6// Repeatedly writes unique test patterns into each FPSIMD register
7// and reads them back to verify integrity.
8//
9// for x in `seq 1 NR_CPUS`; do fpsimd-test & pids=$pids\ $! ; done
10// (leave it running for as long as you want...)
11// kill $pids
12
13#include <asm/unistd.h>
14#include "assembler.h"
15#include "asm-offsets.h"
16
17#define NVR	32
18#define MAXVL_B	(128 / 8)
19
20.macro _vldr Vn:req, Xt:req
21	ld1	{v\Vn\().2d}, [x\Xt]
22.endm
23
24.macro _vstr Vn:req, Xt:req
25	st1	{v\Vn\().2d}, [x\Xt]
26.endm
27
28// Generate accessor functions to read/write programmatically selected
29// FPSIMD registers.
30// x0 is the register index to access
31// x1 is the memory address to read from (getv,setp) or store to (setv,setp)
32// All clobber x0-x2
33define_accessor setv, NVR, _vldr
34define_accessor getv, NVR, _vstr
35
36// Declare some storate space to shadow the SVE register contents:
37.pushsection .text
38.data
39.align 4
40vref:
41	.space	MAXVL_B * NVR
42scratch:
43	.space	MAXVL_B
44.popsection
45
46// Generate a test pattern for storage in SVE registers
47// x0: pid	(16 bits)
48// x1: register number (6 bits)
49// x2: generation (4 bits)
50function pattern
51	orr	w1, w0, w1, lsl #16
52	orr	w2, w1, w2, lsl #28
53
54	ldr	x0, =scratch
55	mov	w1, #MAXVL_B / 4
56
570:	str	w2, [x0], #4
58	add	w2, w2, #(1 << 22)
59	subs	w1, w1, #1
60	bne	0b
61
62	ret
63endfunction
64
65// Get the address of shadow data for FPSIMD V-register V<xn>
66.macro _adrv xd, xn, nrtmp
67	ldr	\xd, =vref
68	mov	x\nrtmp, #16
69	madd	\xd, x\nrtmp, \xn, \xd
70.endm
71
72// Set up test pattern in a FPSIMD V-register
73// x0: pid
74// x1: register number
75// x2: generation
76function setup_vreg
77	mov	x4, x30
78
79	mov	x6, x1
80	bl	pattern
81	_adrv	x0, x6, 2
82	mov	x5, x0
83	ldr	x1, =scratch
84	bl	memcpy
85
86	mov	x0, x6
87	mov	x1, x5
88	bl	setv
89
90	ret	x4
91endfunction
92
93// Trivial memory compare: compare x2 bytes starting at address x0 with
94// bytes starting at address x1.
95// Returns only if all bytes match; otherwise, the program is aborted.
96// Clobbers x0-x5.
97function memcmp
98	cbz	x2, 1f
99
100	mov	x5, #0
1010:	ldrb	w3, [x0, x5]
102	ldrb	w4, [x1, x5]
103	add	x5, x5, #1
104	cmp	w3, w4
105	b.ne	barf
106	subs	x2, x2, #1
107	b.ne	0b
108
1091:	ret
110endfunction
111
112// Verify that a FPSIMD V-register matches its shadow in memory, else abort
113// x0: reg number
114// Clobbers x0-x5.
115function check_vreg
116	mov	x3, x30
117
118	_adrv	x5, x0, 6
119	mov	x4, x0
120	ldr	x7, =scratch
121
122	mov	x0, x7
123	mov	x1, x6
124	bl	memfill_ae
125
126	mov	x0, x4
127	mov	x1, x7
128	bl	getv
129
130	mov	x0, x5
131	mov	x1, x7
132	mov	x2, x6
133	mov	x30, x3
134	b	memcmp
135endfunction
136
137// Modify live register state, the signal return will undo our changes
138function irritator_handler
139	// Increment the irritation signal count (x23):
140	ldr	x0, [x2, #ucontext_regs + 8 * 23]
141	add	x0, x0, #1
142	str	x0, [x2, #ucontext_regs + 8 * 23]
143
144	// Corrupt some random V-regs
145	movi	v0.8b, #7
146	movi	v9.16b, #9
147	movi	v31.8b, #31
148
149	ret
150endfunction
151
152function tickle_handler
153	// Increment the signal count (x23):
154	ldr	x0, [x2, #ucontext_regs + 8 * 23]
155	add	x0, x0, #1
156	str	x0, [x2, #ucontext_regs + 8 * 23]
157
158	ret
159endfunction
160
161function terminate_handler
162	mov	w21, w0
163	mov	x20, x2
164
165	puts	"Terminated by signal "
166	mov	w0, w21
167	bl	putdec
168	puts	", no error, iterations="
169	ldr	x0, [x20, #ucontext_regs + 8 * 22]
170	bl	putdec
171	puts	", signals="
172	ldr	x0, [x20, #ucontext_regs + 8 * 23]
173	bl	putdecn
174
175	mov	x0, #0
176	mov	x8, #__NR_exit
177	svc	#0
178endfunction
179
180// w0: signal number
181// x1: sa_action
182// w2: sa_flags
183// Clobbers x0-x6,x8
184function setsignal
185	str	x30, [sp, #-((sa_sz + 15) / 16 * 16 + 16)]!
186
187	mov	w4, w0
188	mov	x5, x1
189	mov	w6, w2
190
191	add	x0, sp, #16
192	mov	x1, #sa_sz
193	bl	memclr
194
195	mov	w0, w4
196	add	x1, sp, #16
197	str	w6, [x1, #sa_flags]
198	str	x5, [x1, #sa_handler]
199	mov	x2, #0
200	mov	x3, #sa_mask_sz
201	mov	x8, #__NR_rt_sigaction
202	svc	#0
203
204	cbz	w0, 1f
205
206	puts	"sigaction failure\n"
207	b	.Labort
208
2091:	ldr	x30, [sp], #((sa_sz + 15) / 16 * 16 + 16)
210	ret
211endfunction
212
213// Main program entry point
214.globl _start
215function _start
216	mov	x23, #0		// signal count
217
218	mov	w0, #SIGINT
219	adr	x1, terminate_handler
220	mov	w2, #SA_SIGINFO
221	bl	setsignal
222
223	mov	w0, #SIGTERM
224	adr	x1, terminate_handler
225	mov	w2, #SA_SIGINFO
226	bl	setsignal
227
228	mov	w0, #SIGUSR1
229	adr	x1, irritator_handler
230	mov	w2, #SA_SIGINFO
231	orr	w2, w2, #SA_NODEFER
232	bl	setsignal
233
234	mov	w0, #SIGUSR2
235	adr	x1, tickle_handler
236	mov	w2, #SA_SIGINFO
237	orr	w2, w2, #SA_NODEFER
238	bl	setsignal
239
240	// Sanity-check and report the vector length
241
242	mov	x19, #128
243	cmp	x19, #128
244	b.lo	1f
245	cmp	x19, #2048
246	b.hi	1f
247	tst	x19, #(8 - 1)
248	b.eq	2f
249
2501:	puts	"Bad vector length: "
251	mov	x0, x19
252	bl	putdecn
253	b	.Labort
254
2552:	puts	"Vector length:\t"
256	mov	x0, x19
257	bl	putdec
258	puts	" bits\n"
259
260	// Obtain our PID, to ensure test pattern uniqueness between processes
261
262	mov	x8, #__NR_getpid
263	svc	#0
264	mov	x20, x0
265
266	puts	"PID:\t"
267	mov	x0, x20
268	bl	putdecn
269
270	mov	x22, #0		// generation number, increments per iteration
271.Ltest_loop:
272
273	mov	x21, #0		// Set up V-regs & shadow with test pattern
2740:	mov	x0, x20
275	mov	x1, x21
276	and	x2, x22, #0xf
277	bl	setup_vreg
278	add	x21, x21, #1
279	cmp	x21, #NVR
280	b.lo	0b
281
282// Can't do this when SVE state is volatile across SVC:
283	mov	x8, #__NR_sched_yield	// Encourage preemption
284	svc	#0
285
286	mov	x21, #0
2870:	mov	x0, x21
288	bl	check_vreg
289	add	x21, x21, #1
290	cmp	x21, #NVR
291	b.lo	0b
292
293	add	x22, x22, #1
294	b	.Ltest_loop
295
296.Labort:
297	mov	x0, #0
298	mov	x1, #SIGABRT
299	mov	x8, #__NR_kill
300	svc	#0
301endfunction
302
303function barf
304	mov	x10, x0	// expected data
305	mov	x11, x1	// actual data
306	mov	x12, x2	// data size
307
308	puts	"Mismatch: PID="
309	mov	x0, x20
310	bl	putdec
311	puts	", iteration="
312	mov	x0, x22
313	bl	putdec
314	puts	", reg="
315	mov	x0, x21
316	bl	putdecn
317	puts	"\tExpected ["
318	mov	x0, x10
319	mov	x1, x12
320	bl	dumphex
321	puts	"]\n\tGot      ["
322	mov	x0, x11
323	mov	x1, x12
324	bl	dumphex
325	puts	"]\n"
326
327	mov	x8, #__NR_exit
328	mov	x1, #1
329	svc	#0
330endfunction
331