1*19c3b8c2SApple OSS Distributions #include <unistd.h>
2*19c3b8c2SApple OSS Distributions #include <stdio.h>
3*19c3b8c2SApple OSS Distributions #include <signal.h>
4*19c3b8c2SApple OSS Distributions
5*19c3b8c2SApple OSS Distributions #include <darwintest.h>
6*19c3b8c2SApple OSS Distributions #include <darwintest_utils.h>
7*19c3b8c2SApple OSS Distributions
8*19c3b8c2SApple OSS Distributions /*
9*19c3b8c2SApple OSS Distributions * We're going to inject ECC errors into shared library text, so don't
10*19c3b8c2SApple OSS Distributions * run with other tests.
11*19c3b8c2SApple OSS Distributions */
12*19c3b8c2SApple OSS Distributions T_GLOBAL_META(T_META_RUN_CONCURRENTLY(false),
13*19c3b8c2SApple OSS Distributions T_META_OWNER("josephb_22"),
14*19c3b8c2SApple OSS Distributions T_META_NAMESPACE("xnu.vm"),
15*19c3b8c2SApple OSS Distributions T_META_RADAR_COMPONENT_NAME("xnu"),
16*19c3b8c2SApple OSS Distributions T_META_RADAR_COMPONENT_VERSION("VM"));
17*19c3b8c2SApple OSS Distributions
18*19c3b8c2SApple OSS Distributions /*
19*19c3b8c2SApple OSS Distributions * No system(3c) on watchOS, so provide our own.
20*19c3b8c2SApple OSS Distributions * returns -1 if fails to run
21*19c3b8c2SApple OSS Distributions * returns 0 if process exits normally.
22*19c3b8c2SApple OSS Distributions * returns +n if process exits due to signal N
23*19c3b8c2SApple OSS Distributions */
24*19c3b8c2SApple OSS Distributions static int
my_system(const char * command,const char * arg)25*19c3b8c2SApple OSS Distributions my_system(const char *command, const char *arg)
26*19c3b8c2SApple OSS Distributions {
27*19c3b8c2SApple OSS Distributions pid_t pid;
28*19c3b8c2SApple OSS Distributions int status = 0;
29*19c3b8c2SApple OSS Distributions int signal = 0;
30*19c3b8c2SApple OSS Distributions int ret;
31*19c3b8c2SApple OSS Distributions const char *argv[] = {
32*19c3b8c2SApple OSS Distributions command,
33*19c3b8c2SApple OSS Distributions /* "-v", uncomment if debugging the tests */
34*19c3b8c2SApple OSS Distributions arg,
35*19c3b8c2SApple OSS Distributions NULL
36*19c3b8c2SApple OSS Distributions };
37*19c3b8c2SApple OSS Distributions
38*19c3b8c2SApple OSS Distributions if (dt_launch_tool(&pid, (char **)(void *)argv, FALSE, NULL, NULL)) {
39*19c3b8c2SApple OSS Distributions return -1;
40*19c3b8c2SApple OSS Distributions }
41*19c3b8c2SApple OSS Distributions
42*19c3b8c2SApple OSS Distributions ret = dt_waitpid(pid, &status, &signal, 100);
43*19c3b8c2SApple OSS Distributions if (signal != 0) {
44*19c3b8c2SApple OSS Distributions return signal;
45*19c3b8c2SApple OSS Distributions } else if (status != 0) {
46*19c3b8c2SApple OSS Distributions return status;
47*19c3b8c2SApple OSS Distributions }
48*19c3b8c2SApple OSS Distributions return 0;
49*19c3b8c2SApple OSS Distributions }
50*19c3b8c2SApple OSS Distributions
51*19c3b8c2SApple OSS Distributions
52*19c3b8c2SApple OSS Distributions /*
53*19c3b8c2SApple OSS Distributions * The tests are run in the following order:
54*19c3b8c2SApple OSS Distributions *
55*19c3b8c2SApple OSS Distributions * - call foo (i.e. private text page)
56*19c3b8c2SApple OSS Distributions * - Inject ECC error into foo, then call foo
57*19c3b8c2SApple OSS Distributions *
58*19c3b8c2SApple OSS Distributions * - call atan (i.e. shared text page)
59*19c3b8c2SApple OSS Distributions * - inject ecc error into atan, then call atan
60*19c3b8c2SApple OSS Distributions *
61*19c3b8c2SApple OSS Distributions * atan() was picked as a shared region function that isn't likely used by any normal daemons.
62*19c3b8c2SApple OSS Distributions *
63*19c3b8c2SApple OSS Distributions * - reference to clean data page
64*19c3b8c2SApple OSS Distributions * - reference to clean data page with injected error
65*19c3b8c2SApple OSS Distributions *
66*19c3b8c2SApple OSS Distributions * - reference to dirty data page
67*19c3b8c2SApple OSS Distributions * - reference to dirty data page with injected error
68*19c3b8c2SApple OSS Distributions *
69*19c3b8c2SApple OSS Distributions * - copyout to page
70*19c3b8c2SApple OSS Distributions * - copyout to a page with injected error
71*19c3b8c2SApple OSS Distributions */
72*19c3b8c2SApple OSS Distributions static void
test_body(bool corrected)73*19c3b8c2SApple OSS Distributions test_body(bool corrected)
74*19c3b8c2SApple OSS Distributions {
75*19c3b8c2SApple OSS Distributions int ret;
76*19c3b8c2SApple OSS Distributions
77*19c3b8c2SApple OSS Distributions /*
78*19c3b8c2SApple OSS Distributions * test of process text page
79*19c3b8c2SApple OSS Distributions */
80*19c3b8c2SApple OSS Distributions ret = my_system("./ecc_test_helper", "foo");
81*19c3b8c2SApple OSS Distributions T_QUIET; T_ASSERT_EQ(ret, 0, "First call of foo");
82*19c3b8c2SApple OSS Distributions
83*19c3b8c2SApple OSS Distributions ret = my_system("./ecc_test_helper", "Xfoo");
84*19c3b8c2SApple OSS Distributions T_QUIET; T_ASSERT_EQ(ret, 0, "Failed to recover from ECC to clean app text page");
85*19c3b8c2SApple OSS Distributions
86*19c3b8c2SApple OSS Distributions ret = my_system("./ecc_test_helper", "foo");
87*19c3b8c2SApple OSS Distributions T_QUIET; T_ASSERT_EQ(ret, 0, "Fixed call of foo");
88*19c3b8c2SApple OSS Distributions
89*19c3b8c2SApple OSS Distributions /*
90*19c3b8c2SApple OSS Distributions * test of shared library text page
91*19c3b8c2SApple OSS Distributions */
92*19c3b8c2SApple OSS Distributions ret = my_system("./ecc_test_helper", "atan");
93*19c3b8c2SApple OSS Distributions T_QUIET; T_ASSERT_EQ(ret, 0, "First call of atan");
94*19c3b8c2SApple OSS Distributions
95*19c3b8c2SApple OSS Distributions ret = my_system("./ecc_test_helper", "Xatan");
96*19c3b8c2SApple OSS Distributions T_QUIET; T_ASSERT_EQ(ret, 0, "Failed to recover from ECC to clean shared region page");
97*19c3b8c2SApple OSS Distributions
98*19c3b8c2SApple OSS Distributions ret = my_system("./ecc_test_helper", "atan");
99*19c3b8c2SApple OSS Distributions T_QUIET; T_ASSERT_EQ(ret, 0, "Fixed call of atan");
100*19c3b8c2SApple OSS Distributions
101*19c3b8c2SApple OSS Distributions /*
102*19c3b8c2SApple OSS Distributions * test of clean data page
103*19c3b8c2SApple OSS Distributions */
104*19c3b8c2SApple OSS Distributions ret = my_system("./ecc_test_helper", "clean");
105*19c3b8c2SApple OSS Distributions T_QUIET; T_ASSERT_EQ(ret, 0, "First call of clean");
106*19c3b8c2SApple OSS Distributions
107*19c3b8c2SApple OSS Distributions ret = my_system("./ecc_test_helper", "Xclean");
108*19c3b8c2SApple OSS Distributions T_QUIET; T_ASSERT_EQ(ret, 0, "Failed to recover from ECC to clean page");
109*19c3b8c2SApple OSS Distributions
110*19c3b8c2SApple OSS Distributions ret = my_system("./ecc_test_helper", "clean");
111*19c3b8c2SApple OSS Distributions T_QUIET; T_ASSERT_EQ(ret, 0, "Fixed call of clean");
112*19c3b8c2SApple OSS Distributions
113*19c3b8c2SApple OSS Distributions /*
114*19c3b8c2SApple OSS Distributions * test of dirty data page
115*19c3b8c2SApple OSS Distributions */
116*19c3b8c2SApple OSS Distributions ret = my_system("./ecc_test_helper", "Xdirty");
117*19c3b8c2SApple OSS Distributions if (corrected) {
118*19c3b8c2SApple OSS Distributions T_QUIET; T_ASSERT_EQ(ret, 0, "Corrected ECC read of dirty failed");
119*19c3b8c2SApple OSS Distributions } else {
120*19c3b8c2SApple OSS Distributions T_QUIET; T_ASSERT_NE(ret, 0, "Read of Uncorrected ECC dirty data didn't fail");
121*19c3b8c2SApple OSS Distributions }
122*19c3b8c2SApple OSS Distributions
123*19c3b8c2SApple OSS Distributions /*
124*19c3b8c2SApple OSS Distributions * test of ecc during copyout
125*19c3b8c2SApple OSS Distributions */
126*19c3b8c2SApple OSS Distributions ret = my_system("./ecc_test_helper", "Xcopyout");
127*19c3b8c2SApple OSS Distributions if (corrected) {
128*19c3b8c2SApple OSS Distributions T_QUIET; T_ASSERT_EQ(ret, 0, "Corrected ECC copyout failed");
129*19c3b8c2SApple OSS Distributions } else {
130*19c3b8c2SApple OSS Distributions T_QUIET; T_ASSERT_NE(ret, 0, "Uncorrected ECC copyout didn't fail"); /* not recoverable */
131*19c3b8c2SApple OSS Distributions }
132*19c3b8c2SApple OSS Distributions }
133*19c3b8c2SApple OSS Distributions
134*19c3b8c2SApple OSS Distributions T_DECL(ecc_uncorrected_test, "test detection/recovery from ECC uncorrected errors",
135*19c3b8c2SApple OSS Distributions T_META_IGNORECRASHES(".*ecc_test_helper.*"),
136*19c3b8c2SApple OSS Distributions T_META_ASROOT(true),
137*19c3b8c2SApple OSS Distributions T_META_ENABLED(FALSE)) /* once other support lands, change to T_META_ENABLED(TARGET_CPU_ARM64 && TARGET_OS_OSX) */
138*19c3b8c2SApple OSS Distributions {
139*19c3b8c2SApple OSS Distributions int err;
140*19c3b8c2SApple OSS Distributions uint value = 0;
141*19c3b8c2SApple OSS Distributions size_t s = sizeof value;
142*19c3b8c2SApple OSS Distributions
143*19c3b8c2SApple OSS Distributions /*
144*19c3b8c2SApple OSS Distributions * Only run on systems which support retired pages.
145*19c3b8c2SApple OSS Distributions */
146*19c3b8c2SApple OSS Distributions err = sysctlbyname("vm.retired_pages_count", &value, &s, NULL, 0);
147*19c3b8c2SApple OSS Distributions if (err) {
148*19c3b8c2SApple OSS Distributions T_SKIP("ECC not supported");
149*19c3b8c2SApple OSS Distributions }
150*19c3b8c2SApple OSS Distributions
151*19c3b8c2SApple OSS Distributions /*
152*19c3b8c2SApple OSS Distributions * Set testing mode to uncorrected.
153*19c3b8c2SApple OSS Distributions */
154*19c3b8c2SApple OSS Distributions value = 0;
155*19c3b8c2SApple OSS Distributions err = sysctlbyname("vm.test_corrected_ecc", NULL, NULL, &value, s);
156*19c3b8c2SApple OSS Distributions if (err) {
157*19c3b8c2SApple OSS Distributions T_SKIP("Failed to set uncorrected mode");
158*19c3b8c2SApple OSS Distributions }
159*19c3b8c2SApple OSS Distributions
160*19c3b8c2SApple OSS Distributions test_body(false);
161*19c3b8c2SApple OSS Distributions }
162*19c3b8c2SApple OSS Distributions
163*19c3b8c2SApple OSS Distributions T_DECL(ecc_corrected_test, "test detection/recovery from ECC corrected errors",
164*19c3b8c2SApple OSS Distributions T_META_IGNORECRASHES(".*ecc_test_helper.*"),
165*19c3b8c2SApple OSS Distributions T_META_ASROOT(true),
166*19c3b8c2SApple OSS Distributions T_META_ENABLED(FALSE)) /* once other support lands, change to T_META_ENABLED(TARGET_CPU_ARM64 && TARGET_OS_OSX) */
167*19c3b8c2SApple OSS Distributions {
168*19c3b8c2SApple OSS Distributions int err;
169*19c3b8c2SApple OSS Distributions uint value = 0;
170*19c3b8c2SApple OSS Distributions size_t s = sizeof value;
171*19c3b8c2SApple OSS Distributions
172*19c3b8c2SApple OSS Distributions /*
173*19c3b8c2SApple OSS Distributions * Only run on systems which support retired pages.
174*19c3b8c2SApple OSS Distributions */
175*19c3b8c2SApple OSS Distributions err = sysctlbyname("vm.retired_pages_count", &value, &s, NULL, 0);
176*19c3b8c2SApple OSS Distributions if (err) {
177*19c3b8c2SApple OSS Distributions T_SKIP("ECC not supported");
178*19c3b8c2SApple OSS Distributions }
179*19c3b8c2SApple OSS Distributions
180*19c3b8c2SApple OSS Distributions /*
181*19c3b8c2SApple OSS Distributions * Set testing mode to corrected.
182*19c3b8c2SApple OSS Distributions */
183*19c3b8c2SApple OSS Distributions value = 1;
184*19c3b8c2SApple OSS Distributions err = sysctlbyname("vm.test_corrected_ecc", NULL, NULL, &value, s);
185*19c3b8c2SApple OSS Distributions if (err) {
186*19c3b8c2SApple OSS Distributions T_SKIP("Failed to set corrected mode");
187*19c3b8c2SApple OSS Distributions }
188*19c3b8c2SApple OSS Distributions
189*19c3b8c2SApple OSS Distributions test_body(true);
190*19c3b8c2SApple OSS Distributions }
191