Fix various typos in comments and documentation. Cc: Eric Dong <eric.dong@intel.com> Cc: Ray Ni <ray.ni@intel.com> Cc: Laszlo Ersek <lersek@redhat.com> Signed-off-by: Antoine Coeur <coeur@gmx.fr> Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com> Reviewed-by: Laszlo Ersek <lersek@redhat.com> Reviewed-by: Eric Dong <eric.dong@intel.com> Signed-off-by: Philippe Mathieu-Daude <philmd@redhat.com> Message-Id: <20200207010831.9046-79-philmd@redhat.com>
		
			
				
	
	
		
			1298 lines
		
	
	
		
			36 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1298 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 <PiSmm.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 "SmmStm.h"
 | 
						|
 | 
						|
#define TXT_EVTYPE_BASE                  0x400
 | 
						|
#define TXT_EVTYPE_STM_HASH              (TXT_EVTYPE_BASE + 14)
 | 
						|
 | 
						|
#define RDWR_ACCS             3
 | 
						|
#define FULL_ACCS             7
 | 
						|
 | 
						|
/**
 | 
						|
  The constructor function
 | 
						|
 | 
						|
  @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
 | 
						|
SmmCpuFeaturesLibConstructor (
 | 
						|
  IN EFI_HANDLE        ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE  *SystemTable
 | 
						|
  );
 | 
						|
 | 
						|
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
 | 
						|
 | 
						|
  @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 ();
 | 
						|
 | 
						|
  //
 | 
						|
  // Call the common constructor function
 | 
						|
  //
 | 
						|
  Status = SmmCpuFeaturesLibConstructor (ImageHandle, SystemTable);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  //
 | 
						|
  // 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;
 | 
						|
}
 | 
						|
 |