Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

selftests/arm64: Add a testcase for handling of ZA on clone()

Add a small testcase that attempts to do a clone() with ZA enabled and
verifies that it remains enabled with the same contents. We only check
one word in one horizontal vector of ZA since there's already other tests
that check for data corruption more broadly, we're just looking to make
sure that ZA is still enabled and it looks like the data got copied.

Signed-off-by: Mark Brown <broonie@kernel.org>
Link: https://lore.kernel.org/r/20220419112247.711548-40-broonie@kernel.org
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>

authored by

Mark Brown and committed by
Catalin Marinas
212b0426 43e3f855

+226 -1
+1
tools/testing/selftests/arm64/fp/.gitignore
··· 8 8 ssve-test 9 9 vec-syscfg 10 10 vlset 11 + za-fork 11 12 za-ptrace 12 13 za-test
+8 -1
tools/testing/selftests/arm64/fp/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 3 3 CFLAGS += -I../../../../../usr/include/ 4 - TEST_GEN_PROGS := sve-ptrace sve-probe-vls vec-syscfg za-ptrace 4 + TEST_GEN_PROGS := sve-ptrace sve-probe-vls vec-syscfg za-fork za-ptrace 5 5 TEST_PROGS_EXTENDED := fp-pidbench fpsimd-test fpsimd-stress \ 6 6 rdvl-sme rdvl-sve \ 7 7 sve-test sve-stress \ ··· 11 11 12 12 all: $(TEST_GEN_PROGS) $(TEST_PROGS_EXTENDED) 13 13 14 + # Build with nolibc to avoid effects due to libc's clone() support 14 15 fp-pidbench: fp-pidbench.S asm-utils.o 15 16 $(CC) -nostdlib $^ -o $@ 16 17 fpsimd-test: fpsimd-test.o asm-utils.o ··· 26 25 $(CC) -DSSVE -nostdlib $^ -o $@ 27 26 vec-syscfg: vec-syscfg.o rdvl.o 28 27 vlset: vlset.o 28 + za-fork: za-fork.o za-fork-asm.o 29 + $(CC) -nostdlib -static $^ -o $@ -lgcc 30 + za-fork.o: za-fork.c 31 + $(CC) -c -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib \ 32 + -include ../../../../include/nolibc/nolibc.h \ 33 + -ffreestanding -Wall $^ -o $@ 29 34 za-test: za-test.o asm-utils.o 30 35 $(CC) -nostdlib $^ -o $@ 31 36 za-ptrace: za-ptrace.o
+61
tools/testing/selftests/arm64/fp/za-fork-asm.S
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + // Copyright (C) 2021 ARM Limited. 3 + 4 + #include "sme-inst.h" 5 + 6 + .arch_extension sve 7 + 8 + #define MAGIC 42 9 + 10 + #define MAXVL 2048 11 + #define MAXVL_B (MAXVL / 8) 12 + 13 + .pushsection .text 14 + .data 15 + .align 4 16 + scratch: 17 + .space MAXVL_B 18 + .popsection 19 + 20 + .globl fork_test 21 + fork_test: 22 + smstart_za 23 + 24 + // For simplicity just set one word in one vector, other tests 25 + // cover general data corruption issues. 26 + ldr x0, =scratch 27 + mov x1, #MAGIC 28 + str x1, [x0] 29 + mov w12, wzr 30 + _ldr_za 12, 0 // ZA.H[W12] loaded from [X0] 31 + 32 + // Tail call into the C portion that does the fork & verify 33 + b fork_test_c 34 + 35 + .globl verify_fork 36 + verify_fork: 37 + // SVCR should have ZA=1, SM=0 38 + mrs x0, S3_3_C4_C2_2 39 + and x1, x0, #3 40 + cmp x1, #2 41 + beq 1f 42 + mov x0, xzr 43 + b 100f 44 + 1: 45 + 46 + // ZA should still have the value we loaded 47 + ldr x0, =scratch 48 + mov w12, wzr 49 + _str_za 12, 0 // ZA.H[W12] stored to [X0] 50 + ldr x1, [x0] 51 + cmp x1, #MAGIC 52 + beq 2f 53 + mov x0, xzr 54 + b 100f 55 + 56 + 2: 57 + // All tests passed 58 + mov x0, #1 59 + 100: 60 + ret 61 +
+156
tools/testing/selftests/arm64/fp/za-fork.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (C) 2022 ARM Limited. 4 + * Original author: Mark Brown <broonie@kernel.org> 5 + */ 6 + 7 + // SPDX-License-Identifier: GPL-2.0-only 8 + 9 + #include <linux/sched.h> 10 + #include <linux/wait.h> 11 + 12 + #define EXPECTED_TESTS 1 13 + 14 + static void putstr(const char *str) 15 + { 16 + write(1, str, strlen(str)); 17 + } 18 + 19 + static void putnum(unsigned int num) 20 + { 21 + char c; 22 + 23 + if (num / 10) 24 + putnum(num / 10); 25 + 26 + c = '0' + (num % 10); 27 + write(1, &c, 1); 28 + } 29 + 30 + static int tests_run; 31 + static int tests_passed; 32 + static int tests_failed; 33 + static int tests_skipped; 34 + 35 + static void print_summary(void) 36 + { 37 + if (tests_passed + tests_failed + tests_skipped != EXPECTED_TESTS) 38 + putstr("# UNEXPECTED TEST COUNT: "); 39 + 40 + putstr("# Totals: pass:"); 41 + putnum(tests_passed); 42 + putstr(" fail:"); 43 + putnum(tests_failed); 44 + putstr(" xfail:0 xpass:0 skip:"); 45 + putnum(tests_skipped); 46 + putstr(" error:0\n"); 47 + } 48 + 49 + int fork_test(void); 50 + int verify_fork(void); 51 + 52 + /* 53 + * If we fork the value in the parent should be unchanged and the 54 + * child should start with the same value. This is called from the 55 + * fork_test() asm function. 56 + */ 57 + int fork_test_c(void) 58 + { 59 + pid_t newpid, waiting; 60 + int child_status, parent_result; 61 + 62 + newpid = fork(); 63 + if (newpid == 0) { 64 + /* In child */ 65 + if (!verify_fork()) { 66 + putstr("# ZA state invalid in child\n"); 67 + exit(0); 68 + } else { 69 + exit(1); 70 + } 71 + } 72 + if (newpid < 0) { 73 + putstr("# fork() failed: -"); 74 + putnum(-newpid); 75 + putstr("\n"); 76 + return 0; 77 + } 78 + 79 + parent_result = verify_fork(); 80 + if (!parent_result) 81 + putstr("# ZA state invalid in parent\n"); 82 + 83 + for (;;) { 84 + waiting = waitpid(newpid, &child_status, 0); 85 + 86 + if (waiting < 0) { 87 + if (errno == EINTR) 88 + continue; 89 + putstr("# waitpid() failed: "); 90 + putnum(errno); 91 + putstr("\n"); 92 + return 0; 93 + } 94 + if (waiting != newpid) { 95 + putstr("# waitpid() returned wrong PID\n"); 96 + return 0; 97 + } 98 + 99 + if (!WIFEXITED(child_status)) { 100 + putstr("# child did not exit\n"); 101 + return 0; 102 + } 103 + 104 + return WEXITSTATUS(child_status) && parent_result; 105 + } 106 + } 107 + 108 + #define run_test(name) \ 109 + if (name()) { \ 110 + tests_passed++; \ 111 + } else { \ 112 + tests_failed++; \ 113 + putstr("not "); \ 114 + } \ 115 + putstr("ok "); \ 116 + putnum(++tests_run); \ 117 + putstr(" " #name "\n"); 118 + 119 + int main(int argc, char **argv) 120 + { 121 + int ret, i; 122 + 123 + putstr("TAP version 13\n"); 124 + putstr("1.."); 125 + putnum(EXPECTED_TESTS); 126 + putstr("\n"); 127 + 128 + putstr("# PID: "); 129 + putnum(getpid()); 130 + putstr("\n"); 131 + 132 + /* 133 + * This test is run with nolibc which doesn't support hwcap and 134 + * it's probably disproportionate to implement so instead check 135 + * for the default vector length configuration in /proc. 136 + */ 137 + ret = open("/proc/sys/abi/sme_default_vector_length", O_RDONLY, 0); 138 + if (ret >= 0) { 139 + run_test(fork_test); 140 + 141 + } else { 142 + putstr("# SME support not present\n"); 143 + 144 + for (i = 0; i < EXPECTED_TESTS; i++) { 145 + putstr("ok "); 146 + putnum(i); 147 + putstr(" skipped\n"); 148 + } 149 + 150 + tests_skipped += EXPECTED_TESTS; 151 + } 152 + 153 + print_summary(); 154 + 155 + return 0; 156 + }