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 / zt-ptrace.c
blob584b8d59b7ea1c034e90f8af1d768889aad8cfad
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
27 #ifndef NT_ARM_ZT
28 #define NT_ARM_ZT 0x40d
29 #endif
31 #define EXPECTED_TESTS 3
33 static int sme_vl;
35 static void fill_buf(char *buf, size_t size)
37 int i;
39 for (i = 0; i < size; i++)
40 buf[i] = random();
43 static int do_child(void)
45 if (ptrace(PTRACE_TRACEME, -1, NULL, NULL))
46 ksft_exit_fail_msg("ptrace(PTRACE_TRACEME) failed: %s (%d)\n",
47 strerror(errno), errno);
49 if (raise(SIGSTOP))
50 ksft_exit_fail_msg("raise(SIGSTOP) failed: %s (%d)\n",
51 strerror(errno), errno);
53 return EXIT_SUCCESS;
56 static struct user_za_header *get_za(pid_t pid, void **buf, size_t *size)
58 struct user_za_header *za;
59 void *p;
60 size_t sz = sizeof(*za);
61 struct iovec iov;
63 while (1) {
64 if (*size < sz) {
65 p = realloc(*buf, sz);
66 if (!p) {
67 errno = ENOMEM;
68 goto error;
71 *buf = p;
72 *size = sz;
75 iov.iov_base = *buf;
76 iov.iov_len = sz;
77 if (ptrace(PTRACE_GETREGSET, pid, NT_ARM_ZA, &iov))
78 goto error;
80 za = *buf;
81 if (za->size <= sz)
82 break;
84 sz = za->size;
87 return za;
89 error:
90 return NULL;
93 static int set_za(pid_t pid, const struct user_za_header *za)
95 struct iovec iov;
97 iov.iov_base = (void *)za;
98 iov.iov_len = za->size;
99 return ptrace(PTRACE_SETREGSET, pid, NT_ARM_ZA, &iov);
102 static int get_zt(pid_t pid, char zt[ZT_SIG_REG_BYTES])
104 struct iovec iov;
106 iov.iov_base = zt;
107 iov.iov_len = ZT_SIG_REG_BYTES;
108 return ptrace(PTRACE_GETREGSET, pid, NT_ARM_ZT, &iov);
112 static int set_zt(pid_t pid, const char zt[ZT_SIG_REG_BYTES])
114 struct iovec iov;
116 iov.iov_base = (void *)zt;
117 iov.iov_len = ZT_SIG_REG_BYTES;
118 return ptrace(PTRACE_SETREGSET, pid, NT_ARM_ZT, &iov);
121 /* Reading with ZA disabled returns all zeros */
122 static void ptrace_za_disabled_read_zt(pid_t child)
124 struct user_za_header za;
125 char zt[ZT_SIG_REG_BYTES];
126 int ret, i;
127 bool fail = false;
129 /* Disable PSTATE.ZA using the ZA interface */
130 memset(&za, 0, sizeof(za));
131 za.vl = sme_vl;
132 za.size = sizeof(za);
134 ret = set_za(child, &za);
135 if (ret != 0) {
136 ksft_print_msg("Failed to disable ZA\n");
137 fail = true;
140 /* Read back ZT */
141 ret = get_zt(child, zt);
142 if (ret != 0) {
143 ksft_print_msg("Failed to read ZT\n");
144 fail = true;
147 for (i = 0; i < ARRAY_SIZE(zt); i++) {
148 if (zt[i]) {
149 ksft_print_msg("zt[%d]: 0x%x != 0\n", i, zt[i]);
150 fail = true;
154 ksft_test_result(!fail, "ptrace_za_disabled_read_zt\n");
157 /* Writing then reading ZT should return the data written */
158 static void ptrace_set_get_zt(pid_t child)
160 char zt_in[ZT_SIG_REG_BYTES];
161 char zt_out[ZT_SIG_REG_BYTES];
162 int ret, i;
163 bool fail = false;
165 fill_buf(zt_in, sizeof(zt_in));
167 ret = set_zt(child, zt_in);
168 if (ret != 0) {
169 ksft_print_msg("Failed to set ZT\n");
170 fail = true;
173 ret = get_zt(child, zt_out);
174 if (ret != 0) {
175 ksft_print_msg("Failed to read ZT\n");
176 fail = true;
179 for (i = 0; i < ARRAY_SIZE(zt_in); i++) {
180 if (zt_in[i] != zt_out[i]) {
181 ksft_print_msg("zt[%d]: 0x%x != 0x%x\n", i,
182 zt_in[i], zt_out[i]);
183 fail = true;
187 ksft_test_result(!fail, "ptrace_set_get_zt\n");
190 /* Writing ZT should set PSTATE.ZA */
191 static void ptrace_enable_za_via_zt(pid_t child)
193 struct user_za_header za_in;
194 struct user_za_header *za_out;
195 char zt[ZT_SIG_REG_BYTES];
196 char *za_data;
197 size_t za_out_size;
198 int ret, i, vq;
199 bool fail = false;
201 /* Disable PSTATE.ZA using the ZA interface */
202 memset(&za_in, 0, sizeof(za_in));
203 za_in.vl = sme_vl;
204 za_in.size = sizeof(za_in);
206 ret = set_za(child, &za_in);
207 if (ret != 0) {
208 ksft_print_msg("Failed to disable ZA\n");
209 fail = true;
212 /* Write ZT */
213 fill_buf(zt, sizeof(zt));
214 ret = set_zt(child, zt);
215 if (ret != 0) {
216 ksft_print_msg("Failed to set ZT\n");
217 fail = true;
220 /* Read back ZA and check for register data */
221 za_out = NULL;
222 za_out_size = 0;
223 if (get_za(child, (void **)&za_out, &za_out_size)) {
224 /* Should have an unchanged VL */
225 if (za_out->vl != sme_vl) {
226 ksft_print_msg("VL changed from %d to %d\n",
227 sme_vl, za_out->vl);
228 fail = true;
230 vq = __sve_vq_from_vl(za_out->vl);
231 za_data = (char *)za_out + ZA_PT_ZA_OFFSET;
233 /* Should have register data */
234 if (za_out->size < ZA_PT_SIZE(vq)) {
235 ksft_print_msg("ZA data less than expected: %u < %u\n",
236 za_out->size, (unsigned int)ZA_PT_SIZE(vq));
237 fail = true;
238 vq = 0;
241 /* That register data should be non-zero */
242 for (i = 0; i < ZA_PT_ZA_SIZE(vq); i++) {
243 if (za_data[i]) {
244 ksft_print_msg("ZA byte %d is %x\n",
245 i, za_data[i]);
246 fail = true;
249 } else {
250 ksft_print_msg("Failed to read ZA\n");
251 fail = true;
254 ksft_test_result(!fail, "ptrace_enable_za_via_zt\n");
257 static int do_parent(pid_t child)
259 int ret = EXIT_FAILURE;
260 pid_t pid;
261 int status;
262 siginfo_t si;
264 /* Attach to the child */
265 while (1) {
266 int sig;
268 pid = wait(&status);
269 if (pid == -1) {
270 perror("wait");
271 goto error;
275 * This should never happen but it's hard to flag in
276 * the framework.
278 if (pid != child)
279 continue;
281 if (WIFEXITED(status) || WIFSIGNALED(status))
282 ksft_exit_fail_msg("Child died unexpectedly\n");
284 if (!WIFSTOPPED(status))
285 goto error;
287 sig = WSTOPSIG(status);
289 if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {
290 if (errno == ESRCH)
291 goto disappeared;
293 if (errno == EINVAL) {
294 sig = 0; /* bust group-stop */
295 goto cont;
298 ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",
299 strerror(errno));
300 goto error;
303 if (sig == SIGSTOP && si.si_code == SI_TKILL &&
304 si.si_pid == pid)
305 break;
307 cont:
308 if (ptrace(PTRACE_CONT, pid, NULL, sig)) {
309 if (errno == ESRCH)
310 goto disappeared;
312 ksft_test_result_fail("PTRACE_CONT: %s\n",
313 strerror(errno));
314 goto error;
318 ksft_print_msg("Parent is %d, child is %d\n", getpid(), child);
320 ptrace_za_disabled_read_zt(child);
321 ptrace_set_get_zt(child);
322 ptrace_enable_za_via_zt(child);
324 ret = EXIT_SUCCESS;
326 error:
327 kill(child, SIGKILL);
329 disappeared:
330 return ret;
333 int main(void)
335 int ret = EXIT_SUCCESS;
336 pid_t child;
338 srandom(getpid());
340 ksft_print_header();
342 if (!(getauxval(AT_HWCAP2) & HWCAP2_SME2)) {
343 ksft_set_plan(1);
344 ksft_exit_skip("SME2 not available\n");
347 /* We need a valid SME VL to enable/disable ZA */
348 sme_vl = prctl(PR_SME_GET_VL);
349 if (sme_vl == -1) {
350 ksft_set_plan(1);
351 ksft_exit_skip("Failed to read SME VL: %d (%s)\n",
352 errno, strerror(errno));
355 ksft_set_plan(EXPECTED_TESTS);
357 child = fork();
358 if (!child)
359 return do_child();
361 if (do_parent(child))
362 ret = EXIT_FAILURE;
364 ksft_print_cnts();
366 return ret;