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