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