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