blob: 7aeda2292f5956c84b90c9423c8444c52fdd9702 [file] [log] [blame]
Andrew Scull18834872018-10-12 11:48:09 +01001/*
Andrew Walbran692b3252019-03-07 15:51:31 +00002 * Copyright 2018 The Hafnium Authors.
Andrew Scull18834872018-10-12 11:48:09 +01003 *
Andrew Walbrane959ec12020-06-17 15:01:09 +01004 * 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.
Andrew Scull18834872018-10-12 11:48:09 +01007 */
8
Andrew Scullf0551c82018-12-15 20:38:47 +00009#include "hf/arch/vm/power_mgmt.h"
10
Andrew Walbranafabe852019-03-20 17:55:11 +000011#include "hf/boot_params.h"
12#include "hf/fdt_handler.h"
Andrew Scullbc7189d2018-08-14 09:35:13 +010013#include "hf/memiter.h"
Andrew Scull8d9e1212019-04-05 13:52:55 +010014#include "hf/std.h"
Andrew Scullbc7189d2018-08-14 09:35:13 +010015
David Brazdil3ad6e542019-09-13 17:17:09 +010016#include "hftest_common.h"
Andrew Walbran1e7c7742019-12-13 17:10:02 +000017#include "test/hftest.h"
Andrew Scullbc7189d2018-08-14 09:35:13 +010018
Daniel Boulby61049dc2023-06-16 14:15:21 +010019#define HFTEST_CTRL_JSON_START "[hftest_ctrl:json_start]"
20#define HFTEST_CTRL_JSON_END "[hftest_ctrl:json_end]"
21
Andrew Scullbc7189d2018-08-14 09:35:13 +010022HFTEST_ENABLE();
23
Andrew Walbranbc342d42019-02-05 16:56:02 +000024static struct hftest_test hftest_constructed[HFTEST_MAX_TESTS];
25static size_t hftest_count;
26static struct hftest_test *hftest_list;
Andrew Scullbc7189d2018-08-14 09:35:13 +010027
Andrew Scullf0551c82018-12-15 20:38:47 +000028static struct hftest_context global_context;
29
J-Alves31e5c952024-07-12 09:45:05 +010030static alignas(PAGE_SIZE) uint8_t secondary_ec_stack[MAX_CPUS][PAGE_SIZE];
31
Andrew Scullf0551c82018-12-15 20:38:47 +000032struct hftest_context *hftest_get_context(void)
33{
34 return &global_context;
35}
36
Andrew Walbranbc342d42019-02-05 16:56:02 +000037/**
38 * Adds the given test information to the global list, to be used by
39 * `hftest_use_registered_list`.
40 */
41void hftest_register(struct hftest_test test)
Andrew Scullbc7189d2018-08-14 09:35:13 +010042{
Andrew Walbranbc342d42019-02-05 16:56:02 +000043 if (hftest_count < HFTEST_MAX_TESTS) {
44 hftest_constructed[hftest_count++] = test;
45 } else {
Andrew Walbran78a63b72019-03-18 17:28:22 +000046 HFTEST_FAIL(true, "Too many tests");
Andrew Walbranbc342d42019-02-05 16:56:02 +000047 }
48}
49
50/**
51 * Uses the list of tests registered by `hftest_register(...)` as the ones to
52 * run.
53 */
54void hftest_use_registered_list(void)
55{
56 hftest_list = hftest_constructed;
57}
58
59/**
60 * Uses the given list of tests as the ones to run.
61 */
62void hftest_use_list(struct hftest_test list[], size_t count)
63{
64 hftest_list = list;
65 hftest_count = count;
66}
67
68/**
69 * Writes out a JSON structure describing the available tests.
70 */
71void hftest_json(void)
72{
Andrew Scullbc7189d2018-08-14 09:35:13 +010073 const char *suite = NULL;
Andrew Walbranbc342d42019-02-05 16:56:02 +000074 size_t i;
Andrew Scullbc7189d2018-08-14 09:35:13 +010075 size_t tests_in_suite = 0;
76
Daniel Boulby61049dc2023-06-16 14:15:21 +010077 /* Wrap the JSON in tags for the hftest script to use. */
78 HFTEST_LOG(HFTEST_CTRL_JSON_START);
79
Andrew Scullbc7189d2018-08-14 09:35:13 +010080 HFTEST_LOG("{");
81 HFTEST_LOG(" \"suites\": [");
Andrew Walbranbc342d42019-02-05 16:56:02 +000082 for (i = 0; i < hftest_count; ++i) {
83 struct hftest_test *test = &hftest_list[i];
Andrew Scullbc7189d2018-08-14 09:35:13 +010084 if (test->suite != suite) {
85 /* Close out previously open suite. */
86 if (tests_in_suite) {
87 HFTEST_LOG(" ]");
88 HFTEST_LOG(" },");
89 }
90 /* Move onto new suite. */
Andrew Scullbc7189d2018-08-14 09:35:13 +010091 suite = test->suite;
92 tests_in_suite = 0;
93 HFTEST_LOG(" {");
94 HFTEST_LOG(" \"name\": \"%s\",", test->suite);
95 }
96 if (test->kind == HFTEST_KIND_SET_UP) {
97 HFTEST_LOG(" \"setup\": true,");
98 }
99 if (test->kind == HFTEST_KIND_TEAR_DOWN) {
100 HFTEST_LOG(" \"teardown\": true,");
101 }
102 if (test->kind == HFTEST_KIND_TEST) {
J-Alvesd459b562022-12-05 14:56:33 +0000103 /*
104 * If test has a precondition, run respective function.
105 * If it returns false, then the current setup is not
106 * meant to run the test. Hence, we must skip it.
107 */
108 bool skip_test = test->precondition != NULL &&
109 !test->precondition();
110
Andrew Scullbc7189d2018-08-14 09:35:13 +0100111 if (!tests_in_suite) {
112 HFTEST_LOG(" \"tests\": [");
113 }
Andrew Scullf0551c82018-12-15 20:38:47 +0000114 /*
115 * It's easier to put the comma at the start of the line
Andrew Scull2b5fbad2019-04-05 13:55:56 +0100116 * than the end even though the JSON looks a bit funky.
Andrew Scullf0551c82018-12-15 20:38:47 +0000117 */
David Brazdil3cc24aa2019-09-27 10:24:41 +0100118 HFTEST_LOG(" %c{", tests_in_suite ? ',' : ' ');
119 HFTEST_LOG(" \"name\": \"%s\",", test->name);
J-Alvesd459b562022-12-05 14:56:33 +0000120 HFTEST_LOG(" \"is_long_running\": %s,",
David Brazdil3cc24aa2019-09-27 10:24:41 +0100121 test->is_long_running ? "true" : "false");
J-Alvesd459b562022-12-05 14:56:33 +0000122 HFTEST_LOG(" \"skip_test\": %s",
123 skip_test ? "true" : "false");
David Brazdil3cc24aa2019-09-27 10:24:41 +0100124 HFTEST_LOG(" }");
Andrew Scullbc7189d2018-08-14 09:35:13 +0100125 ++tests_in_suite;
126 }
127 }
128 if (tests_in_suite) {
129 HFTEST_LOG(" ]");
130 HFTEST_LOG(" }");
131 }
132 HFTEST_LOG(" ]");
133 HFTEST_LOG("}");
Daniel Boulby61049dc2023-06-16 14:15:21 +0100134
135 /* Wrap the JSON in tags for the hftest script to use. */
136 HFTEST_LOG(HFTEST_CTRL_JSON_END);
Andrew Scullbc7189d2018-08-14 09:35:13 +0100137}
138
Andrew Walbranbc342d42019-02-05 16:56:02 +0000139/**
140 * Logs a failure message and shut down.
141 */
Andrew Sculla59f9bc2019-04-03 15:24:35 +0100142noreturn void abort(void)
Andrew Scullf0551c82018-12-15 20:38:47 +0000143{
144 HFTEST_LOG("FAIL");
Andrew Walbranc6903d12019-03-05 18:28:20 +0000145 arch_power_off();
Andrew Scullf0551c82018-12-15 20:38:47 +0000146}
147
Andrew Scullbc7189d2018-08-14 09:35:13 +0100148static void run_test(hftest_test_fn set_up, hftest_test_fn test,
David Brazdilb856be62020-03-25 10:14:55 +0000149 hftest_test_fn tear_down, const struct fdt *fdt)
Andrew Scullbc7189d2018-08-14 09:35:13 +0100150{
Andrew Scullf0551c82018-12-15 20:38:47 +0000151 /* Prepare the context. */
152 struct hftest_context *ctx = hftest_get_context();
Andrew Scull2b5fbad2019-04-05 13:55:56 +0100153 memset_s(ctx, sizeof(*ctx), 0, sizeof(*ctx));
Andrew Scullf0551c82018-12-15 20:38:47 +0000154 ctx->abort = abort;
Andrew Walbranafabe852019-03-20 17:55:11 +0000155 ctx->fdt = fdt;
Andrew Scullbc7189d2018-08-14 09:35:13 +0100156
Andrew Scullf0551c82018-12-15 20:38:47 +0000157 /* Run any set up functions. */
Andrew Scullbc7189d2018-08-14 09:35:13 +0100158 if (set_up) {
Andrew Scullf0551c82018-12-15 20:38:47 +0000159 set_up();
160 if (ctx->failures) {
161 abort();
Andrew Scullbc7189d2018-08-14 09:35:13 +0100162 }
163 }
164
Andrew Scullf0551c82018-12-15 20:38:47 +0000165 /* Run the test. */
166 test();
167 if (ctx->failures) {
168 abort();
Andrew Scullbc7189d2018-08-14 09:35:13 +0100169 }
170
Andrew Scullf0551c82018-12-15 20:38:47 +0000171 /* Run any tear down functions. */
Andrew Scullbc7189d2018-08-14 09:35:13 +0100172 if (tear_down) {
Andrew Scullf0551c82018-12-15 20:38:47 +0000173 tear_down();
174 if (ctx->failures) {
175 abort();
Andrew Scullbc7189d2018-08-14 09:35:13 +0100176 }
177 }
178
Andrew Scullf0551c82018-12-15 20:38:47 +0000179 HFTEST_LOG("FINISHED");
Andrew Scullbc7189d2018-08-14 09:35:13 +0100180}
181
Andrew Walbranbc342d42019-02-05 16:56:02 +0000182/**
183 * Runs the given test case.
184 */
Andrew Walbranafabe852019-03-20 17:55:11 +0000185void hftest_run(struct memiter suite_name, struct memiter test_name,
David Brazdilb856be62020-03-25 10:14:55 +0000186 const struct fdt *fdt)
Andrew Scullbc7189d2018-08-14 09:35:13 +0100187{
Andrew Walbranbc342d42019-02-05 16:56:02 +0000188 size_t i;
Andrew Scullbc7189d2018-08-14 09:35:13 +0100189 hftest_test_fn suite_set_up = NULL;
190 hftest_test_fn suite_tear_down = NULL;
191
Andrew Walbranbc342d42019-02-05 16:56:02 +0000192 for (i = 0; i < hftest_count; ++i) {
193 struct hftest_test *test = &hftest_list[i];
Andrew Walbran320c84e2019-11-12 12:48:24 +0000194
195 /* Check if this test is part of the suite we want. */
196 if (memiter_iseq(&suite_name, test->suite)) {
197 switch (test->kind) {
198 /*
199 * The first entries in the suite are the set up and
200 * tear down functions.
201 */
202 case HFTEST_KIND_SET_UP:
203 suite_set_up = test->fn;
204 break;
205 case HFTEST_KIND_TEAR_DOWN:
206 suite_tear_down = test->fn;
207 break;
208 /* Find the test. */
209 case HFTEST_KIND_TEST:
210 if (memiter_iseq(&test_name, test->name)) {
211 run_test(suite_set_up, test->fn,
212 suite_tear_down, fdt);
213 return;
214 }
215 break;
216 default:
217 /* Ignore other kinds. */
Andrew Scullbc7189d2018-08-14 09:35:13 +0100218 break;
219 }
Andrew Scullbc7189d2018-08-14 09:35:13 +0100220 }
221 }
222
223 HFTEST_LOG("Unable to find requested tests.");
224}
225
Andrew Walbranbc342d42019-02-05 16:56:02 +0000226/**
227 * Writes out usage information.
228 */
229void hftest_help(void)
Andrew Scullbc7189d2018-08-14 09:35:13 +0100230{
231 HFTEST_LOG("usage:");
232 HFTEST_LOG("");
233 HFTEST_LOG(" help");
234 HFTEST_LOG("");
235 HFTEST_LOG(" Show this help.");
236 HFTEST_LOG("");
237 HFTEST_LOG(" json");
238 HFTEST_LOG("");
239 HFTEST_LOG(
240 " Print a directory of test suites and tests in "
241 "JSON "
242 "format.");
243 HFTEST_LOG("");
244 HFTEST_LOG(" run <suite> <test>");
245 HFTEST_LOG("");
246 HFTEST_LOG(" Run the named test from the named test suite.");
247}
Andrew Walbranafabe852019-03-20 17:55:11 +0000248
J-Alves070a40d2021-01-21 14:35:12 +0000249void hftest_command(struct fdt *fdt)
250{
251 struct memiter command_line;
252 struct memiter command;
253
254 if (!hftest_ctrl_start(fdt, &command_line)) {
255 HFTEST_LOG("Unable to read the command line.");
256 return;
257 }
258
259 if (!memiter_parse_str(&command_line, &command)) {
260 HFTEST_LOG("Unable to parse command.");
261 return;
262 }
263
264 if (memiter_iseq(&command, "exit")) {
265 hftest_device_exit_test_environment();
266 return;
267 }
268
269 if (memiter_iseq(&command, "json")) {
270 hftest_json();
271 return;
272 }
273
274 if (memiter_iseq(&command, "run")) {
275 struct memiter suite_name;
276 struct memiter test_name;
277
278 if (!memiter_parse_str(&command_line, &suite_name)) {
279 HFTEST_LOG("Unable to parse test suite.");
280 return;
281 }
282
283 if (!memiter_parse_str(&command_line, &test_name)) {
284 HFTEST_LOG("Unable to parse test.");
285 return;
286 }
287 hftest_run(suite_name, test_name, fdt);
288 return;
289 }
290
291 hftest_help();
292}
293
Andrew Walbranafabe852019-03-20 17:55:11 +0000294static uintptr_t vcpu_index_to_id(size_t index)
295{
296 /* For now we use indices as IDs for vCPUs. */
297 return index;
298}
299
J-Alves31e5c952024-07-12 09:45:05 +0100300uint8_t *hftest_get_secondary_ec_stack(size_t id)
301{
302 assert(id < MAX_CPUS);
303 return secondary_ec_stack[id];
304}
305
Andrew Walbranafabe852019-03-20 17:55:11 +0000306/**
307 * Get the ID of the CPU with the given index.
308 */
Karl Meakin2b56fc12024-07-02 15:24:27 +0100309cpu_id_t hftest_get_cpu_id(size_t index)
Andrew Walbranafabe852019-03-20 17:55:11 +0000310{
311 struct boot_params params;
David Brazdilb856be62020-03-25 10:14:55 +0000312 const struct fdt *fdt = hftest_get_context()->fdt;
Andrew Walbranafabe852019-03-20 17:55:11 +0000313
314 if (fdt == NULL) {
315 /*
316 * We must be in a service VM, so apply the mapping that Hafnium
317 * uses for vCPU IDs.
318 */
319 return vcpu_index_to_id(index);
320 }
321
J-Alves0c029c22023-06-21 10:32:57 +0100322 /*
323 * VM is primary VM. Convert vCPU ids to the linear cpu id as passed to
324 * the primary VM in the FDT structure.
325 */
326 index = MAX_CPUS - index;
327
Andrew Walbranafabe852019-03-20 17:55:11 +0000328 /* Find physical CPU ID from FDT. */
David Brazdilb856be62020-03-25 10:14:55 +0000329 fdt_find_cpus(fdt, params.cpu_ids, &params.cpu_count);
Andrew Walbranafabe852019-03-20 17:55:11 +0000330
331 return params.cpu_ids[index];
332}