linux/tools/testing/selftests/arm64/fp/fpsimd-test.S
<<
>>
Prefs
   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