Index: /trunk/include/VBox/vmm/pdmtpmifs.h
===================================================================
--- /trunk/include/VBox/vmm/pdmtpmifs.h	(revision 90512)
+++ /trunk/include/VBox/vmm/pdmtpmifs.h	(revision 90512)
@@ -0,0 +1,145 @@
+/** @file
+ * PDM - Pluggable Device Manager, TPM related interfaces.
+ */
+
+/*
+ * Copyright (C) 2021 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+#ifndef VBOX_INCLUDED_vmm_pdmtpmifs_h
+#define VBOX_INCLUDED_vmm_pdmtpmifs_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <VBox/types.h>
+
+RT_C_DECLS_BEGIN
+
+/** @defgroup grp_pdm_ifs_serial       PDM TPM Interfaces
+ * @ingroup grp_pdm_interfaces
+ * @{
+ */
+
+
+/** Pointer to a TPM port interface. */
+typedef struct PDMITPMPORT *PPDMITPMPORT;
+/**
+ * TPM port interface (down).
+ */
+typedef struct PDMITPMPORT
+{
+    /**
+     * @todo
+     */
+    DECLR3CALLBACKMEMBER(int, pfnDummy, (PPDMITPMPORT pInterface));
+
+} PDMITPMPORT;
+/** PDMITPMPORT interface ID. */
+#define PDMITPMPORT_IID                       "1e57710f-f820-47ec-afa6-2713195f8f94"
+
+
+/** Pointer to a TPM interface. */
+typedef struct PDMITPMCONNECTOR *PPDMITPMCONNECTOR;
+/**
+ * TPM interface (up).
+ * Pairs with PDMITPMPORT.
+ */
+typedef struct PDMITPMCONNECTOR
+{
+    /**
+     * Starts the TPM.
+     *
+     * @returns VBox status code.
+     * @param   pInterface          Pointer to the interface structure containing the called function pointer.
+     * @param   cbCmdResp           Size of the command/response buffer.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnStartup, (PPDMITPMCONNECTOR pInterface, size_t cbCmdResp));
+
+    /**
+     * Shuts down the TPM.
+     *
+     * @returns VBox status code.
+     * @param   pInterface          Pointer to the interface structure containing the called function pointer.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnShutdown, (PPDMITPMCONNECTOR pInterface));
+
+    /**
+     * Resets the TPM.
+     *
+     * @returns VBox status code.
+     * @param   pInterface          Pointer to the interface structure containing the called function pointer.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnReset, (PPDMITPMCONNECTOR pInterface));
+
+    /**
+     * Returns the version of the TPM implemented by the driver below.
+     *
+     * @returns The TPM version.
+     * @param   pInterface          Pointer to the interface structure containing the called function pointer.
+     */
+    DECLR3CALLBACKMEMBER(uint32_t, pfnGetVersion, (PPDMITPMCONNECTOR pInterface));
+
+    /**
+     * Returns the status of the established flag.
+     *
+     * @returns Status of the established flag.
+     * @param   pInterface          Pointer to the interface structure containing the called function pointer.
+     */
+    DECLR3CALLBACKMEMBER(bool, pfnGetEstablishedFlag, (PPDMITPMCONNECTOR pInterface));
+
+    /**
+     * Resets the TPM established flag.
+     *
+     * @returns VBox status code.
+     * @param   pInterface          Pointer to the interface structure containing the called function pointer.
+     * @param   bLoc                The locality issuing this request.
+     */
+    DECLR3CALLBACKMEMBER(int, pfnResetEstablishedFlag, (PPDMITPMCONNECTOR pInterface, uint8_t bLoc));
+
+    /**
+     * Executes the given command.
+     *
+     * @returns Status of the established flag.
+     * @param   pInterface          Pointer to the interface structure containing the called function pointer.
+     * @param   pvCmd               Pointer to the command data.
+     * @param   cbCmd               Size of the command in bytes.
+     * @param   pvResp              Where to store the response data.
+     * @param   cbResp              Size of the response buffer in bytes.
+     */
+    DECLR3CALLBACKMEMBER(bool, pfnCmdExec, (PPDMITPMCONNECTOR pInterface, const void *pvCmd, size_t cbCmd, void *pvResp, size_t cbResp));
+
+    /**
+     * Cancels the currently executed command.
+     *
+     * @returns Status of the established flag.
+     * @param   pInterface          Pointer to the interface structure containing the called function pointer.
+     */
+    DECLR3CALLBACKMEMBER(bool, pfnCmdCancel, (PPDMITPMCONNECTOR pInterface));
+
+} PDMITPMCONNECTOR;
+/** PDMITPMCONNECTOR interface ID. */
+#define PDMITPMCONNECTOR_IID                  "30afefd8-c11f-4e2a-a746-424e3d99fa86"
+
+/** @} */
+
+RT_C_DECLS_END
+
+#endif /* !VBOX_INCLUDED_vmm_pdmtpmifs_h */
Index: /trunk/src/VBox/Devices/Security/DevTpm.cpp
===================================================================
--- /trunk/src/VBox/Devices/Security/DevTpm.cpp	(revision 90511)
+++ /trunk/src/VBox/Devices/Security/DevTpm.cpp	(revision 90512)
@@ -25,6 +25,8 @@
 #define LOG_GROUP LOG_GROUP_DEFAULT /** @todo DEV_TPM */
 #include <VBox/vmm/pdmdev.h>
+#include <VBox/vmm/pdmtpmifs.h>
 #include <iprt/assert.h>
 #include <iprt/string.h>
+#include <iprt/uuid.h>
 
 #include "VBoxDD.h"
@@ -55,144 +57,301 @@
 #define TPM_LOCALITY_MMIO_SIZE                          0x1000
 
-/** @name TPM locality register related defines.
+/** @name TPM locality register related defines for the FIFO interface.
  * @{ */
 /** Ownership management for a particular locality. */
-#define TPM_LOCALITY_REG_ACCESS                         0x00
-/** INdicates whether a dynamic OS has been established on this platform before.. */
-# define TPM_LOCALITY_REG_ESTABLISHMENT                 RT_BIT(0)
+#define TPM_FIFO_LOCALITY_REG_ACCESS                         0x00
+/** Indicates whether a dynamic OS has been established on this platform before.. */
+# define TPM_FIFO_LOCALITY_REG_ESTABLISHMENT                 RT_BIT(0)
 /** On reads indicates whether the locality requests use of the TPM (1) or not or is already active locality (0),
  * writing a 1 requests the locality to be granted getting the active locality.. */
-# define TPM_LOCALITY_REG_REQUEST_USE                   RT_BIT(1)
+# define TPM_FIFO_LOCALITY_REG_REQUEST_USE                   RT_BIT(1)
 /** Indicates whether another locality is requesting usage of the TPM. */
-# define TPM_LOCALITY_REG_PENDING_REQUEST               RT_BIT(2)
+# define TPM_FIFO_LOCALITY_REG_PENDING_REQUEST               RT_BIT(2)
 /** Writing a 1 forces the TPM to give control to the locality if it has a higher priority. */
-# define TPM_LOCALITY_REG_ACCESS_SEIZE                  RT_BIT(3)
+# define TPM_FIFO_LOCALITY_REG_ACCESS_SEIZE                  RT_BIT(3)
 /** On reads indicates whether this locality has been seized by a higher locality (1) or not (0), writing a 1 clears this bit. */
-# define TPM_LOCALITY_REG_ACCESS_BEEN_SEIZED            RT_BIT(4)
+# define TPM_FIFO_LOCALITY_REG_ACCESS_BEEN_SEIZED            RT_BIT(4)
 /** On reads indicates whether this locality is active (1) or not (0), writing a 1 relinquishes control for this locality. */
-# define TPM_LOCALITY_REG_ACCESS_ACTIVE                 RT_BIT(5)
+# define TPM_FIFO_LOCALITY_REG_ACCESS_ACTIVE                 RT_BIT(5)
 /** Set bit indicates whether all other bits in this register have valid data. */
-# define TPM_LOCALITY_REG_ACCESS_VALID                  RT_BIT(7)
+# define TPM_FIFO_LOCALITY_REG_ACCESS_VALID                  RT_BIT(7)
 /** Writable mask. */
-# define TPM_LOCALITY_REG_ACCESS_WR_MASK                0x3a
+# define TPM_FIFO_LOCALITY_REG_ACCESS_WR_MASK                0x3a
 
 /** Interrupt enable register. */
-#define TPM_LOCALITY_REG_INT_ENABLE                     0x08
+#define TPM_FIFO_LOCALITY_REG_INT_ENABLE                     0x08
 /** Data available interrupt enable bit. */
-# define TPM_LOCALITY_REG_INT_ENABLE_DATA_AVAIL         RT_BIT_32(0)
+# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_DATA_AVAIL         RT_BIT_32(0)
 /** Status valid interrupt enable bit. */
-# define TPM_LOCALITY_REG_INT_ENABLE_STS_VALID          RT_BIT_32(1)
+# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_STS_VALID          RT_BIT_32(1)
 /** Locality change interrupt enable bit. */
