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, ¶ms.cpu_count);
299
300 return params.cpu_ids[index];
301 }
302