~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/testing/selftests/arm64/fp/za-ptrace.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 
 40 static 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 
 48 static int do_child(void)
 49 {
 50         if (ptrace(PTRACE_TRACEME, -1, NULL, NULL))
 51                 ksft_exit_fail_msg("PTRACE_TRACEME", strerror(errno));
 52 
 53         if (raise(SIGSTOP))
 54                 ksft_exit_fail_msg("raise(SIGSTOP)", strerror(errno));
 55 
 56         return EXIT_SUCCESS;
 57 }
 58 
 59 static struct user_za_header *get_za(pid_t pid, void **buf, size_t *size)
 60 {
 61         struct user_za_header *za;
 62         void *p;
 63         size_t sz = sizeof(*za);
 64         struct iovec iov;
 65 
 66         while (1) {
 67                 if (*size < sz) {
 68                         p = realloc(*buf, sz);
 69                         if (!p) {
 70                                 errno = ENOMEM;
 71                                 goto error;
 72                         }
 73 
 74                         *buf = p;
 75                         *size = sz;
 76                 }
 77 
 78                 iov.iov_base = *buf;
 79                 iov.iov_len = sz;
 80                 if (ptrace(PTRACE_GETREGSET, pid, NT_ARM_ZA, &iov))
 81                         goto error;
 82 
 83                 za = *buf;
 84                 if (za->size <= sz)
 85                         break;
 86 
 87                 sz = za->size;
 88         }
 89 
 90         return za;
 91 
 92 error:
 93         return NULL;
 94 }
 95 
 96 static int set_za(pid_t pid, const struct user_za_header *za)
 97 {
 98         struct iovec iov;
 99 
100         iov.iov_base = (void *)za;
101         iov.iov_len = za->size;
102         return ptrace(PTRACE_SETREGSET, pid, NT_ARM_ZA, &iov);
103 }
104 
105 /* Validate attempting to set the specfied VL via ptrace */
106 static void ptrace_set_get_vl(pid_t child, unsigned int vl, bool *supported)
107 {
108         struct user_za_header za;
109         struct user_za_header *new_za = NULL;
110         size_t new_za_size = 0;
111         int ret, prctl_vl;
112 
113         *supported = false;
114 
115         /* Check if the VL is supported in this process */
116         prctl_vl = prctl(PR_SME_SET_VL, vl);
117         if (prctl_vl == -1)
118                 ksft_exit_fail_msg("prctl(PR_SME_SET_VL) failed: %s (%d)\n",
119                                    strerror(errno), errno);
120 
121         /* If the VL is not supported then a supported VL will be returned */
122         *supported = (prctl_vl == vl);
123 
124         /* Set the VL by doing a set with no register payload */
125         memset(&za, 0, sizeof(za));
126         za.size = sizeof(za);
127         za.vl = vl;
128         ret = set_za(child, &za);
129         if (ret != 0) {
130                 ksft_test_result_fail("Failed to set VL %u\n", vl);
131                 return;
132         }
133 
134         /*
135          * Read back the new register state and verify that we have the
136          * same VL that we got from prctl() on ourselves.
137          */
138         if (!get_za(child, (void **)&new_za, &new_za_size)) {
139                 ksft_test_result_fail("Failed to read VL %u\n", vl);
140                 return;
141         }
142 
143         ksft_test_result(new_za->vl = prctl_vl, "Set VL %u\n", vl);
144 
145         free(new_za);
146 }
147 
148 /* Validate attempting to set no ZA data and read it back */
149 static void ptrace_set_no_data(pid_t child, unsigned int vl)
150 {
151         void *read_buf = NULL;
152         struct user_za_header write_za;
153         struct user_za_header *read_za;
154         size_t read_za_size = 0;
155         int ret;
156 
157         /* Set up some data and write it out */
158         memset(&write_za, 0, sizeof(write_za));
159         write_za.size = ZA_PT_ZA_OFFSET;
160         write_za.vl = vl;
161 
162         ret = set_za(child, &write_za);
163         if (ret != 0) {
164                 ksft_test_result_fail("Failed to set VL %u no data\n", vl);
165                 return;
166         }
167 
168         /* Read the data back */
169         if (!get_za(child, (void **)&read_buf, &read_za_size)) {
170                 ksft_test_result_fail("Failed to read VL %u no data\n", vl);
171                 return;
172         }
173         read_za = read_buf;
174 
175         /* We might read more data if there's extensions we don't know */
176         if (read_za->size < write_za.size) {
177                 ksft_test_result_fail("VL %u wrote %d bytes, only read %d\n",
178                                       vl, write_za.size, read_za->size);
179                 goto out_read;
180         }
181 
182         ksft_test_result(read_za->size == write_za.size,
183                          "Disabled ZA for VL %u\n", vl);
184 
185 out_read:
186         free(read_buf);
187 }
188 
189 /* Validate attempting to set data and read it back */
190 static void ptrace_set_get_data(pid_t child, unsigned int vl)
191 {
192         void *write_buf;
193         void *read_buf = NULL;
194         struct user_za_header *write_za;
195         struct user_za_header *read_za;
196         size_t read_za_size = 0;
197         unsigned int vq = sve_vq_from_vl(vl);
198         int ret;
199         size_t data_size;
200 
201         data_size = ZA_PT_SIZE(vq);
202         write_buf = malloc(data_size);
203         if (!write_buf) {
204                 ksft_test_result_fail("Error allocating %d byte buffer for VL %u\n",
205                                       data_size, vl);
206                 return;
207         }
208         write_za = write_buf;
209 
210         /* Set up some data and write it out */
211         memset(write_za, 0, data_size);
212         write_za->size = data_size;
213         write_za->vl = vl;
214 
215         fill_buf(write_buf + ZA_PT_ZA_OFFSET, ZA_PT_ZA_SIZE(vq));
216 
217         ret = set_za(child, write_za);
218         if (ret != 0) {
219                 ksft_test_result_fail("Failed to set VL %u data\n", vl);
220                 goto out;
221         }
222 
223         /* Read the data back */
224         if (!get_za(child, (void **)&read_buf, &read_za_size)) {
225                 ksft_test_result_fail("Failed to read VL %u data\n", vl);
226                 goto out;
227         }
228         read_za = read_buf;
229 
230         /* We might read more data if there's extensions we don't know */
231         if (read_za->size < write_za->size) {
232                 ksft_test_result_fail("VL %u wrote %d bytes, only read %d\n",
233                                       vl, write_za->size, read_za->size);
234                 goto out_read;
235         }
236 
237         ksft_test_result(memcmp(write_buf + ZA_PT_ZA_OFFSET,
238                                 read_buf + ZA_PT_ZA_OFFSET,
239                                 ZA_PT_ZA_SIZE(vq)) == 0,
240                          "Data match for VL %u\n", vl);
241 
242 out_read:
243         free(read_buf);
244 out:
245         free(write_buf);
246 }
247 
248 static int do_parent(pid_t child)
249 {
250         int ret = EXIT_FAILURE;
251         pid_t pid;
252         int status;
253         siginfo_t si;
254         unsigned int vq, vl;
255         bool vl_supported;
256 
257         /* Attach to the child */
258         while (1) {
259                 int sig;
260 
261                 pid = wait(&status);
262                 if (pid == -1) {
263                         perror("wait");
264                         goto error;
265                 }
266 
267                 /*
268                  * This should never happen but it's hard to flag in
269                  * the framework.
270                  */
271                 if (pid != child)
272                         continue;
273 
274                 if (WIFEXITED(status) || WIFSIGNALED(status))
275                         ksft_exit_fail_msg("Child died unexpectedly\n");
276 
277                 if (!WIFSTOPPED(status))
278                         goto error;
279 
280                 sig = WSTOPSIG(status);
281 
282                 if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {
283                         if (errno == ESRCH)
284                                 goto disappeared;
285 
286                         if (errno == EINVAL) {
287                                 sig = 0; /* bust group-stop */
288                                 goto cont;
289                         }
290 
291                         ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",
292                                               strerror(errno));
293                         goto error;
294                 }
295 
296                 if (sig == SIGSTOP && si.si_code == SI_TKILL &&
297                     si.si_pid == pid)
298                         break;
299 
300         cont:
301                 if (ptrace(PTRACE_CONT, pid, NULL, sig)) {
302                         if (errno == ESRCH)
303                                 goto disappeared;
304 
305                         ksft_test_result_fail("PTRACE_CONT: %s\n",
306                                               strerror(errno));
307                         goto error;
308                 }
309         }
310 
311         ksft_print_msg("Parent is %d, child is %d\n", getpid(), child);
312 
313         /* Step through every possible VQ */
314         for (vq = SVE_VQ_MIN; vq <= TEST_VQ_MAX; vq++) {
315                 vl = sve_vl_from_vq(vq);
316 
317                 /* First, try to set this vector length */
318                 ptrace_set_get_vl(child, vl, &vl_supported);
319 
320                 /* If the VL is supported validate data set/get */
321                 if (vl_supported) {
322                         ptrace_set_no_data(child, vl);
323                         ptrace_set_get_data(child, vl);
324                 } else {
325                         ksft_test_result_skip("Disabled ZA for VL %u\n", vl);
326                         ksft_test_result_skip("Get and set data for VL %u\n",
327                                               vl);
328                 }
329         }
330 
331         ret = EXIT_SUCCESS;
332 
333 error:
334         kill(child, SIGKILL);
335 
336 disappeared:
337         return ret;
338 }
339 
340 int main(void)
341 {
342         int ret = EXIT_SUCCESS;
343         pid_t child;
344 
345         srandom(getpid());
346 
347         ksft_print_header();
348 
349         if (!(getauxval(AT_HWCAP2) & HWCAP2_SME)) {
350                 ksft_set_plan(1);
351                 ksft_exit_skip("SME not available\n");
352         }
353 
354         ksft_set_plan(EXPECTED_TESTS);
355 
356         child = fork();
357         if (!child)
358                 return do_child();
359 
360         if (do_parent(child))
361                 ret = EXIT_FAILURE;
362 
363         ksft_print_cnts();
364 
365         return ret;
366 }
367 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php