File Index
Files and directories
Sign in
FILE

za-ptrace.c

File preview with syntax highlighting.

linux-6.19.14/tools/testing/selftests/arm64/fp/za-ptrace.c C
  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>
 20
 21#include "kselftest.h"
 22
 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
 27
 28/*
 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.
 35 */
 36#define TEST_VQ_MAX 17
 37
 38#define EXPECTED_TESTS (((TEST_VQ_MAX - SVE_VQ_MIN) + 1) * 3)
 39
 40static void fill_buf(char *buf, size_t size)
 41{
 42	int i;
 43
 44	for (i = 0; i < size; i++)
 45		buf[i] = random();
 46}
 47
 48static int do_child(void)
 49{
 50	if (ptrace(PTRACE_TRACEME, -1, NULL, NULL))
 51		ksft_exit_fail_msg("ptrace(PTRACE_TRACEME) failed: %s (%d)",
 52				   strerror(errno), errno);
 53
 54	if (raise(SIGSTOP))
 55		ksft_exit_fail_msg("raise(SIGSTOP) failed: %s (%d)\n",
 56				   strerror(errno), errno);
 57
 58	return EXIT_SUCCESS;
 59}
 60
 61static struct user_za_header *get_za(pid_t pid, void **buf, size_t *size)
 62{
 63	struct user_za_header *za;
 64	void *p;
 65	size_t sz = sizeof(*za);
 66	struct iovec iov;
 67
 68	while (1) {
 69		if (*size < sz) {
 70			p = realloc(*buf, sz);
 71			if (!p) {
 72				errno = ENOMEM;
 73				goto error;
 74			}
 75
 76			*buf = p;
 77			*size = sz;
 78		}
 79
 80		iov.iov_base = *buf;
 81		iov.iov_len = sz;
 82		if (ptrace(PTRACE_GETREGSET, pid, NT_ARM_ZA, &iov))
 83			goto error;
 84
 85		za = *buf;
 86		if (za->size <= sz)
 87			break;
 88
 89		sz = za->size;
 90	}
 91
 92	return za;
 93
 94error:
 95	return NULL;
 96}
 97
 98static int set_za(pid_t pid, const struct user_za_header *za)
 99{
100	struct iovec iov;
101
102	iov.iov_base = (void *)za;
103	iov.iov_len = za->size;
104	return ptrace(PTRACE_SETREGSET, pid, NT_ARM_ZA, &iov);
105}
106
107/* Validate attempting to set the specfied VL via ptrace */
108static void ptrace_set_get_vl(pid_t child, unsigned int vl, bool *supported)
109{
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;
114
115	*supported = false;
116
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);
122
123	/* If the VL is not supported then a supported VL will be returned */
124	*supported = (prctl_vl == vl);
125
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;
134	}
135
136	/*
137	 * Read back the new register state and verify that we have the
138	 * same VL that we got from prctl() on ourselves.
139	 */
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;
143	}
144
145	ksft_test_result(new_za->vl = prctl_vl, "Set VL %u\n", vl);
146
147	free(new_za);
148}
149
150/* Validate attempting to set no ZA data and read it back */
151static void ptrace_set_no_data(pid_t child, unsigned int vl)
152{
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;
158
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;
163
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;
168	}
169
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;
174	}
175	read_za = read_buf;
176
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;
182	}
183
184	ksft_test_result(read_za->size == write_za.size,
185			 "Disabled ZA for VL %u\n", vl);
186
187out_read:
188	free(read_buf);
189}
190
191/* Validate attempting to set data and read it back */
192static void ptrace_set_get_data(pid_t child, unsigned int vl)
193{
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;
202
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;
209	}
210	write_za = write_buf;
211
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;
216
217	fill_buf(write_buf + ZA_PT_ZA_OFFSET, ZA_PT_ZA_SIZE(vq));
218
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;
223	}
224
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;
229	}
230	read_za = read_buf;
231
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;
237	}
238
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);
243
244out_read:
245	free(read_buf);
246out:
247	free(write_buf);
248}
249
250static int do_parent(pid_t child)
251{
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;
258
259	/* Attach to the child */
260	while (1) {
261		int sig;
262
263		pid = wait(&status);
264		if (pid == -1) {
265			perror("wait");
266			goto error;
267		}
268
269		/*
270		 * This should never happen but it's hard to flag in
271		 * the framework.
272		 */
273		if (pid != child)
274			continue;
275
276		if (WIFEXITED(status) || WIFSIGNALED(status))
277			ksft_exit_fail_msg("Child died unexpectedly\n");
278
279		if (!WIFSTOPPED(status))
280			goto error;
281
282		sig = WSTOPSIG(status);
283
284		if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {
285			if (errno == ESRCH)
286				goto disappeared;
287
288			if (errno == EINVAL) {
289				sig = 0; /* bust group-stop */
290				goto cont;
291			}
292
293			ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",
294					      strerror(errno));
295			goto error;
296		}
297
298		if (sig == SIGSTOP && si.si_code == SI_TKILL &&
299		    si.si_pid == pid)
300			break;
301
302	cont:
303		if (ptrace(PTRACE_CONT, pid, NULL, sig)) {
304			if (errno == ESRCH)
305				goto disappeared;
306
307			ksft_test_result_fail("PTRACE_CONT: %s\n",
308					      strerror(errno));
309			goto error;
310		}
311	}
312
313	ksft_print_msg("Parent is %d, child is %d\n", getpid(), child);
314
315	/* Step through every possible VQ */
316	for (vq = SVE_VQ_MIN; vq <= TEST_VQ_MAX; vq++) {
317		vl = sve_vl_from_vq(vq);
318
319		/* First, try to set this vector length */
320		ptrace_set_get_vl(child, vl, &vl_supported);
321
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);
330		}
331	}
332
333	ret = EXIT_SUCCESS;
334
335error:
336	kill(child, SIGKILL);
337
338disappeared:
339	return ret;
340}
341
342int main(void)
343{
344	int ret = EXIT_SUCCESS;
345	pid_t child;
346
347	srandom(getpid());
348
349	ksft_print_header();
350
351	if (!(getauxval(AT_HWCAP2) & HWCAP2_SME)) {
352		ksft_set_plan(1);
353		ksft_exit_skip("SME not available\n");
354	}
355
356	ksft_set_plan(EXPECTED_TESTS);
357
358	child = fork();
359	if (!child)
360		return do_child();
361
362	if (do_parent(child))
363		ret = EXIT_FAILURE;
364
365	ksft_print_cnts();
366
367	return ret;
368}
~/ Read-only file preview.