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
28 #define NT_ARM_ZT 0x40d
31 #define EXPECTED_TESTS 3
35 static void fill_buf(char *buf
, size_t size
)
39 for (i
= 0; i
< size
; i
++)
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
);
50 ksft_exit_fail_msg("raise(SIGSTOP) failed: %s (%d)\n",
51 strerror(errno
), errno
);
56 static struct user_za_header
*get_za(pid_t pid
, void **buf
, size_t *size
)
58 struct user_za_header
*za
;
60 size_t sz
= sizeof(*za
);
65 p
= realloc(*buf
, sz
);
77 if (ptrace(PTRACE_GETREGSET
, pid
, NT_ARM_ZA
, &iov
))
93 static int set_za(pid_t pid
, const struct user_za_header
*za
)
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
])
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
])
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
];
129 /* Disable PSTATE.ZA using the ZA interface */
130 memset(&za
, 0, sizeof(za
));
132 za
.size
= sizeof(za
);
134 ret
= set_za(child
, &za
);
136 ksft_print_msg("Failed to disable ZA\n");
141 ret
= get_zt(child
, zt
);
143 ksft_print_msg("Failed to read ZT\n");
147 for (i
= 0; i
< ARRAY_SIZE(zt
); i
++) {
149 ksft_print_msg("zt[%d]: 0x%x != 0\n", i
, zt
[i
]);
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
];
165 fill_buf(zt_in
, sizeof(zt_in
));
167 ret
= set_zt(child
, zt_in
);
169 ksft_print_msg("Failed to set ZT\n");
173 ret
= get_zt(child
, zt_out
);
175 ksft_print_msg("Failed to read ZT\n");
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
]);
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
];
201 /* Disable PSTATE.ZA using the ZA interface */
202 memset(&za_in
, 0, sizeof(za_in
));
204 za_in
.size
= sizeof(za_in
);
206 ret
= set_za(child
, &za_in
);
208 ksft_print_msg("Failed to disable ZA\n");
213 fill_buf(zt
, sizeof(zt
));
214 ret
= set_zt(child
, zt
);
216 ksft_print_msg("Failed to set ZT\n");
220 /* Read back ZA and check for register data */
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",
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
));
241 /* That register data should be non-zero */
242 for (i
= 0; i
< ZA_PT_ZA_SIZE(vq
); i
++) {
244 ksft_print_msg("ZA byte %d is %x\n",
250 ksft_print_msg("Failed to read ZA\n");
254 ksft_test_result(!fail
, "ptrace_enable_za_via_zt\n");
257 static int do_parent(pid_t child
)
259 int ret
= EXIT_FAILURE
;
264 /* Attach to the child */
275 * This should never happen but it's hard to flag in
281 if (WIFEXITED(status
) || WIFSIGNALED(status
))
282 ksft_exit_fail_msg("Child died unexpectedly\n");
284 if (!WIFSTOPPED(status
))
287 sig
= WSTOPSIG(status
);
289 if (ptrace(PTRACE_GETSIGINFO
, pid
, NULL
, &si
)) {
293 if (errno
== EINVAL
) {
294 sig
= 0; /* bust group-stop */
298 ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",
303 if (sig
== SIGSTOP
&& si
.si_code
== SI_TKILL
&&
308 if (ptrace(PTRACE_CONT
, pid
, NULL
, sig
)) {
312 ksft_test_result_fail("PTRACE_CONT: %s\n",
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
);
327 kill(child
, SIGKILL
);
335 int ret
= EXIT_SUCCESS
;
342 if (!(getauxval(AT_HWCAP2
) & HWCAP2_SME2
)) {
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
);
351 ksft_exit_skip("Failed to read SME VL: %d (%s)\n",
352 errno
, strerror(errno
));
355 ksft_set_plan(EXPECTED_TESTS
);
361 if (do_parent(child
))