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/isa/isa.h"
  27#include "qapi/error.h"
  28
  29#include "hw/acpi/tpm.h"
  30#include "hw/pci/pci_ids.h"
  31#include "sysemu/tpm_backend.h"
  32#include "tpm_int.h"
  33#include "tpm_util.h"
  34#include "trace.h"
  35
  36#define TPM_TIS_NUM_LOCALITIES      5     /* per spec */
  37#define TPM_TIS_LOCALITY_SHIFT      12
  38#define TPM_TIS_NO_LOCALITY         0xff
  39
  40#define TPM_TIS_IS_VALID_LOCTY(x)   ((x) < TPM_TIS_NUM_LOCALITIES)
  41
  42#define TPM_TIS_BUFFER_MAX          4096
  43
  44typedef enum {
  45    TPM_TIS_STATE_IDLE = 0,
  46    TPM_TIS_STATE_READY,
  47    TPM_TIS_STATE_COMPLETION,
  48    TPM_TIS_STATE_EXECUTION,
  49    TPM_TIS_STATE_RECEPTION,
  50} TPMTISState;
  51
  52/* locality data  -- all fields are persisted */
  53typedef struct TPMLocality {
  54    TPMTISState state;
  55    uint8_t access;
  56    uint32_t sts;
  57    uint32_t iface_id;
  58    uint32_t inte;
  59    uint32_t ints;
  60} TPMLocality;
  61
  62typedef struct TPMState {
  63    ISADevice busdev;
  64    MemoryRegion mmio;
  65
  66    unsigned char buffer[TPM_TIS_BUFFER_MAX];
  67    uint16_t rw_offset;
  68
  69    uint8_t active_locty;
  70    uint8_t aborting_locty;
  71    uint8_t next_locty;
  72
  73    TPMLocality loc[TPM_TIS_NUM_LOCALITIES];
  74
  75    qemu_irq irq;
  76    uint32_t irq_num;
  77
  78    TPMBackendCmd cmd;
  79
  80    TPMBackend *be_driver;
  81    TPMVersion be_tpm_version;
  82
  83    size_t be_buffer_size;
  84} TPMState;
  85
  86#define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
  87
  88#define DEBUG_TIS 0
  89
  90/* local prototypes */
  91
  92static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
  93                                  unsigned size);
  94
  95/* utility functions */
  96
  97static uint8_t tpm_tis_locality_from_addr(hwaddr addr)
  98{
  99    return (uint8_t)((addr >> TPM_TIS_LOCALITY_SHIFT) & 0x7);
 100}
 101
 102static void tpm_tis_show_buffer(const unsigned char *buffer,
 103                                size_t buffer_size, const char *string)
 104{
 105    uint32_t len, i;
 106
 107    len = MIN(tpm_cmd_get_size(buffer), buffer_size);
 108    printf("tpm_tis: %s length = %d\n", string, len);
 109    for (i = 0; i < len; i++) {
 110        if (i && !(i % 16)) {
 111            printf("\n");
 112        }
 113        printf("%.2X ", buffer[i]);
 114    }
 115    printf("\n");
 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 */
 131static 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 */
 140static void tpm_tis_tpm_send(TPMState *s, uint8_t locty)
 141{
 142    if (DEBUG_TIS) {
 143        tpm_tis_show_buffer(s->buffer, s->be_buffer_size,
 144                            "tpm_tis: To TPM");
 145    }
 146
 147    /*
 148     * rw_offset serves as length indicator for length of data;
 149     * it's reset when the response comes back
 150     */
 151    s->loc[locty].state = TPM_TIS_STATE_EXECUTION;
 152
 153    s->cmd = (TPMBackendCmd) {
 154        .locty = locty,
 155        .in = s->buffer,
 156        .in_len = s->rw_offset,
 157        .out = s->buffer,
 158        .out_len = s->be_buffer_size,
 159    };
 160
 161    tpm_backend_deliver_request(s->be_driver, &s->cmd);
 162}
 163
 164/* raise an interrupt if allowed */
 165static void tpm_tis_raise_irq(TPMState *s, uint8_t locty, uint32_t irqmask)
 166{
 167    if (!TPM_TIS_IS_VALID_LOCTY(locty)) {
 168        return;
 169    }
 170
 171    if ((s->loc[locty].inte & TPM_TIS_INT_ENABLED) &&
 172        (s->loc[locty].inte & irqmask)) {
 173        trace_tpm_tis_raise_irq(irqmask);
 174        qemu_irq_raise(s->irq);
 175        s->loc[locty].ints |= irqmask;
 176    }
 177}
 178
 179static uint32_t tpm_tis_check_request_use_except(TPMState *s, uint8_t locty)
 180{
 181    uint8_t l;
 182
 183    for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
 184        if (l == locty) {
 185            continue;
 186        }
 187        if ((s->loc[l].access & TPM_TIS_ACCESS_REQUEST_USE)) {
 188            return 1;
 189        }
 190    }
 191
 192    return 0;
 193}
 194
 195static void tpm_tis_new_active_locality(TPMState *s, uint8_t new_active_locty)
 196{
 197    bool change = (s->active_locty != new_active_locty);
 198    bool is_seize;
 199    uint8_t mask;
 200
 201    if (change && TPM_TIS_IS_VALID_LOCTY(s->active_locty)) {
 202        is_seize = TPM_TIS_IS_VALID_LOCTY(new_active_locty) &&
 203                   s->loc[new_active_locty].access & TPM_TIS_ACCESS_SEIZE;
 204
 205        if (is_seize) {
 206            mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY);
 207        } else {
 208            mask = ~(TPM_TIS_ACCESS_ACTIVE_LOCALITY|
 209                     TPM_TIS_ACCESS_REQUEST_USE);
 210        }
 211        /* reset flags on the old active locality */
 212        s->loc[s->active_locty].access &= mask;
 213
 214        if (is_seize) {
 215            s->loc[s->active_locty].access |= TPM_TIS_ACCESS_BEEN_SEIZED;
 216        }
 217    }
 218
 219    s->active_locty = new_active_locty;
 220
 221    trace_tpm_tis_new_active_locality(s->active_locty);
 222
 223    if (TPM_TIS_IS_VALID_LOCTY(new_active_locty)) {
 224        /* set flags on the new active locality */
 225        s->loc[new_active_locty].access |= TPM_TIS_ACCESS_ACTIVE_LOCALITY;
 226        s->loc[new_active_locty].access &= ~(TPM_TIS_ACCESS_REQUEST_USE |
 227                                               TPM_TIS_ACCESS_SEIZE);
 228    }
 229
 230    if (change) {
 231        tpm_tis_raise_irq(s, s->active_locty, TPM_TIS_INT_LOCALITY_CHANGED);
 232    }
 233}
 234
 235/* abort -- this function switches the locality */
 236static void tpm_tis_abort(TPMState *s, uint8_t locty)
 237{
 238    s->rw_offset = 0;
 239
 240    trace_tpm_tis_abort(s->next_locty);
 241
 242    /*
 243     * Need to react differently depending on who's aborting now and
 244     * which locality will become active afterwards.
 245     */
 246    if (s->aborting_locty == s->next_locty) {
 247        s->loc[s->aborting_locty].state = TPM_TIS_STATE_READY;
 248        tpm_tis_sts_set(&s->loc[s->aborting_locty],
 249                        TPM_TIS_STS_COMMAND_READY);
 250        tpm_tis_raise_irq(s, s->aborting_locty, TPM_TIS_INT_COMMAND_READY);
 251    }
 252
 253    /* locality after abort is another one than the current one */
 254    tpm_tis_new_active_locality(s, s->next_locty);
 255
 256    s->next_locty = TPM_TIS_NO_LOCALITY;
 257    /* nobody's aborting a command anymore */
 258    s->aborting_locty = TPM_TIS_NO_LOCALITY;
 259}
 260
 261/* prepare aborting current command */
 262static void tpm_tis_prep_abort(TPMState *s, uint8_t locty, uint8_t newlocty)
 263{
 264    uint8_t busy_locty;
 265
 266    s->aborting_locty = locty;
 267    s->next_locty = newlocty;  /* locality after successful abort */
 268
 269    /*
 270     * only abort a command using an interrupt if currently executing
 271     * a command AND if there's a valid connection to the vTPM.
 272     */
 273    for (busy_locty = 0; busy_locty < TPM_TIS_NUM_LOCALITIES; busy_locty++) {
 274        if (s->loc[busy_locty].state == TPM_TIS_STATE_EXECUTION) {
 275            /*
 276             * request the backend to cancel. Some backends may not
 277             * support it
 278             */
 279            tpm_backend_cancel_cmd(s->be_driver);
 280            return;
 281        }
 282    }
 283
 284    tpm_tis_abort(s, locty);
 285}
 286
 287/*
 288 * Callback from the TPM to indicate that the response was received.
 289 */
 290static void tpm_tis_request_completed(TPMIf *ti, int ret)
 291{
 292    TPMState *s = TPM(ti);
 293    uint8_t locty = s->cmd.locty;
 294    uint8_t l;
 295
 296    if (s->cmd.selftest_done) {
 297        for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
 298            s->loc[locty].sts |= TPM_TIS_STS_SELFTEST_DONE;
 299        }
 300    }
 301
 302    /* FIXME: report error if ret != 0 */
 303    tpm_tis_sts_set(&s->loc[locty],
 304                    TPM_TIS_STS_VALID | TPM_TIS_STS_DATA_AVAILABLE);
 305    s->loc[locty].state = TPM_TIS_STATE_COMPLETION;
 306    s->rw_offset = 0;
 307
 308    if (DEBUG_TIS) {
 309        tpm_tis_show_buffer(s->buffer, s->be_buffer_size,
 310                            "tpm_tis: From TPM");
 311    }
 312
 313    if (TPM_TIS_IS_VALID_LOCTY(s->next_locty)) {
 314        tpm_tis_abort(s, locty);
 315    }
 316
 317    tpm_tis_raise_irq(s, locty,
 318                      TPM_TIS_INT_DATA_AVAILABLE | TPM_TIS_INT_STS_VALID);
 319}
 320
 321/*
 322 * Read a byte of response data
 323 */
 324static uint32_t tpm_tis_data_read(TPMState *s, uint8_t locty)
 325{
 326    uint32_t ret = TPM_TIS_NO_DATA_BYTE;
 327    uint16_t len;
 328
 329    if ((s->loc[locty].sts & TPM_TIS_STS_DATA_AVAILABLE)) {
 330        len = MIN(tpm_cmd_get_size(&s->buffer),
 331                  s->be_buffer_size);
 332
 333        ret = s->buffer[s->rw_offset++];
 334        if (s->rw_offset >= len) {
 335            /* got last byte */
 336            tpm_tis_sts_set(&s->loc[locty], TPM_TIS_STS_VALID);
 337            tpm_tis_raise_irq(s, locty, TPM_TIS_INT_STS_VALID);
 338        }
 339        trace_tpm_tis_data_read(ret, s->rw_offset - 1);
 340    }
 341
 342    return ret;
 343}
 344
 345#ifdef DEBUG_TIS
 346static void tpm_tis_dump_state(void *opaque, hwaddr addr)
 347{
 348    static const unsigned regs[] = {
 349        TPM_TIS_REG_ACCESS,
 350        TPM_TIS_REG_INT_ENABLE,
 351        TPM_TIS_REG_INT_VECTOR,
 352        TPM_TIS_REG_INT_STATUS,
 353        TPM_TIS_REG_INTF_CAPABILITY,
 354        TPM_TIS_REG_STS,
 355        TPM_TIS_REG_DID_VID,
 356        TPM_TIS_REG_RID,
 357        0xfff};
 358    int idx;
 359    uint8_t locty = tpm_tis_locality_from_addr(addr);
 360    hwaddr base = addr & ~0xfff;
 361    TPMState *s = opaque;
 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(opaque, 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 */
 393static 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(opaque, 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 */
 514static 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 - 1; 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
 830static 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 */
 843static enum TPMVersion tpm_tis_get_tpm_version(TPMIf *ti)
 844{
 845    TPMState *s = TPM(ti);
 846
 847    if (tpm_backend_had_startup_error(s->be_driver)) {
 848        return TPM_VERSION_UNSPEC;
 849    }
 850
 851    return tpm_backend_get_tpm_version(s->be_driver);
 852}
 853
 854/*
 855 * This function is called when the machine starts, resets or due to
 856 * S3 resume.
 857 */
 858static void tpm_tis_reset(DeviceState *dev)
 859{
 860    TPMState *s = TPM(dev);
 861    int c;
 862
 863    s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
 864    s->be_buffer_size = MIN(tpm_backend_get_buffer_size(s->be_driver),
 865                            TPM_TIS_BUFFER_MAX);
 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    tpm_backend_startup_tpm(s->be_driver, s->be_buffer_size);
 895}
 896
 897static const VMStateDescription vmstate_tpm_tis = {
 898    .name = "tpm",
 899    .unmigratable = 1,
 900};
 901
 902static Property tpm_tis_properties[] = {
 903    DEFINE_PROP_UINT32("irq", TPMState, irq_num, TPM_TIS_IRQ),
 904    DEFINE_PROP_TPMBE("tpmdev", TPMState, be_driver),
 905    DEFINE_PROP_END_OF_LIST(),
 906};
 907
 908static void tpm_tis_realizefn(DeviceState *dev, Error **errp)
 909{
 910    TPMState *s = TPM(dev);
 911
 912    if (!tpm_find()) {
 913        error_setg(errp, "at most one TPM device is permitted");
 914        return;
 915    }
 916
 917    if (!s->be_driver) {
 918        error_setg(errp, "'tpmdev' property is required");
 919        return;
 920    }
 921    if (s->irq_num > 15) {
 922        error_setg(errp, "IRQ %d is outside valid range of 0 to 15",
 923                   s->irq_num);
 924        return;
 925    }
 926
 927    isa_init_irq(&s->busdev, &s->irq, s->irq_num);
 928
 929    memory_region_add_subregion(isa_address_space(ISA_DEVICE(dev)),
 930                                TPM_TIS_ADDR_BASE, &s->mmio);
 931}
 932
 933static void tpm_tis_initfn(Object *obj)
 934{
 935    TPMState *s = TPM(obj);
 936
 937    memory_region_init_io(&s->mmio, OBJECT(s), &tpm_tis_memory_ops,
 938                          s, "tpm-tis-mmio",
 939                          TPM_TIS_NUM_LOCALITIES << TPM_TIS_LOCALITY_SHIFT);
 940}
 941
 942static void tpm_tis_class_init(ObjectClass *klass, void *data)
 943{
 944    DeviceClass *dc = DEVICE_CLASS(klass);
 945    TPMIfClass *tc = TPM_IF_CLASS(klass);
 946
 947    dc->realize = tpm_tis_realizefn;
 948    dc->props = tpm_tis_properties;
 949    dc->reset = tpm_tis_reset;
 950    dc->vmsd  = &vmstate_tpm_tis;
 951    tc->model = TPM_MODEL_TPM_TIS;
 952    tc->get_version = tpm_tis_get_tpm_version;
 953    tc->request_completed = tpm_tis_request_completed;
 954}
 955
 956static const TypeInfo tpm_tis_info = {
 957    .name = TYPE_TPM_TIS,
 958    .parent = TYPE_ISA_DEVICE,
 959    .instance_size = sizeof(TPMState),
 960    .instance_init = tpm_tis_initfn,
 961    .class_init  = tpm_tis_class_init,
 962    .interfaces = (InterfaceInfo[]) {
 963        { TYPE_TPM_IF },
 964        { }
 965    }
 966};
 967
 968static void tpm_tis_register(void)
 969{
 970    type_register_static(&tpm_tis_info);
 971}
 972
 973type_init(tpm_tis_register)
 974