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