-# define TPM_LOCALITY_REG_INT_ENABLE_LOCALITY_CHANGE    RT_BIT_32(2)
+# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_LOCALITY_CHANGE    RT_BIT_32(2)
 /** Interrupt polarity configuration. */
-# define TPM_LOCALITY_REG_INT_ENABLE_POLARITY_MASK      0x18
-# define TPM_LOCALITY_REG_INT_ENABLE_POLARITY_SHIFT     3
-# define TPM_LOCALITY_REG_INT_ENABLE_POLARITY_SET(a)    ((a) << TPM_LOCALITY_REG_INT_POLARITY_SHIFT)
-# define TPM_LOCALITY_REG_INT_ENABLE_POLARITY_GET(a)    (((a) & TPM_LOCALITY_REG_INT_POLARITY_MASK) >> TPM_LOCALITY_REG_INT_POLARITY_SHIFT)
+# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_MASK      0x18
+# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_SHIFT     3
+# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_SET(a)    ((a) << TPM_FIFO_LOCALITY_REG_INT_POLARITY_SHIFT)
+# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_GET(a)    (((a) & TPM_FIFO_LOCALITY_REG_INT_POLARITY_MASK) >> TPM_FIFO_LOCALITY_REG_INT_POLARITY_SHIFT)
 /** High level interrupt trigger. */
-#  define TPM_LOCALITY_REG_INT_ENABLE_POLARITY_HIGH     0
+#  define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_HIGH     0
 /** Low level interrupt trigger. */
-#  define TPM_LOCALITY_REG_INT_ENABLE_POLARITY_LOW      1
+#  define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_LOW      1
 /** Rising edge interrupt trigger. */
-#  define TPM_LOCALITY_REG_INT_ENABLE_POLARITY_RISING   2
+#  define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_RISING   2
 /** Falling edge interrupt trigger. */
-#  define TPM_LOCALITY_REG_INT_ENABLE_POLARITY_FALLING  3
+#  define TPM_FIFO_LOCALITY_REG_INT_ENABLE_POLARITY_FALLING  3
 /** Command ready enable bit. */
-# define TPM_LOCALITY_REG_INT_ENABLE_CMD_RDY            RT_BIT_32(7)
+# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_CMD_RDY            RT_BIT_32(7)
 /** Global interrupt enable/disable bit. */
-# define TPM_LOCALITY_REG_INT_ENABLE_GLOBAL             RT_BIT_32(31)
+# define TPM_FIFO_LOCALITY_REG_INT_ENABLE_GLOBAL             RT_BIT_32(31)
 
 /** Configured interrupt vector register. */
-#define TPM_LOCALITY_REG_INT_VEC                        0x0c
+#define TPM_FIFO_LOCALITY_REG_INT_VEC                        0x0c
 
 /** Interrupt status register. */
-#define TPM_LOCALITY_REG_INT_STS                        0x10
+#define TPM_FIFO_LOCALITY_REG_INT_STS                        0x10
 /** Data available interrupt occured bit, writing a 1 clears the bit. */
-# define TPM_LOCALITY_REG_INT_STS_DATA_AVAIL            RT_BIT_32(0)
+# define TPM_FIFO_LOCALITY_REG_INT_STS_DATA_AVAIL            RT_BIT_32(0)
 /** Status valid interrupt occured bit, writing a 1 clears the bit. */
-# define TPM_LOCALITY_REG_INT_STS_STS_VALID             RT_BIT_32(1)
+# define TPM_FIFO_LOCALITY_REG_INT_STS_STS_VALID             RT_BIT_32(1)
 /** Locality change interrupt occured bit, writing a 1 clears the bit. */
-# define TPM_LOCALITY_REG_INT_STS_LOCALITY_CHANGE       RT_BIT_32(2)
+# define TPM_FIFO_LOCALITY_REG_INT_STS_LOCALITY_CHANGE       RT_BIT_32(2)
 /** Command ready occured bit, writing a 1 clears the bit. */
-# define TPM_LOCALITY_REG_INT_STS_CMD_RDY               RT_BIT_32(7)
+# define TPM_FIFO_LOCALITY_REG_INT_STS_CMD_RDY               RT_BIT_32(7)
 /** Writable mask. */
-# define TPM_LOCALITY_REG_INT_STS_WR_MASK               UINT32_C(0x87)
+# define TPM_FIFO_LOCALITY_REG_INT_STS_WR_MASK               UINT32_C(0x87)
 
 /** Interfacce capabilities register. */
-#define TPM_LOCALITY_REG_IF_CAP                         0x14
+#define TPM_FIFO_LOCALITY_REG_IF_CAP                         0x14
 /** Flag whether the TPM supports the data avilable interrupt. */
-# define TPM_LOCALITY_REG_IF_CAP_INT_DATA_AVAIL         RT_BIT(0)
+# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_DATA_AVAIL         RT_BIT(0)
 /** Flag whether the TPM supports the status valid interrupt. */
-# define TPM_LOCALITY_REG_IF_CAP_INT_STS_VALID          RT_BIT(1)
+# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_STS_VALID          RT_BIT(1)
 /** Flag whether the TPM supports the data avilable interrupt. */
-# define TPM_LOCALITY_REG_IF_CAP_INT_LOCALITY_CHANGE    RT_BIT(2)
+# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_LOCALITY_CHANGE    RT_BIT(2)
 /** Flag whether the TPM supports high level interrupts. */
-# define TPM_LOCALITY_REG_IF_CAP_INT_LVL_HIGH           RT_BIT(3)
+# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_LVL_HIGH           RT_BIT(3)
 /** Flag whether the TPM supports low level interrupts. */
-# define TPM_LOCALITY_REG_IF_CAP_INT_LVL_LOW            RT_BIT(4)
+# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_LVL_LOW            RT_BIT(4)
 /** Flag whether the TPM supports rising edge interrupts. */
-# define TPM_LOCALITY_REG_IF_CAP_INT_RISING_EDGE        RT_BIT(5)
+# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_RISING_EDGE        RT_BIT(5)
 /** Flag whether the TPM supports falling edge interrupts. */
-# define TPM_LOCALITY_REG_IF_CAP_INT_FALLING_EDGE       RT_BIT(6)
+# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_FALLING_EDGE       RT_BIT(6)
 /** Flag whether the TPM supports the command ready interrupt. */
-# define TPM_LOCALITY_REG_IF_CAP_INT_CMD_RDY            RT_BIT(7)
+# define TPM_FIFO_LOCALITY_REG_IF_CAP_INT_CMD_RDY            RT_BIT(7)
 /** Flag whether the busrt count field is static or dynamic. */
-# define TPM_LOCALITY_REG_IF_CAP_BURST_CNT_STATIC       RT_BIT(8)
+# define TPM_FIFO_LOCALITY_REG_IF_CAP_BURST_CNT_STATIC       RT_BIT(8)
 /** Maximum transfer size support. */
-# define TPM_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_MASK      0x600
-# define TPM_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_SHIFT     9
-# define TPM_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_SET(a)    ((a) << TPM_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_SHIFT)
+# define TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_MASK      0x600
+# define TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_SHIFT     9
+# define TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_SET(a)    ((a) << TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_SHIFT)
 /** Only legacy transfers supported. */
-#  define TPM_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_LEGACY   0x0
+#  define TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_LEGACY   0x0
 /** 8B maximum transfer size. */
-#  define TPM_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_8B       0x1
+#  define TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_8B       0x1
 /** 32B maximum transfer size. */
-#  define TPM_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_32B      0x2
+#  define TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_32B      0x2
 /** 64B maximum transfer size. */
-#  define TPM_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_64B      0x3
+#  define TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_64B      0x3
 /** Interface version. */
-# define TPM_LOCALITY_REG_IF_CAP_IF_VERSION_MASK        UINT32_C(0x70000000)
-# define TPM_LOCALITY_REG_IF_CAP_IF_VERSION_SHIFT       28
-# define TPM_LOCALITY_REG_IF_CAP_IF_VERSION_SET(a)      ((a) << TPM_LOCALITY_REG_IF_CAP_IF_VERSION_SHIFT)
+# define TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_MASK        UINT32_C(0x70000000)
+# define TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_SHIFT       28
+# define TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_SET(a)      ((a) << TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_SHIFT)
 /** Interface 1.21 or ealier. */
-#  define TPM_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_21    0
+#  define TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_21    0
 /** Interface 1.3. */
-#  define TPM_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_3     2
+#  define TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_3     2
 /** Interface 1.3 for TPM 2.0. */
-#  define TPM_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_3_TPM2    3
+#  define TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_3_TPM2    3
 
 /** TPM status register. */
-#define TPM_LOCALITY_REG_STS                            0x18
+#define TPM_FIFO_LOCALITY_REG_STS                            0x18
 /** Writing a 1 forces the TPM to re-send the response. */
-# define TPM_LOCALITY_REG_STS_RESPONSE_RETRY            RT_BIT_32(1)
+# define TPM_FIFO_LOCALITY_REG_STS_RESPONSE_RETRY            RT_BIT_32(1)
 /** Indicating whether the TPM has finished a self test. */
