Andrew Scull | f0551c8 | 2018-12-15 20:38:47 +0000 | [diff] [blame] | 1 | /* |
Andrew Walbran | 692b325 | 2019-03-07 15:51:31 +0000 | [diff] [blame^] | 2 | * Copyright 2018 The Hafnium Authors. |
Andrew Scull | f0551c8 | 2018-12-15 20:38:47 +0000 | [diff] [blame] | 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 Walbran | 4a53ba6 | 2019-03-05 17:26:12 +0000 | [diff] [blame] | 21 | #include "hf/arch/std.h" |
Andrew Scull | 9726c25 | 2019-01-23 13:44:19 +0000 | [diff] [blame] | 22 | |
Andrew Scull | f0551c8 | 2018-12-15 20:38:47 +0000 | [diff] [blame] | 23 | /* |
| 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. */ |
| 108 | struct 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 | |
| 117 | struct hftest_context *hftest_get_context(void); |
| 118 | |
| 119 | /* A test case. */ |
| 120 | typedef void (*hftest_test_fn)(void); |
| 121 | |
| 122 | enum 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 | */ |
| 134 | struct 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 | */ |
| 149 | union 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 Walbran | b90daf1 | 2018-12-11 14:25:54 +0000 | [diff] [blame] | 233 | #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 Scull | f0551c8 | 2018-12-15 20:38:47 +0000 | [diff] [blame] | 244 | /** |
| 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 Filho | 17c997f | 2019-01-09 18:50:09 +0000 | [diff] [blame] | 260 | ASSERT_EQ(hf_mailbox_send(vm_id, strlen(service), false), 0); \ |
Andrew Scull | f0551c8 | 2018-12-15 20:38:47 +0000 | [diff] [blame] | 261 | 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 |