diff mbox

[1/3] Extend TPM TIS interface to version 2.0

Message ID 1427830813-639306-2-git-send-email-stefanb@linux.vnet.ibm.com
State New
Headers show

Commit Message

Stefan Berger March 31, 2015, 7:40 p.m. UTC
Following the recent upgrade to version 1.3, extend the TPM TIS
interface with capabilities introduced for support of a TPM 2.

TPM TIS for TPM 2 introduced the following extensions beyond the
TPM TIS 1.3 (used for TPM 1.2):

- A new 32bit interface Id register was introduced.
- New flags for the status (STS) register were defined.
- New flags for the capability flags were defined.

Support the above if a TPM TIS 1.3 for TPM 2 is used with a TPM 2
on the backend side. Support the old TPM TIS 1.3 configuration if a
TPM 1.2 is being used. A subsequent patch will then determine which
TPM version is being used in the backend.

Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
---
 backends/tpm.c               |  14 ++++++
 hw/tpm/tpm_int.h             |   1 +
 hw/tpm/tpm_passthrough.c     |  14 ++++++
 hw/tpm/tpm_tis.c             | 109 +++++++++++++++++++++++++++++++++++++++----
 hw/tpm/tpm_tis.h             |   1 +
 include/sysemu/tpm.h         |   7 +++
 include/sysemu/tpm_backend.h |  23 +++++++++
 7 files changed, 160 insertions(+), 9 deletions(-)

Comments

Michael S. Tsirkin April 14, 2015, 5:50 a.m. UTC | #1
On Tue, Mar 31, 2015 at 03:40:11PM -0400, Stefan Berger wrote:
> Following the recent upgrade to version 1.3, extend the TPM TIS
> interface with capabilities introduced for support of a TPM 2.
> 
> TPM TIS for TPM 2 introduced the following extensions beyond the
> TPM TIS 1.3 (used for TPM 1.2):
> 
> - A new 32bit interface Id register was introduced.
> - New flags for the status (STS) register were defined.
> - New flags for the capability flags were defined.
> 
> Support the above if a TPM TIS 1.3 for TPM 2 is used with a TPM 2
> on the backend side. Support the old TPM TIS 1.3 configuration if a
> TPM 1.2 is being used. A subsequent patch will then determine which
> TPM version is being used in the backend.
> 
> Signed-off-by: Stefan Berger <stefanb@linux.vnet.ibm.com>
> ---
>  backends/tpm.c               |  14 ++++++
>  hw/tpm/tpm_int.h             |   1 +
>  hw/tpm/tpm_passthrough.c     |  14 ++++++
>  hw/tpm/tpm_tis.c             | 109 +++++++++++++++++++++++++++++++++++++++----
>  hw/tpm/tpm_tis.h             |   1 +
>  include/sysemu/tpm.h         |   7 +++
>  include/sysemu/tpm_backend.h |  23 +++++++++
>  7 files changed, 160 insertions(+), 9 deletions(-)
> 
> diff --git a/backends/tpm.c b/backends/tpm.c
> index 4efe367..3ebb603 100644
> --- a/backends/tpm.c
> +++ b/backends/tpm.c
> @@ -96,6 +96,20 @@ bool tpm_backend_get_tpm_established_flag(TPMBackend *s)
>      return k->ops->get_tpm_established_flag(s);
>  }
>  
> +int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty)
> +{
> +    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
> +
> +    return k->ops->reset_tpm_established_flag(s, locty);
> +}
> +
> +enum TPMVersion tpm_backend_get_tpm_version(TPMBackend *s)


use typedef without enum pls

