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 Scalable Vector Extension context switch test
6// Repeatedly writes unique test patterns into each SVE register
7// and reads them back to verify integrity.
8//
9// for x in `seq 1 NR_CPUS`; do sve-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#include "sme-inst.h"
17
18#define NZR	32
19#define NPR	16
20#define MAXVL_B	(2048 / 8)
21
22.arch_extension sve
23
24.macro _sve_ldr_v zt, xn
25	ldr	z\zt, [x\xn]
26.endm
27
28.macro _sve_str_v zt, xn
29	str	z\zt, [x\xn]
30.endm
31
32.macro _sve_ldr_p pt, xn
33	ldr	p\pt, [x\xn]
34.endm
35
36.macro _sve_str_p pt, xn
37	str	p\pt, [x\xn]
38.endm
39
40// Generate accessor functions to read/write programmatically selected
41// SVE registers.
42// x0 is the register index to access
43// x1 is the memory address to read from (getz,setp) or store to (setz,setp)
44// All clobber x0-x2
45define_accessor setz, NZR, _sve_ldr_v
46define_accessor getz, NZR, _sve_str_v
47define_accessor setp, NPR, _sve_ldr_p
48define_accessor getp, NPR, _sve_str_p
49
50// Declare some storate space to shadow the SVE register contents:
51.pushsection .text
52.data
53.align 4
54zref:
55	.space	MAXVL_B * NZR
56pref:
57	.space	MAXVL_B / 8 * NPR
58ffrref:
59	.space	MAXVL_B / 8
60scratch:
61	.space	MAXVL_B
62.popsection
63
64// Generate a test pattern for storage in SVE registers
65// x0: pid	(16 bits)
66// x1: register number (6 bits)
67// x2: generation (4 bits)
68
69// These values are used to constuct a 32-bit pattern that is repeated in the
70// scratch buffer as many times as will fit:
71// bits 31:28	generation number (increments once per test_loop)
72// bits 27:22	32-bit lane index
73// bits 21:16	register number
74// bits 15: 0	pid
75
76function pattern
77	orr	w1, w0, w1, lsl #16
78	orr	w2, w1, w2, lsl #28
79
80	ldr	x0, =scratch
81	mov	w1, #MAXVL_B / 4
82
830:	str	w2, [x0], #4
84	add	w2, w2, #(1 << 22)
85	subs	w1, w1, #1
86	bne	0b
87
88	ret
89endfunction
90
91// Get the address of shadow data for SVE Z-register Z<xn>
92.macro _adrz xd, xn, nrtmp
93	ldr	\xd, =zref
94	rdvl	x\nrtmp, #1
95	madd	\xd, x\nrtmp, \xn, \xd
96.endm
97
98// Get the address of shadow data for SVE P-register P<xn - NZR>
99.macro _adrp xd, xn, nrtmp
100	ldr	\xd, =pref
101	rdvl	x\nrtmp, #1
102	lsr	x\nrtmp, x\nrtmp, #3
103	sub	\xn, \xn, #NZR
104	madd	\xd, x\nrtmp, \xn, \xd
105.endm
106
107// Set up test pattern in a SVE Z-register
108// x0: pid
109// x1: register number
110// x2: generation
111function setup_zreg
112	mov	x4, x30
113
114	mov	x6, x1
115	bl	pattern
116	_adrz	x0, x6, 2
117	mov	x5, x0
118	ldr	x1, =scratch
119	bl	memcpy
120
121	mov	x0, x6
122	mov	x1, x5
123	bl	setz
124
125	ret	x4
126endfunction
127
128// Set up test pattern in a SVE P-register
129// x0: pid
130// x1: register number
131// x2: generation
132function setup_preg
133	mov	x4, x30
134
135	mov	x6, x1
136	bl	pattern
137	_adrp	x0, x6, 2
138	mov	x5, x0
139	ldr	x1, =scratch
140	bl	memcpy
141
142	mov	x0, x6
143	mov	x1, x5
144	bl	setp
145
146	ret	x4
147endfunction
148
149// Set up test pattern in the FFR
150// x0: pid
151// x2: generation
152//
153// We need to generate a canonical FFR value, which consists of a number of
154// low "1" bits, followed by a number of zeros. This gives us 17 unique values
155// per 16 bits of FFR, so we create a 4 bit signature out of the PID and
156// generation, and use that as the initial number of ones in the pattern.
157// We fill the upper lanes of FFR with zeros.
158// Beware: corrupts P0.
159function setup_ffr
160#ifndef SSVE
161	mov	x4, x30
162
163	and	w0, w0, #0x3
164	bfi	w0, w2, #2, #2
165	mov	w1, #1
166	lsl	w1, w1, w0
167	sub	w1, w1, #1
168
169	ldr	x0, =ffrref
170	strh	w1, [x0], 2
171	rdvl	x1, #1
172	lsr	x1, x1, #3
173	sub	x1, x1, #2
174	bl	memclr
175
176	mov	x0, #0
177	ldr	x1, =ffrref
178	bl	setp
179
180	wrffr	p0.b
181
182	ret	x4
183#else
184	ret
185#endif
186endfunction
187
188// Trivial memory compare: compare x2 bytes starting at address x0 with
189// bytes starting at address x1.
190// Returns only if all bytes match; otherwise, the program is aborted.
191// Clobbers x0-x5.
192function memcmp
193	cbz	x2, 2f
194
195	stp	x0, x1, [sp, #-0x20]!
196	str	x2, [sp, #0x10]
197
198	mov	x5, #0
1990:	ldrb	w3, [x0, x5]
200	ldrb	w4, [x1, x5]
201	add	x5, x5, #1
202	cmp	w3, w4
203	b.ne	1f
204	subs	x2, x2, #1
205	b.ne	0b
206
2071:	ldr	x2, [sp, #0x10]
208	ldp	x0, x1, [sp], #0x20
209	b.ne	barf
210
2112:	ret
212endfunction
213
214// Verify that a SVE Z-register matches its shadow in memory, else abort
215// x0: reg number
216// Clobbers x0-x7.
217function check_zreg
218	mov	x3, x30
219
220	_adrz	x5, x0, 6
221	mov	x4, x0
222	ldr	x7, =scratch
223
224	mov	x0, x7
225	mov	x1, x6
226	bl	memfill_ae
227
228	mov	x0, x4
229	mov	x1, x7
230	bl	getz
231
232	mov	x0, x5
233	mov	x1, x7
234	mov	x2, x6
235	mov	x30, x3
236	b	memcmp
237endfunction
238
239// Verify that a SVE P-register matches its shadow in memory, else abort
240// x0: reg number
241// Clobbers x0-x7.
242function check_preg
243	mov	x3, x30
244
245	_adrp	x5, x0, 6
246	mov	x4, x0
247	ldr	x7, =scratch
248
249	mov	x0, x7
250	mov	x1, x6
251	bl	memfill_ae
252
253	mov	x0, x4
254	mov	x1, x7
255	bl	getp
256
257	mov	x0, x5
258	mov	x1, x7
259	mov	x2, x6
260	mov	x30, x3
261	b	memcmp
262endfunction
263
264// Verify that the FFR matches its shadow in memory, else abort
265// Beware -- corrupts P0.
266// Clobbers x0-x5.
267function check_ffr
268#ifndef SSVE
269	mov	x3, x30
270
271	ldr	x4, =scratch
272	rdvl	x5, #1
273	lsr	x5, x5, #3
274
275	mov	x0, x4
276	mov	x1, x5
277	bl	memfill_ae
278
279	rdffr	p0.b
280	mov	x0, #0
281	mov	x1, x4
282	bl	getp
283
284	ldr	x0, =ffrref
285	mov	x1, x4
286	mov	x2, x5
287	mov	x30, x3
288	b	memcmp
289#else
290	ret
291#endif
292endfunction
293
294// Any SVE register modified here can cause corruption in the main
295// thread -- but *only* the registers modified here.
296function irritator_handler
297	// Increment the irritation signal count (x23):
298	ldr	x0, [x2, #ucontext_regs + 8 * 23]
299	add	x0, x0, #1
300	str	x0, [x2, #ucontext_regs + 8 * 23]
301
302	// Corrupt some random Z-regs
303	adr	x0, .text + (irritator_handler - .text) / 16 * 16
304	movi	v0.8b, #1
305	movi	v9.16b, #2
306	movi	v31.8b, #3
307#ifndef SSVE
308	// And P0
309	rdffr	p0.b
310	// And FFR
311	wrffr	p15.b
312#endif
313
314	ret
315endfunction
316
317function tickle_handler
318	// Increment the signal count (x23):
319	ldr	x0, [x2, #ucontext_regs + 8 * 23]
320	add	x0, x0, #1
321	str	x0, [x2, #ucontext_regs + 8 * 23]
322
323	ret
324endfunction
325
326function terminate_handler
327	mov	w21, w0
328	mov	x20, x2
329
330	puts	"Terminated by signal "
331	mov	w0, w21
332	bl	putdec
333	puts	", no error, iterations="
334	ldr	x0, [x20, #ucontext_regs + 8 * 22]
335	bl	putdec
336	puts	", signals="
337	ldr	x0, [x20, #ucontext_regs + 8 * 23]
338	bl	putdecn
339
340	mov	x0, #0
341	mov	x8, #__NR_exit
342	svc	#0
343endfunction
344
345// w0: signal number
346// x1: sa_action
347// w2: sa_flags
348// Clobbers x0-x6,x8
349function setsignal
350	str	x30, [sp, #-((sa_sz + 15) / 16 * 16 + 16)]!
351
352	mov	w4, w0
353	mov	x5, x1
354	mov	w6, w2
355
356	add	x0, sp, #16
357	mov	x1, #sa_sz
358	bl	memclr
359
360	mov	w0, w4
361	add	x1, sp, #16
362	str	w6, [x1, #sa_flags]
363	str	x5, [x1, #sa_handler]
364	mov	x2, #0
365	mov	x3, #sa_mask_sz
366	mov	x8, #__NR_rt_sigaction
367	svc	#0
368
369	cbz	w0, 1f
370
371	puts	"sigaction failure\n"
372	b	.Labort
373
3741:	ldr	x30, [sp], #((sa_sz + 15) / 16 * 16 + 16)
375	ret
376endfunction
377
378// Main program entry point
379.globl _start
380function _start
381_start:
382	mov	x23, #0		// Irritation signal count
383
384	mov	w0, #SIGINT
385	adr	x1, terminate_handler
386	mov	w2, #SA_SIGINFO
387	bl	setsignal
388
389	mov	w0, #SIGTERM
390	adr	x1, terminate_handler
391	mov	w2, #SA_SIGINFO
392	bl	setsignal
393
394	mov	w0, #SIGUSR1
395	adr	x1, irritator_handler
396	mov	w2, #SA_SIGINFO
397	orr	w2, w2, #SA_NODEFER
398	bl	setsignal
399
400	mov	w0, #SIGUSR2
401	adr	x1, tickle_handler
402	mov	w2, #SA_SIGINFO
403	orr	w2, w2, #SA_NODEFER
404	bl	setsignal
405
406#ifdef SSVE
407	puts	"Streaming mode "
408	smstart_sm
409#endif
410
411	// Sanity-check and report the vector length
412
413	rdvl	x19, #8
414	cmp	x19, #128
415	b.lo	1f
416	cmp	x19, #2048
417	b.hi	1f
418	tst	x19, #(8 - 1)
419	b.eq	2f
420
4211:	puts	"Bad vector length: "
422	mov	x0, x19
423	bl	putdecn
424	b	.Labort
425
4262:	puts	"Vector length:\t"
427	mov	x0, x19
428	bl	putdec
429	puts	" bits\n"
430
431	// Obtain our PID, to ensure test pattern uniqueness between processes
432
433	mov	x8, #__NR_getpid
434	svc	#0
435	mov	x20, x0
436
437	puts	"PID:\t"
438	mov	x0, x20
439	bl	putdecn
440
441#ifdef SSVE
442	smstart_sm		// syscalls will have exited streaming mode
443#endif
444
445	mov	x22, #0		// generation number, increments per iteration
446.Ltest_loop:
447	rdvl	x0, #8
448	cmp	x0, x19
449	b.ne	vl_barf
450
451	mov	x21, #0		// Set up Z-regs & shadow with test pattern
4520:	mov	x0, x20
453	mov	x1, x21
454	and	x2, x22, #0xf
455	bl	setup_zreg
456	add	x21, x21, #1
457	cmp	x21, #NZR
458	b.lo	0b
459
460	mov	x0, x20		// Set up FFR & shadow with test pattern
461	mov	x1, #NZR + NPR
462	and	x2, x22, #0xf
463	bl	setup_ffr
464
4650:	mov	x0, x20		// Set up P-regs & shadow with test pattern
466	mov	x1, x21
467	and	x2, x22, #0xf
468	bl	setup_preg
469	add	x21, x21, #1
470	cmp	x21, #NZR + NPR
471	b.lo	0b
472
473// Can't do this when SVE state is volatile across SVC:
474//	mov	x8, #__NR_sched_yield	// Encourage preemption
475//	svc	#0
476
477	mov	x21, #0
4780:	mov	x0, x21
479	bl	check_zreg
480	add	x21, x21, #1
481	cmp	x21, #NZR
482	b.lo	0b
483
4840:	mov	x0, x21
485	bl	check_preg
486	add	x21, x21, #1
487	cmp	x21, #NZR + NPR
488	b.lo	0b
489
490	bl	check_ffr
491
492	add	x22, x22, #1
493	b	.Ltest_loop
494
495.Labort:
496	mov	x0, #0
497	mov	x1, #SIGABRT
498	mov	x8, #__NR_kill
499	svc	#0
500endfunction
501
502function barf
503// fpsimd.c acitivty log dump hack
504//	ldr	w0, =0xdeadc0de
505//	mov	w8, #__NR_exit
506//	svc	#0
507// end hack
508	mov	x10, x0	// expected data
509	mov	x11, x1	// actual data
510	mov	x12, x2	// data size
511
512	puts	"Mismatch: PID="
513	mov	x0, x20
514	bl	putdec
515	puts	", iteration="
516	mov	x0, x22
517	bl	putdec
518	puts	", reg="
519	mov	x0, x21
520	bl	putdecn
521	puts	"\tExpected ["
522	mov	x0, x10
523	mov	x1, x12
524	bl	dumphex
525	puts	"]\n\tGot      ["
526	mov	x0, x11
527	mov	x1, x12
528	bl	dumphex
529	puts	"]\n"
530
531	mov	x8, #__NR_getpid
532	svc	#0
533// fpsimd.c acitivty log dump hack
534//	ldr	w0, =0xdeadc0de
535//	mov	w8, #__NR_exit
536//	svc	#0
537// ^ end of hack
538	mov	x1, #SIGABRT
539	mov	x8, #__NR_kill
540	svc	#0
541//	mov	x8, #__NR_exit
542//	mov	x1, #1
543//	svc	#0
544endfunction
545
546function vl_barf
547	mov	x10, x0
548
549	puts	"Bad active VL: "
550	mov	x0, x10
551	bl	putdecn
552
553	mov	x8, #__NR_exit
554	mov	x1, #1
555	svc	#0
556endfunction
557