-# define TPM_LOCALITY_REG_STS_SELF_TEST_DONE            RT_BIT_32(2)
+# define TPM_FIFO_LOCALITY_REG_STS_SELF_TEST_DONE            RT_BIT_32(2)
 /** Flag indicating whether the TPM expects more data for the command. */
-# define TPM_LOCALITY_REG_STS_EXPECT                    RT_BIT_32(3)
+# define TPM_FIFO_LOCALITY_REG_STS_EXPECT                    RT_BIT_32(3)
 /** Flag indicating whether the TPM has more response data available. */
-# define TPM_LOCALITY_REG_STS_DATA_AVAIL                RT_BIT_32(4)
+# define TPM_FIFO_LOCALITY_REG_STS_DATA_AVAIL                RT_BIT_32(4)
 /** Written by software to cause the TPM to execute a previously transfered command. */
-# define TPM_LOCALITY_REG_STS_TPM_GO                    RT_BIT_32(5)
+# define TPM_FIFO_LOCALITY_REG_STS_TPM_GO                    RT_BIT_32(5)
 /** On reads indicates whether the TPM is ready to receive a new command (1) or not (0),
  * a write of 1 causes the TPM to transition to this state. */
-# define TPM_LOCALITY_REG_STS_CMD_RDY                   RT_BIT_32(6)
+# define TPM_FIFO_LOCALITY_REG_STS_CMD_RDY                   RT_BIT_32(6)
 /** Indicates whether the Expect and data available bits are valid. */
-# define TPM_LOCALITY_REG_STS_VALID                     RT_BIT_32(7)
-# define TPM_LOCALITY_REG_STS_BURST_CNT_MASK            UINT32_C(0xffff00)
-# define TPM_LOCALITY_REG_STS_BURST_CNT_SHIFT           8
-# define TPM_LOCALITY_REG_STS_BURST_CNT_SET(a)          ((a) << TPM_LOCALITY_REG_STS_BURST_CNT_SHIFT)
+# define TPM_FIFO_LOCALITY_REG_STS_VALID                     RT_BIT_32(7)
+# define TPM_FIFO_LOCALITY_REG_STS_BURST_CNT_MASK            UINT32_C(0xffff00)
+# define TPM_FIFO_LOCALITY_REG_STS_BURST_CNT_SHIFT           8
+# define TPM_FIFO_LOCALITY_REG_STS_BURST_CNT_SET(a)          ((a) << TPM_FIFO_LOCALITY_REG_STS_BURST_CNT_SHIFT)
 
 /** TPM end of HASH operation signal register for locality 4. */
-#define TPM_LOCALITY_REG_HASH_END                       0x20
+#define TPM_FIFO_LOCALITY_REG_HASH_END                       0x20
 /** Data FIFO read/write register. */
-#define TPM_LOCALITY_REG_DATA_FIFO                      0x24
+#define TPM_FIFO_LOCALITY_REG_DATA_FIFO                      0x24
 /** TPM start of HASH operation signal register for locality 4. */
-#define TPM_LOCALITY_REG_HASH_START                     0x28
+#define TPM_FIFO_LOCALITY_REG_HASH_START                     0x28
 /** Extended data FIFO read/write register. */
-#define TPM_LOCALITY_REG_XDATA_FIFO                     0x80
+#define TPM_FIFO_LOCALITY_REG_XDATA_FIFO                     0x80
 /** TPM device and vendor ID. */
-#define TPM_LOCALITY_REG_DID_VID                        0xf00
+#define TPM_FIFO_LOCALITY_REG_DID_VID                        0xf00
 /** TPM revision ID. */
-#define TPM_LOCALITY_REG_RID                            0xf04
+#define TPM_FIFO_LOCALITY_REG_RID                            0xf04
+/** @} */
+
+
+/** @name TPM locality register related defines for the CRB interface.
+ * @{ */
+/** Locality state register. */
+#define TPM_CRB_LOCALITY_REG_STATE                           0x00
+/** Indicates whether a dynamic OS has been established on this platform before.. */
+# define TPM_CRB_LOCALITY_REG_ESTABLISHMENT                  RT_BIT(0)
+/** Flag whether the host has a locality assigned (1) or not (0). */
+# define TPM_CRB_LOCALITY_REG_STATE_LOC_ASSIGNED             RT_BIT(1)
+/** Indicates the currently active locality. */
+# define TPM_CRB_LOCALITY_REG_STATE_ACTIVE_LOC_MASK          UINT32_C(0x1c)
+# define TPM_CRB_LOCALITY_REG_STATE_ACTIVE_LOC_SHIFT         2
+# define TPM_CRB_LOCALITY_REG_STATE_ACTIVE_LOC_SET(a)        ((a) << TPM_CRB_LOCALITY_REG_STATE_ACTIVE_LOC_SHIFT)
+/** Flag whether the register contains valid values. */
+# define TPM_CRB_LOCALITY_REG_STATE_VALID                    RT_BIT(7)
+
+/** Locality control register. */
+#define TPM_CRB_LOCALITY_REG_CTRL                            0x08
+/** Request TPM access from this locality. */
+# define TPM_CRB_LOCALITY_REG_CTRL_REQ_ACCESS                RT_BIT(0)
+/** Release TPM access from this locality. */
+# define TPM_CRB_LOCALITY_REG_CTRL_RELINQUISH                RT_BIT(1)
+/** Seize TPM access in favor of this locality if it has a higher priority. */
+# define TPM_CRB_LOCALITY_REG_CTRL_SEIZE                     RT_BIT(2)
+/** Resets the established bit if written from locality 3 or 4. */
+# define TPM_CRB_LOCALITY_REG_CTRL_RST_ESTABLISHMENT         RT_BIT(3)
+
+/** Locality status register. */
+#define TPM_CRB_LOCALITY_REG_STS                             0x0c
+/** Locality has been granted access to the TPM. */
+# define TPM_CRB_LOCALITY_REG_STS_GRANTED                    RT_BIT(0)
+/** A higher locality has seized the TPM from this locality. */
+# define TPM_CRB_LOCALITY_REG_STS_SEIZED                     RT_BIT(1)
+
+/** Locality interface ID register. */
+#define TPM_CRB_LOCALITY_REG_INTF_ID                         0x30
+/** Interface type field. */
+# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_MASK           UINT32_C(0xf)
+# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_SHIFT          0
+# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_SET(a)         ((a) << TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_SHIFT)
+/** FIFO interface as defined in PTP for TPM 2.0 is active. */
+#  define TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_FIFO_TPM20    0x0
+/** CRB interface is active. */
+#  define TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_CRB           0x1
+/** FIFO interface as defined in TIS 1.3 is active. */
+#  define TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_TIS1_3        0xf
+/** Interface type field. */
+# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_MASK           UINT32_C(0xf)
+# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_SHIFT          4
+# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_SET(a)         ((a) << TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_SHIFT)
+/** FIFO interface for TPM 2.0 */
+#  define TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_FIFO          0
+/** CRB interface version 0. */
+#  define TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_CRB           1
+/** Only locality 0 is supported when clear, set if 5 localities are supported. */
+# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_LOCALITY           RT_BIT(8)
+/** @todo TPM supports ... */
+# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_CRB_IDLE_BYPASS    RT_BIT(9)
+/** Maximum transfer size support. */
+# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_MASK   0x1800
+# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_SHIFT  11
+# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_SET(a) ((a) << TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_SHIFT)
+/** Only legacy transfers supported. */
+#  define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_LEGACY 0x0
+/** 8B maximum transfer size. */
+#  define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_8B   0x1
+/** 32B maximum transfer size. */
+#  define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_32B  0x2
+/** 64B maximum transfer size. */
+#  define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_64B  0x3
+/** FIFO interface is supported and may be selected. */
+# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_FIFO               RT_BIT(13)
+/** CRB interface is supported and may be selected. */
+# define TPM_CRB_LOCALITY_REG_INTF_ID_CAP_CRB                RT_BIT(14)
+/** Interrupt polarity configuration. */
+# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_MASK            0x60000
+# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_SHIFT           17
+# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_SET(a)          ((a) << TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_SHIFT)
+# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_GET(a)          (((a) & TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_MASK) >> TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_SHIFT)
+/** Selects the FIFO interface, takes effect on next _TPM_INIT. */
+#  define TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_FIFO           0
+/** Selects the CRB interface, takes effect on next _TPM_INIT. */
+#  define TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_CRB            1
+/** Locks the interface selector field and prevents further changes. */
+# define TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_LOCK            RT_BIT(19)
+/** Revision ID field. */
+# define TPM_CRB_LOCALITY_REG_INTF_ID_RID_SHIFT              17
+# define TPM_CRB_LOCALITY_REG_INTF_ID_RID_SET(a)             ((uint64_t)(a) << TPM_CRB_LOCALITY_REG_INTF_ID_RID_SHIFT)
+/** Vendor ID field. */
+# define TPM_CRB_LOCALITY_REG_INTF_ID_VID_SHIFT              32
+# define TPM_CRB_LOCALITY_REG_INTF_ID_VID_SET(a)             ((uint64_t)(a) << TPM_CRB_LOCALITY_REG_INTF_ID_VID_SHIFT)
+/** Device ID field. */
+# define TPM_CRB_LOCALITY_REG_INTF_ID_DID_SHIFT              48
+# define TPM_CRB_LOCALITY_REG_INTF_ID_DID_SET(a)             ((uint64_t)(a) << TPM_CRB_LOCALITY_REG_INTF_ID_DID_SHIFT)
+
+/** Locality CRB extension register (optional and locality 0 only). */
+#define TPM_CRB_LOCALITY_REG_CTRL_EXT                        0x38
+
+/** Locality CRB request register. */
+#define TPM_CRB_LOCALITY_REG_CTRL_REQ                        0x40
+/** The TPM should transition to the ready state to receive a new command. */
+# define TPM_CRB_LOCALITY_REG_CTRL_REQ_CMD_RDY               RT_BIT(0)
+/** The TPM should transition to the idle state. */
+# define TPM_CRB_LOCALITY_REG_CTRL_REQ_IDLE                  RT_BIT(1)
+
+/** Locality CRB status register. */
+#define TPM_CRB_LOCALITY_REG_CTRL_STS                        0x44
+/** This bit indicates that the TPM ran into a fatal error if set. */
+# define TPM_CRB_LOCALITY_REG_CTRL_STS_TPM_FATAL_ERR         RT_BIT(0)
+/** This bit indicates that the TPM is in the idle state. */
+# define TPM_CRB_LOCALITY_REG_CTRL_STS_TPM_IDLE              RT_BIT(1)
+
+/** Locality CRB cancel register. */
+#define TPM_CRB_LOCALITY_REG_CTRL_CANCEL                     0x48
+/** Locality CRB start register. */
+#define TPM_CRB_LOCALITY_REG_CTRL_START                      0x4c
+
+/** Locality interrupt enable register. */
+#define TPM_CRB_LOCALITY_REG_INT_ENABLE                      0x50
+/** Enable the "TPM has executed a reqeust and response is available" interrupt. */
+# define TPM_CRB_LOCALITY_REG_INT_ENABLE_START               RT_BIT(0)
+/** Enable the "TPM has transitioned to the command ready state" interrupt. */
+# define TPM_CRB_LOCALITY_REG_INT_CMD_RDY                    RT_BIT(1)
+/** Enable the "TPM has cleared the establishment flag" interrupt. */
+# define TPM_CRB_LOCALITY_REG_INT_ESTABLISHMENT_CLR          RT_BIT(2)
+/** Enable the "active locality has changed" interrupt. */
+# define TPM_CRB_LOCALITY_REG_INT_LOC_CHANGED                RT_BIT(3)
+/** Enables interrupts globally as defined by the individual bits in this register. */
+# define TPM_CRB_LOCALITY_REG_INT_GLOBAL_ENABLE              RT_BIT(31)
+
+/** Locality interrupt status register. */
+#define TPM_CRB_LOCALITY_REG_INT_STS                         0x54
+/** Indicates that the TPM as executed a command and the response is available for reading, writing a 1 clears the bit. */
+# define TPM_CRB_LOCALITY_REG_INT_STS_START                  RT_BIT(0)
+/** Indicates that the TPM has finished the transition to the ready state, writing a 1 clears this bit. */
+# define TPM_CRB_LOCALITY_REG_INT_STS_CMD_RDY                RT_BIT(1)
+/** Indicates that the TPM has cleared the establishment flag, writing a 1 clears this bit. */
+# define TPM_CRB_LOCALITY_REG_INT_STS_ESTABLISHMENT_CLR      RT_BIT(2)
+/** Indicates that a locality change has occurrec, writing a 1 clears this bit. */
+# define TPM_CRB_LOCALITY_REG_INT_STS_LOC_CHANGED            RT_BIT(3)
+
+/** Locality command buffer size register. */
+#define TPM_CRB_LOCALITY_REG_CTRL_CMD_SZ                     0x58
+/** Locality command buffer low address register. */
+#define TPM_CRB_LOCALITY_REG_CTRL_CMD_LADDR                  0x5c
+/** Locality command buffer low address register. */
+#define TPM_CRB_LOCALITY_REG_CTRL_CMD_HADDR                  0x60
+/** Locality response buffer size register. */
+#define TPM_CRB_LOCALITY_REG_CTRL_RSP_SZ                     0x64
+/** Locality response buffer size register. */
+#define TPM_CRB_LOCALITY_REG_CTRL_RSP_ADDR                   0x68
+/** Locality data buffer. */
+#define TPM_CRB_LOCALITY_REG_DATA_BUFFER                     0x80
+/** Size of the data buffer. */
+#define TPM_CRB_LOCALITY_REG_DATA_BUFFER_SIZE                3968
 /** @} */
 
