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