sve-ptrace.c (18356B)
1// SPDX-License-Identifier: GPL-2.0-only 2/* 3 * Copyright (C) 2015-2021 ARM Limited. 4 * Original author: Dave Martin <Dave.Martin@arm.com> 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 33struct vec_type { 34 const char *name; 35 unsigned long hwcap_type; 36 unsigned long hwcap; 37 int regset; 38 int prctl_set; 39}; 40 41static const struct vec_type vec_types[] = { 42 { 43 .name = "SVE", 44 .hwcap_type = AT_HWCAP, 45 .hwcap = HWCAP_SVE, 46 .regset = NT_ARM_SVE, 47 .prctl_set = PR_SVE_SET_VL, 48 }, 49 { 50 .name = "Streaming SVE", 51 .hwcap_type = AT_HWCAP2, 52 .hwcap = HWCAP2_SME, 53 .regset = NT_ARM_SSVE, 54 .prctl_set = PR_SME_SET_VL, 55 }, 56}; 57 58#define VL_TESTS (((SVE_VQ_MAX - SVE_VQ_MIN) + 1) * 4) 59#define FLAG_TESTS 2 60#define FPSIMD_TESTS 2 61 62#define EXPECTED_TESTS ((VL_TESTS + FLAG_TESTS + FPSIMD_TESTS) * ARRAY_SIZE(vec_types)) 63 64static void fill_buf(char *buf, size_t size) 65{ 66 int i; 67 68 for (i = 0; i < size; i++) 69 buf[i] = random(); 70} 71 72static int do_child(void) 73{ 74 if (ptrace(PTRACE_TRACEME, -1, NULL, NULL)) 75 ksft_exit_fail_msg("PTRACE_TRACEME", strerror(errno)); 76 77 if (raise(SIGSTOP)) 78 ksft_exit_fail_msg("raise(SIGSTOP)", strerror(errno)); 79 80 return EXIT_SUCCESS; 81} 82 83static int get_fpsimd(pid_t pid, struct user_fpsimd_state *fpsimd) 84{ 85 struct iovec iov; 86 87 iov.iov_base = fpsimd; 88 iov.iov_len = sizeof(*fpsimd); 89 return ptrace(PTRACE_GETREGSET, pid, NT_PRFPREG, &iov); 90} 91 92static int set_fpsimd(pid_t pid, struct user_fpsimd_state *fpsimd) 93{ 94 struct iovec iov; 95 96 iov.iov_base = fpsimd; 97 iov.iov_len = sizeof(*fpsimd); 98 return ptrace(PTRACE_SETREGSET, pid, NT_PRFPREG, &iov); 99} 100 101static struct user_sve_header *get_sve(pid_t pid, const struct vec_type *type, 102 void **buf, size_t *size) 103{ 104 struct user_sve_header *sve; 105 void *p; 106 size_t sz = sizeof *sve; 107 struct iovec iov; 108 109 while (1) { 110 if (*size < sz) { 111 p = realloc(*buf, sz); 112 if (!p) { 113 errno = ENOMEM; 114 goto error; 115 } 116 117 *buf = p; 118 *size = sz; 119 } 120 121 iov.iov_base = *buf; 122 iov.iov_len = sz; 123 if (ptrace(PTRACE_GETREGSET, pid, type->regset, &iov)) 124 goto error; 125 126 sve = *buf; 127 if (sve->size <= sz) 128 break; 129 130 sz = sve->size; 131 } 132 133 return sve; 134 135error: 136 return NULL; 137} 138 139static int set_sve(pid_t pid, const struct vec_type *type, 140 const struct user_sve_header *sve) 141{ 142 struct iovec iov; 143 144 iov.iov_base = (void *)sve; 145 iov.iov_len = sve->size; 146 return ptrace(PTRACE_SETREGSET, pid, type->regset, &iov); 147} 148 149/* Validate setting and getting the inherit flag */ 150static void ptrace_set_get_inherit(pid_t child, const struct vec_type *type) 151{ 152 struct user_sve_header sve; 153 struct user_sve_header *new_sve = NULL; 154 size_t new_sve_size = 0; 155 int ret; 156 157 /* First set the flag */ 158 memset(&sve, 0, sizeof(sve)); 159 sve.size = sizeof(sve); 160 sve.vl = sve_vl_from_vq(SVE_VQ_MIN); 161 sve.flags = SVE_PT_VL_INHERIT; 162 ret = set_sve(child, type, &sve); 163 if (ret != 0) { 164 ksft_test_result_fail("Failed to set %s SVE_PT_VL_INHERIT\n", 165 type->name); 166 return; 167 } 168 169 /* 170 * Read back the new register state and verify that we have 171 * set the flags we expected. 172 */ 173 if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) { 174 ksft_test_result_fail("Failed to read %s SVE flags\n", 175 type->name); 176 return; 177 } 178 179 ksft_test_result(new_sve->flags & SVE_PT_VL_INHERIT, 180 "%s SVE_PT_VL_INHERIT set\n", type->name); 181 182 /* Now clear */ 183 sve.flags &= ~SVE_PT_VL_INHERIT; 184 ret = set_sve(child, type, &sve); 185 if (ret != 0) { 186 ksft_test_result_fail("Failed to clear %s SVE_PT_VL_INHERIT\n", 187 type->name); 188 return; 189 } 190 191 if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) { 192 ksft_test_result_fail("Failed to read %s SVE flags\n", 193 type->name); 194 return; 195 } 196 197 ksft_test_result(!(new_sve->flags & SVE_PT_VL_INHERIT), 198 "%s SVE_PT_VL_INHERIT cleared\n", type->name); 199 200 free(new_sve); 201} 202 203/* Validate attempting to set the specfied VL via ptrace */ 204static void ptrace_set_get_vl(pid_t child, const struct vec_type *type, 205 unsigned int vl, bool *supported) 206{ 207 struct user_sve_header sve; 208 struct user_sve_header *new_sve = NULL; 209 size_t new_sve_size = 0; 210 int ret, prctl_vl; 211 212 *supported = false; 213 214 /* Check if the VL is supported in this process */ 215 prctl_vl = prctl(type->prctl_set, vl); 216 if (prctl_vl == -1) 217 ksft_exit_fail_msg("prctl(PR_%s_SET_VL) failed: %s (%d)\n", 218 type->name, strerror(errno), errno); 219 220 /* If the VL is not supported then a supported VL will be returned */ 221 *supported = (prctl_vl == vl); 222 223 /* Set the VL by doing a set with no register payload */ 224 memset(&sve, 0, sizeof(sve)); 225 sve.size = sizeof(sve); 226 sve.vl = vl; 227 ret = set_sve(child, type, &sve); 228 if (ret != 0) { 229 ksft_test_result_fail("Failed to set %s VL %u\n", 230 type->name, vl); 231 return; 232 } 233 234 /* 235 * Read back the new register state and verify that we have the 236 * same VL that we got from prctl() on ourselves. 237 */ 238 if (!get_sve(child, type, (void **)&new_sve, &new_sve_size)) { 239 ksft_test_result_fail("Failed to read %s VL %u\n", 240 type->name, vl); 241 return; 242 } 243 244 ksft_test_result(new_sve->vl = prctl_vl, "Set %s VL %u\n", 245 type->name, vl); 246 247 free(new_sve); 248} 249 250static void check_u32(unsigned int vl, const char *reg, 251 uint32_t *in, uint32_t *out, int *errors) 252{ 253 if (*in != *out) { 254 printf("# VL %d %s wrote %x read %x\n", 255 vl, reg, *in, *out); 256 (*errors)++; 257 } 258} 259 260/* Access the FPSIMD registers via the SVE regset */ 261static void ptrace_sve_fpsimd(pid_t child, const struct vec_type *type) 262{ 263 void *svebuf; 264 struct user_sve_header *sve; 265 struct user_fpsimd_state *fpsimd, new_fpsimd; 266 unsigned int i, j; 267 unsigned char *p; 268 int ret; 269 270 svebuf = malloc(SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD)); 271 if (!svebuf) { 272 ksft_test_result_fail("Failed to allocate FPSIMD buffer\n"); 273 return; 274 } 275 276 memset(svebuf, 0, SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD)); 277 sve = svebuf; 278 sve->flags = SVE_PT_REGS_FPSIMD; 279 sve->size = SVE_PT_SIZE(0, SVE_PT_REGS_FPSIMD); 280 sve->vl = 16; /* We don't care what the VL is */ 281 282 /* Try to set a known FPSIMD state via PT_REGS_SVE */ 283 fpsimd = (struct user_fpsimd_state *)((char *)sve + 284 SVE_PT_FPSIMD_OFFSET); 285 for (i = 0; i < 32; ++i) { 286 p = (unsigned char *)&fpsimd->vregs[i]; 287 288 for (j = 0; j < sizeof(fpsimd->vregs[i]); ++j) 289 p[j] = j; 290 } 291 292 ret = set_sve(child, type, sve); 293 ksft_test_result(ret == 0, "%s FPSIMD set via SVE: %d\n", 294 type->name, ret); 295 if (ret) 296 goto out; 297 298 /* Verify via the FPSIMD regset */ 299 if (get_fpsimd(child, &new_fpsimd)) { 300 ksft_test_result_fail("get_fpsimd(): %s\n", 301 strerror(errno)); 302 goto out; 303 } 304 if (memcmp(fpsimd, &new_fpsimd, sizeof(*fpsimd)) == 0) 305 ksft_test_result_pass("%s get_fpsimd() gave same state\n", 306 type->name); 307 else 308 ksft_test_result_fail("%s get_fpsimd() gave different state\n", 309 type->name); 310 311out: 312 free(svebuf); 313} 314 315/* Validate attempting to set SVE data and read SVE data */ 316static void ptrace_set_sve_get_sve_data(pid_t child, 317 const struct vec_type *type, 318 unsigned int vl) 319{ 320 void *write_buf; 321 void *read_buf = NULL; 322 struct user_sve_header *write_sve; 323 struct user_sve_header *read_sve; 324 size_t read_sve_size = 0; 325 unsigned int vq = sve_vq_from_vl(vl); 326 int ret, i; 327 size_t data_size; 328 int errors = 0; 329 330 data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE); 331 write_buf = malloc(data_size); 332 if (!write_buf) { 333 ksft_test_result_fail("Error allocating %d byte buffer for %s VL %u\n", 334 data_size, type->name, vl); 335 return; 336 } 337 write_sve = write_buf; 338 339 /* Set up some data and write it out */ 340 memset(write_sve, 0, data_size); 341 write_sve->size = data_size; 342 write_sve->vl = vl; 343 write_sve->flags = SVE_PT_REGS_SVE; 344 345 for (i = 0; i < __SVE_NUM_ZREGS; i++) 346 fill_buf(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i), 347 SVE_PT_SVE_ZREG_SIZE(vq)); 348 349 for (i = 0; i < __SVE_NUM_PREGS; i++) 350 fill_buf(write_buf + SVE_PT_SVE_PREG_OFFSET(vq, i), 351 SVE_PT_SVE_PREG_SIZE(vq)); 352 353 fill_buf(write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), SVE_PT_SVE_FPSR_SIZE); 354 fill_buf(write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), SVE_PT_SVE_FPCR_SIZE); 355 356 /* TODO: Generate a valid FFR pattern */ 357 358 ret = set_sve(child, type, write_sve); 359 if (ret != 0) { 360 ksft_test_result_fail("Failed to set %s VL %u data\n", 361 type->name, vl); 362 goto out; 363 } 364 365 /* Read the data back */ 366 if (!get_sve(child, type, (void **)&read_buf, &read_sve_size)) { 367 ksft_test_result_fail("Failed to read %s VL %u data\n", 368 type->name, vl); 369 goto out; 370 } 371 read_sve = read_buf; 372 373 /* We might read more data if there's extensions we don't know */ 374 if (read_sve->size < write_sve->size) { 375 ksft_test_result_fail("%s wrote %d bytes, only read %d\n", 376 type->name, write_sve->size, 377 read_sve->size); 378 goto out_read; 379 } 380 381 for (i = 0; i < __SVE_NUM_ZREGS; i++) { 382 if (memcmp(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i), 383 read_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i), 384 SVE_PT_SVE_ZREG_SIZE(vq)) != 0) { 385 printf("# Mismatch in %u Z%d\n", vl, i); 386 errors++; 387 } 388 } 389 390 for (i = 0; i < __SVE_NUM_PREGS; i++) { 391 if (memcmp(write_buf + SVE_PT_SVE_PREG_OFFSET(vq, i), 392 read_buf + SVE_PT_SVE_PREG_OFFSET(vq, i), 393 SVE_PT_SVE_PREG_SIZE(vq)) != 0) { 394 printf("# Mismatch in %u P%d\n", vl, i); 395 errors++; 396 } 397 } 398 399 check_u32(vl, "FPSR", write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), 400 read_buf + SVE_PT_SVE_FPSR_OFFSET(vq), &errors); 401 check_u32(vl, "FPCR", write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), 402 read_buf + SVE_PT_SVE_FPCR_OFFSET(vq), &errors); 403 404 ksft_test_result(errors == 0, "Set and get %s data for VL %u\n", 405 type->name, vl); 406 407out_read: 408 free(read_buf); 409out: 410 free(write_buf); 411} 412 413/* Validate attempting to set SVE data and read it via the FPSIMD regset */ 414static void ptrace_set_sve_get_fpsimd_data(pid_t child, 415 const struct vec_type *type, 416 unsigned int vl) 417{ 418 void *write_buf; 419 struct user_sve_header *write_sve; 420 unsigned int vq = sve_vq_from_vl(vl); 421 struct user_fpsimd_state fpsimd_state; 422 int ret, i; 423 size_t data_size; 424 int errors = 0; 425 426 if (__BYTE_ORDER == __BIG_ENDIAN) { 427 ksft_test_result_skip("Big endian not supported\n"); 428 return; 429 } 430 431 data_size = SVE_PT_SVE_OFFSET + SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE); 432 write_buf = malloc(data_size); 433 if (!write_buf) { 434 ksft_test_result_fail("Error allocating %d byte buffer for %s VL %u\n", 435 data_size, type->name, vl); 436 return; 437 } 438 write_sve = write_buf; 439 440 /* Set up some data and write it out */ 441 memset(write_sve, 0, data_size); 442 write_sve->size = data_size; 443 write_sve->vl = vl; 444 write_sve->flags = SVE_PT_REGS_SVE; 445 446 for (i = 0; i < __SVE_NUM_ZREGS; i++) 447 fill_buf(write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i), 448 SVE_PT_SVE_ZREG_SIZE(vq)); 449 450 fill_buf(write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), SVE_PT_SVE_FPSR_SIZE); 451 fill_buf(write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), SVE_PT_SVE_FPCR_SIZE); 452 453 ret = set_sve(child, type, write_sve); 454 if (ret != 0) { 455 ksft_test_result_fail("Failed to set %s VL %u data\n", 456 type->name, vl); 457 goto out; 458 } 459 460 /* Read the data back */ 461 if (get_fpsimd(child, &fpsimd_state)) { 462 ksft_test_result_fail("Failed to read %s VL %u FPSIMD data\n", 463 type->name, vl); 464 goto out; 465 } 466 467 for (i = 0; i < __SVE_NUM_ZREGS; i++) { 468 __uint128_t tmp = 0; 469 470 /* 471 * Z regs are stored endianness invariant, this won't 472 * work for big endian 473 */ 474 memcpy(&tmp, write_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i), 475 sizeof(tmp)); 476 477 if (tmp != fpsimd_state.vregs[i]) { 478 printf("# Mismatch in FPSIMD for %s VL %u Z%d\n", 479 type->name, vl, i); 480 errors++; 481 } 482 } 483 484 check_u32(vl, "FPSR", write_buf + SVE_PT_SVE_FPSR_OFFSET(vq), 485 &fpsimd_state.fpsr, &errors); 486 check_u32(vl, "FPCR", write_buf + SVE_PT_SVE_FPCR_OFFSET(vq), 487 &fpsimd_state.fpcr, &errors); 488 489 ksft_test_result(errors == 0, "Set and get FPSIMD data for %s VL %u\n", 490 type->name, vl); 491 492out: 493 free(write_buf); 494} 495 496/* Validate attempting to set FPSIMD data and read it via the SVE regset */ 497static void ptrace_set_fpsimd_get_sve_data(pid_t child, 498 const struct vec_type *type, 499 unsigned int vl) 500{ 501 void *read_buf = NULL; 502 unsigned char *p; 503 struct user_sve_header *read_sve; 504 unsigned int vq = sve_vq_from_vl(vl); 505 struct user_fpsimd_state write_fpsimd; 506 int ret, i, j; 507 size_t read_sve_size = 0; 508 size_t expected_size; 509 int errors = 0; 510 511 if (__BYTE_ORDER == __BIG_ENDIAN) { 512 ksft_test_result_skip("Big endian not supported\n"); 513 return; 514 } 515 516 for (i = 0; i < 32; ++i) { 517 p = (unsigned char *)&write_fpsimd.vregs[i]; 518 519 for (j = 0; j < sizeof(write_fpsimd.vregs[i]); ++j) 520 p[j] = j; 521 } 522 523 ret = set_fpsimd(child, &write_fpsimd); 524 if (ret != 0) { 525 ksft_test_result_fail("Failed to set FPSIMD state: %d\n)", 526 ret); 527 return; 528 } 529 530 if (!get_sve(child, type, (void **)&read_buf, &read_sve_size)) { 531 ksft_test_result_fail("Failed to read %s VL %u data\n", 532 type->name, vl); 533 return; 534 } 535 read_sve = read_buf; 536 537 if (read_sve->vl != vl) { 538 ksft_test_result_fail("Child VL != expected VL %d\n", 539 read_sve->vl, vl); 540 goto out; 541 } 542 543 /* The kernel may return either SVE or FPSIMD format */ 544 switch (read_sve->flags & SVE_PT_REGS_MASK) { 545 case SVE_PT_REGS_FPSIMD: 546 expected_size = SVE_PT_FPSIMD_SIZE(vq, SVE_PT_REGS_FPSIMD); 547 if (read_sve_size < expected_size) { 548 ksft_test_result_fail("Read %d bytes, expected %d\n", 549 read_sve_size, expected_size); 550 goto out; 551 } 552 553 ret = memcmp(&write_fpsimd, read_buf + SVE_PT_FPSIMD_OFFSET, 554 sizeof(write_fpsimd)); 555 if (ret != 0) { 556 ksft_print_msg("Read FPSIMD data mismatch\n"); 557 errors++; 558 } 559 break; 560 561 case SVE_PT_REGS_SVE: 562 expected_size = SVE_PT_SVE_SIZE(vq, SVE_PT_REGS_SVE); 563 if (read_sve_size < expected_size) { 564 ksft_test_result_fail("Read %d bytes, expected %d\n", 565 read_sve_size, expected_size); 566 goto out; 567 } 568 569 for (i = 0; i < __SVE_NUM_ZREGS; i++) { 570 __uint128_t tmp = 0; 571 572 /* 573 * Z regs are stored endianness invariant, this won't 574 * work for big endian 575 */ 576 memcpy(&tmp, read_buf + SVE_PT_SVE_ZREG_OFFSET(vq, i), 577 sizeof(tmp)); 578 579 if (tmp != write_fpsimd.vregs[i]) { 580 ksft_print_msg("Mismatch in FPSIMD for %s VL %u Z%d/V%d\n", 581 type->name, vl, i, i); 582 errors++; 583 } 584 } 585 586 check_u32(vl, "FPSR", &write_fpsimd.fpsr, 587 read_buf + SVE_PT_SVE_FPSR_OFFSET(vq), &errors); 588 check_u32(vl, "FPCR", &write_fpsimd.fpcr, 589 read_buf + SVE_PT_SVE_FPCR_OFFSET(vq), &errors); 590 break; 591 default: 592 ksft_print_msg("Unexpected regs type %d\n", 593 read_sve->flags & SVE_PT_REGS_MASK); 594 errors++; 595 break; 596 } 597 598 ksft_test_result(errors == 0, "Set FPSIMD, read via SVE for %s VL %u\n", 599 type->name, vl); 600 601out: 602 free(read_buf); 603} 604 605static int do_parent(pid_t child) 606{ 607 int ret = EXIT_FAILURE; 608 pid_t pid; 609 int status, i; 610 siginfo_t si; 611 unsigned int vq, vl; 612 bool vl_supported; 613 614 ksft_print_msg("Parent is %d, child is %d\n", getpid(), child); 615 616 /* Attach to the child */ 617 while (1) { 618 int sig; 619 620 pid = wait(&status); 621 if (pid == -1) { 622 perror("wait"); 623 goto error; 624 } 625 626 /* 627 * This should never happen but it's hard to flag in 628 * the framework. 629 */ 630 if (pid != child) 631 continue; 632 633 if (WIFEXITED(status) || WIFSIGNALED(status)) 634 ksft_exit_fail_msg("Child died unexpectedly\n"); 635 636 if (!WIFSTOPPED(status)) 637 goto error; 638 639 sig = WSTOPSIG(status); 640 641 if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) { 642 if (errno == ESRCH) 643 goto disappeared; 644 645 if (errno == EINVAL) { 646 sig = 0; /* bust group-stop */ 647 goto cont; 648 } 649 650 ksft_test_result_fail("PTRACE_GETSIGINFO: %s\n", 651 strerror(errno)); 652 goto error; 653 } 654 655 if (sig == SIGSTOP && si.si_code == SI_TKILL && 656 si.si_pid == pid) 657 break; 658 659 cont: 660 if (ptrace(PTRACE_CONT, pid, NULL, sig)) { 661 if (errno == ESRCH) 662 goto disappeared; 663 664 ksft_test_result_fail("PTRACE_CONT: %s\n", 665 strerror(errno)); 666 goto error; 667 } 668 } 669 670 for (i = 0; i < ARRAY_SIZE(vec_types); i++) { 671 /* FPSIMD via SVE regset */ 672 if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) { 673 ptrace_sve_fpsimd(child, &vec_types[i]); 674 } else { 675 ksft_test_result_skip("%s FPSIMD set via SVE\n", 676 vec_types[i].name); 677 ksft_test_result_skip("%s FPSIMD read\n", 678 vec_types[i].name); 679 } 680 681 /* prctl() flags */ 682 if (getauxval(vec_types[i].hwcap_type) & vec_types[i].hwcap) { 683 ptrace_set_get_inherit(child, &vec_types[i]); 684 } else { 685 ksft_test_result_skip("%s SVE_PT_VL_INHERIT set\n", 686 vec_types[i].name); 687 ksft_test_result_skip("%s SVE_PT_VL_INHERIT cleared\n", 688 vec_types[i].name); 689 } 690 691 /* Step through every possible VQ */ 692 for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; vq++) { 693 vl = sve_vl_from_vq(vq); 694 695 /* First, try to set this vector length */ 696 if (getauxval(vec_types[i].hwcap_type) & 697 vec_types[i].hwcap) { 698 ptrace_set_get_vl(child, &vec_types[i], vl, 699 &vl_supported); 700 } else { 701 ksft_test_result_skip("%s get/set VL %d\n", 702 vec_types[i].name, vl); 703 vl_supported = false; 704 } 705 706 /* If the VL is supported validate data set/get */ 707 if (vl_supported) { 708 ptrace_set_sve_get_sve_data(child, &vec_types[i], vl); 709 ptrace_set_sve_get_fpsimd_data(child, &vec_types[i], vl); 710 ptrace_set_fpsimd_get_sve_data(child, &vec_types[i], vl); 711 } else { 712 ksft_test_result_skip("%s set SVE get SVE for VL %d\n", 713 vec_types[i].name, vl); 714 ksft_test_result_skip("%s set SVE get FPSIMD for VL %d\n", 715 vec_types[i].name, vl); 716 ksft_test_result_skip("%s set FPSIMD get SVE for VL %d\n", 717 vec_types[i].name, vl); 718 } 719 } 720 } 721 722 ret = EXIT_SUCCESS; 723 724error: 725 kill(child, SIGKILL); 726 727disappeared: 728 return ret; 729} 730 731int main(void) 732{ 733 int ret = EXIT_SUCCESS; 734 pid_t child; 735 736 srandom(getpid()); 737 738 ksft_print_header(); 739 ksft_set_plan(EXPECTED_TESTS); 740 741 if (!(getauxval(AT_HWCAP) & HWCAP_SVE)) 742 ksft_exit_skip("SVE not available\n"); 743 744 child = fork(); 745 if (!child) 746 return do_child(); 747 748 if (do_parent(child)) 749 ret = EXIT_FAILURE; 750 751 ksft_print_cnts(); 752 753 return ret; 754}