Merge tag 'trace-printf-v6.13' of git://git.kernel.org/pub/scm/linux/kernel/git/trace...
[drm/drm-misc.git] / tools / testing / selftests / arm64 / fp / za-ptrace.c
blob08c777f87ea2ef12c9ca9fb12db5d9785938968f
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2021 ARM Limited.
4 */
5 #include <errno.h>
6 #include <stdbool.h>
7 #include <stddef.h>
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <unistd.h>
12 #include <sys/auxv.h>
13 #include <sys/prctl.h>
14 #include <sys/ptrace.h>
15 #include <sys/types.h>
16 #include <sys/uio.h>
17 #include <sys/wait.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: */
24 #ifndef NT_ARM_ZA
25 #define NT_ARM_ZA 0x40c
26 #endif
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
34 * the VL as expected.
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)
42 int i;
44 for (i = 0; i < size; i++)
45 buf[i] = random();
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);
54 if (raise(SIGSTOP))
55 ksft_exit_fail_msg("raise(SIGSTOP) failed: %s (%d)\n",
56 strerror(errno), errno);
58 return EXIT_SUCCESS;
61 static struct user_za_header *get_za(pid_t pid, void **buf, size_t *size)
63 struct user_za_header *za;
64 void *p;
65 size_t sz = sizeof(*za);
66 struct iovec iov;
68 while (1) {
69 if (*size < sz) {
70 p = realloc(*buf, sz);
71 if (!p) {
72 errno = ENOMEM;
73 goto error;
76 *buf = p;
77 *size = sz;
80 iov.iov_base = *buf;
81 iov.iov_len = sz;
82 if (ptrace(PTRACE_GETREGSET, pid, NT_ARM_ZA, &iov))
83 goto error;
85 za = *buf;
86 if (za->size <= sz)
87 break;
89 sz = za->size;
92 return za;
94 error:
95 return NULL;
98 static int set_za(pid_t pid, const struct user_za_header *za)
100 struct iovec iov;
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;
113 int ret, prctl_vl;
115 *supported = false;
117 /* Check if the VL is supported in this process */
118 prctl_vl = prctl(PR_SME_SET_VL, vl);
119 if (prctl_vl == -1)
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);
129 za.vl = vl;
130 ret = set_za(child, &za);
131 if (ret != 0) {
132 ksft_test_result_fail("Failed to set VL %u\n", vl);
133 return;
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);
142 return;
145 ksft_test_result(new_za->vl = prctl_vl, "Set VL %u\n", vl);
147 free(new_za);
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;
157 int ret;
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;
162 write_za.vl = vl;
164 ret = set_za(child, &write_za);
165 if (ret != 0) {
166 ksft_test_result_fail("Failed to set VL %u no data\n", vl);
167 return;
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);
173 return;
175 read_za = read_buf;
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);
181 goto out_read;
184 ksft_test_result(read_za->size == write_za.size,
185 "Disabled ZA for VL %u\n", vl);
187 out_read:
188 free(read_buf);
191 /* Validate attempting to set data and read it back */
192 static void ptrace_set_get_data(pid_t child, unsigned int vl)
194 void *write_buf;
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);
200 int ret;
201 size_t data_size;
203 data_size = ZA_PT_SIZE(vq);
204 write_buf = malloc(data_size);
205 if (!write_buf) {
206 ksft_test_result_fail("Error allocating %ld byte buffer for VL %u\n",
207 data_size, vl);
208 return;
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;
215 write_za->vl = vl;
217 fill_buf(write_buf + ZA_PT_ZA_OFFSET, ZA_PT_ZA_SIZE(vq));
219 ret = set_za(child, write_za);
220 if (ret != 0) {
221 ksft_test_result_fail("Failed to set VL %u data\n", vl);
222 goto out;
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);
228 goto out;
230 read_za = read_buf;
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);
236 goto out_read;
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);
244 out_read:
245 free(read_buf);
246 out:
247 free(write_buf);
250 static int do_parent(pid_t child)
252 int ret = EXIT_FAILURE;
253 pid_t pid;
254 int status;
255 siginfo_t si;
256 unsigned int vq, vl;
257 bool vl_supported;
259 /* Attach to the child */
260 while (1) {
261 int sig;
263 pid = wait(&status);
264 if (pid == -1) {
265 perror("wait");
266 goto error;
270 * This should never happen but it's hard to flag in
271 * the framework.
273 if (pid != child)
274 continue;
276 if (WIFEXITED(status) || WIFSIGNALED(status))
277 ksft_exit_fail_msg("Child died unexpectedly\n");
279 if (!WIFSTOPPED(status))
280 goto error;
282 sig = WSTOPSIG(status);
284 if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {
285 if (errno == ESRCH)
286 goto disappeared;
288 if (errno == EINVAL) {
289 sig = 0; /* bust group-stop */
290 goto cont;
293 ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",
294 strerror(errno));
295 goto error;
298 if (sig == SIGSTOP && si.si_code == SI_TKILL &&
299 si.si_pid == pid)
300 break;
302 cont:
303 if (ptrace(PTRACE_CONT, pid, NULL, sig)) {
304 if (errno == ESRCH)
305 goto disappeared;
307 ksft_test_result_fail("PTRACE_CONT: %s\n",
308 strerror(errno));
309 goto error;
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 */
323 if (vl_supported) {
324 ptrace_set_no_data(child, vl);
325 ptrace_set_get_data(child, vl);
326 } else {
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",
329 vl);
333 ret = EXIT_SUCCESS;
335 error:
336 kill(child, SIGKILL);
338 disappeared:
339 return ret;
342 int main(void)
344 int ret = EXIT_SUCCESS;
345 pid_t child;
347 srandom(getpid());
349 ksft_print_header();
351 if (!(getauxval(AT_HWCAP2) & HWCAP2_SME)) {
352 ksft_set_plan(1);
353 ksft_exit_skip("SME not available\n");
356 ksft_set_plan(EXPECTED_TESTS);
358 child = fork();
359 if (!child)
360 return do_child();
362 if (do_parent(child))
363 ret = EXIT_FAILURE;
365 ksft_print_cnts();
367 return ret;