1 /* 2 * tpm_tis_common.c - QEMU's TPM TIS interface emulator 3 * device agnostic functions 4 * 5 * Copyright (C) 2006,2010-2013 IBM Corporation 6 * 7 * Authors: 8 * Stefan Berger <stefanb@us.ibm.com> 9 * David Safford <safford@us.ibm.com> 10 * 11 * Xen 4 support: Andrease Niederl <andreas.niederl@iaik.tugraz.at> 12 * 13 * This work is licensed under the terms of the GNU GPL, version 2 or later. 14 * See the COPYING file in the top-level directory. 15 * 16 * Implementation of the TIS interface according to specs found at 17 * http://www.trustedcomputinggroup.org. This implementation currently 18 * supports version 1.3, 21 March 2013 19 * In the developers menu choose the PC Client section then find the TIS 20 * specification. 21 * 22 * TPM TIS for TPM 2 implementation following TCG PC Client Platform 23 * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43 24 */ 25 #include "qemu/osdep.h" 26 #include "hw/irq.h" 27 #include "hw/isa/isa.h" 28 #include "qapi/error.h" 29 #include "qemu/module.h" 30 31 #include "hw/acpi/tpm.h" 32 #include "hw/pci/pci_ids.h" 33 #include "hw/qdev-properties.h" 34 #include "migration/vmstate.h" 35 #include "sysemu/tpm_backend.h" 36 #include "tpm_int.h" 37 #include "tpm_util.h" 38 #include "tpm_ppi.h" 39 #include "trace.h" 40 41 #include "tpm_tis.h" 42 43 #define DEBUG_TIS 0 44 45 /* local prototypes */ 46 47 static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, 48 unsigned size); 49 50 /* utility functions */ 51 52 static uint8_t tpm_tis_locality_from_addr(hwaddr addr) 53 { 54 return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7); 55 } 56 57 58 /* 59 * Set the given flags in the STS register by clearing the register but 60 * preserving the SELFTEST_DONE and TPM_FAMILY_MASK flags and then setting 61 * the new flags. 62 * 63 * The SELFTEST_DONE flag is acquired from the backend that determines it by 64 * peeking into TPM commands. 65 * 66 * A VM suspend/resume will preserve the flag by storing it into the VM 67 * device state, but the backend will not remember it when QEMU is started 68 * again. Therefore, we cache the flag here. Once set, it will not be unset 69 * except by a reset. 70 */ 71 static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags) 72 { 73 l->sts &= TPM_TIS_STS_SELFTEST_DONE | TPM_TIS_STS_TPM_FAMILY_MASK; 74 l->sts |= flags; 75 } 76 77 /* 78 * Send a request to the TPM. 79 */ 80 static void tpm_tis_tpm_send(TPMState *s, uint8_t locty) 81 { 82 if (trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { 83 tpm_util_show_buffer(s->buffer, s->be_buffer_size, "To TPM"); 84 } 85 86 /* 87 * rw_offset serves as length indicator for length of data; 88 * it's reset when the response comes back 89 */ 90 s->loc[locty].state = TPM_TIS_STATE_EXECUTION; 91 92 s->cmd = (TPMBackendCmd) { 93 .locty = locty, 94 .in = s->buffer, 95 .in_len = s->rw_offset, 96 .out = s->buffer, 97 .out_len = s->be_buffer_size, 98 }; 99 100 tpm_backend_deliver_request(s->be_driver, &s->cmd); 101 } 102 103 /* raise an interrupt if allowed */ 104 static void tpm_tis_raise_irq(TPMState *s, uint8_t locty, uint32_t irqmask) 105 { 106 if (!TPM_TIS_IS_VALID_LOCTY(locty)) { 107 return; 108 } 109 110 if ((s->loc[locty].inte & TPM_TIS_INT_ENABLED) && 111 (s->loc[locty].inte & irqmask)) { 112 trace_tpm_tis_raise_irq(irqmask); 113 qemu_irq_raise(s->irq); 114 s->loc[locty].ints |= irqmask; 115 } 116 } 117 118 static uint32_t tpm_tis_check_request_use_except(TPMState *s, uint8_t locty) 119 { 120 uint8_t l; 121 122 for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) { 123 if (l == locty) { 124 continue; 125 } 126 if ((s->loc[l].access & TPM_TIS_ACCESS_REQUEST_USE)) { 127 return 1; 128 } 129 } 130 131 return 0; 132 } 133 134 static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty) 135 { 136 bool change = (s->active_locty != new_active_locty); 137 bool is_seize; 138 uint8_t mask; 139 140 if (change && TPM_TIS_IS_VALID_LOCTY(s->active_locty)) { 141 is_seize = TPM_TIS_IS_VALID_LOCTY(new_active_locty) && 142 s->loc[new_active_locty].access & TPM_TIS_ACCESS_SEIZE; 143 144 if (is_seize) { 145 mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY); 146 } else { 147 mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY| 148 TPM_TIS_ACCESS_REQUEST_USE); 149 } 150 /* reset flags on the old active locality */ 151 s->loc[s->active_locty].access &= mask; 152 153 if (is_seize) { 154 s->loc[s->active_locty].access |= TPM_TIS_ACCESS_BEEN_SEIZED; 155 } 156 } 157 158 s->active_locty = new_active_locty; 159 160 trace_tpm_tis_new_active_locality(s->active_locty); 161 162 if (TPM_TIS_IS_VALID_LOCTY(new_active_locty)) { 163 /* set flags on the new active locality */ 164 s->loc[new_active_locty].access |= TPM_TIS_ACCESS_ACTIVE_LOCALITY; 165 s->loc[new_active_locty].access &= ~(TPM_TIS_ACCESS_REQUEST_USE | 166 TPM_TIS_ACCESS_SEIZE); 167 } 168 169 if (change) { 170 tpm_tis_raise_irq(s, s->active_locty, TPM_TIS_INT_LOCALITY_CHANGED); 171 } 172 } 173 174 /* abort -- this function switches the locality */ 175 static void tpm_tis_abort(TPMState *s) 176 { 177 s->rw_offset = 0; 178 179 trace_tpm_tis_abort(s->next_locty); 180 181 /* 182 * Need to react differently depending on who's aborting now and 183 * which locality will become active afterwards. 184 */ 185 if (s->aborting_locty == s->next_locty) { 186 s->loc[s->aborting_locty].state = TPM_TIS_STATE_READY; 187 tpm_tis_sts_set(&s->loc[s->aborting_locty], 188 TPM_TIS_STS_COMMAND_READY); 189 tpm_tis_raise_irq(s, s->aborting_locty, TPM_TIS_INT_COMMAND_READY); 190 } 191 192 /* locality after abort is another one than the current one */ 193 tpm_tis_new_active_locality(s, s->next_locty); 194 195 s->next_locty = TPM_TIS_NO_LOCALITY; 196 /* nobody's aborting a command anymore */ 197 s->aborting_locty = TPM_TIS_NO_LOCALITY; 198 } 199 200 /* prepare aborting current command */ 201 static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty) 202 { 203 uint8_t busy_locty; 204 205 assert(TPM_TIS_IS_VALID_LOCTY(newlocty)); 206 207 s->aborting_locty = locty; /* may also be TPM_TIS_NO_LOCALITY */ 208 s->next_locty = newlocty; /* locality after successful abort */ 209 210 /* 211 * only abort a command using an interrupt if currently executing 212 * a command AND if there's a valid connection to the vTPM. 213 */ 214 for (busy_locty = 0; busy_locty < TPM_TIS_NUM_LOCALITIES; busy_locty++) { 215 if (s->loc[busy_locty].state == TPM_TIS_STATE_EXECUTION) { 216 /* 217 * request the backend to cancel. Some backends may not 218 * support it 219 */ 220 tpm_backend_cancel_cmd(s->be_driver); 221 return; 222 } 223 } 224 225 tpm_tis_abort(s); 226 } 227 228 /* 229 * Callback from the TPM to indicate that the response was received. 230 */ 231 void tpm_tis_request_completed(TPMState *s, int ret) 232 { 233 uint8_t locty = s->cmd.locty; 234 uint8_t l; 235 236 assert(TPM_TIS_IS_VALID_LOCTY(locty)); 237 238 if (s->cmd.selftest_done) { 239 for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) { 240 s->loc[l].sts |= TPM_TIS_STS_SELFTEST_DONE; 241 } 242 } 243 244 /* FIXME: report error if ret != 0 */ 245 tpm_tis_sts_set(&s->loc[locty], 246 TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE); 247 s->loc[locty].state = TPM_TIS_STATE_COMPLETION; 248 s->rw_offset = 0; 249 250 if (trace_event_get_state_backends(TRACE_TPM_UTIL_SHOW_BUFFER)) { 251 tpm_util_show_buffer(s->buffer, s->be_buffer_size, "From TPM"); 252 } 253 254 if (TPM_TIS_IS_VALID_LOCTY(s->next_locty)) { 255 tpm_tis_abort(s); 256 } 257 258 tpm_tis_raise_irq(s, locty, 259 TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID); 260 } 261 262 /* 263 * Read a byte of response data 264 */ 265 static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty) 266 { 267 uint32_t ret = TPM_TIS_NO_DATA_BYTE; 268 uint16_t len; 269 270 if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) { 271 len = MIN(tpm_cmd_get_size(&s->buffer), 272 s->be_buffer_size); 273 274 ret = s->buffer[s->rw_offset++]; 275 if (s->rw_offset >= len) { 276 /* got last byte */ 277 tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID); 278 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID); 279 } 280 trace_tpm_tis_data_read(ret, s->rw_offset - 1); 281 } 282 283 return ret; 284 } 285 286 #ifdef DEBUG_TIS 287 static void tpm_tis_dump_state(TPMState *s, hwaddr addr) 288 { 289 static const unsigned regs[] = { 290 TPM_TIS_REG_ACCESS, 291 TPM_TIS_REG_INT_ENABLE, 292 TPM_TIS_REG_INT_VECTOR, 293 TPM_TIS_REG_INT_STATUS, 294 TPM_TIS_REG_INTF_CAPABILITY, 295 TPM_TIS_REG_STS, 296 TPM_TIS_REG_DID_VID, 297 TPM_TIS_REG_RID, 298 0xfff}; 299 int idx; 300 uint8_t locty = tpm_tis_locality_from_addr(addr); 301 hwaddr base = addr & ~0xfff; 302 303 printf("tpm_tis: active locality : %d\n" 304 "tpm_tis: state of locality %d : %d\n" 305 "tpm_tis: register dump:\n", 306 s->active_locty, 307 locty, s->loc[locty].state); 308 309 for (idx = 0; regs[idx] != 0xfff; idx++) { 310 printf("tpm_tis: 0x%04x : 0x%08x\n", regs[idx], 311 (int)tpm_tis_mmio_read(s, base + regs[idx], 4)); 312 } 313 314 printf("tpm_tis: r/w offset : %d\n" 315 "tpm_tis: result buffer : ", 316 s->rw_offset); 317 for (idx = 0; 318 idx < MIN(tpm_cmd_get_size(&s->buffer), s->be_buffer_size); 319 idx++) { 320 printf("%c%02x%s", 321 s->rw_offset == idx ? '>' : ' ', 322 s->buffer[idx], 323 ((idx & 0xf) == 0xf) ? "\ntpm_tis: " : ""); 324 } 325 printf("\n"); 326 } 327 #endif 328 329 /* 330 * Read a register of the TIS interface 331 * See specs pages 33-63 for description of the registers 332 */ 333 static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr, 334 unsigned size) 335 { 336 TPMState *s = opaque; 337 uint16_t offset = addr & 0xffc; 338 uint8_t shift = (addr & 0x3) * 8; 339 uint32_t val = 0xffffffff; 340 uint8_t locty = tpm_tis_locality_from_addr(addr); 341 uint32_t avail; 342 uint8_t v; 343 344 if (tpm_backend_had_startup_error(s->be_driver)) { 345 return 0; 346 } 347 348 switch (offset) { 349 case TPM_TIS_REG_ACCESS: 350 /* never show the SEIZE flag even though we use it internally */ 351 val = s->loc[locty].access & ~TPM_TIS_ACCESS_SEIZE; 352 /* the pending flag is always calculated */ 353 if (tpm_tis_check_request_use_except(s, locty)) { 354 val |= TPM_TIS_ACCESS_PENDING_REQUEST; 355 } 356 val |= !tpm_backend_get_tpm_established_flag(s->be_driver); 357 break; 358 case TPM_TIS_REG_INT_ENABLE: 359 val = s->loc[locty].inte; 360 break; 361 case TPM_TIS_REG_INT_VECTOR: 362 val = s->irq_num; 363 break; 364 case TPM_TIS_REG_INT_STATUS: 365 val = s->loc[locty].ints; 366 break; 367 case TPM_TIS_REG_INTF_CAPABILITY: 368 switch (s->be_tpm_version) { 369 case TPM_VERSION_UNSPEC: 370 val = 0; 371 break; 372 case TPM_VERSION_1_2: 373 val = TPM_TIS_CAPABILITIES_SUPPORTED1_3; 374 break; 375 case TPM_VERSION_2_0: 376 val = TPM_TIS_CAPABILITIES_SUPPORTED2_0; 377 break; 378 } 379 break; 380 case TPM_TIS_REG_STS: 381 if (s->active_locty == locty) { 382 if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) { 383 val = TPM_TIS_BURST_COUNT( 384 MIN(tpm_cmd_get_size(&s->buffer), 385 s->be_buffer_size) 386 - s->rw_offset) | s->loc[locty].sts; 387 } else { 388 avail = s->be_buffer_size - s->rw_offset; 389 /* 390 * byte-sized reads should not return 0x00 for 0x100 391 * available bytes. 392 */ 393 if (size == 1 && avail > 0xff) { 394 avail = 0xff; 395 } 396 val = TPM_TIS_BURST_COUNT(avail) | s->loc[locty].sts; 397 } 398 } 399 break; 400 case TPM_TIS_REG_DATA_FIFO: 401 case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END: 402 if (s->active_locty == locty) { 403 if (size > 4 - (addr & 0x3)) { 404 /* prevent access beyond FIFO */ 405 size = 4 - (addr & 0x3); 406 } 407 val = 0; 408 shift = 0; 409 while (size > 0) { 410 switch (s->loc[locty].state) { 411 case TPM_TIS_STATE_COMPLETION: 412 v = tpm_tis_data_read(s, locty); 413 break; 414 default: 415 v = TPM_TIS_NO_DATA_BYTE; 416 break; 417 } 418 val |= (v << shift); 419 shift += 8; 420 size--; 421 } 422 shift = 0; /* no more adjustments */ 423 } 424 break; 425 case TPM_TIS_REG_INTERFACE_ID: 426 val = s->loc[locty].iface_id; 427 break; 428 case TPM_TIS_REG_DID_VID: 429 val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID; 430 break; 431 case TPM_TIS_REG_RID: 432 val = TPM_TIS_TPM_RID; 433 break; 434 #ifdef DEBUG_TIS 435 case TPM_TIS_REG_DEBUG: 436 tpm_tis_dump_state(s, addr); 437 break; 438 #endif 439 } 440 441 if (shift) { 442 val >>= shift; 443 } 444 445 trace_tpm_tis_mmio_read(size, addr, val); 446 447 return val; 448 } 449 450 /* 451 * Write a value to a register of the TIS interface 452 * See specs pages 33-63 for description of the registers 453 */ 454 static void tpm_tis_mmio_write(void *opaque, hwaddr addr, 455 uint64_t val, unsigned size) 456 { 457 TPMState *s = opaque; 458 uint16_t off = addr & 0xffc; 459 uint8_t shift = (addr & 0x3) * 8; 460 uint8_t locty = tpm_tis_locality_from_addr(addr); 461 uint8_t active_locty, l; 462 int c, set_new_locty = 1; 463 uint16_t len; 464 uint32_t mask = (size == 1) ? 0xff : ((size == 2) ? 0xffff : ~0); 465 466 trace_tpm_tis_mmio_write(size, addr, val); 467 468 if (locty == 4) { 469 trace_tpm_tis_mmio_write_locty4(); 470 return; 471 } 472 473 if (tpm_backend_had_startup_error(s->be_driver)) { 474 return; 475 } 476 477 val &= mask; 478 479 if (shift) { 480 val <<= shift; 481 mask <<= shift; 482 } 483 484 mask ^= 0xffffffff; 485 486 switch (off) { 487 case TPM_TIS_REG_ACCESS: 488 489 if ((val & TPM_TIS_ACCESS_SEIZE)) { 490 val &= ~(TPM_TIS_ACCESS_REQUEST_USE | 491 TPM_TIS_ACCESS_ACTIVE_LOCALITY); 492 } 493 494 active_locty = s->active_locty; 495 496 if ((val & TPM_TIS_ACCESS_ACTIVE_LOCALITY)) { 497 /* give up locality if currently owned */ 498 if (s->active_locty == locty) { 499 trace_tpm_tis_mmio_write_release_locty(locty); 500 501 uint8_t newlocty = TPM_TIS_NO_LOCALITY; 502 /* anybody wants the locality ? */ 503 for (c = TPM_TIS_NUM_LOCALITIES - 1; c >= 0; c--) { 504 if ((s->loc[c].access & TPM_TIS_ACCESS_REQUEST_USE)) { 505 trace_tpm_tis_mmio_write_locty_req_use(c); 506 newlocty = c; 507 break; 508 } 509 } 510 trace_tpm_tis_mmio_write_next_locty(newlocty); 511 512 if (TPM_TIS_IS_VALID_LOCTY(newlocty)) { 513 set_new_locty = 0; 514 tpm_tis_prep_abort(s, locty, newlocty); 515 } else { 516 active_locty = TPM_TIS_NO_LOCALITY; 517 } 518 } else { 519 /* not currently the owner; clear a pending request */ 520 s->loc[locty].access &= ~TPM_TIS_ACCESS_REQUEST_USE; 521 } 522 } 523 524 if ((val & TPM_TIS_ACCESS_BEEN_SEIZED)) { 525 s->loc[locty].access &= ~TPM_TIS_ACCESS_BEEN_SEIZED; 526 } 527 528 if ((val & TPM_TIS_ACCESS_SEIZE)) { 529 /* 530 * allow seize if a locality is active and the requesting 531 * locality is higher than the one that's active 532 * OR 533 * allow seize for requesting locality if no locality is 534 * active 535 */ 536 while ((TPM_TIS_IS_VALID_LOCTY(s->active_locty) && 537 locty > s->active_locty) || 538 !TPM_TIS_IS_VALID_LOCTY(s->active_locty)) { 539 bool higher_seize = FALSE; 540 541 /* already a pending SEIZE ? */ 542 if ((s->loc[locty].access & TPM_TIS_ACCESS_SEIZE)) { 543 break; 544 } 545 546 /* check for ongoing seize by a higher locality */ 547 for (l = locty + 1; l < TPM_TIS_NUM_LOCALITIES; l++) { 548 if ((s->loc[l].access & TPM_TIS_ACCESS_SEIZE)) { 549 higher_seize = TRUE; 550 break; 551 } 552 } 553 554 if (higher_seize) { 555 break; 556 } 557 558 /* cancel any seize by a lower locality */ 559 for (l = 0; l < locty; l++) { 560 s->loc[l].access &= ~TPM_TIS_ACCESS_SEIZE; 561 } 562 563 s->loc[locty].access |= TPM_TIS_ACCESS_SEIZE; 564 565 trace_tpm_tis_mmio_write_locty_seized(locty, s->active_locty); 566 trace_tpm_tis_mmio_write_init_abort(); 567 568 set_new_locty = 0; 569 tpm_tis_prep_abort(s, s->active_locty, locty); 570 break; 571 } 572 } 573 574 if ((val & TPM_TIS_ACCESS_REQUEST_USE)) { 575 if (s->active_locty != locty) { 576 if (TPM_TIS_IS_VALID_LOCTY(s->active_locty)) { 577 s->loc[locty].access |= TPM_TIS_ACCESS_REQUEST_USE; 578 } else { 579 /* no locality active -> make this one active now */ 580 active_locty = locty; 581 } 582 } 583 } 584 585 if (set_new_locty) { 586 tpm_tis_new_active_locality(s, active_locty); 587 } 588 589 break; 590 case TPM_TIS_REG_INT_ENABLE: 591 if (s->active_locty != locty) { 592 break; 593 } 594 595 s->loc[locty].inte &= mask; 596 s->loc[locty].inte |= (val & (TPM_TIS_INT_ENABLED | 597 TPM_TIS_INT_POLARITY_MASK | 598 TPM_TIS_INTERRUPTS_SUPPORTED)); 599 break; 600 case TPM_TIS_REG_INT_VECTOR: 601 /* hard wired -- ignore */ 602 break; 603 case TPM_TIS_REG_INT_STATUS: 604 if (s->active_locty != locty) { 605 break; 606 } 607 608 /* clearing of interrupt flags */ 609 if (((val & TPM_TIS_INTERRUPTS_SUPPORTED)) && 610 (s->loc[locty].ints & TPM_TIS_INTERRUPTS_SUPPORTED)) { 611 s->loc[locty].ints &= ~val; 612 if (s->loc[locty].ints == 0) { 613 qemu_irq_lower(s->irq); 614 trace_tpm_tis_mmio_write_lowering_irq(); 615 } 616 } 617 s->loc[locty].ints &= ~(val & TPM_TIS_INTERRUPTS_SUPPORTED); 618 break; 619 case TPM_TIS_REG_STS: 620 if (s->active_locty != locty) { 621 break; 622 } 623 624 if (s->be_tpm_version == TPM_VERSION_2_0) { 625 /* some flags that are only supported for TPM 2 */ 626 if (val & TPM_TIS_STS_COMMAND_CANCEL) { 627 if (s->loc[locty].state == TPM_TIS_STATE_EXECUTION) { 628 /* 629 * request the backend to cancel. Some backends may not 630 * support it 631 */ 632 tpm_backend_cancel_cmd(s->be_driver); 633 } 634 } 635 636 if (val & TPM_TIS_STS_RESET_ESTABLISHMENT_BIT) { 637 if (locty == 3 || locty == 4) { 638 tpm_backend_reset_tpm_established_flag(s->be_driver, locty); 639 } 640 } 641 } 642 643 val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO | 644 TPM_TIS_STS_RESPONSE_RETRY); 645 646 if (val == TPM_TIS_STS_COMMAND_READY) { 647 switch (s->loc[locty].state) { 648 649 case TPM_TIS_STATE_READY: 650 s->rw_offset = 0; 651 break; 652 653 case TPM_TIS_STATE_IDLE: 654 tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_COMMAND_READY); 655 s->loc[locty].state = TPM_TIS_STATE_READY; 656 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY); 657 break; 658 659 case TPM_TIS_STATE_EXECUTION: 660 case TPM_TIS_STATE_RECEPTION: 661 /* abort currently running command */ 662 trace_tpm_tis_mmio_write_init_abort(); 663 tpm_tis_prep_abort(s, locty, locty); 664 break; 665 666 case TPM_TIS_STATE_COMPLETION: 667 s->rw_offset = 0; 668 /* shortcut to ready state with C/R set */ 669 s->loc[locty].state = TPM_TIS_STATE_READY; 670 if (!(s->loc[locty].sts & TPM_TIS_STS_COMMAND_READY)) { 671 tpm_tis_sts_set(&s->loc[locty], 672 TPM_TIS_STS_COMMAND_READY); 673 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_COMMAND_READY); 674 } 675 s->loc[locty].sts &= ~(TPM_TIS_STS_DATA_AVAILABLE); 676 break; 677 678 } 679 } else if (val == TPM_TIS_STS_TPM_GO) { 680 switch (s->loc[locty].state) { 681 case TPM_TIS_STATE_RECEPTION: 682 if ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) == 0) { 683 tpm_tis_tpm_send(s, locty); 684 } 685 break; 686 default: 687 /* ignore */ 688 break; 689 } 690 } else if (val == TPM_TIS_STS_RESPONSE_RETRY) { 691 switch (s->loc[locty].state) { 692 case TPM_TIS_STATE_COMPLETION: 693 s->rw_offset = 0; 694 tpm_tis_sts_set(&s->loc[locty], 695 TPM_TIS_STS_VALID| 696 TPM_TIS_STS_DATA_AVAILABLE); 697 break; 698 default: 699 /* ignore */ 700 break; 701 } 702 } 703 break; 704 case TPM_TIS_REG_DATA_FIFO: 705 case TPM_TIS_REG_DATA_XFIFO ... TPM_TIS_REG_DATA_XFIFO_END: 706 /* data fifo */ 707 if (s->active_locty != locty) { 708 break; 709 } 710 711 if (s->loc[locty].state == TPM_TIS_STATE_IDLE || 712 s->loc[locty].state == TPM_TIS_STATE_EXECUTION || 713 s->loc[locty].state == TPM_TIS_STATE_COMPLETION) { 714 /* drop the byte */ 715 } else { 716 trace_tpm_tis_mmio_write_data2send(val, size); 717 if (s->loc[locty].state == TPM_TIS_STATE_READY) { 718 s->loc[locty].state = TPM_TIS_STATE_RECEPTION; 719 tpm_tis_sts_set(&s->loc[locty], 720 TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); 721 } 722 723 val >>= shift; 724 if (size > 4 - (addr & 0x3)) { 725 /* prevent access beyond FIFO */ 726 size = 4 - (addr & 0x3); 727 } 728 729 while ((s->loc[locty].sts & TPM_TIS_STS_EXPECT) && size > 0) { 730 if (s->rw_offset < s->be_buffer_size) { 731 s->buffer[s->rw_offset++] = 732 (uint8_t)val; 733 val >>= 8; 734 size--; 735 } else { 736 tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID); 737 } 738 } 739 740 /* check for complete packet */ 741 if (s->rw_offset > 5 && 742 (s->loc[locty].sts & TPM_TIS_STS_EXPECT)) { 743 /* we have a packet length - see if we have all of it */ 744 bool need_irq = !(s->loc[locty].sts & TPM_TIS_STS_VALID); 745 746 len = tpm_cmd_get_size(&s->buffer); 747 if (len > s->rw_offset) { 748 tpm_tis_sts_set(&s->loc[locty], 749 TPM_TIS_STS_EXPECT | TPM_TIS_STS_VALID); 750 } else { 751 /* packet complete */ 752 tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID); 753 } 754 if (need_irq) { 755 tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID); 756 } 757 } 758 } 759 break; 760 case TPM_TIS_REG_INTERFACE_ID: 761 if (val & TPM_TIS_IFACE_ID_INT_SEL_LOCK) { 762 for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) { 763 s->loc[l].iface_id |= TPM_TIS_IFACE_ID_INT_SEL_LOCK; 764 } 765 } 766 break; 767 } 768 } 769 770 const MemoryRegionOps tpm_tis_memory_ops = { 771 .read = tpm_tis_mmio_read, 772 .write = tpm_tis_mmio_write, 773 .endianness = DEVICE_LITTLE_ENDIAN, 774 .valid = { 775 .min_access_size = 1, 776 .max_access_size = 4, 777 }, 778 }; 779 780 /* 781 * Get the TPMVersion of the backend device being used 782 */ 783 enum TPMVersion tpm_tis_get_tpm_version(TPMState *s) 784 { 785 if (tpm_backend_had_startup_error(s->be_driver)) { 786 return TPM_VERSION_UNSPEC; 787 } 788 789 return tpm_backend_get_tpm_version(s->be_driver); 790 } 791 792 /* 793 * This function is called when the machine starts, resets or due to 794 * S3 resume. 795 */ 796 void tpm_tis_reset(TPMState *s) 797 { 798 int c; 799 800 s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver); 801 s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver), 802 TPM_TIS_BUFFER_MAX); 803 804 if (s->ppi_enabled) { 805 tpm_ppi_reset(&s->ppi); 806 } 807 tpm_backend_reset(s->be_driver); 808 809 s->active_locty = TPM_TIS_NO_LOCALITY; 810 s->next_locty = TPM_TIS_NO_LOCALITY; 811 s->aborting_locty = TPM_TIS_NO_LOCALITY; 812 813 for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) { 814 s->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS; 815 switch (s->be_tpm_version) { 816 case TPM_VERSION_UNSPEC: 817 break; 818 case TPM_VERSION_1_2: 819 s->loc[c].sts = TPM_TIS_STS_TPM_FAMILY1_2; 820 s->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3; 821 break; 822 case TPM_VERSION_2_0: 823 s->loc[c].sts = TPM_TIS_STS_TPM_FAMILY2_0; 824 s->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0; 825 break; 826 } 827 s->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL; 828 s->loc[c].ints = 0; 829 s->loc[c].state = TPM_TIS_STATE_IDLE; 830 831 s->rw_offset = 0; 832 } 833 834 if (tpm_backend_startup_tpm(s->be_driver, s->be_buffer_size) < 0) { 835 exit(1); 836 } 837 } 838 839 /* persistent state handling */ 840 841 int tpm_tis_pre_save(TPMState *s) 842 { 843 uint8_t locty = s->active_locty; 844 845 trace_tpm_tis_pre_save(locty, s->rw_offset); 846 847 if (DEBUG_TIS) { 848 tpm_tis_dump_state(s, 0); 849 } 850 851 /* 852 * Synchronize with backend completion. 853 */ 854 tpm_backend_finish_sync(s->be_driver); 855 856 return 0; 857 } 858 859 const VMStateDescription vmstate_locty = { 860 .name = "tpm-tis/locty", 861 .version_id = 0, 862 .fields = (VMStateField[]) { 863 VMSTATE_UINT32(state, TPMLocality), 864 VMSTATE_UINT32(inte, TPMLocality), 865 VMSTATE_UINT32(ints, TPMLocality), 866 VMSTATE_UINT8(access, TPMLocality), 867 VMSTATE_UINT32(sts, TPMLocality), 868 VMSTATE_UINT32(iface_id, TPMLocality), 869 VMSTATE_END_OF_LIST(), 870 } 871 }; 872 873