@@ -203,24 +362,28 @@
 
 /**
- * Possible locality states
+ * Possible TPM states
  * (see chapter 5.6.12.1 Figure 3 State Transition Diagram).
  */
-typedef enum DEVTPMLOCALITYSTATE
+typedef enum DEVTPMSTATE
 {
     /** Invalid state, do not use. */
-    DEVTPMLOCALITYSTATE_INVALID = 0,
-    /** Init state. */
-    DEVTPMLOCALITYSTATE_INIT,
+    DEVTPMSTATE_INVALID = 0,
+    /** Idle state. */
+    DEVTPMSTATE_IDLE,
     /** Ready to accept command data. */
-    DEVTPMLOCALITYSTATE_READY,
+    DEVTPMSTATE_READY,
     /** Command data being transfered. */
-    DEVTPMLOCALITYSTATE_CMD_RECEPTION,
+    DEVTPMSTATE_CMD_RECEPTION,
     /** Command is being executed by the TPM. */
-    DEVTPMLOCALITYSTATE_CMD_EXEC,
+    DEVTPMSTATE_CMD_EXEC,
     /** Command has completed and data can be read. */
-    DEVTPMLOCALITYSTATE_CMD_COMPLETION,
+    DEVTPMSTATE_CMD_COMPLETION,
+    /** Command is being canceled. */
+    DEVTPMSTATE_CMD_CANCEL,
+    /** TPM ran into a fatal error and is not operational. */
+    DEVTPMSTATE_FATAL_ERROR,
     /** 32bit hack. */
-    DEVTPMLOCALITYSTATE_32BIT_HACK = 0x7fffffff
-} DEVTPMLOCALITYSTATE;
+    DEVTPMSTATE_32BIT_HACK = 0x7fffffff
+} DEVTPMSTATE;
 
 
@@ -230,8 +393,4 @@
 typedef struct DEVTPMLOCALITY
 {
-    /** The current state of the locality. */
-    DEVTPMLOCALITYSTATE             enmState;
-    /** Access register state. */
-    uint32_t                        uRegAccess;
     /** The interrupt enable register. */
     uint32_t                        uRegIntEn;
@@ -239,5 +398,7 @@
     uint32_t                        uRegIntSts;
 } DEVTPMLOCALITY;
+/** Pointer to a locality state. */
 typedef DEVTPMLOCALITY *PDEVTPMLOCALITY;
+/** Pointer to a const locality state. */
 typedef const DEVTPMLOCALITY *PCDEVTPMLOCALITY;
 
@@ -248,6 +409,10 @@
 typedef struct DEVTPM
 {
+    /** Base MMIO address of the TPM device. */
+    RTGCPHYS                        GCPhysMmio;
     /** The handle of the MMIO region. */
     IOMMMIOHANDLE                   hMmio;
+    /** The handle for the ring-3 task. */
+    PDMTASKHANDLE                   hTpmCmdTask;
     /** The vendor ID configured. */
     uint16_t                        uVenId;
@@ -258,4 +423,6 @@
     /** The IRQ value. */
     uint8_t                         uIrq;
+    /** Flag whether CRB access mode is used. */
+    bool                            fCrb;
 
     /** Currently selected locality. */
@@ -263,5 +430,13 @@
     /** States of the implemented localities. */
     DEVTPMLOCALITY                  aLoc[TPM_LOCALITY_COUNT];
-
+    /** Bitmask of localities having requested access to the TPM. */
+    uint32_t                        bmLocReqAcc;
+    /** Bitmask of localities having been seized access from the TPM. */
+    uint32_t                        bmLocSeizedAcc;
+    /** The current state of the TPM. */
+    DEVTPMSTATE                     enmState;
+
+    /** Command/Response buffer. */
+    uint8_t                         abCmdResp[TPM_CRB_LOCALITY_REG_DATA_BUFFER_SIZE];
 } DEVTPM;
 /** Pointer to the shared TPM device state. */
@@ -277,5 +452,10 @@
 typedef struct DEVTPMR3
 {
-    uint8_t                         bDummy;
+    /** The base interface for LUN\#0. */
+    PDMIBASE                        IBase;
+    /** The base interface below. */
+    R3PTRTYPE(PPDMIBASE)            pDrvBase;
+    /** The TPM connector interface below. */
+    R3PTRTYPE(PPDMITPMCONNECTOR)    pDrvTpm;
 } DEVTPMR3;
 /** Pointer to the TPM device state for ring-3. */
@@ -288,5 +468,5 @@
 typedef struct DEVTPMR0
 {
-    uint8_t                         bDummy;
+    uint32_t                        u32Dummy;
 } DEVTPMR0;
 /** Pointer to the TPM device state for ring-0. */
