658 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (C) 2022 ARM Limited.4 */5 6#define _GNU_SOURCE7#define _POSIX_C_SOURCE 199309L8 9#include <errno.h>10#include <getopt.h>11#include <poll.h>12#include <signal.h>13#include <stdbool.h>14#include <stddef.h>15#include <stdio.h>16#include <stdlib.h>17#include <string.h>18#include <unistd.h>19#include <sys/auxv.h>20#include <sys/epoll.h>21#include <sys/prctl.h>22#include <sys/types.h>23#include <sys/uio.h>24#include <sys/wait.h>25#include <asm/hwcap.h>26 27#include "../../kselftest.h"28 29#define MAX_VLS 1630 31struct child_data {32 char *name, *output;33 pid_t pid;34 int stdout;35 bool output_seen;36 bool exited;37 int exit_status;38};39 40static int epoll_fd;41static struct child_data *children;42static struct epoll_event *evs;43static int tests;44static int num_children;45static bool terminate;46 47static int startup_pipe[2];48 49static int num_processors(void)50{51 long nproc = sysconf(_SC_NPROCESSORS_CONF);52 if (nproc < 0) {53 perror("Unable to read number of processors\n");54 exit(EXIT_FAILURE);55 }56 57 return nproc;58}59 60static void child_start(struct child_data *child, const char *program)61{62 int ret, pipefd[2], i;63 struct epoll_event ev;64 65 ret = pipe(pipefd);66 if (ret != 0)67 ksft_exit_fail_msg("Failed to create stdout pipe: %s (%d)\n",68 strerror(errno), errno);69 70 child->pid = fork();71 if (child->pid == -1)72 ksft_exit_fail_msg("fork() failed: %s (%d)\n",73 strerror(errno), errno);74 75 if (!child->pid) {76 /*77 * In child, replace stdout with the pipe, errors to78 * stderr from here as kselftest prints to stdout.79 */80 ret = dup2(pipefd[1], 1);81 if (ret == -1) {82 fprintf(stderr, "dup2() %d\n", errno);83 exit(EXIT_FAILURE);84 }85 86 /*87 * Duplicate the read side of the startup pipe to88 * FD 3 so we can close everything else.89 */90 ret = dup2(startup_pipe[0], 3);91 if (ret == -1) {92 fprintf(stderr, "dup2() %d\n", errno);93 exit(EXIT_FAILURE);94 }95 96 /*97 * Very dumb mechanism to clean open FDs other than98 * stdio. We don't want O_CLOEXEC for the pipes...99 */100 for (i = 4; i < 8192; i++)101 close(i);102 103 /*104 * Read from the startup pipe, there should be no data105 * and we should block until it is closed. We just106 * carry on on error since this isn't super critical.107 */108 ret = read(3, &i, sizeof(i));109 if (ret < 0)110 fprintf(stderr, "read(startp pipe) failed: %s (%d)\n",111 strerror(errno), errno);112 if (ret > 0)113 fprintf(stderr, "%d bytes of data on startup pipe\n",114 ret);115 close(3);116 117 ret = execl(program, program, NULL);118 fprintf(stderr, "execl(%s) failed: %d (%s)\n",119 program, errno, strerror(errno));120 121 exit(EXIT_FAILURE);122 } else {123 /*124 * In parent, remember the child and close our copy of the125 * write side of stdout.126 */127 close(pipefd[1]);128 child->stdout = pipefd[0];129 child->output = NULL;130 child->exited = false;131 child->output_seen = false;132 133 ev.events = EPOLLIN | EPOLLHUP;134 ev.data.ptr = child;135 136 ret = epoll_ctl(epoll_fd, EPOLL_CTL_ADD, child->stdout, &ev);137 if (ret < 0) {138 ksft_exit_fail_msg("%s EPOLL_CTL_ADD failed: %s (%d)\n",139 child->name, strerror(errno), errno);140 }141 }142}143 144static bool child_output_read(struct child_data *child)145{146 char read_data[1024];147 char work[1024];148 int ret, len, cur_work, cur_read;149 150 ret = read(child->stdout, read_data, sizeof(read_data));151 if (ret < 0) {152 if (errno == EINTR)153 return true;154 155 ksft_print_msg("%s: read() failed: %s (%d)\n",156 child->name, strerror(errno),157 errno);158 return false;159 }160 len = ret;161 162 child->output_seen = true;163 164 /* Pick up any partial read */165 if (child->output) {166 strncpy(work, child->output, sizeof(work) - 1);167 cur_work = strnlen(work, sizeof(work));168 free(child->output);169 child->output = NULL;170 } else {171 cur_work = 0;172 }173 174 cur_read = 0;175 while (cur_read < len) {176 work[cur_work] = read_data[cur_read++];177 178 if (work[cur_work] == '\n') {179 work[cur_work] = '\0';180 ksft_print_msg("%s: %s\n", child->name, work);181 cur_work = 0;182 } else {183 cur_work++;184 }185 }186 187 if (cur_work) {188 work[cur_work] = '\0';189 ret = asprintf(&child->output, "%s", work);190 if (ret == -1)191 ksft_exit_fail_msg("Out of memory\n");192 }193 194 return false;195}196 197static void child_output(struct child_data *child, uint32_t events,198 bool flush)199{200 bool read_more;201 202 if (events & EPOLLIN) {203 do {204 read_more = child_output_read(child);205 } while (read_more);206 }207 208 if (events & EPOLLHUP) {209 close(child->stdout);210 child->stdout = -1;211 flush = true;212 }213 214 if (flush && child->output) {215 ksft_print_msg("%s: %s<EOF>\n", child->name, child->output);216 free(child->output);217 child->output = NULL;218 }219}220 221static void child_tickle(struct child_data *child)222{223 if (child->output_seen && !child->exited)224 kill(child->pid, SIGUSR2);225}226 227static void child_stop(struct child_data *child)228{229 if (!child->exited)230 kill(child->pid, SIGTERM);231}232 233static void child_cleanup(struct child_data *child)234{235 pid_t ret;236 int status;237 bool fail = false;238 239 if (!child->exited) {240 do {241 ret = waitpid(child->pid, &status, 0);242 if (ret == -1 && errno == EINTR)243 continue;244 245 if (ret == -1) {246 ksft_print_msg("waitpid(%d) failed: %s (%d)\n",247 child->pid, strerror(errno),248 errno);249 fail = true;250 break;251 }252 } while (!WIFEXITED(status));253 child->exit_status = WEXITSTATUS(status);254 }255 256 if (!child->output_seen) {257 ksft_print_msg("%s no output seen\n", child->name);258 fail = true;259 }260 261 if (child->exit_status != 0) {262 ksft_print_msg("%s exited with error code %d\n",263 child->name, child->exit_status);264 fail = true;265 }266 267 ksft_test_result(!fail, "%s\n", child->name);268}269 270static void handle_child_signal(int sig, siginfo_t *info, void *context)271{272 int i;273 bool found = false;274 275 for (i = 0; i < num_children; i++) {276 if (children[i].pid == info->si_pid) {277 children[i].exited = true;278 children[i].exit_status = info->si_status;279 found = true;280 break;281 }282 }283 284 if (!found)285 ksft_print_msg("SIGCHLD for unknown PID %d with status %d\n",286 info->si_pid, info->si_status);287}288 289static void handle_exit_signal(int sig, siginfo_t *info, void *context)290{291 int i;292 293 /* If we're already exiting then don't signal again */294 if (terminate)295 return;296 297 ksft_print_msg("Got signal, exiting...\n");298 299 terminate = true;300 301 /*302 * This should be redundant, the main loop should clean up303 * after us, but for safety stop everything we can here.304 */305 for (i = 0; i < num_children; i++)306 child_stop(&children[i]);307}308 309static void start_fpsimd(struct child_data *child, int cpu, int copy)310{311 int ret;312 313 ret = asprintf(&child->name, "FPSIMD-%d-%d", cpu, copy);314 if (ret == -1)315 ksft_exit_fail_msg("asprintf() failed\n");316 317 child_start(child, "./fpsimd-test");318 319 ksft_print_msg("Started %s\n", child->name);320}321 322static void start_kernel(struct child_data *child, int cpu, int copy)323{324 int ret;325 326 ret = asprintf(&child->name, "KERNEL-%d-%d", cpu, copy);327 if (ret == -1)328 ksft_exit_fail_msg("asprintf() failed\n");329 330 child_start(child, "./kernel-test");331 332 ksft_print_msg("Started %s\n", child->name);333}334 335static void start_sve(struct child_data *child, int vl, int cpu)336{337 int ret;338 339 ret = prctl(PR_SVE_SET_VL, vl | PR_SVE_VL_INHERIT);340 if (ret < 0)341 ksft_exit_fail_msg("Failed to set SVE VL %d\n", vl);342 343 ret = asprintf(&child->name, "SVE-VL-%d-%d", vl, cpu);344 if (ret == -1)345 ksft_exit_fail_msg("asprintf() failed\n");346 347 child_start(child, "./sve-test");348 349 ksft_print_msg("Started %s\n", child->name);350}351 352static void start_ssve(struct child_data *child, int vl, int cpu)353{354 int ret;355 356 ret = asprintf(&child->name, "SSVE-VL-%d-%d", vl, cpu);357 if (ret == -1)358 ksft_exit_fail_msg("asprintf() failed\n");359 360 ret = prctl(PR_SME_SET_VL, vl | PR_SME_VL_INHERIT);361 if (ret < 0)362 ksft_exit_fail_msg("Failed to set SME VL %d\n", ret);363 364 child_start(child, "./ssve-test");365 366 ksft_print_msg("Started %s\n", child->name);367}368 369static void start_za(struct child_data *child, int vl, int cpu)370{371 int ret;372 373 ret = prctl(PR_SME_SET_VL, vl | PR_SVE_VL_INHERIT);374 if (ret < 0)375 ksft_exit_fail_msg("Failed to set SME VL %d\n", ret);376 377 ret = asprintf(&child->name, "ZA-VL-%d-%d", vl, cpu);378 if (ret == -1)379 ksft_exit_fail_msg("asprintf() failed\n");380 381 child_start(child, "./za-test");382 383 ksft_print_msg("Started %s\n", child->name);384}385 386static void start_zt(struct child_data *child, int cpu)387{388 int ret;389 390 ret = asprintf(&child->name, "ZT-%d", cpu);391 if (ret == -1)392 ksft_exit_fail_msg("asprintf() failed\n");393 394 child_start(child, "./zt-test");395 396 ksft_print_msg("Started %s\n", child->name);397}398 399static void probe_vls(int vls[], int *vl_count, int set_vl)400{401 unsigned int vq;402 int vl;403 404 *vl_count = 0;405 406 for (vq = SVE_VQ_MAX; vq > 0; vq /= 2) {407 vl = prctl(set_vl, vq * 16);408 if (vl == -1)409 ksft_exit_fail_msg("SET_VL failed: %s (%d)\n",410 strerror(errno), errno);411 412 vl &= PR_SVE_VL_LEN_MASK;413 414 if (*vl_count && (vl == vls[*vl_count - 1]))415 break;416 417 vq = sve_vq_from_vl(vl);418 419 vls[*vl_count] = vl;420 *vl_count += 1;421 }422}423 424/* Handle any pending output without blocking */425static void drain_output(bool flush)426{427 int ret = 1;428 int i;429 430 while (ret > 0) {431 ret = epoll_wait(epoll_fd, evs, tests, 0);432 if (ret < 0) {433 if (errno == EINTR)434 continue;435 ksft_print_msg("epoll_wait() failed: %s (%d)\n",436 strerror(errno), errno);437 }438 439 for (i = 0; i < ret; i++)440 child_output(evs[i].data.ptr, evs[i].events, flush);441 }442}443 444static const struct option options[] = {445 { "timeout", required_argument, NULL, 't' },446 { }447};448 449int main(int argc, char **argv)450{451 int ret;452 int timeout = 10;453 int cpus, i, j, c;454 int sve_vl_count, sme_vl_count;455 bool all_children_started = false;456 int seen_children;457 int sve_vls[MAX_VLS], sme_vls[MAX_VLS];458 bool have_sme2;459 struct sigaction sa;460 461 while ((c = getopt_long(argc, argv, "t:", options, NULL)) != -1) {462 switch (c) {463 case 't':464 ret = sscanf(optarg, "%d", &timeout);465 if (ret != 1)466 ksft_exit_fail_msg("Failed to parse timeout %s\n",467 optarg);468 break;469 default:470 ksft_exit_fail_msg("Unknown argument\n");471 }472 }473 474 cpus = num_processors();475 tests = 0;476 477 if (getauxval(AT_HWCAP) & HWCAP_SVE) {478 probe_vls(sve_vls, &sve_vl_count, PR_SVE_SET_VL);479 tests += sve_vl_count * cpus;480 } else {481 sve_vl_count = 0;482 }483 484 if (getauxval(AT_HWCAP2) & HWCAP2_SME) {485 probe_vls(sme_vls, &sme_vl_count, PR_SME_SET_VL);486 tests += sme_vl_count * cpus * 2;487 } else {488 sme_vl_count = 0;489 }490 491 if (getauxval(AT_HWCAP2) & HWCAP2_SME2) {492 tests += cpus;493 have_sme2 = true;494 } else {495 have_sme2 = false;496 }497 498 tests += cpus * 2;499 500 ksft_print_header();501 ksft_set_plan(tests);502 503 ksft_print_msg("%d CPUs, %d SVE VLs, %d SME VLs, SME2 %s\n",504 cpus, sve_vl_count, sme_vl_count,505 have_sme2 ? "present" : "absent");506 507 if (timeout > 0)508 ksft_print_msg("Will run for %ds\n", timeout);509 else510 ksft_print_msg("Will run until terminated\n");511 512 children = calloc(sizeof(*children), tests);513 if (!children)514 ksft_exit_fail_msg("Unable to allocate child data\n");515 516 ret = epoll_create1(EPOLL_CLOEXEC);517 if (ret < 0)518 ksft_exit_fail_msg("epoll_create1() failed: %s (%d)\n",519 strerror(errno), ret);520 epoll_fd = ret;521 522 /* Create a pipe which children will block on before execing */523 ret = pipe(startup_pipe);524 if (ret != 0)525 ksft_exit_fail_msg("Failed to create startup pipe: %s (%d)\n",526 strerror(errno), errno);527 528 /* Get signal handers ready before we start any children */529 memset(&sa, 0, sizeof(sa));530 sa.sa_sigaction = handle_exit_signal;531 sa.sa_flags = SA_RESTART | SA_SIGINFO;532 sigemptyset(&sa.sa_mask);533 ret = sigaction(SIGINT, &sa, NULL);534 if (ret < 0)535 ksft_print_msg("Failed to install SIGINT handler: %s (%d)\n",536 strerror(errno), errno);537 ret = sigaction(SIGTERM, &sa, NULL);538 if (ret < 0)539 ksft_print_msg("Failed to install SIGTERM handler: %s (%d)\n",540 strerror(errno), errno);541 sa.sa_sigaction = handle_child_signal;542 ret = sigaction(SIGCHLD, &sa, NULL);543 if (ret < 0)544 ksft_print_msg("Failed to install SIGCHLD handler: %s (%d)\n",545 strerror(errno), errno);546 547 evs = calloc(tests, sizeof(*evs));548 if (!evs)549 ksft_exit_fail_msg("Failed to allocated %d epoll events\n",550 tests);551 552 for (i = 0; i < cpus; i++) {553 start_fpsimd(&children[num_children++], i, 0);554 start_kernel(&children[num_children++], i, 0);555 556 for (j = 0; j < sve_vl_count; j++)557 start_sve(&children[num_children++], sve_vls[j], i);558 559 for (j = 0; j < sme_vl_count; j++) {560 start_ssve(&children[num_children++], sme_vls[j], i);561 start_za(&children[num_children++], sme_vls[j], i);562 }563 564 if (have_sme2)565 start_zt(&children[num_children++], i);566 }567 568 /*569 * All children started, close the startup pipe and let them570 * run.571 */572 close(startup_pipe[0]);573 close(startup_pipe[1]);574 575 for (;;) {576 /* Did we get a signal asking us to exit? */577 if (terminate)578 break;579 580 /*581 * Timeout is counted in seconds with no output, the582 * tests print during startup then are silent when583 * running so this should ensure they all ran enough584 * to install the signal handler, this is especially585 * useful in emulation where we will both be slow and586 * likely to have a large set of VLs.587 */588 ret = epoll_wait(epoll_fd, evs, tests, 1000);589 if (ret < 0) {590 if (errno == EINTR)591 continue;592 ksft_exit_fail_msg("epoll_wait() failed: %s (%d)\n",593 strerror(errno), errno);594 }595 596 /* Output? */597 if (ret > 0) {598 for (i = 0; i < ret; i++) {599 child_output(evs[i].data.ptr, evs[i].events,600 false);601 }602 continue;603 }604 605 /* Otherwise epoll_wait() timed out */606 607 /*608 * If the child processes have not produced output they609 * aren't actually running the tests yet .610 */611 if (!all_children_started) {612 seen_children = 0;613 614 for (i = 0; i < num_children; i++)615 if (children[i].output_seen ||616 children[i].exited)617 seen_children++;618 619 if (seen_children != num_children) {620 ksft_print_msg("Waiting for %d children\n",621 num_children - seen_children);622 continue;623 }624 625 all_children_started = true;626 }627 628 ksft_print_msg("Sending signals, timeout remaining: %d\n",629 timeout);630 631 for (i = 0; i < num_children; i++)632 child_tickle(&children[i]);633 634 /* Negative timeout means run indefinitely */635 if (timeout < 0)636 continue;637 if (--timeout == 0)638 break;639 }640 641 ksft_print_msg("Finishing up...\n");642 terminate = true;643 644 for (i = 0; i < tests; i++)645 child_stop(&children[i]);646 647 drain_output(false);648 649 for (i = 0; i < tests; i++)650 child_cleanup(&children[i]);651 652 drain_output(true);653 654 ksft_print_cnts();655 656 return 0;657}658