xref: /xnu-10002.81.5/tests/ecc_test.c (revision 5e3eaea39dcf651e66cb99ba7d70e32cc4a99587)
1*5e3eaea3SApple OSS Distributions #include <unistd.h>
2*5e3eaea3SApple OSS Distributions #include <stdio.h>
3*5e3eaea3SApple OSS Distributions #include <signal.h>
4*5e3eaea3SApple OSS Distributions 
5*5e3eaea3SApple OSS Distributions #include <darwintest.h>
6*5e3eaea3SApple OSS Distributions #include <darwintest_utils.h>
7*5e3eaea3SApple OSS Distributions 
8*5e3eaea3SApple OSS Distributions /*
9*5e3eaea3SApple OSS Distributions  * We're going to inject ECC errors into shared library text, so don't
10*5e3eaea3SApple OSS Distributions  * run with other tests.
11*5e3eaea3SApple OSS Distributions  */
12*5e3eaea3SApple OSS Distributions T_GLOBAL_META(T_META_RUN_CONCURRENTLY(false),
13*5e3eaea3SApple OSS Distributions     T_META_OWNER("josephb_22"),
14*5e3eaea3SApple OSS Distributions     T_META_NAMESPACE("xnu.vm"),
15*5e3eaea3SApple OSS Distributions     T_META_RADAR_COMPONENT_NAME("xnu"),
16*5e3eaea3SApple OSS Distributions     T_META_RADAR_COMPONENT_VERSION("VM"));
17*5e3eaea3SApple OSS Distributions 
18*5e3eaea3SApple OSS Distributions /*
19*5e3eaea3SApple OSS Distributions  * No system(3c) on watchOS, so provide our own.
20*5e3eaea3SApple OSS Distributions  * returns -1 if fails to run
21*5e3eaea3SApple OSS Distributions  * returns 0 if process exits normally.
22*5e3eaea3SApple OSS Distributions  * returns +n if process exits due to signal N
23*5e3eaea3SApple OSS Distributions  */
24*5e3eaea3SApple OSS Distributions static int
my_system(const char * command,const char * arg)25*5e3eaea3SApple OSS Distributions my_system(const char *command, const char *arg)
26*5e3eaea3SApple OSS Distributions {
27*5e3eaea3SApple OSS Distributions 	pid_t pid;
28*5e3eaea3SApple OSS Distributions 	int status = 0;
29*5e3eaea3SApple OSS Distributions 	int signal = 0;
30*5e3eaea3SApple OSS Distributions 	int ret;
31*5e3eaea3SApple OSS Distributions 	const char *argv[] = {
32*5e3eaea3SApple OSS Distributions 		command,
33*5e3eaea3SApple OSS Distributions 		/* "-v",           uncomment if debugging the tests */
34*5e3eaea3SApple OSS Distributions 		arg,
35*5e3eaea3SApple OSS Distributions 		NULL
36*5e3eaea3SApple OSS Distributions 	};
37*5e3eaea3SApple OSS Distributions 
38*5e3eaea3SApple OSS Distributions 	if (dt_launch_tool(&pid, (char **)(void *)argv, FALSE, NULL, NULL)) {
39*5e3eaea3SApple OSS Distributions 		return -1;
40*5e3eaea3SApple OSS Distributions 	}
41*5e3eaea3SApple OSS Distributions 
42*5e3eaea3SApple OSS Distributions 	ret = dt_waitpid(pid, &status, &signal, 100);
43*5e3eaea3SApple OSS Distributions 	if (signal != 0) {
44*5e3eaea3SApple OSS Distributions 		return signal;
45*5e3eaea3SApple OSS Distributions 	} else if (status != 0) {
46*5e3eaea3SApple OSS Distributions 		return status;
47*5e3eaea3SApple OSS Distributions 	}
48*5e3eaea3SApple OSS Distributions 	return 0;
49*5e3eaea3SApple OSS Distributions }
50*5e3eaea3SApple OSS Distributions 
51*5e3eaea3SApple OSS Distributions 
52*5e3eaea3SApple OSS Distributions /*
53*5e3eaea3SApple OSS Distributions  * The tests are run in the following order:
54*5e3eaea3SApple OSS Distributions  *
55*5e3eaea3SApple OSS Distributions  * - call foo (i.e. private text page)
56*5e3eaea3SApple OSS Distributions  * - Inject ECC error into foo, then call foo
57*5e3eaea3SApple OSS Distributions  *
58*5e3eaea3SApple OSS Distributions  * - call atan (i.e. shared text page)
59*5e3eaea3SApple OSS Distributions  * - inject ecc error into atan, then call atan
60*5e3eaea3SApple OSS Distributions  *
61*5e3eaea3SApple OSS Distributions  * atan() was picked as a shared region function that isn't likely used by any normal daemons.
62*5e3eaea3SApple OSS Distributions  *
63*5e3eaea3SApple OSS Distributions  * - reference to clean data page
64*5e3eaea3SApple OSS Distributions  * - reference to clean data page with injected error
65*5e3eaea3SApple OSS Distributions  *
66*5e3eaea3SApple OSS Distributions  * - reference to dirty data page
67*5e3eaea3SApple OSS Distributions  * - reference to dirty data page with injected error
68*5e3eaea3SApple OSS Distributions  *
69*5e3eaea3SApple OSS Distributions  * - copyout to page
70*5e3eaea3SApple OSS Distributions  * - copyout to a page with injected error
71*5e3eaea3SApple OSS Distributions  */
72*5e3eaea3SApple OSS Distributions static void
test_body(bool corrected)73*5e3eaea3SApple OSS Distributions test_body(bool corrected)
74*5e3eaea3SApple OSS Distributions {
75*5e3eaea3SApple OSS Distributions 	int ret;
76*5e3eaea3SApple OSS Distributions 
77*5e3eaea3SApple OSS Distributions 	/*
78*5e3eaea3SApple OSS Distributions 	 * test of process text page
79*5e3eaea3SApple OSS Distributions 	 */
80*5e3eaea3SApple OSS Distributions 	ret = my_system("./ecc_test_helper", "foo");
81*5e3eaea3SApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(ret, 0, "First call of foo");
82*5e3eaea3SApple OSS Distributions 
83*5e3eaea3SApple OSS Distributions 	ret = my_system("./ecc_test_helper", "Xfoo");
84*5e3eaea3SApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(ret, 0, "Failed to recover from ECC to clean app text page");
85*5e3eaea3SApple OSS Distributions 
86*5e3eaea3SApple OSS Distributions 	ret = my_system("./ecc_test_helper", "foo");
87*5e3eaea3SApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(ret, 0, "Fixed call of foo");
88*5e3eaea3SApple OSS Distributions 
89*5e3eaea3SApple OSS Distributions 	/*
90*5e3eaea3SApple OSS Distributions 	 * test of shared library text page
91*5e3eaea3SApple OSS Distributions 	 */
92*5e3eaea3SApple OSS Distributions 	ret = my_system("./ecc_test_helper", "atan");
93*5e3eaea3SApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(ret, 0, "First call of atan");
94*5e3eaea3SApple OSS Distributions 
95*5e3eaea3SApple OSS Distributions 	ret = my_system("./ecc_test_helper", "Xatan");
96*5e3eaea3SApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(ret, 0, "Failed to recover from ECC to clean shared region page");
97*5e3eaea3SApple OSS Distributions 
98*5e3eaea3SApple OSS Distributions 	ret = my_system("./ecc_test_helper", "atan");
99*5e3eaea3SApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(ret, 0, "Fixed call of atan");
100*5e3eaea3SApple OSS Distributions 
101*5e3eaea3SApple OSS Distributions 	/*
102*5e3eaea3SApple OSS Distributions 	 * test of clean data page
103*5e3eaea3SApple OSS Distributions 	 */
104*5e3eaea3SApple OSS Distributions 	ret = my_system("./ecc_test_helper", "clean");
105*5e3eaea3SApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(ret, 0, "First call of clean");
106*5e3eaea3SApple OSS Distributions 
107*5e3eaea3SApple OSS Distributions 	ret = my_system("./ecc_test_helper", "Xclean");
108*5e3eaea3SApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(ret, 0, "Failed to recover from ECC to clean page");
109*5e3eaea3SApple OSS Distributions 
110*5e3eaea3SApple OSS Distributions 	ret = my_system("./ecc_test_helper", "clean");
111*5e3eaea3SApple OSS Distributions 	T_QUIET; T_ASSERT_EQ(ret, 0, "Fixed call of clean");
112*5e3eaea3SApple OSS Distributions 
113*5e3eaea3SApple OSS Distributions 	/*
114*5e3eaea3SApple OSS Distributions 	 * test of dirty data page
115*5e3eaea3SApple OSS Distributions 	 */
116*5e3eaea3SApple OSS Distributions 	ret = my_system("./ecc_test_helper", "Xdirty");
117*5e3eaea3SApple OSS Distributions 	if (corrected) {
118*5e3eaea3SApple OSS Distributions 		T_QUIET; T_ASSERT_EQ(ret, 0, "Corrected ECC read of dirty failed");
119*5e3eaea3SApple OSS Distributions 	} else {
120*5e3eaea3SApple OSS Distributions 		T_QUIET; T_ASSERT_NE(ret, 0, "Read of Uncorrected ECC dirty data didn't fail");
121*5e3eaea3SApple OSS Distributions 	}
122*5e3eaea3SApple OSS Distributions 
123*5e3eaea3SApple OSS Distributions 	/*
124*5e3eaea3SApple OSS Distributions 	 * test of ecc during copyout
125*5e3eaea3SApple OSS Distributions 	 */
126*5e3eaea3SApple OSS Distributions 	ret = my_system("./ecc_test_helper", "Xcopyout");
127*5e3eaea3SApple OSS Distributions 	if (corrected) {
128*5e3eaea3SApple OSS Distributions 		T_QUIET; T_ASSERT_EQ(ret, 0, "Corrected ECC copyout failed");
129*5e3eaea3SApple OSS Distributions 	} else {
130*5e3eaea3SApple OSS Distributions 		T_QUIET; T_ASSERT_NE(ret, 0, "Uncorrected ECC copyout didn't fail"); /* not recoverable */
131*5e3eaea3SApple OSS Distributions 	}
132*5e3eaea3SApple OSS Distributions }
133*5e3eaea3SApple OSS Distributions 
134*5e3eaea3SApple OSS Distributions T_DECL(ecc_uncorrected_test, "test detection/recovery from ECC uncorrected errors",
135*5e3eaea3SApple OSS Distributions     T_META_IGNORECRASHES(".*ecc_test_helper.*"),
136*5e3eaea3SApple OSS Distributions     T_META_ASROOT(true),
137*5e3eaea3SApple OSS Distributions     T_META_ENABLED(FALSE))  /* once other support lands, change to T_META_ENABLED(TARGET_CPU_ARM64 && TARGET_OS_OSX) */
138*5e3eaea3SApple OSS Distributions {
139*5e3eaea3SApple OSS Distributions 	int err;
140*5e3eaea3SApple OSS Distributions 	uint value = 0;
141*5e3eaea3SApple OSS Distributions 	size_t s = sizeof value;
142*5e3eaea3SApple OSS Distributions 
143*5e3eaea3SApple OSS Distributions 	/*
144*5e3eaea3SApple OSS Distributions 	 * Only run on systems which support retired pages.
145*5e3eaea3SApple OSS Distributions 	 */
146*5e3eaea3SApple OSS Distributions 	err = sysctlbyname("vm.retired_pages_count", &value, &s, NULL, 0);
147*5e3eaea3SApple OSS Distributions 	if (err) {
148*5e3eaea3SApple OSS Distributions 		T_SKIP("ECC not supported");
149*5e3eaea3SApple OSS Distributions 	}
150*5e3eaea3SApple OSS Distributions 
151*5e3eaea3SApple OSS Distributions 	/*
152*5e3eaea3SApple OSS Distributions 	 * Set testing mode to acc
153*5e3eaea3SApple OSS Distributions 	 */
154*5e3eaea3SApple OSS Distributions 	value = 0;
155*5e3eaea3SApple OSS Distributions 	err = sysctlbyname("vm.test_ecc_dcs", NULL, NULL, &value, s);
156*5e3eaea3SApple OSS Distributions 	if (err) {
157*5e3eaea3SApple OSS Distributions 		T_SKIP("Failed to clear dcs mode");
158*5e3eaea3SApple OSS Distributions 	}
159*5e3eaea3SApple OSS Distributions 
160*5e3eaea3SApple OSS Distributions 	/*
161*5e3eaea3SApple OSS Distributions 	 * Set testing mode to uncorrected.
162*5e3eaea3SApple OSS Distributions 	 */
163*5e3eaea3SApple OSS Distributions 	value = 0;
164*5e3eaea3SApple OSS Distributions 	err = sysctlbyname("vm.test_corrected_ecc", NULL, NULL, &value, s);
165*5e3eaea3SApple OSS Distributions 	if (err) {
166*5e3eaea3SApple OSS Distributions 		T_SKIP("Failed to set uncorrected mode");
167*5e3eaea3SApple OSS Distributions 	}
168*5e3eaea3SApple OSS Distributions 
169*5e3eaea3SApple OSS Distributions 	test_body(false);
170*5e3eaea3SApple OSS Distributions }
171*5e3eaea3SApple OSS Distributions 
172*5e3eaea3SApple OSS Distributions T_DECL(ecc_corrected_test, "test detection/recovery from ECC corrected errors",
173*5e3eaea3SApple OSS Distributions     T_META_IGNORECRASHES(".*ecc_test_helper.*"),
174*5e3eaea3SApple OSS Distributions     T_META_ASROOT(true),
175*5e3eaea3SApple OSS Distributions     T_META_ENABLED(FALSE))  /* once other support lands, change to T_META_ENABLED(TARGET_CPU_ARM64 && TARGET_OS_OSX) */
176*5e3eaea3SApple OSS Distributions {
177*5e3eaea3SApple OSS Distributions 	int err;
178*5e3eaea3SApple OSS Distributions 	uint value = 0;
179*5e3eaea3SApple OSS Distributions 	size_t s = sizeof value;
180*5e3eaea3SApple OSS Distributions 
181*5e3eaea3SApple OSS Distributions 	/*
182*5e3eaea3SApple OSS Distributions 	 * Only run on systems which support retired pages.
183*5e3eaea3SApple OSS Distributions 	 */
184*5e3eaea3SApple OSS Distributions 	err = sysctlbyname("vm.retired_pages_count", &value, &s, NULL, 0);
185*5e3eaea3SApple OSS Distributions 	if (err) {
186*5e3eaea3SApple OSS Distributions 		T_SKIP("ECC not supported");
187*5e3eaea3SApple OSS Distributions 	}
188*5e3eaea3SApple OSS Distributions 
189*5e3eaea3SApple OSS Distributions 	/*
190*5e3eaea3SApple OSS Distributions 	 * Set testing mode to acc
191*5e3eaea3SApple OSS Distributions 	 */
192*5e3eaea3SApple OSS Distributions 	value = 0;
193*5e3eaea3SApple OSS Distributions 	err = sysctlbyname("vm.test_ecc_dcs", NULL, NULL, &value, s);
194*5e3eaea3SApple OSS Distributions 	if (err) {
195*5e3eaea3SApple OSS Distributions 		T_SKIP("Failed to clear dcs mode");
196*5e3eaea3SApple OSS Distributions 	}
197*5e3eaea3SApple OSS Distributions 
198*5e3eaea3SApple OSS Distributions 	/*
199*5e3eaea3SApple OSS Distributions 	 * Set testing mode to corrected.
200*5e3eaea3SApple OSS Distributions 	 */
201*5e3eaea3SApple OSS Distributions 	value = 1;
202*5e3eaea3SApple OSS Distributions 	err = sysctlbyname("vm.test_corrected_ecc", NULL, NULL, &value, s);
203*5e3eaea3SApple OSS Distributions 	if (err) {
204*5e3eaea3SApple OSS Distributions 		T_SKIP("Failed to set corrected mode");
205*5e3eaea3SApple OSS Distributions 	}
206*5e3eaea3SApple OSS Distributions 
207*5e3eaea3SApple OSS Distributions 	test_body(true);
208*5e3eaea3SApple OSS Distributions }
209*5e3eaea3SApple OSS Distributions 
210*5e3eaea3SApple OSS Distributions T_DECL(dcs_uncorrected_test, "test detection/recovery from ECC uncorrected errors via dcs",
211*5e3eaea3SApple OSS Distributions     T_META_IGNORECRASHES(".*ecc_test_helper.*"),
212*5e3eaea3SApple OSS Distributions     T_META_ASROOT(true),
213*5e3eaea3SApple OSS Distributions     T_META_ENABLED(FALSE))  /* once other support lands, change to T_META_ENABLED(TARGET_CPU_ARM64 && TARGET_OS_OSX) */
214*5e3eaea3SApple OSS Distributions {
215*5e3eaea3SApple OSS Distributions 	int err;
216*5e3eaea3SApple OSS Distributions 	uint value = 0;
217*5e3eaea3SApple OSS Distributions 	size_t s = sizeof value;
218*5e3eaea3SApple OSS Distributions 
219*5e3eaea3SApple OSS Distributions 	/*
220*5e3eaea3SApple OSS Distributions 	 * Only run on systems which support retired pages.
221*5e3eaea3SApple OSS Distributions 	 */
222*5e3eaea3SApple OSS Distributions 	err = sysctlbyname("vm.retired_pages_count", &value, &s, NULL, 0);
223*5e3eaea3SApple OSS Distributions 	if (err) {
224*5e3eaea3SApple OSS Distributions 		T_SKIP("ECC not supported");
225*5e3eaea3SApple OSS Distributions 	}
226*5e3eaea3SApple OSS Distributions 
227*5e3eaea3SApple OSS Distributions 	/*
228*5e3eaea3SApple OSS Distributions 	 * Set testing mode to dcs
229*5e3eaea3SApple OSS Distributions 	 */
230*5e3eaea3SApple OSS Distributions 	value = 1;
231*5e3eaea3SApple OSS Distributions 	err = sysctlbyname("vm.test_ecc_dcs", NULL, NULL, &value, s);
232*5e3eaea3SApple OSS Distributions 	if (err) {
233*5e3eaea3SApple OSS Distributions 		T_SKIP("Failed to set dcs mode");
234*5e3eaea3SApple OSS Distributions 	}
235*5e3eaea3SApple OSS Distributions 
236*5e3eaea3SApple OSS Distributions 	/*
237*5e3eaea3SApple OSS Distributions 	 * Set testing mode to uncorrected.
238*5e3eaea3SApple OSS Distributions 	 */
239*5e3eaea3SApple OSS Distributions 	value = 0;
240*5e3eaea3SApple OSS Distributions 	err = sysctlbyname("vm.test_corrected_ecc", NULL, NULL, &value, s);
241*5e3eaea3SApple OSS Distributions 	if (err) {
242*5e3eaea3SApple OSS Distributions 		T_SKIP("Failed to set uncorrected mode");
243*5e3eaea3SApple OSS Distributions 	}
244*5e3eaea3SApple OSS Distributions 
245*5e3eaea3SApple OSS Distributions 	test_body(false);
246*5e3eaea3SApple OSS Distributions }
247*5e3eaea3SApple OSS Distributions 
248*5e3eaea3SApple OSS Distributions T_DECL(dcs_corrected_test, "test detection/recovery from ECC corrected errors via dcs",
249*5e3eaea3SApple OSS Distributions     T_META_IGNORECRASHES(".*ecc_test_helper.*"),
250*5e3eaea3SApple OSS Distributions     T_META_ASROOT(true),
251*5e3eaea3SApple OSS Distributions     T_META_ENABLED(FALSE))  /* once other support lands, change to T_META_ENABLED(TARGET_CPU_ARM64 && TARGET_OS_OSX) */
252*5e3eaea3SApple OSS Distributions {
253*5e3eaea3SApple OSS Distributions 	int err;
254*5e3eaea3SApple OSS Distributions 	uint value = 0;
255*5e3eaea3SApple OSS Distributions 	size_t s = sizeof value;
256*5e3eaea3SApple OSS Distributions 
257*5e3eaea3SApple OSS Distributions 	/*
258*5e3eaea3SApple OSS Distributions 	 * Only run on systems which support retired pages.
259*5e3eaea3SApple OSS Distributions 	 */
260*5e3eaea3SApple OSS Distributions 	err = sysctlbyname("vm.retired_pages_count", &value, &s, NULL, 0);
261*5e3eaea3SApple OSS Distributions 	if (err) {
262*5e3eaea3SApple OSS Distributions 		T_SKIP("ECC not supported");
263*5e3eaea3SApple OSS Distributions 	}
264*5e3eaea3SApple OSS Distributions 
265*5e3eaea3SApple OSS Distributions 	/*
266*5e3eaea3SApple OSS Distributions 	 * Set testing mode to dcs
267*5e3eaea3SApple OSS Distributions 	 */
268*5e3eaea3SApple OSS Distributions 	value = 1;
269*5e3eaea3SApple OSS Distributions 	err = sysctlbyname("vm.test_ecc_dcs", NULL, NULL, &value, s);
270*5e3eaea3SApple OSS Distributions 	if (err) {
271*5e3eaea3SApple OSS Distributions 		T_SKIP("Failed to set dcs mode");
272*5e3eaea3SApple OSS Distributions 	}
273*5e3eaea3SApple OSS Distributions 
274*5e3eaea3SApple OSS Distributions 	/*
275*5e3eaea3SApple OSS Distributions 	 * Set testing mode to corrected.
276*5e3eaea3SApple OSS Distributions 	 */
277*5e3eaea3SApple OSS Distributions 	value = 1;
278*5e3eaea3SApple OSS Distributions 	err = sysctlbyname("vm.test_corrected_ecc", NULL, NULL, &value, s);
279*5e3eaea3SApple OSS Distributions 	if (err) {
280*5e3eaea3SApple OSS Distributions 		T_SKIP("Failed to set corrected mode");
281*5e3eaea3SApple OSS Distributions 	}
282*5e3eaea3SApple OSS Distributions 
283*5e3eaea3SApple OSS Distributions 	test_body(true);
284*5e3eaea3SApple OSS Distributions }
285