Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/arm64/fp/za-ptrace.c
26295 views
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(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
61
static 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
94
error:
95
return NULL;
96
}
97
98
static 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 */
108
static 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 */
151
static 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
187
out_read:
188
free(read_buf);
189
}
190
191
/* Validate attempting to set data and read it back */
192
static 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
244
out_read:
245
free(read_buf);
246
out:
247
free(write_buf);
248
}
249
250
static 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
335
error:
336
kill(child, SIGKILL);
337
338
disappeared:
339
return ret;
340
}
341
342
int 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
}
369
370