> +{
> +    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
> +
> +    return k->ops->get_tpm_version(s);
> +}
> +
>  static bool tpm_backend_prop_get_opened(Object *obj, Error **errp)
>  {
>      TPMBackend *s = TPM_BACKEND(obj);
> diff --git a/hw/tpm/tpm_int.h b/hw/tpm/tpm_int.h
> index 2b35fe2..24e12ce 100644
> --- a/hw/tpm/tpm_int.h
> +++ b/hw/tpm/tpm_int.h
> @@ -29,6 +29,7 @@ struct TPMState {
>  
>      char *backend;
>      TPMBackend *be_driver;
> +    enum TPMVersion be_tpm_version;

same

>  };
>  
>  #define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
> diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
> index 73ca906..dd769a7 100644
> --- a/hw/tpm/tpm_passthrough.c
> +++ b/hw/tpm/tpm_passthrough.c
> @@ -267,6 +267,13 @@ static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb)
>      return false;
>  }
>  
> +static int tpm_passthrough_reset_tpm_established_flag(TPMBackend *tb,
> +                                                      uint8_t locty)
> +{
> +    /* only a TPM 2.0 will support this */
> +    return 0;
> +}
> +
>  static bool tpm_passthrough_get_startup_error(TPMBackend *tb)
>  {
>      TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
> @@ -324,6 +331,11 @@ static const char *tpm_passthrough_create_desc(void)
>      return "Passthrough TPM backend driver";
>  }
>  
> +static enum TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb)
> +{
> +    return TPMVersion1_2;
> +}
> +
>  /*
>   * A basic test of a TPM device. We expect a well formatted response header
>   * (error response is fine) within one second.
> @@ -540,6 +552,8 @@ static const TPMDriverOps tpm_passthrough_driver = {
>      .deliver_request          = tpm_passthrough_deliver_request,
>      .cancel_cmd               = tpm_passthrough_cancel_cmd,
>      .get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag,
> +    .reset_tpm_established_flag = tpm_passthrough_reset_tpm_established_flag,
> +    .get_tpm_version          = tpm_passthrough_get_tpm_version,
>  };
>  
>  static void tpm_passthrough_inst_init(Object *obj)
> diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c
> index 4b6d601..89e401d 100644
> --- a/hw/tpm/tpm_tis.c
> +++ b/hw/tpm/tpm_tis.c
> @@ -17,6 +17,9 @@
>   * supports version 1.3, 21 March 2013
>   * In the developers menu choose the PC Client section then find the TIS
>   * specification.
> + *
> + * TPM TIS for TPM 2 implementation following TCG PC Client Platform
> + * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43
>   */
>  
>  #include "sysemu/tpm_backend.h"
> @@ -49,6 +52,7 @@
>  #define TPM_TIS_REG_INTF_CAPABILITY       0x14
>  #define TPM_TIS_REG_STS                   0x18
>  #define TPM_TIS_REG_DATA_FIFO             0x24
> +#define TPM_TIS_REG_INTERFACE_ID          0x30
>  #define TPM_TIS_REG_DATA_XFIFO            0x80
>  #define TPM_TIS_REG_DATA_XFIFO_END        0xbc
>  #define TPM_TIS_REG_DID_VID               0xf00
> @@ -57,6 +61,12 @@
>  /* vendor-specific registers */
>  #define TPM_TIS_REG_DEBUG                 0xf90
>  
> +#define TPM_TIS_STS_TPM_FAMILY_MASK         (0x3 << 26)/* TPM 2.0 */
> +#define TPM_TIS_STS_TPM_FAMILY1_2           (0 << 26)  /* TPM 2.0 */
> +#define TPM_TIS_STS_TPM_FAMILY2_0           (1 << 26)  /* TPM 2.0 */
> +#define TPM_TIS_STS_RESET_ESTABLISHMENT_BIT (1 << 25)  /* TPM 2.0 */
> +#define TPM_TIS_STS_COMMAND_CANCEL          (1 << 24)  /* TPM 2.0 */
> +
>  #define TPM_TIS_STS_VALID                 (1 << 7)
>  #define TPM_TIS_STS_COMMAND_READY         (1 << 6)
>  #define TPM_TIS_STS_TPM_GO                (1 << 5)
> @@ -102,15 +112,42 @@
>  #endif
>  
>  #define TPM_TIS_CAP_INTERFACE_VERSION1_3 (2 << 28)
> +#define TPM_TIS_CAP_INTERFACE_VERSION1_3_FOR_TPM2_0 (3 << 28)
>  #define TPM_TIS_CAP_DATA_TRANSFER_64B    (3 << 9)
>  #define TPM_TIS_CAP_DATA_TRANSFER_LEGACY (0 << 9)
>  #define TPM_TIS_CAP_BURST_COUNT_DYNAMIC  (0 << 8)
>  #define TPM_TIS_CAP_INTERRUPT_LOW_LEVEL  (1 << 4) /* support is mandatory */
> -#define TPM_TIS_CAPABILITIES_SUPPORTED   (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
> -                                          TPM_TIS_CAP_BURST_COUNT_DYNAMIC | \
> -                                          TPM_TIS_CAP_DATA_TRANSFER_64B | \
> -                                          TPM_TIS_CAP_INTERFACE_VERSION1_3 | \
> -                                          TPM_TIS_INTERRUPTS_SUPPORTED)
> +#define TPM_TIS_CAPABILITIES_SUPPORTED1_3 \
> +    (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
> +     TPM_TIS_CAP_BURST_COUNT_DYNAMIC | \
> +     TPM_TIS_CAP_DATA_TRANSFER_64B | \
> +     TPM_TIS_CAP_INTERFACE_VERSION1_3 | \
> +     TPM_TIS_INTERRUPTS_SUPPORTED)
> +
> +#define TPM_TIS_CAPABILITIES_SUPPORTED2_0 \
> +    (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
> +     TPM_TIS_CAP_BURST_COUNT_DYNAMIC | \
> +     TPM_TIS_CAP_DATA_TRANSFER_64B | \
> +     TPM_TIS_CAP_INTERFACE_VERSION1_3_FOR_TPM2_0 | \
> +     TPM_TIS_INTERRUPTS_SUPPORTED)
> +
> +#define TPM_TIS_IFACE_ID_INTERFACE_TIS1_3   (0xf)     /* TPM 2.0 */
> +#define TPM_TIS_IFACE_ID_INTERFACE_FIFO     (0x0)     /* TPM 2.0 */
> +#define TPM_TIS_IFACE_ID_INTERFACE_VER_FIFO (0 << 4)  /* TPM 2.0 */
> +#define TPM_TIS_IFACE_ID_CAP_5_LOCALITIES   (1 << 8)  /* TPM 2.0 */
> +#define TPM_TIS_IFACE_ID_CAP_TIS_SUPPORTED  (1 << 13) /* TPM 2.0 */
> +#define TPM_TIS_IFACE_ID_INT_SEL_LOCK       (1 << 19) /* TPM 2.0 */
> +
> +#define TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3 \
> +    (TPM_TIS_IFACE_ID_INTERFACE_TIS1_3 | \
> +     (~0 << 4)/* all of it is don't care */)
> +
> +/* if backend was a TPM 2.0: */
> +#define TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0 \
> +    (TPM_TIS_IFACE_ID_INTERFACE_FIFO | \
> +     TPM_TIS_IFACE_ID_INTERFACE_VER_FIFO | \
> +     TPM_TIS_IFACE_ID_CAP_5_LOCALITIES | \
> +     TPM_TIS_IFACE_ID_CAP_TIS_SUPPORTED)
>  
>  #define TPM_TIS_TPM_DID       0x0001
>  #define TPM_TIS_TPM_VID       PCI_VENDOR_ID_IBM
> @@ -154,7 +191,8 @@ static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string)
>  
>  /*
>   * Set the given flags in the STS register by clearing the register but
> - * preserving the SELFTEST_DONE flag and then setting the new flags.
> + * preserving the SELFTEST_DONE and TPMFAMILY_MASK flags and then setting
> + * the new flags.
>   *
>   * The SELFTEST_DONE flag is acquired from the backend that determines it by
>   * peeking into TPM commands.
> @@ -166,7 +204,7 @@ static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string)
>   */
>  static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags)
>  {
> -    l->sts &= TPM_TIS_STS_SELFTEST_DONE;
> +    l->sts &= (TPM_TIS_STS_SELFTEST_DONE | TPM_TIS_STS_TPM_FAMILY_MASK);

no () to right of = please.

>      l->sts |= flags;
>  }
>  
> @@ -489,7 +527,17 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
>          val = tis->loc[locty].ints;
>          break;
>      case TPM_TIS_REG_INTF_CAPABILITY:
> -        val = TPM_TIS_CAPABILITIES_SUPPORTED;
> +        switch (s->be_tpm_version) {
> +        case TPMVersion_Unspec:
> +            val = 0;
> +            break;
> +        case TPMVersion1_2:
> +            val = TPM_TIS_CAPABILITIES_SUPPORTED1_3;
> +            break;
> +        case TPMVersion2_0:
> +            val = TPM_TIS_CAPABILITIES_SUPPORTED2_0;
> +            break;
> +        }
>          break;
>      case TPM_TIS_REG_STS:
>          if (tis->active_locty == locty) {
> @@ -536,6 +584,9 @@ static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
>              shift = 0; /* no more adjustments */
>          }
>          break;
> +    case TPM_TIS_REG_INTERFACE_ID:
> +        val = tis->loc[locty].iface_id;
> +        break;
>      case TPM_TIS_REG_DID_VID:
>          val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID;
>          break;
> @@ -736,6 +787,25 @@ static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,
>              break;
>          }
>  
> +        if (s->be_tpm_version == TPMVersion2_0) {
> +            /* some flags that are only supported for TPM 2 */
> +            if (val & TPM_TIS_STS_COMMAND_CANCEL) {
> +                if (tis->loc[locty].state == TPM_TIS_STATE_EXECUTION) {
> +                    /*
> +                     * request the backend to cancel. Some backends may not
> +                     * support it
> +                     */
> +                    tpm_backend_cancel_cmd(s->be_driver);
> +                }
> +            }
> +
> +            if (val & TPM_TIS_STS_RESET_ESTABLISHMENT_BIT) {
> +                if (locty == 3 || locty == 4) {
> +                    tpm_backend_reset_tpm_established_flag(s->be_driver, locty);
> +                }
> +            }
> +        }
> +
>          val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO |
>                  TPM_TIS_STS_RESPONSE_RETRY);
>  
> @@ -860,6 +930,14 @@ static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,
>              }
>          }
>          break;
> +        case TPM_TIS_REG_INTERFACE_ID:
> +            if (val & TPM_TIS_IFACE_ID_INT_SEL_LOCK) {
> +                for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
> +                    tis->loc[l].iface_id |= TPM_TIS_IFACE_ID_INT_SEL_LOCK;
> +                }
> +            }
> +
> +        break;
>      }
>  }
>  
> @@ -894,6 +972,8 @@ static void tpm_tis_reset(DeviceState *dev)
>      TPMTISEmuState *tis = &s->s.tis;
>      int c;
>  
> +    s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
> +
>      tpm_backend_reset(s->be_driver);
>  
>      tis->active_locty = TPM_TIS_NO_LOCALITY;
> @@ -902,7 +982,18 @@ static void tpm_tis_reset(DeviceState *dev)
>  
>      for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) {
>          tis->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS;
> -        tis->loc[c].sts = 0;
> +        switch (s->be_tpm_version) {
> +        case TPMVersion_Unspec:
> +            break;
> +        case TPMVersion1_2:
> +            tis->loc[c].sts = TPM_TIS_STS_TPM_FAMILY1_2;
> +            tis->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3;
> +            break;
> +        case TPMVersion2_0:
> +            tis->loc[c].sts = TPM_TIS_STS_TPM_FAMILY2_0;
> +            tis->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0;
> +            break;
> +        }
>          tis->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL;
>          tis->loc[c].ints = 0;
>          tis->loc[c].state = TPM_TIS_STATE_IDLE;
> diff --git a/hw/tpm/tpm_tis.h b/hw/tpm/tpm_tis.h
> index db78d51..a1df41f 100644
> --- a/hw/tpm/tpm_tis.h
> +++ b/hw/tpm/tpm_tis.h
> @@ -42,6 +42,7 @@ typedef struct TPMLocality {
>      TPMTISState state;
>      uint8_t access;
>      uint32_t sts;
> +    uint32_t iface_id;
>      uint32_t inte;
>      uint32_t ints;
>  
> diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h
> index 9b81ce9..9a77889 100644
> --- a/include/sysemu/tpm.h
> +++ b/include/sysemu/tpm.h
> @@ -20,6 +20,13 @@ int tpm_config_parse(QemuOptsList *opts_list, const char *optarg);
>  int tpm_init(void);
>  void tpm_cleanup(void);
>  
> +enum TPMVersion {
> +    TPMVersion_Unspec = 0,
> +    TPMVersion1_2 = 1,
> +    TPMVersion2_0 = 2,
> +};


needs a typedef

> +
> +

don't add two empty lines pls

>  #define TYPE_TPM_TIS                "tpm-tis"
>  
>  static inline bool tpm_find(void)
> diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h
> index 540ee25..cbe064f 100644
> --- a/include/sysemu/tpm_backend.h
> +++ b/include/sysemu/tpm_backend.h
> @@ -88,6 +88,10 @@ struct TPMDriverOps {
>      void (*cancel_cmd)(TPMBackend *t);
>  
>      bool (*get_tpm_established_flag)(TPMBackend *t);
> +
> +    int (*reset_tpm_established_flag)(TPMBackend *t, uint8_t locty);
> +
> +    enum TPMVersion (*get_tpm_version)(TPMBackend *t);


drop enum

>  };
>  
>  
> @@ -192,6 +196,15 @@ void tpm_backend_cancel_cmd(TPMBackend *s);
>  bool tpm_backend_get_tpm_established_flag(TPMBackend *s);
>  
>  /**
> + * tpm_backend_reset_tpm_established_flag:
> + * @s: the backend
> + * @locty: the locality number
> + *
> + * Reset the TPM establishment flag.
> + */
> +int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty);
> +
> +/**
>   * tpm_backend_open:
>   * @s: the backend to open
>   * @errp: a pointer to return the #Error object if an error occurs.
> @@ -201,6 +214,16 @@ bool tpm_backend_get_tpm_established_flag(TPMBackend *s);
>   */
>  void tpm_backend_open(TPMBackend *s, Error **errp);
>  
> +/**
> + * tpm_backend_get_tpm_version:
> + * @s: the backend to call into
> + *
> + * Get the TPM Version that is emulated at the backend.
> + *
> + * Returns an enum TPMVersion.
> + */
> +enum TPMVersion tpm_backend_get_tpm_version(TPMBackend *s);
> +

same

>  TPMBackend *qemu_find_tpm(const char *id);
>  
>  const TPMDriverOps *tpm_get_backend_driver(const char *type);
> -- 
> 1.9.3
diff mbox

Patch

diff --git a/backends/tpm.c b/backends/tpm.c
index 4efe367..3ebb603 100644
--- a/backends/tpm.c
+++ b/backends/tpm.c
@@ -96,6 +96,20 @@  bool tpm_backend_get_tpm_established_flag(TPMBackend *s)
     return k->ops->get_tpm_established_flag(s);
 }
 
