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