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 483