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