]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/Tcg/Tcg2Smm/Tcg2Smm.c
SecurityPkg: Tcg2Smm: Separate Tcg2Smm into 2 modules
[mirror_edk2.git] / SecurityPkg / Tcg / Tcg2Smm / Tcg2Smm.c
index 08105c3692ba027131570e83f9ef4c8bb76ef626..589c08794bcf5c8778fedd440eba69c11a9d6bd8 100644 (file)
   PhysicalPresenceCallback() and MemoryClearCallback() will receive untrusted input and do some check.\r
 \r
 Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) Microsoft Corporation.\r
 SPDX-License-Identifier: BSD-2-Clause-Patent\r
 \r
 **/\r
 \r
 #include "Tcg2Smm.h"\r
 \r
-#pragma pack(1)\r
-\r
-typedef struct {\r
-  EFI_ACPI_DESCRIPTION_HEADER Header;\r
-  // Flags field is replaced in version 4 and above\r
-  //    BIT0~15:  PlatformClass      This field is only valid for version 4 and above\r
-  //    BIT16~31: Reserved\r
-  UINT32                      Flags;\r
-  UINT64                      AddressOfControlArea;\r
-  UINT32                      StartMethod;\r
-  UINT8                       PlatformSpecificParameters[12];  // size up to 12\r
-  UINT32                      Laml;                          // Optional\r
-  UINT64                      Lasa;                          // Optional\r
-} EFI_TPM2_ACPI_TABLE_V4;\r
-\r
-#pragma pack()\r
-\r
-EFI_TPM2_ACPI_TABLE_V4  mTpm2AcpiTemplate = {\r
-  {\r
-    EFI_ACPI_5_0_TRUSTED_COMPUTING_PLATFORM_2_TABLE_SIGNATURE,\r
-    sizeof (mTpm2AcpiTemplate),\r
-    EFI_TPM2_ACPI_TABLE_REVISION,\r
-    //\r
-    // Compiler initializes the remaining bytes to 0\r
-    // These fields should be filled in in production\r
-    //\r
-  },\r
-  0, // BIT0~15:  PlatformClass\r
-     // BIT16~31: Reserved\r
-  0, // Control Area\r
-  EFI_TPM2_ACPI_TABLE_START_METHOD_TIS, // StartMethod\r
-};\r
-\r
-EFI_SMM_VARIABLE_PROTOCOL  *mSmmVariable;\r
-TCG_NVS                    *mTcgNvs;\r
+EFI_SMM_VARIABLE_PROTOCOL  *mSmmVariable = NULL;\r
+TCG_NVS                    *mTcgNvs = NULL;\r
+UINTN                       mPpSoftwareSmi;\r
+UINTN                       mMcSoftwareSmi;\r
+EFI_HANDLE                  mReadyToLockHandle;\r
+\r
+/**\r
+  Communication service SMI Handler entry.\r
+\r
+  This handler takes requests to exchange Mmi channel and Nvs address between MM and DXE.\r
+\r
+  Caution: This function may receive untrusted input.\r
+  Communicate buffer and buffer size are external input, so this function will do basic validation.\r
+\r
+  @param[in]      DispatchHandle    The unique handle assigned to this handler by SmiHandlerRegister().\r
+  @param[in]      RegisterContext   Points to an optional handler context which was specified when the\r
+                                    handler was registered.\r
+  @param[in, out] CommBuffer        A pointer to a collection of data in memory that will\r
+                                    be conveyed from a non-SMM environment into an SMM environment.\r
+  @param[in, out] CommBufferSize    The size of the CommBuffer.\r
+\r
+  @retval EFI_SUCCESS               The interrupt was handled and quiesced. No other handlers\r
+                                    should still be called.\r
+  @retval EFI_UNSUPPORTED           An unknown test function was requested.\r
+  @retval EFI_ACCESS_DENIED         Part of the communication buffer lies in an invalid region.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+TpmNvsCommunciate (\r
+  IN     EFI_HANDLE                   DispatchHandle,\r
+  IN     CONST VOID                   *RegisterContext,\r
+  IN OUT VOID                         *CommBuffer,\r
+  IN OUT UINTN                        *CommBufferSize\r
+  )\r
+{\r
+  EFI_STATUS                Status;\r
+  UINTN                     TempCommBufferSize;\r
+  TPM_NVS_MM_COMM_BUFFER    *CommParams;\r
+\r
+  DEBUG ((DEBUG_VERBOSE, "%a()\n", __FUNCTION__));\r
+\r
+  //\r
+  // If input is invalid, stop processing this SMI\r
+  //\r
+  if (CommBuffer == NULL || CommBufferSize == NULL) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
+  TempCommBufferSize = *CommBufferSize;\r
+\r
+  if(TempCommBufferSize != sizeof (TPM_NVS_MM_COMM_BUFFER)) {\r
+    DEBUG ((DEBUG_ERROR, "[%a] MM Communication buffer size is invalid for this handler!\n", __FUNCTION__));\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+  if (!IsBufferOutsideMmValid ((UINTN) CommBuffer, TempCommBufferSize)) {\r
+    DEBUG ((DEBUG_ERROR, "[%a] - MM Communication buffer in invalid location!\n", __FUNCTION__));\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  //\r
+  // Farm out the job to individual functions based on what was requested.\r
+  //\r
+  CommParams = (TPM_NVS_MM_COMM_BUFFER*) CommBuffer;\r
+  Status = EFI_SUCCESS;\r
+  switch (CommParams->Function) {\r
+    case TpmNvsMmExchangeInfo:\r
+      DEBUG ((DEBUG_VERBOSE, "[%a] - Function requested: MM_EXCHANGE_NVS_INFO\n", __FUNCTION__));\r
+      CommParams->RegisteredPpSwiValue = mPpSoftwareSmi;\r
+      CommParams->RegisteredMcSwiValue = mMcSoftwareSmi;\r
+      mTcgNvs = (TCG_NVS*) (UINTN) CommParams->TargetAddress;\r
+      break;\r
+\r
+    default:\r
+      DEBUG ((DEBUG_INFO, "[%a] - Unknown function %d!\n", __FUNCTION__, CommParams->Function));\r
+      Status = EFI_UNSUPPORTED;\r
+      break;\r
+  }\r
+\r
+  CommParams->ReturnStatus = (UINT64) Status;\r
+  return EFI_SUCCESS;\r
+}\r
 \r
 /**\r
   Software SMI callback for TPM physical presence which is called from ACPI method.\r
@@ -186,721 +234,140 @@ MemoryClearCallback (
 }\r
 \r
 /**\r
-  Find the operation region in TCG ACPI table by given Name and Size,\r
-  and initialize it if the region is found.\r
-\r
-  @param[in, out] Table          The TPM item in ACPI table.\r
-  @param[in]      Name           The name string to find in TPM table.\r
-  @param[in]      Size           The size of the region to find.\r
-\r
-  @return                        The allocated address for the found region.\r
-\r
-**/\r
-VOID *\r
-AssignOpRegion (\r
-  EFI_ACPI_DESCRIPTION_HEADER    *Table,\r
-  UINT32                         Name,\r
-  UINT16                         Size\r
-  )\r
-{\r
-  EFI_STATUS                     Status;\r
-  AML_OP_REGION_32_8             *OpRegion;\r
-  EFI_PHYSICAL_ADDRESS           MemoryAddress;\r
-\r
-  MemoryAddress = SIZE_4GB - 1;\r
-\r
-  //\r
-  // Patch some pointers for the ASL code before loading the SSDT.\r
-  //\r
-  for (OpRegion  = (AML_OP_REGION_32_8 *) (Table + 1);\r
-       OpRegion <= (AML_OP_REGION_32_8 *) ((UINT8 *) Table + Table->Length);\r
-       OpRegion  = (AML_OP_REGION_32_8 *) ((UINT8 *) OpRegion + 1)) {\r
-    if ((OpRegion->OpRegionOp  == AML_EXT_REGION_OP) &&\r
-        (OpRegion->NameString  == Name) &&\r
-        (OpRegion->DWordPrefix == AML_DWORD_PREFIX) &&\r
-        (OpRegion->BytePrefix  == AML_BYTE_PREFIX)) {\r
-\r
-      Status = gBS->AllocatePages(AllocateMaxAddress, EfiACPIMemoryNVS, EFI_SIZE_TO_PAGES (Size), &MemoryAddress);\r
-      ASSERT_EFI_ERROR (Status);\r
-      ZeroMem ((VOID *)(UINTN)MemoryAddress, Size);\r
-      OpRegion->RegionOffset = (UINT32) (UINTN) MemoryAddress;\r
-      OpRegion->RegionLen    = (UINT8) Size;\r
-      break;\r
-    }\r
-  }\r
-\r
-  return (VOID *) (UINTN) MemoryAddress;\r
-}\r
-\r
-/**\r
-  Patch version string of Physical Presence interface supported by platform. The initial string tag in TPM\r
-ACPI table is "$PV".\r
-\r
-  @param[in, out] Table          The TPM item in ACPI table.\r
-  @param[in]      PPVer          Version string of Physical Presence interface supported by platform.\r
-\r
-  @return                        The allocated address for the found region.\r
-\r
-**/\r
-EFI_STATUS\r
-UpdatePPVersion (\r
-  EFI_ACPI_DESCRIPTION_HEADER    *Table,\r
-  CHAR8                          *PPVer\r
-  )\r
-{\r
-  EFI_STATUS  Status;\r
-  UINT8       *DataPtr;\r
-\r
-  //\r
-  // Patch some pointers for the ASL code before loading the SSDT.\r
-  //\r
-  for (DataPtr  = (UINT8 *)(Table + 1);\r
-       DataPtr <= (UINT8 *) ((UINT8 *) Table + Table->Length - PHYSICAL_PRESENCE_VERSION_SIZE);\r
-       DataPtr += 1) {\r
-    if (AsciiStrCmp((CHAR8 *)DataPtr,  PHYSICAL_PRESENCE_VERSION_TAG) == 0) {\r
-      Status = AsciiStrCpyS((CHAR8 *)DataPtr, PHYSICAL_PRESENCE_VERSION_SIZE, PPVer);\r
-      DEBUG((EFI_D_INFO, "TPM2 Physical Presence Interface Version update status 0x%x\n", Status));\r
-      return Status;\r
-    }\r
-  }\r
-\r
-  return EFI_NOT_FOUND;\r
-}\r
-\r
-/**\r
-  Patch interrupt resources returned by TPM _PRS. ResourceTemplate to patch is determined by input\r
-  interrupt buffer size. BufferSize, PkgLength and interrupt descriptor in ByteList need to be patched\r
+  Notification for SMM ReadyToLock protocol.\r
 \r
-  @param[in, out] Table            The TPM item in ACPI table.\r
-  @param[in]      IrqBuffer        Input new IRQ buffer.\r
-  @param[in]      IrqBuffserSize   Input new IRQ buffer size.\r
-  @param[out]     IsShortFormPkgLength   If _PRS returns Short length Package(ACPI spec 20.2.4).\r
+  @param[in] Protocol   Points to the protocol's unique identifier.\r
+  @param[in] Interface  Points to the interface instance.\r
+  @param[in] Handle     The handle on which the interface was installed.\r
 \r
-  @return                          patch status.\r
+  @retval EFI_SUCCESS   Notification runs successfully.\r
 \r
 **/\r
 EFI_STATUS\r
