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