1 /*
2  * Copyright 2018 The Hafnium Authors.
3  *
4  * Use of this source code is governed by a BSD-style
5  * license that can be found in the LICENSE file or at
6  * https://opensource.org/licenses/BSD-3-Clause.
7  */
8 
9 #pragma once
10 
11 #include "hf/fdt.h"
12 #include "hf/ffa.h"
13 #include "hf/ffa_partition_manifest.h"
14 #include "hf/std.h"
15 
16 #include "vmapi/hf/ffa.h"
17 
18 #define HFTEST_MAX_TESTS 50
19 
20 /*
21  * Log with the HFTEST_LOG_PREFIX and a new line. The newline is passed as
22  * an argument so there is always at least one variadic argument.
23  */
24 #define HFTEST_LOG(...) HFTEST_LOG_IMPL(__VA_ARGS__, "\n")
25 #define HFTEST_LOG_IMPL(format, ...) \
26 	dlog(HFTEST_LOG_PREFIX format "%s", __VA_ARGS__)
27 
28 /* Helper to wrap the argument in quotes. */
29 #define HFTEST_STR(str) #str
30 
31 /*
32  * Sections are names such that when the linker sorts them, all entries for the
33  * same test suite are contiguous and the set up and tear down entries come
34  * before the tests. This order simplifies test discovery in the running image.
35  */
36 #define HFTEST_SET_UP_SECTION(suite_name) \
37 	HFTEST_STR(.hftest.suite.suite_name.1set_up)
38 #define HFTEST_TEAR_DOWN_SECTION(suite_name) \
39 	HFTEST_STR(.hftest.suite.suite_name.1tear_down)
40 #define HFTEST_TEST_SECTION(suite_name, test_name) \
41 	HFTEST_STR(.hftest.suite.suite_name.2test.test_name)
42 #define HFTEST_SERVICE_SET_UP_SECTION(service_name) \
43 	HFTEST_STR(.hftest.service_set_up.service_name)
44 #define HFTEST_SERVICE_SECTION(service_name) \
45 	HFTEST_STR(.hftest.service.service_name)
46 
47 /* Helpers to construct unique identifiers. */
48 #define HFTEST_SET_UP_STRUCT(suite_name) hftest_set_up_##suite_name
49 #define HFTEST_TEAR_DOWN_STRUCT(suite_name) hftest_tear_down_##suite_name
50 #define HFTEST_TEST_STRUCT(suite_name, test_name) \
51 	hftest_test_##suite_name##_##test_name
52 #define HFTEST_SERVICE_SET_UP_STRUCT(service_name) \
53 	hftest_service_set_up_##service_name
54 #define HFTEST_SERVICE_STRUCT(service_name) hftest_service_##service_name
55 
56 #define HFTEST_SET_UP_FN(suite_name) hftest_set_up_fn_##suite_name
57 #define HFTEST_TEAR_DOWN_FN(suite_name) hftest_tear_down_fn_##suite_name
58 #define HFTEST_TEST_FN(suite_name, test_name) \
59 	hftest_test_fn_##suite_name##_##test_name
60 #define HFTEST_SERVICE_SET_UP_FN(service_name) \
61 	hftest_service_set_up_fn_##service_name
62 #define HFTEST_SERVICE_FN(service_name) hftest_service_fn_##service_name
63 
64 #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 
70 /* Register test functions. */
71 #define HFTEST_SET_UP(suite_name)                                         \
72 	static void HFTEST_SET_UP_FN(suite_name)(void);                   \
73 	[[gnu::used]] [[gnu::section(HFTEST_SET_UP_SECTION(suite_name))]] \
74 	const struct hftest_test 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 	};                                                                \
79 	static void HFTEST_SET_UP_FN(suite_name)(void)
80 
81 #define HFTEST_TEAR_DOWN(suite_name)                                         \
82 	static void HFTEST_TEAR_DOWN_FN(suite_name)(void);                   \
83 	[[gnu::used]] [[gnu::section(HFTEST_TEAR_DOWN_SECTION(suite_name))]] \
84 	const struct hftest_test HFTEST_TEAR_DOWN_STRUCT(suite_name) = {     \
85 		.suite = #suite_name,                                        \
86 		.kind = HFTEST_KIND_TEAR_DOWN,                               \
87 		.fn = HFTEST_TEAR_DOWN_FN(suite_name),                       \
88 	};                                                                   \
89 	static void HFTEST_TEAR_DOWN_FN(suite_name)(void)
90 
91 #define HFTEST_TEST(suite_name, test_name, long_running, precon_fn)            \
92 	static void HFTEST_TEST_FN(suite_name, test_name)(void);               \
93 	[[gnu::used]] [[gnu::section(                                          \
94 		HFTEST_TEST_SECTION(suite_name, test_name))]]                  \
95 	const struct hftest_test HFTEST_TEST_STRUCT(suite_name, test_name) = { \
96 		.suite = #suite_name,                                          \
97 		.kind = HFTEST_KIND_TEST,                                      \
98 		.name = #test_name,                                            \
99 		.is_long_running = (long_running),                             \
100 		.fn = HFTEST_TEST_FN(suite_name, test_name),                   \
101 		.precondition = (precon_fn),                                   \
102 	};                                                                     \
103 	static void HFTEST_TEST_FN(suite_name, test_name)(void)
104 
105 #define HFTEST_SERVICE_SET_UP(service_name)                       \
106 	static void HFTEST_SERVICE_SET_UP_FN(service_name)(void); \
107 	[[gnu::used]] [[gnu::section(                             \
108 		HFTEST_SERVICE_SET_UP_SECTION(service_name))]]    \
109 	const struct hftest_test HFTEST_SERVICE_SET_UP_STRUCT(    \
110 		service_name) = {                                 \
111 		.name = #service_name,                            \
112 		.kind = HFTEST_KIND_SERVICE_SET_UP,               \
113 		.fn = HFTEST_SERVICE_SET_UP_FN(service_name),     \
114 	};                                                        \
115 	static void HFTEST_SERVICE_SET_UP_FN(service_name)(void)
116 
117 #define HFTEST_TEST_SERVICE(service_name)                                    \
118 	static void HFTEST_SERVICE_FN(service_name)(void);                   \
119 	[[gnu::used]] [[gnu::section(HFTEST_SERVICE_SECTION(service_name))]] \
120 	const struct hftest_test HFTEST_SERVICE_STRUCT(service_name) = {     \
121 		.kind = HFTEST_KIND_SERVICE,                                 \
122 		.name = #service_name,                                       \
123 		.fn = HFTEST_SERVICE_FN(service_name),                       \
124 		.precondition = NULL,                                        \
125 	};                                                                   \
126 	static void HFTEST_SERVICE_FN(service_name)(void)
127 
128 /* Context for tests. */
129 struct hftest_context {
130 	uint32_t failures;
131 	void (*abort)(void);
132 
133 	/* These are used in primary VMs. */
134 	const struct fdt *fdt;
135 	bool is_ffa_manifest_parsed;
136 	struct ffa_partition_manifest partition_manifest;
137 
138 	/* These are used in services. */
139 	void *send;
140 	void *recv;
141 	size_t memory_size;
142 	ffa_id_t dir_req_source_id;
143 };
144 
145 struct hftest_context *hftest_get_context(void);
146 
147 /* A test case. */
148 typedef void (*hftest_test_fn)(void);
149 typedef bool (*hftest_test_precondition)(void);
150 
151 enum hftest_kind {
152 	HFTEST_KIND_SET_UP = 0,
153 	HFTEST_KIND_TEST = 1,
154 	HFTEST_KIND_TEAR_DOWN = 2,
155 	HFTEST_KIND_SERVICE_SET_UP = 3,
156 	HFTEST_KIND_SERVICE = 4,
157 };
158 
159 /**
160  * The .hftest section contains an array of this struct which describes the test
161  * functions contained in the image allowing the image to inspect the tests it
162  * contains.
163  */
164 /* NOLINTNEXTLINE(clang-analyzer-optin.performance.Padding) */
165 struct hftest_test {
166 	const char *suite;
167 	enum hftest_kind kind;
168 	const char *name;
169 	bool is_long_running;
170 	hftest_test_fn fn;
171 	hftest_test_precondition precondition;
172 };
173 
174 /* _Generic formatting doesn't seem to be supported so doing this manually. */
175 /* clang-format off */
176 #define HFTEST_LOG_FAILURE() \
177 	dlog(HFTEST_LOG_PREFIX "Failure: %s:%u\n", __FILE__, __LINE__);
178 
179 #ifdef HFTEST_OPTIMIZE_FOR_SIZE
180 #define HFTEST_LOG_ASSERT_DETAILS(lhs, rhs, op)
181 #else /* HFTEST_OPTIMIZE_FOR_SIZE */
182 #define HFTEST_LOG_ASSERT_DETAILS(lhs, rhs, op)                                    \
183 	do {                                                                           \
184 		dlog(HFTEST_LOG_PREFIX "assertion failed: `%s %s %s`\n", #lhs, #op, #rhs); \
185 		dlog(_Generic(lhs_value,                                                   \
186 			bool:               HFTEST_LOG_PREFIX "lhs = %hhu (%#02hhx)",          \
187 			char:               HFTEST_LOG_PREFIX "lhs = '%c' (%#02hhx)",          \
188 			signed char:        HFTEST_LOG_PREFIX "lhs = %hhd (%#02hhx)",          \
189 			unsigned char:      HFTEST_LOG_PREFIX "lhs = %hhu (%#02hhx)",          \
190 			signed short:       HFTEST_LOG_PREFIX "lhs = %hd (%#04hx)",            \
191 			unsigned short:     HFTEST_LOG_PREFIX "lhs = %hu (%#04hx)",            \
192 			signed int:         HFTEST_LOG_PREFIX "lhs = %d (%#08x)",              \
193 			unsigned int:       HFTEST_LOG_PREFIX "lhs = %u (%#08x)",              \
194 			signed long:        HFTEST_LOG_PREFIX "lhs = %ld (%#016lx)",            \
195 			unsigned long:      HFTEST_LOG_PREFIX "lhs = %lu (%#016lx)",            \
196 			signed long long:   HFTEST_LOG_PREFIX "lhs = %lld (%#016llx)",         \
197 			unsigned long long: HFTEST_LOG_PREFIX "lhs = %llu (%#016llx)"          \
198 		), lhs_value, lhs_value);                                                  \
199 		dlog(_Generic(rhs_value,                                                   \
200 			bool:               HFTEST_LOG_PREFIX "rhs = %hhu (%#02hhx)",          \
201 			char:               HFTEST_LOG_PREFIX "rhs = '%c' (%#02hhx)",          \
202 			signed char:        HFTEST_LOG_PREFIX "rhs = %hhd (%#02hhx)",          \
203 			unsigned char:      HFTEST_LOG_PREFIX "rhs = %hhu (%#02hhx)",          \
204 			signed short:       HFTEST_LOG_PREFIX "rhs = %hd (%#04hx)",            \
205 			unsigned short:     HFTEST_LOG_PREFIX "rhs = %hu (%#04hx)",            \
206 			signed int:         HFTEST_LOG_PREFIX "rhs = %d (%#08x)",              \
207 			unsigned int:       HFTEST_LOG_PREFIX "rhs = %u (%#08x)",              \
208 			signed long:        HFTEST_LOG_PREFIX "rhs = %ld (%#016lx)",            \
209 			unsigned long:      HFTEST_LOG_PREFIX "rhs = %lu (%#016lx)",            \
210 			signed long long:   HFTEST_LOG_PREFIX "rhs = %lld (%#016llx)",         \
211 			unsigned long long: HFTEST_LOG_PREFIX "rhs = %llu (%#016llx)"          \
212 		), rhs_value, rhs_value);                                                  \
213 	} while (0)
214 #endif /* HFTEST_OPTIMIZE_FOR_SIZE */
215 /* clang-format on */
216 
217 #ifdef HFTEST_OPTIMIZE_FOR_SIZE
218 #define HFTEST_LOG_ASSERT_STRING_DETAILS(lhs, rhs, op)
219 #else /* HFTEST_OPTIMIZE_FOR_SIZE */
220 #define HFTEST_LOG_ASSERT_STRING_DETAILS(lhs, rhs, op)                         \
221 	do {                                                                   \
222 		dlog(HFTEST_LOG_PREFIX "assertion failed: `%s %s %s`\n", #lhs, \
223 		     #op, #rhs);                                               \
224 		dlog(HFTEST_LOG_PREFIX "lhs = \"%s\"\n", lhs_value);           \
225 		dlog(HFTEST_LOG_PREFIX "rhs = \"%s\"\n", rhs_value);           \
226 		dlog("\n");                                                    \
227 	} while (0)
228 
229 #endif /* HFTEST_OPTIMIZE_FOR_SIZE */
230 
231 #define HFTEST_ASSERT_OP(lhs, rhs, op, fatal)                              \
232 	do {                                                               \
233 		typeof(lhs) lhs_value = lhs;                               \
234 		typeof(rhs) rhs_value = rhs;                               \
235 		if (!(lhs_value op rhs_value)) {                           \
236 			struct hftest_context *ctx = hftest_get_context(); \
237 			++ctx->failures;                                   \
238 			HFTEST_LOG_FAILURE();                              \
239 			HFTEST_LOG_ASSERT_DETAILS(lhs, rhs, op);           \
240 			if (fatal) {                                       \
241 				ctx->abort();                              \
242 			}                                                  \
243 		}                                                          \
244 	} while (0)
245 
246 #define HFTEST_ASSERT_STRING_OP(lhs, rhs, op, fatal)                       \
247 	do {                                                               \
248 		char *lhs_value = (lhs);                                   \
249 		char *rhs_value = (rhs);                                   \
250 		/* NOLINTNEXTLINE(bugprone-macro-parentheses) */           \
251 		if (!(strncmp(lhs_value, rhs_value, RSIZE_MAX) op 0)) {    \
252 			struct hftest_context *ctx = hftest_get_context(); \
253 			++ctx->failures;                                   \
254 			HFTEST_LOG_FAILURE();                              \
255 			HFTEST_LOG_ASSERT_STRING_DETAILS(lhs, rhs, op);    \
256 			if (fatal) {                                       \
257 				ctx->abort();                              \
258 			}                                                  \
259 		}                                                          \
260 	} while (0)
261 
262 #define HFTEST_FAIL(fatal, ...)                                        \
263 	do {                                                           \
264 		struct hftest_context *ctx = hftest_get_context();     \
265 		++ctx->failures;                                       \
266 		HFTEST_LOG_FAILURE();                                  \
267 		dlog(HFTEST_LOG_PREFIX HFTEST_LOG_INDENT __VA_ARGS__); \
268 		dlog("\n");                                            \
269 		if (fatal) {                                           \
270 			ctx->abort();                                  \
271 		}                                                      \
272 	} while (0)
273 
274 /**
275  * Select the service to run in a service VM.
276  */
277 #define HFTEST_SERVICE_SELECT(vm_id, service, send_buffer, vcpu_id)           \
278 	do {                                                                  \
279 		struct ffa_value res;                                         \
280 		uint32_t msg_length =                                         \
281 			strnlen_s(service, SERVICE_NAME_MAX_LENGTH);          \
282 		struct ffa_partition_msg *message =                           \
283 			(struct ffa_partition_msg *)(send_buffer);            \
284                                                                               \
285 		/*                                                            \
286 		 * If service is a Secondary VM, let the service configure    \
287 		 * its mailbox and wait for a message.                        \
288 		 */                                                           \
289 		if (ffa_is_vm_id(vm_id)) {                                    \
290 			res = ffa_run(vm_id, vcpu_id);                        \
291 			ASSERT_EQ(res.func, FFA_MSG_WAIT_32);                 \
292 			ASSERT_EQ(res.arg2, FFA_SLEEP_INDEFINITE);            \
293 		}                                                             \
294                                                                               \
295 		/*                                                            \
296 		 * Send the selected service to run and let it be             \
297 		 * handled.                                                   \
298 		 */                                                           \
299 		ffa_rxtx_header_init(&message->header, hf_vm_get_id(), vm_id, \
300 				     msg_length);                             \
301 		memcpy_s(message->payload, FFA_PARTITION_MSG_PAYLOAD_MAX,     \
302 			 service, msg_length);                                \
303 		res = ffa_msg_send2(0);                                       \
304                                                                               \
305 		ASSERT_EQ(res.func, FFA_SUCCESS_32);                          \
306 		res = ffa_run(vm_id, vcpu_id);                                \
307 		ASSERT_EQ(res.func, FFA_YIELD_32);                            \
308 	} while (0)
309 
310 #define HFTEST_SERVICE_SEND_BUFFER() hftest_get_context()->send
311 #define HFTEST_SERVICE_RECV_BUFFER() hftest_get_context()->recv
312 #define HFTEST_SERVICE_MEMORY_SIZE() hftest_get_context()->memory_size
313