@@ -299,5 +479,5 @@
 typedef struct DEVTPMRC
 {
-    uint8_t                         bDummy;
+    uint32_t                        u32Dummy;
 } DEVTPMRC;
 /** Pointer to the TPM device state for raw-mode. */
@@ -338,8 +518,42 @@
 PDMBOTHCBDECL(void) tpmLocIrqUpdate(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc)
 {
-    if (pLoc->uRegIntEn & pLoc->uRegIntSts)
+    if (   (pLoc->uRegIntEn & TPM_CRB_LOCALITY_REG_INT_GLOBAL_ENABLE)
+        && (pLoc->uRegIntEn & pLoc->uRegIntSts))
         tpmIrqReq(pDevIns, pThis, 1);
     else
         tpmIrqReq(pDevIns, pThis, 0);
+}
+
+
+/**
+ * Sets the interrupt status for the given locality, firing an interrupt if necessary.
+ *
+ * @returns nothing.
+ * @param   pDevIns             Pointer to the PDM device instance data.
+ * @param   pThis               Pointer to the shared TPM device.
+ * @param   pLoc                The locality state.
+ * @param   uSts                The interrupt status bit to set.
+ */
+static void tpmLocSetIntSts(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc, uint32_t uSts)
+{
+    pLoc->uRegIntSts |= uSts;
+    tpmLocIrqUpdate(pDevIns, pThis, pLoc);
+}
+
+
+/**
+ * Selects the next locality which has requested access.
+ *
+ * @returns nothing.
+ * @param   pDevIns             Pointer to the PDM device instance data.
+ * @param   pThis               Pointer to the shared TPM device.
+ */
+static void tpmLocSelectNext(PPDMDEVINS pDevIns, PDEVTPM pThis)
+{
+    Assert(pThis->bmLocReqAcc);
+    Assert(pThis->bLoc == TPM_NO_LOCALITY_SELECTED);
+    pThis->bLoc = (uint8_t)ASMBitLastSetU32(pThis->bmLocReqAcc) - 1; /* Select one with highest priority. */
+
+    tpmLocSetIntSts(pDevIns, pThis, &pThis->aLoc[pThis->bLoc], TPM_CRB_LOCALITY_REG_INT_STS_LOC_CHANGED);
 }
 
