blob: be4c44c65a368ac00fad388896e89bbad6abca64 [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 Scullf0551c82018-12-15 20:38:47 +000022static struct hftest_context global_context;
23
Karl Meakin95d5c062025-03-20 13:46:31 +000024extern struct hftest_test hftest_begin[];
25extern struct hftest_test hftest_end[];
26
J-Alves31e5c952024-07-12 09:45:05 +010027static alignas(PAGE_SIZE) uint8_t secondary_ec_stack[MAX_CPUS][PAGE_SIZE];
28
Andrew Scullf0551c82018-12-15 20:38:47 +000029struct hftest_context *hftest_get_context(void)
30{
31 return &global_context;
32}
33
Andrew Walbranbc342d42019-02-05 16:56:02 +000034/**
Andrew Walbranbc342d42019-02-05 16:56:02 +000035 * Writes out a JSON structure describing the available tests.
36 */
37void hftest_json(void)
38{
Andrew Scullbc7189d2018-08-14 09:35:13 +010039 const char *suite = NULL;
Andrew Scullbc7189d2018-08-14 09:35:13 +010040 size_t tests_in_suite = 0;
41
Daniel Boulby61049dc2023-06-16 14:15:21 +010042 /* Wrap the JSON in tags for the hftest script to use. */
43 HFTEST_LOG(HFTEST_CTRL_JSON_START);
44
Andrew Scullbc7189d2018-08-14 09:35:13 +010045 HFTEST_LOG("{");
46 HFTEST_LOG(" \"suites\": [");
Karl Meakin95d5c062025-03-20 13:46:31 +000047 for (struct hftest_test *test = hftest_begin; test < hftest_end;
48 ++test) {
Andrew Scullbc7189d2018-08-14 09:35:13 +010049 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. */
Andrew Scullbc7189d2018-08-14 09:35:13 +010056 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) {
J-Alvesd459b562022-12-05 14:56:33 +000068 /*
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
Andrew Scullbc7189d2018-08-14 09:35:13 +010076 if (!tests_in_suite) {
77 HFTEST_LOG(" \"tests\": [");
78 }
Andrew Scullf0551c82018-12-15 20:38:47 +000079 /*
80 * It's easier to put the comma at the start of the line
Andrew Scull2b5fbad2019-04-05 13:55:56 +010081 * than the end even though the JSON looks a bit funky.
Andrew Scullf0551c82018-12-15 20:38:47 +000082 */
David Brazdil3cc24aa2019-09-27 10:24:41 +010083 HFTEST_LOG(" %c{", tests_in_suite ? ',' : ' ');
84 HFTEST_LOG(" \"name\": \"%s\",", test->name);
J-Alvesd459b562022-12-05 14:56:33 +000085 HFTEST_LOG(" \"is_long_running\": %s,",
David Brazdil3cc24aa2019-09-27 10:24:41 +010086 test->is_long_running ? "true" : "false");
J-Alvesd459b562022-12-05 14:56:33 +000087 HFTEST_LOG(" \"skip_test\": %s",
88 skip_test ? "true" : "false");
David Brazdil3cc24aa2019-09-27 10:24:41 +010089 HFTEST_LOG(" }");
Andrew Scullbc7189d2018-08-14 09:35:13 +010090 ++tests_in_suite;
91 }
92 }
93 if (tests_in_suite) {
94 HFTEST_LOG(" ]");
95 HFTEST_LOG(" }");
96 }
97 HFTEST_LOG(" ]");
98 HFTEST_LOG("}");
Daniel Boulby61049dc2023-06-16 14:15:21 +010099
100 /* Wrap the JSON in tags for the hftest script to use. */
101 HFTEST_LOG(HFTEST_CTRL_JSON_END);
Andrew Scullbc7189d2018-08-14 09:35:13 +0100102}
103
Andrew Walbranbc342d42019-02-05 16:56:02 +0000104/**
105 * Logs a failure message and shut down.
106 */
Andrew Sculla59f9bc2019-04-03 15:24:35 +0100107noreturn void abort(void)
Andrew Scullf0551c82018-12-15 20:38:47 +0000108{
109 HFTEST_LOG("FAIL");
Andrew Walbranc6903d12019-03-05 18:28:20 +0000110 arch_power_off();
Andrew Scullf0551c82018-12-15 20:38:47 +0000111}
112
Andrew Scullbc7189d2018-08-14 09:35:13 +0100113static void run_test(hftest_test_fn set_up, hftest_test_fn test,
David Brazdilb856be62020-03-25 10:14:55 +0000114 hftest_test_fn tear_down, const struct fdt *fdt)
Andrew Scullbc7189d2018-08-14 09:35:13 +0100115{
Andrew Scullf0551c82018-12-15 20:38:47 +0000116 /* Prepare the context. */
117 struct hftest_context *ctx = hftest_get_context();
Andrew Scull2b5fbad2019-04-05 13:55:56 +0100118 memset_s(ctx, sizeof(*ctx), 0, sizeof(*ctx));
Andrew Scullf0551c82018-12-15 20:38:47 +0000119 ctx->abort = abort;
Andrew Walbranafabe852019-03-20 17:55:11 +0000120 ctx->fdt = fdt;
Andrew Scullbc7189d2018-08-14 09:35:13 +0100121
Andrew Scullf0551c82018-12-15 20:38:47 +0000122 /* Run any set up functions. */
Andrew Scullbc7189d2018-08-14 09:35:13 +0100123 if (set_up) {
Andrew Scullf0551c82018-12-15 20:38:47 +0000124 set_up();
125 if (ctx->failures) {
126 abort();
Andrew Scullbc7189d2018-08-14 09:35:13 +0100127 }
128 }
129
Andrew Scullf0551c82018-12-15 20:38:47 +0000130 /* Run the test. */
131 test();
132 if (ctx->failures) {
133 abort();
Andrew Scullbc7189d2018-08-14 09:35:13 +0100134 }
135
Andrew Scullf0551c82018-12-15 20:38:47 +0000136 /* Run any tear down functions. */
Andrew Scullbc7189d2018-08-14 09:35:13 +0100137 if (tear_down) {
Andrew Scullf0551c82018-12-15 20:38:47 +0000138 tear_down();
139 if (ctx->failures) {
140 abort();
Andrew Scullbc7189d2018-08-14 09:35:13 +0100141 }
142 }
143
Andrew Scullf0551c82018-12-15 20:38:47 +0000144 HFTEST_LOG("FINISHED");
Andrew Scullbc7189d2018-08-14 09:35:13 +0100145}
146
Andrew Walbranbc342d42019-02-05 16:56:02 +0000147/**
148 * Runs the given test case.
149 */
Andrew Walbranafabe852019-03-20 17:55:11 +0000150void hftest_run(struct memiter suite_name, struct memiter test_name,
David Brazdilb856be62020-03-25 10:14:55 +0000151 const struct fdt *fdt)
Andrew Scullbc7189d2018-08-14 09:35:13 +0100152{
Andrew Scullbc7189d2018-08-14 09:35:13 +0100153 hftest_test_fn suite_set_up = NULL;
154 hftest_test_fn suite_tear_down = NULL;
155
Karl Meakin95d5c062025-03-20 13:46:31 +0000156 for (struct hftest_test *test = hftest_begin; test < hftest_end;
157 ++test) {
Andrew Walbran320c84e2019-11-12 12:48:24 +0000158 /* 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. */
Andrew Scullbc7189d2018-08-14 09:35:13 +0100181 break;
182 }
Andrew Scullbc7189d2018-08-14 09:35:13 +0100183 }
184 }
185
186 HFTEST_LOG("Unable to find requested tests.");
187}
188
Andrew Walbranbc342d42019-02-05 16:56:02 +0000189/**
190 * Writes out usage information.
191 */
192void hftest_help(void)
Andrew Scullbc7189d2018-08-14 09:35:13 +0100193{
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}
Andrew Walbranafabe852019-03-20 17:55:11 +0000211
J-Alves070a40d2021-01-21 14:35:12 +0000212void 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
Andrew Walbranafabe852019-03-20 17:55:11 +0000257static 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
J-Alves31e5c952024-07-12 09:45:05 +0100263uint8_t *hftest_get_secondary_ec_stack(size_t id)
264{
265 assert(id < MAX_CPUS);
266 return secondary_ec_stack[id];
267}
268
Andrew Walbranafabe852019-03-20 17:55:11 +0000269/**
270 * Get the ID of the CPU with the given index.
271 */
Karl Meakin2b56fc12024-07-02 15:24:27 +0100272cpu_id_t hftest_get_cpu_id(size_t index)
Andrew Walbranafabe852019-03-20 17:55:11 +0000273{
274 struct boot_params params;
David Brazdilb856be62020-03-25 10:14:55 +0000275 const struct fdt *fdt = hftest_get_context()->fdt;
Andrew Walbranafabe852019-03-20 17:55:11 +0000276
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
J-Alves0c029c22023-06-21 10:32:57 +0100285 /*
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
Andrew Walbranafabe852019-03-20 17:55:11 +0000291 /* Find physical CPU ID from FDT. */
David Brazdilb856be62020-03-25 10:14:55 +0000292 fdt_find_cpus(fdt, params.cpu_ids, &params.cpu_count);
Andrew Walbranafabe852019-03-20 17:55:11 +0000293
294 return params.cpu_ids[index];
295}