-UpdatePossibleResource (\r
-  IN OUT  EFI_ACPI_DESCRIPTION_HEADER    *Table,\r
-  IN      UINT32                         *IrqBuffer,\r
-  IN      UINT32                         IrqBuffserSize,\r
-  OUT     BOOLEAN                        *IsShortFormPkgLength\r
-  )\r
-{\r
-  UINT8       *DataPtr;\r
-  UINT8       *DataEndPtr;\r
-  UINT32      NewPkgLength;\r
-  UINT32      OrignalPkgLength;\r
-\r
-  NewPkgLength     = 0;\r
-  OrignalPkgLength = 0;\r
-  DataEndPtr       = NULL;\r
-\r
-  //\r
-  // Follow ACPI spec\r
-  //           6.4.3   Extend Interrupt Descriptor.\r
-  //           19.3.3 ASL Resource Template\r
-  //           20      AML specification\r
-  // to patch TPM ACPI object _PRS returned ResourceTemplate() containing 2 resource descriptors and an auto appended End Tag\r
-  //\r
-  //  AML data is organized by following rule.\r
-  //  Code need to patch BufferSize and PkgLength and interrupt descriptor in ByteList\r
-  //\r
-  // =============  Buffer ====================\r
-  //           DefBuffer := BufferOp PkgLength BufferSize ByteList\r
-  //            BufferOp := 0x11\r
-  //\r
-  // ==============PkgLength==================\r
-  //          PkgLength := PkgLeadByte |\r
-  //                              <PkgLeadByte ByteData> |\r
-  //                              <PkgLeadByte ByteData ByteData> |\r
-  //                              <PkgLeadByte ByteData ByteData ByteData>\r
-  //\r
-  //       PkgLeadByte := <bit 7-6: ByteData count that follows (0-3)>\r
-  //                               <bit 5-4: Only used if PkgLength <= 63 >\r
-  //                               <bit 3-0: Least significant package length nybble>\r
-  //\r
-  //==============BufferSize==================\r
-  //        BufferSize := Integer\r
-  //           Integer := ByteConst|WordConst|DwordConst....\r
-  //\r
-  //           ByteConst := BytePrefix ByteData\r
-  //\r
-  //==============ByteList===================\r
-  //          ByteList := ByteData ByteList\r
-  //\r
-  //=========================================\r
-\r
-  //\r
-  // 1. Check TPM_PRS_RESS with PkgLength <=63 can hold the input interrupt number buffer for patching\r
-  //\r
-  for (DataPtr  = (UINT8 *)(Table + 1);\r
-       DataPtr < (UINT8 *) ((UINT8 *) Table + Table->Length - (TPM_PRS_RES_NAME_SIZE + TPM_POS_RES_TEMPLATE_MIN_SIZE));\r
-       DataPtr += 1) {\r
-    if (CompareMem(DataPtr, TPM_PRS_RESS, TPM_PRS_RES_NAME_SIZE) == 0) {\r
-      //\r
-      // Jump over object name & BufferOp\r
-      //\r
-      DataPtr += TPM_PRS_RES_NAME_SIZE + 1;\r
-\r
-      if ((*DataPtr & (BIT7|BIT6)) == 0) {\r
-        OrignalPkgLength = (UINT32)*DataPtr;\r
-        DataEndPtr       = DataPtr + OrignalPkgLength;\r
-\r
-        //\r
-        // Jump over PkgLength = PkgLeadByte only\r
-        //\r
-        NewPkgLength++;\r
-\r
-        //\r
-        // Jump over BufferSize\r
-        //\r
-        if (*(DataPtr + 1) == AML_BYTE_PREFIX) {\r
-          NewPkgLength += 2;\r
-        } else if (*(DataPtr + 1) == AML_WORD_PREFIX) {\r
-          NewPkgLength += 3;\r
-        } else if (*(DataPtr + 1) == AML_DWORD_PREFIX) {\r
-          NewPkgLength += 5;\r
-        } else {\r
-          ASSERT(FALSE);\r
-          return EFI_UNSUPPORTED;\r
-        }\r
-      } else {\r
-        ASSERT(FALSE);\r
-        return EFI_UNSUPPORTED;\r
-      }\r
-\r
-      //\r
-      // Include Memory32Fixed Descriptor (12 Bytes) + Interrupt Descriptor header(5 Bytes) + End Tag(2 Bytes)\r
-      //\r
-      NewPkgLength += 19 + IrqBuffserSize;\r
-      if (NewPkgLength > 63) {\r
-        break;\r
-      }\r
-\r
-      if (NewPkgLength > OrignalPkgLength) {\r
-        ASSERT(FALSE);\r
-        return EFI_INVALID_PARAMETER;\r
-      }\r
-\r
-      //\r
-      // 1.1 Patch PkgLength\r
-      //\r
-      *DataPtr = (UINT8)NewPkgLength;\r
-\r
-      //\r
-      // 1.2 Patch BufferSize = sizeof(Memory32Fixed Descriptor + Interrupt Descriptor + End Tag).\r
-      //      It is Little endian. So only patch lowest byte of BufferSize due to current interrupt number limit.\r
-      //\r
-      *(DataPtr + 2) = (UINT8)(IrqBuffserSize + 19);\r
-\r
-      //\r
-      // Notify _PRS to report short formed ResourceTemplate\r
-      //\r
-      *IsShortFormPkgLength = TRUE;\r
-\r
-      break;\r
-    }\r
-  }\r
-\r
-  //\r
-  // 2. Use TPM_PRS_RESL with PkgLength > 63 to hold longer input interrupt number buffer for patching\r
-  //\r
-  if (NewPkgLength > 63) {\r
-    NewPkgLength     = 0;\r
-    OrignalPkgLength = 0;\r
-    for (DataPtr  = (UINT8 *)(Table + 1);\r
-         DataPtr < (UINT8 *) ((UINT8 *) Table + Table->Length - (TPM_PRS_RES_NAME_SIZE + TPM_POS_RES_TEMPLATE_MIN_SIZE));\r
-         DataPtr += 1) {\r
-      if (CompareMem(DataPtr, TPM_PRS_RESL, TPM_PRS_RES_NAME_SIZE) == 0) {\r
-        //\r
-        // Jump over object name & BufferOp\r
-        //\r
-        DataPtr += TPM_PRS_RES_NAME_SIZE + 1;\r
-\r
-        if ((*DataPtr & (BIT7|BIT6)) != 0) {\r
-          OrignalPkgLength = (UINT32)(*(DataPtr + 1) << 4) + (*DataPtr & 0x0F);\r
-          DataEndPtr       = DataPtr + OrignalPkgLength;\r
-          //\r
-          // Jump over PkgLength = PkgLeadByte + ByteData length\r
-          //\r
-          NewPkgLength += 1 + ((*DataPtr & (BIT7|BIT6)) >> 6);\r
-\r
-          //\r
-          // Jump over BufferSize\r
-          //\r
-          if (*(DataPtr + NewPkgLength) == AML_BYTE_PREFIX) {\r
-            NewPkgLength += 2;\r
-          } else if (*(DataPtr + NewPkgLength) == AML_WORD_PREFIX) {\r
-            NewPkgLength += 3;\r
-          } else if (*(DataPtr + NewPkgLength) == AML_DWORD_PREFIX) {\r
-            NewPkgLength += 5;\r
-          } else {\r
-            ASSERT(FALSE);\r
-            return EFI_UNSUPPORTED;\r
-          }\r
-        } else {\r
-          ASSERT(FALSE);\r
-          return EFI_UNSUPPORTED;\r
-        }\r
-\r
-        //\r
-        // Include Memory32Fixed Descriptor (12 Bytes) + Interrupt Descriptor header(5 Bytes) + End Tag(2  Bytes)\r
-        //\r
-        NewPkgLength += 19 + IrqBuffserSize;\r
-\r
-        if (NewPkgLength > OrignalPkgLength) {\r
-          ASSERT(FALSE);\r
-          return EFI_INVALID_PARAMETER;\r
-        }\r
-\r
-        //\r
-        // 2.1 Patch PkgLength. Only patch PkgLeadByte and first ByteData\r
-        //\r
-        *DataPtr = (UINT8)((*DataPtr) & 0xF0) | (NewPkgLength & 0x0F);\r
-        *(DataPtr + 1) = (UINT8)((NewPkgLength & 0xFF0) >> 4);\r
-\r
-        //\r
-        // 2.2 Patch BufferSize = sizeof(Memory32Fixed Descriptor + Interrupt Descriptor + End Tag).\r
-        //     It is Little endian. Only patch lowest byte of BufferSize due to current interrupt number limit.\r
-        //\r
-        *(DataPtr + 2 + ((*DataPtr & (BIT7|BIT6)) >> 6)) = (UINT8)(IrqBuffserSize + 19);\r
-\r
-        //\r
-        // Notify _PRS to report long formed ResourceTemplate\r
-        //\r
-        *IsShortFormPkgLength = FALSE;\r
-        break;\r
-      }\r
-    }\r
-  }\r
-\r
-  if (DataPtr >= (UINT8 *) ((UINT8 *) Table + Table->Length - (TPM_PRS_RES_NAME_SIZE + TPM_POS_RES_TEMPLATE_MIN_SIZE))) {\r
-    return EFI_NOT_FOUND;\r
-  }\r
-\r
-  //\r
-  // 3. Move DataPtr to Interrupt descriptor header and patch interrupt descriptor.\r
-  //     5 bytes for interrupt descriptor header, 2 bytes for End Tag\r
-  //\r
-  DataPtr += NewPkgLength - (5 + IrqBuffserSize + 2);\r
-  //\r
-  //   3.1 Patch Length bit[7:0] of Interrupt descriptor patch interrupt descriptor\r
-  //\r
-  *(DataPtr + 1) = (UINT8)(2 + IrqBuffserSize);\r
-  //\r
-  //   3.2 Patch Interrupt Table Length\r
-  //\r
-  *(DataPtr + 4) = (UINT8)(IrqBuffserSize / sizeof(UINT32));\r
-  //\r
-  //   3.3 Copy patched InterruptNumBuffer\r
-  //\r
-  CopyMem(DataPtr + 5, IrqBuffer, IrqBuffserSize);\r
-\r
-  //\r
-  // 4. Jump over Interrupt descriptor and Patch END Tag, set Checksum field to 0\r
-  //\r
-  DataPtr       += 5 + IrqBuffserSize;\r
-  *DataPtr       = ACPI_END_TAG_DESCRIPTOR;\r
-  *(DataPtr + 1) = 0;\r
-\r
-  //\r
-  // 5. Jump over new ResourceTemplate. Stuff rest bytes to NOOP\r
-  //\r
-  DataPtr += 2;\r
-  if (DataPtr < DataEndPtr) {\r
-    SetMem(DataPtr, (UINTN)DataEndPtr - (UINTN)DataPtr, AML_NOOP_OP);\r
-  }\r
-\r
-  return EFI_SUCCESS;\r
-}\r
-\r
-/**\r
-  Patch TPM2 device HID string.  The initial string tag in TPM2 ACPI table is "NNN0000".\r
-\r
-  @param[in, out] Table          The TPM2 SSDT ACPI table.\r
-\r
-  @return                               HID Update status.\r
-\r
-**/\r
-EFI_STATUS\r
-UpdateHID (\r
-  EFI_ACPI_DESCRIPTION_HEADER    *Table\r
-  )\r
-{\r
-  EFI_STATUS  Status;\r
-  UINT8       *DataPtr;\r
-  CHAR8       Hid[TPM_HID_ACPI_SIZE];\r
-  UINT32      ManufacturerID;\r
-  UINT32      FirmwareVersion1;\r
-  UINT32      FirmwareVersion2;\r
-  BOOLEAN     PnpHID;\r
-\r
-  PnpHID = TRUE;\r
-\r
-  //\r
-  // Initialize HID with Default PNP string\r
-  //\r
-  ZeroMem(Hid, TPM_HID_ACPI_SIZE);\r
-\r
-  //\r
-  // Get Manufacturer ID\r
-  //\r
-  Status = Tpm2GetCapabilityManufactureID(&ManufacturerID);\r
-  if (!EFI_ERROR(Status)) {\r
-    DEBUG((EFI_D_INFO, "TPM_PT_MANUFACTURER 0x%08x\n", ManufacturerID));\r
-    //\r
-    // ManufacturerID defined in TCG Vendor ID Registry\r
-    // may tailed with 0x00 or 0x20\r
-    //\r
-    if ((ManufacturerID >> 24) == 0x00 || ((ManufacturerID >> 24) == 0x20)) {\r
-      //\r
-      //  HID containing PNP ID "NNN####"\r
-      //   NNN is uppercase letter for Vendor ID specified by manufacturer\r
-      //\r
-      CopyMem(Hid, &ManufacturerID, 3);\r
-    } else {\r
-      //\r
-      //  HID containing ACP ID "NNNN####"\r
-      //   NNNN is uppercase letter for Vendor ID specified by manufacturer\r
-      //\r
-      CopyMem(Hid, &ManufacturerID, 4);\r
-      PnpHID = FALSE;\r
-    }\r
-  } else {\r
-    DEBUG ((EFI_D_ERROR, "Get TPM_PT_MANUFACTURER failed %x!\n", Status));\r
-    ASSERT(FALSE);\r
-    return Status;\r
-  }\r
-\r
-  Status = Tpm2GetCapabilityFirmwareVersion(&FirmwareVersion1, &FirmwareVersion2);\r
-  if (!EFI_ERROR(Status)) {\r
-    DEBUG((EFI_D_INFO, "TPM_PT_FIRMWARE_VERSION_1 0x%x\n", FirmwareVersion1));\r
-    DEBUG((EFI_D_INFO, "TPM_PT_FIRMWARE_VERSION_2 0x%x\n", FirmwareVersion2));\r
-    //\r
-    //   #### is Firmware Version 1\r
-    //\r
-    if (PnpHID) {\r
-      AsciiSPrint(Hid + 3, TPM_HID_PNP_SIZE - 3, "%02d%02d", ((FirmwareVersion1 & 0xFFFF0000) >> 16), (FirmwareVersion1 & 0x0000FFFF));\r
-    } else {\r
-      AsciiSPrint(Hid + 4, TPM_HID_ACPI_SIZE - 4, "%02d%02d", ((FirmwareVersion1 & 0xFFFF0000) >> 16), (FirmwareVersion1 & 0x0000FFFF));\r
-    }\r
-\r
-  } else {\r
-    DEBUG ((EFI_D_ERROR, "Get TPM_PT_FIRMWARE_VERSION_X failed %x!\n", Status));\r
-    ASSERT(FALSE);\r
-    return Status;\r
-  }\r
-\r
-  //\r
-  // Patch HID in ASL code before loading the SSDT.\r
-  //\r
-  for (DataPtr  = (UINT8 *)(Table + 1);\r
-       DataPtr <= (UINT8 *) ((UINT8 *) Table + Table->Length - TPM_HID_PNP_SIZE);\r
-       DataPtr += 1) {\r
-    if (AsciiStrCmp((CHAR8 *)DataPtr,  TPM_HID_TAG) == 0) {\r
-      if (PnpHID) {\r
-        CopyMem(DataPtr, Hid, TPM_HID_PNP_SIZE);\r
-        //\r
-        // if HID is PNP ID, patch the last byte in HID TAG to Noop\r
-        //\r
-        *(DataPtr + TPM_HID_PNP_SIZE) = AML_NOOP_OP;\r
-      } else {\r
-\r
-        CopyMem(DataPtr, Hid, TPM_HID_ACPI_SIZE);\r
-      }\r
-      DEBUG((DEBUG_INFO, "TPM2 ACPI _HID is patched to %a\n", DataPtr));\r
-\r
-      return Status;\r
-    }\r
-  }\r
-\r
-  DEBUG((EFI_D_ERROR, "TPM2 ACPI HID TAG for patch not found!\n"));\r
-  return EFI_NOT_FOUND;\r
-}\r
-\r
-/**\r
-  Initialize and publish TPM items in ACPI table.\r
-\r
-  @retval   EFI_SUCCESS     The TCG ACPI table is published successfully.\r
-  @retval   Others          The TCG ACPI table is not published.\r
-\r
-**/\r
-EFI_STATUS\r
-PublishAcpiTable (\r
-  VOID\r
-  )\r
-{\r
-  EFI_STATUS                     Status;\r
-  EFI_ACPI_TABLE_PROTOCOL        *AcpiTable;\r
-  UINTN                          TableKey;\r
-  EFI_ACPI_DESCRIPTION_HEADER    *Table;\r
-  UINTN                          TableSize;\r
-  UINT32                         *PossibleIrqNumBuf;\r
-  UINT32                         PossibleIrqNumBufSize;\r
-  BOOLEAN                        IsShortFormPkgLength;\r
-\r
-  IsShortFormPkgLength = FALSE;\r
-\r
-  Status = GetSectionFromFv (\r
-             &gEfiCallerIdGuid,\r
-             EFI_SECTION_RAW,\r
-             0,\r
-             (VOID **) &Table,\r
-             &TableSize\r
-             );\r
-  ASSERT_EFI_ERROR (Status);\r
-\r
-  //\r
-  // Measure to PCR[0] with event EV_POST_CODE ACPI DATA.\r
-  // The measurement has to be done before any update.\r
-  // Otherwise, the PCR record would be different after TPM FW update\r
-  // or the PCD configuration change.\r
-  //\r
-  TpmMeasureAndLogData(\r
-    0,\r
-    EV_POST_CODE,\r
-    EV_POSTCODE_INFO_ACPI_DATA,\r
-    ACPI_DATA_LEN,\r
-    Table,\r
-    TableSize\r
-    );\r
-\r
-  //\r
-  // Update Table version before measuring it to PCR\r
-  //\r
-  Status = UpdatePPVersion(Table, (CHAR8 *)PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer));\r
-  ASSERT_EFI_ERROR (Status);\r
-\r
-  DEBUG ((\r
-    DEBUG_INFO,\r
-    "Current physical presence interface version - %a\n",\r
-    (CHAR8 *) PcdGetPtr(PcdTcgPhysicalPresenceInterfaceVer)\r
-    ));\r
-\r
-  //\r
-  // Update TPM2 HID after measuring it to PCR\r
-  //\r
-  Status = UpdateHID(Table);\r
-  if (EFI_ERROR(Status)) {\r
-    return Status;\r
-  }\r
-\r
-  if (PcdGet32(PcdTpm2CurrentIrqNum) != 0) {\r
-    //\r
-    // Patch _PRS interrupt resource only when TPM interrupt is supported\r
-    //\r
-    PossibleIrqNumBuf     = (UINT32 *)PcdGetPtr(PcdTpm2PossibleIrqNumBuf);\r
-    PossibleIrqNumBufSize = (UINT32)PcdGetSize(PcdTpm2PossibleIrqNumBuf);\r
-\r
-    if (PossibleIrqNumBufSize <= MAX_PRS_INT_BUF_SIZE && (PossibleIrqNumBufSize % sizeof(UINT32)) == 0) {\r
-      Status = UpdatePossibleResource(Table, PossibleIrqNumBuf, PossibleIrqNumBufSize, &IsShortFormPkgLength);\r
-      DEBUG ((\r
-        DEBUG_INFO,\r
-        "UpdatePossibleResource status - %x. TPM2 service may not ready in OS.\n",\r
-        Status\r
-        ));\r
-    } else {\r
-      DEBUG ((\r
-        DEBUG_INFO,\r
-        "PcdTpm2PossibleIrqNumBuf size %x is not correct. TPM2 service may not ready in OS.\n",\r
-        PossibleIrqNumBufSize\r
-      ));\r
-    }\r
-  }\r
-\r
-  ASSERT (Table->OemTableId == SIGNATURE_64 ('T', 'p', 'm', '2', 'T', 'a', 'b', 'l'));\r
-  CopyMem (Table->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (Table->OemId) );\r
-  mTcgNvs = AssignOpRegion (Table, SIGNATURE_32 ('T', 'N', 'V', 'S'), (UINT16) sizeof (TCG_NVS));\r
-  ASSERT (mTcgNvs != NULL);\r
-  mTcgNvs->TpmIrqNum            = PcdGet32(PcdTpm2CurrentIrqNum);\r
-  mTcgNvs->IsShortFormPkgLength = IsShortFormPkgLength;\r
-\r
-  //\r
-  // Publish the TPM ACPI table. Table is re-checksummed.\r
-  //\r
-  Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);\r
-  ASSERT_EFI_ERROR (Status);\r
-\r
-  TableKey = 0;\r
-  Status = AcpiTable->InstallAcpiTable (\r
-                        AcpiTable,\r
-                        Table,\r
-                        TableSize,\r
-                        &TableKey\r
-                        );\r
-  ASSERT_EFI_ERROR (Status);\r
-\r
-  return Status;\r
-}\r
-\r
-/**\r
-  Publish TPM2 ACPI table\r
-\r
-  @retval   EFI_SUCCESS     The TPM2 ACPI table is published successfully.\r
-  @retval   Others          The TPM2 ACPI table is not published.\r
-\r
-**/\r
-EFI_STATUS\r
-PublishTpm2 (\r
-  VOID\r
-  )\r
+EFIAPI\r
+TcgMmReadyToLock (\r
+  IN CONST EFI_GUID  *Protocol,\r
+  IN VOID            *Interface,\r
+  IN EFI_HANDLE      Handle\r
+)\r
 {\r
-  EFI_STATUS                     Status;\r
-  EFI_ACPI_TABLE_PROTOCOL        *AcpiTable;\r
-  UINTN                          TableKey;\r
-  UINT64                         OemTableId;\r
-  EFI_TPM2_ACPI_CONTROL_AREA     *ControlArea;\r
-  TPM2_PTP_INTERFACE_TYPE        InterfaceType;\r
-\r
-  //\r
-  // Measure to PCR[0] with event EV_POST_CODE ACPI DATA.\r
-  // The measurement has to be done before any update.\r
-  // Otherwise, the PCR record would be different after event log update\r
-  // or the PCD configuration change.\r
-  //\r
-  TpmMeasureAndLogData(\r
-    0,\r
-    EV_POST_CODE,\r
-    EV_POSTCODE_INFO_ACPI_DATA,\r
-    ACPI_DATA_LEN,\r
-    &mTpm2AcpiTemplate,\r
-    mTpm2AcpiTemplate.Header.Length\r
-    );\r
-\r
-  mTpm2AcpiTemplate.Header.Revision = PcdGet8(PcdTpm2AcpiTableRev);\r
-  DEBUG((DEBUG_INFO, "Tpm2 ACPI table revision is %d\n", mTpm2AcpiTemplate.Header.Revision));\r
-\r
-  //\r
-  // PlatformClass is only valid for version 4 and above\r
-  //    BIT0~15:  PlatformClass\r
-  //    BIT16~31: Reserved\r
-  //\r
-  if (mTpm2AcpiTemplate.Header.Revision >= EFI_TPM2_ACPI_TABLE_REVISION_4) {\r
-    mTpm2AcpiTemplate.Flags = (mTpm2AcpiTemplate.Flags & 0xFFFF0000) | PcdGet8(PcdTpmPlatformClass);\r
-    DEBUG((DEBUG_INFO, "Tpm2 ACPI table PlatformClass is %d\n", (mTpm2AcpiTemplate.Flags & 0x0000FFFF)));\r
-  }\r
-\r
-  mTpm2AcpiTemplate.Laml = PcdGet32(PcdTpm2AcpiTableLaml);\r
-  mTpm2AcpiTemplate.Lasa = PcdGet64(PcdTpm2AcpiTableLasa);\r
-  if ((mTpm2AcpiTemplate.Header.Revision < EFI_TPM2_ACPI_TABLE_REVISION_4) ||\r
-      (mTpm2AcpiTemplate.Laml == 0) || (mTpm2AcpiTemplate.Lasa == 0)) {\r
-    //\r
-    // If version is smaller than 4 or Laml/Lasa is not valid, rollback to original Length.\r
-    //\r
-    mTpm2AcpiTemplate.Header.Length = sizeof(EFI_TPM2_ACPI_TABLE);\r
-  }\r
+  EFI_STATUS Status;\r
 \r
-  InterfaceType = PcdGet8(PcdActiveTpmInterfaceType);\r
-  switch (InterfaceType) {\r
-  case Tpm2PtpInterfaceCrb:\r
-    mTpm2AcpiTemplate.StartMethod = EFI_TPM2_ACPI_TABLE_START_METHOD_COMMAND_RESPONSE_BUFFER_INTERFACE;\r
-    mTpm2AcpiTemplate.AddressOfControlArea = PcdGet64 (PcdTpmBaseAddress) + 0x40;\r
-    ControlArea = (EFI_TPM2_ACPI_CONTROL_AREA *)(UINTN)mTpm2AcpiTemplate.AddressOfControlArea;\r
-    ControlArea->CommandSize  = 0xF80;\r
-    ControlArea->ResponseSize = 0xF80;\r
-    ControlArea->Command      = PcdGet64 (PcdTpmBaseAddress) + 0x80;\r
-    ControlArea->Response     = PcdGet64 (PcdTpmBaseAddress) + 0x80;\r
-    break;\r
-  case Tpm2PtpInterfaceFifo:\r
-  case Tpm2PtpInterfaceTis:\r
-    break;\r
-  default:\r
-    DEBUG((EFI_D_ERROR, "TPM2 InterfaceType get error! %d\n", InterfaceType));\r
-    break;\r
+  if (mReadyToLockHandle != NULL) {\r
+    Status = gMmst->MmiHandlerUnRegister (mReadyToLockHandle);\r
+    mReadyToLockHandle = NULL;\r
   }\r
-\r
-  CopyMem (mTpm2AcpiTemplate.Header.OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (mTpm2AcpiTemplate.Header.OemId));\r
-  OemTableId = PcdGet64 (PcdAcpiDefaultOemTableId);\r
-  CopyMem (&mTpm2AcpiTemplate.Header.OemTableId, &OemTableId, sizeof (UINT64));\r
-  mTpm2AcpiTemplate.Header.OemRevision      = PcdGet32 (PcdAcpiDefaultOemRevision);\r
-  mTpm2AcpiTemplate.Header.CreatorId        = PcdGet32 (PcdAcpiDefaultCreatorId);\r
-  mTpm2AcpiTemplate.Header.CreatorRevision  = PcdGet32 (PcdAcpiDefaultCreatorRevision);\r
-\r
-  //\r
-  // Construct ACPI table\r
-  //\r
-  Status = gBS->LocateProtocol (&gEfiAcpiTableProtocolGuid, NULL, (VOID **) &AcpiTable);\r
-  ASSERT_EFI_ERROR (Status);\r
-\r
-  Status = AcpiTable->InstallAcpiTable (\r
-                        AcpiTable,\r
-                        &mTpm2AcpiTemplate,\r
-                        mTpm2AcpiTemplate.Header.Length,\r
-                        &TableKey\r
-                        );\r
-  ASSERT_EFI_ERROR (Status);\r
-\r
   return Status;\r
 }\r
 \r
 /**\r
-  The driver's entry point.\r
+  The driver's common initialization routine.\r
 \r
   It install callbacks for TPM physical presence and MemoryClear, and locate\r
   SMM variable to be used in the callback function.\r
 \r
-  @param[in] ImageHandle  The firmware allocated handle for the EFI image.\r
-  @param[in] SystemTable  A pointer to the EFI System Table.\r
-\r
   @retval EFI_SUCCESS     The entry point is executed successfully.\r
   @retval Others          Some error occurs when executing this entry point.\r
 \r
 **/\r
 EFI_STATUS\r
-EFIAPI\r
-InitializeTcgSmm (\r
-  IN EFI_HANDLE                  ImageHandle,\r
-  IN EFI_SYSTEM_TABLE            *SystemTable\r
+InitializeTcgCommon (\r
+  VOID\r
   )\r
 {\r
   EFI_STATUS                     Status;\r
   EFI_SMM_SW_DISPATCH2_PROTOCOL  *SwDispatch;\r
   EFI_SMM_SW_REGISTER_CONTEXT    SwContext;\r
-  EFI_HANDLE                     SwHandle;\r
+  EFI_HANDLE                     PpSwHandle;\r
+  EFI_HANDLE                     McSwHandle;\r
+  EFI_HANDLE                     NotifyHandle;\r
 \r
   if (!CompareGuid (PcdGetPtr(PcdTpmInstanceGuid), &gEfiTpmDeviceInstanceTpm20DtpmGuid)){\r
     DEBUG ((EFI_D_ERROR, "No TPM2 DTPM instance required!\n"));\r
     return EFI_UNSUPPORTED;\r
   }\r
 \r
-  Status = PublishAcpiTable ();\r
+  // Initialize variables first\r
+  mReadyToLockHandle = NULL;\r
+  SwDispatch = NULL;\r
+  PpSwHandle = NULL;\r
+  McSwHandle = NULL;\r
+  NotifyHandle = NULL;\r
+\r
+  // Register a root handler to communicate the NVS region and SMI channel between MM and DXE\r
+  Status = gMmst->MmiHandlerRegister (TpmNvsCommunciate, &gTpmNvsMmGuid, &mReadyToLockHandle);\r
   ASSERT_EFI_ERROR (Status);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "[%a] Failed to register NVS communicate as root MM handler - %r!\n", __FUNCTION__, Status));\r
+    goto Cleanup;\r
+  }\r
 \r
   //\r
   // Get the Sw dispatch protocol and register SMI callback functions.\r
   //\r
   Status = gMmst->MmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NULL, (VOID**)&SwDispatch);\r
   ASSERT_EFI_ERROR (Status);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "[%a] Failed to locate Sw dispatch protocol - %r!\n", __FUNCTION__, Status));\r
