xref: /xnu-8792.81.2/tests/ecc_test.c (revision 19c3b8c28c31cb8130e034cfb5df6bf9ba342d90)
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