Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/testing/selftests/arm64/fp/sve-ptrace.c
48893 views
1
// SPDX-License-Identifier: GPL-2.0-only
2
/*
3
* Copyright (C) 2015-2021 ARM Limited.
4
* Original author: Dave Martin <[email protected]>
5
*/
6
#include <errno.h>
7
#include <stdbool.h>
8
#include <stddef.h>
9
#include <stdio.h>
10
#include <stdlib.h>
11
#include <string.h>
12
#include <unistd.h>
13
#include <sys/auxv.h>
14
#include <sys/prctl.h>
15
#include <sys/ptrace.h>
16
#include <sys/types.h>
17
#include <sys/uio.h>
18
#include <sys/wait.h>
19
#include <asm/sigcontext.h>
20
#include <asm/ptrace.h>
21
22
#include "kselftest.h"
23
24
/* <linux/elf.h> and <sys/auxv.h> don't like each other, so: */
25
#ifndef NT_ARM_SVE
26
#define NT_ARM_SVE 0x405
27
#endif
28
29
#ifndef NT_ARM_SSVE
30
#define NT_ARM_SSVE 0x40b
31
#endif
32
33
/*
34
* The architecture defines the maximum VQ as 16 but for extensibility
35
* the kernel specifies the SVE_VQ_MAX as 512 resulting in us running
36
* a *lot* more tests than are useful if we use it. Until the
37
* architecture is extended let's limit our coverage to what is
38
* currently allowed, plus one extra to ensure we cover constraining
39
* the VL as expected.
40
*/
41
#define TEST_VQ_MAX 17
42
43
struct vec_type {
44
const char *name;
45
unsigned long hwcap_type;
46
unsigned long hwcap;
47
int regset;
48
int prctl_set;
49
};
50
51
static const struct vec_type vec_types[] = {
52
{
53
.name = "SVE",
54
.hwcap_type = AT_HWCAP,
55
.hwcap = HWCAP_SVE,
56
.regset = NT_ARM_SVE,
57
.prctl_set = PR_SVE_SET_VL,
58
},
59
{
60
.name = "Streaming SVE",
61
.hwcap_type = AT_HWCAP2,
62
.hwcap = HWCAP2_SME,
63
.regset = NT_ARM_SSVE,
64
.prctl_set = PR_SME_SET_VL,
65
},
66
};
67
68
#define VL_TESTS (((TEST_VQ_MAX - SVE_VQ_MIN) + 1) * 4)
69
#define FLAG_TESTS 4
70
#define FPSIMD_TESTS 2
71
72
#define EXPECTED_TESTS ((VL_TESTS + FLAG_TESTS + FPSIMD_TESTS) * ARRAY_SIZE(vec_types))
73
74
static void fill_buf(char *buf, size_t size)
75
{
76
int i;
77
78
for (i = 0; i < size; i++)
79
buf[i] = random();
80
}
81
82
static int do_child(void)
83
{
84
if (ptrace(PTRACE_TRACEME, -1, NULL, NULL))
85
ksft_exit_fail_msg("ptrace(PTRACE_TRACEME) failed: %s (%d)\n",
86
strerror(errno), errno);
87
88
if (raise(SIGSTOP))
89
ksft_exit_fail_msg("raise(SIGSTOP) failed: %s (%d)\n",
90
strerror(errno), errno);
91
92
return EXIT_SUCCESS;
93
}
94
95
static int get_fpsimd(pid_t pid, struct user_fpsimd_state *fpsimd)
96
{
97
struct iovec iov;
98
int ret;
99
100
iov.iov_base = fpsimd;
101
iov.iov_len = sizeof(*fpsimd);
102
ret = ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov);
103
if (ret == -1)
104
ksft_perror("ptrace(PTRACE_GETREGSET)");
105
return ret;
106
}
107
108
static int set_fpsimd(pid_t pid, struct user_fpsimd_state *fpsimd)
109
{
110
struct iovec iov;
111
int ret;
112
113
iov.iov_base = fpsimd;
114
iov.iov_len = sizeof(*fpsimd);
115
ret = ptrace(PTRACE_SETREGSET, pid, NT_PRFPREG, &iov);
116
if (ret == -1)
117
ksft_perror("ptrace(PTRACE_SETREGSET)");
118
return ret;
119
}
120
121
static struct user_sve_header *get_sve(pid_t pid, const struct vec_type *type,
122
void **buf, size_t *size)
123
{
124
struct user_sve_header *sve;
125
void *p;
126
size_t sz = sizeof(*sve);
127
struct iovec iov;
128
int ret;
129
130
while (1) {
131
if (*size < sz) {
132
p = realloc(*buf, sz);
133
if (!p) {
134
errno = ENOMEM;
135
goto error;
136
}
137
138
*buf = p;
139
*size = sz;
140
}
141
142
iov.iov_base = *buf;
143
iov.iov_len = sz;
144
ret = ptrace(PTRACE_GETREGSET, pid, type->regset, &iov);
145
if (ret) {
146
ksft_perror("ptrace(PTRACE_GETREGSET)");
147
goto error;
148
}
149
150
sve = *buf;
151
if (sve->size <= sz)
152
break;
153
154
sz = sve->size;
155
}
156
157
return sve;
158
159
error:
160
return NULL;
161
}
162
163
static int set_sve(pid_t pid, const struct vec_type *type,
164
const struct user_sve_header *sve)
165
{
166
struct iovec iov;
167
int ret;
168
169
iov.iov_base = (void *)sve;
170
iov.iov_len = sve->size;
171
ret = ptrace(PTRACE_SETREGSET, pid, type->regset, &iov);
172
if (ret == -1)
173
ksft_perror("ptrace(PTRACE_SETREGSET)");
174
return ret;
175
}
176
177
/* A read operation fails */
178
static void read_fails(pid_t child, const struct vec_type *type)
179
{
180
struct user_sve_header *new_sve = NULL;
181
size_t new_sve_size = 0;
182
void *ret;
183
184
ret = get_sve(child, type, (void **)&new_sve, &new_sve_size);
185
186
ksft_test_result(ret == NULL, "%s unsupported read fails\n",
187
type->name);
188
189
free(new_sve);
190
}
191
192
/* A write operation fails */
193
static void write_fails(pid_t child, const struct vec_type *type)
194
{
195
struct user_sve_header sve;
196
int ret;
197
198
/* Just the header, no data */
199
memset(&sve, 0, sizeof(sve));
200
sve.size = sizeof(sve);
201
sve.flags = SVE_PT_REGS_SVE;
202
sve.vl = SVE_VL_MIN;
203
ret = set_sve(child, type, &sve);
204
205
ksft_test_result(ret != 0, "%s unsupported write fails\n",
206
type->name);
207
}
208
209
/* Validate setting and getting the inherit flag */
210
static void ptrace_set_get_inherit(pid_t child, const struct vec_type *type)
211
{
212
struct user_sve_header sve;
213
struct user_sve_header *new_sve = NULL;
214
size_t new_sve_size = 0;
215
int ret;
216
217
/* First set the flag */
218
memset(&sve, 0, sizeof(sve));
219
sve.size = sizeof(sve);
220
sve.vl = sve_vl_from_vq(SVE_VQ_MIN);
221
sve.flags = SVE_PT_VL_INHERIT | SVE_PT_REGS_SVE;
222
ret = set_sve(child, type, &sve);
223
if (ret != 0) {
224
ksft_test_result_fail("Failed to set %s SVE_PT_VL_INHERIT\n",
225
type->name);
226
return;
227
}
228
229
/*
230
* Read back the new register state and verify that we have
231
* set the flags we expected.
232
*/
233
if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) {
234
ksft_test_result_fail("Failed to read %s SVE flags\n",
235
type->name);
236
return;
237
}
238
239
ksft_test_result(new_sve->flags & SVE_PT_VL_INHERIT,
240
"%s SVE_PT_VL_INHERIT set\n", type->name);
241
242
/* Now clear */
243
sve.flags &= ~SVE_PT_VL_INHERIT;
244
ret = set_sve(child, type, &sve);
245
if (ret != 0) {
246
ksft_test_result_fail("Failed to clear %s SVE_PT_VL_INHERIT\n",
247
type->name);
248
return;
249
}
250
251
if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) {
252
ksft_test_result_fail("Failed to read %s SVE flags\n",
253
type->name);
254
return;
255
}
256
257
ksft_test_result(!(new_sve->flags & SVE_PT_VL_INHERIT),
258
"%s SVE_PT_VL_INHERIT cleared\n", type->name);
259
260
free(new_sve);
261
}
262
263
/* Validate attempting to set the specfied VL via ptrace */
264
static void ptrace_set_get_vl(pid_t child, const struct vec_type *type,
265
unsigned int vl, bool *supported)
266
{
267
struct user_sve_header sve;
268
struct user_sve_header *new_sve = NULL;
269
size_t new_sve_size = 0;
270
int ret, prctl_vl;
271
272
*supported = false;
273
274
/* Check if the VL is supported in this process */
275
prctl_vl = prctl(type->prctl_set, vl);
276
if (prctl_vl == -1)
277
ksft_exit_fail_msg("prctl(PR_%s_SET_VL) failed: %s (%d)\n",
278
type->name, strerror(errno), errno);
279
280
/* If the VL is not supported then a supported VL will be returned */
281
*supported = (prctl_vl == vl);
282
283
/* Set the VL by doing a set with no register payload */
284
memset(&sve, 0, sizeof(sve));
285
sve.size = sizeof(sve);
286
sve.flags = SVE_PT_REGS_SVE;
287
sve.vl = vl;
288
ret = set_sve(child, type, &sve);
289
if (ret != 0) {
290
ksft_test_result_fail("Failed to set %s VL %u\n",
291
type->name, vl);
292
return;
293
}
294
295
/*
296
* Read back the new register state and verify that we have the
297
* same VL that we got from prctl() on ourselves.
298
*/
299
if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) {
300
ksft_test_result_fail("Failed to read %s VL %u\n",
301
type->name, vl);
302
return;
303
}
304
305
ksft_test_result(new_sve->vl == prctl_vl, "Set %s VL %u\n",
306
type->name, vl);
307
308
free(new_sve);
309
}
310
311
static void check_u32(unsigned int vl, const char *reg,
312
uint32_t *in, uint32_t *out, int *errors)
313
{
314
if (*in != *out) {
315
printf("# VL %d %s wrote %x read %x\n",
316
vl, reg, *in, *out);
317
(*errors)++;
318
}
319
}
320
321
/* Set out of range VLs */
322
static void ptrace_set_vl_ranges(pid_t child, const struct vec_type *type)
323
{
324
struct user_sve_header sve;
325
int ret;
326
327
memset(&sve, 0, sizeof(sve));
328
sve.flags = SVE_PT_REGS_SVE;
329
sve.size = sizeof(sve);
330
331
ret = set_sve(child, type, &sve);
332
ksft_test_result(ret != 0, "%s Set invalid VL 0\n", type->name);
333
334
sve.vl = SVE_VL_MAX + SVE_VQ_BYTES;
335
ret = set_sve(child, type, &sve);
336
ksft_test_result(ret != 0, "%s Set invalid VL %d\n", type->name,
337
SVE_VL_MAX + SVE_VQ_BYTES);
338
}
339
340
/* Access the FPSIMD registers via the SVE regset */
341
static void ptrace_sve_fpsimd(pid_t child, const struct vec_type *type)
342
{
343
void *svebuf;
344
struct user_sve_header *sve;
345
struct user_fpsimd_state *fpsimd, new_fpsimd;
346
unsigned int i, j;
347
unsigned char *p;
348
int ret;
349
350
svebuf = malloc(SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD));
351
if (!svebuf) {
352
ksft_test_result_fail("Failed to allocate FPSIMD buffer\n");
353
return;
354
}
355
356
memset(svebuf, 0, SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD));
357
sve = svebuf;
358
sve->flags = SVE_PT_REGS_FPSIMD;
359
sve->size = SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD);
360
sve->vl = 16; /* We don't care what the VL is */
361
362
/* Try to set a known FPSIMD state via PT_REGS_SVE */
363
fpsimd = (struct user_fpsimd_state *)((char *)sve +
364
SVE_PT_FPSIMD_OFFSET);
365
for (i = 0; i < 32; ++i) {
366
p = (unsigned char *)&fpsimd->vregs[i];
367
368
for (j = 0; j < sizeof(fpsimd->vregs[i]); ++j)
369
p[j] = j;
370
}
371
372
/* This should only succeed for SVE */
373
ret = set_sve(child, type, sve);
374
ksft_test_result((type->regset == NT_ARM_SVE) == (ret == 0),
375
"%s FPSIMD set via SVE: %d\n",
376
type->name, ret);
377
if (ret)
378
goto out;
379
380
/* Verify via the FPSIMD regset */
381
if (get_fpsimd(child, &new_fpsimd)) {
382
ksft_test_result_fail("get_fpsimd(): %s\n",
383
strerror(errno));
384
goto out;
385
}
386
if (memcmp(fpsimd, &new_fpsimd, sizeof(*fpsimd)) == 0)
387
ksft_test_result_pass("%s get_fpsimd() gave same state\n",
388
type->name);
389
else
390
ksft_test_result_fail("%s get_fpsimd() gave different state\n",
391
type->name);
392
393
out:
394
free(svebuf);
395
}
396
397
/* Write the FPSIMD registers via the SVE regset when SVE is not supported */
398
static void ptrace_sve_fpsimd_no_sve(pid_t child)
399
{
400
void *svebuf;
401
struct user_sve_header *sve;
402
struct user_fpsimd_state *fpsimd, new_fpsimd;
403
unsigned int i, j;
404
unsigned char *p;
405
int ret;
406
407
svebuf = malloc(SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD));
408
if (!svebuf) {
409
ksft_test_result_fail("Failed to allocate FPSIMD buffer\n");
410
return;
411
}
412
413
/* On a system without SVE the VL should be set to 0 */
414
memset(svebuf, 0, SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD));
415
sve = svebuf;
416
sve->flags = SVE_PT_REGS_FPSIMD;
417
sve->size = SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD);
418
sve->vl = 0;
419
420
/* Try to set a known FPSIMD state via PT_REGS_SVE */
421
fpsimd = (struct user_fpsimd_state *)((char *)sve +
422
SVE_PT_FPSIMD_OFFSET);
423
for (i = 0; i < 32; ++i) {
424
p = (unsigned char *)&fpsimd->vregs[i];
425
426
for (j = 0; j < sizeof(fpsimd->vregs[i]); ++j)
427
p[j] = j;
428
}
429
430
ret = set_sve(child, &vec_types[0], sve);
431
ksft_test_result(ret == 0, "FPSIMD write via SVE\n");
432
if (ret) {
433
ksft_test_result_skip("Verify FPSIMD write via SVE\n");
434
goto out;
435
}
436
437
/* Verify via the FPSIMD regset */
438
if (get_fpsimd(child, &new_fpsimd)) {
439
ksft_test_result_skip("Verify FPSIMD write via SVE\n");
440
goto out;
441
}
442
ksft_test_result(memcmp(fpsimd, &new_fpsimd, sizeof(*fpsimd)) == 0,
443
"Verify FPSIMD write via SVE\n");
444
445
out:
446
free(svebuf);
447
}
448
449
/* Validate attempting to set SVE data and read SVE data */
450
static void ptrace_set_sve_get_sve_data(pid_t child,
451
const struct vec_type *type,
452
unsigned int vl)
453
{
454
void *write_buf;
455
void *read_buf = NULL;
456
struct user_sve_header *write_sve;
457
struct user_sve_header *read_sve;
458
size_t read_sve_size = 0;
459
unsigned int vq = sve_vq_from_vl(vl);
460
int ret, i;
461
size_t data_size;
462
int errors = 0;
463
464
data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);
465
write_buf = malloc(data_size);
466
if (!write_buf) {
467
ksft_test_result_fail("Error allocating %ld byte buffer for %s VL %u\n",
468
data_size, type->name, vl);
469
return;
470
}
471
write_sve = write_buf;
472
473
/* Set up some data and write it out */
474
memset(write_sve, 0, data_size);
475
write_sve->size = data_size;
476
write_sve->vl = vl;
477
write_sve->flags = SVE_PT_REGS_SVE;
478
479
for (i = 0; i < __SVE_NUM_ZREGS; i++)
480
fill_buf(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
481
SVE_PT_SVE_ZREG_SIZE(vq));
482
483
for (i = 0; i < __SVE_NUM_PREGS; i++)
484
fill_buf(write_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),
485
SVE_PT_SVE_PREG_SIZE(vq));
486
487
fill_buf(write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), SVE_PT_SVE_FPSR_SIZE);
488
fill_buf(write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), SVE_PT_SVE_FPCR_SIZE);
489
490
/* TODO: Generate a valid FFR pattern */
491
492
ret = set_sve(child, type, write_sve);
493
if (ret != 0) {
494
ksft_test_result_fail("Failed to set %s VL %u data\n",
495
type->name, vl);
496
goto out;
497
}
498
499
/* Read the data back */
500
if (!get_sve(child, type, (void **)&read_buf, &read_sve_size)) {
501
ksft_test_result_fail("Failed to read %s VL %u data\n",
502
type->name, vl);
503
goto out;
504
}
505
read_sve = read_buf;
506
507
/* We might read more data if there's extensions we don't know */
508
if (read_sve->size < write_sve->size) {
509
ksft_test_result_fail("%s wrote %d bytes, only read %d\n",
510
type->name, write_sve->size,
511
read_sve->size);
512
goto out_read;
513
}
514
515
for (i = 0; i < __SVE_NUM_ZREGS; i++) {
516
if (memcmp(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
517
read_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
518
SVE_PT_SVE_ZREG_SIZE(vq)) != 0) {
519
printf("# Mismatch in %u Z%d\n", vl, i);
520
errors++;
521
}
522
}
523
524
for (i = 0; i < __SVE_NUM_PREGS; i++) {
525
if (memcmp(write_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),
526
read_buf + SVE_PT_SVE_PREG_OFFSET(vq, i),
527
SVE_PT_SVE_PREG_SIZE(vq)) != 0) {
528
printf("# Mismatch in %u P%d\n", vl, i);
529
errors++;
530
}
531
}
532
533
check_u32(vl, "FPSR", write_buf + SVE_PT_SVE_FPSR_OFFSET(vq),
534
read_buf + SVE_PT_SVE_FPSR_OFFSET(vq), &errors);
535
check_u32(vl, "FPCR", write_buf + SVE_PT_SVE_FPCR_OFFSET(vq),
536
read_buf + SVE_PT_SVE_FPCR_OFFSET(vq), &errors);
537
538
ksft_test_result(errors == 0, "Set and get %s data for VL %u\n",
539
type->name, vl);
540
541
out_read:
542
free(read_buf);
543
out:
544
free(write_buf);
545
}
546
547
/* Validate attempting to set SVE data and read it via the FPSIMD regset */
548
static void ptrace_set_sve_get_fpsimd_data(pid_t child,
549
const struct vec_type *type,
550
unsigned int vl)
551
{
552
void *write_buf;
553
struct user_sve_header *write_sve;
554
unsigned int vq = sve_vq_from_vl(vl);
555
struct user_fpsimd_state fpsimd_state;
556
int ret, i;
557
size_t data_size;
558
int errors = 0;
559
560
if (__BYTE_ORDER == __BIG_ENDIAN) {
561
ksft_test_result_skip("Big endian not supported\n");
562
return;
563
}
564
565
data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);
566
write_buf = malloc(data_size);
567
if (!write_buf) {
568
ksft_test_result_fail("Error allocating %ld byte buffer for %s VL %u\n",
569
data_size, type->name, vl);
570
return;
571
}
572
write_sve = write_buf;
573
574
/* Set up some data and write it out */
575
memset(write_sve, 0, data_size);
576
write_sve->size = data_size;
577
write_sve->vl = vl;
578
write_sve->flags = SVE_PT_REGS_SVE;
579
580
for (i = 0; i < __SVE_NUM_ZREGS; i++)
581
fill_buf(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
582
SVE_PT_SVE_ZREG_SIZE(vq));
583
584
fill_buf(write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), SVE_PT_SVE_FPSR_SIZE);
585
fill_buf(write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), SVE_PT_SVE_FPCR_SIZE);
586
587
ret = set_sve(child, type, write_sve);
588
if (ret != 0) {
589
ksft_test_result_fail("Failed to set %s VL %u data\n",
590
type->name, vl);
591
goto out;
592
}
593
594
/* Read the data back */
595
if (get_fpsimd(child, &fpsimd_state)) {
596
ksft_test_result_fail("Failed to read %s VL %u FPSIMD data\n",
597
type->name, vl);
598
goto out;
599
}
600
601
for (i = 0; i < __SVE_NUM_ZREGS; i++) {
602
__uint128_t tmp = 0;
603
604
/*
605
* Z regs are stored endianness invariant, this won't
606
* work for big endian
607
*/
608
memcpy(&tmp, write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
609
sizeof(tmp));
610
611
if (tmp != fpsimd_state.vregs[i]) {
612
printf("# Mismatch in FPSIMD for %s VL %u Z%d\n",
613
type->name, vl, i);
614
errors++;
615
}
616
}
617
618
check_u32(vl, "FPSR", write_buf + SVE_PT_SVE_FPSR_OFFSET(vq),
619
&fpsimd_state.fpsr, &errors);
620
check_u32(vl, "FPCR", write_buf + SVE_PT_SVE_FPCR_OFFSET(vq),
621
&fpsimd_state.fpcr, &errors);
622
623
ksft_test_result(errors == 0, "Set and get FPSIMD data for %s VL %u\n",
624
type->name, vl);
625
626
out:
627
free(write_buf);
628
}
629
630
/* Validate attempting to set FPSIMD data and read it via the SVE regset */
631
static void ptrace_set_fpsimd_get_sve_data(pid_t child,
632
const struct vec_type *type,
633
unsigned int vl)
634
{
635
void *read_buf = NULL;
636
unsigned char *p;
637
struct user_sve_header *read_sve;
638
unsigned int vq = sve_vq_from_vl(vl);
639
struct user_fpsimd_state write_fpsimd;
640
int ret, i, j;
641
size_t read_sve_size = 0;
642
size_t expected_size;
643
int errors = 0;
644
645
if (__BYTE_ORDER == __BIG_ENDIAN) {
646
ksft_test_result_skip("Big endian not supported\n");
647
return;
648
}
649
650
for (i = 0; i < 32; ++i) {
651
p = (unsigned char *)&write_fpsimd.vregs[i];
652
653
for (j = 0; j < sizeof(write_fpsimd.vregs[i]); ++j)
654
p[j] = j;
655
}
656
657
ret = set_fpsimd(child, &write_fpsimd);
658
if (ret != 0) {
659
ksft_test_result_fail("Failed to set FPSIMD state: %d\n)",
660
ret);
661
return;
662
}
663
664
if (!get_sve(child, type, (void **)&read_buf, &read_sve_size)) {
665
ksft_test_result_fail("Failed to read %s VL %u data\n",
666
type->name, vl);
667
return;
668
}
669
read_sve = read_buf;
670
671
if (read_sve->vl != vl) {
672
ksft_test_result_fail("Child VL != expected VL: %u != %u\n",
673
read_sve->vl, vl);
674
goto out;
675
}
676
677
/* The kernel may return either SVE or FPSIMD format */
678
switch (read_sve->flags & SVE_PT_REGS_MASK) {
679
case SVE_PT_REGS_FPSIMD:
680
expected_size = SVE_PT_FPSIMD_SIZE(vq, SVE_PT_REGS_FPSIMD);
681
if (read_sve_size < expected_size) {
682
ksft_test_result_fail("Read %ld bytes, expected %ld\n",
683
read_sve_size, expected_size);
684
goto out;
685
}
686
687
ret = memcmp(&write_fpsimd, read_buf + SVE_PT_FPSIMD_OFFSET,
688
sizeof(write_fpsimd));
689
if (ret != 0) {
690
ksft_print_msg("Read FPSIMD data mismatch\n");
691
errors++;
692
}
693
break;
694
695
case SVE_PT_REGS_SVE:
696
expected_size = SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE);
697
if (read_sve_size < expected_size) {
698
ksft_test_result_fail("Read %ld bytes, expected %ld\n",
699
read_sve_size, expected_size);
700
goto out;
701
}
702
703
for (i = 0; i < __SVE_NUM_ZREGS; i++) {
704
__uint128_t tmp = 0;
705
706
/*
707
* Z regs are stored endianness invariant, this won't
708
* work for big endian
709
*/
710
memcpy(&tmp, read_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i),
711
sizeof(tmp));
712
713
if (tmp != write_fpsimd.vregs[i]) {
714
ksft_print_msg("Mismatch in FPSIMD for %s VL %u Z%d/V%d\n",
715
type->name, vl, i, i);
716
errors++;
717
}
718
}
719
720
check_u32(vl, "FPSR", &write_fpsimd.fpsr,
721
read_buf + SVE_PT_SVE_FPSR_OFFSET(vq), &errors);
722
check_u32(vl, "FPCR", &write_fpsimd.fpcr,
723
read_buf + SVE_PT_SVE_FPCR_OFFSET(vq), &errors);
724
break;
725
default:
726
ksft_print_msg("Unexpected regs type %d\n",
727
read_sve->flags & SVE_PT_REGS_MASK);
728
errors++;
729
break;
730
}
731
732
ksft_test_result(errors == 0, "Set FPSIMD, read via SVE for %s VL %u\n",
733
type->name, vl);
734
735
out:
736
free(read_buf);
737
}
738
739
static int do_parent(pid_t child)
740
{
741
int ret = EXIT_FAILURE;
742
pid_t pid;
743
int status, i;
744
siginfo_t si;
745
unsigned int vq, vl;
746
bool vl_supported;
747
748
ksft_print_msg("Parent is %d, child is %d\n", getpid(), child);
749
750
/* Attach to the child */
751
while (1) {
752
int sig;
753
754
pid = wait(&status);
755
if (pid == -1) {
756
perror("wait");
757
goto error;
758
}
759
760
/*
761
* This should never happen but it's hard to flag in
762
* the framework.
763
*/
764
if (pid != child)
765
continue;
766
767
if (WIFEXITED(status) || WIFSIGNALED(status))
768
ksft_exit_fail_msg("Child died unexpectedly\n");
769
770
if (!WIFSTOPPED(status))
771
goto error;
772
773
sig = WSTOPSIG(status);
774
775
if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {
776
if (errno == ESRCH)
777
goto disappeared;
778
779
if (errno == EINVAL) {
780
sig = 0; /* bust group-stop */
781
goto cont;
782
}
783
784
ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n",
785
strerror(errno));
786
goto error;
787
}
788
789
if (sig == SIGSTOP && si.si_code == SI_TKILL &&
790
si.si_pid == pid)
791
break;
792
793
cont:
794
if (ptrace(PTRACE_CONT, pid, NULL, sig)) {
795
if (errno == ESRCH)
796
goto disappeared;
797
798
ksft_test_result_fail("PTRACE_CONT: %s\n",
799
strerror(errno));
800
goto error;
801
}
802
}
803
804
for (i = 0; i < ARRAY_SIZE(vec_types); i++) {
805
/*
806
* If the vector type isn't supported reads and writes
807
* should fail.
808
*/
809
if (!(getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap)) {
810
read_fails(child, &vec_types[i]);
811
write_fails(child, &vec_types[i]);
812
} else {
813
ksft_test_result_skip("%s unsupported read fails\n",
814
vec_types[i].name);
815
ksft_test_result_skip("%s unsupported write fails\n",
816
vec_types[i].name);
817
}
818
819
/* FPSIMD via SVE regset */
820
if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {
821
ptrace_sve_fpsimd(child, &vec_types[i]);
822
} else {
823
ksft_test_result_skip("%s FPSIMD set via SVE\n",
824
vec_types[i].name);
825
ksft_test_result_skip("%s FPSIMD read\n",
826
vec_types[i].name);
827
}
828
829
/* prctl() flags */
830
if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {
831
ptrace_set_get_inherit(child, &vec_types[i]);
832
} else {
833
ksft_test_result_skip("%s SVE_PT_VL_INHERIT set\n",
834
vec_types[i].name);
835
ksft_test_result_skip("%s SVE_PT_VL_INHERIT cleared\n",
836
vec_types[i].name);
837
}
838
839
/* Setting out of bounds VLs should fail */
840
if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) {
841
ptrace_set_vl_ranges(child, &vec_types[i]);
842
} else {
843
ksft_test_result_skip("%s Set invalid VL 0\n",
844
vec_types[i].name);
845
ksft_test_result_skip("%s Set invalid VL %d\n",
846
vec_types[i].name,
847
SVE_VL_MAX + SVE_VQ_BYTES);
848
}
849
850
/* Step through every possible VQ */
851
for (vq = SVE_VQ_MIN; vq <= TEST_VQ_MAX; vq++) {
852
vl = sve_vl_from_vq(vq);
853
854
/* First, try to set this vector length */
855
if (getauxval(vec_types[i].hwcap_type) &
856
vec_types[i].hwcap) {
857
ptrace_set_get_vl(child, &vec_types[i], vl,
858
&vl_supported);
859
} else {
860
ksft_test_result_skip("%s get/set VL %d\n",
861
vec_types[i].name, vl);
862
vl_supported = false;
863
}
864
865
/* If the VL is supported validate data set/get */
866
if (vl_supported) {
867
ptrace_set_sve_get_sve_data(child, &vec_types[i], vl);
868
ptrace_set_sve_get_fpsimd_data(child, &vec_types[i], vl);
869
ptrace_set_fpsimd_get_sve_data(child, &vec_types[i], vl);
870
} else {
871
ksft_test_result_skip("%s set SVE get SVE for VL %d\n",
872
vec_types[i].name, vl);
873
ksft_test_result_skip("%s set SVE get FPSIMD for VL %d\n",
874
vec_types[i].name, vl);
875
ksft_test_result_skip("%s set FPSIMD get SVE for VL %d\n",
876
vec_types[i].name, vl);
877
}
878
}
879
}
880
881
/* We support SVE writes of FPSMID format on SME only systems */
882
if (!(getauxval(AT_HWCAP) & HWCAP_SVE) &&
883
(getauxval(AT_HWCAP2) & HWCAP2_SME)) {
884
ptrace_sve_fpsimd_no_sve(child);
885
} else {
886
ksft_test_result_skip("FPSIMD write via SVE\n");
887
ksft_test_result_skip("Verify FPSIMD write via SVE\n");
888
}
889
890
ret = EXIT_SUCCESS;
891
892
error:
893
kill(child, SIGKILL);
894
895
disappeared:
896
return ret;
897
}
898
899
int main(void)
900
{
901
int ret = EXIT_SUCCESS;
902
pid_t child;
903
904
srandom(getpid());
905
906
ksft_print_header();
907
ksft_set_plan(EXPECTED_TESTS);
908
909
child = fork();
910
if (!child)
911
return do_child();
912
913
if (do_parent(child))
914
ret = EXIT_FAILURE;
915
916
ksft_print_cnts();
917
918
return ret;
919
}
920
921