1f50a7f3dSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
23752e453SMichael Ellerman /*
33752e453SMichael Ellerman * Copyright 2014, Michael Ellerman, IBM Corp.
43752e453SMichael Ellerman */
53752e453SMichael Ellerman
63752e453SMichael Ellerman #define _GNU_SOURCE /* For CPU_ZERO etc. */
73752e453SMichael Ellerman
83752e453SMichael Ellerman #include <errno.h>
93752e453SMichael Ellerman #include <sched.h>
103752e453SMichael Ellerman #include <setjmp.h>
113752e453SMichael Ellerman #include <stdlib.h>
123752e453SMichael Ellerman #include <sys/wait.h>
133752e453SMichael Ellerman
143752e453SMichael Ellerman #include "utils.h"
153752e453SMichael Ellerman #include "lib.h"
163752e453SMichael Ellerman
173752e453SMichael Ellerman #define PARENT_TOKEN 0xAA
183752e453SMichael Ellerman #define CHILD_TOKEN 0x55
193752e453SMichael Ellerman
sync_with_child(union pipe read_pipe,union pipe write_pipe)203752e453SMichael Ellerman int sync_with_child(union pipe read_pipe, union pipe write_pipe)
213752e453SMichael Ellerman {
223752e453SMichael Ellerman char c = PARENT_TOKEN;
233752e453SMichael Ellerman
243752e453SMichael Ellerman FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
253752e453SMichael Ellerman FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1);
263752e453SMichael Ellerman if (c != CHILD_TOKEN) /* sometimes expected */
273752e453SMichael Ellerman return 1;
283752e453SMichael Ellerman
293752e453SMichael Ellerman return 0;
303752e453SMichael Ellerman }
313752e453SMichael Ellerman
wait_for_parent(union pipe read_pipe)323752e453SMichael Ellerman int wait_for_parent(union pipe read_pipe)
333752e453SMichael Ellerman {
343752e453SMichael Ellerman char c;
353752e453SMichael Ellerman
363752e453SMichael Ellerman FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1);
373752e453SMichael Ellerman FAIL_IF(c != PARENT_TOKEN);
383752e453SMichael Ellerman
393752e453SMichael Ellerman return 0;
403752e453SMichael Ellerman }
413752e453SMichael Ellerman
notify_parent(union pipe write_pipe)423752e453SMichael Ellerman int notify_parent(union pipe write_pipe)
433752e453SMichael Ellerman {
443752e453SMichael Ellerman char c = CHILD_TOKEN;
453752e453SMichael Ellerman
463752e453SMichael Ellerman FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
473752e453SMichael Ellerman
483752e453SMichael Ellerman return 0;
493752e453SMichael Ellerman }
503752e453SMichael Ellerman
notify_parent_of_error(union pipe write_pipe)513752e453SMichael Ellerman int notify_parent_of_error(union pipe write_pipe)
523752e453SMichael Ellerman {
533752e453SMichael Ellerman char c = ~CHILD_TOKEN;
543752e453SMichael Ellerman
553752e453SMichael Ellerman FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1);
563752e453SMichael Ellerman
573752e453SMichael Ellerman return 0;
583752e453SMichael Ellerman }
593752e453SMichael Ellerman
wait_for_child(pid_t child_pid)603752e453SMichael Ellerman int wait_for_child(pid_t child_pid)
613752e453SMichael Ellerman {
623752e453SMichael Ellerman int rc;
633752e453SMichael Ellerman
643752e453SMichael Ellerman if (waitpid(child_pid, &rc, 0) == -1) {
653752e453SMichael Ellerman perror("waitpid");
663752e453SMichael Ellerman return 1;
673752e453SMichael Ellerman }
683752e453SMichael Ellerman
693752e453SMichael Ellerman if (WIFEXITED(rc))
703752e453SMichael Ellerman rc = WEXITSTATUS(rc);
713752e453SMichael Ellerman else
723752e453SMichael Ellerman rc = 1; /* Signal or other */
733752e453SMichael Ellerman
743752e453SMichael Ellerman return rc;
753752e453SMichael Ellerman }
763752e453SMichael Ellerman
kill_child_and_wait(pid_t child_pid)773752e453SMichael Ellerman int kill_child_and_wait(pid_t child_pid)
783752e453SMichael Ellerman {
793752e453SMichael Ellerman kill(child_pid, SIGTERM);
803752e453SMichael Ellerman
813752e453SMichael Ellerman return wait_for_child(child_pid);
823752e453SMichael Ellerman }
833752e453SMichael Ellerman
eat_cpu_child(union pipe read_pipe,union pipe write_pipe)843752e453SMichael Ellerman static int eat_cpu_child(union pipe read_pipe, union pipe write_pipe)
853752e453SMichael Ellerman {
863752e453SMichael Ellerman volatile int i = 0;
873752e453SMichael Ellerman
883752e453SMichael Ellerman /*
893752e453SMichael Ellerman * We are just here to eat cpu and die. So make sure we can be killed,
903752e453SMichael Ellerman * and also don't do any custom SIGTERM handling.
913752e453SMichael Ellerman */
923752e453SMichael Ellerman signal(SIGTERM, SIG_DFL);
933752e453SMichael Ellerman
943752e453SMichael Ellerman notify_parent(write_pipe);
953752e453SMichael Ellerman wait_for_parent(read_pipe);
963752e453SMichael Ellerman
973752e453SMichael Ellerman /* Soak up cpu forever */
983752e453SMichael Ellerman while (1) i++;
993752e453SMichael Ellerman
1003752e453SMichael Ellerman return 0;
1013752e453SMichael Ellerman }
1023752e453SMichael Ellerman
eat_cpu(int (test_function)(void))1033752e453SMichael Ellerman pid_t eat_cpu(int (test_function)(void))
1043752e453SMichael Ellerman {
1053752e453SMichael Ellerman union pipe read_pipe, write_pipe;
106*6ff4dc25SBenjamin Gray int rc;
1073752e453SMichael Ellerman pid_t pid;
1083752e453SMichael Ellerman
109*6ff4dc25SBenjamin Gray FAIL_IF(bind_to_cpu(BIND_CPU_ANY) < 0);
1103752e453SMichael Ellerman
1113752e453SMichael Ellerman if (pipe(read_pipe.fds) == -1)
1123752e453SMichael Ellerman return -1;
1133752e453SMichael Ellerman
1143752e453SMichael Ellerman if (pipe(write_pipe.fds) == -1)
1153752e453SMichael Ellerman return -1;
1163752e453SMichael Ellerman
1173752e453SMichael Ellerman pid = fork();
1183752e453SMichael Ellerman if (pid == 0)
1193752e453SMichael Ellerman exit(eat_cpu_child(write_pipe, read_pipe));
1203752e453SMichael Ellerman
1213752e453SMichael Ellerman if (sync_with_child(read_pipe, write_pipe)) {
1223752e453SMichael Ellerman rc = -1;
1233752e453SMichael Ellerman goto out;
1243752e453SMichael Ellerman }
1253752e453SMichael Ellerman
1263752e453SMichael Ellerman printf("main test running as pid %d\n", getpid());
1273752e453SMichael Ellerman
1283752e453SMichael Ellerman rc = test_function();
1293752e453SMichael Ellerman out:
1303752e453SMichael Ellerman kill(pid, SIGKILL);
1313752e453SMichael Ellerman
1323752e453SMichael Ellerman return rc;
1333752e453SMichael Ellerman }
1343752e453SMichael Ellerman
1353752e453SMichael Ellerman struct addr_range libc, vdso;
1363752e453SMichael Ellerman
parse_proc_maps(void)1373752e453SMichael Ellerman int parse_proc_maps(void)
1383752e453SMichael Ellerman {
1396861b44aSMichael Ellerman unsigned long start, end;
1403752e453SMichael Ellerman char execute, name[128];
1413752e453SMichael Ellerman FILE *f;
1423752e453SMichael Ellerman int rc;
1433752e453SMichael Ellerman
1443752e453SMichael Ellerman f = fopen("/proc/self/maps", "r");
1453752e453SMichael Ellerman if (!f) {
1463752e453SMichael Ellerman perror("fopen");
1473752e453SMichael Ellerman return -1;
1483752e453SMichael Ellerman }
1493752e453SMichael Ellerman
1503752e453SMichael Ellerman do {
1513752e453SMichael Ellerman /* This skips line with no executable which is what we want */
1523752e453SMichael Ellerman rc = fscanf(f, "%lx-%lx %*c%*c%c%*c %*x %*d:%*d %*d %127s\n",
1533752e453SMichael Ellerman &start, &end, &execute, name);
1543752e453SMichael Ellerman if (rc <= 0)
1553752e453SMichael Ellerman break;
1563752e453SMichael Ellerman
1573752e453SMichael Ellerman if (execute != 'x')
1583752e453SMichael Ellerman continue;
1593752e453SMichael Ellerman
1603752e453SMichael Ellerman if (strstr(name, "libc")) {
1613752e453SMichael Ellerman libc.first = start;
1623752e453SMichael Ellerman libc.last = end - 1;
1633752e453SMichael Ellerman } else if (strstr(name, "[vdso]")) {
1643752e453SMichael Ellerman vdso.first = start;
1653752e453SMichael Ellerman vdso.last = end - 1;
1663752e453SMichael Ellerman }
1673752e453SMichael Ellerman } while(1);
1683752e453SMichael Ellerman
1693752e453SMichael Ellerman fclose(f);
1703752e453SMichael Ellerman
1713752e453SMichael Ellerman return 0;
1723752e453SMichael Ellerman }
1733752e453SMichael Ellerman
1743752e453SMichael Ellerman #define PARANOID_PATH "/proc/sys/kernel/perf_event_paranoid"
1753752e453SMichael Ellerman
require_paranoia_below(int level)1763752e453SMichael Ellerman bool require_paranoia_below(int level)
1773752e453SMichael Ellerman {
178a974f0c1SBenjamin Gray int err;
179d4ecdff2SCyril Bur long current;
1803752e453SMichael Ellerman
1815c20de57SBenjamin Gray err = read_long(PARANOID_PATH, ¤t, 10);
182d1bc05b7SBenjamin Gray if (err) {
1833752e453SMichael Ellerman printf("Couldn't parse " PARANOID_PATH "?\n");
184a974f0c1SBenjamin Gray return false;
1853752e453SMichael Ellerman }
1863752e453SMichael Ellerman
187a974f0c1SBenjamin Gray return current < level;
1883752e453SMichael Ellerman }
189