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