+int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty)
+{
+    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+    return k->ops->reset_tpm_established_flag(s, locty);
+}
+
+enum TPMVersion tpm_backend_get_tpm_version(TPMBackend *s)
+{
+    TPMBackendClass *k = TPM_BACKEND_GET_CLASS(s);
+
+    return k->ops->get_tpm_version(s);
+}
+
 static bool tpm_backend_prop_get_opened(Object *obj, Error **errp)
 {
     TPMBackend *s = TPM_BACKEND(obj);
diff --git a/hw/tpm/tpm_int.h b/hw/tpm/tpm_int.h
index 2b35fe2..24e12ce 100644
--- a/hw/tpm/tpm_int.h
+++ b/hw/tpm/tpm_int.h
@@ -29,6 +29,7 @@  struct TPMState {
 
     char *backend;
     TPMBackend *be_driver;
+    enum TPMVersion be_tpm_version;
 };
 
 #define TPM(obj) OBJECT_CHECK(TPMState, (obj), TYPE_TPM_TIS)
diff --git a/hw/tpm/tpm_passthrough.c b/hw/tpm/tpm_passthrough.c
index 73ca906..dd769a7 100644
--- a/hw/tpm/tpm_passthrough.c
+++ b/hw/tpm/tpm_passthrough.c
@@ -267,6 +267,13 @@  static bool tpm_passthrough_get_tpm_established_flag(TPMBackend *tb)
     return false;
 }
 
