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