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