1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2021 ARM Limited. 4 * Original author: Mark Brown <broonie@kernel.org> 5 */ 6 #include <assert.h> 7 #include <errno.h> 8 #include <fcntl.h> 9 #include <stddef.h> 10 #include <stdio.h> 11 #include <stdlib.h> 12 #include <string.h> 13 #include <unistd.h> 14 #include <sys/auxv.h> 15 #include <sys/prctl.h> 16 #include <sys/types.h> 17 #include <sys/wait.h> 18 #include <asm/sigcontext.h> 19 #include <asm/hwcap.h> 20 21 #include "../../kselftest.h" 22 #include "rdvl.h" 23 24 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 25 26 #define ARCH_MIN_VL SVE_VL_MIN 27 28 struct vec_data { 29 const char *name; 30 unsigned long hwcap_type; 31 unsigned long hwcap; 32 const char *rdvl_binary; 33 int (*rdvl)(void); 34 35 int prctl_get; 36 int prctl_set; 37 const char *default_vl_file; 38 39 int default_vl; 40 int min_vl; 41 int max_vl; 42 }; 43 44 45 static struct vec_data vec_data[] = { 46 { 47 .name = "SVE", 48 .hwcap_type = AT_HWCAP, 49 .hwcap = HWCAP_SVE, 50 .rdvl = rdvl_sve, 51 .rdvl_binary = "./rdvl-sve", 52 .prctl_get = PR_SVE_GET_VL, 53 .prctl_set = PR_SVE_SET_VL, 54 .default_vl_file = "/proc/sys/abi/sve_default_vector_length", 55 }, 56 }; 57 58 static int stdio_read_integer(FILE *f, const char *what, int *val) 59 { 60 int n = 0; 61 int ret; 62 63 ret = fscanf(f, "%d%*1[\n]%n", val, &n); 64 if (ret < 1 || n < 1) { 65 ksft_print_msg("failed to parse integer from %s\n", what); 66 return -1; 67 } 68 69 return 0; 70 } 71 72 /* Start a new process and return the vector length it sees */ 73 static int get_child_rdvl(struct vec_data *data) 74 { 75 FILE *out; 76 int pipefd[2]; 77 pid_t pid, child; 78 int read_vl, ret; 79 80 ret = pipe(pipefd); 81 if (ret == -1) { 82 ksft_print_msg("pipe() failed: %d (%s)\n", 83 errno, strerror(errno)); 84 return -1; 85 } 86 87 fflush(stdout); 88 89 child = fork(); 90 if (child == -1) { 91 ksft_print_msg("fork() failed: %d (%s)\n", 92 errno, strerror(errno)); 93 close(pipefd[0]); 94 close(pipefd[1]); 95 return -1; 96 } 97 98 /* Child: put vector length on the pipe */ 99 if (child == 0) { 100 /* 101 * Replace stdout with the pipe, errors to stderr from 102 * here as kselftest prints to stdout. 103 */ 104 ret = dup2(pipefd[1], 1); 105 if (ret == -1) { 106 fprintf(stderr, "dup2() %d\n", errno); 107 exit(EXIT_FAILURE); 108 } 109 110 /* exec() a new binary which puts the VL on stdout */ 111 ret = execl(data->rdvl_binary, data->rdvl_binary, NULL); 112 fprintf(stderr, "execl(%s) failed: %d (%s)\n", 113 data->rdvl_binary, errno, strerror(errno)); 114 115 exit(EXIT_FAILURE); 116 } 117 118 close(pipefd[1]); 119 120 /* Parent; wait for the exit status from the child & verify it */ 121 do { 122 pid = wait(&ret); 123 if (pid == -1) { 124 ksft_print_msg("wait() failed: %d (%s)\n", 125 errno, strerror(errno)); 126 close(pipefd[0]); 127 return -1; 128 } 129 } while (pid != child); 130 131 assert(pid == child); 132 133 if (!WIFEXITED(ret)) { 134 ksft_print_msg("child exited abnormally\n"); 135 close(pipefd[0]); 136 return -1; 137 } 138 139 if (WEXITSTATUS(ret) != 0) { 140 ksft_print_msg("child returned error %d\n", 141 WEXITSTATUS(ret)); 142 close(pipefd[0]); 143 return -1; 144 } 145 146 out = fdopen(pipefd[0], "r"); 147 if (!out) { 148 ksft_print_msg("failed to open child stdout\n"); 149 close(pipefd[0]); 150 return -1; 151 } 152 153 ret = stdio_read_integer(out, "child", &read_vl); 154 fclose(out); 155 if (ret != 0) 156 return ret; 157 158 return read_vl; 159 } 160 161 static int file_read_integer(const char *name, int *val) 162 { 163 FILE *f; 164 int ret; 165 166 f = fopen(name, "r"); 167 if (!f) { 168 ksft_test_result_fail("Unable to open %s: %d (%s)\n", 169 name, errno, 170 strerror(errno)); 171 return -1; 172 } 173 174 ret = stdio_read_integer(f, name, val); 175 fclose(f); 176 177 return ret; 178 } 179 180 static int file_write_integer(const char *name, int val) 181 { 182 FILE *f; 183 184 f = fopen(name, "w"); 185 if (!f) { 186 ksft_test_result_fail("Unable to open %s: %d (%s)\n", 187 name, errno, 188 strerror(errno)); 189 return -1; 190 } 191 192 fprintf(f, "%d", val); 193 fclose(f); 194 195 return 0; 196 } 197 198 /* 199 * Verify that we can read the default VL via proc, checking that it 200 * is set in a freshly spawned child. 201 */ 202 static void proc_read_default(struct vec_data *data) 203 { 204 int default_vl, child_vl, ret; 205 206 ret = file_read_integer(data->default_vl_file, &default_vl); 207 if (ret != 0) 208 return; 209 210 /* Is this the actual default seen by new processes? */ 211 child_vl = get_child_rdvl(data); 212 if (child_vl != default_vl) { 213 ksft_test_result_fail("%s is %d but child VL is %d\n", 214 data->default_vl_file, 215 default_vl, child_vl); 216 return; 217 } 218 219 ksft_test_result_pass("%s default vector length %d\n", data->name, 220 default_vl); 221 data->default_vl = default_vl; 222 } 223 224 /* Verify that we can write a minimum value and have it take effect */ 225 static void proc_write_min(struct vec_data *data) 226 { 227 int ret, new_default, child_vl; 228 229 if (geteuid() != 0) { 230 ksft_test_result_skip("Need to be root to write to /proc\n"); 231 return; 232 } 233 234 ret = file_write_integer(data->default_vl_file, ARCH_MIN_VL); 235 if (ret != 0) 236 return; 237 238 /* What was the new value? */ 239 ret = file_read_integer(data->default_vl_file, &new_default); 240 if (ret != 0) 241 return; 242 243 /* Did it take effect in a new process? */ 244 child_vl = get_child_rdvl(data); 245 if (child_vl != new_default) { 246 ksft_test_result_fail("%s is %d but child VL is %d\n", 247 data->default_vl_file, 248 new_default, child_vl); 249 return; 250 } 251 252 ksft_test_result_pass("%s minimum vector length %d\n", data->name, 253 new_default); 254 data->min_vl = new_default; 255 256 file_write_integer(data->default_vl_file, data->default_vl); 257 } 258 259 /* Verify that we can write a maximum value and have it take effect */ 260 static void proc_write_max(struct vec_data *data) 261 { 262 int ret, new_default, child_vl; 263 264 if (geteuid() != 0) { 265 ksft_test_result_skip("Need to be root to write to /proc\n"); 266 return; 267 } 268 269 /* -1 is accepted by the /proc interface as the maximum VL */ 270 ret = file_write_integer(data->default_vl_file, -1); 271 if (ret != 0) 272 return; 273 274 /* What was the new value? */ 275 ret = file_read_integer(data->default_vl_file, &new_default); 276 if (ret != 0) 277 return; 278 279 /* Did it take effect in a new process? */ 280 child_vl = get_child_rdvl(data); 281 if (child_vl != new_default) { 282 ksft_test_result_fail("%s is %d but child VL is %d\n", 283 data->default_vl_file, 284 new_default, child_vl); 285 return; 286 } 287 288 ksft_test_result_pass("%s maximum vector length %d\n", data->name, 289 new_default); 290 data->max_vl = new_default; 291 292 file_write_integer(data->default_vl_file, data->default_vl); 293 } 294 295 /* Can we read back a VL from prctl? */ 296 static void prctl_get(struct vec_data *data) 297 { 298 int ret; 299 300 ret = prctl(data->prctl_get); 301 if (ret == -1) { 302 ksft_test_result_fail("%s prctl() read failed: %d (%s)\n", 303 data->name, errno, strerror(errno)); 304 return; 305 } 306 307 /* Mask out any flags */ 308 ret &= PR_SVE_VL_LEN_MASK; 309 310 /* Is that what we can read back directly? */ 311 if (ret == data->rdvl()) 312 ksft_test_result_pass("%s current VL is %d\n", 313 data->name, ret); 314 else 315 ksft_test_result_fail("%s prctl() VL %d but RDVL is %d\n", 316 data->name, ret, data->rdvl()); 317 } 318 319 /* Does the prctl let us set the VL we already have? */ 320 static void prctl_set_same(struct vec_data *data) 321 { 322 int cur_vl = data->rdvl(); 323 int ret; 324 325 ret = prctl(data->prctl_set, cur_vl); 326 if (ret < 0) { 327 ksft_test_result_fail("%s prctl set failed: %d (%s)\n", 328 data->name, errno, strerror(errno)); 329 return; 330 } 331 332 ksft_test_result(cur_vl == data->rdvl(), 333 "%s set VL %d and have VL %d\n", 334 data->name, cur_vl, data->rdvl()); 335 } 336 337 /* Can we set a new VL for this process? */ 338 static void prctl_set(struct vec_data *data) 339 { 340 int ret; 341 342 if (data->min_vl == data->max_vl) { 343 ksft_test_result_skip("%s only one VL supported\n", 344 data->name); 345 return; 346 } 347 348 /* Try to set the minimum VL */ 349 ret = prctl(data->prctl_set, data->min_vl); 350 if (ret < 0) { 351 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n", 352 data->name, data->min_vl, 353 errno, strerror(errno)); 354 return; 355 } 356 357 if ((ret & PR_SVE_VL_LEN_MASK) != data->min_vl) { 358 ksft_test_result_fail("%s prctl set %d but return value is %d\n", 359 data->name, data->min_vl, data->rdvl()); 360 return; 361 } 362 363 if (data->rdvl() != data->min_vl) { 364 ksft_test_result_fail("%s set %d but RDVL is %d\n", 365 data->name, data->min_vl, data->rdvl()); 366 return; 367 } 368 369 /* Try to set the maximum VL */ 370 ret = prctl(data->prctl_set, data->max_vl); 371 if (ret < 0) { 372 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n", 373 data->name, data->max_vl, 374 errno, strerror(errno)); 375 return; 376 } 377 378 if ((ret & PR_SVE_VL_LEN_MASK) != data->max_vl) { 379 ksft_test_result_fail("%s prctl() set %d but return value is %d\n", 380 data->name, data->max_vl, data->rdvl()); 381 return; 382 } 383 384 /* The _INHERIT flag should not be present when we read the VL */ 385 ret = prctl(data->prctl_get); 386 if (ret == -1) { 387 ksft_test_result_fail("%s prctl() read failed: %d (%s)\n", 388 data->name, errno, strerror(errno)); 389 return; 390 } 391 392 if (ret & PR_SVE_VL_INHERIT) { 393 ksft_test_result_fail("%s prctl() reports _INHERIT\n", 394 data->name); 395 return; 396 } 397 398 ksft_test_result_pass("%s prctl() set min/max\n", data->name); 399 } 400 401 /* If we didn't request it a new VL shouldn't affect the child */ 402 static void prctl_set_no_child(struct vec_data *data) 403 { 404 int ret, child_vl; 405 406 if (data->min_vl == data->max_vl) { 407 ksft_test_result_skip("%s only one VL supported\n", 408 data->name); 409 return; 410 } 411 412 ret = prctl(data->prctl_set, data->min_vl); 413 if (ret < 0) { 414 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n", 415 data->name, data->min_vl, 416 errno, strerror(errno)); 417 return; 418 } 419 420 /* Ensure the default VL is different */ 421 ret = file_write_integer(data->default_vl_file, data->max_vl); 422 if (ret != 0) 423 return; 424 425 /* Check that the child has the default we just set */ 426 child_vl = get_child_rdvl(data); 427 if (child_vl != data->max_vl) { 428 ksft_test_result_fail("%s is %d but child VL is %d\n", 429 data->default_vl_file, 430 data->max_vl, child_vl); 431 return; 432 } 433 434 ksft_test_result_pass("%s vector length used default\n", data->name); 435 436 file_write_integer(data->default_vl_file, data->default_vl); 437 } 438 439 /* If we didn't request it a new VL shouldn't affect the child */ 440 static void prctl_set_for_child(struct vec_data *data) 441 { 442 int ret, child_vl; 443 444 if (data->min_vl == data->max_vl) { 445 ksft_test_result_skip("%s only one VL supported\n", 446 data->name); 447 return; 448 } 449 450 ret = prctl(data->prctl_set, data->min_vl | PR_SVE_VL_INHERIT); 451 if (ret < 0) { 452 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n", 453 data->name, data->min_vl, 454 errno, strerror(errno)); 455 return; 456 } 457 458 /* The _INHERIT flag should be present when we read the VL */ 459 ret = prctl(data->prctl_get); 460 if (ret == -1) { 461 ksft_test_result_fail("%s prctl() read failed: %d (%s)\n", 462 data->name, errno, strerror(errno)); 463 return; 464 } 465 if (!(ret & PR_SVE_VL_INHERIT)) { 466 ksft_test_result_fail("%s prctl() does not report _INHERIT\n", 467 data->name); 468 return; 469 } 470 471 /* Ensure the default VL is different */ 472 ret = file_write_integer(data->default_vl_file, data->max_vl); 473 if (ret != 0) 474 return; 475 476 /* Check that the child inherited our VL */ 477 child_vl = get_child_rdvl(data); 478 if (child_vl != data->min_vl) { 479 ksft_test_result_fail("%s is %d but child VL is %d\n", 480 data->default_vl_file, 481 data->min_vl, child_vl); 482 return; 483 } 484 485 ksft_test_result_pass("%s vector length was inherited\n", data->name); 486 487 file_write_integer(data->default_vl_file, data->default_vl); 488 } 489 490 /* _ONEXEC takes effect only in the child process */ 491 static void prctl_set_onexec(struct vec_data *data) 492 { 493 int ret, child_vl; 494 495 if (data->min_vl == data->max_vl) { 496 ksft_test_result_skip("%s only one VL supported\n", 497 data->name); 498 return; 499 } 500 501 /* Set a known value for the default and our current VL */ 502 ret = file_write_integer(data->default_vl_file, data->max_vl); 503 if (ret != 0) 504 return; 505 506 ret = prctl(data->prctl_set, data->max_vl); 507 if (ret < 0) { 508 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n", 509 data->name, data->min_vl, 510 errno, strerror(errno)); 511 return; 512 } 513 514 /* Set a different value for the child to have on exec */ 515 ret = prctl(data->prctl_set, data->min_vl | PR_SVE_SET_VL_ONEXEC); 516 if (ret < 0) { 517 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n", 518 data->name, data->min_vl, 519 errno, strerror(errno)); 520 return; 521 } 522 523 /* Our current VL should stay the same */ 524 if (data->rdvl() != data->max_vl) { 525 ksft_test_result_fail("%s VL changed by _ONEXEC prctl()\n", 526 data->name); 527 return; 528 } 529 530 /* Check that the child inherited our VL */ 531 child_vl = get_child_rdvl(data); 532 if (child_vl != data->min_vl) { 533 ksft_test_result_fail("Set %d _ONEXEC but child VL is %d\n", 534 data->min_vl, child_vl); 535 return; 536 } 537 538 ksft_test_result_pass("%s vector length set on exec\n", data->name); 539 540 file_write_integer(data->default_vl_file, data->default_vl); 541 } 542 543 /* For each VQ verify that setting via prctl() does the right thing */ 544 static void prctl_set_all_vqs(struct vec_data *data) 545 { 546 int ret, vq, vl, new_vl; 547 int errors = 0; 548 549 if (!data->min_vl || !data->max_vl) { 550 ksft_test_result_skip("%s Failed to enumerate VLs, not testing VL setting\n", 551 data->name); 552 return; 553 } 554 555 for (vq = SVE_VQ_MIN; vq <= SVE_VQ_MAX; vq++) { 556 vl = sve_vl_from_vq(vq); 557 558 /* Attempt to set the VL */ 559 ret = prctl(data->prctl_set, vl); 560 if (ret < 0) { 561 errors++; 562 ksft_print_msg("%s prctl set failed for %d: %d (%s)\n", 563 data->name, vl, 564 errno, strerror(errno)); 565 continue; 566 } 567 568 new_vl = ret & PR_SVE_VL_LEN_MASK; 569 570 /* Check that we actually have the reported new VL */ 571 if (data->rdvl() != new_vl) { 572 ksft_print_msg("Set %s VL %d but RDVL reports %d\n", 573 data->name, new_vl, data->rdvl()); 574 errors++; 575 } 576 577 /* Was that the VL we asked for? */ 578 if (new_vl == vl) 579 continue; 580 581 /* Should round up to the minimum VL if below it */ 582 if (vl < data->min_vl) { 583 if (new_vl != data->min_vl) { 584 ksft_print_msg("%s VL %d returned %d not minimum %d\n", 585 data->name, vl, new_vl, 586 data->min_vl); 587 errors++; 588 } 589 590 continue; 591 } 592 593 /* Should round down to maximum VL if above it */ 594 if (vl > data->max_vl) { 595 if (new_vl != data->max_vl) { 596 ksft_print_msg("%s VL %d returned %d not maximum %d\n", 597 data->name, vl, new_vl, 598 data->max_vl); 599 errors++; 600 } 601 602 continue; 603 } 604 605 /* Otherwise we should've rounded down */ 606 if (!(new_vl < vl)) { 607 ksft_print_msg("%s VL %d returned %d, did not round down\n", 608 data->name, vl, new_vl); 609 errors++; 610 611 continue; 612 } 613 } 614 615 ksft_test_result(errors == 0, "%s prctl() set all VLs, %d errors\n", 616 data->name, errors); 617 } 618 619 typedef void (*test_type)(struct vec_data *); 620 621 static const test_type tests[] = { 622 /* 623 * The default/min/max tests must be first and in this order 624 * to provide data for other tests. 625 */ 626 proc_read_default, 627 proc_write_min, 628 proc_write_max, 629 630 prctl_get, 631 prctl_set_same, 632 prctl_set, 633 prctl_set_no_child, 634 prctl_set_for_child, 635 prctl_set_onexec, 636 prctl_set_all_vqs, 637 }; 638 639 int main(void) 640 { 641 int i, j; 642 643 ksft_print_header(); 644 ksft_set_plan(ARRAY_SIZE(tests) * ARRAY_SIZE(vec_data)); 645 646 for (i = 0; i < ARRAY_SIZE(vec_data); i++) { 647 struct vec_data *data = &vec_data[i]; 648 unsigned long supported; 649 650 supported = getauxval(data->hwcap_type) & data->hwcap; 651 652 for (j = 0; j < ARRAY_SIZE(tests); j++) { 653 if (supported) 654 tests[j](data); 655 else 656 ksft_test_result_skip("%s not supported\n", 657 data->name); 658 } 659 } 660 661 ksft_exit_pass(); 662 } 663