@@ -369,76 +583,71 @@
 
 
-/* -=-=-=-=-=- MMIO callbacks -=-=-=-=-=- */
-
-
-/**
- * @callback_method_impl{FNIOMMMIONEWREAD}
- */
-static DECLCALLBACK(VBOXSTRICTRC) tpmMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
-{
-    PDEVTPM pThis  = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
-    RT_NOREF(pvUser);
-
-    Assert(!(off & (cb - 1)));
-
-    LogFlowFunc((": %RGp %#x\n", off, cb));
+/**
+ * Read from a FIFO interface register.
+ *
+ * @returns VBox strict status code.
+ * @param   pDevIns             Pointer to the PDM device instance data.
+ * @param   pThis               Pointer to the shared TPM device.
+ * @param   pLoc                The locality state being read from.
+ * @param   bLoc                The locality index.
+ * @param   uReg                The register offset being accessed.
+ * @param   pu64                Where to store the read data.
+ */
+static VBOXSTRICTRC tpmMmioFifoRead(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc,
+                                    uint8_t bLoc, uint32_t uReg, uint64_t *pu64)
+{
+    RT_NOREF(pDevIns, pThis, pLoc, bLoc, uReg, pu64);
     VBOXSTRICTRC rc = VINF_SUCCESS;
-    uint32_t uReg = tpmGetRegisterFromOffset(off);
-    uint8_t bLoc = tpmGetLocalityFromOffset(off);
-    PDEVTPMLOCALITY pLoc = &pThis->aLoc[bLoc];
-    uint32_t u32;
+
+#if 0
+    uint64_t u64;
     switch (uReg)
     {
-        case TPM_LOCALITY_REG_ACCESS:
-            u32 = 0;
-            break;
-        case TPM_LOCALITY_REG_INT_ENABLE:
-            u32 = pLoc->uRegIntEn;
-            break;
-        case TPM_LOCALITY_REG_INT_VEC:
-            u32 = pThis->uIrq;
-            break;
-        case TPM_LOCALITY_REG_INT_STS:
-            u32 = pLoc->uRegIntSts;
-            break;
-        case TPM_LOCALITY_REG_IF_CAP:
-            u32 =   TPM_LOCALITY_REG_IF_CAP_INT_DATA_AVAIL
-                  | TPM_LOCALITY_REG_IF_CAP_INT_STS_VALID
-                  | TPM_LOCALITY_REG_IF_CAP_INT_LOCALITY_CHANGE
-                  | TPM_LOCALITY_REG_IF_CAP_INT_LVL_LOW
-                  | TPM_LOCALITY_REG_IF_CAP_INT_CMD_RDY
-                  | TPM_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_SET(TPM_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_64B)
-                  | TPM_LOCALITY_REG_IF_CAP_IF_VERSION_SET(TPM_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_3); /** @todo Make some of them configurable? */
-            break;
-        case TPM_LOCALITY_REG_STS:
+        case TPM_FIFO_LOCALITY_REG_ACCESS:
+            u64 = 0;
+            break;
+        case TPM_FIFO_LOCALITY_REG_INT_ENABLE:
+            u64 = pLoc->uRegIntEn;
+            break;
+        case TPM_FIFO_LOCALITY_REG_INT_VEC:
+            u64 = pThis->uIrq;
+            break;
+        case TPM_FIFO_LOCALITY_REG_INT_STS:
+            u64 = pLoc->uRegIntSts;
+            break;
+        case TPM_FIFO_LOCALITY_REG_IF_CAP:
+            u64 =   TPM_FIFO_LOCALITY_REG_IF_CAP_INT_DATA_AVAIL
+                  | TPM_FIFO_LOCALITY_REG_IF_CAP_INT_STS_VALID
+                  | TPM_FIFO_LOCALITY_REG_IF_CAP_INT_LOCALITY_CHANGE
+                  | TPM_FIFO_LOCALITY_REG_IF_CAP_INT_LVL_LOW
+                  | TPM_FIFO_LOCALITY_REG_IF_CAP_INT_CMD_RDY
+                  | TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_SET(TPM_FIFO_LOCALITY_REG_IF_CAP_DATA_XFER_SZ_64B)
+                  | TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_SET(TPM_FIFO_LOCALITY_REG_IF_CAP_IF_VERSION_IF_1_3); /** @todo Make some of them configurable? */
+            break;
+        case TPM_FIFO_LOCALITY_REG_STS:
             if (bLoc != pThis->bLoc)
             {
-                u32 = UINT32_MAX;
+                u64 = UINT64_MAX;
                 break;
             }
             /** @todo */
             break;
-        case TPM_LOCALITY_REG_DATA_FIFO:
-        case TPM_LOCALITY_REG_DATA_XFIFO:
+        case TPM_FIFO_LOCALITY_REG_DATA_FIFO:
+        //case TPM_FIFO_LOCALITY_REG_DATA_XFIFO:
             /** @todo */
             break;
-        case TPM_LOCALITY_REG_DID_VID:
-            u32 = RT_H2BE_U32(RT_MAKE_U32(pThis->uVenId, pThis->uDevId));
-            break;
-        case TPM_LOCALITY_REG_RID:
-            u32 = pThis->bRevId;
+        case TPM_FIFO_LOCALITY_REG_DID_VID:
+            u64 = RT_H2BE_U32(RT_MAKE_U32(pThis->uVenId, pThis->uDevId));
+            break;
+        case TPM_FIFO_LOCALITY_REG_RID:
+            u64 = pThis->bRevId;
             break;
         default: /* Return ~0. */
-            u32 = UINT32_MAX;
+            u64 = UINT64_MAX;
             break;
     }
 
-    switch (cb)
-    {
-        case 1: *(uint8_t *)pv = (uint8_t)u32; break;
-        case 2: *(uint16_t *)pv = (uint16_t)u32; break;
-        case 4: *(uint32_t *)pv = u32; break;
-        default: AssertFailedBreakStmt(rc = VERR_INTERNAL_ERROR);
-    }
+    *pu64 = u64;
+#endif
 
     return rc;
@@ -447,32 +656,27 @@
 
 /**
- * @callback_method_impl{FNIOMMMIONEWWRITE}
- */
-static DECLCALLBACK(VBOXSTRICTRC) tpmMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
-{
-    PDEVTPM pThis  = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
-    RT_NOREF(pvUser);
-
-    Assert(!(off & (cb - 1)));
-
-    uint32_t u32;
-    switch (cb)
-    {
-        case 1: u32 = *(const uint8_t *)pv; break;
-        case 2: u32 = *(const uint16_t *)pv; break;
-        case 4: u32 = *(const uint32_t *)pv; break;
-        default: AssertFailedReturn(VERR_INTERNAL_ERROR);
-    }
-
-    LogFlowFunc((": %RGp %#x\n", off, u32));
+ * Read to a FIFO interface register.
+ *
+ * @returns VBox strict status code.
+ * @param   pDevIns             Pointer to the PDM device instance data.
+ * @param   pThis               Pointer to the shared TPM device.
+ * @param   pLoc                The locality state being written to.
+ * @param   bLoc                The locality index.
+ * @param   uReg                The register offset being accessed.
+ * @param   u64                 The value to write.
+ */
+static VBOXSTRICTRC tpmMmioFifoWrite(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc,
+                                     uint8_t bLoc, uint32_t uReg, uint64_t u64)
+{
+    RT_NOREF(pDevIns, pThis, pLoc, bLoc, uReg, u64);
 
     VBOXSTRICTRC rc = VINF_SUCCESS;
-    uint32_t uReg = tpmGetRegisterFromOffset(off);
-    uint8_t bLoc = tpmGetLocalityFromOffset(off);
-    PDEVTPMLOCALITY pLoc = &pThis->aLoc[bLoc];
+#if 0
+    uint32_t u32 = (uint32_t)u64;
+
     switch (uReg)
     {
-        case TPM_LOCALITY_REG_ACCESS:
-            u32 &= TPM_LOCALITY_REG_ACCESS_WR_MASK;
+        case TPM_FIFO_LOCALITY_REG_ACCESS:
+            u32 &= TPM_FIFO_LOCALITY_REG_ACCESS_WR_MASK;
              /*
               * Chapter 5.6.11, 2 states that writing to this register with more than one
@@ -484,16 +688,16 @@
             /** @todo */
             break;
-        case TPM_LOCALITY_REG_INT_ENABLE:
+        case TPM_FIFO_LOCALITY_REG_INT_ENABLE:
             if (bLoc != pThis->bLoc)
                 break;
             /** @todo */
             break;
-        case TPM_LOCALITY_REG_INT_STS:
+        case TPM_FIFO_LOCALITY_REG_INT_STS:
             if (bLoc != pThis->bLoc)
                 break;
-            pLoc->uRegSts &= ~(u32 & TPM_LOCALITY_REG_INT_STS_WR_MASK);
+            pLoc->uRegSts &= ~(u32 & TPM_FIFO_LOCALITY_REG_INT_STS_WR_MASK);
             tpmLocIrqUpdate(pDevIns, pThis, pLoc);
             break;
-        case TPM_LOCALITY_REG_STS:
+        case TPM_FIFO_LOCALITY_REG_STS:
             /*
              * Writes are ignored completely if the locality being accessed is not the
@@ -502,27 +706,382 @@
              */
             if (   bLoc != pThis->bLoc
-                || !RT_IS_POWER_OF_TWO(u32))
+                || !RT_IS_POWER_OF_TWO(u64))
                 break;
             /** @todo */
             break;
-        case TPM_LOCALITY_REG_DATA_FIFO:
-        case TPM_LOCALITY_REG_DATA_XFIFO:
+        case TPM_FIFO_LOCALITY_REG_DATA_FIFO:
+        case TPM_FIFO_LOCALITY_REG_DATA_XFIFO:
             if (bLoc != pThis->bLoc)
                 break;
             /** @todo */
             break;
-        case TPM_LOCALITY_REG_INT_VEC:
-        case TPM_LOCALITY_REG_IF_CAP:
-        case TPM_LOCALITY_REG_DID_VID:
-        case TPM_LOCALITY_REG_RID:
+        case TPM_FIFO_LOCALITY_REG_INT_VEC:
+        case TPM_FIFO_LOCALITY_REG_IF_CAP:
+        case TPM_FIFO_LOCALITY_REG_DID_VID:
+        case TPM_FIFO_LOCALITY_REG_RID:
         default: /* Ignore. */
             break;
     }
-
+#endif
     return rc;
 }
 
 
+/**
+ * Read from a CRB interface register.
+ *
+ * @returns VBox strict status code.
+ * @param   pDevIns             Pointer to the PDM device instance data.
+ * @param   pThis               Pointer to the shared TPM device.
+ * @param   pLoc                The locality state being read from.
+ * @param   bLoc                The locality index.
+ * @param   uReg                The register offset being accessed.
+ * @param   pu64                Where to store the read data.
+ * @param   cb                  Size of the read in bytes.
+ */
+static VBOXSTRICTRC tpmMmioCrbRead(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc,
+                                   uint8_t bLoc, uint32_t uReg, uint64_t *pu64, size_t cb)
+{
+    RT_NOREF(pDevIns);
+
+    /* Special path for the data buffer. */
+    if (   uReg >= TPM_CRB_LOCALITY_REG_DATA_BUFFER
+        && uReg < TPM_CRB_LOCALITY_REG_DATA_BUFFER + TPM_CRB_LOCALITY_REG_DATA_BUFFER_SIZE
+        && bLoc == pThis->bLoc
+        && pThis->enmState == DEVTPMSTATE_CMD_COMPLETION)
+    {
+        memcpy(pu64, &pThis->abCmdResp[uReg - TPM_CRB_LOCALITY_REG_DATA_BUFFER], cb);
+        return VINF_SUCCESS;
+    }
+
+    VBOXSTRICTRC rc = VINF_SUCCESS;
+    uint64_t u64 = UINT64_MAX;
+    switch (uReg)
+    {
+        case TPM_CRB_LOCALITY_REG_STATE:
+            u64 =   TPM_CRB_LOCALITY_REG_STATE_VALID
+                  | (  pThis->bLoc != TPM_NO_LOCALITY_SELECTED
+                     ? TPM_CRB_LOCALITY_REG_STATE_ACTIVE_LOC_SET(pThis->bLoc) | TPM_CRB_LOCALITY_REG_STATE_LOC_ASSIGNED
+                     : TPM_CRB_LOCALITY_REG_STATE_ACTIVE_LOC_SET(0));
+            break;
+        case TPM_CRB_LOCALITY_REG_STS:
+            u64 =   pThis->bLoc == bLoc
+                  ? TPM_CRB_LOCALITY_REG_STS_GRANTED
+                  : 0;
+            u64 |=   pThis->bmLocSeizedAcc & RT_BIT_32(bLoc)
+                   ? TPM_CRB_LOCALITY_REG_STS_SEIZED
+                   : 0;
+            break;
+        case TPM_CRB_LOCALITY_REG_INTF_ID:
+            u64 =   TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_SET(TPM_CRB_LOCALITY_REG_INTF_ID_IF_TYPE_CRB)
+                  | TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_SET(TPM_CRB_LOCALITY_REG_INTF_ID_IF_VERS_CRB)
+                  | TPM_CRB_LOCALITY_REG_INTF_ID_CAP_LOCALITY
+                  | TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_SET(TPM_CRB_LOCALITY_REG_INTF_ID_CAP_DATA_XFER_SZ_64B)
+                  | TPM_CRB_LOCALITY_REG_INTF_ID_CAP_CRB
+                  | TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_GET(TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_CRB)
+                  | TPM_CRB_LOCALITY_REG_INTF_ID_IF_SEL_LOCK
+                  | TPM_CRB_LOCALITY_REG_INTF_ID_RID_SET(pThis->bRevId)
+                  | TPM_CRB_LOCALITY_REG_INTF_ID_VID_SET(pThis->uVenId)
+                  | TPM_CRB_LOCALITY_REG_INTF_ID_DID_SET(pThis->uDevId);
+            break;
+        case TPM_CRB_LOCALITY_REG_CTRL_REQ:
+            if (bLoc != pThis->bLoc)
+                break;
+            /*
+             * Command ready and go idle are always 0 upon read
+             * as we don't need time to transition to this state
+             * when written by the guest.
+             */
+            u64 = 0;
+            break;
+        case TPM_CRB_LOCALITY_REG_CTRL_STS:
+            if (bLoc != pThis->bLoc)
+                break;
+            if (pThis->enmState == DEVTPMSTATE_FATAL_ERROR)
+                u64 = TPM_CRB_LOCALITY_REG_CTRL_STS_TPM_FATAL_ERR;
+            else if (pThis->enmState == DEVTPMSTATE_IDLE)
+                u64 = TPM_CRB_LOCALITY_REG_CTRL_STS_TPM_IDLE;
+            else
+                u64 = 0;
+            break;
+        case TPM_CRB_LOCALITY_REG_CTRL_CANCEL:
+            if (bLoc != pThis->bLoc)
+                break;
+            if (pThis->enmState == DEVTPMSTATE_CMD_CANCEL)
+                u64 = 0x1;
+            else
+                u64 = 0;
+            break;
+        case TPM_CRB_LOCALITY_REG_CTRL_START:
+            if (bLoc != pThis->bLoc)
+                break;
+            if (pThis->enmState == DEVTPMSTATE_CMD_EXEC)
+                u64 = 0x1;
+            else
+                u64 = 0;
+            break;
+        case TPM_CRB_LOCALITY_REG_INT_ENABLE:
+            u64 = pLoc->uRegIntEn;
+            break;
+        case TPM_CRB_LOCALITY_REG_INT_STS:
+            u64 = pLoc->uRegIntSts;
+            break;
+        case TPM_CRB_LOCALITY_REG_CTRL_CMD_LADDR:
+            u64 = pThis->GCPhysMmio + (bLoc * TPM_LOCALITY_MMIO_SIZE) + TPM_CRB_LOCALITY_REG_DATA_BUFFER;
+            break;
+        case TPM_CRB_LOCALITY_REG_CTRL_CMD_HADDR:
+            u64 = (pThis->GCPhysMmio + (bLoc * TPM_LOCALITY_MMIO_SIZE) + TPM_CRB_LOCALITY_REG_DATA_BUFFER) >> 32;
+            break;
+        case TPM_CRB_LOCALITY_REG_CTRL_CMD_SZ:
+        case TPM_CRB_LOCALITY_REG_CTRL_RSP_SZ:
+            u64 = TPM_CRB_LOCALITY_REG_DATA_BUFFER_SIZE;
+            break;
+        case TPM_CRB_LOCALITY_REG_CTRL_RSP_ADDR:
+            u64 = pThis->GCPhysMmio + (bLoc * TPM_LOCALITY_MMIO_SIZE) + TPM_CRB_LOCALITY_REG_DATA_BUFFER;
+            break;
+        case TPM_CRB_LOCALITY_REG_CTRL: /* Writeonly */
+            u64 = 0;
+            break;
+        case TPM_CRB_LOCALITY_REG_CTRL_EXT:
+        default:
+            break; /* Return ~0 */
+    }
+
+    *pu64 = u64;
+    return rc;
+}
+
+
+/**
+ * Read to a CRB interface register.
+ *
+ * @returns VBox strict status code.
+ * @param   pDevIns             Pointer to the PDM device instance data.
+ * @param   pThis               Pointer to the shared TPM device.
+ * @param   pLoc                The locality state being written to.
+ * @param   bLoc                The locality index.
+ * @param   uReg                The register offset being accessed.
+ * @param   u64                 The value to write.
+ * @param   cb                  Size of the write in bytes.
+ */
+static VBOXSTRICTRC tpmMmioCrbWrite(PPDMDEVINS pDevIns, PDEVTPM pThis, PDEVTPMLOCALITY pLoc,
+                                    uint8_t bLoc, uint32_t uReg, uint64_t u64, size_t cb)
+{
+    VBOXSTRICTRC rc = VINF_SUCCESS;
+    uint32_t u32 = (uint32_t)u64;
+
+    /* Special path for the data buffer. */
+    if (   uReg >= TPM_CRB_LOCALITY_REG_DATA_BUFFER
+        && uReg < TPM_CRB_LOCALITY_REG_DATA_BUFFER + TPM_CRB_LOCALITY_REG_DATA_BUFFER_SIZE
+        && bLoc == pThis->bLoc
+        && pThis->enmState == DEVTPMSTATE_CMD_RECEPTION)
+    {
+        memcpy(&pThis->abCmdResp[uReg - TPM_CRB_LOCALITY_REG_DATA_BUFFER], &u64, cb);
+        return VINF_SUCCESS;
+    }
+
+    switch (uReg)
+    {
+        case TPM_CRB_LOCALITY_REG_CTRL:
+        {
+            /* See chapter 6.5.3.2.2.1. */
+            if (u64 & TPM_CRB_LOCALITY_REG_CTRL_RST_ESTABLISHMENT)
+                /** @todo */;
+
+            /*
+             * The following three checks should be mutually exclusive as the writer shouldn't
+             * request, relinquish and seize access in the same write.
+             */
+            /* Seize access only if this locality has a higher priority than the currently selected one. */
+            if (   (u64 & TPM_CRB_LOCALITY_REG_CTRL_SEIZE)
+                && pThis->bLoc != TPM_NO_LOCALITY_SELECTED
+                && bLoc > pThis->bLoc)
+            {
+                pThis->bmLocSeizedAcc |= RT_BIT_32(pThis->bLoc);
+                /** @todo Abort command. */
+                pThis->bLoc = bLoc;
+            }
+
+            if (   (u64 & TPM_CRB_LOCALITY_REG_CTRL_REQ_ACCESS)
+                && !(pThis->bmLocReqAcc & RT_BIT_32(bLoc)))
+            {
+                pThis->bmLocReqAcc |= RT_BIT_32(bLoc);
+                if (pThis->bLoc == TPM_NO_LOCALITY_SELECTED)
+                {
+                    pThis->bLoc = bLoc; /* Doesn't fire an interrupt. */
+                    pThis->bmLocSeizedAcc &= ~RT_BIT_32(bLoc);
+                }
+            }
+
+            if (   (u64 & TPM_CRB_LOCALITY_REG_CTRL_RELINQUISH)
+                && (pThis->bmLocReqAcc & RT_BIT_32(bLoc)))
+            {
+                pThis->bmLocReqAcc &= ~RT_BIT_32(bLoc);
+                if (pThis->bLoc == bLoc)
+                {
+                    pThis->bLoc = TPM_NO_LOCALITY_SELECTED;
+                    if (pThis->bmLocReqAcc)
+                        tpmLocSelectNext(pDevIns, pThis); /* Select the next locality. */
+                }
+            }
+            break;
+        }
+        case TPM_CRB_LOCALITY_REG_CTRL_REQ:
+            if (   bLoc != pThis->bLoc
+                || !RT_IS_POWER_OF_TWO(u32)) /* Ignore if multiple bits are set. */
+                break;
+            if (   (u32 & TPM_CRB_LOCALITY_REG_CTRL_REQ_CMD_RDY)
+                && pThis->enmState == DEVTPMSTATE_IDLE)
+            {
+                pThis->enmState = DEVTPMSTATE_READY;
+                tpmLocSetIntSts(pDevIns, pThis, pLoc, TPM_CRB_LOCALITY_REG_INT_STS_CMD_RDY);
+            }
+            else if (   (u32 & TPM_CRB_LOCALITY_REG_CTRL_REQ_IDLE)
+                     && pThis->enmState != DEVTPMSTATE_CMD_EXEC)
+            {
+                /* Invalidate the command/response buffer. */
+                RT_ZERO(pThis->abCmdResp);
+                pThis->enmState = DEVTPMSTATE_IDLE;
+            }
+            break;
+        case TPM_CRB_LOCALITY_REG_CTRL_CANCEL:
+            if (bLoc != pThis->bLoc)
+                break;
+            if (   pThis->enmState == DEVTPMSTATE_CMD_EXEC
+                && u32 == 0x1)
+            {
+                pThis->enmState == DEVTPMSTATE_CMD_CANCEL;
+                /** @todo Cancel. */
+                pThis->enmState == DEVTPMSTATE_CMD_COMPLETION;
+                tpmLocSetIntSts(pDevIns, pThis, pLoc, TPM_CRB_LOCALITY_REG_INT_STS_START);
+            }
+            break;
+        case TPM_CRB_LOCALITY_REG_CTRL_START:
+            if (bLoc != pThis->bLoc)
+                break;
+            if (   pThis->enmState == DEVTPMSTATE_CMD_RECEPTION
+                && u32 == 0x1)
+            {
+                pThis->enmState == DEVTPMSTATE_CMD_EXEC;
+                rc = PDMDevHlpTaskTrigger(pDevIns, pThis->hTpmCmdTask);
+            }
+            break;
+        case TPM_CRB_LOCALITY_REG_INT_ENABLE:
+            pLoc->uRegIntEn = u32;
+            tpmLocIrqUpdate(pDevIns, pThis, pLoc);
+            break;
+        case TPM_CRB_LOCALITY_REG_INT_STS:
+            pLoc->uRegIntSts &= ~u32;
+            tpmLocIrqUpdate(pDevIns, pThis, pLoc);
+            break;
+        case TPM_CRB_LOCALITY_REG_CTRL_EXT: /* Not implemented. */
+        case TPM_CRB_LOCALITY_REG_STATE: /* Readonly */
+        case TPM_CRB_LOCALITY_REG_INTF_ID:
+        case TPM_CRB_LOCALITY_REG_CTRL_STS:
+        case TPM_CRB_LOCALITY_REG_CTRL_CMD_LADDR:
+        case TPM_CRB_LOCALITY_REG_CTRL_CMD_HADDR:
+        case TPM_CRB_LOCALITY_REG_CTRL_CMD_SZ:
+        case TPM_CRB_LOCALITY_REG_CTRL_RSP_SZ:
+        case TPM_CRB_LOCALITY_REG_CTRL_RSP_ADDR:
+        default: /* Ignore. */
+            break;
+    }
+
+    return rc;
+}
+
+
+/* -=-=-=-=-=- MMIO callbacks -=-=-=-=-=- */
+
+/**
+ * @callback_method_impl{FNIOMMMIONEWREAD}
+ */
+static DECLCALLBACK(VBOXSTRICTRC) tpmMmioRead(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void *pv, unsigned cb)
+{
+    PDEVTPM pThis  = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
+    RT_NOREF(pvUser);
+
+    Assert(!(off & (cb - 1)));
+
+    LogFlowFunc((": %RGp %#x\n", off, cb));
+    VBOXSTRICTRC rc = VINF_SUCCESS;
+    uint32_t uReg = tpmGetRegisterFromOffset(off);
+    uint8_t bLoc = tpmGetLocalityFromOffset(off);
+    PDEVTPMLOCALITY pLoc = &pThis->aLoc[bLoc];
+
+
+    uint64_t u64;
+    if (pThis->fCrb)
+        rc = tpmMmioCrbRead(pDevIns, pThis, pLoc, bLoc, uReg, &u64, cb);
+    else
+        rc = tpmMmioFifoRead(pDevIns, pThis, pLoc, bLoc, uReg, &u64);
+
+    if (rc == VINF_SUCCESS)
+    {
+        switch (cb)
+        {
+            case 1: *(uint8_t *)pv = (uint8_t)u64; break;
+            case 2: *(uint16_t *)pv = (uint16_t)u64; break;
+            case 4: *(uint32_t *)pv = (uint32_t)u64; break;
+            case 8: *(uint64_t *)pv = u64; break;
+            default: AssertFailedBreakStmt(rc = VERR_INTERNAL_ERROR);
+        }
+    }
+
+    return rc;
+}
+
+
+/**
+ * @callback_method_impl{FNIOMMMIONEWWRITE}
+ */
+static DECLCALLBACK(VBOXSTRICTRC) tpmMmioWrite(PPDMDEVINS pDevIns, void *pvUser, RTGCPHYS off, void const *pv, unsigned cb)
+{
+    PDEVTPM pThis  = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
+    RT_NOREF(pvUser);
+
+    Assert(!(off & (cb - 1)));
+
+    uint64_t u64;
+    switch (cb)
+    {
+        case 1: u64 = *(const uint8_t *)pv; break;
+        case 2: u64 = *(const uint16_t *)pv; break;
+        case 4: u64 = *(const uint32_t *)pv; break;
+        case 8: u64 = *(const uint64_t *)pv; break;
+        default: AssertFailedReturn(VERR_INTERNAL_ERROR);
+    }
+
+    LogFlowFunc((": %RGp %#llx\n", off, u64));
+
+    VBOXSTRICTRC rc = VINF_SUCCESS;
+    uint32_t uReg = tpmGetRegisterFromOffset(off);
+    uint8_t bLoc = tpmGetLocalityFromOffset(off);
+    PDEVTPMLOCALITY pLoc = &pThis->aLoc[bLoc];
+
+    if (pThis->fCrb)
+        rc = tpmMmioCrbWrite(pDevIns, pThis, pLoc, bLoc, uReg, u64, cb);
+    else
+        rc = tpmMmioFifoWrite(pDevIns, pThis, pLoc, bLoc, uReg, u64);
+
+    return rc;
+}
+
+
 #ifdef IN_RING3
+
+/**
+ * @callback_method_impl{FNPDMTASKDEV, Execute a command in ring-3}
+ */
+static DECLCALLBACK(void) tpmR3CmdExecWorker(PPDMDEVINS pDevIns, void *pvUser)
+{
+    PDEVTPM     pThis   = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
+    PDEVTPMR3   pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVTPMR3);
+    RT_NOREF(pvUser);
+    LogFlowFunc(("\n"));
+
+    /** @todo */
+    RT_NOREF(pThis, pThisCC);
+}
 
 
@@ -590,4 +1149,18 @@
 
 
+/* -=-=-=-=-=-=-=-=- PDMIBASE -=-=-=-=-=-=-=-=- */
+
+/**
+ * @interface_method_impl{PDMIBASE,pfnQueryInterface}
+ */
+static DECLCALLBACK(void *) tpmR3QueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+    PDEVTPMCC pThisCC = RT_FROM_MEMBER(pInterface, DEVTPMCC, IBase);
+    PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pThisCC->IBase);
+    //PDMIBASE_RETURN_INTERFACE(pszIID, PDMITPMPORT, &pThisCC->ITpmPort);
+    return NULL;
+}
+
+
 /* -=-=-=-=-=-=-=-=- PDMDEVREG -=-=-=-=-=-=-=-=- */
 
