xref: /openbmc/linux/tools/testing/selftests/breakpoints/step_after_suspend_test.c (revision fac59652993f075d57860769c99045b3ca18780d)
19c92ab61SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2bfd092b8SGreg Hackmann /*
3bfd092b8SGreg Hackmann  * Copyright (C) 2016 Google, Inc.
4bfd092b8SGreg Hackmann  */
5bfd092b8SGreg Hackmann 
6bfd092b8SGreg Hackmann #define _GNU_SOURCE
7bfd092b8SGreg Hackmann 
8bfd092b8SGreg Hackmann #include <errno.h>
9bfd092b8SGreg Hackmann #include <fcntl.h>
10bfd092b8SGreg Hackmann #include <sched.h>
11bfd092b8SGreg Hackmann #include <signal.h>
12bfd092b8SGreg Hackmann #include <stdbool.h>
13bfd092b8SGreg Hackmann #include <stdio.h>
14bfd092b8SGreg Hackmann #include <string.h>
15bfd092b8SGreg Hackmann #include <unistd.h>
16bfd092b8SGreg Hackmann #include <sys/ptrace.h>
17bfd092b8SGreg Hackmann #include <sys/stat.h>
18bfd092b8SGreg Hackmann #include <sys/timerfd.h>
19bfd092b8SGreg Hackmann #include <sys/types.h>
20bfd092b8SGreg Hackmann #include <sys/wait.h>
21bfd092b8SGreg Hackmann 
22bfd092b8SGreg Hackmann #include "../kselftest.h"
23bfd092b8SGreg Hackmann 
child(int cpu)24bfd092b8SGreg Hackmann void child(int cpu)
25bfd092b8SGreg Hackmann {
26bfd092b8SGreg Hackmann 	cpu_set_t set;
27bfd092b8SGreg Hackmann 
28bfd092b8SGreg Hackmann 	CPU_ZERO(&set);
29bfd092b8SGreg Hackmann 	CPU_SET(cpu, &set);
30bfd092b8SGreg Hackmann 	if (sched_setaffinity(0, sizeof(set), &set) != 0) {
313fa72f2cSShuah Khan 		ksft_print_msg("sched_setaffinity() failed: %s\n",
323fa72f2cSShuah Khan 			strerror(errno));
33bfd092b8SGreg Hackmann 		_exit(1);
34bfd092b8SGreg Hackmann 	}
35bfd092b8SGreg Hackmann 
36bfd092b8SGreg Hackmann 	if (ptrace(PTRACE_TRACEME, 0, NULL, NULL) != 0) {
373fa72f2cSShuah Khan 		ksft_print_msg("ptrace(PTRACE_TRACEME) failed: %s\n",
383fa72f2cSShuah Khan 			strerror(errno));
39bfd092b8SGreg Hackmann 		_exit(1);
40bfd092b8SGreg Hackmann 	}
41bfd092b8SGreg Hackmann 
42bfd092b8SGreg Hackmann 	if (raise(SIGSTOP) != 0) {
433fa72f2cSShuah Khan 		ksft_print_msg("raise(SIGSTOP) failed: %s\n", strerror(errno));
44bfd092b8SGreg Hackmann 		_exit(1);
45bfd092b8SGreg Hackmann 	}
46bfd092b8SGreg Hackmann 
47bfd092b8SGreg Hackmann 	_exit(0);
48bfd092b8SGreg Hackmann }
49bfd092b8SGreg Hackmann 
run_test(int cpu)50f000a39cSPaolo Bonzini int run_test(int cpu)
51bfd092b8SGreg Hackmann {
52bfd092b8SGreg Hackmann 	int status;
53bfd092b8SGreg Hackmann 	pid_t pid = fork();
54bfd092b8SGreg Hackmann 	pid_t wpid;
55bfd092b8SGreg Hackmann 
56bfd092b8SGreg Hackmann 	if (pid < 0) {
573fa72f2cSShuah Khan 		ksft_print_msg("fork() failed: %s\n", strerror(errno));
58f000a39cSPaolo Bonzini 		return KSFT_FAIL;
59bfd092b8SGreg Hackmann 	}
60bfd092b8SGreg Hackmann 	if (pid == 0)
61bfd092b8SGreg Hackmann 		child(cpu);
62bfd092b8SGreg Hackmann 
63bfd092b8SGreg Hackmann 	wpid = waitpid(pid, &status, __WALL);
64bfd092b8SGreg Hackmann 	if (wpid != pid) {
653fa72f2cSShuah Khan 		ksft_print_msg("waitpid() failed: %s\n", strerror(errno));
66f000a39cSPaolo Bonzini 		return KSFT_FAIL;
67bfd092b8SGreg Hackmann 	}
68bfd092b8SGreg Hackmann 	if (!WIFSTOPPED(status)) {
693fa72f2cSShuah Khan 		ksft_print_msg("child did not stop: %s\n", strerror(errno));
70f000a39cSPaolo Bonzini 		return KSFT_FAIL;
71bfd092b8SGreg Hackmann 	}
72bfd092b8SGreg Hackmann 	if (WSTOPSIG(status) != SIGSTOP) {
733fa72f2cSShuah Khan 		ksft_print_msg("child did not stop with SIGSTOP: %s\n",
743fa72f2cSShuah Khan 			strerror(errno));
75f000a39cSPaolo Bonzini 		return KSFT_FAIL;
76bfd092b8SGreg Hackmann 	}
77bfd092b8SGreg Hackmann 
78bfd092b8SGreg Hackmann 	if (ptrace(PTRACE_SINGLESTEP, pid, NULL, NULL) < 0) {
79bfd092b8SGreg Hackmann 		if (errno == EIO) {
80f000a39cSPaolo Bonzini 			ksft_print_msg(
813fa72f2cSShuah Khan 				"ptrace(PTRACE_SINGLESTEP) not supported on this architecture: %s\n",
823fa72f2cSShuah Khan 				strerror(errno));
83f000a39cSPaolo Bonzini 			return KSFT_SKIP;
84bfd092b8SGreg Hackmann 		}
853fa72f2cSShuah Khan 		ksft_print_msg("ptrace(PTRACE_SINGLESTEP) failed: %s\n",
863fa72f2cSShuah Khan 			strerror(errno));
87f000a39cSPaolo Bonzini 		return KSFT_FAIL;
88bfd092b8SGreg Hackmann 	}
89bfd092b8SGreg Hackmann 
90bfd092b8SGreg Hackmann 	wpid = waitpid(pid, &status, __WALL);
91bfd092b8SGreg Hackmann 	if (wpid != pid) {
923fa72f2cSShuah Khan 		ksft_print_msg("waitpid() failed: $s\n", strerror(errno));
93f000a39cSPaolo Bonzini 		return KSFT_FAIL;
94bfd092b8SGreg Hackmann 	}
95bfd092b8SGreg Hackmann 	if (WIFEXITED(status)) {
963fa72f2cSShuah Khan 		ksft_print_msg("child did not single-step: %s\n",
973fa72f2cSShuah Khan 			strerror(errno));
98f000a39cSPaolo Bonzini 		return KSFT_FAIL;
99bfd092b8SGreg Hackmann 	}
100bfd092b8SGreg Hackmann 	if (!WIFSTOPPED(status)) {
1013fa72f2cSShuah Khan 		ksft_print_msg("child did not stop: %s\n", strerror(errno));
102f000a39cSPaolo Bonzini 		return KSFT_FAIL;
103bfd092b8SGreg Hackmann 	}
104bfd092b8SGreg Hackmann 	if (WSTOPSIG(status) != SIGTRAP) {
1053fa72f2cSShuah Khan 		ksft_print_msg("child did not stop with SIGTRAP: %s\n",
1063fa72f2cSShuah Khan 			strerror(errno));
107f000a39cSPaolo Bonzini 		return KSFT_FAIL;
108bfd092b8SGreg Hackmann 	}
109bfd092b8SGreg Hackmann 
110bfd092b8SGreg Hackmann 	if (ptrace(PTRACE_CONT, pid, NULL, NULL) < 0) {
1113fa72f2cSShuah Khan 		ksft_print_msg("ptrace(PTRACE_CONT) failed: %s\n",
1123fa72f2cSShuah Khan 			strerror(errno));
113f000a39cSPaolo Bonzini 		return KSFT_FAIL;
114bfd092b8SGreg Hackmann 	}
115bfd092b8SGreg Hackmann 
116bfd092b8SGreg Hackmann 	wpid = waitpid(pid, &status, __WALL);
117bfd092b8SGreg Hackmann 	if (wpid != pid) {
1183fa72f2cSShuah Khan 		ksft_print_msg("waitpid() failed: %s\n", strerror(errno));
119f000a39cSPaolo Bonzini 		return KSFT_FAIL;
120bfd092b8SGreg Hackmann 	}
121bfd092b8SGreg Hackmann 	if (!WIFEXITED(status)) {
1223fa72f2cSShuah Khan 		ksft_print_msg("child did not exit after PTRACE_CONT: %s\n",
1233fa72f2cSShuah Khan 			strerror(errno));
124f000a39cSPaolo Bonzini 		return KSFT_FAIL;
125bfd092b8SGreg Hackmann 	}
126bfd092b8SGreg Hackmann 
127f000a39cSPaolo Bonzini 	return KSFT_PASS;
128bfd092b8SGreg Hackmann }
129bfd092b8SGreg Hackmann 
suspend(void)130bfd092b8SGreg Hackmann void suspend(void)
131bfd092b8SGreg Hackmann {
132bfd092b8SGreg Hackmann 	int power_state_fd;
133bfd092b8SGreg Hackmann 	struct sigevent event = {};
134bfd092b8SGreg Hackmann 	int timerfd;
135bfd092b8SGreg Hackmann 	int err;
136bfd092b8SGreg Hackmann 	struct itimerspec spec = {};
137bfd092b8SGreg Hackmann 
138423353a1SShuah Khan (Samsung OSG) 	if (getuid() != 0)
139423353a1SShuah Khan (Samsung OSG) 		ksft_exit_skip("Please run the test as root - Exiting.\n");
140423353a1SShuah Khan (Samsung OSG) 
141bfd092b8SGreg Hackmann 	power_state_fd = open("/sys/power/state", O_RDWR);
142b9012164SPaul Elder 	if (power_state_fd < 0)
143b9012164SPaul Elder 		ksft_exit_fail_msg(
144423353a1SShuah Khan (Samsung OSG) 			"open(\"/sys/power/state\") failed %s)\n",
145423353a1SShuah Khan (Samsung OSG) 			strerror(errno));
146bfd092b8SGreg Hackmann 
147bfd092b8SGreg Hackmann 	timerfd = timerfd_create(CLOCK_BOOTTIME_ALARM, 0);
148b9012164SPaul Elder 	if (timerfd < 0)
1493fa72f2cSShuah Khan 		ksft_exit_fail_msg("timerfd_create() failed\n");
150bfd092b8SGreg Hackmann 
151bfd092b8SGreg Hackmann 	spec.it_value.tv_sec = 5;
152bfd092b8SGreg Hackmann 	err = timerfd_settime(timerfd, 0, &spec, NULL);
153b9012164SPaul Elder 	if (err < 0)
1543fa72f2cSShuah Khan 		ksft_exit_fail_msg("timerfd_settime() failed\n");
155bfd092b8SGreg Hackmann 
156*4019391dSYifei Liu 	system("(echo mem > /sys/power/state) 2> /dev/null");
157*4019391dSYifei Liu 
158*4019391dSYifei Liu 	timerfd_gettime(timerfd, &spec);
159*4019391dSYifei Liu 	if (spec.it_value.tv_sec != 0 || spec.it_value.tv_nsec != 0)
1603fa72f2cSShuah Khan 		ksft_exit_fail_msg("Failed to enter Suspend state\n");
161bfd092b8SGreg Hackmann 
162bfd092b8SGreg Hackmann 	close(timerfd);
163bfd092b8SGreg Hackmann 	close(power_state_fd);
164bfd092b8SGreg Hackmann }
165bfd092b8SGreg Hackmann 
main(int argc,char ** argv)166bfd092b8SGreg Hackmann int main(int argc, char **argv)
167bfd092b8SGreg Hackmann {
168bfd092b8SGreg Hackmann 	int opt;
169bfd092b8SGreg Hackmann 	bool do_suspend = true;
170bfd092b8SGreg Hackmann 	bool succeeded = true;
1715821ba96SKees Cook 	unsigned int tests = 0;
172bfd092b8SGreg Hackmann 	cpu_set_t available_cpus;
173bfd092b8SGreg Hackmann 	int err;
174bfd092b8SGreg Hackmann 	int cpu;
175b9012164SPaul Elder 
176b9012164SPaul Elder 	ksft_print_header();
177bfd092b8SGreg Hackmann 
178bfd092b8SGreg Hackmann 	while ((opt = getopt(argc, argv, "n")) != -1) {
179bfd092b8SGreg Hackmann 		switch (opt) {
180bfd092b8SGreg Hackmann 		case 'n':
181bfd092b8SGreg Hackmann 			do_suspend = false;
182bfd092b8SGreg Hackmann 			break;
183bfd092b8SGreg Hackmann 		default:
184bfd092b8SGreg Hackmann 			printf("Usage: %s [-n]\n", argv[0]);
185bfd092b8SGreg Hackmann 			printf("        -n: do not trigger a suspend/resume cycle before the test\n");
186bfd092b8SGreg Hackmann 			return -1;
187bfd092b8SGreg Hackmann 		}
188bfd092b8SGreg Hackmann 	}
189bfd092b8SGreg Hackmann 
190ce32659bSPaolo Bonzini 	err = sched_getaffinity(0, sizeof(available_cpus), &available_cpus);
191ce32659bSPaolo Bonzini 	if (err < 0)
192ce32659bSPaolo Bonzini 		ksft_exit_fail_msg("sched_getaffinity() failed\n");
193ce32659bSPaolo Bonzini 
1945821ba96SKees Cook 	for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
1955821ba96SKees Cook 		if (!CPU_ISSET(cpu, &available_cpus))
1965821ba96SKees Cook 			continue;
1975821ba96SKees Cook 		tests++;
1985821ba96SKees Cook 	}
1995821ba96SKees Cook 
200bfd092b8SGreg Hackmann 	if (do_suspend)
201bfd092b8SGreg Hackmann 		suspend();
202bfd092b8SGreg Hackmann 
203f000a39cSPaolo Bonzini 	ksft_set_plan(tests);
204bfd092b8SGreg Hackmann 	for (cpu = 0; cpu < CPU_SETSIZE; cpu++) {
205f000a39cSPaolo Bonzini 		int test_success;
206bfd092b8SGreg Hackmann 
207bfd092b8SGreg Hackmann 		if (!CPU_ISSET(cpu, &available_cpus))
208bfd092b8SGreg Hackmann 			continue;
209bfd092b8SGreg Hackmann 
210bfd092b8SGreg Hackmann 		test_success = run_test(cpu);
211f000a39cSPaolo Bonzini 		switch (test_success) {
212f000a39cSPaolo Bonzini 		case KSFT_PASS:
2133fa72f2cSShuah Khan 			ksft_test_result_pass("CPU %d\n", cpu);
214f000a39cSPaolo Bonzini 			break;
215f000a39cSPaolo Bonzini 		case KSFT_SKIP:
216f000a39cSPaolo Bonzini 			ksft_test_result_skip("CPU %d\n", cpu);
217f000a39cSPaolo Bonzini 			break;
218f000a39cSPaolo Bonzini 		case KSFT_FAIL:
2193fa72f2cSShuah Khan 			ksft_test_result_fail("CPU %d\n", cpu);
220bfd092b8SGreg Hackmann 			succeeded = false;
221f000a39cSPaolo Bonzini 			break;
222bfd092b8SGreg Hackmann 		}
223bfd092b8SGreg Hackmann 	}
224bfd092b8SGreg Hackmann 
225bfd092b8SGreg Hackmann 	if (succeeded)
226bfd092b8SGreg Hackmann 		ksft_exit_pass();
227bfd092b8SGreg Hackmann 	else
228bfd092b8SGreg Hackmann 		ksft_exit_fail();
229bfd092b8SGreg Hackmann }
230