+    goto Cleanup;\r
+  }\r
+\r
   SwContext.SwSmiInputValue = (UINTN) -1;\r
-  Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &SwHandle);\r
+  Status = SwDispatch->Register (SwDispatch, PhysicalPresenceCallback, &SwContext, &PpSwHandle);\r
   ASSERT_EFI_ERROR (Status);\r
   if (EFI_ERROR (Status)) {\r
-    return Status;\r
+    DEBUG ((DEBUG_ERROR, "[%a] Failed to register PP callback as SW MM handler - %r!\n", __FUNCTION__, Status));\r
+    goto Cleanup;\r
   }\r
-  mTcgNvs->PhysicalPresence.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;\r
+  mPpSoftwareSmi = SwContext.SwSmiInputValue;\r
 \r
   SwContext.SwSmiInputValue = (UINTN) -1;\r
-  Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &SwHandle);\r
+  Status = SwDispatch->Register (SwDispatch, MemoryClearCallback, &SwContext, &McSwHandle);\r
   ASSERT_EFI_ERROR (Status);\r
   if (EFI_ERROR (Status)) {\r
-    return Status;\r
+    DEBUG ((DEBUG_ERROR, "[%a] Failed to register MC callback as SW MM handler - %r!\n", __FUNCTION__, Status));\r
+    goto Cleanup;\r
   }\r
