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 /* 131 * Reads the suspend success count from sysfs. 132 * Returns the count on success or exits on failure. 133 */ 134 static int get_suspend_success_count_or_fail(void) 135 { 136 FILE *fp; 137 int val; 138 139 fp = fopen("/sys/power/suspend_stats/success", "r"); 140 if (!fp) 141 ksft_exit_fail_msg( 142 "Failed to open suspend_stats/success: %s\n", 143 strerror(errno)); 144 145 if (fscanf(fp, "%d", &val) != 1) { 146 fclose(fp); 147 ksft_exit_fail_msg( 148 "Failed to read suspend success count\n"); 149 } 150 151 fclose(fp); 152 return val; 153 } 154 155 void suspend(void) 156 { 157 int timerfd; 158 int err; 159 int count_before; 160 int count_after; 161 struct itimerspec spec = {}; 162 163 if (getuid() != 0) 164 ksft_exit_skip("Please run the test as root - Exiting.\n"); 165 166 timerfd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0); 167 if (timerfd < 0) 168 ksft_exit_fail_msg("timerfd_create() failed\n"); 169 170 spec.it_value.tv_sec = 5; 171 err = timerfd_settime(timerfd, 0, &spec, NULL); 172 if (err < 0) 173 ksft_exit_fail_msg("timerfd_settime() failed\n"); 174 175 count_before = get_suspend_success_count_or_fail(); 176 177 system("(echo mem > /sys/power/state) 2> /dev/null"); 178 179 count_after = get_suspend_success_count_or_fail(); 180 if (count_after <= count_before) 181 ksft_exit_fail_msg("Failed to enter Suspend state\n"); 182 183 close(timerfd); 184 } 185 186 int main(int argc, char **argv) 187 { 188 int opt; 189 bool do_suspend = true; 190 bool succeeded = true; 191 unsigned int tests = 0; 192 cpu_set_t available_cpus; 193 int err; 194 int cpu; 195 196 ksft_print_header(); 197 198 while ((opt = getopt(argc, argv, "n")) != -1) { 199 switch (opt) { 200 case 'n': 201 do_suspend = false; 202 break; 203 default: 204 printf("Usage: %s [-n]\n", argv[0]); 205 printf(" -n: do not trigger a suspend/resume cycle before the test\n"); 206 return -1; 207 } 208 } 209 210 err = sched_getaffinity(0, sizeof(available_cpus), &available_cpus); 211 if (err < 0) 212 ksft_exit_fail_msg("sched_getaffinity() failed\n"); 213 214 for (cpu = 0; cpu < CPU_SETSIZE; cpu++) { 215 if (!CPU_ISSET(cpu, &available_cpus)) 216 continue; 217 tests++; 218 } 219 220 if (do_suspend) 221 suspend(); 222 223 ksft_set_plan(tests); 224 for (cpu = 0; cpu < CPU_SETSIZE; cpu++) { 225 int test_success; 226 227 if (!CPU_ISSET(cpu, &available_cpus)) 228 continue; 229 230 test_success = run_test(cpu); 231 switch (test_success) { 232 case KSFT_PASS: 233 ksft_test_result_pass("CPU %d\n", cpu); 234 break; 235 case KSFT_SKIP: 236 ksft_test_result_skip("CPU %d\n", cpu); 237 break; 238 case KSFT_FAIL: 239 ksft_test_result_fail("CPU %d\n", cpu); 240 succeeded = false; 241 break; 242 } 243 } 244 245 if (succeeded) 246 ksft_exit_pass(); 247 else 248 ksft_exit_fail(); 249 } 250