mirror of
https://github.com/torvalds/linux.git
synced 2026-04-19 23:34:00 -04:00
On failure we log the actual and expected value of the register we detect a mismatch in. For SME one obvious potential source of corruption would be if we had corrupted SVCR since changes in streaming mode will reset the register values, log the value to aid in understanding issues. Signed-off-by: Mark Brown <broonie@kernel.org> Link: https://lore.kernel.org/r/20231205-arm64-kselftest-log-svcr-v1-1-b77abd9ee7f3@kernel.org Signed-off-by: Will Deacon <will@kernel.org>
322 lines
5.5 KiB
ArmAsm
322 lines
5.5 KiB
ArmAsm
// SPDX-License-Identifier: GPL-2.0-only
|
|
// Copyright (C) 2021-2 ARM Limited.
|
|
// Original author: Mark Brown <broonie@kernel.org>
|
|
//
|
|
// Scalable Matrix Extension ZT context switch test
|
|
// Repeatedly writes unique test patterns into ZT0
|
|
// and reads them back to verify integrity.
|
|
|
|
#include <asm/unistd.h>
|
|
#include "assembler.h"
|
|
#include "asm-offsets.h"
|
|
#include "sme-inst.h"
|
|
|
|
.arch_extension sve
|
|
|
|
#define ZT_SZ 512
|
|
#define ZT_B (ZT_SZ / 8)
|
|
|
|
// Declare some storage space to shadow ZT register contents and a
|
|
// scratch buffer.
|
|
.pushsection .text
|
|
.data
|
|
.align 4
|
|
ztref:
|
|
.space ZT_B
|
|
scratch:
|
|
.space ZT_B
|
|
.popsection
|
|
|
|
|
|
// Generate a test pattern for storage in ZT
|
|
// x0: pid
|
|
// x1: generation
|
|
|
|
// These values are used to construct a 32-bit pattern that is repeated in the
|
|
// scratch buffer as many times as will fit:
|
|
// bits 31:24 generation number (increments once per test_loop)
|
|
// bits 23: 8 pid
|
|
// bits 7: 0 32-bit lane index
|
|
|
|
function pattern
|
|
mov w3, wzr
|
|
bfi w3, w0, #8, #16 // PID
|
|
bfi w3, w1, #24, #8 // Generation
|
|
|
|
ldr x0, =scratch
|
|
mov w1, #ZT_B / 4
|
|
|
|
0: str w3, [x0], #4
|
|
add w3, w3, #1 // Lane
|
|
subs w1, w1, #1
|
|
b.ne 0b
|
|
|
|
ret
|
|
endfunction
|
|
|
|
// Set up test pattern in a ZT horizontal vector
|
|
// x0: pid
|
|
// x1: generation
|
|
function setup_zt
|
|
mov x4, x30
|
|
|
|
bl pattern // Get pattern in scratch buffer
|
|
ldr x0, =ztref
|
|
ldr x1, =scratch
|
|
mov x2, #ZT_B
|
|
bl memcpy
|
|
|
|
ldr x0, =ztref
|
|
_ldr_zt 0 // load zt0 from pointer x0
|
|
|
|
ret x4
|
|
endfunction
|
|
|
|
// Trivial memory compare: compare x2 bytes starting at address x0 with
|
|
// bytes starting at address x1.
|
|
// Returns only if all bytes match; otherwise, the program is aborted.
|
|
// Clobbers x0-x5.
|
|
function memcmp
|
|
cbz x2, 2f
|
|
|
|
stp x0, x1, [sp, #-0x20]!
|
|
str x2, [sp, #0x10]
|
|
|
|
mov x5, #0
|
|
0: ldrb w3, [x0, x5]
|
|
ldrb w4, [x1, x5]
|
|
add x5, x5, #1
|
|
cmp w3, w4
|
|
b.ne 1f
|
|
subs x2, x2, #1
|
|
b.ne 0b
|
|
|
|
1: ldr x2, [sp, #0x10]
|
|
ldp x0, x1, [sp], #0x20
|
|
b.ne barf
|
|
|
|
2: ret
|
|
endfunction
|
|
|
|
// Verify that a ZT vector matches its shadow in memory, else abort
|
|
// Clobbers x0-x3
|
|
function check_zt
|
|
mov x3, x30
|
|
|
|
ldr x0, =scratch // Poison scratch
|
|
mov x1, #ZT_B
|
|
bl memfill_ae
|
|
|
|
ldr x0, =scratch
|
|
_str_zt 0
|
|
|
|
ldr x0, =ztref
|
|
ldr x1, =scratch
|
|
mov x2, #ZT_B
|
|
mov x30, x3
|
|
b memcmp
|
|
endfunction
|
|
|
|
// Any SME register modified here can cause corruption in the main
|
|
// thread -- but *only* the locations modified here.
|
|
function irritator_handler
|
|
// Increment the irritation signal count (x23):
|
|
ldr x0, [x2, #ucontext_regs + 8 * 23]
|
|
add x0, x0, #1
|
|
str x0, [x2, #ucontext_regs + 8 * 23]
|
|
|
|
// Corrupt some random ZT data
|
|
#if 0
|
|
adr x0, .text + (irritator_handler - .text) / 16 * 16
|
|
movi v0.8b, #1
|
|
movi v9.16b, #2
|
|
movi v31.8b, #3
|
|
#endif
|
|
|
|
ret
|
|
endfunction
|
|
|
|
function tickle_handler
|
|
// Increment the signal count (x23):
|
|
ldr x0, [x2, #ucontext_regs + 8 * 23]
|
|
add x0, x0, #1
|
|
str x0, [x2, #ucontext_regs + 8 * 23]
|
|
|
|
ret
|
|
endfunction
|
|
|
|
function terminate_handler
|
|
mov w21, w0
|
|
mov x20, x2
|
|
|
|
puts "Terminated by signal "
|
|
mov w0, w21
|
|
bl putdec
|
|
puts ", no error, iterations="
|
|
ldr x0, [x20, #ucontext_regs + 8 * 22]
|
|
bl putdec
|
|
puts ", signals="
|
|
ldr x0, [x20, #ucontext_regs + 8 * 23]
|
|
bl putdecn
|
|
|
|
mov x0, #0
|
|
mov x8, #__NR_exit
|
|
svc #0
|
|
endfunction
|
|
|
|
// w0: signal number
|
|
// x1: sa_action
|
|
// w2: sa_flags
|
|
// Clobbers x0-x6,x8
|
|
function setsignal
|
|
str x30, [sp, #-((sa_sz + 15) / 16 * 16 + 16)]!
|
|
|
|
mov w4, w0
|
|
mov x5, x1
|
|
mov w6, w2
|
|
|
|
add x0, sp, #16
|
|
mov x1, #sa_sz
|
|
bl memclr
|
|
|
|
mov w0, w4
|
|
add x1, sp, #16
|
|
str w6, [x1, #sa_flags]
|
|
str x5, [x1, #sa_handler]
|
|
mov x2, #0
|
|
mov x3, #sa_mask_sz
|
|
mov x8, #__NR_rt_sigaction
|
|
svc #0
|
|
|
|
cbz w0, 1f
|
|
|
|
puts "sigaction failure\n"
|
|
b .Labort
|
|
|
|
1: ldr x30, [sp], #((sa_sz + 15) / 16 * 16 + 16)
|
|
ret
|
|
endfunction
|
|
|
|
// Main program entry point
|
|
.globl _start
|
|
function _start
|
|
mov x23, #0 // signal count
|
|
|
|
mov w0, #SIGINT
|
|
adr x1, terminate_handler
|
|
mov w2, #SA_SIGINFO
|
|
bl setsignal
|
|
|
|
mov w0, #SIGTERM
|
|
adr x1, terminate_handler
|
|
mov w2, #SA_SIGINFO
|
|
bl setsignal
|
|
|
|
mov w0, #SIGUSR1
|
|
adr x1, irritator_handler
|
|
mov w2, #SA_SIGINFO
|
|
orr w2, w2, #SA_NODEFER
|
|
bl setsignal
|
|
|
|
mov w0, #SIGUSR2
|
|
adr x1, tickle_handler
|
|
mov w2, #SA_SIGINFO
|
|
orr w2, w2, #SA_NODEFER
|
|
bl setsignal
|
|
|
|
smstart_za
|
|
|
|
// Obtain our PID, to ensure test pattern uniqueness between processes
|
|
mov x8, #__NR_getpid
|
|
svc #0
|
|
mov x20, x0
|
|
|
|
puts "PID:\t"
|
|
mov x0, x20
|
|
bl putdecn
|
|
|
|
mov x22, #0 // generation number, increments per iteration
|
|
.Ltest_loop:
|
|
mov x0, x20
|
|
mov x1, x22
|
|
bl setup_zt
|
|
|
|
mov x8, #__NR_sched_yield // Encourage preemption
|
|
svc #0
|
|
|
|
mrs x0, S3_3_C4_C2_2 // SVCR should have ZA=1,SM=0
|
|
and x1, x0, #3
|
|
cmp x1, #2
|
|
b.ne svcr_barf
|
|
|
|
bl check_zt
|
|
|
|
add x22, x22, #1 // Everything still working
|
|
b .Ltest_loop
|
|
|
|
.Labort:
|
|
mov x0, #0
|
|
mov x1, #SIGABRT
|
|
mov x8, #__NR_kill
|
|
svc #0
|
|
endfunction
|
|
|
|
function barf
|
|
// fpsimd.c acitivty log dump hack
|
|
// ldr w0, =0xdeadc0de
|
|
// mov w8, #__NR_exit
|
|
// svc #0
|
|
// end hack
|
|
|
|
mrs x13, S3_3_C4_C2_2
|
|
smstop
|
|
mov x10, x0 // expected data
|
|
mov x11, x1 // actual data
|
|
mov x12, x2 // data size
|
|
|
|
puts "Mismatch: PID="
|
|
mov x0, x20
|
|
bl putdec
|
|
puts ", iteration="
|
|
mov x0, x22
|
|
bl putdec
|
|
puts "\tExpected ["
|
|
mov x0, x10
|
|
mov x1, x12
|
|
bl dumphex
|
|
puts "]\n\tGot ["
|
|
mov x0, x11
|
|
mov x1, x12
|
|
bl dumphex
|
|
puts "]\n"
|
|
puts "\tSVCR: "
|
|
mov x0, x13
|
|
bl putdecn
|
|
|
|
mov x8, #__NR_getpid
|
|
svc #0
|
|
// fpsimd.c acitivty log dump hack
|
|
// ldr w0, =0xdeadc0de
|
|
// mov w8, #__NR_exit
|
|
// svc #0
|
|
// ^ end of hack
|
|
mov x1, #SIGABRT
|
|
mov x8, #__NR_kill
|
|
svc #0
|
|
// mov x8, #__NR_exit
|
|
// mov x1, #1
|
|
// svc #0
|
|
endfunction
|
|
|
|
function svcr_barf
|
|
mov x10, x0
|
|
|
|
puts "Bad SVCR: "
|
|
mov x0, x10
|
|
bl putdecn
|
|
|
|
mov x8, #__NR_exit
|
|
mov x1, #1
|
|
svc #0
|
|
endfunction
|