blob: 81fc5169426351b5cc381c4e228283d85ba8bf4f [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 Scullf0551c82018-12-15 20:38:47 +000017#include "hf/arch/vm/power_mgmt.h"
18
Andrew Walbranafabe852019-03-20 17:55:11 +000019#include "hf/boot_params.h"
20#include "hf/fdt_handler.h"
Andrew Scullbc7189d2018-08-14 09:35:13 +010021#include "hf/memiter.h"
Andrew Scull8d9e1212019-04-05 13:52:55 +010022#include "hf/std.h"
Andrew Scullbc7189d2018-08-14 09:35:13 +010023
Andrew Walbranbc342d42019-02-05 16:56:02 +000024#include "hftest.h"
David Brazdil3ad6e542019-09-13 17:17:09 +010025#include "hftest_common.h"
Andrew Scullbc7189d2018-08-14 09:35:13 +010026
27HFTEST_ENABLE();
28
Andrew Walbranbc342d42019-02-05 16:56:02 +000029static struct hftest_test hftest_constructed[HFTEST_MAX_TESTS];
30static size_t hftest_count;
31static struct hftest_test *hftest_list;
Andrew Scullbc7189d2018-08-14 09:35:13 +010032
Andrew Scullf0551c82018-12-15 20:38:47 +000033static struct hftest_context global_context;
34
35struct hftest_context *hftest_get_context(void)
36{
37 return &global_context;
38}
39
Andrew Walbranbc342d42019-02-05 16:56:02 +000040/**
41 * Adds the given test information to the global list, to be used by
42 * `hftest_use_registered_list`.
43 */
44void hftest_register(struct hftest_test test)
Andrew Scullbc7189d2018-08-14 09:35:13 +010045{
Andrew Walbranbc342d42019-02-05 16:56:02 +000046 if (hftest_count < HFTEST_MAX_TESTS) {
47 hftest_constructed[hftest_count++] = test;
48 } else {
Andrew Walbran78a63b72019-03-18 17:28:22 +000049 HFTEST_FAIL(true, "Too many tests");
Andrew Walbranbc342d42019-02-05 16:56:02 +000050 }
51}
52
53/**
54 * Uses the list of tests registered by `hftest_register(...)` as the ones to
55 * run.
56 */
57void hftest_use_registered_list(void)
58{
59 hftest_list = hftest_constructed;
60}
61
62/**
63 * Uses the given list of tests as the ones to run.
64 */
65void hftest_use_list(struct hftest_test list[], size_t count)
66{
67 hftest_list = list;
68 hftest_count = count;
69}
70
71/**
72 * Writes out a JSON structure describing the available tests.
73 */
74void hftest_json(void)
75{
Andrew Scullbc7189d2018-08-14 09:35:13 +010076 const char *suite = NULL;
Andrew Walbranbc342d42019-02-05 16:56:02 +000077 size_t i;
Andrew Scullbc7189d2018-08-14 09:35:13 +010078 size_t suites_in_image = 0;
79 size_t tests_in_suite = 0;
80
81 HFTEST_LOG("{");
82 HFTEST_LOG(" \"suites\": [");
Andrew Walbranbc342d42019-02-05 16:56:02 +000083 for (i = 0; i < hftest_count; ++i) {
84 struct hftest_test *test = &hftest_list[i];
Andrew Scullbc7189d2018-08-14 09:35:13 +010085 if (test->suite != suite) {
86 /* Close out previously open suite. */
87 if (tests_in_suite) {
88 HFTEST_LOG(" ]");
89 HFTEST_LOG(" },");
90 }
91 /* Move onto new suite. */
92 ++suites_in_image;
93 suite = test->suite;
94 tests_in_suite = 0;
95 HFTEST_LOG(" {");
96 HFTEST_LOG(" \"name\": \"%s\",", test->suite);
97 }
98 if (test->kind == HFTEST_KIND_SET_UP) {
99 HFTEST_LOG(" \"setup\": true,");
100 }
101 if (test->kind == HFTEST_KIND_TEAR_DOWN) {
102 HFTEST_LOG(" \"teardown\": true,");
103 }
104 if (test->kind == HFTEST_KIND_TEST) {
105 if (!tests_in_suite) {
106 HFTEST_LOG(" \"tests\": [");
107 }
Andrew Scullf0551c82018-12-15 20:38:47 +0000108 /*
109 * It's easier to put the comma at the start of the line
Andrew Scull2b5fbad2019-04-05 13:55:56 +0100110 * than the end even though the JSON looks a bit funky.
Andrew Scullf0551c82018-12-15 20:38:47 +0000111 */
Andrew Scullbc7189d2018-08-14 09:35:13 +0100112 HFTEST_LOG(" %c\"%s\"",
113 tests_in_suite ? ',' : ' ', test->name);
114 ++tests_in_suite;
115 }
116 }
117 if (tests_in_suite) {
118 HFTEST_LOG(" ]");
119 HFTEST_LOG(" }");
120 }
121 HFTEST_LOG(" ]");
122 HFTEST_LOG("}");
123}
124
Andrew Walbranbc342d42019-02-05 16:56:02 +0000125/**
126 * Logs a failure message and shut down.
127 */
Andrew Sculla59f9bc2019-04-03 15:24:35 +0100128noreturn void abort(void)
Andrew Scullf0551c82018-12-15 20:38:47 +0000129{
130 HFTEST_LOG("FAIL");
Andrew Walbranc6903d12019-03-05 18:28:20 +0000131 arch_power_off();
Andrew Scullf0551c82018-12-15 20:38:47 +0000132}
133
Andrew Scullbc7189d2018-08-14 09:35:13 +0100134static void run_test(hftest_test_fn set_up, hftest_test_fn test,
Andrew Walbranafabe852019-03-20 17:55:11 +0000135 hftest_test_fn tear_down, const struct fdt_header *fdt)
Andrew Scullbc7189d2018-08-14 09:35:13 +0100136{
Andrew Scullf0551c82018-12-15 20:38:47 +0000137 /* Prepare the context. */
138 struct hftest_context *ctx = hftest_get_context();
Andrew Scull2b5fbad2019-04-05 13:55:56 +0100139 memset_s(ctx, sizeof(*ctx), 0, sizeof(*ctx));
Andrew Scullf0551c82018-12-15 20:38:47 +0000140 ctx->abort = abort;
Andrew Walbranafabe852019-03-20 17:55:11 +0000141 ctx->fdt = fdt;
Andrew Scullbc7189d2018-08-14 09:35:13 +0100142
Andrew Scullf0551c82018-12-15 20:38:47 +0000143 /* Run any set up functions. */
Andrew Scullbc7189d2018-08-14 09:35:13 +0100144 if (set_up) {
Andrew Scullf0551c82018-12-15 20:38:47 +0000145 set_up();
146 if (ctx->failures) {
147 abort();
Andrew Scullbc7189d2018-08-14 09:35:13 +0100148 }
149 }
150
Andrew Scullf0551c82018-12-15 20:38:47 +0000151 /* Run the test. */
152 test();
153 if (ctx->failures) {
154 abort();
Andrew Scullbc7189d2018-08-14 09:35:13 +0100155 }
156
Andrew Scullf0551c82018-12-15 20:38:47 +0000157 /* Run any tear down functions. */
Andrew Scullbc7189d2018-08-14 09:35:13 +0100158 if (tear_down) {
Andrew Scullf0551c82018-12-15 20:38:47 +0000159 tear_down();
160 if (ctx->failures) {
161 abort();
Andrew Scullbc7189d2018-08-14 09:35:13 +0100162 }
163 }
164
Andrew Scullf0551c82018-12-15 20:38:47 +0000165 HFTEST_LOG("FINISHED");
Andrew Scullbc7189d2018-08-14 09:35:13 +0100166}
167
Andrew Walbranbc342d42019-02-05 16:56:02 +0000168/**
169 * Runs the given test case.
170 */
Andrew Walbranafabe852019-03-20 17:55:11 +0000171void hftest_run(struct memiter suite_name, struct memiter test_name,
172 const struct fdt_header *fdt)
Andrew Scullbc7189d2018-08-14 09:35:13 +0100173{
Andrew Walbranbc342d42019-02-05 16:56:02 +0000174 size_t i;
Andrew Scullbc7189d2018-08-14 09:35:13 +0100175 bool found_suite = false;
176 const char *suite = NULL;
177 hftest_test_fn suite_set_up = NULL;
178 hftest_test_fn suite_tear_down = NULL;
179
Andrew Walbranbc342d42019-02-05 16:56:02 +0000180 for (i = 0; i < hftest_count; ++i) {
181 struct hftest_test *test = &hftest_list[i];
Andrew Scullbc7189d2018-08-14 09:35:13 +0100182 /* Find the test suite. */
183 if (found_suite) {
184 if (test->suite != suite) {
185 /* Test wasn't in the suite. */
186 break;
187 }
188 } else {
189 if (test->suite == suite) {
190 /* This isn't the right suite so keep going. */
191 continue;
192 }
193 /* Examine a new suite. */
194 suite = test->suite;
195 if (memiter_iseq(&suite_name, test->suite)) {
196 found_suite = true;
197 }
198 }
199
200 switch (test->kind) {
Andrew Scullf0551c82018-12-15 20:38:47 +0000201 /*
202 * The first entries in the suite are the set up and tear down
203 * functions.
204 */
Andrew Scullbc7189d2018-08-14 09:35:13 +0100205 case HFTEST_KIND_SET_UP:
206 suite_set_up = test->fn;
207 break;
208 case HFTEST_KIND_TEAR_DOWN:
209 suite_tear_down = test->fn;
210 break;
211 /* Find the test. */
212 case HFTEST_KIND_TEST:
213 if (memiter_iseq(&test_name, test->name)) {
214 run_test(suite_set_up, test->fn,
Andrew Walbranafabe852019-03-20 17:55:11 +0000215 suite_tear_down, fdt);
Andrew Scullbc7189d2018-08-14 09:35:13 +0100216 return;
217 }
218 break;
Andrew Scullf0551c82018-12-15 20:38:47 +0000219 default:
220 /* Ignore other kinds. */
221 break;
Andrew Scullbc7189d2018-08-14 09:35:13 +0100222 }
223 }
224
225 HFTEST_LOG("Unable to find requested tests.");
226}
227
Andrew Walbranbc342d42019-02-05 16:56:02 +0000228/**
229 * Writes out usage information.
230 */
231void hftest_help(void)
Andrew Scullbc7189d2018-08-14 09:35:13 +0100232{
233 HFTEST_LOG("usage:");
234 HFTEST_LOG("");
235 HFTEST_LOG(" help");
236 HFTEST_LOG("");
237 HFTEST_LOG(" Show this help.");
238 HFTEST_LOG("");
239 HFTEST_LOG(" json");
240 HFTEST_LOG("");
241 HFTEST_LOG(
242 " Print a directory of test suites and tests in "
243 "JSON "
244 "format.");
245 HFTEST_LOG("");
246 HFTEST_LOG(" run <suite> <test>");
247 HFTEST_LOG("");
248 HFTEST_LOG(" Run the named test from the named test suite.");
249}
Andrew Walbranafabe852019-03-20 17:55:11 +0000250
251static uintptr_t vcpu_index_to_id(size_t index)
252{
253 /* For now we use indices as IDs for vCPUs. */
254 return index;
255}
256
257/**
258 * Get the ID of the CPU with the given index.
259 */
260uintptr_t hftest_get_cpu_id(size_t index)
261{
262 struct boot_params params;
263 struct fdt_node n;
264 const struct fdt_header *fdt = hftest_get_context()->fdt;
265
266 if (fdt == NULL) {
267 /*
268 * We must be in a service VM, so apply the mapping that Hafnium
269 * uses for vCPU IDs.
270 */
271 return vcpu_index_to_id(index);
272 }
273
274 /* Find physical CPU ID from FDT. */
275 if (!fdt_root_node(&n, fdt)) {
276 FAIL("FDT failed validation.");
277 }
278 if (!fdt_find_child(&n, "")) {
279 FAIL("Unable to find FDT root node.");
280 }
281 fdt_find_cpus(&n, params.cpu_ids, &params.cpu_count);
282
283 return params.cpu_ids[index];
284}