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