+/** @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