@@ -597,14 +1170,15 @@
 static DECLCALLBACK(void) tpmR3Reset(PPDMDEVINS pDevIns)
 {
-    PDEVTPM   pThis   = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
-
-    pThis->bLoc = TPM_NO_LOCALITY_SELECTED;
+    PDEVTPM pThis = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
+
+    pThis->enmState = DEVTPMSTATE_IDLE;
+    pThis->bLoc     = TPM_NO_LOCALITY_SELECTED;
+    RT_ZERO(pThis->abCmdResp);
+
     for (uint32_t i = 0; i < RT_ELEMENTS(pThis->aLoc); i++)
     {
         PDEVTPMLOCALITY pLoc = &pThis->aLoc[i];
-
-        pLoc->enmState   = DEVTPMLOCALITYSTATE_INIT;
-        pLoc->aRegIntEn  = 0;
-        pLoc->aRegIntSts = 0;
+        pLoc->uRegIntEn  = 0;
+        pLoc->uRegIntSts = 0;
     }
 }
@@ -632,9 +1206,14 @@
     PDMDEV_CHECK_VERSIONS_RETURN(pDevIns);
     PDEVTPM         pThis   = PDMDEVINS_2_DATA(pDevIns, PDEVTPM);
-    //PDEVTPMCC       pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVTPMCC);
+    PDEVTPMCC       pThisCC = PDMDEVINS_2_DATA_CC(pDevIns, PDEVTPMCC);
     PCPDMDEVHLPR3   pHlp    = pDevIns->pHlpR3;
     int             rc;
 
     RT_NOREF(iInstance);
