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 if (write(power_state_fd, "mem", strlen("mem")) != strlen("mem")) 157 ksft_exit_fail_msg("Failed to enter Suspend state\n"); 158 159 close(timerfd); 160 close(power_state_fd); 161 } 162 163 int main(int argc, char **argv) 164 { 165 int opt; 166 bool do_suspend = true; 167 bool succeeded = true; 168 unsigned int tests = 0; 169 cpu_set_t available_cpus; 170 int err; 171 int cpu; 172 173 ksft_print_header(); 174 175 while ((opt = getopt(argc, argv, "n")) != -1) { 176 switch (opt) { 177 case 'n': 178 do_suspend = false; 179 break; 180 default: 181 printf("Usage: %s [-n]\n", argv[0]); 182 printf(" -n: do not trigger a suspend/resume cycle before the test\n"); 183 return -1; 184 } 185 } 186 187 err = sched_getaffinity(0, sizeof(available_cpus), &available_cpus); 188 if (err < 0) 189 ksft_exit_fail_msg("sched_getaffinity() failed\n"); 190 191 for (cpu = 0; cpu < CPU_SETSIZE; cpu++) { 192 if (!CPU_ISSET(cpu, &available_cpus)) 193 continue; 194 tests++; 195 } 196 197 if (do_suspend) 198 suspend(); 199 200 ksft_set_plan(tests); 201 for (cpu = 0; cpu < CPU_SETSIZE; cpu++) { 202 int test_success; 203 204 if (!CPU_ISSET(cpu, &available_cpus)) 205 continue; 206 207 test_success = run_test(cpu); 208 switch (test_success) { 209 case KSFT_PASS: 210 ksft_test_result_pass("CPU %d\n", cpu); 211 break; 212 case KSFT_SKIP: 213 ksft_test_result_skip("CPU %d\n", cpu); 214 break; 215 case KSFT_FAIL: 216 ksft_test_result_fail("CPU %d\n", cpu); 217 succeeded = false; 218 break; 219 } 220 } 221 222 if (succeeded) 223 ksft_exit_pass(); 224 else 225 ksft_exit_fail(); 226 } 227