18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Copyright 2014, Michael Ellerman, IBM Corp. 48c2ecf20Sopenharmony_ci */ 58c2ecf20Sopenharmony_ci 68c2ecf20Sopenharmony_ci#define _GNU_SOURCE /* For CPU_ZERO etc. */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#include <errno.h> 98c2ecf20Sopenharmony_ci#include <sched.h> 108c2ecf20Sopenharmony_ci#include <setjmp.h> 118c2ecf20Sopenharmony_ci#include <stdlib.h> 128c2ecf20Sopenharmony_ci#include <sys/wait.h> 138c2ecf20Sopenharmony_ci 148c2ecf20Sopenharmony_ci#include "utils.h" 158c2ecf20Sopenharmony_ci#include "lib.h" 168c2ecf20Sopenharmony_ci 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ciint bind_to_cpu(int cpu) 198c2ecf20Sopenharmony_ci{ 208c2ecf20Sopenharmony_ci cpu_set_t mask; 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_ci printf("Binding to cpu %d\n", cpu); 238c2ecf20Sopenharmony_ci 248c2ecf20Sopenharmony_ci CPU_ZERO(&mask); 258c2ecf20Sopenharmony_ci CPU_SET(cpu, &mask); 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_ci return sched_setaffinity(0, sizeof(mask), &mask); 288c2ecf20Sopenharmony_ci} 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci#define PARENT_TOKEN 0xAA 318c2ecf20Sopenharmony_ci#define CHILD_TOKEN 0x55 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ciint sync_with_child(union pipe read_pipe, union pipe write_pipe) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci char c = PARENT_TOKEN; 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1); 388c2ecf20Sopenharmony_ci FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1); 398c2ecf20Sopenharmony_ci if (c != CHILD_TOKEN) /* sometimes expected */ 408c2ecf20Sopenharmony_ci return 1; 418c2ecf20Sopenharmony_ci 428c2ecf20Sopenharmony_ci return 0; 438c2ecf20Sopenharmony_ci} 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ciint wait_for_parent(union pipe read_pipe) 468c2ecf20Sopenharmony_ci{ 478c2ecf20Sopenharmony_ci char c; 488c2ecf20Sopenharmony_ci 498c2ecf20Sopenharmony_ci FAIL_IF(read(read_pipe.read_fd, &c, 1) != 1); 508c2ecf20Sopenharmony_ci FAIL_IF(c != PARENT_TOKEN); 518c2ecf20Sopenharmony_ci 528c2ecf20Sopenharmony_ci return 0; 538c2ecf20Sopenharmony_ci} 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ciint notify_parent(union pipe write_pipe) 568c2ecf20Sopenharmony_ci{ 578c2ecf20Sopenharmony_ci char c = CHILD_TOKEN; 588c2ecf20Sopenharmony_ci 598c2ecf20Sopenharmony_ci FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1); 608c2ecf20Sopenharmony_ci 618c2ecf20Sopenharmony_ci return 0; 628c2ecf20Sopenharmony_ci} 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ciint notify_parent_of_error(union pipe write_pipe) 658c2ecf20Sopenharmony_ci{ 668c2ecf20Sopenharmony_ci char c = ~CHILD_TOKEN; 678c2ecf20Sopenharmony_ci 688c2ecf20Sopenharmony_ci FAIL_IF(write(write_pipe.write_fd, &c, 1) != 1); 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci return 0; 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_ciint wait_for_child(pid_t child_pid) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci int rc; 768c2ecf20Sopenharmony_ci 778c2ecf20Sopenharmony_ci if (waitpid(child_pid, &rc, 0) == -1) { 788c2ecf20Sopenharmony_ci perror("waitpid"); 798c2ecf20Sopenharmony_ci return 1; 808c2ecf20Sopenharmony_ci } 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci if (WIFEXITED(rc)) 838c2ecf20Sopenharmony_ci rc = WEXITSTATUS(rc); 848c2ecf20Sopenharmony_ci else 858c2ecf20Sopenharmony_ci rc = 1; /* Signal or other */ 868c2ecf20Sopenharmony_ci 878c2ecf20Sopenharmony_ci return rc; 888c2ecf20Sopenharmony_ci} 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_ciint kill_child_and_wait(pid_t child_pid) 918c2ecf20Sopenharmony_ci{ 928c2ecf20Sopenharmony_ci kill(child_pid, SIGTERM); 938c2ecf20Sopenharmony_ci 948c2ecf20Sopenharmony_ci return wait_for_child(child_pid); 958c2ecf20Sopenharmony_ci} 968c2ecf20Sopenharmony_ci 978c2ecf20Sopenharmony_cistatic int eat_cpu_child(union pipe read_pipe, union pipe write_pipe) 988c2ecf20Sopenharmony_ci{ 998c2ecf20Sopenharmony_ci volatile int i = 0; 1008c2ecf20Sopenharmony_ci 1018c2ecf20Sopenharmony_ci /* 1028c2ecf20Sopenharmony_ci * We are just here to eat cpu and die. So make sure we can be killed, 1038c2ecf20Sopenharmony_ci * and also don't do any custom SIGTERM handling. 1048c2ecf20Sopenharmony_ci */ 1058c2ecf20Sopenharmony_ci signal(SIGTERM, SIG_DFL); 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci notify_parent(write_pipe); 1088c2ecf20Sopenharmony_ci wait_for_parent(read_pipe); 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_ci /* Soak up cpu forever */ 1118c2ecf20Sopenharmony_ci while (1) i++; 1128c2ecf20Sopenharmony_ci 1138c2ecf20Sopenharmony_ci return 0; 1148c2ecf20Sopenharmony_ci} 1158c2ecf20Sopenharmony_ci 1168c2ecf20Sopenharmony_cipid_t eat_cpu(int (test_function)(void)) 1178c2ecf20Sopenharmony_ci{ 1188c2ecf20Sopenharmony_ci union pipe read_pipe, write_pipe; 1198c2ecf20Sopenharmony_ci int cpu, rc; 1208c2ecf20Sopenharmony_ci pid_t pid; 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci cpu = pick_online_cpu(); 1238c2ecf20Sopenharmony_ci FAIL_IF(cpu < 0); 1248c2ecf20Sopenharmony_ci FAIL_IF(bind_to_cpu(cpu)); 1258c2ecf20Sopenharmony_ci 1268c2ecf20Sopenharmony_ci if (pipe(read_pipe.fds) == -1) 1278c2ecf20Sopenharmony_ci return -1; 1288c2ecf20Sopenharmony_ci 1298c2ecf20Sopenharmony_ci if (pipe(write_pipe.fds) == -1) 1308c2ecf20Sopenharmony_ci return -1; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_ci pid = fork(); 1338c2ecf20Sopenharmony_ci if (pid == 0) 1348c2ecf20Sopenharmony_ci exit(eat_cpu_child(write_pipe, read_pipe)); 1358c2ecf20Sopenharmony_ci 1368c2ecf20Sopenharmony_ci if (sync_with_child(read_pipe, write_pipe)) { 1378c2ecf20Sopenharmony_ci rc = -1; 1388c2ecf20Sopenharmony_ci goto out; 1398c2ecf20Sopenharmony_ci } 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci printf("main test running as pid %d\n", getpid()); 1428c2ecf20Sopenharmony_ci 1438c2ecf20Sopenharmony_ci rc = test_function(); 1448c2ecf20Sopenharmony_ciout: 1458c2ecf20Sopenharmony_ci kill(pid, SIGKILL); 1468c2ecf20Sopenharmony_ci 1478c2ecf20Sopenharmony_ci return rc; 1488c2ecf20Sopenharmony_ci} 1498c2ecf20Sopenharmony_ci 1508c2ecf20Sopenharmony_cistruct addr_range libc, vdso; 1518c2ecf20Sopenharmony_ci 1528c2ecf20Sopenharmony_ciint parse_proc_maps(void) 1538c2ecf20Sopenharmony_ci{ 1548c2ecf20Sopenharmony_ci unsigned long start, end; 1558c2ecf20Sopenharmony_ci char execute, name[128]; 1568c2ecf20Sopenharmony_ci FILE *f; 1578c2ecf20Sopenharmony_ci int rc; 1588c2ecf20Sopenharmony_ci 1598c2ecf20Sopenharmony_ci f = fopen("/proc/self/maps", "r"); 1608c2ecf20Sopenharmony_ci if (!f) { 1618c2ecf20Sopenharmony_ci perror("fopen"); 1628c2ecf20Sopenharmony_ci return -1; 1638c2ecf20Sopenharmony_ci } 1648c2ecf20Sopenharmony_ci 1658c2ecf20Sopenharmony_ci do { 1668c2ecf20Sopenharmony_ci /* This skips line with no executable which is what we want */ 1678c2ecf20Sopenharmony_ci rc = fscanf(f, "%lx-%lx %*c%*c%c%*c %*x %*d:%*d %*d %127s\n", 1688c2ecf20Sopenharmony_ci &start, &end, &execute, name); 1698c2ecf20Sopenharmony_ci if (rc <= 0) 1708c2ecf20Sopenharmony_ci break; 1718c2ecf20Sopenharmony_ci 1728c2ecf20Sopenharmony_ci if (execute != 'x') 1738c2ecf20Sopenharmony_ci continue; 1748c2ecf20Sopenharmony_ci 1758c2ecf20Sopenharmony_ci if (strstr(name, "libc")) { 1768c2ecf20Sopenharmony_ci libc.first = start; 1778c2ecf20Sopenharmony_ci libc.last = end - 1; 1788c2ecf20Sopenharmony_ci } else if (strstr(name, "[vdso]")) { 1798c2ecf20Sopenharmony_ci vdso.first = start; 1808c2ecf20Sopenharmony_ci vdso.last = end - 1; 1818c2ecf20Sopenharmony_ci } 1828c2ecf20Sopenharmony_ci } while(1); 1838c2ecf20Sopenharmony_ci 1848c2ecf20Sopenharmony_ci fclose(f); 1858c2ecf20Sopenharmony_ci 1868c2ecf20Sopenharmony_ci return 0; 1878c2ecf20Sopenharmony_ci} 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci#define PARANOID_PATH "/proc/sys/kernel/perf_event_paranoid" 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cibool require_paranoia_below(int level) 1928c2ecf20Sopenharmony_ci{ 1938c2ecf20Sopenharmony_ci long current; 1948c2ecf20Sopenharmony_ci char *end, buf[16]; 1958c2ecf20Sopenharmony_ci FILE *f; 1968c2ecf20Sopenharmony_ci bool rc; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_ci rc = false; 1998c2ecf20Sopenharmony_ci 2008c2ecf20Sopenharmony_ci f = fopen(PARANOID_PATH, "r"); 2018c2ecf20Sopenharmony_ci if (!f) { 2028c2ecf20Sopenharmony_ci perror("fopen"); 2038c2ecf20Sopenharmony_ci goto out; 2048c2ecf20Sopenharmony_ci } 2058c2ecf20Sopenharmony_ci 2068c2ecf20Sopenharmony_ci if (!fgets(buf, sizeof(buf), f)) { 2078c2ecf20Sopenharmony_ci printf("Couldn't read " PARANOID_PATH "?\n"); 2088c2ecf20Sopenharmony_ci goto out_close; 2098c2ecf20Sopenharmony_ci } 2108c2ecf20Sopenharmony_ci 2118c2ecf20Sopenharmony_ci current = strtol(buf, &end, 10); 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ci if (end == buf) { 2148c2ecf20Sopenharmony_ci printf("Couldn't parse " PARANOID_PATH "?\n"); 2158c2ecf20Sopenharmony_ci goto out_close; 2168c2ecf20Sopenharmony_ci } 2178c2ecf20Sopenharmony_ci 2188c2ecf20Sopenharmony_ci if (current >= level) 2198c2ecf20Sopenharmony_ci goto out_close; 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci rc = true; 2228c2ecf20Sopenharmony_ciout_close: 2238c2ecf20Sopenharmony_ci fclose(f); 2248c2ecf20Sopenharmony_ciout: 2258c2ecf20Sopenharmony_ci return rc; 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 228