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