+static int tpm_passthrough_reset_tpm_established_flag(TPMBackend *tb,
+                                                      uint8_t locty)
+{
+    /* only a TPM 2.0 will support this */
+    return 0;
+}
+
 static bool tpm_passthrough_get_startup_error(TPMBackend *tb)
 {
     TPMPassthruState *tpm_pt = TPM_PASSTHROUGH(tb);
@@ -324,6 +331,11 @@  static const char *tpm_passthrough_create_desc(void)
     return "Passthrough TPM backend driver";
 }
 
+static enum TPMVersion tpm_passthrough_get_tpm_version(TPMBackend *tb)
+{
+    return TPMVersion1_2;
+}
+
 /*
  * A basic test of a TPM device. We expect a well formatted response header
  * (error response is fine) within one second.
@@ -540,6 +552,8 @@  static const TPMDriverOps tpm_passthrough_driver = {
     .deliver_request          = tpm_passthrough_deliver_request,
     .cancel_cmd               = tpm_passthrough_cancel_cmd,
     .get_tpm_established_flag = tpm_passthrough_get_tpm_established_flag,
+    .reset_tpm_established_flag = tpm_passthrough_reset_tpm_established_flag,
+    .get_tpm_version          = tpm_passthrough_get_tpm_version,
 };
 
 static void tpm_passthrough_inst_init(Object *obj)
diff --git a/hw/tpm/tpm_tis.c b/hw/tpm/tpm_tis.c
index 4b6d601..89e401d 100644
--- a/hw/tpm/tpm_tis.c
+++ b/hw/tpm/tpm_tis.c
@@ -17,6 +17,9 @@ 
  * supports version 1.3, 21 March 2013
  * In the developers menu choose the PC Client section then find the TIS
  * specification.
+ *
+ * TPM TIS for TPM 2 implementation following TCG PC Client Platform
+ * TPM Profile (PTP) Specification, Familiy 2.0, Revision 00.43
  */
 
 #include "sysemu/tpm_backend.h"
