Fix various typos in comments and documentation. Cc: Michael D Kinney <michael.d.kinney@intel.com> Cc: Liming Gao <liming.gao@intel.com> Signed-off-by: Antoine Coeur <coeur@gmx.fr> Reviewed-by: Philippe Mathieu-Daude <philmd@redhat.com> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com> Signed-off-by: Philippe Mathieu-Daude <philmd@redhat.com> Message-Id: <20200207010831.9046-27-philmd@redhat.com>
		
			
				
	
	
		
			653 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			653 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Instance of SMM memory check library.
 | 
						|
 | 
						|
  SMM memory check library library implementation. This library consumes SMM_ACCESS2_PROTOCOL
 | 
						|
  to get SMRAM information. In order to use this library instance, the platform should produce
 | 
						|
  all SMRAM range via SMM_ACCESS2_PROTOCOL, including the range for firmware (like SMM Core
 | 
						|
  and SMM driver) and/or specific dedicated hardware.
 | 
						|
 | 
						|
  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/DebugLib.h>
 | 
						|
#include <Library/MemoryAllocationLib.h>
 | 
						|
#include <Library/UefiBootServicesTableLib.h>
 | 
						|
#include <Library/DxeServicesTableLib.h>
 | 
						|
#include <Library/SmmServicesTableLib.h>
 | 
						|
#include <Library/UefiLib.h>
 | 
						|
#include <Library/HobLib.h>
 | 
						|
#include <Protocol/SmmAccess2.h>
 | 
						|
#include <Protocol/SmmReadyToLock.h>
 | 
						|
#include <Protocol/SmmEndOfDxe.h>
 | 
						|
#include <Guid/MemoryAttributesTable.h>
 | 
						|
 | 
						|
//
 | 
						|
// attributes for reserved memory before it is promoted to system memory
 | 
						|
//
 | 
						|
#define EFI_MEMORY_PRESENT      0x0100000000000000ULL
 | 
						|
#define EFI_MEMORY_INITIALIZED  0x0200000000000000ULL
 | 
						|
#define EFI_MEMORY_TESTED       0x0400000000000000ULL
 | 
						|
 | 
						|
EFI_SMRAM_DESCRIPTOR *mSmmMemLibInternalSmramRanges;
 | 
						|
UINTN                mSmmMemLibInternalSmramCount;
 | 
						|
 | 
						|
//
 | 
						|
// Maximum support address used to check input buffer
 | 
						|
//
 | 
						|
EFI_PHYSICAL_ADDRESS  mSmmMemLibInternalMaximumSupportAddress = 0;
 | 
						|
 | 
						|
UINTN                 mMemoryMapEntryCount;
 | 
						|
EFI_MEMORY_DESCRIPTOR *mMemoryMap;
 | 
						|
UINTN                 mDescriptorSize;
 | 
						|
 | 
						|
EFI_GCD_MEMORY_SPACE_DESCRIPTOR   *mSmmMemLibGcdMemSpace       = NULL;
 | 
						|
UINTN                             mSmmMemLibGcdMemNumberOfDesc = 0;
 | 
						|
 | 
						|
EFI_MEMORY_ATTRIBUTES_TABLE  *mSmmMemLibMemoryAttributesTable = NULL;
 | 
						|
 | 
						|
VOID                  *mRegistrationEndOfDxe;
 | 
						|
VOID                  *mRegistrationReadyToLock;
 | 
						|
 | 
						|
BOOLEAN               mSmmMemLibSmmReadyToLock = FALSE;
 | 
						|
 | 
						|
