Home | History | Annotate | Download | only in SmmCpuFeaturesLib
      1 /** @file
      2   SMM STM support functions
      3 
      4   Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
      5   This program and the accompanying materials
      6   are licensed and made available under the terms and conditions of the BSD License
      7   which accompanies this distribution.  The full text of the license may be found at
      8   http://opensource.org/licenses/bsd-license.php.
      9 
     10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     12 
     13 **/
     14 
     15 #include <PiSmm.h>
     16 #include <Library/BaseLib.h>
     17 #include <Library/BaseMemoryLib.h>
     18 #include <Library/MemoryAllocationLib.h>
     19 #include <Library/HobLib.h>
     20 #include <Library/DebugLib.h>
     21 #include <Library/UefiBootServicesTableLib.h>
     22 #include <Library/SmmServicesTableLib.h>
     23 #include <Library/TpmMeasurementLib.h>
     24 #include <Register/Cpuid.h>
     25 #include <Register/ArchitecturalMsr.h>
     26 #include <Register/SmramSaveStateMap.h>
     27 
     28 #include <Protocol/MpService.h>
     29 
     30 #include "SmmStm.h"
     31 
     32 #define TXT_EVTYPE_BASE                  0x400
     33 #define TXT_EVTYPE_STM_HASH              (TXT_EVTYPE_BASE + 14)
     34 
     35 #define RDWR_ACCS             3
     36 #define FULL_ACCS             7
     37 
     38 /**
     39   The constructor function
     40 
     41   @param[in]  ImageHandle  The firmware allocated handle for the EFI image.
     42   @param[in]  SystemTable  A pointer to the EFI System Table.
     43 
     44   @retval EFI_SUCCESS      The constructor always returns EFI_SUCCESS.
     45 
     46 **/
     47 EFI_STATUS
     48 EFIAPI
     49 SmmCpuFeaturesLibConstructor (
     50   IN EFI_HANDLE        ImageHandle,
     51   IN EFI_SYSTEM_TABLE  *SystemTable
     52   );
     53 
     54 EFI_HANDLE  mStmSmmCpuHandle = NULL;
     55 
     56 BOOLEAN mLockLoadMonitor = FALSE;
     57 
     58 //
     59 // Template of STM_RSC_END structure for copying.
     60 //
     61 GLOBAL_REMOVE_IF_UNREFERENCED STM_RSC_END mRscEndNode = {
     62   {END_OF_RESOURCES, sizeof (STM_RSC_END)},
     63 };
     64 
     65 GLOBAL_REMOVE_IF_UNREFERENCED UINT8  *mStmResourcesPtr         = NULL;
     66 GLOBAL_REMOVE_IF_UNREFERENCED UINTN  mStmResourceTotalSize     = 0x0;
     67 GLOBAL_REMOVE_IF_UNREFERENCED UINTN  mStmResourceSizeUsed      = 0x0;
     68 GLOBAL_REMOVE_IF_UNREFERENCED UINTN  mStmResourceSizeAvailable = 0x0;
     69 
     70 GLOBAL_REMOVE_IF_UNREFERENCED UINT32  mStmState = 0;
     71 
     72 //
     73 // System Configuration Table pointing to STM Configuration Table
     74 //
     75 GLOBAL_REMOVE_IF_UNREFERENCED
     76 EFI_SM_MONITOR_INIT_PROTOCOL mSmMonitorInitProtocol = {
     77   LoadMonitor,
     78   AddPiResource,
     79   DeletePiResource,
     80   GetPiResource,
     81   GetMonitorState,
     82 };
     83 
     84 
     85 
     86 
     87 #define   CPUID1_EDX_XD_SUPPORT      0x100000
     88 
     89 //
     90 // External global variables associated with SMI Handler Template
     91 //
     92 extern CONST TXT_PROCESSOR_SMM_DESCRIPTOR  gcStmPsd;
     93 extern UINT32                              gStmSmbase;
     94 extern volatile UINT32                     gStmSmiStack;
     95 extern UINT32                              gStmSmiCr3;
     96 extern volatile UINT8                      gcStmSmiHandlerTemplate[];
     97 extern CONST UINT16                        gcStmSmiHandlerSize;
     98 extern UINT16                              gcStmSmiHandlerOffset;
     99 extern BOOLEAN                             gStmXdSupported;
    100 
    101 //
    102 // Variables used by SMI Handler
    103 //
    104 IA32_DESCRIPTOR  gStmSmiHandlerIdtr;
    105 
    106 //
    107 // MP Services Protocol
    108 //
    109 EFI_MP_SERVICES_PROTOCOL  *mSmmCpuFeaturesLibMpService = NULL;
    110 
    111 //
    112 // MSEG Base and Length in SMRAM
    113 //
    114 UINTN  mMsegBase = 0;
    115 UINTN  mMsegSize = 0;
    116 
    117 BOOLEAN  mStmConfigurationTableInitialized = FALSE;
    118 
    119 
    120 /**
    121   The constructor function
    122 
    123   @param[in]  ImageHandle  The firmware allocated handle for the EFI image.
    124   @param[in]  SystemTable  A pointer to the EFI System Table.
    125 
    126   @retval EFI_SUCCESS      The constructor always returns EFI_SUCCESS.
    127 
    128 **/
    129 EFI_STATUS
    130 EFIAPI
    131 SmmCpuFeaturesLibStmConstructor (
    132   IN EFI_HANDLE        ImageHandle,
    133   IN EFI_SYSTEM_TABLE  *SystemTable
    134   )
    135 {
    136   EFI_STATUS              Status;
    137   CPUID_VERSION_INFO_ECX  RegEcx;
    138   EFI_HOB_GUID_TYPE       *GuidHob;
    139   EFI_SMRAM_DESCRIPTOR    *SmramDescriptor;
    140 
    141   //
    142   // Call the common constructor function
    143   //
    144   Status = SmmCpuFeaturesLibConstructor (ImageHandle, SystemTable);
    145   ASSERT_EFI_ERROR (Status);
    146 
    147   //
    148   // Lookup the MP Services Protocol
    149   //
    150   Status = gBS->LocateProtocol (
    151                   &gEfiMpServiceProtocolGuid,
    152                   NULL,
    153                   (VOID **)&mSmmCpuFeaturesLibMpService
    154                   );
    155   ASSERT_EFI_ERROR (Status);
    156 
    157   //
    158   // If CPU supports VMX, then determine SMRAM range for MSEG.
    159   //
    160   AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &RegEcx.Uint32, NULL);
    161   if (RegEcx.Bits.VMX == 1) {
    162     GuidHob = GetFirstGuidHob (&gMsegSmramGuid);
    163     if (GuidHob != NULL) {
    164       //
    165       // Retrieve MSEG location from MSEG SRAM HOB
    166       //
    167       SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob);
    168       if (SmramDescriptor->PhysicalSize > 0) {
    169         mMsegBase       = (UINTN)SmramDescriptor->CpuStart;
    170         mMsegSize       = (UINTN)SmramDescriptor->PhysicalSize;
    171       }
    172     } else if (PcdGet32 (PcdCpuMsegSize) > 0) {
    173       //
    174       // Allocate MSEG from SMRAM memory
    175       //
    176       mMsegBase = (UINTN)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuMsegSize)));
    177       if (mMsegBase > 0) {
    178         mMsegSize = ALIGN_VALUE (PcdGet32 (PcdCpuMsegSize), EFI_PAGE_SIZE);
    179       } else {
    180         DEBUG ((DEBUG_ERROR, "Not enough SMRAM resource to allocate MSEG size %08x\n", PcdGet32 (PcdCpuMsegSize)));
    181       }
    182     }
    183     if (mMsegBase > 0) {
    184       DEBUG ((DEBUG_INFO, "MsegBase: 0x%08x, MsegSize: 0x%08x\n", mMsegBase, mMsegSize));
    185     }
    186   }
    187 
    188   return EFI_SUCCESS;
    189 }
    190 
    191 /**
    192   Internal worker function that is called to complete CPU initialization at the
    193   end of SmmCpuFeaturesInitializeProcessor().
    194 
    195 **/
    196 VOID
    197 FinishSmmCpuFeaturesInitializeProcessor (
    198   VOID
    199   )
    200 {
    201   MSR_IA32_SMM_MONITOR_CTL_REGISTER  SmmMonitorCtl;
    202 
    203   //
    204   // Set MSEG Base Address in SMM Monitor Control MSR.
    205   //
    206   if (mMsegBase > 0) {
    207     SmmMonitorCtl.Uint64        = 0;
    208     SmmMonitorCtl.Bits.MsegBase = (UINT32)mMsegBase >> 12;
    209     SmmMonitorCtl.Bits.Valid    = 1;
    210     AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL, SmmMonitorCtl.Uint64);
    211   }
    212 }
    213 
    214 /**
    215   Return the size, in bytes, of a custom SMI Handler in bytes.  If 0 is
    216   returned, then a custom SMI handler is not provided by this library,
    217   and the default SMI handler must be used.
    218 
    219   @retval 0    Use the default SMI handler.
    220   @retval > 0  Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler()
    221                The caller is required to allocate enough SMRAM for each CPU to
    222                support the size of the custom SMI handler.
    223 **/
    224 UINTN
    225 EFIAPI
    226 SmmCpuFeaturesGetSmiHandlerSize (
    227   VOID
    228   )
    229 {
    230   return gcStmSmiHandlerSize;
    231 }
    232 
    233 /**
    234   Install a custom SMI handler for the CPU specified by CpuIndex.  This function
    235   is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater
    236   than zero and is called by the CPU that was elected as monarch during System
    237   Management Mode initialization.
    238 
    239   @param[in] CpuIndex   The index of the CPU to install the custom SMI handler.
    240                         The value must be between 0 and the NumberOfCpus field
    241                         in the System Management System Table (SMST).
    242   @param[in] SmBase     The SMBASE address for the CPU specified by CpuIndex.
    243   @param[in] SmiStack   The stack to use when an SMI is processed by the
    244                         the CPU specified by CpuIndex.
    245   @param[in] StackSize  The size, in bytes, if the stack used when an SMI is
    246                         processed by the CPU specified by CpuIndex.
    247   @param[in] GdtBase    The base address of the GDT to use when an SMI is
    248                         processed by the CPU specified by CpuIndex.
    249   @param[in] GdtSize    The size, in bytes, of the GDT used when an SMI is
    250                         processed by the CPU specified by CpuIndex.
    251   @param[in] IdtBase    The base address of the IDT to use when an SMI is
    252                         processed by the CPU specified by CpuIndex.
    253   @param[in] IdtSize    The size, in bytes, of the IDT used when an SMI is
    254                         processed by the CPU specified by CpuIndex.
    255   @param[in] Cr3        The base address of the page tables to use when an SMI
    256                         is processed by the CPU specified by CpuIndex.
    257 **/
    258 VOID
    259 EFIAPI
    260 SmmCpuFeaturesInstallSmiHandler (
    261   IN UINTN   CpuIndex,
    262   IN UINT32  SmBase,
    263   IN VOID    *SmiStack,
    264   IN UINTN   StackSize,
    265   IN UINTN   GdtBase,
    266   IN UINTN   GdtSize,
    267   IN UINTN   IdtBase,
    268   IN UINTN   IdtSize,
    269   IN UINT32  Cr3
    270   )
    271 {
    272   EFI_STATUS                     Status;
    273   TXT_PROCESSOR_SMM_DESCRIPTOR   *Psd;
    274   VOID                           *Hob;
    275   UINT32                         RegEax;
    276   UINT32                         RegEdx;
    277   EFI_PROCESSOR_INFORMATION      ProcessorInfo;
    278 
    279   CopyMem ((VOID *)(UINTN)(SmBase + TXT_SMM_PSD_OFFSET), &gcStmPsd, sizeof (gcStmPsd));
    280   Psd = (TXT_PROCESSOR_SMM_DESCRIPTOR *)(VOID *)(UINTN)(SmBase + TXT_SMM_PSD_OFFSET);
    281   Psd->SmmGdtPtr = GdtBase;
    282   Psd->SmmGdtSize = (UINT32)GdtSize;
    283 
    284   //
    285   // Initialize values in template before copy
    286   //
    287   gStmSmiStack             = (UINT32)((UINTN)SmiStack + StackSize - sizeof (UINTN));
    288   gStmSmiCr3               = Cr3;
    289   gStmSmbase               = SmBase;
    290   gStmSmiHandlerIdtr.Base  = IdtBase;
    291   gStmSmiHandlerIdtr.Limit = (UINT16)(IdtSize - 1);
    292 
    293   if (gStmXdSupported) {
    294     AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);
    295     if (RegEax <= CPUID_EXTENDED_FUNCTION) {
    296       //
    297       // Extended CPUID functions are not supported on this processor.
    298       //
    299       gStmXdSupported = FALSE;
    300     }
    301 
    302     AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx);
    303     if ((RegEdx & CPUID1_EDX_XD_SUPPORT) == 0) {
    304       //
    305       // Execute Disable Bit feature is not supported on this processor.
    306       //
    307       gStmXdSupported = FALSE;
    308     }
    309   }
    310 
    311   //
    312   // Set the value at the top of the CPU stack to the CPU Index
    313   //
    314   *(UINTN*)(UINTN)gStmSmiStack = CpuIndex;
    315 
    316   //
    317   // Copy template to CPU specific SMI handler location
    318   //
    319   CopyMem (
    320     (VOID*)(UINTN)(SmBase + SMM_HANDLER_OFFSET),
    321     (VOID*)gcStmSmiHandlerTemplate,
    322     gcStmSmiHandlerSize
    323     );
    324 
    325   Psd->SmmSmiHandlerRip = SmBase + SMM_HANDLER_OFFSET + gcStmSmiHandlerOffset;
    326   Psd->SmmSmiHandlerRsp = (UINTN)SmiStack + StackSize - sizeof(UINTN);
    327   Psd->SmmCr3           = Cr3;
    328 
    329   DEBUG((DEBUG_ERROR, "CpuSmmStmExceptionStackSize - %x\n", PcdGet32(PcdCpuSmmStmExceptionStackSize)));
    330   DEBUG((DEBUG_ERROR, "Pages - %x\n", EFI_SIZE_TO_PAGES(PcdGet32(PcdCpuSmmStmExceptionStackSize))));
    331   Psd->StmProtectionExceptionHandler.SpeRsp = (UINT64)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize)));
    332   Psd->StmProtectionExceptionHandler.SpeRsp += EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize)));
    333 
    334   Psd->BiosHwResourceRequirementsPtr        = (UINT64)(UINTN)GetStmResource ();
    335 
    336   //
    337   // Get the APIC ID for the CPU specified by CpuIndex
    338   //
    339   Status = mSmmCpuFeaturesLibMpService->GetProcessorInfo (
    340              mSmmCpuFeaturesLibMpService,
    341              CpuIndex,
    342              &ProcessorInfo
    343              );
    344   ASSERT_EFI_ERROR (Status);
    345 
    346   Psd->LocalApicId = (UINT32)ProcessorInfo.ProcessorId;
    347   Psd->AcpiRsdp = 0;
    348 
    349   Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
    350   if (Hob != NULL) {
    351     Psd->PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
    352   } else {
    353     AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
    354     if (RegEax >= 0x80000008) {
    355       AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
    356       Psd->PhysicalAddressBits = (UINT8) RegEax;
    357     } else {
    358       Psd->PhysicalAddressBits = 36;
    359     }
    360   }
    361 
    362   if (!mStmConfigurationTableInitialized) {
    363     StmSmmConfigurationTableInit ();
    364     mStmConfigurationTableInitialized = TRUE;
    365   }
    366 }
    367 
    368 /**
    369   SMM End Of Dxe event notification handler.
    370 
    371   STM support need patch AcpiRsdp in TXT_PROCESSOR_SMM_DESCRIPTOR.
    372 
    373   @param[in] Protocol   Points to the protocol's unique identifier.
    374   @param[in] Interface  Points to the interface instance.
    375   @param[in] Handle     The handle on which the interface was installed.
    376 
    377   @retval EFI_SUCCESS   Notification handler runs successfully.
    378 **/
    379 EFI_STATUS
    380 EFIAPI
    381 SmmEndOfDxeEventNotify (
    382   IN CONST EFI_GUID  *Protocol,
    383   IN VOID            *Interface,
    384   IN EFI_HANDLE      Handle
    385   )
    386 {
    387   VOID                          *Rsdp;
    388   UINTN                         Index;
    389   TXT_PROCESSOR_SMM_DESCRIPTOR  *Psd;
    390 
    391   DEBUG ((DEBUG_INFO, "SmmEndOfDxeEventNotify\n"));
    392 
    393   //
    394   // found ACPI table RSD_PTR from system table
    395   //
    396   Rsdp = NULL;
    397   for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
    398     if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi20TableGuid)) {
    399       //
    400       // A match was found.
    401       //
    402       Rsdp = gST->ConfigurationTable[Index].VendorTable;
    403       break;
    404     }
    405   }
    406   if (Rsdp == NULL) {
    407     for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
    408       if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi10TableGuid)) {
    409         //
    410         // A match was found.
    411         //
    412         Rsdp = gST->ConfigurationTable[Index].VendorTable;
    413         break;
    414       }
    415     }
    416   }
    417 
    418   for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
    419     Psd = (TXT_PROCESSOR_SMM_DESCRIPTOR *)((UINTN)gSmst->CpuSaveState[Index] - SMRAM_SAVE_STATE_MAP_OFFSET + TXT_SMM_PSD_OFFSET);
    420     DEBUG ((DEBUG_INFO, "Index=%d  Psd=%p  Rsdp=%p\n", Index, Psd, Rsdp));
    421     Psd->AcpiRsdp = (UINT64)(UINTN)Rsdp;
    422   }
    423 
    424   mLockLoadMonitor = TRUE;
    425 
    426   return EFI_SUCCESS;
    427 }
    428 
    429 /**
    430   This function initializes the STM configuration table.
    431 **/
    432 VOID
    433 StmSmmConfigurationTableInit (
    434   VOID
    435   )
    436 {
    437   EFI_STATUS    Status;
    438     VOID        *Registration;
    439 
    440   Status = gSmst->SmmInstallProtocolInterface (
    441                     &mStmSmmCpuHandle,
    442                     &gEfiSmMonitorInitProtocolGuid,
    443                     EFI_NATIVE_INTERFACE,
    444                     &mSmMonitorInitProtocol
    445                     );
    446   ASSERT_EFI_ERROR (Status);
    447 
    448   //
    449   //
    450   // Register SMM End of DXE Event
    451   //
    452   Status = gSmst->SmmRegisterProtocolNotify (
    453                     &gEfiSmmEndOfDxeProtocolGuid,
    454                     SmmEndOfDxeEventNotify,
    455                     &Registration
    456                     );
    457   ASSERT_EFI_ERROR (Status);
    458 }
    459 
    460 /**
    461 
    462   Get STM state.
    463 
    464   @return STM state
    465 
    466 **/
    467 EFI_SM_MONITOR_STATE
    468 EFIAPI
    469 GetMonitorState (
    470   VOID
    471   )
    472 {
    473   return mStmState;
    474 }
    475 
    476 /**
    477 
    478   Handle single Resource to see if it can be merged into Record.
    479 
    480   @param Resource  A pointer to resource node to be added
    481   @param Record    A pointer to record node to be merged
    482 
    483   @retval TRUE  resource handled
    484   @retval FALSE resource is not handled
    485 
    486 **/
    487 BOOLEAN
    488 HandleSingleResource (
    489   IN  STM_RSC      *Resource,
    490   IN  STM_RSC      *Record
    491   )
    492 {
    493   UINT64      ResourceLo;
    494   UINT64      ResourceHi;
    495   UINT64      RecordLo;
    496   UINT64      RecordHi;
    497 
    498   ResourceLo = 0;
    499   ResourceHi = 0;
    500   RecordLo = 0;
    501   RecordHi = 0;
    502 
    503   //
    504   // Calling code is responsible for making sure that
    505   // Resource->Header.RscType == (*Record)->Header.RscType
    506   // thus we use just one of them as switch variable.
    507   //
    508   switch (Resource->Header.RscType) {
    509   case MEM_RANGE:
    510   case MMIO_RANGE:
    511     ResourceLo = Resource->Mem.Base;
    512     ResourceHi = Resource->Mem.Base + Resource->Mem.Length;
    513     RecordLo = Record->Mem.Base;
    514     RecordHi = Record->Mem.Base + Record->Mem.Length;
    515     if (Resource->Mem.RWXAttributes != Record->Mem.RWXAttributes) {
    516       if ((ResourceLo == RecordLo) && (ResourceHi == RecordHi)) {
    517         Record->Mem.RWXAttributes = Resource->Mem.RWXAttributes | Record->Mem.RWXAttributes;
    518         return TRUE;
    519       } else {
    520         return FALSE;
    521       }
    522     }
    523     break;
    524   case IO_RANGE:
    525   case TRAPPED_IO_RANGE:
    526     ResourceLo = (UINT64) Resource->Io.Base;
    527     ResourceHi = (UINT64) Resource->Io.Base + (UINT64) Resource->Io.Length;
    528     RecordLo = (UINT64) Record->Io.Base;
    529     RecordHi = (UINT64) Record->Io.Base + (UINT64) Record->Io.Length;
    530     break;
    531   case PCI_CFG_RANGE:
    532     if ((Resource->PciCfg.OriginatingBusNumber != Record->PciCfg.OriginatingBusNumber) ||
    533         (Resource->PciCfg.LastNodeIndex != Record->PciCfg.LastNodeIndex)) {
    534       return FALSE;
    535     }
    536     if (CompareMem (Resource->PciCfg.PciDevicePath, Record->PciCfg.PciDevicePath, sizeof(STM_PCI_DEVICE_PATH_NODE) * (Resource->PciCfg.LastNodeIndex + 1)) != 0) {
    537       return FALSE;
    538     }
    539     ResourceLo = (UINT64) Resource->PciCfg.Base;
    540     ResourceHi = (UINT64) Resource->PciCfg.Base + (UINT64) Resource->PciCfg.Length;
    541     RecordLo = (UINT64) Record->PciCfg.Base;
    542     RecordHi = (UINT64) Record->PciCfg.Base + (UINT64) Record->PciCfg.Length;
    543     if (Resource->PciCfg.RWAttributes != Record->PciCfg.RWAttributes) {
    544       if ((ResourceLo == RecordLo) && (ResourceHi == RecordHi)) {
    545         Record->PciCfg.RWAttributes = Resource->PciCfg.RWAttributes | Record->PciCfg.RWAttributes;
    546         return TRUE;
    547       } else {
    548         return FALSE;
    549       }
    550     }
    551     break;
    552   case MACHINE_SPECIFIC_REG:
    553     //
    554     // Special case - merge MSR masks in place.
    555     //
    556     if (Resource->Msr.MsrIndex != Record->Msr.MsrIndex) {
    557       return FALSE;
    558     }
    559     Record->Msr.ReadMask |= Resource->Msr.ReadMask;
    560     Record->Msr.WriteMask |= Resource->Msr.WriteMask;
    561     return TRUE;
    562   default:
    563     return FALSE;
    564   }
    565   //
    566   // If resources are disjoint
    567   //
    568   if ((ResourceHi < RecordLo) || (ResourceLo > RecordHi)) {
    569     return FALSE;
    570   }
    571 
    572   //
    573   // If resource is consumed by record.
    574   //
    575   if ((ResourceLo >= RecordLo) && (ResourceHi <= RecordHi)) {
    576     return TRUE;
    577   }
    578   //
    579   // Resources are overlapping.
    580   // Resource and record are merged.
    581   //
    582   ResourceLo = (ResourceLo < RecordLo) ? ResourceLo : RecordLo;
    583   ResourceHi = (ResourceHi > RecordHi) ? ResourceHi : RecordHi;
    584 
    585   switch (Resource->Header.RscType) {
    586   case MEM_RANGE:
    587   case MMIO_RANGE:
    588     Record->Mem.Base = ResourceLo;
    589     Record->Mem.Length = ResourceHi - ResourceLo;
    590     break;
    591   case IO_RANGE:
    592   case TRAPPED_IO_RANGE:
    593     Record->Io.Base = (UINT16) ResourceLo;
    594     Record->Io.Length = (UINT16) (ResourceHi - ResourceLo);
    595     break;
    596   case PCI_CFG_RANGE:
    597     Record->PciCfg.Base = (UINT16) ResourceLo;
    598     Record->PciCfg.Length = (UINT16) (ResourceHi - ResourceLo);
    599     break;
    600   default:
    601     return FALSE;
    602   }
    603 
    604   return TRUE;
    605 }
    606 
    607 /**
    608 
    609   Add resource node.
    610 
    611   @param Resource  A pointer to resource node to be added
    612 
    613 **/
    614 VOID
    615 AddSingleResource (
    616   IN  STM_RSC    *Resource
    617   )
    618 {
    619   STM_RSC    *Record;
    620 
    621   Record = (STM_RSC *)mStmResourcesPtr;
    622 
    623   while (TRUE) {
    624     if (Record->Header.RscType == END_OF_RESOURCES) {
    625       break;
    626     }
    627     //
    628     // Go to next record if resource and record types don't match.
    629     //
    630     if (Resource->Header.RscType != Record->Header.RscType) {
    631       Record = (STM_RSC *)((UINTN)Record + Record->Header.Length);
    632       continue;
    633     }
    634     //
    635     // Record is handled inside of procedure - don't adjust.
    636     //
    637     if (HandleSingleResource (Resource, Record)) {
    638       return ;
    639     }
    640     Record = (STM_RSC *)((UINTN)Record + Record->Header.Length);
    641   }
    642 
    643   //
    644   // Add resource to the end of area.
    645   //
    646   CopyMem (
    647     mStmResourcesPtr + mStmResourceSizeUsed - sizeof(mRscEndNode),
    648     Resource,
    649     Resource->Header.Length
    650     );
    651   CopyMem (
    652     mStmResourcesPtr + mStmResourceSizeUsed - sizeof(mRscEndNode) + Resource->Header.Length,
    653     &mRscEndNode,
    654     sizeof(mRscEndNode)
    655     );
    656   mStmResourceSizeUsed += Resource->Header.Length;
    657   mStmResourceSizeAvailable = mStmResourceTotalSize - mStmResourceSizeUsed;
    658 
    659   return ;
    660 }
    661 
    662 /**
    663 
    664   Add resource list.
    665 
    666   @param ResourceList  A pointer to resource list to be added
    667   @param NumEntries    Optional number of entries.
    668                        If 0, list must be terminated by END_OF_RESOURCES.
    669 
    670 **/
    671 VOID
    672 AddResource (
    673   IN  STM_RSC    *ResourceList,
    674   IN  UINT32      NumEntries OPTIONAL
    675   )
    676 {
    677   UINT32      Count;
    678   UINTN       Index;
    679   STM_RSC    *Resource;
    680 
    681   if (NumEntries == 0) {
    682     Count = 0xFFFFFFFF;
    683   } else {
    684     Count = NumEntries;
    685   }
    686 
    687   Resource = ResourceList;
    688 
    689   for (Index = 0; Index < Count; Index++) {
    690     if (Resource->Header.RscType == END_OF_RESOURCES) {
    691       return ;
    692     }
    693     AddSingleResource (Resource);
    694     Resource = (STM_RSC *)((UINTN)Resource + Resource->Header.Length);
    695   }
    696   return ;
    697 }
    698 
    699 /**
    700 
    701   Validate resource list.
    702 
    703   @param ResourceList  A pointer to resource list to be added
    704   @param NumEntries    Optional number of entries.
    705                        If 0, list must be terminated by END_OF_RESOURCES.
    706 
    707   @retval TRUE  resource valid
    708   @retval FALSE resource invalid
    709 
    710 **/
    711 BOOLEAN
    712 ValidateResource (
    713   IN  STM_RSC    *ResourceList,
    714   IN  UINT32      NumEntries OPTIONAL
    715   )
    716 {
    717   UINT32      Count;
    718   UINTN       Index;
    719   STM_RSC    *Resource;
    720   UINTN       SubIndex;
    721 
    722   //
    723   // If NumEntries == 0 make it very big. Scan will be terminated by
    724   // END_OF_RESOURCES.
    725   //
    726   if (NumEntries == 0) {
    727     Count = 0xFFFFFFFF;
    728   } else {
    729     Count = NumEntries;
    730   }
    731 
    732   //
    733   // Start from beginning of resource list.
    734   //
    735   Resource = ResourceList;
    736 
    737   for (Index = 0; Index < Count; Index++) {
    738     DEBUG ((DEBUG_ERROR, "ValidateResource (%d) - RscType(%x)\n", Index, Resource->Header.RscType));
    739     //
    740     // Validate resource.
    741     //
    742     switch (Resource->Header.RscType) {
    743       case END_OF_RESOURCES:
    744         if (Resource->Header.Length != sizeof (STM_RSC_END)) {
    745           return  FALSE;
    746         }
    747         //
    748         // If we are passed actual number of resources to add,
    749         // END_OF_RESOURCES structure between them is considered an
    750         // error. If NumEntries == 0 END_OF_RESOURCES is a termination.
    751         //
    752         if (NumEntries != 0) {
    753           return  FALSE;
    754         } else {
    755           //
    756           // If NumEntries == 0 and list reached end - return success.
    757           //
    758           return TRUE;
    759         }
    760         break;
    761 
    762       case MEM_RANGE:
    763       case MMIO_RANGE:
    764         if (Resource->Header.Length != sizeof (STM_RSC_MEM_DESC)) {
    765           return FALSE;
    766         }
    767 
    768         if (Resource->Mem.RWXAttributes > FULL_ACCS) {
    769           return FALSE;
    770         }
    771         break;
    772 
    773       case IO_RANGE:
    774       case TRAPPED_IO_RANGE:
    775         if (Resource->Header.Length != sizeof (STM_RSC_IO_DESC)) {
    776           return FALSE;
    777         }
    778 
    779         if ((Resource->Io.Base + Resource->Io.Length) > 0xFFFF) {
    780           return FALSE;
    781         }
    782         break;
    783 
    784       case PCI_CFG_RANGE:
    785         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));
    786         if (Resource->Header.Length != sizeof (STM_RSC_PCI_CFG_DESC) + (sizeof(STM_PCI_DEVICE_PATH_NODE) * Resource->PciCfg.LastNodeIndex)) {
    787           return FALSE;
    788         }
    789         for (SubIndex = 0; SubIndex <= Resource->PciCfg.LastNodeIndex; SubIndex++) {
    790           if ((Resource->PciCfg.PciDevicePath[SubIndex].PciDevice > 0x1F) || (Resource->PciCfg.PciDevicePath[SubIndex].PciFunction > 7)) {
    791             return FALSE;
    792           }
    793         }
    794         if ((Resource->PciCfg.Base + Resource->PciCfg.Length) > 0x1000) {
    795           return FALSE;
    796         }
    797         break;
    798 
    799       case MACHINE_SPECIFIC_REG:
    800         if (Resource->Header.Length != sizeof (STM_RSC_MSR_DESC)) {
    801           return FALSE;
    802         }
    803         break;
    804 
    805       default :
    806         DEBUG ((DEBUG_ERROR, "ValidateResource - Unknown RscType(%x)\n", Resource->Header.RscType));
    807         return FALSE;
    808     }
    809     Resource = (STM_RSC *)((UINTN)Resource + Resource->Header.Length);
    810   }
    811   return TRUE;
    812 }
    813 
    814 /**
    815 
    816   Get resource list.
    817   EndResource is excluded.
    818 
    819   @param ResourceList  A pointer to resource list to be added
    820   @param NumEntries    Optional number of entries.
    821                        If 0, list must be terminated by END_OF_RESOURCES.
    822 
    823   @retval TRUE  resource valid
    824   @retval FALSE resource invalid
    825 
    826 **/
    827 UINTN
    828 GetResourceSize (
    829   IN  STM_RSC    *ResourceList,
    830   IN  UINT32      NumEntries OPTIONAL
    831   )
    832 {
    833   UINT32      Count;
    834   UINTN       Index;
    835   STM_RSC    *Resource;
    836 
    837   Resource = ResourceList;
    838 
    839   //
    840   // If NumEntries == 0 make it very big. Scan will be terminated by
    841   // END_OF_RESOURCES.
    842   //
    843   if (NumEntries == 0) {
    844     Count = 0xFFFFFFFF;
    845   } else {
    846     Count = NumEntries;
    847   }
    848 
    849   //
    850   // Start from beginning of resource list.
    851   //
    852   Resource = ResourceList;
    853 
    854   for (Index = 0; Index < Count; Index++) {
    855     if (Resource->Header.RscType == END_OF_RESOURCES) {
    856       break;
    857     }
    858     Resource = (STM_RSC *)((UINTN)Resource + Resource->Header.Length);
    859   }
    860 
    861   return (UINTN)Resource - (UINTN)ResourceList;
    862 }
    863 
    864 /**
    865 
    866   Add resources in list to database. Allocate new memory areas as needed.
    867 
    868   @param ResourceList  A pointer to resource list to be added
    869   @param NumEntries    Optional number of entries.
    870                        If 0, list must be terminated by END_OF_RESOURCES.
    871 
    872   @retval EFI_SUCCESS            If resources are added
    873   @retval EFI_INVALID_PARAMETER  If nested procedure detected resource failer
    874   @retval EFI_OUT_OF_RESOURCES   If nested procedure returned it and we cannot allocate more areas.
    875 
    876 **/
    877 EFI_STATUS
    878 EFIAPI
    879 AddPiResource (
    880   IN  STM_RSC    *ResourceList,
    881   IN  UINT32      NumEntries OPTIONAL
    882   )
    883 {
    884   EFI_STATUS            Status;
    885   UINTN                 ResourceSize;
    886   EFI_PHYSICAL_ADDRESS  NewResource;
    887   UINTN                 NewResourceSize;
    888 
    889   DEBUG ((DEBUG_INFO, "AddPiResource - Enter\n"));
    890 
    891   if (!ValidateResource (ResourceList, NumEntries)) {
    892     return EFI_INVALID_PARAMETER;
    893   }
    894 
    895   ResourceSize = GetResourceSize (ResourceList, NumEntries);
    896   DEBUG ((DEBUG_INFO, "ResourceSize - 0x%08x\n", ResourceSize));
    897   if (ResourceSize == 0) {
    898     return EFI_INVALID_PARAMETER;
    899   }
    900 
    901   if (mStmResourcesPtr == NULL) {
    902     //
    903     // First time allocation
    904     //
    905     NewResourceSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (ResourceSize + sizeof(mRscEndNode)));
    906     DEBUG ((DEBUG_INFO, "Allocate - 0x%08x\n", NewResourceSize));
    907     Status = gSmst->SmmAllocatePages (
    908                       AllocateAnyPages,
    909                       EfiRuntimeServicesData,
    910                       EFI_SIZE_TO_PAGES (NewResourceSize),
    911                       &NewResource
    912                       );
    913     if (EFI_ERROR (Status)) {
    914       return Status;
    915     }
    916 
    917     //
    918     // Copy EndResource for intialization
    919     //
    920     mStmResourcesPtr = (UINT8 *)(UINTN)NewResource;
    921     mStmResourceTotalSize = NewResourceSize;
    922     CopyMem (mStmResourcesPtr, &mRscEndNode, sizeof(mRscEndNode));
    923     mStmResourceSizeUsed      = sizeof(mRscEndNode);
    924     mStmResourceSizeAvailable = mStmResourceTotalSize - sizeof(mRscEndNode);
    925 
    926     //
    927     // Let SmmCore change resource ptr
    928     //
    929     NotifyStmResourceChange (mStmResourcesPtr);
    930   } else if (mStmResourceSizeAvailable < ResourceSize) {
    931     //
    932     // Need enlarge
    933     //
    934     NewResourceSize = mStmResourceTotalSize + (ResourceSize - mStmResourceSizeAvailable);
    935     NewResourceSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (NewResourceSize));
    936     DEBUG ((DEBUG_INFO, "ReAllocate - 0x%08x\n", NewResourceSize));
    937     Status = gSmst->SmmAllocatePages (
    938                       AllocateAnyPages,
    939                       EfiRuntimeServicesData,
    940                       EFI_SIZE_TO_PAGES (NewResourceSize),
    941                       &NewResource
    942                       );
    943     if (EFI_ERROR (Status)) {
    944       return Status;
    945     }
    946     CopyMem ((VOID *)(UINTN)NewResource, mStmResourcesPtr, mStmResourceSizeUsed);
    947     mStmResourceSizeAvailable = NewResourceSize - mStmResourceSizeUsed;
    948 
    949     gSmst->SmmFreePages (
    950              (EFI_PHYSICAL_ADDRESS)(UINTN)mStmResourcesPtr,
    951              EFI_SIZE_TO_PAGES (mStmResourceTotalSize)
    952              );
    953 
    954     mStmResourceTotalSize = NewResourceSize;
    955     mStmResourcesPtr = (UINT8 *)(UINTN)NewResource;
    956 
    957     //
    958     // Let SmmCore change resource ptr
    959     //
    960     NotifyStmResourceChange (mStmResourcesPtr);
    961   }
    962 
    963   //
    964   // Check duplication
    965   //
    966   AddResource (ResourceList, NumEntries);
    967 
    968   return EFI_SUCCESS;
    969 }
    970 
    971 /**
    972 
    973   Delete resources in list to database.
    974 
    975   @param ResourceList  A pointer to resource list to be deleted
    976                        NULL means delete all resources.
    977   @param NumEntries    Optional number of entries.
    978                        If 0, list must be terminated by END_OF_RESOURCES.
    979 
    980   @retval EFI_SUCCESS            If resources are deleted
    981   @retval EFI_INVALID_PARAMETER  If nested procedure detected resource failer
    982 
    983 **/
    984 EFI_STATUS
    985 EFIAPI
    986 DeletePiResource (
    987   IN  STM_RSC    *ResourceList,
    988   IN  UINT32      NumEntries OPTIONAL
    989   )
    990 {
    991   if (ResourceList != NULL) {
    992     // TBD
    993     ASSERT (FALSE);
    994     return EFI_UNSUPPORTED;
    995   }
    996   //
    997   // Delete all
    998   //
    999   CopyMem (mStmResourcesPtr, &mRscEndNode, sizeof(mRscEndNode));
   1000   mStmResourceSizeUsed      = sizeof(mRscEndNode);
   1001   mStmResourceSizeAvailable = mStmResourceTotalSize - sizeof(mRscEndNode);
   1002   return EFI_SUCCESS;
   1003 }
   1004 
   1005 /**
   1006 
   1007   Get BIOS resources.
   1008 
   1009   @param ResourceList  A pointer to resource list to be filled
   1010   @param ResourceSize  On input it means size of resource list input.
   1011                        On output it means size of resource list filled,
   1012                        or the size of resource list to be filled if size of too small.
   1013 
   1014   @retval EFI_SUCCESS            If resources are returned.
   1015   @retval EFI_BUFFER_TOO_SMALL   If resource list buffer is too small to hold the whole resources.
   1016 
   1017 **/
   1018 EFI_STATUS
   1019 EFIAPI
   1020 GetPiResource (
   1021   OUT    STM_RSC *ResourceList,
   1022   IN OUT UINT32  *ResourceSize
   1023   )
   1024 {
   1025   if (*ResourceSize < mStmResourceSizeUsed) {
   1026     *ResourceSize = (UINT32)mStmResourceSizeUsed;
   1027     return EFI_BUFFER_TOO_SMALL;
   1028   }
   1029 
   1030   CopyMem (ResourceList, mStmResourcesPtr, mStmResourceSizeUsed);
   1031   *ResourceSize = (UINT32)mStmResourceSizeUsed;
   1032   return EFI_SUCCESS;
   1033 }
   1034 
   1035 /**
   1036 
   1037   Set valid bit for MSEG MSR.
   1038 
   1039   @param Buffer Ap function buffer. (not used)
   1040 
   1041 **/
   1042 VOID
   1043 EFIAPI
   1044 EnableMsegMsr (
   1045   IN VOID  *Buffer
   1046   )
   1047 {
   1048   MSR_IA32_SMM_MONITOR_CTL_REGISTER  SmmMonitorCtl;
   1049 
   1050   SmmMonitorCtl.Uint64 = AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL);
   1051   SmmMonitorCtl.Bits.Valid = 1;
   1052   AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL, SmmMonitorCtl.Uint64);
   1053 }
   1054 
   1055 /**
   1056 
   1057   Get 4K page aligned VMCS size.
   1058 
   1059   @return 4K page aligned VMCS size
   1060 
   1061 **/
   1062 UINT32
   1063 GetVmcsSize (
   1064   VOID
   1065   )
   1066 {
   1067   MSR_IA32_VMX_BASIC_REGISTER  VmxBasic;
   1068 
   1069   //
   1070   // Read VMCS size and and align to 4KB
   1071   //
   1072   VmxBasic.Uint64 = AsmReadMsr64 (MSR_IA32_VMX_BASIC);
   1073   return ALIGN_VALUE (VmxBasic.Bits.VmcsSize, SIZE_4KB);
   1074 }
   1075 
   1076 /**
   1077 
   1078   Check STM image size.
   1079 
   1080   @param StmImage      STM image
   1081   @param StmImageSize  STM image size
   1082 
   1083   @retval TRUE  check pass
   1084   @retval FALSE check fail
   1085 **/
   1086 BOOLEAN
   1087 StmCheckStmImage (
   1088   IN EFI_PHYSICAL_ADDRESS StmImage,
   1089   IN UINTN                StmImageSize
   1090   )
   1091 {
   1092   UINTN                     MinMsegSize;
   1093   STM_HEADER                *StmHeader;
   1094   IA32_VMX_MISC_REGISTER    VmxMiscMsr;
   1095 
   1096   //
   1097   // Check to see if STM image is compatible with CPU
   1098   //
   1099   StmHeader = (STM_HEADER *)(UINTN)StmImage;
   1100   VmxMiscMsr.Uint64 = AsmReadMsr64 (MSR_IA32_VMX_MISC);
   1101   if (StmHeader->HwStmHdr.MsegHeaderRevision != VmxMiscMsr.Bits.MsegRevisionIdentifier) {
   1102     DEBUG ((DEBUG_ERROR, "STM Image not compatible with CPU\n"));
   1103     DEBUG ((DEBUG_ERROR, "  StmHeader->HwStmHdr.MsegHeaderRevision = %08x\n", StmHeader->HwStmHdr.MsegHeaderRevision));
   1104     DEBUG ((DEBUG_ERROR, "  VmxMiscMsr.Bits.MsegRevisionIdentifier = %08x\n", VmxMiscMsr.Bits.MsegRevisionIdentifier));
   1105     return FALSE;
   1106   }
   1107 
   1108   //
   1109   // Get Minimal required Mseg size
   1110   //
   1111   MinMsegSize = (EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (StmHeader->SwStmHdr.StaticImageSize)) +
   1112                  StmHeader->SwStmHdr.AdditionalDynamicMemorySize +
   1113                  (StmHeader->SwStmHdr.PerProcDynamicMemorySize + GetVmcsSize () * 2) * gSmst->NumberOfCpus);
   1114   if (MinMsegSize < StmImageSize) {
   1115     MinMsegSize = StmImageSize;
   1116   }
   1117 
   1118   if (StmHeader->HwStmHdr.Cr3Offset >= StmHeader->SwStmHdr.StaticImageSize) {
   1119     //
   1120     // We will create page table, just in case that SINIT does not create it.
   1121     //
   1122     if (MinMsegSize < StmHeader->HwStmHdr.Cr3Offset + EFI_PAGES_TO_SIZE(6)) {
   1123       MinMsegSize = StmHeader->HwStmHdr.Cr3Offset + EFI_PAGES_TO_SIZE(6);
   1124     }
   1125   }
   1126 
   1127   //
   1128   // Check if it exceeds MSEG size
   1129   //
   1130   if (MinMsegSize > mMsegSize) {
   1131     DEBUG ((DEBUG_ERROR, "MSEG too small.  Min MSEG Size = %08x  Current MSEG Size = %08x\n", MinMsegSize, mMsegSize));
   1132     DEBUG ((DEBUG_ERROR, "  StmHeader->SwStmHdr.StaticImageSize             = %08x\n", StmHeader->SwStmHdr.StaticImageSize));
   1133     DEBUG ((DEBUG_ERROR, "  StmHeader->SwStmHdr.AdditionalDynamicMemorySize = %08x\n", StmHeader->SwStmHdr.AdditionalDynamicMemorySize));
   1134     DEBUG ((DEBUG_ERROR, "  StmHeader->SwStmHdr.PerProcDynamicMemorySize    = %08x\n", StmHeader->SwStmHdr.PerProcDynamicMemorySize));
   1135     DEBUG ((DEBUG_ERROR, "  VMCS Size                                       = %08x\n", GetVmcsSize ()));
   1136     DEBUG ((DEBUG_ERROR, "  Max CPUs                                        = %08x\n", gSmst->NumberOfCpus));
   1137     DEBUG ((DEBUG_ERROR, "  StmHeader->HwStmHdr.Cr3Offset                   = %08x\n", StmHeader->HwStmHdr.Cr3Offset));
   1138     return FALSE;
   1139   }
   1140 
   1141   return TRUE;
   1142 }
   1143 
   1144 /**
   1145 
   1146   Load STM image to MSEG.
   1147 
   1148   @param StmImage      STM image
   1149   @param StmImageSize  STM image size
   1150 
   1151 **/
   1152 VOID
   1153 StmLoadStmImage (
   1154   IN EFI_PHYSICAL_ADDRESS StmImage,
   1155   IN UINTN                StmImageSize
   1156   )
   1157 {
   1158   MSR_IA32_SMM_MONITOR_CTL_REGISTER  SmmMonitorCtl;
   1159   UINT32                             MsegBase;
   1160   STM_HEADER                         *StmHeader;
   1161 
   1162   //
   1163   // Get MSEG base address from MSR_IA32_SMM_MONITOR_CTL
   1164   //
   1165   SmmMonitorCtl.Uint64 = AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL);
   1166   MsegBase = SmmMonitorCtl.Bits.MsegBase << 12;
   1167 
   1168   //
   1169   // Zero all of MSEG base address
   1170   //
   1171   ZeroMem ((VOID *)(UINTN)MsegBase, mMsegSize);
   1172 
   1173   //
   1174   // Copy STM Image into MSEG
   1175   //
   1176   CopyMem ((VOID *)(UINTN)MsegBase, (VOID *)(UINTN)StmImage, StmImageSize);
   1177 
   1178   //
   1179   // STM Header is at the beginning of the STM Image
   1180   //
   1181   StmHeader = (STM_HEADER *)(UINTN)StmImage;
   1182 
   1183   StmGen4GPageTable ((UINTN)MsegBase + StmHeader->HwStmHdr.Cr3Offset);
   1184 }
   1185 
   1186 /**
   1187 
   1188   Load STM image to MSEG.
   1189 
   1190   @param StmImage      STM image
   1191   @param StmImageSize  STM image size
   1192 
   1193   @retval EFI_SUCCESS            Load STM to MSEG successfully
   1194   @retval EFI_ALREADY_STARTED    STM image is already loaded to MSEG
   1195   @retval EFI_BUFFER_TOO_SMALL   MSEG is smaller than minimal requirement of STM image
   1196   @retval EFI_UNSUPPORTED        MSEG is not enabled
   1197 
   1198 **/
   1199 EFI_STATUS
   1200 EFIAPI
   1201 LoadMonitor (
   1202   IN EFI_PHYSICAL_ADDRESS StmImage,
   1203   IN UINTN                StmImageSize
   1204   )
   1205 {
   1206   MSR_IA32_SMM_MONITOR_CTL_REGISTER  SmmMonitorCtl;
   1207 
   1208   if (mLockLoadMonitor) {
   1209     return EFI_ACCESS_DENIED;
   1210   }
   1211 
   1212   SmmMonitorCtl.Uint64 = AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL);
   1213   if (SmmMonitorCtl.Bits.MsegBase == 0) {
   1214     return EFI_UNSUPPORTED;
   1215   }
   1216 
   1217   if (!StmCheckStmImage (StmImage, StmImageSize)) {
   1218     return EFI_BUFFER_TOO_SMALL;
   1219   }
   1220 
   1221   // Record STM_HASH to PCR 0, just in case it is NOT TXT launch, we still need provide the evidence.
   1222   TpmMeasureAndLogData(
   1223     0,                        // PcrIndex
   1224     TXT_EVTYPE_STM_HASH,      // EventType
   1225     NULL,                     // EventLog
   1226     0,                        // LogLen
   1227     (VOID *)(UINTN)StmImage,  // HashData
   1228     StmImageSize              // HashDataLen
   1229     );
   1230 
   1231   StmLoadStmImage (StmImage, StmImageSize);
   1232 
   1233   mStmState |= EFI_SM_MONITOR_STATE_ENABLED;
   1234 
   1235   return EFI_SUCCESS;
   1236 }
   1237 
   1238 /**
   1239   This function return BIOS STM resource.
   1240   Produced by SmmStm.
   1241   Comsumed by SmmMpService when Init.
   1242 
   1243   @return BIOS STM resource
   1244 
   1245 **/
   1246 VOID *
   1247 GetStmResource(
   1248   VOID
   1249   )
   1250 {
   1251   return mStmResourcesPtr;
   1252 }
   1253 
   1254 /**
   1255   This function notify STM resource change.
   1256 
   1257   @param StmResource BIOS STM resource
   1258 
   1259 **/
   1260 VOID
   1261 NotifyStmResourceChange (
   1262   VOID *StmResource
   1263   )
   1264 {
   1265   UINTN                         Index;
   1266   TXT_PROCESSOR_SMM_DESCRIPTOR  *Psd;
   1267 
   1268   for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
   1269     Psd = (TXT_PROCESSOR_SMM_DESCRIPTOR *)((UINTN)gSmst->CpuSaveState[Index] - SMRAM_SAVE_STATE_MAP_OFFSET + TXT_SMM_PSD_OFFSET);
   1270     Psd->BiosHwResourceRequirementsPtr = (UINT64)(UINTN)StmResource;
   1271   }
   1272   return ;
   1273 }
   1274 
   1275 
   1276 /**
   1277   This is STM setup BIOS callback.
   1278 **/
   1279 VOID
   1280 EFIAPI
   1281 SmmStmSetup (
   1282   VOID
   1283   )
   1284 {
   1285   mStmState |= EFI_SM_MONITOR_STATE_ACTIVATED;
   1286 }
   1287 
   1288 /**
   1289   This is STM teardown BIOS callback.
   1290 **/
   1291 VOID
   1292 EFIAPI
   1293 SmmStmTeardown (
   1294   VOID
   1295   )
   1296 {
   1297   mStmState &= ~EFI_SM_MONITOR_STATE_ACTIVATED;
   1298 }
   1299 
   1300