qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

tpm_tis_common.c (26734B)


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