1 // SPDX-License-Identifier: GPL-2.0-only
3 * Copyright (C) 2021 ARM Limited.
13 #include <sys/prctl.h>
14 #include <sys/ptrace.h>
15 #include <sys/types.h>
18 #include <asm/sigcontext.h>
19 #include <asm/ptrace.h>
21 #include "../../kselftest.h"
23 /* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */
25 #define NT_ARM_ZA 0x40c
29 * The architecture defines the maximum VQ as 16 but for extensibility
30 * the kernel specifies the SVE_VQ_MAX as 512 resulting in us running
31 * a *lot* more tests than are useful if we use it. Until the
32 * architecture is extended let's limit our coverage to what is
33 * currently allowed, plus one extra to ensure we cover constraining
36 #define TEST_VQ_MAX 17
38 #define EXPECTED_TESTS (((TEST_VQ_MAX - SVE_VQ_MIN) + 1) * 3)
40 static void fill_buf(char *buf
, size_t size
)
44 for (i
= 0; i
< size
; i
++)
48 static int do_child(void)
50 if (ptrace(PTRACE_TRACEME
, -1, NULL
, NULL
))
51 ksft_exit_fail_msg("ptrace(PTRACE_TRACEME) failed: %s (%d)",
52 strerror(errno
), errno
);
55 ksft_exit_fail_msg("raise(SIGSTOP) failed: %s (%d)\n",
56 strerror(errno
), errno
);
61 static struct user_za_header
*get_za(pid_t pid
, void **buf
, size_t *size
)
63 struct user_za_header
*za
;
65 size_t sz
= sizeof(*za
);
70 p
= realloc(*buf
, sz
);
82 if (ptrace(PTRACE_GETREGSET
, pid
, NT_ARM_ZA
, &iov
))
98 static int set_za(pid_t pid
, const struct user_za_header
*za
)
102 iov
.iov_base
= (void *)za
;
103 iov
.iov_len
= za
->size
;
104 return ptrace(PTRACE_SETREGSET
, pid
, NT_ARM_ZA
, &iov
);
107 /* Validate attempting to set the specfied VL via ptrace */
108 static void ptrace_set_get_vl(pid_t child
, unsigned int vl
, bool *supported
)
110 struct user_za_header za
;
111 struct user_za_header
*new_za
= NULL
;
112 size_t new_za_size
= 0;
117 /* Check if the VL is supported in this process */
118 prctl_vl
= prctl(PR_SME_SET_VL
, vl
);
120 ksft_exit_fail_msg("prctl(PR_SME_SET_VL) failed: %s (%d)\n",
121 strerror(errno
), errno
);
123 /* If the VL is not supported then a supported VL will be returned */
124 *supported
= (prctl_vl
== vl
);
126 /* Set the VL by doing a set with no register payload */
127 memset(&za
, 0, sizeof(za
));
128 za
.size
= sizeof(za
);
130 ret
= set_za(child
, &za
);
132 ksft_test_result_fail("Failed to set VL %u\n", vl
);
137 * Read back the new register state and verify that we have the
138 * same VL that we got from prctl() on ourselves.
140 if (!get_za(child
, (void **)&new_za
, &new_za_size
)) {
141 ksft_test_result_fail("Failed to read VL %u\n", vl
);
145 ksft_test_result(new_za
->vl
= prctl_vl
, "Set VL %u\n", vl
);
150 /* Validate attempting to set no ZA data and read it back */
151 static void ptrace_set_no_data(pid_t child
, unsigned int vl
)
153 void *read_buf
= NULL
;
154 struct user_za_header write_za
;
155 struct user_za_header
*read_za
;
156 size_t read_za_size
= 0;
159 /* Set up some data and write it out */
160 memset(&write_za
, 0, sizeof(write_za
));
161 write_za
.size
= ZA_PT_ZA_OFFSET
;
164 ret
= set_za(child
, &write_za
);
166 ksft_test_result_fail("Failed to set VL %u no data\n", vl
);
170 /* Read the data back */
171 if (!get_za(child
, (void **)&read_buf
, &read_za_size
)) {
172 ksft_test_result_fail("Failed to read VL %u no data\n", vl
);
177 /* We might read more data if there's extensions we don't know */
178 if (read_za
->size
< write_za
.size
) {
179 ksft_test_result_fail("VL %u wrote %d bytes, only read %d\n",
180 vl
, write_za
.size
, read_za
->size
);
184 ksft_test_result(read_za
->size
== write_za
.size
,
185 "Disabled ZA for VL %u\n", vl
);
191 /* Validate attempting to set data and read it back */
192 static void ptrace_set_get_data(pid_t child
, unsigned int vl
)
195 void *read_buf
= NULL
;
196 struct user_za_header
*write_za
;
197 struct user_za_header
*read_za
;
198 size_t read_za_size
= 0;
199 unsigned int vq
= sve_vq_from_vl(vl
);
203 data_size
= ZA_PT_SIZE(vq
);
204 write_buf
= malloc(data_size
);
206 ksft_test_result_fail("Error allocating %ld byte buffer for VL %u\n",
210 write_za
= write_buf
;
212 /* Set up some data and write it out */
213 memset(write_za
, 0, data_size
);
214 write_za
->size
= data_size
;
217 fill_buf(write_buf
+ ZA_PT_ZA_OFFSET
, ZA_PT_ZA_SIZE(vq
));
219 ret
= set_za(child
, write_za
);
221 ksft_test_result_fail("Failed to set VL %u data\n", vl
);
225 /* Read the data back */
226 if (!get_za(child
, (void **)&read_buf
, &read_za_size
)) {
227 ksft_test_result_fail("Failed to read VL %u data\n", vl
);
232 /* We might read more data if there's extensions we don't know */
233 if (read_za
->size
< write_za
->size
) {
234 ksft_test_result_fail("VL %u wrote %d bytes, only read %d\n",
235 vl
, write_za
->size
, read_za
->size
);
239 ksft_test_result(memcmp(write_buf
+ ZA_PT_ZA_OFFSET
,
240 read_buf
+ ZA_PT_ZA_OFFSET
,
241 ZA_PT_ZA_SIZE(vq
)) == 0,
242 "Data match for VL %u\n", vl
);
250 static int do_parent(pid_t child
)
252 int ret
= EXIT_FAILURE
;
259 /* Attach to the child */
270 * This should never happen but it's hard to flag in
276 if (WIFEXITED(status
) || WIFSIGNALED(status
))
277 ksft_exit_fail_msg("Child died unexpectedly\n");
279 if (!WIFSTOPPED(status
))
282 sig
= WSTOPSIG(status
);
284 if (ptrace(PTRACE_GETSIGINFO
, pid
, NULL
, &si
)) {
288 if (errno
== EINVAL
) {
289 sig
= 0; /* bust group-stop */
293 ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",
298 if (sig
== SIGSTOP
&& si
.si_code
== SI_TKILL
&&
303 if (ptrace(PTRACE_CONT
, pid
, NULL
, sig
)) {
307 ksft_test_result_fail("PTRACE_CONT: %s\n",
313 ksft_print_msg("Parent is %d, child is %d\n", getpid(), child
);
315 /* Step through every possible VQ */
316 for (vq
= SVE_VQ_MIN
; vq
<= TEST_VQ_MAX
; vq
++) {
317 vl
= sve_vl_from_vq(vq
);
319 /* First, try to set this vector length */
320 ptrace_set_get_vl(child
, vl
, &vl_supported
);
322 /* If the VL is supported validate data set/get */
324 ptrace_set_no_data(child
, vl
);
325 ptrace_set_get_data(child
, vl
);
327 ksft_test_result_skip("Disabled ZA for VL %u\n", vl
);
328 ksft_test_result_skip("Get and set data for VL %u\n",
336 kill(child
, SIGKILL
);
344 int ret
= EXIT_SUCCESS
;
351 if (!(getauxval(AT_HWCAP2
) & HWCAP2_SME
)) {
353 ksft_exit_skip("SME not available\n");
356 ksft_set_plan(EXPECTED_TESTS
);
362 if (do_parent(child
))