+
+    pThis->hTpmCmdTask = NIL_PDMTASKHANDLE;
+
+    /* IBase */
+    pThisCC->IBase.pfnQueryInterface = tpmR3QueryInterface;
 
     /*
@@ -645,14 +1224,13 @@
                                            "|VendorId"
                                            "|DeviceId"
-                                           "|RevisionId",
+                                           "|RevisionId"
+                                           "|Crb",
                                            "");
 
-    uint8_t uIrq = 0;
-    rc = pHlp->pfnCFGMQueryU8Def(pCfg, "Irq", &uIrq, 10);
+    rc = pHlp->pfnCFGMQueryU8Def(pCfg, "Irq", &pThis->uIrq, 10);
     if (RT_FAILURE(rc))
         return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"Irq\" value"));
 
-    RTGCPHYS GCPhysMmio;
-    rc = pHlp->pfnCFGMQueryU64Def(pCfg, "MmioBase", &GCPhysMmio, TPM_MMIO_BASE_DEFAULT);
+    rc = pHlp->pfnCFGMQueryU64Def(pCfg, "MmioBase", &pThis->GCPhysMmio, TPM_MMIO_BASE_DEFAULT);
     if (RT_FAILURE(rc))
         return PDMDEV_SET_ERROR(pDevIns, rc,
@@ -671,5 +1249,7 @@
         return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"RevisionId\" value"));
 
-    pThis->uIrq = uIrq;
+    rc = pHlp->pfnCFGMQueryBoolDef(pCfg, "Crb", &pThis->fCrb, true);
+    if (RT_FAILURE(rc))
+        return PDMDEV_SET_ERROR(pDevIns, rc, N_("Configuration error: Failed to get the \"Crb\" value"));
 
     /*
@@ -677,8 +1257,31 @@
      * addresses and sizes.
      */
-    rc = PDMDevHlpMmioCreateAndMap(pDevIns, GCPhysMmio, TPM_MMIO_SIZE, tpmMmioWrite, tpmMmioRead,
+    rc = PDMDevHlpMmioCreateAndMap(pDevIns, pThis->GCPhysMmio, TPM_MMIO_SIZE, tpmMmioWrite, tpmMmioRead,
                                    IOMMMIO_FLAGS_READ_PASSTHRU | IOMMMIO_FLAGS_WRITE_PASSTHRU,
                                    "TPM MMIO", &pThis->hMmio);
     AssertRCReturn(rc, rc);
+
+    /*
+     * Attach any TPM driver below.
+     */
+    rc = PDMDevHlpDriverAttach(pDevIns, 0 /*iLUN*/, &pThisCC->IBase, &pThisCC->pDrvBase, "TPM");
+    if (RT_SUCCESS(rc))
+    {
+        pThisCC->pDrvTpm = PDMIBASE_QUERY_INTERFACE(pThisCC->pDrvBase, PDMITPMCONNECTOR);
+        AssertLogRelMsgReturn(pThisCC->pDrvTpm, ("TPM#%d: Driver is missing the TPM interface.\n", iInstance), VERR_PDM_MISSING_INTERFACE);
+    }
+    else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
+    {
+        pThisCC->pDrvBase = NULL;
+        pThisCC->pDrvTpm  = NULL;
+        LogRel(("TPM#%d: no unit\n", iInstance));
+    }
+    else
+        AssertLogRelMsgRCReturn(rc, ("TPM#%d: Failed to attach to TPM driver. rc=%Rrc\n", iInstance, rc), rc);
+
+    /* Create task for executing requests in ring-3. */
+    rc = PDMDevHlpTaskCreate(pDevIns, PDMTASK_F_RZ, "TPMCmdWrk",
+                             tpmR3CmdExecWorker, NULL /*pvUser*/, &pThis->hTpmCmdTask);
+    AssertRCReturn(rc,rc);
 
     /*
