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// Any SVE register modified here can cause corruption in the main
138// thread -- but *only* the registers modified here.
139function irritator_handler
140	// Increment the irritation signal count (x23):
141	ldr	x0, [x2, #ucontext_regs + 8 * 23]
142	add	x0, x0, #1
143	str	x0, [x2, #ucontext_regs + 8 * 23]
144
145	// Corrupt some random V-regs
146	adr	x0, .text + (irritator_handler - .text) / 16 * 16
147	movi	v0.8b, #7
148	movi	v9.16b, #9
149	movi	v31.8b, #31
150
151	ret
152endfunction
153
154function tickle_handler
155	// Increment the signal count (x23):
156	ldr	x0, [x2, #ucontext_regs + 8 * 23]
157	add	x0, x0, #1
158	str	x0, [x2, #ucontext_regs + 8 * 23]
159
160	ret
161endfunction
162
163function terminate_handler
164	mov	w21, w0
165	mov	x20, x2
166
167	puts	"Terminated by signal "
168	mov	w0, w21
169	bl	putdec
170	puts	", no error, iterations="
171	ldr	x0, [x20, #ucontext_regs + 8 * 22]
172	bl	putdec
173	puts	", signals="
174	ldr	x0, [x20, #ucontext_regs + 8 * 23]
175	bl	putdecn
176
177	mov	x0, #0
178	mov	x8, #__NR_exit
179	svc	#0
180endfunction
181
182// w0: signal number
183// x1: sa_action
184// w2: sa_flags
185// Clobbers x0-x6,x8
186function setsignal
187	str	x30, [sp, #-((sa_sz + 15) / 16 * 16 + 16)]!
188
189	mov	w4, w0
190	mov	x5, x1
191	mov	w6, w2
192
193	add	x0, sp, #16
194	mov	x1, #sa_sz
195	bl	memclr
196
197	mov	w0, w4
198	add	x1, sp, #16
199	str	w6, [x1, #sa_flags]
200	str	x5, [x1, #sa_handler]
201	mov	x2, #0
202	mov	x3, #sa_mask_sz
203	mov	x8, #__NR_rt_sigaction
204	svc	#0
205
206	cbz	w0, 1f
207
208	puts	"sigaction failure\n"
209	b	.Labort
210
2111:	ldr	x30, [sp], #((sa_sz + 15) / 16 * 16 + 16)
212	ret
213endfunction
214
215// Main program entry point
216.globl _start
217function _start
218_start:
219	mov	x23, #0		// signal count
220
221	mov	w0, #SIGINT
222	adr	x1, terminate_handler
223	mov	w2, #SA_SIGINFO
224	bl	setsignal
225
226	mov	w0, #SIGTERM
227	adr	x1, terminate_handler
228	mov	w2, #SA_SIGINFO
229	bl	setsignal
230
231	mov	w0, #SIGUSR1
232	adr	x1, irritator_handler
233	mov	w2, #SA_SIGINFO
234	orr	w2, w2, #SA_NODEFER
235	bl	setsignal
236
237	mov	w0, #SIGUSR2
238	adr	x1, tickle_handler
239	mov	w2, #SA_SIGINFO
240	orr	w2, w2, #SA_NODEFER
241	bl	setsignal
242
243	// Sanity-check and report the vector length
244
245	mov	x19, #128
246	cmp	x19, #128
247	b.lo	1f
248	cmp	x19, #2048
249	b.hi	1f
250	tst	x19, #(8 - 1)
251	b.eq	2f
252
2531:	puts	"Bad vector length: "
254	mov	x0, x19
255	bl	putdecn
256	b	.Labort
257
2582:	puts	"Vector length:\t"
259	mov	x0, x19
260	bl	putdec
261	puts	" bits\n"
262
263	// Obtain our PID, to ensure test pattern uniqueness between processes
264
265	mov	x8, #__NR_getpid
266	svc	#0
267	mov	x20, x0
268
269	puts	"PID:\t"
270	mov	x0, x20
271	bl	putdecn
272
273	mov	x22, #0		// generation number, increments per iteration
274.Ltest_loop:
275
276	mov	x21, #0		// Set up V-regs & shadow with test pattern
2770:	mov	x0, x20
278	mov	x1, x21
279	and	x2, x22, #0xf
280	bl	setup_vreg
281	add	x21, x21, #1
282	cmp	x21, #NVR
283	b.lo	0b
284
285// Can't do this when SVE state is volatile across SVC:
286	mov	x8, #__NR_sched_yield	// Encourage preemption
287	svc	#0
288
289	mov	x21, #0
2900:	mov	x0, x21
291	bl	check_vreg
292	add	x21, x21, #1
293	cmp	x21, #NVR
294	b.lo	0b
295
296	add	x22, x22, #1
297	b	.Ltest_loop
298
299.Labort:
300	mov	x0, #0
301	mov	x1, #SIGABRT
302	mov	x8, #__NR_kill
303	svc	#0
304endfunction
305
306function barf
307	mov	x10, x0	// expected data
308	mov	x11, x1	// actual data
309	mov	x12, x2	// data size
310
311	puts	"Mismatch: PID="
312	mov	x0, x20
313	bl	putdec
314	puts	", iteration="
315	mov	x0, x22
316	bl	putdec
317	puts	", reg="
318	mov	x0, x21
319	bl	putdecn
320	puts	"\tExpected ["
321	mov	x0, x10
322	mov	x1, x12
323	bl	dumphex
324	puts	"]\n\tGot      ["
325	mov	x0, x11
326	mov	x1, x12
327	bl	dumphex
328	puts	"]\n"
329
330	mov	x8, #__NR_exit
331	mov	x1, #1
332	svc	#0
333endfunction
334