15e992c63SMark Brown// SPDX-License-Identifier: GPL-2.0-only 25e992c63SMark Brown// Copyright (C) 2015-2019 ARM Limited. 35e992c63SMark Brown// Original author: Dave Martin <Dave.Martin@arm.com> 45e992c63SMark Brown// 55e992c63SMark Brown// Simple FPSIMD context switch test 65e992c63SMark Brown// Repeatedly writes unique test patterns into each FPSIMD register 75e992c63SMark Brown// and reads them back to verify integrity. 85e992c63SMark Brown// 95e992c63SMark Brown// for x in `seq 1 NR_CPUS`; do fpsimd-test & pids=$pids\ $! ; done 105e992c63SMark Brown// (leave it running for as long as you want...) 115e992c63SMark Brown// kill $pids 125e992c63SMark Brown 135e992c63SMark Brown#include <asm/unistd.h> 145e992c63SMark Brown#include "assembler.h" 155e992c63SMark Brown#include "asm-offsets.h" 165e992c63SMark Brown 175e992c63SMark Brown#define NVR 32 185e992c63SMark Brown#define MAXVL_B (128 / 8) 195e992c63SMark Brown 205e992c63SMark Brown.macro _vldr Vn:req, Xt:req 215e992c63SMark Brown ld1 {v\Vn\().2d}, [x\Xt] 225e992c63SMark Brown.endm 235e992c63SMark Brown 245e992c63SMark Brown.macro _vstr Vn:req, Xt:req 255e992c63SMark Brown st1 {v\Vn\().2d}, [x\Xt] 265e992c63SMark Brown.endm 275e992c63SMark Brown 285e992c63SMark Brown// Generate accessor functions to read/write programmatically selected 295e992c63SMark Brown// FPSIMD registers. 305e992c63SMark Brown// x0 is the register index to access 315e992c63SMark Brown// x1 is the memory address to read from (getv,setp) or store to (setv,setp) 325e992c63SMark Brown// All clobber x0-x2 335e992c63SMark Browndefine_accessor setv, NVR, _vldr 345e992c63SMark Browndefine_accessor getv, NVR, _vstr 355e992c63SMark Brown 365e992c63SMark Brown// Declare some storate space to shadow the SVE register contents: 375e992c63SMark Brown.pushsection .text 385e992c63SMark Brown.data 395e992c63SMark Brown.align 4 405e992c63SMark Brownvref: 415e992c63SMark Brown .space MAXVL_B * NVR 425e992c63SMark Brownscratch: 435e992c63SMark Brown .space MAXVL_B 445e992c63SMark Brown.popsection 455e992c63SMark Brown 465e992c63SMark Brown// Generate a test pattern for storage in SVE registers 475e992c63SMark Brown// x0: pid (16 bits) 485e992c63SMark Brown// x1: register number (6 bits) 495e992c63SMark Brown// x2: generation (4 bits) 505e992c63SMark Brownfunction pattern 515e992c63SMark Brown orr w1, w0, w1, lsl #16 525e992c63SMark Brown orr w2, w1, w2, lsl #28 535e992c63SMark Brown 545e992c63SMark Brown ldr x0, =scratch 555e992c63SMark Brown mov w1, #MAXVL_B / 4 565e992c63SMark Brown 575e992c63SMark Brown0: str w2, [x0], #4 585e992c63SMark Brown add w2, w2, #(1 << 22) 595e992c63SMark Brown subs w1, w1, #1 605e992c63SMark Brown bne 0b 615e992c63SMark Brown 625e992c63SMark Brown ret 635e992c63SMark Brownendfunction 645e992c63SMark Brown 655e992c63SMark Brown// Get the address of shadow data for FPSIMD V-register V<xn> 665e992c63SMark Brown.macro _adrv xd, xn, nrtmp 675e992c63SMark Brown ldr \xd, =vref 685e992c63SMark Brown mov x\nrtmp, #16 695e992c63SMark Brown madd \xd, x\nrtmp, \xn, \xd 705e992c63SMark Brown.endm 715e992c63SMark Brown 725e992c63SMark Brown// Set up test pattern in a FPSIMD V-register 735e992c63SMark Brown// x0: pid 745e992c63SMark Brown// x1: register number 755e992c63SMark Brown// x2: generation 765e992c63SMark Brownfunction setup_vreg 775e992c63SMark Brown mov x4, x30 785e992c63SMark Brown 795e992c63SMark Brown mov x6, x1 805e992c63SMark Brown bl pattern 815e992c63SMark Brown _adrv x0, x6, 2 825e992c63SMark Brown mov x5, x0 835e992c63SMark Brown ldr x1, =scratch 845e992c63SMark Brown bl memcpy 855e992c63SMark Brown 865e992c63SMark Brown mov x0, x6 875e992c63SMark Brown mov x1, x5 885e992c63SMark Brown bl setv 895e992c63SMark Brown 905e992c63SMark Brown ret x4 915e992c63SMark Brownendfunction 925e992c63SMark Brown 935e992c63SMark Brown// Trivial memory compare: compare x2 bytes starting at address x0 with 945e992c63SMark Brown// bytes starting at address x1. 955e992c63SMark Brown// Returns only if all bytes match; otherwise, the program is aborted. 965e992c63SMark Brown// Clobbers x0-x5. 975e992c63SMark Brownfunction memcmp 985e992c63SMark Brown cbz x2, 1f 995e992c63SMark Brown 1005e992c63SMark Brown mov x5, #0 1015e992c63SMark Brown0: ldrb w3, [x0, x5] 1025e992c63SMark Brown ldrb w4, [x1, x5] 1035e992c63SMark Brown add x5, x5, #1 1045e992c63SMark Brown cmp w3, w4 1055e992c63SMark Brown b.ne barf 1065e992c63SMark Brown subs x2, x2, #1 1075e992c63SMark Brown b.ne 0b 1085e992c63SMark Brown 1095e992c63SMark Brown1: ret 1105e992c63SMark Brownendfunction 1115e992c63SMark Brown 1125e992c63SMark Brown// Verify that a FPSIMD V-register matches its shadow in memory, else abort 1135e992c63SMark Brown// x0: reg number 1145e992c63SMark Brown// Clobbers x0-x5. 1155e992c63SMark Brownfunction check_vreg 1165e992c63SMark Brown mov x3, x30 1175e992c63SMark Brown 1185e992c63SMark Brown _adrv x5, x0, 6 1195e992c63SMark Brown mov x4, x0 1205e992c63SMark Brown ldr x7, =scratch 1215e992c63SMark Brown 1225e992c63SMark Brown mov x0, x7 1235e992c63SMark Brown mov x1, x6 1245e992c63SMark Brown bl memfill_ae 1255e992c63SMark Brown 1265e992c63SMark Brown mov x0, x4 1275e992c63SMark Brown mov x1, x7 1285e992c63SMark Brown bl getv 1295e992c63SMark Brown 1305e992c63SMark Brown mov x0, x5 1315e992c63SMark Brown mov x1, x7 1325e992c63SMark Brown mov x2, x6 1335e992c63SMark Brown mov x30, x3 1345e992c63SMark Brown b memcmp 1355e992c63SMark Brownendfunction 1365e992c63SMark Brown 1375e992c63SMark Brown// Any SVE register modified here can cause corruption in the main 1385e992c63SMark Brown// thread -- but *only* the registers modified here. 1395e992c63SMark Brownfunction irritator_handler 1405e992c63SMark Brown // Increment the irritation signal count (x23): 1415e992c63SMark Brown ldr x0, [x2, #ucontext_regs + 8 * 23] 1425e992c63SMark Brown add x0, x0, #1 1435e992c63SMark Brown str x0, [x2, #ucontext_regs + 8 * 23] 1445e992c63SMark Brown 1455e992c63SMark Brown // Corrupt some random V-regs 1465e992c63SMark Brown adr x0, .text + (irritator_handler - .text) / 16 * 16 1475e992c63SMark Brown movi v0.8b, #7 1485e992c63SMark Brown movi v9.16b, #9 1495e992c63SMark Brown movi v31.8b, #31 1505e992c63SMark Brown 1515e992c63SMark Brown ret 1525e992c63SMark Brownendfunction 1535e992c63SMark Brown 15405a5980fSMark Brownfunction tickle_handler 15505a5980fSMark Brown // Increment the signal count (x23): 15605a5980fSMark Brown ldr x0, [x2, #ucontext_regs + 8 * 23] 15705a5980fSMark Brown add x0, x0, #1 15805a5980fSMark Brown str x0, [x2, #ucontext_regs + 8 * 23] 15905a5980fSMark Brown 16005a5980fSMark Brown ret 16105a5980fSMark Brownendfunction 16205a5980fSMark Brown 1635e992c63SMark Brownfunction terminate_handler 1645e992c63SMark Brown mov w21, w0 1655e992c63SMark Brown mov x20, x2 1665e992c63SMark Brown 1675e992c63SMark Brown puts "Terminated by signal " 1685e992c63SMark Brown mov w0, w21 1695e992c63SMark Brown bl putdec 1705e992c63SMark Brown puts ", no error, iterations=" 1715e992c63SMark Brown ldr x0, [x20, #ucontext_regs + 8 * 22] 1725e992c63SMark Brown bl putdec 1735e992c63SMark Brown puts ", signals=" 1745e992c63SMark Brown ldr x0, [x20, #ucontext_regs + 8 * 23] 1755e992c63SMark Brown bl putdecn 1765e992c63SMark Brown 1775e992c63SMark Brown mov x0, #0 1785e992c63SMark Brown mov x8, #__NR_exit 1795e992c63SMark Brown svc #0 1805e992c63SMark Brownendfunction 1815e992c63SMark Brown 1825e992c63SMark Brown// w0: signal number 1835e992c63SMark Brown// x1: sa_action 1845e992c63SMark Brown// w2: sa_flags 1855e992c63SMark Brown// Clobbers x0-x6,x8 1865e992c63SMark Brownfunction setsignal 1875e992c63SMark Brown str x30, [sp, #-((sa_sz + 15) / 16 * 16 + 16)]! 1885e992c63SMark Brown 1895e992c63SMark Brown mov w4, w0 1905e992c63SMark Brown mov x5, x1 1915e992c63SMark Brown mov w6, w2 1925e992c63SMark Brown 1935e992c63SMark Brown add x0, sp, #16 1945e992c63SMark Brown mov x1, #sa_sz 1955e992c63SMark Brown bl memclr 1965e992c63SMark Brown 1975e992c63SMark Brown mov w0, w4 1985e992c63SMark Brown add x1, sp, #16 1995e992c63SMark Brown str w6, [x1, #sa_flags] 2005e992c63SMark Brown str x5, [x1, #sa_handler] 2015e992c63SMark Brown mov x2, #0 2025e992c63SMark Brown mov x3, #sa_mask_sz 2035e992c63SMark Brown mov x8, #__NR_rt_sigaction 2045e992c63SMark Brown svc #0 2055e992c63SMark Brown 2065e992c63SMark Brown cbz w0, 1f 2075e992c63SMark Brown 2085e992c63SMark Brown puts "sigaction failure\n" 2095e992c63SMark Brown b .Labort 2105e992c63SMark Brown 2115e992c63SMark Brown1: ldr x30, [sp], #((sa_sz + 15) / 16 * 16 + 16) 2125e992c63SMark Brown ret 2135e992c63SMark Brownendfunction 2145e992c63SMark Brown 2155e992c63SMark Brown// Main program entry point 2165e992c63SMark Brown.globl _start 2175e992c63SMark Brownfunction _start 218*d47d8a5eSMark Brown mov x23, #0 // signal count 219*d47d8a5eSMark Brown 220*d47d8a5eSMark Brown mov w0, #SIGINT 221*d47d8a5eSMark Brown adr x1, terminate_handler 222*d47d8a5eSMark Brown mov w2, #SA_SIGINFO 223*d47d8a5eSMark Brown bl setsignal 224*d47d8a5eSMark Brown 225*d47d8a5eSMark Brown mov w0, #SIGTERM 226*d47d8a5eSMark Brown adr x1, terminate_handler 227*d47d8a5eSMark Brown mov w2, #SA_SIGINFO 228*d47d8a5eSMark Brown bl setsignal 229*d47d8a5eSMark Brown 230*d47d8a5eSMark Brown mov w0, #SIGUSR1 231*d47d8a5eSMark Brown adr x1, irritator_handler 232*d47d8a5eSMark Brown mov w2, #SA_SIGINFO 233*d47d8a5eSMark Brown orr w2, w2, #SA_NODEFER 234*d47d8a5eSMark Brown bl setsignal 235*d47d8a5eSMark Brown 236*d47d8a5eSMark Brown mov w0, #SIGUSR2 237*d47d8a5eSMark Brown adr x1, tickle_handler 238*d47d8a5eSMark Brown mov w2, #SA_SIGINFO 239*d47d8a5eSMark Brown orr w2, w2, #SA_NODEFER 240*d47d8a5eSMark Brown bl setsignal 241*d47d8a5eSMark Brown 2425e992c63SMark Brown // Sanity-check and report the vector length 2435e992c63SMark Brown 2445e992c63SMark Brown mov x19, #128 2455e992c63SMark Brown cmp x19, #128 2465e992c63SMark Brown b.lo 1f 2475e992c63SMark Brown cmp x19, #2048 2485e992c63SMark Brown b.hi 1f 2495e992c63SMark Brown tst x19, #(8 - 1) 2505e992c63SMark Brown b.eq 2f 2515e992c63SMark Brown 2525e992c63SMark Brown1: puts "Bad vector length: " 2535e992c63SMark Brown mov x0, x19 2545e992c63SMark Brown bl putdecn 2555e992c63SMark Brown b .Labort 2565e992c63SMark Brown 2575e992c63SMark Brown2: puts "Vector length:\t" 2585e992c63SMark Brown mov x0, x19 2595e992c63SMark Brown bl putdec 2605e992c63SMark Brown puts " bits\n" 2615e992c63SMark Brown 2625e992c63SMark Brown // Obtain our PID, to ensure test pattern uniqueness between processes 2635e992c63SMark Brown 2645e992c63SMark Brown mov x8, #__NR_getpid 2655e992c63SMark Brown svc #0 2665e992c63SMark Brown mov x20, x0 2675e992c63SMark Brown 2685e992c63SMark Brown puts "PID:\t" 2695e992c63SMark Brown mov x0, x20 2705e992c63SMark Brown bl putdecn 2715e992c63SMark Brown 2725e992c63SMark Brown mov x22, #0 // generation number, increments per iteration 2735e992c63SMark Brown.Ltest_loop: 2745e992c63SMark Brown 2755e992c63SMark Brown mov x21, #0 // Set up V-regs & shadow with test pattern 2765e992c63SMark Brown0: mov x0, x20 2775e992c63SMark Brown mov x1, x21 2785e992c63SMark Brown and x2, x22, #0xf 2795e992c63SMark Brown bl setup_vreg 2805e992c63SMark Brown add x21, x21, #1 2815e992c63SMark Brown cmp x21, #NVR 2825e992c63SMark Brown b.lo 0b 2835e992c63SMark Brown 2845e992c63SMark Brown// Can't do this when SVE state is volatile across SVC: 2855e992c63SMark Brown mov x8, #__NR_sched_yield // Encourage preemption 2865e992c63SMark Brown svc #0 2875e992c63SMark Brown 2885e992c63SMark Brown mov x21, #0 2895e992c63SMark Brown0: mov x0, x21 2905e992c63SMark Brown bl check_vreg 2915e992c63SMark Brown add x21, x21, #1 2925e992c63SMark Brown cmp x21, #NVR 2935e992c63SMark Brown b.lo 0b 2945e992c63SMark Brown 2955e992c63SMark Brown add x22, x22, #1 2965e992c63SMark Brown b .Ltest_loop 2975e992c63SMark Brown 2985e992c63SMark Brown.Labort: 2995e992c63SMark Brown mov x0, #0 3005e992c63SMark Brown mov x1, #SIGABRT 3015e992c63SMark Brown mov x8, #__NR_kill 3025e992c63SMark Brown svc #0 3035e992c63SMark Brownendfunction 3045e992c63SMark Brown 3055e992c63SMark Brownfunction barf 3065e992c63SMark Brown mov x10, x0 // expected data 3075e992c63SMark Brown mov x11, x1 // actual data 3085e992c63SMark Brown mov x12, x2 // data size 3095e992c63SMark Brown 3103a57a643SMark Brown puts "Mismatch: PID=" 3115e992c63SMark Brown mov x0, x20 3125e992c63SMark Brown bl putdec 3135e992c63SMark Brown puts ", iteration=" 3145e992c63SMark Brown mov x0, x22 3155e992c63SMark Brown bl putdec 3165e992c63SMark Brown puts ", reg=" 3175e992c63SMark Brown mov x0, x21 3185e992c63SMark Brown bl putdecn 3195e992c63SMark Brown puts "\tExpected [" 3205e992c63SMark Brown mov x0, x10 3215e992c63SMark Brown mov x1, x12 3225e992c63SMark Brown bl dumphex 3235e992c63SMark Brown puts "]\n\tGot [" 3245e992c63SMark Brown mov x0, x11 3255e992c63SMark Brown mov x1, x12 3265e992c63SMark Brown bl dumphex 3275e992c63SMark Brown puts "]\n" 3285e992c63SMark Brown 3295e992c63SMark Brown mov x8, #__NR_exit 3305e992c63SMark Brown mov x1, #1 3315e992c63SMark Brown svc #0 3325e992c63SMark Brownendfunction 333