blob: 8c8d334da8862d45ddaf192960fef816143f393d [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 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
Andrew Walbranbc342d42019-02-05 16:56:02 +000017#include "hftest_common.h"
Andrew Scullbc7189d2018-08-14 09:35:13 +010018
Andrew Scullf0551c82018-12-15 20:38:47 +000019#include "hf/arch/vm/power_mgmt.h"
20
Andrew Walbranafabe852019-03-20 17:55:11 +000021#include "hf/boot_params.h"
22#include "hf/fdt_handler.h"
Andrew Scullbc7189d2018-08-14 09:35:13 +010023#include "hf/memiter.h"
Andrew Scull8d9e1212019-04-05 13:52:55 +010024#include "hf/std.h"
Andrew Scullbc7189d2018-08-14 09:35:13 +010025
Andrew Walbranbc342d42019-02-05 16:56:02 +000026#include "hftest.h"
Andrew Scullbc7189d2018-08-14 09:35:13 +010027
28HFTEST_ENABLE();
29
Andrew Walbranbc342d42019-02-05 16:56:02 +000030static struct hftest_test hftest_constructed[HFTEST_MAX_TESTS];
31static size_t hftest_count;
32static struct hftest_test *hftest_list;
Andrew Scullbc7189d2018-08-14 09:35:13 +010033
Andrew Scullf0551c82018-12-15 20:38:47 +000034static struct hftest_context global_context;
35
36struct hftest_context *hftest_get_context(void)
37{
38 return &global_context;
39}
40
Andrew Walbranbc342d42019-02-05 16:56:02 +000041/**
42 * Adds the given test information to the global list, to be used by
43 * `hftest_use_registered_list`.
44 */
45void hftest_register(struct hftest_test test)
Andrew Scullbc7189d2018-08-14 09:35:13 +010046{
Andrew Walbranbc342d42019-02-05 16:56:02 +000047 if (hftest_count < HFTEST_MAX_TESTS) {
48 hftest_constructed[hftest_count++] = test;
49 } else {
Andrew Walbran78a63b72019-03-18 17:28:22 +000050 HFTEST_FAIL(true, "Too many tests");
Andrew Walbranbc342d42019-02-05 16:56:02 +000051 }
52}
53
54/**
55 * Uses the list of tests registered by `hftest_register(...)` as the ones to
56 * run.
57 */
58void hftest_use_registered_list(void)
59{
60 hftest_list = hftest_constructed;
61}
62
63/**
64 * Uses the given list of tests as the ones to run.
65 */
66void hftest_use_list(struct hftest_test list[], size_t count)
67{
68 hftest_list = list;
69 hftest_count = count;
70}
71
72/**
73 * Writes out a JSON structure describing the available tests.
74 */
75void hftest_json(void)
76{
Andrew Scullbc7189d2018-08-14 09:35:13 +010077 const char *suite = NULL;
Andrew Walbranbc342d42019-02-05 16:56:02 +000078 size_t i;
Andrew Scullbc7189d2018-08-14 09:35:13 +010079 size_t suites_in_image = 0;
80 size_t tests_in_suite = 0;
81
82 HFTEST_LOG("{");
83 HFTEST_LOG(" \"suites\": [");
Andrew Walbranbc342d42019-02-05 16:56:02 +000084 for (i = 0; i < hftest_count; ++i) {
85 struct hftest_test *test = &hftest_list[i];
Andrew Scullbc7189d2018-08-14 09:35:13 +010086 if (test->suite != suite) {
87 /* Close out previously open suite. */
88 if (tests_in_suite) {
89 HFTEST_LOG(" ]");
90 HFTEST_LOG(" },");
91 }
92 /* Move onto new suite. */
93 ++suites_in_image;
94 suite = test->suite;
95 tests_in_suite = 0;
96 HFTEST_LOG(" {");
97 HFTEST_LOG(" \"name\": \"%s\",", test->suite);
98 }
99 if (test->kind == HFTEST_KIND_SET_UP) {
100 HFTEST_LOG(" \"setup\": true,");
101 }
102 if (test->kind == HFTEST_KIND_TEAR_DOWN) {
103 HFTEST_LOG(" \"teardown\": true,");
104 }
105 if (test->kind == HFTEST_KIND_TEST) {
106 if (!tests_in_suite) {
107 HFTEST_LOG(" \"tests\": [");
108 }
Andrew Scullf0551c82018-12-15 20:38:47 +0000109 /*
110 * It's easier to put the comma at the start of the line
Andrew Scull2b5fbad2019-04-05 13:55:56 +0100111 * than the end even though the JSON looks a bit funky.
Andrew Scullf0551c82018-12-15 20:38:47 +0000112 */
Andrew Scullbc7189d2018-08-14 09:35:13 +0100113 HFTEST_LOG(" %c\"%s\"",
114 tests_in_suite ? ',' : ' ', test->name);
115 ++tests_in_suite;
116 }
117 }
118 if (tests_in_suite) {
119 HFTEST_LOG(" ]");
120 HFTEST_LOG(" }");
121 }
122 HFTEST_LOG(" ]");
123 HFTEST_LOG("}");
124}
125
Andrew Walbranbc342d42019-02-05 16:56:02 +0000126/**
127 * Logs a failure message and shut down.
128 */
Andrew Sculla59f9bc2019-04-03 15:24:35 +0100129noreturn void abort(void)
Andrew Scullf0551c82018-12-15 20:38:47 +0000130{
131 HFTEST_LOG("FAIL");
Andrew Walbranc6903d12019-03-05 18:28:20 +0000132 arch_power_off();
Andrew Scullf0551c82018-12-15 20:38:47 +0000133}
134
Andrew Scullbc7189d2018-08-14 09:35:13 +0100135static void run_test(hftest_test_fn set_up, hftest_test_fn test,
Andrew Walbranafabe852019-03-20 17:55:11 +0000136 hftest_test_fn tear_down, const struct fdt_header *fdt)
Andrew Scullbc7189d2018-08-14 09:35:13 +0100137{
Andrew Scullf0551c82018-12-15 20:38:47 +0000138 /* Prepare the context. */
139 struct hftest_context *ctx = hftest_get_context();
Andrew Scull2b5fbad2019-04-05 13:55:56 +0100140 memset_s(ctx, sizeof(*ctx), 0, sizeof(*ctx));
Andrew Scullf0551c82018-12-15 20:38:47 +0000141 ctx->abort = abort;
Andrew Walbranafabe852019-03-20 17:55:11 +0000142 ctx->fdt = fdt;
Andrew Scullbc7189d2018-08-14 09:35:13 +0100143
Andrew Scullf0551c82018-12-15 20:38:47 +0000144 /* Run any set up functions. */
Andrew Scullbc7189d2018-08-14 09:35:13 +0100145 if (set_up) {
Andrew Scullf0551c82018-12-15 20:38:47 +0000146 set_up();
147 if (ctx->failures) {
148 abort();
Andrew Scullbc7189d2018-08-14 09:35:13 +0100149 }
150 }
151
Andrew Scullf0551c82018-12-15 20:38:47 +0000152 /* Run the test. */
153 test();
154 if (ctx->failures) {
155 abort();
Andrew Scullbc7189d2018-08-14 09:35:13 +0100156 }
157
Andrew Scullf0551c82018-12-15 20:38:47 +0000158 /* Run any tear down functions. */
Andrew Scullbc7189d2018-08-14 09:35:13 +0100159 if (tear_down) {
Andrew Scullf0551c82018-12-15 20:38:47 +0000160 tear_down();
161 if (ctx->failures) {
162 abort();
Andrew Scullbc7189d2018-08-14 09:35:13 +0100163 }
164 }
165
Andrew Scullf0551c82018-12-15 20:38:47 +0000166 HFTEST_LOG("FINISHED");
Andrew Scullbc7189d2018-08-14 09:35:13 +0100167}
168
Andrew Walbranbc342d42019-02-05 16:56:02 +0000169/**
170 * Runs the given test case.
171 */
Andrew Walbranafabe852019-03-20 17:55:11 +0000172void hftest_run(struct memiter suite_name, struct memiter test_name,
173 const struct fdt_header *fdt)
Andrew Scullbc7189d2018-08-14 09:35:13 +0100174{
Andrew Walbranbc342d42019-02-05 16:56:02 +0000175 size_t i;
Andrew Scullbc7189d2018-08-14 09:35:13 +0100176 bool found_suite = false;
177 const char *suite = NULL;
178 hftest_test_fn suite_set_up = NULL;
179 hftest_test_fn suite_tear_down = NULL;
180
Andrew Walbranbc342d42019-02-05 16:56:02 +0000181 for (i = 0; i < hftest_count; ++i) {
182 struct hftest_test *test = &hftest_list[i];
Andrew Scullbc7189d2018-08-14 09:35:13 +0100183 /* Find the test suite. */
184 if (found_suite) {
185 if (test->suite != suite) {
186 /* Test wasn't in the suite. */
187 break;
188 }
189 } else {
190 if (test->suite == suite) {
191 /* This isn't the right suite so keep going. */
192 continue;
193 }
194 /* Examine a new suite. */
195 suite = test->suite;
196 if (memiter_iseq(&suite_name, test->suite)) {
197 found_suite = true;
198 }
199 }
200
201 switch (test->kind) {
Andrew Scullf0551c82018-12-15 20:38:47 +0000202 /*
203 * The first entries in the suite are the set up and tear down
204 * functions.
205 */
Andrew Scullbc7189d2018-08-14 09:35:13 +0100206 case HFTEST_KIND_SET_UP:
207 suite_set_up = test->fn;
208 break;
209 case HFTEST_KIND_TEAR_DOWN:
210 suite_tear_down = test->fn;
211 break;
212 /* Find the test. */
213 case HFTEST_KIND_TEST:
214 if (memiter_iseq(&test_name, test->name)) {
215 run_test(suite_set_up, test->fn,
Andrew Walbranafabe852019-03-20 17:55:11 +0000216 suite_tear_down, fdt);
Andrew Scullbc7189d2018-08-14 09:35:13 +0100217 return;
218 }
219 break;
Andrew Scullf0551c82018-12-15 20:38:47 +0000220 default:
221 /* Ignore other kinds. */
222 break;
Andrew Scullbc7189d2018-08-14 09:35:13 +0100223 }
224 }
225
226 HFTEST_LOG("Unable to find requested tests.");
227}
228
Andrew Walbranbc342d42019-02-05 16:56:02 +0000229/**
230 * Writes out usage information.
231 */
232void hftest_help(void)
Andrew Scullbc7189d2018-08-14 09:35:13 +0100233{
234 HFTEST_LOG("usage:");
235 HFTEST_LOG("");
236 HFTEST_LOG(" help");
237 HFTEST_LOG("");
238 HFTEST_LOG(" Show this help.");
239 HFTEST_LOG("");
240 HFTEST_LOG(" json");
241 HFTEST_LOG("");
242 HFTEST_LOG(
243 " Print a directory of test suites and tests in "
244 "JSON "
245 "format.");
246 HFTEST_LOG("");
247 HFTEST_LOG(" run <suite> <test>");
248 HFTEST_LOG("");
249 HFTEST_LOG(" Run the named test from the named test suite.");
250}
Andrew Walbranafabe852019-03-20 17:55:11 +0000251
252static uintptr_t vcpu_index_to_id(size_t index)
253{
254 /* For now we use indices as IDs for vCPUs. */
255 return index;
256}
257
258/**
259 * Get the ID of the CPU with the given index.
260 */
261uintptr_t hftest_get_cpu_id(size_t index)
262{
263 struct boot_params params;
264 struct fdt_node n;
265 const struct fdt_header *fdt = hftest_get_context()->fdt;
266
267 if (fdt == NULL) {
268 /*
269 * We must be in a service VM, so apply the mapping that Hafnium
270 * uses for vCPU IDs.
271 */
272 return vcpu_index_to_id(index);
273 }
274
275 /* Find physical CPU ID from FDT. */
276 if (!fdt_root_node(&n, fdt)) {
277 FAIL("FDT failed validation.");
278 }
279 if (!fdt_find_child(&n, "")) {
280 FAIL("Unable to find FDT root node.");
281 }
282 fdt_find_cpus(&n, params.cpu_ids, &params.cpu_count);
283
284 return params.cpu_ids[index];
285}