@@ -49,6 +52,7 @@ 
 #define TPM_TIS_REG_INTF_CAPABILITY       0x14
 #define TPM_TIS_REG_STS                   0x18
 #define TPM_TIS_REG_DATA_FIFO             0x24
+#define TPM_TIS_REG_INTERFACE_ID          0x30
 #define TPM_TIS_REG_DATA_XFIFO            0x80
 #define TPM_TIS_REG_DATA_XFIFO_END        0xbc
 #define TPM_TIS_REG_DID_VID               0xf00
@@ -57,6 +61,12 @@ 
 /* vendor-specific registers */
 #define TPM_TIS_REG_DEBUG                 0xf90
 
+#define TPM_TIS_STS_TPM_FAMILY_MASK         (0x3 << 26)/* TPM 2.0 */
+#define TPM_TIS_STS_TPM_FAMILY1_2           (0 << 26)  /* TPM 2.0 */
+#define TPM_TIS_STS_TPM_FAMILY2_0           (1 << 26)  /* TPM 2.0 */
+#define TPM_TIS_STS_RESET_ESTABLISHMENT_BIT (1 << 25)  /* TPM 2.0 */
+#define TPM_TIS_STS_COMMAND_CANCEL          (1 << 24)  /* TPM 2.0 */
+
 #define TPM_TIS_STS_VALID                 (1 << 7)
 #define TPM_TIS_STS_COMMAND_READY         (1 << 6)
 #define TPM_TIS_STS_TPM_GO                (1 << 5)