/**
 | 
						|
  Calculate and save the maximum support address.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SmmMemLibInternalCalculateMaximumSupportAddress (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  VOID         *Hob;
 | 
						|
  UINT32       RegEax;
 | 
						|
  UINT8        PhysicalAddressBits;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get physical address bits supported.
 | 
						|
  //
 | 
						|
  Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
 | 
						|
  if (Hob != NULL) {
 | 
						|
    PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
 | 
						|
  } else {
 | 
						|
    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
 | 
						|
    if (RegEax >= 0x80000008) {
 | 
						|
      AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
 | 
						|
      PhysicalAddressBits = (UINT8) RegEax;
 | 
						|
    } else {
 | 
						|
      PhysicalAddressBits = 36;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
 | 
						|
  //
 | 
						|
  ASSERT (PhysicalAddressBits <= 52);
 | 
						|
  if (PhysicalAddressBits > 48) {
 | 
						|
    PhysicalAddressBits = 48;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Save the maximum support address in one global variable
 | 
						|
  //
 | 
						|
  mSmmMemLibInternalMaximumSupportAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)(LShiftU64 (1, PhysicalAddressBits) - 1);
 | 
						|
  DEBUG ((EFI_D_INFO, "mSmmMemLibInternalMaximumSupportAddress = 0x%lx\n", mSmmMemLibInternalMaximumSupportAddress));
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function check if the buffer is valid per processor architecture and not overlap with SMRAM.
 | 
						|
 | 
						|
  @param Buffer  The buffer start address to be checked.
 | 
						|
  @param Length  The buffer length to be checked.
 | 
						|
 | 
						|
  @retval TRUE  This buffer is valid per processor architecture and not overlap with SMRAM.
 | 
						|
  @retval FALSE This buffer is not valid per processor architecture or overlap with SMRAM.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
SmmIsBufferOutsideSmmValid (
 | 
						|
  IN EFI_PHYSICAL_ADDRESS  Buffer,
 | 
						|
  IN UINT64                Length
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN  Index;
 | 
						|
 | 
						|
  //
 | 
						|
  // Check override.
 | 
						|
  // NOTE: (B:0->L:4G) is invalid for IA32, but (B:1->L:4G-1)/(B:4G-1->L:1) is valid.
 | 
						|
  //
 | 
						|
  if ((Length > mSmmMemLibInternalMaximumSupportAddress) ||
 | 
						|
      (Buffer > mSmmMemLibInternalMaximumSupportAddress) ||
 | 
						|
      ((Length != 0) && (Buffer > (mSmmMemLibInternalMaximumSupportAddress - (Length - 1)))) ) {
 | 
						|
    //
 | 
						|
    // Overflow happen
 | 
						|
    //
 | 
						|
    DEBUG ((
 | 
						|
      EFI_D_ERROR,
 | 
						|
      "SmmIsBufferOutsideSmmValid: Overflow: Buffer (0x%lx) - Length (0x%lx), MaximumSupportAddress (0x%lx)\n",
 | 
						|
      Buffer,
 | 
						|
      Length,
 | 
						|
      mSmmMemLibInternalMaximumSupportAddress
 | 
						|
      ));
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  for (Index = 0; Index < mSmmMemLibInternalSmramCount; Index ++) {
 | 
						|
    if (((Buffer >= mSmmMemLibInternalSmramRanges[Index].CpuStart) && (Buffer < mSmmMemLibInternalSmramRanges[Index].CpuStart + mSmmMemLibInternalSmramRanges[Index].PhysicalSize)) ||
 | 
						|
        ((mSmmMemLibInternalSmramRanges[Index].CpuStart >= Buffer) && (mSmmMemLibInternalSmramRanges[Index].CpuStart < Buffer + Length))) {
 | 
						|
      DEBUG ((
 | 
						|
        EFI_D_ERROR,
 | 
						|
        "SmmIsBufferOutsideSmmValid: Overlap: Buffer (0x%lx) - Length (0x%lx), ",
 | 
						|
        Buffer,
 | 
						|
        Length
 | 
						|
        ));
 | 
						|
      DEBUG ((
 | 
						|
        EFI_D_ERROR,
 | 
						|
        "CpuStart (0x%lx) - PhysicalSize (0x%lx)\n",
 | 
						|
        mSmmMemLibInternalSmramRanges[Index].CpuStart,
 | 
						|
        mSmmMemLibInternalSmramRanges[Index].PhysicalSize
 | 
						|
        ));
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check override for Valid Communication Region
 | 
						|
  //
 | 
						|
  if (mSmmMemLibSmmReadyToLock) {
 | 
						|
    EFI_MEMORY_DESCRIPTOR          *MemoryMap;
 | 
						|
    BOOLEAN                        InValidCommunicationRegion;
 | 
						|
 | 
						|
    InValidCommunicationRegion = FALSE;
 | 
						|
    MemoryMap = mMemoryMap;
 | 
						|
    for (Index = 0; Index < mMemoryMapEntryCount; Index++) {
 | 
						|
      if ((Buffer >= MemoryMap->PhysicalStart) &&
 | 
						|
          (Buffer + Length <= MemoryMap->PhysicalStart + LShiftU64 (MemoryMap->NumberOfPages, EFI_PAGE_SHIFT))) {
 | 
						|
        InValidCommunicationRegion = TRUE;
 | 
						|
      }
 | 
						|
      MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, mDescriptorSize);
 | 
						|
    }
 | 
						|
 | 
						|
    if (!InValidCommunicationRegion) {
 | 
						|
      DEBUG ((
 | 
						|
        EFI_D_ERROR,
 | 
						|
        "SmmIsBufferOutsideSmmValid: Not in ValidCommunicationRegion: Buffer (0x%lx) - Length (0x%lx)\n",
 | 
						|
        Buffer,
 | 
						|
        Length
 | 
						|
        ));
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Check untested memory as invalid communication buffer.
 | 
						|
    //
 | 
						|
    for (Index = 0; Index < mSmmMemLibGcdMemNumberOfDesc; Index++) {
 | 
						|
      if (((Buffer >= mSmmMemLibGcdMemSpace[Index].BaseAddress) && (Buffer < mSmmMemLibGcdMemSpace[Index].BaseAddress + mSmmMemLibGcdMemSpace[Index].Length)) ||
 | 
						|
          ((mSmmMemLibGcdMemSpace[Index].BaseAddress >= Buffer) && (mSmmMemLibGcdMemSpace[Index].BaseAddress < Buffer + Length))) {
 | 
						|
        DEBUG ((
 | 
						|
          EFI_D_ERROR,
 | 
						|
          "SmmIsBufferOutsideSmmValid: In Untested Memory Region: Buffer (0x%lx) - Length (0x%lx)\n",
 | 
						|
          Buffer,
 | 
						|
          Length
 | 
						|
          ));
 | 
						|
        return FALSE;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    //
 | 
						|
    // Check UEFI runtime memory with EFI_MEMORY_RO as invalid communication buffer.
 | 
						|
    //
 | 
						|
    if (mSmmMemLibMemoryAttributesTable != NULL) {
 | 
						|
      EFI_MEMORY_DESCRIPTOR *Entry;
 | 
						|
 | 
						|
      Entry = (EFI_MEMORY_DESCRIPTOR *)(mSmmMemLibMemoryAttributesTable + 1);
 | 
						|
      for (Index = 0; Index < mSmmMemLibMemoryAttributesTable->NumberOfEntries; Index++) {
 | 
						|
        if (Entry->Type == EfiRuntimeServicesCode || Entry->Type == EfiRuntimeServicesData) {
 | 
						|
          if ((Entry->Attribute & EFI_MEMORY_RO) != 0) {
 | 
						|
            if (((Buffer >= Entry->PhysicalStart) && (Buffer < Entry->PhysicalStart + LShiftU64 (Entry->NumberOfPages, EFI_PAGE_SHIFT))) ||
 | 
						|
                ((Entry->PhysicalStart >= Buffer) && (Entry->PhysicalStart < Buffer + Length))) {
 | 
						|
              DEBUG ((
 | 
						|
                EFI_D_ERROR,
 | 
						|
                "SmmIsBufferOutsideSmmValid: In RuntimeCode Region: Buffer (0x%lx) - Length (0x%lx)\n",
 | 
						|
                Buffer,
 | 
						|
                Length
 | 
						|
                ));
 | 
						|
              return FALSE;
 | 
						|
            }
 | 
						|
          }
 | 
						|
        }
 | 
						|
        Entry = NEXT_MEMORY_DESCRIPTOR (Entry, mSmmMemLibMemoryAttributesTable->DescriptorSize);
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Copies a source buffer (non-SMRAM) to a destination buffer (SMRAM).
 | 
						|
 | 
						|
  This function copies a source buffer (non-SMRAM) to a destination buffer (SMRAM).
 | 
						|
  It checks if source buffer is valid per processor architecture and not overlap with SMRAM.
 | 
						|
  If the check passes, it copies memory and returns EFI_SUCCESS.
 | 
						|
  If the check fails, it return EFI_SECURITY_VIOLATION.
 | 
						|
  The implementation must be reentrant.
 | 
						|
 | 
						|
  @param  DestinationBuffer   The pointer to the destination buffer of the memory copy.
 | 
						|
  @param  SourceBuffer        The pointer to the source buffer of the memory copy.
 | 
						|
  @param  Length              The number of bytes to copy from SourceBuffer to DestinationBuffer.
 | 
						|
 | 
						|
  @retval EFI_SECURITY_VIOLATION The SourceBuffer is invalid per processor architecture or overlap with SMRAM.
 | 
						|
  @retval EFI_SUCCESS            Memory is copied.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
SmmCopyMemToSmram (
 | 
						|
  OUT VOID       *DestinationBuffer,
 | 
						|
  IN CONST VOID  *SourceBuffer,
 | 
						|
  IN UINTN       Length
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)SourceBuffer, Length)) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "SmmCopyMemToSmram: Security Violation: Source (0x%x), Length (0x%x)\n", SourceBuffer, Length));
 | 
						|
    return EFI_SECURITY_VIOLATION;
 | 
						|
  }
 | 
						|
  CopyMem (DestinationBuffer, SourceBuffer, Length);
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Copies a source buffer (SMRAM) to a destination buffer (NON-SMRAM).
 | 
						|
 | 
						|
  This function copies a source buffer (non-SMRAM) to a destination buffer (SMRAM).
 | 
						|
  It checks if destination buffer is valid per processor architecture and not overlap with SMRAM.
 | 
						|
  If the check passes, it copies memory and returns EFI_SUCCESS.
 | 
						|
  If the check fails, it returns EFI_SECURITY_VIOLATION.
 | 
						|
  The implementation must be reentrant.
 | 
						|
 | 
						|
  @param  DestinationBuffer   The pointer to the destination buffer of the memory copy.
 | 
						|
  @param  SourceBuffer        The pointer to the source buffer of the memory copy.
 | 
						|
  @param  Length              The number of bytes to copy from SourceBuffer to DestinationBuffer.
 | 
						|
 | 
						|
  @retval EFI_SECURITY_VIOLATION The DestinationBuffer is invalid per processor architecture or overlap with SMRAM.
 | 
						|
  @retval EFI_SUCCESS            Memory is copied.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
SmmCopyMemFromSmram (
 | 
						|
  OUT VOID       *DestinationBuffer,
 | 
						|
  IN CONST VOID  *SourceBuffer,
 | 
						|
  IN UINTN       Length
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)DestinationBuffer, Length)) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "SmmCopyMemFromSmram: Security Violation: Destination (0x%x), Length (0x%x)\n", DestinationBuffer, Length));
 | 
						|
    return EFI_SECURITY_VIOLATION;
 | 
						|
  }
 | 
						|
  CopyMem (DestinationBuffer, SourceBuffer, Length);
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Copies a source buffer (NON-SMRAM) to a destination buffer (NON-SMRAM).
 | 
						|
 | 
						|
  This function copies a source buffer (non-SMRAM) to a destination buffer (SMRAM).
 | 
						|
  It checks if source buffer and destination buffer are valid per processor architecture and not overlap with SMRAM.
 | 
						|
  If the check passes, it copies memory and returns EFI_SUCCESS.
 | 
						|
  If the check fails, it returns EFI_SECURITY_VIOLATION.
 | 
						|
  The implementation must be reentrant, and it must handle the case where source buffer overlaps destination buffer.
 | 
						|
 | 
						|
  @param  DestinationBuffer   The pointer to the destination buffer of the memory copy.
 | 
						|
  @param  SourceBuffer        The pointer to the source buffer of the memory copy.
 | 
						|
  @param  Length              The number of bytes to copy from SourceBuffer to DestinationBuffer.
 | 
						|
 | 
						|
  @retval EFI_SECURITY_VIOLATION The DestinationBuffer is invalid per processor architecture or overlap with SMRAM.
 | 
						|
  @retval EFI_SECURITY_VIOLATION The SourceBuffer is invalid per processor architecture or overlap with SMRAM.
 | 
						|
  @retval EFI_SUCCESS            Memory is copied.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
SmmCopyMem (
 | 
						|
  OUT VOID       *DestinationBuffer,
 | 
						|
  IN CONST VOID  *SourceBuffer,
 | 
						|
  IN UINTN       Length
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)DestinationBuffer, Length)) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "SmmCopyMem: Security Violation: Destination (0x%x), Length (0x%x)\n", DestinationBuffer, Length));
 | 
						|
    return EFI_SECURITY_VIOLATION;
 | 
						|
  }
 | 
						|
  if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)SourceBuffer, Length)) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "SmmCopyMem: Security Violation: Source (0x%x), Length (0x%x)\n", SourceBuffer, Length));
 | 
						|
    return EFI_SECURITY_VIOLATION;
 | 
						|
  }
 | 
						|
  CopyMem (DestinationBuffer, SourceBuffer, Length);
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Fills a target buffer (NON-SMRAM) with a byte value.
 | 
						|
 | 
						|
  This function fills a target buffer (non-SMRAM) with a byte value.
 | 
						|
  It checks if target buffer is valid per processor architecture and not overlap with SMRAM.
 | 
						|
  If the check passes, it fills memory and returns EFI_SUCCESS.
 | 
						|
  If the check fails, it returns EFI_SECURITY_VIOLATION.
 | 
						|
 | 
						|
  @param  Buffer    The memory to set.
 | 
						|
  @param  Length    The number of bytes to set.
 | 
						|
  @param  Value     The value with which to fill Length bytes of Buffer.
 | 
						|
 | 
						|
  @retval EFI_SECURITY_VIOLATION The Buffer is invalid per processor architecture or overlap with SMRAM.
 | 
						|
  @retval EFI_SUCCESS            Memory is set.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
SmmSetMem (
 | 
						|
  OUT VOID  *Buffer,
 | 
						|
  IN UINTN  Length,
 | 
						|
  IN UINT8  Value
 | 
						|
  )
 | 
						|
{
 | 
						|
  if (!SmmIsBufferOutsideSmmValid ((EFI_PHYSICAL_ADDRESS)(UINTN)Buffer, Length)) {
 | 
						|
    DEBUG ((EFI_D_ERROR, "SmmSetMem: Security Violation: Source (0x%x), Length (0x%x)\n", Buffer, Length));
 | 
						|
    return EFI_SECURITY_VIOLATION;
 | 
						|
  }
 | 
						|
  SetMem (Buffer, Length, Value);
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get GCD memory map.
 | 
						|
  Only record untested memory as invalid communication buffer.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SmmMemLibInternalGetGcdMemoryMap (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                            NumberOfDescriptors;
 | 
						|
  EFI_GCD_MEMORY_SPACE_DESCRIPTOR  *MemSpaceMap;
 | 
						|
  EFI_STATUS                       Status;
 | 
						|
  UINTN                            Index;
 | 
						|
 | 
						|
  Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemSpaceMap);
 | 
						|
  if (EFI_ERROR (Status)) {
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
 | 
						|
  mSmmMemLibGcdMemNumberOfDesc = 0;
 | 
						|
  for (Index = 0; Index < NumberOfDescriptors; Index++) {
 | 
						|
    if (MemSpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeReserved &&
 | 
						|
        (MemSpaceMap[Index].Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
 | 
						|
          (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)
 | 
						|
          ) {
 | 
						|
      mSmmMemLibGcdMemNumberOfDesc++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  mSmmMemLibGcdMemSpace = AllocateZeroPool (mSmmMemLibGcdMemNumberOfDesc * sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR));
 | 
						|
  ASSERT (mSmmMemLibGcdMemSpace != NULL);
 | 
						|
  if (mSmmMemLibGcdMemSpace == NULL) {
 | 
						|
    mSmmMemLibGcdMemNumberOfDesc = 0;
 | 
						|
    gBS->FreePool (MemSpaceMap);
 | 
						|
    return ;
 | 
						|
  }
 | 
						|
 | 
						|
  mSmmMemLibGcdMemNumberOfDesc = 0;
 | 
						|
  for (Index = 0; Index < NumberOfDescriptors; Index++) {
 | 
						|
    if (MemSpaceMap[Index].GcdMemoryType == EfiGcdMemoryTypeReserved &&
 | 
						|
        (MemSpaceMap[Index].Capabilities & (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED | EFI_MEMORY_TESTED)) ==
 | 
						|
          (EFI_MEMORY_PRESENT | EFI_MEMORY_INITIALIZED)
 | 
						|
          ) {
 | 
						|
      CopyMem (
 | 
						|
        &mSmmMemLibGcdMemSpace[mSmmMemLibGcdMemNumberOfDesc],
 | 
						|
        &MemSpaceMap[Index],
 | 
						|
        sizeof(EFI_GCD_MEMORY_SPACE_DESCRIPTOR)
 | 
						|
        );
 | 
						|
      mSmmMemLibGcdMemNumberOfDesc++;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  gBS->FreePool (MemSpaceMap);
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Get UEFI MemoryAttributesTable.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SmmMemLibInternalGetUefiMemoryAttributesTable (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                   Status;
 | 
						|
  EFI_MEMORY_ATTRIBUTES_TABLE  *MemoryAttributesTable;
 | 
						|
  UINTN                        MemoryAttributesTableSize;
 | 
						|
 | 
						|
  Status = EfiGetSystemConfigurationTable (&gEfiMemoryAttributesTableGuid, (VOID **)&MemoryAttributesTable);
 | 
						|
  if (!EFI_ERROR (Status) && (MemoryAttributesTable != NULL)) {
 | 
						|
    MemoryAttributesTableSize = sizeof(EFI_MEMORY_ATTRIBUTES_TABLE) + MemoryAttributesTable->DescriptorSize * MemoryAttributesTable->NumberOfEntries;
 | 
						|
    mSmmMemLibMemoryAttributesTable = AllocateCopyPool (MemoryAttributesTableSize, MemoryAttributesTable);
 | 
						|
    ASSERT (mSmmMemLibMemoryAttributesTable != NULL);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Notification for SMM EndOfDxe protocol.
 | 
						|
 | 
						|
  @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 runs successfully.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
SmmLibInternalEndOfDxeNotify (
 | 
						|
  IN CONST EFI_GUID  *Protocol,
 | 
						|
  IN VOID            *Interface,
 | 
						|
  IN EFI_HANDLE      Handle
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS            Status;
 | 
						|
  UINTN                 MapKey;
 | 
						|
  UINTN                 MemoryMapSize;
 | 
						|
  EFI_MEMORY_DESCRIPTOR *MemoryMap;
 | 
						|
  EFI_MEMORY_DESCRIPTOR *MemoryMapStart;
 | 
						|
  EFI_MEMORY_DESCRIPTOR *SmmMemoryMapStart;
 | 
						|
  UINTN                 MemoryMapEntryCount;
 | 
						|
  UINTN                 DescriptorSize;
 | 
						|
  UINT32                DescriptorVersion;
 | 
						|
  UINTN                 Index;
 | 
						|
 | 
						|
  MemoryMapSize = 0;
 | 
						|
  MemoryMap = NULL;
 | 
						|
  Status = gBS->GetMemoryMap (
 | 
						|
             &MemoryMapSize,
 | 
						|
             MemoryMap,
 | 
						|
             &MapKey,
 | 
						|
             &DescriptorSize,
 | 
						|
             &DescriptorVersion
 | 
						|
             );
 | 
						|
  ASSERT (Status == EFI_BUFFER_TOO_SMALL);
 | 
						|
 | 
						|
  do {
 | 
						|
    Status = gBS->AllocatePool (EfiBootServicesData, MemoryMapSize, (VOID **)&MemoryMap);
 | 
						|
    ASSERT (MemoryMap != NULL);
 | 
						|
 | 
						|
    Status = gBS->GetMemoryMap (
 | 
						|
               &MemoryMapSize,
 | 
						|
               MemoryMap,
 | 
						|
               &MapKey,
 | 
						|
               &DescriptorSize,
 | 
						|
               &DescriptorVersion
 | 
						|
               );
 | 
						|
    if (EFI_ERROR (Status)) {
 | 
						|
      gBS->FreePool (MemoryMap);
 | 
						|
    }
 | 
						|
  } while (Status == EFI_BUFFER_TOO_SMALL);
 | 
						|
 | 
						|
  //
 | 
						|
  // Get Count
 | 
						|
  //
 | 
						|
  mDescriptorSize = DescriptorSize;
 | 
						|
  MemoryMapEntryCount = MemoryMapSize/DescriptorSize;
 | 
						|
  MemoryMapStart = MemoryMap;
 | 
						|
  mMemoryMapEntryCount = 0;
 | 
						|
  for (Index = 0; Index < MemoryMapEntryCount; Index++) {
 | 
						|
    switch (MemoryMap->Type) {
 | 
						|
    case EfiReservedMemoryType:
 | 
						|
    case EfiRuntimeServicesCode:
 | 
						|
    case EfiRuntimeServicesData:
 | 
						|
    case EfiACPIMemoryNVS:
 | 
						|
      mMemoryMapEntryCount++;
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);
 | 
						|
  }
 | 
						|
  MemoryMap = MemoryMapStart;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get Data
 | 
						|
  //
 | 
						|
  mMemoryMap = AllocatePool (mMemoryMapEntryCount*DescriptorSize);
 | 
						|
  ASSERT (mMemoryMap != NULL);
 | 
						|
  SmmMemoryMapStart = mMemoryMap;
 | 
						|
  for (Index = 0; Index < MemoryMapEntryCount; Index++) {
 | 
						|
    switch (MemoryMap->Type) {
 | 
						|
    case EfiReservedMemoryType:
 | 
						|
    case EfiRuntimeServicesCode:
 | 
						|
    case EfiRuntimeServicesData:
 | 
						|
    case EfiACPIMemoryNVS:
 | 
						|
      CopyMem (mMemoryMap, MemoryMap, DescriptorSize);
 | 
						|
      mMemoryMap = NEXT_MEMORY_DESCRIPTOR(mMemoryMap, DescriptorSize);
 | 
						|
      break;
 | 
						|
    }
 | 
						|
    MemoryMap = NEXT_MEMORY_DESCRIPTOR(MemoryMap, DescriptorSize);
 | 
						|
  }
 | 
						|
  mMemoryMap = SmmMemoryMapStart;
 | 
						|
  MemoryMap = MemoryMapStart;
 | 
						|
 | 
						|
  gBS->FreePool (MemoryMap);
 | 
						|
 | 
						|
  //
 | 
						|
  // Get additional information from GCD memory map.
 | 
						|
  //
 | 
						|
  SmmMemLibInternalGetGcdMemoryMap ();
 | 
						|
 | 
						|
  //
 | 
						|
  // Get UEFI memory attributes table.
 | 
						|
  //
 | 
						|
  SmmMemLibInternalGetUefiMemoryAttributesTable ();
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Notification for SMM ReadyToLock protocol.
 | 
						|
 | 
						|
  @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 runs successfully.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
SmmLibInternalReadyToLockNotify (
 | 
						|
  IN CONST EFI_GUID  *Protocol,
 | 
						|
  IN VOID            *Interface,
 | 
						|
  IN EFI_HANDLE      Handle
 | 
						|
  )
 | 
						|
{
 | 
						|
  mSmmMemLibSmmReadyToLock = TRUE;
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
/**
 | 
						|
  The constructor function initializes the Smm Mem library
 | 
						|
 | 
						|
  @param  ImageHandle   The firmware allocated handle for the EFI image.
 | 
						|
  @param  SystemTable   A pointer to the EFI System Table.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS   The constructor always returns EFI_SUCCESS.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
SmmMemLibConstructor (
 | 
						|
  IN EFI_HANDLE        ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE  *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
  EFI_SMM_ACCESS2_PROTOCOL      *SmmAccess;
 | 
						|
  UINTN                         Size;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get SMRAM information
 | 
						|
  //
 | 
						|
  Status = gBS->LocateProtocol (&gEfiSmmAccess2ProtocolGuid, NULL, (VOID **)&SmmAccess);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  Size = 0;
 | 
						|
  Status = SmmAccess->GetCapabilities (SmmAccess, &Size, NULL);
 | 
						|
  ASSERT (Status == EFI_BUFFER_TOO_SMALL);
 | 
						|
 | 
						|
  mSmmMemLibInternalSmramRanges = AllocatePool (Size);
 | 
						|
  ASSERT (mSmmMemLibInternalSmramRanges != NULL);
 | 
						|
 | 
						|
  Status = SmmAccess->GetCapabilities (SmmAccess, &Size, mSmmMemLibInternalSmramRanges);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  mSmmMemLibInternalSmramCount = Size / sizeof (EFI_SMRAM_DESCRIPTOR);
 | 
						|
 | 
						|
  //
 | 
						|
  // Calculate and save maximum support address
 | 
						|
  //
 | 
						|
  SmmMemLibInternalCalculateMaximumSupportAddress ();
 | 
						|
 | 
						|
  //
 | 
						|
  // Register EndOfDxe to get UEFI memory map
 | 
						|
  //
 | 
						|
  Status = gSmst->SmmRegisterProtocolNotify (&gEfiSmmEndOfDxeProtocolGuid, SmmLibInternalEndOfDxeNotify, &mRegistrationEndOfDxe);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  //
 | 
						|
  // Register ready to lock so that we can know when to check valid SMRAM region
 | 
						|
  //
 | 
						|
  Status = gSmst->SmmRegisterProtocolNotify (&gEfiSmmReadyToLockProtocolGuid, SmmLibInternalReadyToLockNotify, &mRegistrationReadyToLock);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The destructor function frees resource used in the Smm Mem library
 | 
						|
 | 
						|
  @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 deconstructor always returns EFI_SUCCESS.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
SmmMemLibDestructor (
 | 
						|
  IN EFI_HANDLE        ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE  *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  FreePool (mSmmMemLibInternalSmramRanges);
 | 
						|
 | 
						|
  gSmst->SmmRegisterProtocolNotify (&gEfiSmmEndOfDxeProtocolGuid, NULL, &mRegistrationEndOfDxe);
 | 
						|
  gSmst->SmmRegisterProtocolNotify (&gEfiSmmReadyToLockProtocolGuid, NULL, &mRegistrationReadyToLock);
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 |