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