]> git.proxmox.com Git - mirror_edk2.git/blobdiff - UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmStm.c
UefiCpuPkg/SmmCpuFeaturesLibStm: Add STM library instance
[mirror_edk2.git] / UefiCpuPkg / Library / SmmCpuFeaturesLib / SmmStm.c
diff --git a/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmStm.c b/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmStm.c
new file mode 100644 (file)
index 0000000..59c49e3
--- /dev/null
@@ -0,0 +1,1299 @@
+/** @file\r
+  SMM STM support functions\r
+\r
+  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php.\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiSmm.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/SmmServicesTableLib.h>\r
+#include <Library/TpmMeasurementLib.h>\r
+#include <Register/Cpuid.h>\r
+#include <Register/ArchitecturalMsr.h>\r
+#include <Register/SmramSaveStateMap.h>\r
+\r
+#include <Protocol/MpService.h>\r
+\r
+#include "SmmStm.h"\r
+\r
+#define TXT_EVTYPE_BASE                  0x400\r
+#define TXT_EVTYPE_STM_HASH              (TXT_EVTYPE_BASE + 14)\r
+\r
+#define RDWR_ACCS             3\r
+#define FULL_ACCS             7\r
+\r
+/**\r
+  The constructor 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 constructor always returns EFI_SUCCESS.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmCpuFeaturesLibConstructor (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  );\r
+\r
+EFI_HANDLE  mStmSmmCpuHandle = NULL;\r
+\r
+BOOLEAN mLockLoadMonitor = FALSE;\r
+\r
+//\r
+// Template of STM_RSC_END structure for copying.\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED STM_RSC_END mRscEndNode = {\r
+  {END_OF_RESOURCES, sizeof (STM_RSC_END)},\r
+};\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8  *mStmResourcesPtr         = NULL;\r
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN  mStmResourceTotalSize     = 0x0;\r
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN  mStmResourceSizeUsed      = 0x0;\r
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN  mStmResourceSizeAvailable = 0x0;\r
+\r
+GLOBAL_REMOVE_IF_UNREFERENCED UINT32  mStmState = 0;\r
+\r
+//\r
+// System Configuration Table pointing to STM Configuration Table\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED\r
+EFI_SM_MONITOR_INIT_PROTOCOL mSmMonitorInitProtocol = {\r
+  LoadMonitor,\r
+  AddPiResource,\r
+  DeletePiResource,\r
+  GetPiResource,\r
+  GetMonitorState,\r
+};\r
+\r
+\r
+\r
+\r
+#define   CPUID1_EDX_XD_SUPPORT      0x100000\r
+\r
+//\r
+// External global variables associated with SMI Handler Template\r
+//\r
+extern CONST TXT_PROCESSOR_SMM_DESCRIPTOR  gcStmPsd;\r
+extern UINT32                              gStmSmbase;\r
+extern volatile UINT32                     gStmSmiStack;\r
+extern UINT32                              gStmSmiCr3;\r
+extern volatile UINT8                      gcStmSmiHandlerTemplate[];\r
+extern CONST UINT16                        gcStmSmiHandlerSize;\r
+extern UINT16                              gcStmSmiHandlerOffset;\r
+extern BOOLEAN                             gStmXdSupported;\r
+\r
+//\r
+// Variables used by SMI Handler\r
+//\r
+IA32_DESCRIPTOR  gStmSmiHandlerIdtr;\r
+\r
+//\r
+// MP Services Protocol\r
+//\r
+EFI_MP_SERVICES_PROTOCOL  *mSmmCpuFeaturesLibMpService = NULL;\r
+\r
+//\r
+// MSEG Base and Length in SMRAM\r
+//\r
+UINTN  mMsegBase = 0;\r
+UINTN  mMsegSize = 0;\r
+\r
+BOOLEAN  mStmConfigurationTableInitialized = FALSE;\r
+\r
+\r
+/**\r
+  The constructor 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 constructor always returns EFI_SUCCESS.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmCpuFeaturesLibStmConstructor (\r
+  IN EFI_HANDLE        ImageHandle,\r
+  IN EFI_SYSTEM_TABLE  *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  CPUID_VERSION_INFO_ECX  RegEcx;\r
+  EFI_HOB_GUID_TYPE       *GuidHob;\r
+  EFI_SMRAM_DESCRIPTOR    *SmramDescriptor;\r
+\r
+  //\r
+  // Call the common constructor function\r
+  //\r
+  Status = SmmCpuFeaturesLibConstructor (ImageHandle, SystemTable);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Lookup the MP Services Protocol\r
+  //\r
+  Status = gBS->LocateProtocol (\r
+                  &gEfiMpServiceProtocolGuid,\r
+                  NULL,\r
+                  (VOID **)&mSmmCpuFeaturesLibMpService\r
+                  );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // If CPU supports VMX, then determine SMRAM range for MSEG.\r
+  //\r
+  AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &RegEcx.Uint32, NULL);\r
+  if (RegEcx.Bits.VMX == 1) {\r
+    GuidHob = GetFirstGuidHob (&gMsegSmramGuid);\r
+    if (GuidHob != NULL) {\r
+      //\r
+      // Retrieve MSEG location from MSEG SRAM HOB\r
+      //\r
+      SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob);\r
+      if (SmramDescriptor->PhysicalSize > 0) {\r
+        mMsegBase       = (UINTN)SmramDescriptor->CpuStart;\r
+        mMsegSize       = (UINTN)SmramDescriptor->PhysicalSize;\r
+      }\r
+    } else if (PcdGet32 (PcdCpuMsegSize) > 0) {\r
+      //\r
+      // Allocate MSEG from SMRAM memory\r
+      //\r
+      mMsegBase = (UINTN)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuMsegSize)));\r
+      if (mMsegBase > 0) {\r
+        mMsegSize = ALIGN_VALUE (PcdGet32 (PcdCpuMsegSize), EFI_PAGE_SIZE);\r
+      } else {\r
+        DEBUG ((DEBUG_ERROR, "Not enough SMRAM resource to allocate MSEG size %08x\n", PcdGet32 (PcdCpuMsegSize)));\r
+      }\r
+    }\r
+    if (mMsegBase > 0) {\r
+      DEBUG ((DEBUG_INFO, "MsegBase: 0x%08x, MsegSize: 0x%08x\n", mMsegBase, mMsegSize));\r
+    }\r
+  }\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  Internal worker function that is called to complete CPU initialization at the\r
+  end of SmmCpuFeaturesInitializeProcessor()\r
+\r
+**/\r
+VOID\r
+FinishSmmCpuFeaturesInitializeProcessor (\r
+  VOID\r
+  )\r
+{\r
+  MSR_IA32_SMM_MONITOR_CTL_REGISTER  SmmMonitorCtl;\r
+\r
+  //\r
+  // Set MSEG Base Address in SMM Monitor Control MSR.\r
+  //\r
+  if (mMsegBase > 0) {\r
+    SmmMonitorCtl.Uint64        = 0;\r
+    SmmMonitorCtl.Bits.MsegBase = (UINT32)mMsegBase >> 12;\r
+    SmmMonitorCtl.Bits.Valid    = 1;\r
+    AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL, SmmMonitorCtl.Uint64);\r
+  }\r
+}\r
+\r
+/**\r
+  Return the size, in bytes, of a custom SMI Handler in bytes.  If 0 is\r
+  returned, then a custom SMI handler is not provided by this library,\r
+  and the default SMI handler must be used.\r
+\r
+  @retval 0    Use the default SMI handler.\r
+  @retval > 0  Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler()\r
+               The caller is required to allocate enough SMRAM for each CPU to\r
+               support the size of the custom SMI handler.\r
+**/\r
+UINTN\r
+EFIAPI\r
+SmmCpuFeaturesGetSmiHandlerSize (\r
+  VOID\r
+  )\r
+{\r
+  return gcStmSmiHandlerSize;\r
+}\r
+\r
+/**\r
+  Install a custom SMI handler for the CPU specified by CpuIndex.  This function\r
+  is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater\r
+  than zero and is called by the CPU that was elected as monarch during System\r
+  Management Mode initialization.\r
+\r
+  @param[in] CpuIndex   The index of the CPU to install the custom SMI handler.\r
+                        The value must be between 0 and the NumberOfCpus field\r
+                        in the System Management System Table (SMST).\r
+  @param[in] SmBase     The SMBASE address for the CPU specified by CpuIndex.\r
+  @param[in] SmiStack   The stack to use when an SMI is processed by the\r
+                        the CPU specified by CpuIndex.\r
+  @param[in] StackSize  The size, in bytes, if the stack used when an SMI is\r
+                        processed by the CPU specified by CpuIndex.\r
+  @param[in] GdtBase    The base address of the GDT to use when an SMI is\r
+                        processed by the CPU specified by CpuIndex.\r
+  @param[in] GdtSize    The size, in bytes, of the GDT used when an SMI is\r
+                        processed by the CPU specified by CpuIndex.\r
+  @param[in] IdtBase    The base address of the IDT to use when an SMI is\r
+                        processed by the CPU specified by CpuIndex.\r
+  @param[in] IdtSize    The size, in bytes, of the IDT used when an SMI is\r
+                        processed by the CPU specified by CpuIndex.\r
+  @param[in] Cr3        The base address of the page tables to use when an SMI\r
+                        is processed by the CPU specified by CpuIndex.\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmCpuFeaturesInstallSmiHandler (\r
+  IN UINTN   CpuIndex,\r
+  IN UINT32  SmBase,\r
+  IN VOID    *SmiStack,\r
+  IN UINTN   StackSize,\r
+  IN UINTN   GdtBase,\r
+  IN UINTN   GdtSize,\r
+  IN UINTN   IdtBase,\r
+  IN UINTN   IdtSize,\r
+  IN UINT32  Cr3\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  TXT_PROCESSOR_SMM_DESCRIPTOR   *Psd;\r
+  VOID                           *Hob;\r
+  UINT32                         RegEax;\r
+  UINT32                         RegEdx;\r
+  EFI_PROCESSOR_INFORMATION      ProcessorInfo;\r
+\r
+  CopyMem ((VOID *)(UINTN)(SmBase + TXT_SMM_PSD_OFFSET), &gcStmPsd, sizeof (gcStmPsd));\r
+  Psd = (TXT_PROCESSOR_SMM_DESCRIPTOR *)(VOID *)(UINTN)(SmBase + TXT_SMM_PSD_OFFSET);\r
+  Psd->SmmGdtPtr = GdtBase;\r
+  Psd->SmmGdtSize = (UINT32)GdtSize;\r
+\r
+  //\r
+  // Initialize values in template before copy\r
+  //\r
+  gStmSmiStack             = (UINT32)((UINTN)SmiStack + StackSize - sizeof (UINTN));\r
+  gStmSmiCr3               = Cr3;\r
+  gStmSmbase               = SmBase;\r
+  gStmSmiHandlerIdtr.Base  = IdtBase;\r
+  gStmSmiHandlerIdtr.Limit = (UINT16)(IdtSize - 1);\r
+\r
+  if (gStmXdSupported) {\r
+    AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);\r
+    if (RegEax <= CPUID_EXTENDED_FUNCTION) {\r
+      //\r
+      // Extended CPUID functions are not supported on this processor.\r
+      //\r
+      gStmXdSupported = FALSE;\r
+    }\r
+\r
+    AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx);\r
+    if ((RegEdx & CPUID1_EDX_XD_SUPPORT) == 0) {\r
+      //\r
+      // Execute Disable Bit feature is not supported on this processor.\r
+      //\r
+      gStmXdSupported = FALSE;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Set the value at the top of the CPU stack to the CPU Index\r
+  //\r
+  *(UINTN*)(UINTN)gStmSmiStack = CpuIndex;\r
+\r
+  //\r
+  // Copy template to CPU specific SMI handler location\r
+  //\r
+  CopyMem (\r
+    (VOID*)(UINTN)(SmBase + SMM_HANDLER_OFFSET),\r
+    (VOID*)gcStmSmiHandlerTemplate,\r
+    gcStmSmiHandlerSize\r
+    );\r
+\r
+  Psd->SmmSmiHandlerRip = SmBase + SMM_HANDLER_OFFSET + gcStmSmiHandlerOffset;\r
+  Psd->SmmSmiHandlerRsp = (UINTN)SmiStack + StackSize - sizeof(UINTN);\r
+  Psd->SmmCr3           = Cr3;\r
+\r
+  DEBUG((DEBUG_ERROR, "CpuSmmStmExceptionStackSize - %x\n", PcdGet32(PcdCpuSmmStmExceptionStackSize)));\r
+  DEBUG((DEBUG_ERROR, "Pages - %x\n", EFI_SIZE_TO_PAGES(PcdGet32(PcdCpuSmmStmExceptionStackSize))));\r
+  Psd->StmProtectionExceptionHandler.SpeRsp = (UINT64)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize)));\r
+  Psd->StmProtectionExceptionHandler.SpeRsp += EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize)));\r
+\r
+  Psd->BiosHwResourceRequirementsPtr        = (UINT64)(UINTN)GetStmResource ();\r
+\r
+  //\r
+  // Get the APIC ID for the CPU specified by CpuIndex\r
+  //\r
+  Status = mSmmCpuFeaturesLibMpService->GetProcessorInfo (\r
+             mSmmCpuFeaturesLibMpService,\r
+             CpuIndex,\r
+             &ProcessorInfo\r
+             );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Psd->LocalApicId = (UINT32)ProcessorInfo.ProcessorId;\r
+  Psd->AcpiRsdp = 0;\r
+\r
+  Hob = GetFirstHob (EFI_HOB_TYPE_CPU);\r
+  if (Hob != NULL) {\r
+    Psd->PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;\r
+  } else {\r
+    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);\r
+    if (RegEax >= 0x80000008) {\r
+      AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);\r
+      Psd->PhysicalAddressBits = (UINT8) RegEax;\r
+    } else {\r
+      Psd->PhysicalAddressBits = 36;\r
+    }\r
+  }\r
+\r
+  if (!mStmConfigurationTableInitialized) {\r
+    StmSmmConfigurationTableInit ();\r
+    mStmConfigurationTableInitialized = TRUE;\r
+  }\r
+}\r
+\r
+/**\r
+  SMM End Of Dxe event notification handler.\r
+\r
+  STM support need patch AcpiRsdp in TXT_PROCESSOR_SMM_DESCRIPTOR.\r
+\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
+  @retval EFI_SUCCESS   Notification handler runs successfully.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SmmEndOfDxeEventNotify (\r
+  IN CONST EFI_GUID  *Protocol,\r
+  IN VOID            *Interface,\r
+  IN EFI_HANDLE      Handle\r
+  )\r
+{\r
+  VOID                          *Rsdp;\r
+  UINTN                         Index;\r
+  TXT_PROCESSOR_SMM_DESCRIPTOR  *Psd;\r
+\r
+  DEBUG ((DEBUG_INFO, "SmmEndOfDxeEventNotify\n"));\r
+\r
+  //\r
+  // found ACPI table RSD_PTR from system table\r
+  //\r
+  Rsdp = NULL;\r
+  for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {\r
+    if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi20TableGuid)) {\r
+      //\r
+      // A match was found.\r
+      //\r
+      Rsdp = gST->ConfigurationTable[Index].VendorTable;\r
+      break;\r
+    }\r
+  }\r
+  if (Rsdp == NULL) {\r
+    for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {\r
+      if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi10TableGuid)) {\r
+        //\r
+        // A match was found.\r
+        //\r
+        Rsdp = gST->ConfigurationTable[Index].VendorTable;\r
+        break;\r
+      }\r
+    }\r
+  }\r
+\r
+  for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {\r
+    Psd = (TXT_PROCESSOR_SMM_DESCRIPTOR *)((UINTN)gSmst->CpuSaveState[Index] - SMRAM_SAVE_STATE_MAP_OFFSET + TXT_SMM_PSD_OFFSET);\r
+    DEBUG ((DEBUG_INFO, "Index=%d  Psd=%p  Rsdp=%p\n", Index, Psd, Rsdp));\r
+    Psd->AcpiRsdp = (UINT64)(UINTN)Rsdp;\r
+  }\r
+\r
+  mLockLoadMonitor = TRUE;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function initializes the STM configuration table.\r
+**/\r
+VOID\r
+StmSmmConfigurationTableInit (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS    Status;\r
+    VOID        *Registration;\r
+\r
+  Status = gSmst->SmmInstallProtocolInterface (\r
+                    &mStmSmmCpuHandle,\r
+                    &gEfiSmMonitorInitProtocolGuid,\r
+                    EFI_NATIVE_INTERFACE,\r
+                    &mSmMonitorInitProtocol\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  //\r
+  // Register SMM End of DXE Event\r
+  //\r
+  Status = gSmst->SmmRegisterProtocolNotify (\r
+                    &gEfiSmmEndOfDxeProtocolGuid,\r
+                    SmmEndOfDxeEventNotify,\r
+                    &Registration\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
+}\r
+\r
+/**\r
+\r
+  Get STM state.\r
+\r
+  @return STM state\r
+\r
+**/\r
+EFI_SM_MONITOR_STATE\r
+EFIAPI\r
+GetMonitorState (\r
+  VOID\r
+  )\r
+{\r
+  return mStmState;\r
+}\r
+\r
+/**\r
+\r
+  Handle single Resource to see if it can be merged into Record.\r
+\r
+  @param Resource  A pointer to resource node to be added\r
+  @param Record    A pointer to record node to be merged\r
+\r
+  @retval TRUE  resource handled\r
+  @retval FALSE resource is not handled\r
+\r
+**/\r
+BOOLEAN\r
+HandleSingleResource (\r
+  IN  STM_RSC      *Resource,\r
+  IN  STM_RSC      *Record\r
+  )\r
+{\r
+  UINT64      ResourceLo;\r
+  UINT64      ResourceHi;\r
+  UINT64      RecordLo;\r
+  UINT64      RecordHi;\r
+\r
+  ResourceLo = 0;\r
+  ResourceHi = 0;\r
+  RecordLo = 0;\r
+  RecordHi = 0;\r
+\r
+  //\r
+  // Calling code is responsible for making sure that\r
+  // Resource->Header.RscType == (*Record)->Header.RscType\r
+  // thus we use just one of them as switch variable.\r
+  //\r
+  switch (Resource->Header.RscType) {\r
+  case MEM_RANGE:\r
+  case MMIO_RANGE:\r
+    ResourceLo = Resource->Mem.Base;\r
+    ResourceHi = Resource->Mem.Base + Resource->Mem.Length;\r
+    RecordLo = Record->Mem.Base;\r
+    RecordHi = Record->Mem.Base + Record->Mem.Length;\r
+    if (Resource->Mem.RWXAttributes != Record->Mem.RWXAttributes) {\r
+      if ((ResourceLo == RecordLo) && (ResourceHi == RecordHi)) {\r
+        Record->Mem.RWXAttributes = Resource->Mem.RWXAttributes | Record->Mem.RWXAttributes;\r
+        return TRUE;\r
+      } else {\r
+        return FALSE;\r
+      }\r
+    }\r
+    break;\r
+  case IO_RANGE:\r
+  case TRAPPED_IO_RANGE:\r
+    ResourceLo = (UINT64) Resource->Io.Base;\r
+    ResourceHi = (UINT64) Resource->Io.Base + (UINT64) Resource->Io.Length;\r
+    RecordLo = (UINT64) Record->Io.Base;\r
+    RecordHi = (UINT64) Record->Io.Base + (UINT64) Record->Io.Length;\r
+    break;\r
+  case PCI_CFG_RANGE:\r
+    if ((Resource->PciCfg.OriginatingBusNumber != Record->PciCfg.OriginatingBusNumber) ||\r
+        (Resource->PciCfg.LastNodeIndex != Record->PciCfg.LastNodeIndex)) {\r
+      return FALSE;\r
+    }\r
+    if (CompareMem (Resource->PciCfg.PciDevicePath, Record->PciCfg.PciDevicePath, sizeof(STM_PCI_DEVICE_PATH_NODE) * (Resource->PciCfg.LastNodeIndex + 1)) != 0) {\r
+      return FALSE;\r
+    }\r
+    ResourceLo = (UINT64) Resource->PciCfg.Base;\r
+    ResourceHi = (UINT64) Resource->PciCfg.Base + (UINT64) Resource->PciCfg.Length;\r
+    RecordLo = (UINT64) Record->PciCfg.Base;\r
+    RecordHi = (UINT64) Record->PciCfg.Base + (UINT64) Record->PciCfg.Length;\r
+    if (Resource->PciCfg.RWAttributes != Record->PciCfg.RWAttributes) {\r
+      if ((ResourceLo == RecordLo) && (ResourceHi == RecordHi)) {\r
+        Record->PciCfg.RWAttributes = Resource->PciCfg.RWAttributes | Record->PciCfg.RWAttributes;\r
+        return TRUE;\r
+      } else {\r
+        return FALSE;\r
+      }\r
+    }\r
+    break;\r
+  case MACHINE_SPECIFIC_REG:\r
+    //\r
+    // Special case - merge MSR masks in place.\r
+    //\r
+    if (Resource->Msr.MsrIndex != Record->Msr.MsrIndex) {\r
+      return FALSE;\r
+    }\r
+    Record->Msr.ReadMask |= Resource->Msr.ReadMask;\r
+    Record->Msr.WriteMask |= Resource->Msr.WriteMask;\r
+    return TRUE;\r
+  default:\r
+    return FALSE;\r
+  }\r
+  //\r
+  // If resources are disjoint\r
+  //\r
+  if ((ResourceHi < RecordLo) || (ResourceLo > RecordHi)) {\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // If resource is consumed by record.\r
+  //\r
+  if ((ResourceLo >= RecordLo) && (ResourceHi <= RecordHi)) {\r
+    return TRUE;\r
+  }\r
+  //\r
+  // Resources are overlapping.\r
+  // Resource and record are merged.\r
+  //\r
+  ResourceLo = (ResourceLo < RecordLo) ? ResourceLo : RecordLo;\r
+  ResourceHi = (ResourceHi > RecordHi) ? ResourceHi : RecordHi;\r
+\r
+  switch (Resource->Header.RscType) {\r
+  case MEM_RANGE:\r
+  case MMIO_RANGE:\r
+    Record->Mem.Base = ResourceLo;\r
+    Record->Mem.Length = ResourceHi - ResourceLo;\r
+    break;\r
+  case IO_RANGE:\r
+  case TRAPPED_IO_RANGE:\r
+    Record->Io.Base = (UINT16) ResourceLo;\r
+    Record->Io.Length = (UINT16) (ResourceHi - ResourceLo);\r
+    break;\r
+  case PCI_CFG_RANGE:\r
+    Record->PciCfg.Base = (UINT16) ResourceLo;\r
+    Record->PciCfg.Length = (UINT16) (ResourceHi - ResourceLo);\r
+    break;\r
+  default:\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+\r
+  Add resource node.\r
+\r
+  @param Resource  A pointer to resource node to be added\r
+\r
+**/\r
+VOID\r
+AddSingleResource (\r
+  IN  STM_RSC    *Resource\r
+  )\r
+{\r
+  STM_RSC    *Record;\r
+\r
+  Record = (STM_RSC *)mStmResourcesPtr;\r
+\r
+  while (TRUE) {\r
+    if (Record->Header.RscType == END_OF_RESOURCES) {\r
+      break;\r
+    }\r
+    //\r
+    // Go to next record if resource and record types don't match.\r
+    //\r
+    if (Resource->Header.RscType != Record->Header.RscType) {\r
+      Record = (STM_RSC *)((UINTN)Record + Record->Header.Length);\r
+      continue;\r
+    }\r
+    //\r
+    // Record is handled inside of procedure - don't adjust.\r
+    //\r
+    if (HandleSingleResource (Resource, Record)) {\r
+      return ;\r
+    }\r
+    Record = (STM_RSC *)((UINTN)Record + Record->Header.Length);\r
+  }\r
+\r
+  //\r
+  // Add resource to the end of area.\r
+  //\r
+  CopyMem (\r
+    mStmResourcesPtr + mStmResourceSizeUsed - sizeof(mRscEndNode),\r
+    Resource,\r
+    Resource->Header.Length\r
+    );\r
+  CopyMem (\r
+    mStmResourcesPtr + mStmResourceSizeUsed - sizeof(mRscEndNode) + Resource->Header.Length,\r
+    &mRscEndNode,\r
+    sizeof(mRscEndNode)\r
+    );\r
+  mStmResourceSizeUsed += Resource->Header.Length;\r
+  mStmResourceSizeAvailable = mStmResourceTotalSize - mStmResourceSizeUsed;\r
+\r
+  return ;\r
+}\r
+\r
+/**\r
+\r
+  Add resource list.\r
+\r
+  @param ResourceList  A pointer to resource list to be added\r
+  @param NumEntries    Optional number of entries.\r
+                       If 0, list must be terminated by END_OF_RESOURCES.\r
+\r
+**/\r
+VOID\r
+AddResource (\r
+  IN  STM_RSC    *ResourceList,\r
+  IN  UINT32      NumEntries OPTIONAL\r
+  )\r
+{\r
+  UINT32      Count;\r
+  UINTN       Index;\r
+  STM_RSC    *Resource;\r
+\r
+  if (NumEntries == 0) {\r
+    Count = 0xFFFFFFFF;\r
+  } else {\r
+    Count = NumEntries;\r
+  }\r
+\r
+  Resource = ResourceList;\r
+\r
+  for (Index = 0; Index < Count; Index++) {\r
+    if (Resource->Header.RscType == END_OF_RESOURCES) {\r
+      return ;\r
+    }\r
+    AddSingleResource (Resource);\r
+    Resource = (STM_RSC *)((UINTN)Resource + Resource->Header.Length);\r
+  }\r
+  return ;\r
+}\r
+\r
+/**\r
+\r
+  Validate resource list.\r
+\r
+  @param ResourceList  A pointer to resource list to be added\r
+  @param NumEntries    Optional number of entries.\r
+                       If 0, list must be terminated by END_OF_RESOURCES.\r
+\r
+  @retval TRUE  resource valid\r
+  @retval FALSE resource invalid\r
+\r
+**/\r
+BOOLEAN\r
+ValidateResource (\r
+  IN  STM_RSC    *ResourceList,\r
+  IN  UINT32      NumEntries OPTIONAL\r
+  )\r
+{\r
+  UINT32      Count;\r
+  UINTN       Index;\r
+  STM_RSC    *Resource;\r
+  UINTN       SubIndex;\r
+\r
+  //\r
+  // If NumEntries == 0 make it very big. Scan will be terminated by\r
+  // END_OF_RESOURCES.\r
+  //\r
+  if (NumEntries == 0) {\r
+    Count = 0xFFFFFFFF;\r
+  } else {\r
+    Count = NumEntries;\r
+  }\r
+\r
+  //\r
+  // Start from beginning of resource list.\r
+  //\r
+  Resource = ResourceList;\r
+\r
+  for (Index = 0; Index < Count; Index++) {\r
+    DEBUG ((DEBUG_ERROR, "ValidateResource (%d) - RscType(%x)\n", Index, Resource->Header.RscType));\r
+    //\r
+    // Validate resource.\r
+    //\r
+    switch (Resource->Header.RscType) {\r
+      case END_OF_RESOURCES:\r
+        if (Resource->Header.Length != sizeof (STM_RSC_END)) {\r
+          return  FALSE;\r
+        }\r
+        //\r
+        // If we are passed actual number of resources to add,\r
+        // END_OF_RESOURCES structure between them is considered an\r
+        // error. If NumEntries == 0 END_OF_RESOURCES is a termination.\r
+        //\r
+        if (NumEntries != 0) {\r
+          return  FALSE;\r
+        } else {\r
+          //\r
+          // If NumEntries == 0 and list reached end - return success.\r
+          //\r
+          return TRUE;\r
+        }\r
+        break;\r
+\r
+      case MEM_RANGE:\r
+      case MMIO_RANGE:\r
+        if (Resource->Header.Length != sizeof (STM_RSC_MEM_DESC)) {\r
+          return FALSE;\r
+        }\r
+\r
+        if (Resource->Mem.RWXAttributes > FULL_ACCS) {\r
+          return FALSE;\r
+        }\r
+        break;\r
+\r
+      case IO_RANGE:\r
+      case TRAPPED_IO_RANGE:\r
+        if (Resource->Header.Length != sizeof (STM_RSC_IO_DESC)) {\r
+          return FALSE;\r
+        }\r
+\r
+        if ((Resource->Io.Base + Resource->Io.Length) > 0xFFFF) {\r
+          return FALSE;\r
+        }\r
+        break;\r
+\r
+      case PCI_CFG_RANGE:\r
+        DEBUG ((DEBUG_ERROR, "ValidateResource - PCI (0x%02x, 0x%08x, 0x%02x, 0x%02x)\n", Resource->PciCfg.OriginatingBusNumber, Resource->PciCfg.LastNodeIndex, Resource->PciCfg.PciDevicePath[0].PciDevice, Resource->PciCfg.PciDevicePath[0].PciFunction));\r
+        if (Resource->Header.Length != sizeof (STM_RSC_PCI_CFG_DESC) + (sizeof(STM_PCI_DEVICE_PATH_NODE) * Resource->PciCfg.LastNodeIndex)) {\r
+          return FALSE;\r
+        }\r
+        for (SubIndex = 0; SubIndex <= Resource->PciCfg.LastNodeIndex; SubIndex++) {\r
+          if ((Resource->PciCfg.PciDevicePath[SubIndex].PciDevice > 0x1F) || (Resource->PciCfg.PciDevicePath[SubIndex].PciFunction > 7)) {\r
+            return FALSE;\r
+          }\r
+        }\r
+        if ((Resource->PciCfg.Base + Resource->PciCfg.Length) > 0x1000) {\r
+          return FALSE;\r
+        }\r
+        break;\r
+\r
+      case MACHINE_SPECIFIC_REG:\r
+        if (Resource->Header.Length != sizeof (STM_RSC_MSR_DESC)) {\r
+          return FALSE;\r
+        }\r
+        break;\r
+\r
+      default :\r
+        DEBUG ((DEBUG_ERROR, "ValidateResource - Unknown RscType(%x)\n", Resource->Header.RscType));\r
+        return FALSE;\r
+    }\r
+    Resource = (STM_RSC *)((UINTN)Resource + Resource->Header.Length);\r
+  }\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+\r
+  Get resource list.\r
+  EndResource is excluded.\r
+\r
+  @param ResourceList  A pointer to resource list to be added\r
+  @param NumEntries    Optional number of entries.\r
+                       If 0, list must be terminated by END_OF_RESOURCES.\r
+\r
+  @retval TRUE  resource valid\r
+  @retval FALSE resource invalid\r
+\r
+**/\r
+UINTN\r
+GetResourceSize (\r
+  IN  STM_RSC    *ResourceList,\r
+  IN  UINT32      NumEntries OPTIONAL\r
+  )\r
+{\r
+  UINT32      Count;\r
+  UINTN       Index;\r
+  STM_RSC    *Resource;\r
+\r
+  Resource = ResourceList;\r
+\r
+  //\r
+  // If NumEntries == 0 make it very big. Scan will be terminated by\r
+  // END_OF_RESOURCES.\r
+  //\r
+  if (NumEntries == 0) {\r
+    Count = 0xFFFFFFFF;\r
+  } else {\r
+    Count = NumEntries;\r
+  }\r
+\r
+  //\r
+  // Start from beginning of resource list.\r
+  //\r
+  Resource = ResourceList;\r
+\r
+  for (Index = 0; Index < Count; Index++) {\r
+    if (Resource->Header.RscType == END_OF_RESOURCES) {\r
+      break;\r
+    }\r
+    Resource = (STM_RSC *)((UINTN)Resource + Resource->Header.Length);\r
+  }\r
+\r
+  return (UINTN)Resource - (UINTN)ResourceList;\r
+}\r
+\r
+/**\r
+\r
+  Add resources in list to database. Allocate new memory areas as needed.\r
+\r
+  @param ResourceList  A pointer to resource list to be added\r
+  @param NumEntries    Optional number of entries.\r
+                       If 0, list must be terminated by END_OF_RESOURCES.\r
+\r
+  @retval EFI_SUCCESS            If resources are added\r
+  @retval EFI_INVALID_PARAMETER  If nested procedure detected resource failer\r
+  @retval EFI_OUT_OF_RESOURCES   If nested procedure returned it and we cannot allocate more areas.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+AddPiResource (\r
+  IN  STM_RSC    *ResourceList,\r
+  IN  UINT32      NumEntries OPTIONAL\r
+  )\r
+{\r
+  EFI_STATUS            Status;\r
+  UINTN                 ResourceSize;\r
+  EFI_PHYSICAL_ADDRESS  NewResource;\r
+  UINTN                 NewResourceSize;\r
+\r
+  DEBUG ((DEBUG_INFO, "AddPiResource - Enter\n"));\r
+\r
+  if (!ValidateResource (ResourceList, NumEntries)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  ResourceSize = GetResourceSize (ResourceList, NumEntries);\r
+  DEBUG ((DEBUG_INFO, "ResourceSize - 0x%08x\n", ResourceSize));\r
+  if (ResourceSize == 0) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if (mStmResourcesPtr == NULL) {\r
+    //\r
+    // First time allocation\r
+    //\r
+    NewResourceSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (ResourceSize + sizeof(mRscEndNode)));\r
+    DEBUG ((DEBUG_INFO, "Allocate - 0x%08x\n", NewResourceSize));\r
+    Status = gSmst->SmmAllocatePages (\r
+                      AllocateAnyPages,\r
+                      EfiRuntimeServicesData,\r
+                      EFI_SIZE_TO_PAGES (NewResourceSize),\r
+                      &NewResource\r
+                      );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+\r
+    //\r
+    // Copy EndResource for intialization\r
+    //\r
+    mStmResourcesPtr = (UINT8 *)(UINTN)NewResource;\r
+    mStmResourceTotalSize = NewResourceSize;\r
+    CopyMem (mStmResourcesPtr, &mRscEndNode, sizeof(mRscEndNode));\r
+    mStmResourceSizeUsed      = sizeof(mRscEndNode);\r
+    mStmResourceSizeAvailable = mStmResourceTotalSize - sizeof(mRscEndNode);\r
+\r
+    //\r
+    // Let SmmCore change resource ptr\r
+    //\r
+    NotifyStmResourceChange (mStmResourcesPtr);\r
+  } else if (mStmResourceSizeAvailable < ResourceSize) {\r
+    //\r
+    // Need enlarge\r
+    //\r
+    NewResourceSize = mStmResourceTotalSize + (ResourceSize - mStmResourceSizeAvailable);\r
+    NewResourceSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (NewResourceSize));\r
+    DEBUG ((DEBUG_INFO, "ReAllocate - 0x%08x\n", NewResourceSize));\r
+    Status = gSmst->SmmAllocatePages (\r
+                      AllocateAnyPages,\r
+                      EfiRuntimeServicesData,\r
+                      EFI_SIZE_TO_PAGES (NewResourceSize),\r
+                      &NewResource\r
+                      );\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+    CopyMem ((VOID *)(UINTN)NewResource, mStmResourcesPtr, mStmResourceSizeUsed);\r
+    mStmResourceSizeAvailable = NewResourceSize - mStmResourceSizeUsed;\r
+\r
+    gSmst->SmmFreePages (\r
+             (EFI_PHYSICAL_ADDRESS)(UINTN)mStmResourcesPtr,\r
+             EFI_SIZE_TO_PAGES (mStmResourceTotalSize)\r
+             );\r
+\r
+    mStmResourceTotalSize = NewResourceSize;\r
+    mStmResourcesPtr = (UINT8 *)(UINTN)NewResource;\r
+\r
+    //\r
+    // Let SmmCore change resource ptr\r
+    //\r
+    NotifyStmResourceChange (mStmResourcesPtr);\r
+  }\r
+\r
+  //\r
+  // Check duplication\r
+  //\r
+  AddResource (ResourceList, NumEntries);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+  Delete resources in list to database.\r
+\r
+  @param ResourceList  A pointer to resource list to be deleted\r
+                       NULL means delete all resources.\r
+  @param NumEntries    Optional number of entries.\r
+                       If 0, list must be terminated by END_OF_RESOURCES.\r
+\r
+  @retval EFI_SUCCESS            If resources are deleted\r
+  @retval EFI_INVALID_PARAMETER  If nested procedure detected resource failer\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DeletePiResource (\r
+  IN  STM_RSC    *ResourceList,\r
+  IN  UINT32      NumEntries OPTIONAL\r
+  )\r
+{\r
+  if (ResourceList != NULL) {\r
+    // TBD\r
+    ASSERT (FALSE);\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+  //\r
+  // Delete all\r
+  //\r
+  CopyMem (mStmResourcesPtr, &mRscEndNode, sizeof(mRscEndNode));\r
+  mStmResourceSizeUsed      = sizeof(mRscEndNode);\r
+  mStmResourceSizeAvailable = mStmResourceTotalSize - sizeof(mRscEndNode);\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+  Get BIOS resources.\r
+\r
+  @param ResourceList  A pointer to resource list to be filled\r
+  @param ResourceSize  On input it means size of resource list input.\r
+                       On output it means size of resource list filled,\r
+                       or the size of resource list to be filled if size of too small.\r
+\r
+  @retval EFI_SUCCESS            If resources are returned.\r
+  @retval EFI_BUFFER_TOO_SMALL   If resource list buffer is too small to hold the whole resources.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetPiResource (\r
+  OUT    STM_RSC *ResourceList,\r
+  IN OUT UINT32  *ResourceSize\r
+  )\r
+{\r
+  if (*ResourceSize < mStmResourceSizeUsed) {\r
+    *ResourceSize = (UINT32)mStmResourceSizeUsed;\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  CopyMem (ResourceList, mStmResourcesPtr, mStmResourceSizeUsed);\r
+  *ResourceSize = (UINT32)mStmResourceSizeUsed;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+  Set valid bit for MSEG MSR.\r
+\r
+  @param Buffer Ap function buffer. (not used)\r
+\r
+**/\r
+VOID\r
+EFIAPI\r
+EnableMsegMsr (\r
+  IN VOID  *Buffer\r
+  )\r
+{\r
+  MSR_IA32_SMM_MONITOR_CTL_REGISTER  SmmMonitorCtl;\r
+\r
+  SmmMonitorCtl.Uint64 = AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL);\r
+  SmmMonitorCtl.Bits.Valid = 1;\r
+  AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL, SmmMonitorCtl.Uint64);\r
+}\r
+\r
+/**\r
+\r
+  Get 4K page aligned VMCS size.\r
+\r
+  @return 4K page aligned VMCS size\r
+\r
+**/\r
+UINT32\r
+GetVmcsSize (\r
+  VOID\r
+  )\r
+{\r
+  MSR_IA32_VMX_BASIC_REGISTER  VmxBasic;\r
+\r
+  //\r
+  // Read VMCS size and and align to 4KB\r
+  //\r
+  VmxBasic.Uint64 = AsmReadMsr64 (MSR_IA32_VMX_BASIC);\r
+  return ALIGN_VALUE (VmxBasic.Bits.VmcsSize, SIZE_4KB);\r
+}\r
+\r
+/**\r
+\r
+  Check STM image size.\r
+\r
+  @param StmImage      STM image\r
+  @param StmImageSize  STM image size\r
+\r
+  @retval TRUE  check pass\r
+  @retval FALSE check fail\r
+**/\r
+BOOLEAN\r
+StmCheckStmImage (\r
+  IN EFI_PHYSICAL_ADDRESS StmImage,\r
+  IN UINTN                StmImageSize\r
+  )\r
+{\r
+  UINTN                     MinMsegSize;\r
+  STM_HEADER                *StmHeader;\r
+  IA32_VMX_MISC_REGISTER    VmxMiscMsr;\r
+\r
+  //\r
+  // Check to see if STM image is compatible with CPU\r
+  //\r
+  StmHeader = (STM_HEADER *)(UINTN)StmImage;\r
+  VmxMiscMsr.Uint64 = AsmReadMsr64 (MSR_IA32_VMX_MISC);\r
+  if (StmHeader->HwStmHdr.MsegHeaderRevision != VmxMiscMsr.Bits.MsegRevisionIdentifier) {\r
+    DEBUG ((DEBUG_ERROR, "STM Image not compatible with CPU\n"));\r
+    DEBUG ((DEBUG_ERROR, "  StmHeader->HwStmHdr.MsegHeaderRevision = %08x\n", StmHeader->HwStmHdr.MsegHeaderRevision));\r
+    DEBUG ((DEBUG_ERROR, "  VmxMiscMsr.Bits.MsegRevisionIdentifier = %08x\n", VmxMiscMsr.Bits.MsegRevisionIdentifier));\r
+    return FALSE;\r
+  }\r
+\r
+  //\r
+  // Get Minimal required Mseg size\r
+  //\r
+  MinMsegSize = (EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (StmHeader->SwStmHdr.StaticImageSize)) +\r
+                 StmHeader->SwStmHdr.AdditionalDynamicMemorySize +\r
+                 (StmHeader->SwStmHdr.PerProcDynamicMemorySize + GetVmcsSize () * 2) * gSmst->NumberOfCpus);\r
+  if (MinMsegSize < StmImageSize) {\r
+    MinMsegSize = StmImageSize;\r
+  }\r
+\r
+  if (StmHeader->HwStmHdr.Cr3Offset >= StmHeader->SwStmHdr.StaticImageSize) {\r
+    //\r
+    // We will create page table, just in case that SINIT does not create it.\r
+    //\r
+    if (MinMsegSize < StmHeader->HwStmHdr.Cr3Offset + EFI_PAGES_TO_SIZE(6)) {\r
+      MinMsegSize = StmHeader->HwStmHdr.Cr3Offset + EFI_PAGES_TO_SIZE(6);\r
+    }\r
+  }\r
+\r
+  //\r
+  // Check if it exceeds MSEG size\r
+  //\r
+  if (MinMsegSize > mMsegSize) {\r
+    DEBUG ((DEBUG_ERROR, "MSEG too small.  Min MSEG Size = %08x  Current MSEG Size = %08x\n", MinMsegSize, mMsegSize));\r
+    DEBUG ((DEBUG_ERROR, "  StmHeader->SwStmHdr.StaticImageSize             = %08x\n", StmHeader->SwStmHdr.StaticImageSize));\r
+    DEBUG ((DEBUG_ERROR, "  StmHeader->SwStmHdr.AdditionalDynamicMemorySize = %08x\n", StmHeader->SwStmHdr.AdditionalDynamicMemorySize));\r
+    DEBUG ((DEBUG_ERROR, "  StmHeader->SwStmHdr.PerProcDynamicMemorySize    = %08x\n", StmHeader->SwStmHdr.PerProcDynamicMemorySize));\r
+    DEBUG ((DEBUG_ERROR, "  VMCS Size                                       = %08x\n", GetVmcsSize ()));\r
+    DEBUG ((DEBUG_ERROR, "  Max CPUs                                        = %08x\n", gSmst->NumberOfCpus));\r
+    DEBUG ((DEBUG_ERROR, "  StmHeader->HwStmHdr.Cr3Offset                   = %08x\n", StmHeader->HwStmHdr.Cr3Offset));\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+/**\r
+\r
+  Load STM image to MSEG.\r
+\r
+  @param StmImage      STM image\r
+  @param StmImageSize  STM image size\r
+\r
+**/\r
+VOID\r
+StmLoadStmImage (\r
+  IN EFI_PHYSICAL_ADDRESS StmImage,\r
+  IN UINTN                StmImageSize\r
+  )\r
+{\r
+  MSR_IA32_SMM_MONITOR_CTL_REGISTER  SmmMonitorCtl;\r
+  UINT32                             MsegBase;\r
+  STM_HEADER                         *StmHeader;\r
+\r
+  //\r
+  // Get MSEG base address from MSR_IA32_SMM_MONITOR_CTL\r
+  //\r
+  SmmMonitorCtl.Uint64 = AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL);\r
+  MsegBase = SmmMonitorCtl.Bits.MsegBase << 12;\r
+\r
+  //\r
+  // Zero all of MSEG base address\r
+  //\r
+  ZeroMem ((VOID *)(UINTN)MsegBase, mMsegSize);\r
+\r
+  //\r
+  // Copy STM Image into MSEG\r
+  //\r
+  CopyMem ((VOID *)(UINTN)MsegBase, (VOID *)(UINTN)StmImage, StmImageSize);\r
+\r
+  //\r
+  // STM Header is at the beginning of the STM Image\r
+  //\r
+  StmHeader = (STM_HEADER *)(UINTN)StmImage;\r
+\r
+  StmGen4GPageTable ((UINTN)MsegBase + StmHeader->HwStmHdr.Cr3Offset);\r
+}\r
+\r
+/**\r
+\r
+  Load STM image to MSEG.\r
+\r
+  @param StmImage      STM image\r
+  @param StmImageSize  STM image size\r
+\r
+  @retval EFI_SUCCESS            Load STM to MSEG successfully\r
+  @retval EFI_ALREADY_STARTED    STM image is already loaded to MSEG\r
+  @retval EFI_BUFFER_TOO_SMALL   MSEG is smaller than minimal requirement of STM image\r
+  @retval EFI_UNSUPPORTED        MSEG is not enabled\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+LoadMonitor (\r
+  IN EFI_PHYSICAL_ADDRESS StmImage,\r
+  IN UINTN                StmImageSize\r
+  )\r
+{\r
+  MSR_IA32_SMM_MONITOR_CTL_REGISTER  SmmMonitorCtl;\r
+\r
+  if (mLockLoadMonitor) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  SmmMonitorCtl.Uint64 = AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL);\r
+  if (SmmMonitorCtl.Bits.MsegBase == 0) {\r
+    return EFI_UNSUPPORTED;\r
+  }\r
+\r
+  if (!StmCheckStmImage (StmImage, StmImageSize)) {\r
+    return EFI_BUFFER_TOO_SMALL;\r
+  }\r
+\r
+  // Record STM_HASH to PCR 0, just in case it is NOT TXT launch, we still need provide the evidence.\r
+  TpmMeasureAndLogData(\r
+    0,                        // PcrIndex\r
+    TXT_EVTYPE_STM_HASH,      // EventType\r
+    NULL,                     // EventLog\r
+    0,                        // LogLen\r
+    (VOID *)(UINTN)StmImage,  // HashData\r
+    StmImageSize              // HashDataLen\r
+    );\r
+\r
+  StmLoadStmImage (StmImage, StmImageSize);\r
+\r
+  mStmState |= EFI_SM_MONITOR_STATE_ENABLED;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  This function return BIOS STM resource.\r
+  Produced by SmmStm.\r
+  Comsumed by SmmMpService when Init.\r
+\r
+  @return BIOS STM resource\r
+\r
+**/\r
+VOID *\r
+GetStmResource(\r
+  VOID\r
+  )\r
+{\r
+  return mStmResourcesPtr;\r
+}\r
+\r
+/**\r
+  This function notify STM resource change.\r
+\r
+  @param StmResource BIOS STM resource\r
+\r
+**/\r
+VOID\r
+NotifyStmResourceChange (\r
+  VOID *StmResource\r
+  )\r
+{\r
+  UINTN                         Index;\r
+  TXT_PROCESSOR_SMM_DESCRIPTOR  *Psd;\r
+\r
+  for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {\r
+    Psd = (TXT_PROCESSOR_SMM_DESCRIPTOR *)((UINTN)gSmst->CpuSaveState[Index] - SMRAM_SAVE_STATE_MAP_OFFSET + TXT_SMM_PSD_OFFSET);\r
+    Psd->BiosHwResourceRequirementsPtr = (UINT64)(UINTN)StmResource;\r
+  }\r
+  return ;\r
+}\r
+\r
+\r
+/**\r
+  This is STM setup BIOS callback.\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmStmSetup (\r
+  VOID\r
+  )\r
+{\r
+  mStmState |= EFI_SM_MONITOR_STATE_ACTIVATED;\r
+}\r
+\r
+/**\r
+  This is STM teardown BIOS callback.\r
+**/\r
+VOID\r
+EFIAPI\r
+SmmStmTeardown (\r
+  VOID\r
+  )\r
+{\r
+  mStmState &= ~EFI_SM_MONITOR_STATE_ACTIVATED;\r
+}\r
+\r