-  mTcgNvs->MemoryClear.SoftwareSmi = (UINT8) SwContext.SwSmiInputValue;\r
+  mMcSoftwareSmi = SwContext.SwSmiInputValue;\r
 \r
   //\r
   // Locate SmmVariableProtocol.\r
   //\r
   Status = gMmst->MmLocateProtocol (&gEfiSmmVariableProtocolGuid, NULL, (VOID**)&mSmmVariable);\r
   ASSERT_EFI_ERROR (Status);\r
+  if (EFI_ERROR (Status)) {\r
+    // Should not happen\r
+    DEBUG ((DEBUG_ERROR, "[%a] Failed to locate SMM variable protocol - %r!\n", __FUNCTION__, Status));\r
+    goto Cleanup;\r
+  }\r
 \r
-  //\r
-  // Set TPM2 ACPI table\r
-  //\r
-  Status = PublishTpm2 ();\r
+  // Turn off the light before leaving the room... at least, take a remote...\r
+  Status = gMmst->MmRegisterProtocolNotify (&gEfiMmReadyToLockProtocolGuid, TcgMmReadyToLock, &NotifyHandle);\r
   ASSERT_EFI_ERROR (Status);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((DEBUG_ERROR, "[%a] Failed to register ready to lock notification - %r!\n", __FUNCTION__, Status));\r
+    goto Cleanup;\r
+  }\r
 \r
+  Tcg2NotifyMmReady ();\r
 \r
-  return EFI_SUCCESS;\r
+Cleanup:\r
+  if (EFI_ERROR (Status)) {\r
+    // Something is whacked, clean up the mess...\r
+    if (NotifyHandle != NULL) {\r
+      gMmst->MmRegisterProtocolNotify (&gEfiMmReadyToLockProtocolGuid, NULL, &NotifyHandle);\r
+    }\r
+    if (McSwHandle != NULL && SwDispatch != NULL) {\r
+      SwDispatch->UnRegister (SwDispatch, McSwHandle);\r
+    }\r
+    if (PpSwHandle != NULL && SwDispatch != NULL) {\r
+      SwDispatch->UnRegister (SwDispatch, PpSwHandle);\r
+    }\r
+    if (mReadyToLockHandle != NULL) {\r
+      gMmst->MmiHandlerUnRegister (mReadyToLockHandle);\r
+    }\r
+  }\r
+\r
+  return Status;\r
 }\r
 \r