@@ -102,15 +112,42 @@ 
 #endif
 
 #define TPM_TIS_CAP_INTERFACE_VERSION1_3 (2 << 28)
+#define TPM_TIS_CAP_INTERFACE_VERSION1_3_FOR_TPM2_0 (3 << 28)
 #define TPM_TIS_CAP_DATA_TRANSFER_64B    (3 << 9)
 #define TPM_TIS_CAP_DATA_TRANSFER_LEGACY (0 << 9)
 #define TPM_TIS_CAP_BURST_COUNT_DYNAMIC  (0 << 8)
 #define TPM_TIS_CAP_INTERRUPT_LOW_LEVEL  (1 << 4) /* support is mandatory */
-#define TPM_TIS_CAPABILITIES_SUPPORTED   (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
-                                          TPM_TIS_CAP_BURST_COUNT_DYNAMIC | \
-                                          TPM_TIS_CAP_DATA_TRANSFER_64B | \
-                                          TPM_TIS_CAP_INTERFACE_VERSION1_3 | \
-                                          TPM_TIS_INTERRUPTS_SUPPORTED)
+#define TPM_TIS_CAPABILITIES_SUPPORTED1_3 \
+    (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
+     TPM_TIS_CAP_BURST_COUNT_DYNAMIC | \
+     TPM_TIS_CAP_DATA_TRANSFER_64B | \
+     TPM_TIS_CAP_INTERFACE_VERSION1_3 | \
+     TPM_TIS_INTERRUPTS_SUPPORTED)
+
+#define TPM_TIS_CAPABILITIES_SUPPORTED2_0 \
+    (TPM_TIS_CAP_INTERRUPT_LOW_LEVEL | \
+     TPM_TIS_CAP_BURST_COUNT_DYNAMIC | \
+     TPM_TIS_CAP_DATA_TRANSFER_64B | \
+     TPM_TIS_CAP_INTERFACE_VERSION1_3_FOR_TPM2_0 | \
+     TPM_TIS_INTERRUPTS_SUPPORTED)
+
+#define TPM_TIS_IFACE_ID_INTERFACE_TIS1_3   (0xf)     /* TPM 2.0 */
+#define TPM_TIS_IFACE_ID_INTERFACE_FIFO     (0x0)     /* TPM 2.0 */
+#define TPM_TIS_IFACE_ID_INTERFACE_VER_FIFO (0 << 4)  /* TPM 2.0 */
+#define TPM_TIS_IFACE_ID_CAP_5_LOCALITIES   (1 << 8)  /* TPM 2.0 */
+#define TPM_TIS_IFACE_ID_CAP_TIS_SUPPORTED  (1 << 13) /* TPM 2.0 */
+#define TPM_TIS_IFACE_ID_INT_SEL_LOCK       (1 << 19) /* TPM 2.0 */
+
+#define TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3 \
+    (TPM_TIS_IFACE_ID_INTERFACE_TIS1_3 | \
+     (~0 << 4)/* all of it is don't care */)
+
+/* if backend was a TPM 2.0: */
+#define TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0 \
+    (TPM_TIS_IFACE_ID_INTERFACE_FIFO | \
+     TPM_TIS_IFACE_ID_INTERFACE_VER_FIFO | \
+     TPM_TIS_IFACE_ID_CAP_5_LOCALITIES | \
+     TPM_TIS_IFACE_ID_CAP_TIS_SUPPORTED)
 
 #define TPM_TIS_TPM_DID       0x0001
 #define TPM_TIS_TPM_VID       PCI_VENDOR_ID_IBM
