1 // SPDX-License-Identifier: GPL-2.0-only 2 /* 3 * Copyright (C) 2016 Google, Inc. 4 */ 5 6 #define _GNU_SOURCE 7 8 #include <errno.h> 9 #include <fcntl.h> 10 #include <sched.h> 11 #include <signal.h> 12 #include <stdbool.h> 13 #include <stdio.h> 14 #include <string.h> 15 #include <unistd.h> 16 #include <sys/ptrace.h> 17 #include <sys/stat.h> 18 #include <sys/timerfd.h> 19 #include <sys/types.h> 20 #include <sys/wait.h> 21 22 #include "../kselftest.h" 23 24 void child(int cpu) 25 { 26 cpu_set_t set; 27 28 CPU_ZERO(&set); 29 CPU_SET(cpu, &set); 30 if (sched_setaffinity(0, sizeof(set), &set) != 0) { 31 ksft_print_msg("sched_setaffinity() failed: %s\n", 32 strerror(errno)); 33 _exit(1); 34 } 35 36 if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) != 0) { 37 ksft_print_msg("ptrace(PTRACE_TRACEME) failed: %s\n", 38 strerror(errno)); 39 _exit(1); 40 } 41 42 if (raise(SIGSTOP) != 0) { 43 ksft_print_msg("raise(SIGSTOP) failed: %s\n", strerror(errno)); 44 _exit(1); 45 } 46 47 _exit(0); 48 } 49 50 bool run_test(int cpu) 51 { 52 int status; 53 pid_t pid = fork(); 54 pid_t wpid; 55 56 if (pid < 0) { 57 ksft_print_msg("fork() failed: %s\n", strerror(errno)); 58 return false; 59 } 60 if (pid == 0) 61 child(cpu); 62 63 wpid = waitpid(pid, &status, __WALL); 64 if (wpid != pid) { 65 ksft_print_msg("waitpid() failed: %s\n", strerror(errno)); 66 return false; 67 } 68 if (!WIFSTOPPED(status)) { 69 ksft_print_msg("child did not stop: %s\n", strerror(errno)); 70 return false; 71 } 72 if (WSTOPSIG(status) != SIGSTOP) { 73 ksft_print_msg("child did not stop with SIGSTOP: %s\n", 74 strerror(errno)); 75 return false; 76 } 77 78 if (ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0) { 79 if (errno == EIO) { 80 ksft_exit_skip( 81 "ptrace(PTRACE_SINGLESTEP) not supported on this architecture: %s\n", 82 strerror(errno)); 83 } 84 ksft_print_msg("ptrace(PTRACE_SINGLESTEP) failed: %s\n", 85 strerror(errno)); 86 return false; 87 } 88 89 wpid = waitpid(pid, &status, __WALL); 90 if (wpid != pid) { 91 ksft_print_msg("waitpid() failed: $s\n", strerror(errno)); 92 return false; 93 } 94 if (WIFEXITED(status)) { 95 ksft_print_msg("child did not single-step: %s\n", 96 strerror(errno)); 97 return false; 98 } 99 if (!WIFSTOPPED(status)) { 100 ksft_print_msg("child did not stop: %s\n", strerror(errno)); 101 return false; 102 } 103 if (WSTOPSIG(status) != SIGTRAP) { 104 ksft_print_msg("child did not stop with SIGTRAP: %s\n", 105 strerror(errno)); 106 return false; 107 } 108 109 if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) { 110 ksft_print_msg("ptrace(PTRACE_CONT) failed: %s\n", 111 strerror(errno)); 112 return false; 113 } 114 115 wpid = waitpid(pid, &status, __WALL); 116 if (wpid != pid) { 117 ksft_print_msg("waitpid() failed: %s\n", strerror(errno)); 118 return false; 119 } 120 if (!WIFEXITED(status)) { 121 ksft_print_msg("child did not exit after PTRACE_CONT: %s\n", 122 strerror(errno)); 123 return false; 124 } 125 126 return true; 127 } 128 129 void suspend(void) 130 { 131 int power_state_fd; 132 struct sigevent event = {}; 133 int timerfd; 134 int err; 135 struct itimerspec spec = {}; 136 137 if (getuid() != 0) 138 ksft_exit_skip("Please run the test as root - Exiting.\n"); 139 140 power_state_fd = open("/sys/power/state", O_RDWR); 141 if (power_state_fd < 0) 142 ksft_exit_fail_msg( 143 "open(\"/sys/power/state\") failed %s)\n", 144 strerror(errno)); 145 146 timerfd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0); 147 if (timerfd < 0) 148 ksft_exit_fail_msg("timerfd_create() failed\n"); 149 150 spec.it_value.tv_sec = 5; 151 err = timerfd_settime(timerfd, 0, &spec, NULL); 152 if (err < 0) 153 ksft_exit_fail_msg("timerfd_settime() failed\n"); 154 155 if (write(power_state_fd, "mem", strlen("mem")) != strlen("mem")) 156 ksft_exit_fail_msg("Failed to enter Suspend state\n"); 157 158 close(timerfd); 159 close(power_state_fd); 160 } 161 162 int main(int argc, char **argv) 163 { 164 int opt; 165 bool do_suspend = true; 166 bool succeeded = true; 167 unsigned int tests = 0; 168 cpu_set_t available_cpus; 169 int err; 170 int cpu; 171 172 ksft_print_header(); 173 174 while ((opt = getopt(argc, argv, "n")) != -1) { 175 switch (opt) { 176 case 'n': 177 do_suspend = false; 178 break; 179 default: 180 printf("Usage: %s [-n]\n", argv[0]); 181 printf(" -n: do not trigger a suspend/resume cycle before the test\n"); 182 return -1; 183 } 184 } 185 186 for (cpu = 0; cpu < CPU_SETSIZE; cpu++) { 187 if (!CPU_ISSET(cpu, &available_cpus)) 188 continue; 189 tests++; 190 } 191 ksft_set_plan(tests); 192 193 if (do_suspend) 194 suspend(); 195 196 err = sched_getaffinity(0, sizeof(available_cpus), &available_cpus); 197 if (err < 0) 198 ksft_exit_fail_msg("sched_getaffinity() failed\n"); 199 200 for (cpu = 0; cpu < CPU_SETSIZE; cpu++) { 201 bool test_success; 202 203 if (!CPU_ISSET(cpu, &available_cpus)) 204 continue; 205 206 test_success = run_test(cpu); 207 if (test_success) { 208 ksft_test_result_pass("CPU %d\n", cpu); 209 } else { 210 ksft_test_result_fail("CPU %d\n", cpu); 211 succeeded = false; 212 } 213 } 214 215 if (succeeded) 216 ksft_exit_pass(); 217 else 218 ksft_exit_fail(); 219 } 220