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\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 int ret; 184 185 f = fopen(name, "w"); 186 if (!f) { 187 ksft_test_result_fail("Unable to open %s: %d (%s)\n", 188 name, errno, 189 strerror(errno)); 190 return -1; 191 } 192 193 fprintf(f, "%d", val); 194 fclose(f); 195 if (ret < 0) { 196 ksft_test_result_fail("Error writing %d to %s\n", 197 val, name); 198 return -1; 199 } 200 201 return 0; 202 } 203 204 /* 205 * Verify that we can read the default VL via proc, checking that it 206 * is set in a freshly spawned child. 207 */ 208 static void proc_read_default(struct vec_data *data) 209 { 210 int default_vl, child_vl, ret; 211 212 ret = file_read_integer(data->default_vl_file, &default_vl); 213 if (ret != 0) 214 return; 215 216 /* Is this the actual default seen by new processes? */ 217 child_vl = get_child_rdvl(data); 218 if (child_vl != default_vl) { 219 ksft_test_result_fail("%s is %d but child VL is %d\n", 220 data->default_vl_file, 221 default_vl, child_vl); 222 return; 223 } 224 225 ksft_test_result_pass("%s default vector length %d\n", data->name, 226 default_vl); 227 data->default_vl = default_vl; 228 } 229 230 /* Verify that we can write a minimum value and have it take effect */ 231 static void proc_write_min(struct vec_data *data) 232 { 233 int ret, new_default, child_vl; 234 235 if (geteuid() != 0) { 236 ksft_test_result_skip("Need to be root to write to /proc\n"); 237 return; 238 } 239 240 ret = file_write_integer(data->default_vl_file, ARCH_MIN_VL); 241 if (ret != 0) 242 return; 243 244 /* What was the new value? */ 245 ret = file_read_integer(data->default_vl_file, &new_default); 246 if (ret != 0) 247 return; 248 249 /* Did it take effect in a new process? */ 250 child_vl = get_child_rdvl(data); 251 if (child_vl != new_default) { 252 ksft_test_result_fail("%s is %d but child VL is %d\n", 253 data->default_vl_file, 254 new_default, child_vl); 255 return; 256 } 257 258 ksft_test_result_pass("%s minimum vector length %d\n", data->name, 259 new_default); 260 data->min_vl = new_default; 261 262 file_write_integer(data->default_vl_file, data->default_vl); 263 } 264 265 /* Verify that we can write a maximum value and have it take effect */ 266 static void proc_write_max(struct vec_data *data) 267 { 268 int ret, new_default, child_vl; 269 270 if (geteuid() != 0) { 271 ksft_test_result_skip("Need to be root to write to /proc\n"); 272 return; 273 } 274 275 /* -1 is accepted by the /proc interface as the maximum VL */ 276 ret = file_write_integer(data->default_vl_file, -1); 277 if (ret != 0) 278 return; 279 280 /* What was the new value? */ 281 ret = file_read_integer(data->default_vl_file, &new_default); 282 if (ret != 0) 283 return; 284 285 /* Did it take effect in a new process? */ 286 child_vl = get_child_rdvl(data); 287 if (child_vl != new_default) { 288 ksft_test_result_fail("%s is %d but child VL is %d\n", 289 data->default_vl_file, 290 new_default, child_vl); 291 return; 292 } 293 294 ksft_test_result_pass("%s maximum vector length %d\n", data->name, 295 new_default); 296 data->max_vl = new_default; 297 298 file_write_integer(data->default_vl_file, data->default_vl); 299 } 300 301 /* Can we read back a VL from prctl? */ 302 static void prctl_get(struct vec_data *data) 303 { 304 int ret; 305 306 ret = prctl(data->prctl_get); 307 if (ret == -1) { 308 ksft_test_result_fail("%s prctl() read failed: %d (%s)\n", 309 data->name, errno, strerror(errno)); 310 return; 311 } 312 313 /* Mask out any flags */ 314 ret &= PR_SVE_VL_LEN_MASK; 315 316 /* Is that what we can read back directly? */ 317 if (ret == data->rdvl()) 318 ksft_test_result_pass("%s current VL is %d\n", 319 data->name, ret); 320 else 321 ksft_test_result_fail("%s prctl() VL %d but RDVL is %d\n", 322 data->name, ret, data->rdvl()); 323 } 324 325 /* Does the prctl let us set the VL we already have? */ 326 static void prctl_set_same(struct vec_data *data) 327 { 328 int cur_vl = data->rdvl(); 329 int ret; 330 331 ret = prctl(data->prctl_set, cur_vl); 332 if (ret < 0) { 333 ksft_test_result_fail("%s prctl set failed: %d (%s)\n", 334 data->name, errno, strerror(errno)); 335 return; 336 } 337 338 if (cur_vl != data->rdvl()) 339 ksft_test_result_pass("%s current VL is %d\n", 340 data->name, ret); 341 else 342 ksft_test_result_fail("%s prctl() VL %d but RDVL is %d\n", 343 data->name, ret, data->rdvl()); 344 } 345 346 /* Can we set a new VL for this process? */ 347 static void prctl_set(struct vec_data *data) 348 { 349 int ret; 350 351 if (data->min_vl == data->max_vl) { 352 ksft_test_result_skip("%s only one VL supported\n", 353 data->name); 354 return; 355 } 356 357 /* Try to set the minimum VL */ 358 ret = prctl(data->prctl_set, data->min_vl); 359 if (ret < 0) { 360 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n", 361 data->name, data->min_vl, 362 errno, strerror(errno)); 363 return; 364 } 365 366 if ((ret & PR_SVE_VL_LEN_MASK) != data->min_vl) { 367 ksft_test_result_fail("%s prctl set %d but return value is %d\n", 368 data->name, data->min_vl, data->rdvl()); 369 return; 370 } 371 372 if (data->rdvl() != data->min_vl) { 373 ksft_test_result_fail("%s set %d but RDVL is %d\n", 374 data->name, data->min_vl, data->rdvl()); 375 return; 376 } 377 378 /* Try to set the maximum VL */ 379 ret = prctl(data->prctl_set, data->max_vl); 380 if (ret < 0) { 381 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n", 382 data->name, data->max_vl, 383 errno, strerror(errno)); 384 return; 385 } 386 387 if ((ret & PR_SVE_VL_LEN_MASK) != data->max_vl) { 388 ksft_test_result_fail("%s prctl() set %d but return value is %d\n", 389 data->name, data->max_vl, data->rdvl()); 390 return; 391 } 392 393 /* The _INHERIT flag should not be present when we read the VL */ 394 ret = prctl(data->prctl_get); 395 if (ret == -1) { 396 ksft_test_result_fail("%s prctl() read failed: %d (%s)\n", 397 data->name, errno, strerror(errno)); 398 return; 399 } 400 401 if (ret & PR_SVE_VL_INHERIT) { 402 ksft_test_result_fail("%s prctl() reports _INHERIT\n", 403 data->name); 404 return; 405 } 406 407 ksft_test_result_pass("%s prctl() set min/max\n", data->name); 408 } 409 410 /* If we didn't request it a new VL shouldn't affect the child */ 411 static void prctl_set_no_child(struct vec_data *data) 412 { 413 int ret, child_vl; 414 415 if (data->min_vl == data->max_vl) { 416 ksft_test_result_skip("%s only one VL supported\n", 417 data->name); 418 return; 419 } 420 421 ret = prctl(data->prctl_set, data->min_vl); 422 if (ret < 0) { 423 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n", 424 data->name, data->min_vl, 425 errno, strerror(errno)); 426 return; 427 } 428 429 /* Ensure the default VL is different */ 430 ret = file_write_integer(data->default_vl_file, data->max_vl); 431 if (ret != 0) 432 return; 433 434 /* Check that the child has the default we just set */ 435 child_vl = get_child_rdvl(data); 436 if (child_vl != data->max_vl) { 437 ksft_test_result_fail("%s is %d but child VL is %d\n", 438 data->default_vl_file, 439 data->max_vl, child_vl); 440 return; 441 } 442 443 ksft_test_result_pass("%s vector length used default\n", data->name); 444 445 file_write_integer(data->default_vl_file, data->default_vl); 446 } 447 448 /* If we didn't request it a new VL shouldn't affect the child */ 449 static void prctl_set_for_child(struct vec_data *data) 450 { 451 int ret, child_vl; 452 453 if (data->min_vl == data->max_vl) { 454 ksft_test_result_skip("%s only one VL supported\n", 455 data->name); 456 return; 457 } 458 459 ret = prctl(data->prctl_set, data->min_vl | PR_SVE_VL_INHERIT); 460 if (ret < 0) { 461 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n", 462 data->name, data->min_vl, 463 errno, strerror(errno)); 464 return; 465 } 466 467 /* The _INHERIT flag should be present when we read the VL */ 468 ret = prctl(data->prctl_get); 469 if (ret == -1) { 470 ksft_test_result_fail("%s prctl() read failed: %d (%s)\n", 471 data->name, errno, strerror(errno)); 472 return; 473 } 474 if (!(ret & PR_SVE_VL_INHERIT)) { 475 ksft_test_result_fail("%s prctl() does not report _INHERIT\n", 476 data->name); 477 return; 478 } 479 480 /* Ensure the default VL is different */ 481 ret = file_write_integer(data->default_vl_file, data->max_vl); 482 if (ret != 0) 483 return; 484 485 /* Check that the child inherited our VL */ 486 child_vl = get_child_rdvl(data); 487 if (child_vl != data->min_vl) { 488 ksft_test_result_fail("%s is %d but child VL is %d\n", 489 data->default_vl_file, 490 data->min_vl, child_vl); 491 return; 492 } 493 494 ksft_test_result_pass("%s vector length was inherited\n", data->name); 495 496 file_write_integer(data->default_vl_file, data->default_vl); 497 } 498 499 /* _ONEXEC takes effect only in the child process */ 500 static void prctl_set_onexec(struct vec_data *data) 501 { 502 int ret, child_vl; 503 504 if (data->min_vl == data->max_vl) { 505 ksft_test_result_skip("%s only one VL supported\n", 506 data->name); 507 return; 508 } 509 510 /* Set a known value for the default and our current VL */ 511 ret = file_write_integer(data->default_vl_file, data->max_vl); 512 if (ret != 0) 513 return; 514 515 ret = prctl(data->prctl_set, data->max_vl); 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 /* Set a different value for the child to have on exec */ 524 ret = prctl(data->prctl_set, data->min_vl | PR_SVE_SET_VL_ONEXEC); 525 if (ret < 0) { 526 ksft_test_result_fail("%s prctl set failed for %d: %d (%s)\n", 527 data->name, data->min_vl, 528 errno, strerror(errno)); 529 return; 530 } 531 532 /* Our current VL should stay the same */ 533 if (data->rdvl() != data->max_vl) { 534 ksft_test_result_fail("%s VL changed by _ONEXEC prctl()\n", 535 data->name); 536 return; 537 } 538 539 /* Check that the child inherited our VL */ 540 child_vl = get_child_rdvl(data); 541 if (child_vl != data->min_vl) { 542 ksft_test_result_fail("Set %d _ONEXEC but child VL is %d\n", 543 data->min_vl, child_vl); 544 return; 545 } 546 547 ksft_test_result_pass("%s vector length set on exec\n", data->name); 548 549 file_write_integer(data->default_vl_file, data->default_vl); 550 } 551 552 typedef void (*test_type)(struct vec_data *); 553 554 static const test_type tests[] = { 555 /* 556 * The default/min/max tests must be first and in this order 557 * to provide data for other tests. 558 */ 559 proc_read_default, 560 proc_write_min, 561 proc_write_max, 562 563 prctl_get, 564 prctl_set, 565 prctl_set_no_child, 566 prctl_set_for_child, 567 prctl_set_onexec, 568 }; 569 570 int main(void) 571 { 572 int i, j; 573 574 ksft_print_header(); 575 ksft_set_plan(ARRAY_SIZE(tests) * ARRAY_SIZE(vec_data)); 576 577 for (i = 0; i < ARRAY_SIZE(vec_data); i++) { 578 struct vec_data *data = &vec_data[i]; 579 unsigned long supported; 580 581 supported = getauxval(data->hwcap_type) & data->hwcap; 582 583 for (j = 0; j < ARRAY_SIZE(tests); j++) { 584 if (supported) 585 tests[j](data); 586 else 587 ksft_test_result_skip("%s not supported\n", 588 data->name); 589 } 590 } 591 592 ksft_exit_pass(); 593 } 594