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 int 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 KSFT_FAIL; 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 KSFT_FAIL; 67 } 68 if (!WIFSTOPPED(status)) { 69 ksft_print_msg("child did not stop: %s\n", strerror(errno)); 70 return KSFT_FAIL; 71 } 72 if (WSTOPSIG(status) != SIGSTOP) { 73 ksft_print_msg("child did not stop with SIGSTOP: %s\n", 74 strerror(errno)); 75 return KSFT_FAIL; 76 } 77 78 if (ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0) { 79 if (errno == EIO) { 80 ksft_print_msg( 81 "ptrace(PTRACE_SINGLESTEP) not supported on this architecture: %s\n", 82 strerror(errno)); 83 return KSFT_SKIP; 84 } 85 ksft_print_msg("ptrace(PTRACE_SINGLESTEP) failed: %s\n", 86 strerror(errno)); 87 return KSFT_FAIL; 88 } 89 90 wpid = waitpid(pid, &status, __WALL); 91 if (wpid != pid) { 92 ksft_print_msg("waitpid() failed: $s\n", strerror(errno)); 93 return KSFT_FAIL; 94 } 95 if (WIFEXITED(status)) { 96 ksft_print_msg("child did not single-step: %s\n", 97 strerror(errno)); 98 return KSFT_FAIL; 99 } 100 if (!WIFSTOPPED(status)) { 101 ksft_print_msg("child did not stop: %s\n", strerror(errno)); 102 return KSFT_FAIL; 103 } 104 if (WSTOPSIG(status) != SIGTRAP) { 105 ksft_print_msg("child did not stop with SIGTRAP: %s\n", 106 strerror(errno)); 107 return KSFT_FAIL; 108 } 109 110 if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) { 111 ksft_print_msg("ptrace(PTRACE_CONT) failed: %s\n", 112 strerror(errno)); 113 return KSFT_FAIL; 114 } 115 116 wpid = waitpid(pid, &status, __WALL); 117 if (wpid != pid) { 118 ksft_print_msg("waitpid() failed: %s\n", strerror(errno)); 119 return KSFT_FAIL; 120 } 121 if (!WIFEXITED(status)) { 122 ksft_print_msg("child did not exit after PTRACE_CONT: %s\n", 123 strerror(errno)); 124 return KSFT_FAIL; 125 } 126 127 return KSFT_PASS; 128 } 129 130 void suspend(void) 131 { 132 int power_state_fd; 133 struct sigevent event = {}; 134 int timerfd; 135 int err; 136 struct itimerspec spec = {}; 137 138 if (getuid() != 0) 139 ksft_exit_skip("Please run the test as root - Exiting.\n"); 140 141 power_state_fd = open("/sys/power/state", O_RDWR); 142 if (power_state_fd < 0) 143 ksft_exit_fail_msg( 144 "open(\"/sys/power/state\") failed %s)\n", 145 strerror(errno)); 146 147 timerfd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0); 148 if (timerfd < 0) 149 ksft_exit_fail_msg("timerfd_create() failed\n"); 150 151 spec.it_value.tv_sec = 5; 152 err = timerfd_settime(timerfd, 0, &spec, NULL); 153 if (err < 0) 154 ksft_exit_fail_msg("timerfd_settime() failed\n"); 155 156 system("(echo mem > /sys/power/state) 2> /dev/null"); 157 158 timerfd_gettime(timerfd, &spec); 159 if (spec.it_value.tv_sec != 0 || spec.it_value.tv_nsec != 0) 160 ksft_exit_fail_msg("Failed to enter Suspend state\n"); 161 162 close(timerfd); 163 close(power_state_fd); 164 } 165 166 int main(int argc, char **argv) 167 { 168 int opt; 169 bool do_suspend = true; 170 bool succeeded = true; 171 unsigned int tests = 0; 172 cpu_set_t available_cpus; 173 int err; 174 int cpu; 175 176 ksft_print_header(); 177 178 while ((opt = getopt(argc, argv, "n")) != -1) { 179 switch (opt) { 180 case 'n': 181 do_suspend = false; 182 break; 183 default: 184 printf("Usage: %s [-n]\n", argv[0]); 185 printf(" -n: do not trigger a suspend/resume cycle before the test\n"); 186 return -1; 187 } 188 } 189 190 err = sched_getaffinity(0, sizeof(available_cpus), &available_cpus); 191 if (err < 0) 192 ksft_exit_fail_msg("sched_getaffinity() failed\n"); 193 194 for (cpu = 0; cpu < CPU_SETSIZE; cpu++) { 195 if (!CPU_ISSET(cpu, &available_cpus)) 196 continue; 197 tests++; 198 } 199 200 if (do_suspend) 201 suspend(); 202 203 ksft_set_plan(tests); 204 for (cpu = 0; cpu < CPU_SETSIZE; cpu++) { 205 int test_success; 206 207 if (!CPU_ISSET(cpu, &available_cpus)) 208 continue; 209 210 test_success = run_test(cpu); 211 switch (test_success) { 212 case KSFT_PASS: 213 ksft_test_result_pass("CPU %d\n", cpu); 214 break; 215 case KSFT_SKIP: 216 ksft_test_result_skip("CPU %d\n", cpu); 217 break; 218 case KSFT_FAIL: 219 ksft_test_result_fail("CPU %d\n", cpu); 220 succeeded = false; 221 break; 222 } 223 } 224 225 if (succeeded) 226 ksft_exit_pass(); 227 else 228 ksft_exit_fail(); 229 } 230