Skip to content

Commit 212b042

Browse files
brooniectmarinas
authored andcommitted
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 <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Catalin Marinas <[email protected]>
1 parent 43e3f85 commit 212b042

File tree

4 files changed

+226
-1
lines changed

4 files changed

+226
-1
lines changed

tools/testing/selftests/arm64/fp/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,6 @@ sve-test
88
ssve-test
99
vec-syscfg
1010
vlset
11+
za-fork
1112
za-ptrace
1213
za-test

tools/testing/selftests/arm64/fp/Makefile

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# SPDX-License-Identifier: GPL-2.0
22

33
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
55
TEST_PROGS_EXTENDED := fp-pidbench fpsimd-test fpsimd-stress \
66
rdvl-sme rdvl-sve \
77
sve-test sve-stress \
@@ -11,6 +11,7 @@ TEST_PROGS_EXTENDED := fp-pidbench fpsimd-test fpsimd-stress \
1111

1212
all: $(TEST_GEN_PROGS) $(TEST_PROGS_EXTENDED)
1313

14+
# Build with nolibc to avoid effects due to libc's clone() support
1415
fp-pidbench: fp-pidbench.S asm-utils.o
1516
$(CC) -nostdlib $^ -o $@
1617
fpsimd-test: fpsimd-test.o asm-utils.o
@@ -25,6 +26,12 @@ ssve-test: sve-test.S asm-utils.o
2526
$(CC) -DSSVE -nostdlib $^ -o $@
2627
vec-syscfg: vec-syscfg.o rdvl.o
2728
vlset: vlset.o
29+
za-fork: za-fork.o za-fork-asm.o
30+
$(CC) -nostdlib -static $^ -o $@ -lgcc
31+
za-fork.o: za-fork.c
32+
$(CC) -c -fno-asynchronous-unwind-tables -fno-ident -s -Os -nostdlib \
33+
-include ../../../../include/nolibc/nolibc.h \
34+
-ffreestanding -Wall $^ -o $@
2835
za-test: za-test.o asm-utils.o
2936
$(CC) -nostdlib $^ -o $@
3037
za-ptrace: za-ptrace.o
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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+
Lines changed: 156 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,156 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/*
3+
* Copyright (C) 2022 ARM Limited.
4+
* Original author: Mark Brown <[email protected]>
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+
}

0 commit comments

Comments
 (0)