1 /*
2  * Copyright 2018 The Hafnium Authors.
3  *
4  * Use of this source code is governed by a BSD-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/BSD-3-Clause.
7  */
8 
9 #include "hf/arch/vm/power_mgmt.h"
10 
11 #include "hf/boot_params.h"
12 #include "hf/fdt_handler.h"
13 #include "hf/memiter.h"
14 #include "hf/std.h"
15 
16 #include "hftest_common.h"
17 #include "test/hftest.h"
18 
19 HFTEST_ENABLE();
20 
21 static struct hftest_test hftest_constructed[HFTEST_MAX_TESTS];
22 static size_t hftest_count;
23 static struct hftest_test *hftest_list;
24 
25 static struct hftest_context global_context;
26 
hftest_get_context(void)27 struct hftest_context *hftest_get_context(void)
28 {
29 	return &global_context;
30 }
31 
32 /**
33  * Adds the given test information to the global list, to be used by
34  * `hftest_use_registered_list`.
35  */
hftest_register(struct hftest_test test)36 void hftest_register(struct hftest_test test)
37 {
38 	if (hftest_count < HFTEST_MAX_TESTS) {
39 		hftest_constructed[hftest_count++] = test;
40 	} else {
41 		HFTEST_FAIL(true, "Too many tests");
42 	}
43 }
44 
45 /**
46  * Uses the list of tests registered by `hftest_register(...)` as the ones to
47  * run.
48  */
hftest_use_registered_list(void)49 void hftest_use_registered_list(void)
50 {
51 	hftest_list = hftest_constructed;
52 }
53 
54 /**
55  * Uses the given list of tests as the ones to run.
56  */
hftest_use_list(struct hftest_test list[],size_t count)57 void hftest_use_list(struct hftest_test list[], size_t count)
58 {
59 	hftest_list = list;
60 	hftest_count = count;
61 }
62 
63 /**
64  * Writes out a JSON structure describing the available tests.
65  */
hftest_json(void)66 void hftest_json(void)
67 {
68 	const char *suite = NULL;
69 	size_t i;
70 	size_t suites_in_image = 0;
71 	size_t tests_in_suite = 0;
72 
73 	HFTEST_LOG("{");
74 	HFTEST_LOG("  \"suites\": [");
75 	for (i = 0; i < hftest_count; ++i) {
76 		struct hftest_test *test = &hftest_list[i];
77 		if (test->suite != suite) {
78 			/* Close out previously open suite. */
79 			if (tests_in_suite) {
80 				HFTEST_LOG("      ]");
81 				HFTEST_LOG("    },");
82 			}
83 			/* Move onto new suite. */
84 			++suites_in_image;
85 			suite = test->suite;
86 			tests_in_suite = 0;
87 			HFTEST_LOG("    {");
88 			HFTEST_LOG("      \"name\": \"%s\",", test->suite);
89 		}
90 		if (test->kind == HFTEST_KIND_SET_UP) {
91 			HFTEST_LOG("      \"setup\": true,");
92 		}
93 		if (test->kind == HFTEST_KIND_TEAR_DOWN) {
94 			HFTEST_LOG("      \"teardown\": true,");
95 		}
96 		if (test->kind == HFTEST_KIND_TEST) {
97 			if (!tests_in_suite) {
98 				HFTEST_LOG("      \"tests\": [");
99 			}
100 			/*
101 			 * It's easier to put the comma at the start of the line
102 			 * than the end even though the JSON looks a bit funky.
103 			 */
104 			HFTEST_LOG("       %c{", tests_in_suite ? ',' : ' ');
105 			HFTEST_LOG("          \"name\": \"%s\",", test->name);
106 			HFTEST_LOG("          \"is_long_running\": %s",
107 				   test->is_long_running ? "true" : "false");
108 			HFTEST_LOG("       }");
109 			++tests_in_suite;
110 		}
111 	}
112 	if (tests_in_suite) {
113 		HFTEST_LOG("      ]");
114 		HFTEST_LOG("    }");
115 	}
116 	HFTEST_LOG("  ]");
117 	HFTEST_LOG("}");
118 }
119 
120 /**
121  * Logs a failure message and shut down.
122  */
abort(void)123 noreturn void abort(void)
124 {
125 	HFTEST_LOG("FAIL");
126 	arch_power_off();
127 }
128 
run_test(hftest_test_fn set_up,hftest_test_fn test,hftest_test_fn tear_down,const struct fdt * fdt)129 static void run_test(hftest_test_fn set_up, hftest_test_fn test,
130 		     hftest_test_fn tear_down, const struct fdt *fdt)
131 {
132 	/* Prepare the context. */
133 	struct hftest_context *ctx = hftest_get_context();
134 	memset_s(ctx, sizeof(*ctx), 0, sizeof(*ctx));
135 	ctx->abort = abort;
136 	ctx->fdt = fdt;
137 
138 	/* Run any set up functions. */
139 	if (set_up) {
140 		set_up();
141 		if (ctx->failures) {
142 			abort();
143 		}
144 	}
145 
146 	/* Run the test. */
147 	test();
148 	if (ctx->failures) {
149 		abort();
150 	}
151 
152 	/* Run any tear down functions. */
153 	if (tear_down) {
154 		tear_down();
155 		if (ctx->failures) {
156 			abort();
157 		}
158 	}
159 
160 	HFTEST_LOG("FINISHED");
161 }
162 
163 /**
164  * Runs the given test case.
165  */
hftest_run(struct memiter suite_name,struct memiter test_name,const struct fdt * fdt)166 void hftest_run(struct memiter suite_name, struct memiter test_name,
167 		const struct fdt *fdt)
168 {
169 	size_t i;
170 	hftest_test_fn suite_set_up = NULL;
171 	hftest_test_fn suite_tear_down = NULL;
172 
173 	for (i = 0; i < hftest_count; ++i) {
174 		struct hftest_test *test = &hftest_list[i];
175 
176 		/* Check if this test is part of the suite we want. */
177 		if (memiter_iseq(&suite_name, test->suite)) {
178 			switch (test->kind) {
179 			/*
180 			 * The first entries in the suite are the set up and
181 			 * tear down functions.
182 			 */
183 			case HFTEST_KIND_SET_UP:
184 				suite_set_up = test->fn;
185 				break;
186 			case HFTEST_KIND_TEAR_DOWN:
187 				suite_tear_down = test->fn;
188 				break;
189 			/* Find the test. */
190 			case HFTEST_KIND_TEST:
191 				if (memiter_iseq(&test_name, test->name)) {
192 					run_test(suite_set_up, test->fn,
193 						 suite_tear_down, fdt);
194 					return;
195 				}
196 				break;
197 			default:
198 				/* Ignore other kinds. */
199 				break;
200 			}
201 		}
202 	}
203 
204 	HFTEST_LOG("Unable to find requested tests.");
205 }
206 
207 /**
208  * Writes out usage information.
209  */
hftest_help(void)210 void hftest_help(void)
211 {
212 	HFTEST_LOG("usage:");
213 	HFTEST_LOG("");
214 	HFTEST_LOG("  help");
215 	HFTEST_LOG("");
216 	HFTEST_LOG("    Show this help.");
217 	HFTEST_LOG("");
218 	HFTEST_LOG("  json");
219 	HFTEST_LOG("");
220 	HFTEST_LOG(
221 		"    Print a directory of test suites and tests in "
222 		"JSON "
223 		"format.");
224 	HFTEST_LOG("");
225 	HFTEST_LOG("  run <suite> <test>");
226 	HFTEST_LOG("");
227 	HFTEST_LOG("    Run the named test from the named test suite.");
228 }
229 
hftest_command(struct fdt * fdt)230 void hftest_command(struct fdt *fdt)
231 {
232 	struct memiter command_line;
233 	struct memiter command;
234 
235 	if (!hftest_ctrl_start(fdt, &command_line)) {
236 		HFTEST_LOG("Unable to read the command line.");
237 		return;
238 	}
239 
240 	if (!memiter_parse_str(&command_line, &command)) {
241 		HFTEST_LOG("Unable to parse command.");
242 		return;
243 	}
244 
245 	if (memiter_iseq(&command, "exit")) {
246 		hftest_device_exit_test_environment();
247 		return;
248 	}
249 
250 	if (memiter_iseq(&command, "json")) {
251 		hftest_json();
252 		return;
253 	}
254 
255 	if (memiter_iseq(&command, "run")) {
256 		struct memiter suite_name;
257 		struct memiter test_name;
258 
259 		if (!memiter_parse_str(&command_line, &suite_name)) {
260 			HFTEST_LOG("Unable to parse test suite.");
261 			return;
262 		}
263 
264 		if (!memiter_parse_str(&command_line, &test_name)) {
265 			HFTEST_LOG("Unable to parse test.");
266 			return;
267 		}
268 		hftest_run(suite_name, test_name, fdt);
269 		return;
270 	}
271 
272 	hftest_help();
273 }
274 
vcpu_index_to_id(size_t index)275 static uintptr_t vcpu_index_to_id(size_t index)
276 {
277 	/* For now we use indices as IDs for vCPUs. */
278 	return index;
279 }
280 
281 /**
282  * Get the ID of the CPU with the given index.
283  */
hftest_get_cpu_id(size_t index)284 uintptr_t hftest_get_cpu_id(size_t index)
285 {
286 	struct boot_params params;
287 	const struct fdt *fdt = hftest_get_context()->fdt;
288 
289 	if (fdt == NULL) {
290 		/*
291 		 * We must be in a service VM, so apply the mapping that Hafnium
292 		 * uses for vCPU IDs.
293 		 */
294 		return vcpu_index_to_id(index);
295 	}
296 
297 	/* Find physical CPU ID from FDT. */
298 	fdt_find_cpus(fdt, params.cpu_ids, &params.cpu_count);
299 
300 	return params.cpu_ids[index];
301 }
302