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