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