blob: c4df298c0bed7b1ca7d8a1cf8f515b4ea3ad36d2 [file] [log] [blame]
Andrew Scullf0551c82018-12-15 20:38:47 +00001/*
Andrew Walbran692b3252019-03-07 15:51:31 +00002 * Copyright 2018 The Hafnium Authors.
Andrew Scullf0551c82018-12-15 20:38:47 +00003 *
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
17#pragma once
18
19#include <stdnoreturn.h>
20
Andrew Walbran4a53ba62019-03-05 17:26:12 +000021#include "hf/arch/std.h"
Andrew Scull9726c252019-01-23 13:44:19 +000022
Andrew Walbranbc342d42019-02-05 16:56:02 +000023#define HFTEST_MAX_TESTS 50
24
Andrew Scullf0551c82018-12-15 20:38:47 +000025/*
26 * Log with the HFTEST_LOG_PREFIX and a new line. The zero is added so there is
27 * always at least one variadic argument.
28 */
29#define HFTEST_LOG(...) HFTEST_LOG_IMPL(__VA_ARGS__, 0)
30#define HFTEST_LOG_IMPL(format, ...) \
31 dlog("%s" format "\n", HFTEST_LOG_PREFIX, __VA_ARGS__)
32
33/* Helper to wrap the argument in quotes. */
34#define HFTEST_STR(str) #str
35
36/*
37 * Sections are names such that when the linker sorts them, all entries for the
38 * same test suite are contiguous and the set up and tear down entries come
39 * before the tests. This order simplifies test discovery in the running image.
40 */
41#define HFTEST_SET_UP_SECTION(suite_name) \
42 HFTEST_STR(.hftest.suite.suite_name .1set_up)
43#define HFTEST_TEAR_DOWN_SECTION(suite_name) \
44 HFTEST_STR(.hftest.suite.suite_name .1tear_down)
45#define HFTEST_TEST_SECTION(suite_name, test_name) \
46 HFTEST_STR(.hftest.suite.suite_name .2test.test_name)
47#define HFTEST_SERVICE_SECTION(service_name) \
48 HFTEST_STR(.hftest.service.service_name)
49
50/* Helpers to construct unique identifiers. */
51#define HFTEST_SET_UP_STRUCT(suite_name) hftest_set_up_##suite_name
52#define HFTEST_TEAR_DOWN_STRUCT(suite_name) hftest_tear_down_##suite_name
53#define HFTEST_TEST_STRUCT(suite_name, test_name) \
54 hftest_test_##suite_name##_##test_name
55#define HFTEST_SERVICE_STRUCT(service_name) hftest_service_##service_name
56
57#define HFTEST_SET_UP_FN(suite_name) hftest_set_up_fn_##suite_name
58#define HFTEST_TEAR_DOWN_FN(suite_name) hftest_tear_down_fn_##suite_name
59#define HFTEST_TEST_FN(suite_name, test_name) \
60 hftest_test_fn_##suite_name##_##test_name
61#define HFTEST_SERVICE_FN(service_name) hftest_service_fn_##service_name
62
Andrew Walbranbc342d42019-02-05 16:56:02 +000063#define HFTEST_SET_UP_CONSTRUCTOR(suite_name) hftest_set_up_ctor_##suite_name
64#define HFTEST_TEAR_DOWN_CONSTRUCTOR(suite_name) \
65 hftest_tear_down_ctor_##suite_name
66#define HFTEST_TEST_CONSTRUCTOR(suite_name, test_name) \
67 hftest_test_ctor_##suite_name##_##test_name
68
Andrew Scullf0551c82018-12-15 20:38:47 +000069/* Register test functions. */
70#define HFTEST_SET_UP(suite_name) \
71 static void HFTEST_SET_UP_FN(suite_name)(void); \
72 const struct hftest_test __attribute__((used)) \
73 __attribute__((section(HFTEST_SET_UP_SECTION(suite_name)))) \
74 HFTEST_SET_UP_STRUCT(suite_name) = { \
75 .suite = #suite_name, \
76 .kind = HFTEST_KIND_SET_UP, \
77 .fn = HFTEST_SET_UP_FN(suite_name), \
78 }; \
Andrew Walbranbc342d42019-02-05 16:56:02 +000079 static void __attribute__((constructor)) \
80 HFTEST_SET_UP_CONSTRUCTOR(suite_name)(void) \
81 { \
82 hftest_register(HFTEST_SET_UP_STRUCT(suite_name)); \
83 } \
Andrew Scullf0551c82018-12-15 20:38:47 +000084 static void HFTEST_SET_UP_FN(suite_name)(void)
85
86#define HFTEST_TEAR_DOWN(suite_name) \
87 static void HFTEST_TEAR_DOWN_FN(suite_name)(void); \
88 const struct hftest_test __attribute__((used)) \
89 __attribute__((section(HFTEST_TEAR_DOWN_SECTION(suite_name)))) \
90 HFTEST_TEAR_DOWN_STRUCT(suite_name) = { \
91 .suite = #suite_name, \
92 .kind = HFTEST_KIND_TEAR_DOWN, \
93 .fn = HFTEST_TEAR_DOWN_FN(suite_name), \
94 }; \
Andrew Walbranbc342d42019-02-05 16:56:02 +000095 static void __attribute__((constructor)) \
96 HFTEST_TEAR_DOWN_CONSTRUCTOR(suite_name)(void) \
97 { \
98 hftest_register(HFTEST_TEAR_DOWN_STRUCT(suite_name)); \
99 } \
Andrew Scullf0551c82018-12-15 20:38:47 +0000100 static void HFTEST_TEAR_DOWN_FN(suite_name)(void)
101
Andrew Walbranbc342d42019-02-05 16:56:02 +0000102#define HFTEST_TEST(suite_name, test_name) \
103 static void HFTEST_TEST_FN(suite_name, test_name)(void); \
104 const struct hftest_test __attribute__((used)) __attribute__( \
105 (section(HFTEST_TEST_SECTION(suite_name, test_name)))) \
106 HFTEST_TEST_STRUCT(suite_name, test_name) = { \
107 .suite = #suite_name, \
108 .kind = HFTEST_KIND_TEST, \
109 .name = #test_name, \
110 .fn = HFTEST_TEST_FN(suite_name, test_name), \
111 }; \
112 static void __attribute__((constructor)) \
113 HFTEST_TEST_CONSTRUCTOR(suite_name, test_name)(void) \
114 { \
115 hftest_register(HFTEST_TEST_STRUCT(suite_name, test_name)); \
116 } \
Andrew Scullf0551c82018-12-15 20:38:47 +0000117 static void HFTEST_TEST_FN(suite_name, test_name)(void)
118
119#define HFTEST_TEST_SERVICE(service_name) \
120 static void HFTEST_SERVICE_FN(service_name)(void); \
121 const struct hftest_test __attribute__((used)) \
122 __attribute__((section(HFTEST_SERVICE_SECTION(service_name)))) \
123 HFTEST_SERVICE_STRUCT(service_name) = { \
124 .kind = HFTEST_KIND_SERVICE, \
125 .name = #service_name, \
126 .fn = HFTEST_SERVICE_FN(service_name), \
127 }; \
128 static void HFTEST_SERVICE_FN(service_name)(void)
129
130/* Context for tests. */
131struct hftest_context {
132 uint32_t failures;
133 noreturn void (*abort)(void);
134
135 /* These are used in services. */
136 void *send;
137 void *recv;
138};
139
140struct hftest_context *hftest_get_context(void);
141
142/* A test case. */
143typedef void (*hftest_test_fn)(void);
144
145enum hftest_kind {
146 HFTEST_KIND_SET_UP = 0,
147 HFTEST_KIND_TEST = 1,
148 HFTEST_KIND_TEAR_DOWN = 2,
149 HFTEST_KIND_SERVICE = 3,
150};
151
152/**
153 * The .hftest section contains an array of this struct which describes the test
154 * functions contained in the image allowing the image to inspect the tests it
155 * contains.
156 */
157struct hftest_test {
158 const char *suite;
159 enum hftest_kind kind;
160 const char *name;
161 hftest_test_fn fn;
162};
163
164/*
165 * This union can store any of the primitive types supported by the assertion
166 * macros.
167 *
168 * It does not include pointers as comparison of pointers is not often needed
169 * and could be a mistake for string comparison. If pointer comparison is needed
170 * and explicit assertion such as ASSERT_PTR_EQ() would be more appropriate.
171 */
172union hftest_any {
173 bool b;
174 char c;
175 signed char sc;
176 unsigned char uc;
177 signed short ss;
178 unsigned short us;
179 signed int si;
180 unsigned int ui;
181 signed long int sli;
182 unsigned long int uli;
183 signed long long int slli;
184 unsigned long long int ulli;
185};
186
187/* _Generic formatting doesn't seem to be supported so doing this manually. */
188/* clang-format off */
189
190/* Select the union member to match the type of the expression. */
191#define hftest_any_get(any, x) \
192 _Generic((x), \
193 bool: (any).b, \
194 char: (any).c, \
195 signed char: (any).sc, \
196 unsigned char: (any).uc, \
197 signed short: (any).ss, \
198 unsigned short: (any).us, \
199 signed int: (any).si, \
200 unsigned int: (any).ui, \
201 signed long int: (any).sli, \
202 unsigned long int: (any).uli, \
203 signed long long int: (any).slli, \
204 unsigned long long int: (any).ulli)
205
206/*
207 * dlog format specifier for types. Note, these aren't the standard specifiers
208 * for the types.
209 */
210#define hftest_dlog_format(x) \
211 _Generic((x), \
212 bool: "%u", \
213 char: "%c", \
214 signed char: "%d", \
215 unsigned char: "%u", \
216 signed short: "%d", \
217 unsigned short: "%u", \
218 signed int: "%d", \
219 unsigned int: "%u", \
220 signed long int: "%d", \
221 unsigned long int: "%u", \
222 signed long long int: "%d", \
223 unsigned long long int: "%u")
224
225/* clang-format on */
226
227#define HFTEST_LOG_FAILURE() \
228 dlog(HFTEST_LOG_PREFIX "Failure: %s:%u\n", __FILE__, __LINE__);
229
230#define HFTEST_ASSERT_OP(lhs, rhs, op, fatal) \
231 do { \
232 union hftest_any lhs_value; \
233 union hftest_any rhs_value; \
234 hftest_any_get(lhs_value, lhs) = (lhs); \
235 hftest_any_get(rhs_value, rhs) = (rhs); \
236 if (!(hftest_any_get(lhs_value, lhs) \
237 op hftest_any_get(rhs_value, rhs))) { \
238 struct hftest_context *ctx = hftest_get_context(); \
239 ++ctx->failures; \
240 HFTEST_LOG_FAILURE(); \
241 dlog(HFTEST_LOG_PREFIX HFTEST_LOG_INDENT \
242 "%s %s %s (%s=", \
243 #lhs, #op, #rhs, #lhs); \
244 dlog(hftest_dlog_format(lhs), \
245 hftest_any_get(lhs_value, lhs)); \
246 dlog(", %s=", #rhs); \
247 dlog(hftest_dlog_format(rhs), \
248 hftest_any_get(rhs_value, rhs)); \
249 dlog(")\n"); \
250 if (fatal) { \
251 ctx->abort(); \
252 } \
253 } \
254 } while (0)
255
Andrew Walbranb90daf12018-12-11 14:25:54 +0000256#define HFTEST_FAIL(message, fatal) \
257 do { \
258 struct hftest_context *ctx = hftest_get_context(); \
259 ++ctx->failures; \
260 HFTEST_LOG_FAILURE(); \
261 dlog(HFTEST_LOG_PREFIX HFTEST_LOG_INDENT "%s\n", message); \
262 if (fatal) { \
263 ctx->abort(); \
264 } \
265 } while (0)
266
Andrew Scullf0551c82018-12-15 20:38:47 +0000267/**
268 * Select the service to run in a service VM.
269 */
270#define HFTEST_SERVICE_SELECT(vm_id, service, send_buffer) \
271 do { \
272 struct hf_vcpu_run_return run_res; \
273 \
274 /* \
275 * Let the service configure its mailbox and wait for a \
276 * message. \
277 */ \
278 run_res = hf_vcpu_run(vm_id, 0); \
279 ASSERT_EQ(run_res.code, HF_VCPU_RUN_WAIT_FOR_INTERRUPT); \
280 \
281 /* Send the selected service to run and let it be handled. */ \
282 memcpy(send_buffer, service, strlen(service)); \
Wedson Almeida Filho17c997f2019-01-09 18:50:09 +0000283 ASSERT_EQ(hf_mailbox_send(vm_id, strlen(service), false), 0); \
Andrew Scullf0551c82018-12-15 20:38:47 +0000284 run_res = hf_vcpu_run(vm_id, 0); \
285 ASSERT_EQ(run_res.code, HF_VCPU_RUN_YIELD); \
286 } while (0)
287
288#define HFTEST_SERVICE_SEND_BUFFER() hftest_get_context()->send
289#define HFTEST_SERVICE_RECV_BUFFER() hftest_get_context()->recv
Andrew Walbranbc342d42019-02-05 16:56:02 +0000290
291void hftest_register(struct hftest_test test);