@@ -154,7 +191,8 @@  static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string)
 
 /*
  * Set the given flags in the STS register by clearing the register but
- * preserving the SELFTEST_DONE flag and then setting the new flags.
+ * preserving the SELFTEST_DONE and TPMFAMILY_MASK flags and then setting
+ * the new flags.
  *
  * The SELFTEST_DONE flag is acquired from the backend that determines it by
  * peeking into TPM commands.
@@ -166,7 +204,7 @@  static void tpm_tis_show_buffer(const TPMSizedBuffer *sb, const char *string)
  */
 static void tpm_tis_sts_set(TPMLocality *l, uint32_t flags)
 {
-    l->sts &= TPM_TIS_STS_SELFTEST_DONE;
+    l->sts &= (TPM_TIS_STS_SELFTEST_DONE | TPM_TIS_STS_TPM_FAMILY_MASK);
     l->sts |= flags;
 }
 
@@ -489,7 +527,17 @@  static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
         val = tis->loc[locty].ints;
         break;
     case TPM_TIS_REG_INTF_CAPABILITY:
-        val = TPM_TIS_CAPABILITIES_SUPPORTED;
+        switch (s->be_tpm_version) {
+        case TPMVersion_Unspec:
+            val = 0;
+            break;
+        case TPMVersion1_2:
+            val = TPM_TIS_CAPABILITIES_SUPPORTED1_3;
+            break;
+        case TPMVersion2_0:
+            val = TPM_TIS_CAPABILITIES_SUPPORTED2_0;
+            break;
+        }
         break;
     case TPM_TIS_REG_STS:
         if (tis->active_locty == locty) {
@@ -536,6 +584,9 @@  static uint64_t tpm_tis_mmio_read(void *opaque, hwaddr addr,
             shift = 0; /* no more adjustments */
         }
         break;
+    case TPM_TIS_REG_INTERFACE_ID:
+        val = tis->loc[locty].iface_id;
+        break;
     case TPM_TIS_REG_DID_VID:
         val = (TPM_TIS_TPM_DID << 16) | TPM_TIS_TPM_VID;
         break;
@@ -736,6 +787,25 @@  static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,
             break;
         }
 
+        if (s->be_tpm_version == TPMVersion2_0) {
+            /* some flags that are only supported for TPM 2 */
+            if (val & TPM_TIS_STS_COMMAND_CANCEL) {
+                if (tis->loc[locty].state == TPM_TIS_STATE_EXECUTION) {
+                    /*
+                     * request the backend to cancel. Some backends may not
+                     * support it
+                     */
+                    tpm_backend_cancel_cmd(s->be_driver);
+                }
+            }
+
+            if (val & TPM_TIS_STS_RESET_ESTABLISHMENT_BIT) {
+                if (locty == 3 || locty == 4) {
+                    tpm_backend_reset_tpm_established_flag(s->be_driver, locty);
+                }
+            }
+        }
+
         val &= (TPM_TIS_STS_COMMAND_READY | TPM_TIS_STS_TPM_GO |
                 TPM_TIS_STS_RESPONSE_RETRY);
 
@@ -860,6 +930,14 @@  static void tpm_tis_mmio_write_intern(void *opaque, hwaddr addr,
             }
         }
         break;
+        case TPM_TIS_REG_INTERFACE_ID:
+            if (val & TPM_TIS_IFACE_ID_INT_SEL_LOCK) {
+                for (l = 0; l < TPM_TIS_NUM_LOCALITIES; l++) {
+                    tis->loc[l].iface_id |= TPM_TIS_IFACE_ID_INT_SEL_LOCK;
+                }
+            }
+
+        break;
     }
 }
 
