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