blob: 1016a9a7465e3b75c67d71a97e20714958b019ae [file] [log] [blame]
Andrew Scull18834872018-10-12 11:48:09 +01001/*
2 * Copyright 2018 Google LLC
3 *
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 Scullbc7189d2018-08-14 09:35:13 +010017#include "hftest.h"
18
19#include <stdalign.h>
20#include <stdint.h>
21
Andrew Walbran4a53ba62019-03-05 17:26:12 +000022#include "hf/arch/std.h"
Andrew Scullf0551c82018-12-15 20:38:47 +000023#include "hf/arch/vm/power_mgmt.h"
24
Andrew Scullbc7189d2018-08-14 09:35:13 +010025#include "hf/fdt.h"
26#include "hf/memiter.h"
27
28alignas(4096) uint8_t kstack[4096];
29
30HFTEST_ENABLE();
31
32extern struct hftest_test hftest_begin[];
33extern struct hftest_test hftest_end[];
34
Andrew Scullf0551c82018-12-15 20:38:47 +000035static struct hftest_context global_context;
36
37struct hftest_context *hftest_get_context(void)
38{
39 return &global_context;
40}
41
Andrew Scullbc7189d2018-08-14 09:35:13 +010042static void json(void)
43{
44 struct hftest_test *test;
45 const char *suite = NULL;
46 size_t suites_in_image = 0;
47 size_t tests_in_suite = 0;
48
49 HFTEST_LOG("{");
50 HFTEST_LOG(" \"suites\": [");
51 for (test = hftest_begin; test < hftest_end; ++test) {
52 if (test->suite != suite) {
53 /* Close out previously open suite. */
54 if (tests_in_suite) {
55 HFTEST_LOG(" ]");
56 HFTEST_LOG(" },");
57 }
58 /* Move onto new suite. */
59 ++suites_in_image;
60 suite = test->suite;
61 tests_in_suite = 0;
62 HFTEST_LOG(" {");
63 HFTEST_LOG(" \"name\": \"%s\",", test->suite);
64 }
65 if (test->kind == HFTEST_KIND_SET_UP) {
66 HFTEST_LOG(" \"setup\": true,");
67 }
68 if (test->kind == HFTEST_KIND_TEAR_DOWN) {
69 HFTEST_LOG(" \"teardown\": true,");
70 }
71 if (test->kind == HFTEST_KIND_TEST) {
72 if (!tests_in_suite) {
73 HFTEST_LOG(" \"tests\": [");
74 }
Andrew Scullf0551c82018-12-15 20:38:47 +000075 /*
76 * It's easier to put the comma at the start of the line
Andrew Scullbc7189d2018-08-14 09:35:13 +010077 * than the end even
Andrew Scullf0551c82018-12-15 20:38:47 +000078 * though the JSON looks a bit funky.
79 */
Andrew Scullbc7189d2018-08-14 09:35:13 +010080 HFTEST_LOG(" %c\"%s\"",
81 tests_in_suite ? ',' : ' ', test->name);
82 ++tests_in_suite;
83 }
84 }
85 if (tests_in_suite) {
86 HFTEST_LOG(" ]");
87 HFTEST_LOG(" }");
88 }
89 HFTEST_LOG(" ]");
90 HFTEST_LOG("}");
91}
92
Andrew Scullf0551c82018-12-15 20:38:47 +000093static noreturn void abort(void)
94{
95 HFTEST_LOG("FAIL");
96 shutdown();
97}
98
Andrew Scullbc7189d2018-08-14 09:35:13 +010099static void run_test(hftest_test_fn set_up, hftest_test_fn test,
100 hftest_test_fn tear_down)
101{
Andrew Scullf0551c82018-12-15 20:38:47 +0000102 /* Prepare the context. */
103 struct hftest_context *ctx = hftest_get_context();
104 memset(ctx, 0, sizeof(*ctx));
105 ctx->abort = abort;
Andrew Scullbc7189d2018-08-14 09:35:13 +0100106
Andrew Scullf0551c82018-12-15 20:38:47 +0000107 /* Run any set up functions. */
Andrew Scullbc7189d2018-08-14 09:35:13 +0100108 if (set_up) {
Andrew Scullf0551c82018-12-15 20:38:47 +0000109 set_up();
110 if (ctx->failures) {
111 abort();
Andrew Scullbc7189d2018-08-14 09:35:13 +0100112 }
113 }
114
Andrew Scullf0551c82018-12-15 20:38:47 +0000115 /* Run the test. */
116 test();
117 if (ctx->failures) {
118 abort();
Andrew Scullbc7189d2018-08-14 09:35:13 +0100119 }
120
Andrew Scullf0551c82018-12-15 20:38:47 +0000121 /* Run any tear down functions. */
Andrew Scullbc7189d2018-08-14 09:35:13 +0100122 if (tear_down) {
Andrew Scullf0551c82018-12-15 20:38:47 +0000123 tear_down();
124 if (ctx->failures) {
125 abort();
Andrew Scullbc7189d2018-08-14 09:35:13 +0100126 }
127 }
128
Andrew Scullf0551c82018-12-15 20:38:47 +0000129 HFTEST_LOG("FINISHED");
Andrew Scullbc7189d2018-08-14 09:35:13 +0100130}
131
132static void run(struct memiter *args)
133{
134 struct memiter suite_name;
135 struct memiter test_name;
136 struct hftest_test *test;
137 bool found_suite = false;
138 const char *suite = NULL;
139 hftest_test_fn suite_set_up = NULL;
140 hftest_test_fn suite_tear_down = NULL;
141
142 if (!memiter_parse_str(args, &suite_name)) {
143 HFTEST_LOG("Unable to parse test suite.");
144 return;
145 }
146
147 if (!memiter_parse_str(args, &test_name)) {
148 HFTEST_LOG("Unable to parse test.");
149 return;
150 }
151
152 for (test = hftest_begin; test < hftest_end; ++test) {
153 /* Find the test suite. */
154 if (found_suite) {
155 if (test->suite != suite) {
156 /* Test wasn't in the suite. */
157 break;
158 }
159 } else {
160 if (test->suite == suite) {
161 /* This isn't the right suite so keep going. */
162 continue;
163 }
164 /* Examine a new suite. */
165 suite = test->suite;
166 if (memiter_iseq(&suite_name, test->suite)) {
167 found_suite = true;
168 }
169 }
170
171 switch (test->kind) {
Andrew Scullf0551c82018-12-15 20:38:47 +0000172 /*
173 * The first entries in the suite are the set up and tear down
174 * functions.
175 */
Andrew Scullbc7189d2018-08-14 09:35:13 +0100176 case HFTEST_KIND_SET_UP:
177 suite_set_up = test->fn;
178 break;
179 case HFTEST_KIND_TEAR_DOWN:
180 suite_tear_down = test->fn;
181 break;
182 /* Find the test. */
183 case HFTEST_KIND_TEST:
184 if (memiter_iseq(&test_name, test->name)) {
185 run_test(suite_set_up, test->fn,
186 suite_tear_down);
187 return;
188 }
189 break;
Andrew Scullf0551c82018-12-15 20:38:47 +0000190 default:
191 /* Ignore other kinds. */
192 break;
Andrew Scullbc7189d2018-08-14 09:35:13 +0100193 }
194 }
195
196 HFTEST_LOG("Unable to find requested tests.");
197}
198
Andrew Scullf0551c82018-12-15 20:38:47 +0000199static void help(void)
Andrew Scullbc7189d2018-08-14 09:35:13 +0100200{
201 HFTEST_LOG("usage:");
202 HFTEST_LOG("");
203 HFTEST_LOG(" help");
204 HFTEST_LOG("");
205 HFTEST_LOG(" Show this help.");
206 HFTEST_LOG("");
207 HFTEST_LOG(" json");
208 HFTEST_LOG("");
209 HFTEST_LOG(
210 " Print a directory of test suites and tests in "
211 "JSON "
212 "format.");
213 HFTEST_LOG("");
214 HFTEST_LOG(" run <suite> <test>");
215 HFTEST_LOG("");
216 HFTEST_LOG(" Run the named test from the named test suite.");
217}
218
Andrew Scullf0551c82018-12-15 20:38:47 +0000219void kmain(const struct fdt_header *fdt)
Andrew Scullbc7189d2018-08-14 09:35:13 +0100220{
221 struct fdt_node n;
222 const char *bootargs;
223 uint32_t bootargs_size;
224 struct memiter bootargs_iter;
225 struct memiter command;
226
227 if (!fdt_root_node(&n, fdt)) {
228 HFTEST_LOG("FDT failed validation.");
229 return;
230 }
231
232 if (!fdt_find_child(&n, "")) {
233 HFTEST_LOG("Unable to find root node in FDT.");
234 return;
235 }
236
237 if (!fdt_find_child(&n, "chosen")) {
238 HFTEST_LOG("Unable to find 'chosen' node in FDT.");
239 return;
240 }
241
242 if (!fdt_read_property(&n, "bootargs", &bootargs, &bootargs_size)) {
243 HFTEST_LOG("Unable to read bootargs.");
244 return;
245 }
246
247 /* Remove null terminator. */
248 memiter_init(&bootargs_iter, bootargs, bootargs_size - 1);
249
250 if (!memiter_parse_str(&bootargs_iter, &command)) {
251 HFTEST_LOG("Unable to parse command.");
252 return;
253 }
254
255 if (memiter_iseq(&command, "json")) {
256 json();
257 return;
258 }
259
260 if (memiter_iseq(&command, "run")) {
261 run(&bootargs_iter);
262 return;
263 }
264
265 help();
266}