@@ -894,6 +972,8 @@  static void tpm_tis_reset(DeviceState *dev)
     TPMTISEmuState *tis = &s->s.tis;
     int c;
 
+    s->be_tpm_version = tpm_backend_get_tpm_version(s->be_driver);
+
     tpm_backend_reset(s->be_driver);
 
     tis->active_locty = TPM_TIS_NO_LOCALITY;
@@ -902,7 +982,18 @@  static void tpm_tis_reset(DeviceState *dev)
 
     for (c = 0; c < TPM_TIS_NUM_LOCALITIES; c++) {
         tis->loc[c].access = TPM_TIS_ACCESS_TPM_REG_VALID_STS;
-        tis->loc[c].sts = 0;
+        switch (s->be_tpm_version) {
+        case TPMVersion_Unspec:
+            break;
+        case TPMVersion1_2:
+            tis->loc[c].sts = TPM_TIS_STS_TPM_FAMILY1_2;
+            tis->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS1_3;
+            break;
+        case TPMVersion2_0:
+            tis->loc[c].sts = TPM_TIS_STS_TPM_FAMILY2_0;
+            tis->loc[c].iface_id = TPM_TIS_IFACE_ID_SUPPORTED_FLAGS2_0;
+            break;
+        }
         tis->loc[c].inte = TPM_TIS_INT_POLARITY_LOW_LEVEL;
         tis->loc[c].ints = 0;
         tis->loc[c].state = TPM_TIS_STATE_IDLE;
diff --git a/hw/tpm/tpm_tis.h b/hw/tpm/tpm_tis.h
index db78d51..a1df41f 100644
--- a/hw/tpm/tpm_tis.h
+++ b/hw/tpm/tpm_tis.h
@@ -42,6 +42,7 @@  typedef struct TPMLocality {
     TPMTISState state;
     uint8_t access;
     uint32_t sts;
+    uint32_t iface_id;
     uint32_t inte;
     uint32_t ints;
 
diff --git a/include/sysemu/tpm.h b/include/sysemu/tpm.h
index 9b81ce9..9a77889 100644
--- a/include/sysemu/tpm.h
+++ b/include/sysemu/tpm.h
@@ -20,6 +20,13 @@  int tpm_config_parse(QemuOptsList *opts_list, const char *optarg);
 int tpm_init(void);
 void tpm_cleanup(void);
 
+enum TPMVersion {
+    TPMVersion_Unspec = 0,
+    TPMVersion1_2 = 1,
+    TPMVersion2_0 = 2,
+};
+
+
 #define TYPE_TPM_TIS                "tpm-tis"
 
 static inline bool tpm_find(void)
diff --git a/include/sysemu/tpm_backend.h b/include/sysemu/tpm_backend.h
index 540ee25..cbe064f 100644
--- a/include/sysemu/tpm_backend.h
+++ b/include/sysemu/tpm_backend.h
@@ -88,6 +88,10 @@  struct TPMDriverOps {
     void (*cancel_cmd)(TPMBackend *t);
 
     bool (*get_tpm_established_flag)(TPMBackend *t);
+
+    int (*reset_tpm_established_flag)(TPMBackend *t, uint8_t locty);
+
+    enum TPMVersion (*get_tpm_version)(TPMBackend *t);
 };
 
 
@@ -192,6 +196,15 @@  void tpm_backend_cancel_cmd(TPMBackend *s);
 bool tpm_backend_get_tpm_established_flag(TPMBackend *s);
 
 /**
+ * tpm_backend_reset_tpm_established_flag:
+ * @s: the backend
+ * @locty: the locality number
+ *
+ * Reset the TPM establishment flag.
+ */
+int tpm_backend_reset_tpm_established_flag(TPMBackend *s, uint8_t locty);
+
+/**
  * tpm_backend_open:
  * @s: the backend to open
  * @errp: a pointer to return the #Error object if an error occurs.
@@ -201,6 +214,16 @@  bool tpm_backend_get_tpm_established_flag(TPMBackend *s);
  */
 void tpm_backend_open(TPMBackend *s, Error **errp);
 
+/**
+ * tpm_backend_get_tpm_version:
+ * @s: the backend to call into
+ *
+ * Get the TPM Version that is emulated at the backend.
+ *
+ * Returns an enum TPMVersion.
+ */
+enum TPMVersion tpm_backend_get_tpm_version(TPMBackend *s);
+
 TPMBackend *qemu_find_tpm(const char *id);
 
 const TPMDriverOps *tpm_get_backend_driver(const char *type);