1 /* 2 * QTest testcase for TPM TIS 3 * 4 * Copyright (c) 2018 Red Hat, Inc. 5 * Copyright (c) 2018 IBM Corporation 6 * 7 * Authors: 8 * Marc-André Lureau <marcandre.lureau@redhat.com> 9 * Stefan Berger <stefanb@linux.vnet.ibm.com> 10 * 11 * This work is licensed under the terms of the GNU GPL, version 2 or later. 12 * See the COPYING file in the top-level directory. 13 */ 14 15 #include "qemu/osdep.h" 16 #include <glib/gstdio.h> 17 18 #include "hw/acpi/tpm.h" 19 #include "io/channel-socket.h" 20 #include "libqtest.h" 21 #include "tpm-emu.h" 22 23 #define TIS_REG(LOCTY, REG) \ 24 (TPM_TIS_ADDR_BASE + ((LOCTY) << 12) + REG) 25 26 #define DEBUG_TIS_TEST 0 27 28 #define DPRINTF(fmt, ...) do { \ 29 if (DEBUG_TIS_TEST) { \ 30 printf(fmt, ## __VA_ARGS__); \ 31 } \ 32 } while (0) 33 34 #define DPRINTF_ACCESS \ 35 DPRINTF("%s: %d: locty=%d l=%d access=0x%02x pending_request_flag=0x%x\n", \ 36 __func__, __LINE__, locty, l, access, pending_request_flag) 37 38 #define DPRINTF_STS \ 39 DPRINTF("%s: %d: sts = 0x%08x\n", __func__, __LINE__, sts) 40 41 static const uint8_t TPM_CMD[12] = 42 "\x80\x01\x00\x00\x00\x0c\x00\x00\x01\x44\x00\x00"; 43 44 static void tpm_tis_test_check_localities(const void *data) 45 { 46 uint8_t locty; 47 uint8_t access; 48 uint32_t ifaceid; 49 uint32_t capability; 50 uint32_t didvid; 51 uint32_t rid; 52 53 for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES; locty++) { 54 access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); 55 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 56 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 57 58 capability = readl(TIS_REG(locty, TPM_TIS_REG_INTF_CAPABILITY)); 59 g_assert_cmpint(capability, ==, TPM_TIS_CAPABILITIES_SUPPORTED2_0); 60 61 ifaceid = readl(TIS_REG(locty, TPM_TIS_REG_INTERFACE_ID)); 62 g_assert_cmpint(ifaceid, ==, TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0); 63 64 didvid = readl(TIS_REG(locty, TPM_TIS_REG_DID_VID)); 65 g_assert_cmpint(didvid, !=, 0); 66 g_assert_cmpint(didvid, !=, 0xffffffff); 67 68 rid = readl(TIS_REG(locty, TPM_TIS_REG_RID)); 69 g_assert_cmpint(rid, !=, 0); 70 g_assert_cmpint(rid, !=, 0xffffffff); 71 } 72 } 73 74 static void tpm_tis_test_check_access_reg(const void *data) 75 { 76 uint8_t locty; 77 uint8_t access; 78 79 /* do not test locality 4 (hw only) */ 80 for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) { 81 access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); 82 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 83 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 84 85 /* request use of locality */ 86 writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); 87 88 access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); 89 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 90 TPM_TIS_ACCESS_ACTIVE_LOCALITY | 91 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 92 93 /* release access */ 94 writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), 95 TPM_TIS_ACCESS_ACTIVE_LOCALITY); 96 access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); 97 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 98 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 99 } 100 } 101 102 /* 103 * Test case for seizing access by a higher number locality 104 */ 105 static void tpm_tis_test_check_access_reg_seize(const void *data) 106 { 107 int locty, l; 108 uint8_t access; 109 uint8_t pending_request_flag; 110 111 /* do not test locality 4 (hw only) */ 112 for (locty = 0; locty < TPM_TIS_NUM_LOCALITIES - 1; locty++) { 113 pending_request_flag = 0; 114 115 access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); 116 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 117 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 118 119 /* request use of locality */ 120 writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); 121 access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); 122 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 123 TPM_TIS_ACCESS_ACTIVE_LOCALITY | 124 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 125 126 /* lower localities cannot seize access */ 127 for (l = 0; l < locty; l++) { 128 /* lower locality is not active */ 129 access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); 130 DPRINTF_ACCESS; 131 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 132 pending_request_flag | 133 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 134 135 /* try to request use from 'l' */ 136 writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); 137 138 /* requesting use from 'l' was not possible; 139 we must see REQUEST_USE and possibly PENDING_REQUEST */ 140 access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); 141 DPRINTF_ACCESS; 142 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 143 TPM_TIS_ACCESS_REQUEST_USE | 144 pending_request_flag | 145 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 146 147 /* locality 'locty' must be unchanged; 148 we must see PENDING_REQUEST */ 149 access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); 150 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 151 TPM_TIS_ACCESS_ACTIVE_LOCALITY | 152 TPM_TIS_ACCESS_PENDING_REQUEST | 153 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 154 155 /* try to seize from 'l' */ 156 writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE); 157 /* seize from 'l' was not possible */ 158 access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); 159 DPRINTF_ACCESS; 160 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 161 TPM_TIS_ACCESS_REQUEST_USE | 162 pending_request_flag | 163 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 164 165 /* locality 'locty' must be unchanged */ 166 access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); 167 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 168 TPM_TIS_ACCESS_ACTIVE_LOCALITY | 169 TPM_TIS_ACCESS_PENDING_REQUEST | 170 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 171 172 /* on the next loop we will have a PENDING_REQUEST flag 173 set for locality 'l' */ 174 pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST; 175 } 176 177 /* higher localities can 'seize' access but not 'request use'; 178 note: this will activate first l+1, then l+2 etc. */ 179 for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { 180 /* try to 'request use' from 'l' */ 181 writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); 182 183 /* requesting use from 'l' was not possible; we should see 184 REQUEST_USE and may see PENDING_REQUEST */ 185 access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); 186 DPRINTF_ACCESS; 187 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 188 TPM_TIS_ACCESS_REQUEST_USE | 189 pending_request_flag | 190 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 191 192 /* locality 'l-1' must be unchanged; we should always 193 see PENDING_REQUEST from 'l' requesting access */ 194 access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); 195 DPRINTF_ACCESS; 196 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 197 TPM_TIS_ACCESS_ACTIVE_LOCALITY | 198 TPM_TIS_ACCESS_PENDING_REQUEST | 199 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 200 201 /* try to seize from 'l' */ 202 writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_SEIZE); 203 204 /* seize from 'l' was possible */ 205 access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); 206 DPRINTF_ACCESS; 207 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 208 TPM_TIS_ACCESS_ACTIVE_LOCALITY | 209 pending_request_flag | 210 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 211 212 /* l - 1 should show that it has BEEN_SEIZED */ 213 access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); 214 DPRINTF_ACCESS; 215 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 216 TPM_TIS_ACCESS_BEEN_SEIZED | 217 pending_request_flag | 218 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 219 220 /* clear the BEEN_SEIZED flag and make sure it's gone */ 221 writeb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS), 222 TPM_TIS_ACCESS_BEEN_SEIZED); 223 224 access = readb(TIS_REG(l - 1, TPM_TIS_REG_ACCESS)); 225 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 226 pending_request_flag | 227 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 228 } 229 230 /* PENDING_REQUEST will not be set if locty = 0 since all localities 231 were active; in case of locty = 1, locality 0 will be active 232 but no PENDING_REQUEST anywhere */ 233 if (locty <= 1) { 234 pending_request_flag = 0; 235 } 236 237 /* release access from l - 1; this activates locty - 1 */ 238 l--; 239 240 access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); 241 DPRINTF_ACCESS; 242 243 DPRINTF("%s: %d: relinquishing control on l = %d\n", 244 __func__, __LINE__, l); 245 writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), 246 TPM_TIS_ACCESS_ACTIVE_LOCALITY); 247 248 access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); 249 DPRINTF_ACCESS; 250 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 251 pending_request_flag | 252 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 253 254 for (l = locty - 1; l >= 0; l--) { 255 access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); 256 DPRINTF_ACCESS; 257 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 258 TPM_TIS_ACCESS_ACTIVE_LOCALITY | 259 pending_request_flag | 260 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 261 262 /* release this locality */ 263 writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), 264 TPM_TIS_ACCESS_ACTIVE_LOCALITY); 265 266 if (l == 1) { 267 pending_request_flag = 0; 268 } 269 } 270 271 /* no locality may be active now */ 272 for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { 273 access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); 274 DPRINTF_ACCESS; 275 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 276 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 277 } 278 } 279 } 280 281 /* 282 * Test case for getting access when higher number locality relinquishes access 283 */ 284 static void tpm_tis_test_check_access_reg_release(const void *data) 285 { 286 int locty, l; 287 uint8_t access; 288 uint8_t pending_request_flag; 289 290 /* do not test locality 4 (hw only) */ 291 for (locty = TPM_TIS_NUM_LOCALITIES - 2; locty >= 0; locty--) { 292 pending_request_flag = 0; 293 294 access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); 295 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 296 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 297 298 /* request use of locality */ 299 writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); 300 access = readb(TIS_REG(locty, TPM_TIS_REG_ACCESS)); 301 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 302 TPM_TIS_ACCESS_ACTIVE_LOCALITY | 303 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 304 305 /* request use of all other localities */ 306 for (l = 0; l < TPM_TIS_NUM_LOCALITIES - 1; l++) { 307 if (l == locty) { 308 continue; 309 } 310 /* request use of locality 'l' -- we MUST see REQUEST USE and 311 may see PENDING_REQUEST */ 312 writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); 313 access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); 314 DPRINTF_ACCESS; 315 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 316 TPM_TIS_ACCESS_REQUEST_USE | 317 pending_request_flag | 318 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 319 pending_request_flag = TPM_TIS_ACCESS_PENDING_REQUEST; 320 } 321 /* release locality 'locty' */ 322 writeb(TIS_REG(locty, TPM_TIS_REG_ACCESS), 323 TPM_TIS_ACCESS_ACTIVE_LOCALITY); 324 /* highest locality should now be active; release it and make sure the 325 next higest locality is active afterwards */ 326 for (l = TPM_TIS_NUM_LOCALITIES - 2; l >= 0; l--) { 327 if (l == locty) { 328 continue; 329 } 330 /* 'l' should be active now */ 331 access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); 332 DPRINTF_ACCESS; 333 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 334 TPM_TIS_ACCESS_ACTIVE_LOCALITY | 335 pending_request_flag | 336 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 337 /* 'l' relinquishes access */ 338 writeb(TIS_REG(l, TPM_TIS_REG_ACCESS), 339 TPM_TIS_ACCESS_ACTIVE_LOCALITY); 340 access = readb(TIS_REG(l, TPM_TIS_REG_ACCESS)); 341 DPRINTF_ACCESS; 342 if (l == 1 || (locty <= 1 && l == 2)) { 343 pending_request_flag = 0; 344 } 345 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 346 pending_request_flag | 347 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 348 } 349 } 350 } 351 352 /* 353 * Test case for transmitting packets 354 */ 355 static void tpm_tis_test_check_transmit(const void *data) 356 { 357 const TestState *s = data; 358 uint8_t access; 359 uint32_t sts; 360 uint16_t bcount; 361 size_t i; 362 363 /* request use of locality 0 */ 364 writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_REQUEST_USE); 365 access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); 366 g_assert_cmpint(access, ==, TPM_TIS_ACCESS_TPM_REG_VALID_STS | 367 TPM_TIS_ACCESS_ACTIVE_LOCALITY | 368 TPM_TIS_ACCESS_TPM_ESTABLISHMENT); 369 370 sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); 371 DPRINTF_STS; 372 373 g_assert_cmpint(sts & 0xff, ==, 0); 374 g_assert_cmpint(sts & TPM_TIS_STS_TPM_FAMILY_MASK, ==, 375 TPM_TIS_STS_TPM_FAMILY2_0); 376 377 bcount = (sts >> 8) & 0xffff; 378 g_assert_cmpint(bcount, >=, 128); 379 380 writel(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_COMMAND_READY); 381 sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); 382 DPRINTF_STS; 383 g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_COMMAND_READY); 384 385 /* transmit command */ 386 for (i = 0; i < sizeof(TPM_CMD); i++) { 387 writeb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO), TPM_CMD[i]); 388 sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); 389 DPRINTF_STS; 390 if (i < sizeof(TPM_CMD) - 1) { 391 g_assert_cmpint(sts & 0xff, ==, 392 TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); 393 } else { 394 g_assert_cmpint(sts & 0xff, ==, TPM_TIS_STS_VALID); 395 } 396 g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount); 397 } 398 /* start processing */ 399 writeb(TIS_REG(0, TPM_TIS_REG_STS), TPM_TIS_STS_TPM_GO); 400 401 uint64_t end_time = g_get_monotonic_time() + 50 * G_TIME_SPAN_SECOND; 402 do { 403 sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); 404 if ((sts & TPM_TIS_STS_DATA_AVAILABLE) != 0) { 405 break; 406 } 407 } while (g_get_monotonic_time() < end_time); 408 409 sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); 410 DPRINTF_STS; 411 g_assert_cmpint(sts & 0xff, == , 412 TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE); 413 bcount = (sts >> 8) & 0xffff; 414 415 /* read response */ 416 uint8_t tpm_msg[sizeof(struct tpm_hdr)]; 417 g_assert_cmpint(sizeof(tpm_msg), ==, bcount); 418 419 for (i = 0; i < sizeof(tpm_msg); i++) { 420 tpm_msg[i] = readb(TIS_REG(0, TPM_TIS_REG_DATA_FIFO)); 421 sts = readl(TIS_REG(0, TPM_TIS_REG_STS)); 422 DPRINTF_STS; 423 if (sts & TPM_TIS_STS_DATA_AVAILABLE) { 424 g_assert_cmpint((sts >> 8) & 0xffff, ==, --bcount); 425 } 426 } 427 g_assert_cmpmem(tpm_msg, sizeof(tpm_msg), s->tpm_msg, sizeof(*s->tpm_msg)); 428 429 /* relinquish use of locality 0 */ 430 writeb(TIS_REG(0, TPM_TIS_REG_ACCESS), TPM_TIS_ACCESS_ACTIVE_LOCALITY); 431 access = readb(TIS_REG(0, TPM_TIS_REG_ACCESS)); 432 } 433 434 int main(int argc, char **argv) 435 { 436 int ret; 437 char *args, *tmp_path = g_dir_make_tmp("qemu-tpm-tis-test.XXXXXX", NULL); 438 GThread *thread; 439 TestState test; 440 441 module_call_init(MODULE_INIT_QOM); 442 g_test_init(&argc, &argv, NULL); 443 444 test.addr = g_new0(SocketAddress, 1); 445 test.addr->type = SOCKET_ADDRESS_TYPE_UNIX; 446 test.addr->u.q_unix.path = g_build_filename(tmp_path, "sock", NULL); 447 g_mutex_init(&test.data_mutex); 448 g_cond_init(&test.data_cond); 449 450 thread = g_thread_new(NULL, tpm_emu_ctrl_thread, &test); 451 tpm_emu_test_wait_cond(&test); 452 453 args = g_strdup_printf( 454 "-chardev socket,id=chr,path=%s " 455 "-tpmdev emulator,id=dev,chardev=chr " 456 "-device tpm-tis,tpmdev=dev", 457 test.addr->u.q_unix.path); 458 qtest_start(args); 459 460 qtest_add_data_func("/tpm-tis/test_check_localities", &test, 461 tpm_tis_test_check_localities); 462 463 qtest_add_data_func("/tpm-tis/test_check_access_reg", &test, 464 tpm_tis_test_check_access_reg); 465 466 qtest_add_data_func("/tpm-tis/test_check_access_reg_seize", &test, 467 tpm_tis_test_check_access_reg_seize); 468 469 qtest_add_data_func("/tpm-tis/test_check_access_reg_release", &test, 470 tpm_tis_test_check_access_reg_release); 471 472 qtest_add_data_func("/tpm-tis/test_check_transmit", &test, 473 tpm_tis_test_check_transmit); 474 475 ret = g_test_run(); 476 477 qtest_end(); 478 479 g_thread_join(thread); 480 g_unlink(test.addr->u.q_unix.path); 481 qapi_free_SocketAddress(test.addr); 482 g_rmdir(tmp_path); 483 g_free(tmp_path); 484 g_free(args); 485 return ret; 486 } 487