1 // SPDX-License-Identifier: GPL-2.0-only
2 // Copyright (C) 2015-2019 ARM Limited.
3 // Original author: Dave Martin <Dave.Martin@arm.com>
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.
9 // for x in `seq 1 NR_CPUS`; do sve-test & pids=$pids\ $! ; done
10 // (leave it running for as long as you want...)
13 #include <asm/unistd.h>
14 #include "assembler.h"
15 #include "asm-offsets.h"
19 #define MAXVL_B (2048 / 8)
23 .macro _sve_ldr_v zt, xn
27 .macro _sve_str_v zt, xn
31 .macro _sve_ldr_p pt, xn
35 .macro _sve_str_p pt, xn
39 // Generate accessor functions to read/write programmatically selected
41 // x0 is the register index to access
42 // x1 is the memory address to read from (getz,setp) or store to (setz,setp)
44 define_accessor setz, NZR, _sve_ldr_v
45 define_accessor getz, NZR, _sve_str_v
46 define_accessor setp, NPR, _sve_ldr_p
47 define_accessor getp, NPR, _sve_str_p
49 // Print a single character x0 to stdout
54 mov x0, #1 // STDOUT_FILENO
64 // Print a NUL-terminated string starting at address x0 to stdout
75 1: mov w0, #1 // STDOUT_FILENO
82 // Utility macro to print a literal string
85 .pushsection .rodata.str1.1, "aMS", 1
86 .L__puts_literal\@: .string "\string"
89 ldr x0, =.L__puts_literal\@
93 // Print an unsigned decimal number x0 to stdout
97 str x30, [sp, #-32]! // Result can't be > 20 digits
100 strb w2, [x1, #-1]! // Write the NUL terminator
103 0: udiv x3, x0, x2 // div-mod loop to generate the digits
112 mov w0, #'0' // Print "0" for 0, not ""
122 // Print an unsigned decimal number x0 to stdout, followed by a newline
136 str x30, [sp, #-0x10]!
144 // fall through to puthexnibble
147 function puthexnibble
151 add w0, w0, #'a' - ('9' + 1)
156 // x0=data in, x1=size in, clobbers x0-x5,x8
158 str x30, [sp, #-0x10]!
169 1: ldr x30, [sp], #0x10
173 // Declare some storate space to shadow the SVE register contents:
180 .space MAXVL_B / 8 * NPR
187 // Trivial memory copy: copy x2 bytes, starting at address x1, to address x0.
199 // Generate a test pattern for storage in SVE registers
201 // x1: register number (6 bits)
202 // x2: generation (4 bits)
204 // These values are used to constuct a 32-bit pattern that is repeated in the
205 // scratch buffer as many times as will fit:
206 // bits 31:28 generation number (increments once per test_loop)
207 // bits 27:22 32-bit lane index
208 // bits 21:16 register number
212 orr w1, w0, w1, lsl #16
213 orr w2, w1, w2, lsl #28
219 add w2, w2, #(1 << 22)
226 // Get the address of shadow data for SVE Z-register Z<xn>
227 .macro _adrz xd, xn, nrtmp
230 madd \xd, x\nrtmp, \xn, \xd
233 // Get the address of shadow data for SVE P-register P<xn - NZR>
234 .macro _adrp xd, xn, nrtmp
237 lsr x\nrtmp, x\nrtmp, #3
239 madd \xd, x\nrtmp, \xn, \xd
242 // Set up test pattern in a SVE Z-register
244 // x1: register number
263 // Set up test pattern in a SVE P-register
265 // x1: register number
284 // Set up test pattern in the FFR
287 // Beware: corrupts P0.
307 // Fill x1 bytes starting at x0 with 0xae (for canary purposes)
314 // Fill x1 bytes starting at x0 with 0.
319 // fall through to memfill
321 // Trivial memory fill: fill x1 bytes starting at address x0 with byte w2
334 // Trivial memory compare: compare x2 bytes starting at address x0 with
335 // bytes starting at address x1.
336 // Returns only if all bytes match; otherwise, the program is aborted.
341 stp x0, x1, [sp, #-0x20]!
353 1: ldr x2, [sp, #0x10]
354 ldp x0, x1, [sp], #0x20
360 // Verify that a SVE Z-register matches its shadow in memory, else abort
385 // Verify that a SVE P-register matches its shadow in memory, else abort
410 // Verify that the FFR matches its shadow in memory, else abort
411 // Beware -- corrupts P0.
436 // Any SVE register modified here can cause corruption in the main
437 // thread -- but *only* the registers modified here.
438 function irritator_handler
439 // Increment the irritation signal count (x23):
440 ldr x0, [x2, #ucontext_regs + 8 * 23]
442 str x0, [x2, #ucontext_regs + 8 * 23]
444 // Corrupt some random Z-regs
445 adr x0, .text + (irritator_handler - .text) / 16 * 16
457 function terminate_handler
461 puts "Terminated by signal "
464 puts ", no error, iterations="
465 ldr x0, [x20, #ucontext_regs + 8 * 22]
468 ldr x0, [x20, #ucontext_regs + 8 * 23]
481 str x30, [sp, #-((sa_sz + 15) / 16 * 16 + 16)]!
493 str w6, [x1, #sa_flags]
494 str x5, [x1, #sa_handler]
497 mov x8, #__NR_rt_sigaction
502 puts "sigaction failure\n"
505 1: ldr x30, [sp], #((sa_sz + 15) / 16 * 16 + 16)
509 // Main program entry point
513 // Sanity-check and report the vector length
523 1: puts "Bad vector length: "
528 2: puts "Vector length:\t"
533 // Obtain our PID, to ensure test pattern uniqueness between processes
543 mov x23, #0 // Irritation signal count
546 adr x1, terminate_handler
551 adr x1, terminate_handler
556 adr x1, irritator_handler
558 orr w2, w2, #SA_NODEFER
561 mov x22, #0 // generation number, increments per iteration
567 mov x21, #0 // Set up Z-regs & shadow with test pattern
576 mov x0, x20 // Set up FFR & shadow with test pattern
581 0: mov x0, x20 // Set up P-regs & shadow with test pattern
589 // Can't do this when SVE state is volatile across SVC:
590 // mov x8, #__NR_sched_yield // Encourage preemption
619 // fpsimd.c acitivty log dump hack
620 // ldr w0, =0xdeadc0de
621 // mov w8, #__NR_exit
624 mov x10, x0 // expected data
625 mov x11, x1 // actual data
626 mov x12, x2 // data size
628 puts "Mistatch: PID="
649 // fpsimd.c acitivty log dump hack
650 // ldr w0, =0xdeadc0de
651 // mov w8, #__NR_exit
657 // mov x8, #__NR_exit
665 puts "Bad active VL: "