https://bugzilla.tianocore.org/show_bug.cgi?id=1373 Replace BSD 2-Clause License with BSD+Patent License. This change is based on the following emails: https://lists.01.org/pipermail/edk2-devel/2019-February/036260.html https://lists.01.org/pipermail/edk2-devel/2018-October/030385.html RFCs with detailed process for the license change: V3: https://lists.01.org/pipermail/edk2-devel/2019-March/038116.html V2: https://lists.01.org/pipermail/edk2-devel/2019-March/037669.html V1: https://lists.01.org/pipermail/edk2-devel/2019-March/037500.html Contributed-under: TianoCore Contribution Agreement 1.1 Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Liming Gao <liming.gao@intel.com>
		
			
				
	
	
		
			326 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			326 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  Instance of SMM IO check library.
 | 
						|
 | 
						|
  SMM IO check library library implementation. This library consumes GCD to collect all valid
 | 
						|
  IO space defined by a platform.
 | 
						|
  A platform may have its own SmmIoLib instance to exclude more IO space.
 | 
						|
 | 
						|
  Copyright (c) 2017, 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/SmmServicesTableLib.h>
 | 
						|
#include <Library/HobLib.h>
 | 
						|
#include <Library/DxeServicesTableLib.h>
 | 
						|
#include <Protocol/SmmReadyToLock.h>
 | 
						|
#include <Protocol/SmmEndOfDxe.h>
 | 
						|
 | 
						|
EFI_GCD_MEMORY_SPACE_DESCRIPTOR   *mSmmIoLibGcdMemSpace       = NULL;
 | 
						|
UINTN                             mSmmIoLibGcdMemNumberOfDesc = 0;
 | 
						|
 | 
						|
EFI_PHYSICAL_ADDRESS  mSmmIoLibInternalMaximumSupportMemAddress = 0;
 | 
						|
 | 
						|
VOID                  *mSmmIoLibRegistrationEndOfDxe;
 | 
						|
VOID                  *mSmmIoLibRegistrationReadyToLock;
 | 
						|
 | 
						|
BOOLEAN               mSmmIoLibReadyToLock = FALSE;
 | 
						|
 | 
						|
/**
 | 
						|
  Calculate and save the maximum support address.
 | 
						|
 | 
						|
**/
 | 
						|
VOID
 | 
						|
SmmIoLibInternalCalculateMaximumSupportAddress (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  VOID         *Hob;
 | 
						|
  UINT32       RegEax;
 | 
						|
  UINT8        MemPhysicalAddressBits;
 | 
						|
 | 
						|
  //
 | 
						|
  // Get physical address bits supported.
 | 
						|
  //
 | 
						|
  Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
 | 
						|
  if (Hob != NULL) {
 | 
						|
    MemPhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
 | 
						|
  } else {
 | 
						|
    AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
 | 
						|
    if (RegEax >= 0x80000008) {
 | 
						|
      AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
 | 
						|
      MemPhysicalAddressBits = (UINT8) RegEax;
 | 
						|
    } else {
 | 
						|
      MemPhysicalAddressBits = 36;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  //
 | 
						|
  // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
 | 
						|
  //
 | 
						|
  ASSERT (MemPhysicalAddressBits <= 52);
 | 
						|
  if (MemPhysicalAddressBits > 48) {
 | 
						|
    MemPhysicalAddressBits = 48;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Save the maximum support address in one global variable
 | 
						|
  //
 | 
						|
  mSmmIoLibInternalMaximumSupportMemAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)(LShiftU64 (1, MemPhysicalAddressBits) - 1);
 | 
						|
  DEBUG ((DEBUG_INFO, "mSmmIoLibInternalMaximumSupportMemAddress = 0x%lx\n", mSmmIoLibInternalMaximumSupportMemAddress));
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function check if the MMIO resource is valid per processor architecture and
 | 
						|
  valid per platform design.
 | 
						|
 | 
						|
  @param BaseAddress  The MMIO start address to be checked.
 | 
						|
  @param Length       The MMIO length to be checked.
 | 
						|
  @param Owner        A GUID representing the owner of the resource.
 | 
						|
                      This GUID may be used by producer to correlate the device ownership of the resource.
 | 
						|
                      NULL means no specific owner.
 | 
						|
 | 
						|
  @retval TRUE  This MMIO resource is valid per processor architecture and valid per platform design.
 | 
						|
  @retval FALSE This MMIO resource is not valid per processor architecture or valid per platform design.
 | 
						|
**/
 | 
						|
BOOLEAN
 | 
						|
EFIAPI
 | 
						|
SmmIsMmioValid (
 | 
						|
  IN EFI_PHYSICAL_ADDRESS  BaseAddress,
 | 
						|
  IN UINT64                Length,
 | 
						|
  IN EFI_GUID              *Owner  OPTIONAL
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                           Index;
 | 
						|
  EFI_GCD_MEMORY_SPACE_DESCRIPTOR *Desc;
 | 
						|
  BOOLEAN                         InValidRegion;
 | 
						|
 | 
						|
  //
 | 
						|
  // 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 > mSmmIoLibInternalMaximumSupportMemAddress) ||
 | 
						|
      (BaseAddress > mSmmIoLibInternalMaximumSupportMemAddress) ||
 | 
						|
      ((Length != 0) && (BaseAddress > (mSmmIoLibInternalMaximumSupportMemAddress - (Length - 1)))) ) {
 | 
						|
    //
 | 
						|
    // Overflow happen
 | 
						|
    //
 | 
						|
    DEBUG ((
 | 
						|
      DEBUG_ERROR,
 | 
						|
      "SmmIsMmioValid: Overflow: BaseAddress (0x%lx) - Length (0x%lx), MaximumSupportMemAddress (0x%lx)\n",
 | 
						|
      BaseAddress,
 | 
						|
      Length,
 | 
						|
      mSmmIoLibInternalMaximumSupportMemAddress
 | 
						|
      ));
 | 
						|
    return FALSE;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Check override for valid MMIO region
 | 
						|
  //
 | 
						|
  if (mSmmIoLibReadyToLock) {
 | 
						|
    InValidRegion = FALSE;
 | 
						|
    for (Index = 0; Index < mSmmIoLibGcdMemNumberOfDesc; Index ++) {
 | 
						|
      Desc = &mSmmIoLibGcdMemSpace[Index];
 | 
						|
      if ((Desc->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
 | 
						|
          (BaseAddress >= Desc->BaseAddress) &&
 | 
						|
          ((BaseAddress + Length) <= (Desc->BaseAddress + Desc->Length))) {
 | 
						|
        InValidRegion = TRUE;
 | 
						|
      }
 | 
						|
    }
 | 
						|
 | 
						|
    if (!InValidRegion) {
 | 
						|
      DEBUG ((
 | 
						|
        DEBUG_ERROR,
 | 
						|
        "SmmIsMmioValid: Not in valid MMIO region: BaseAddress (0x%lx) - Length (0x%lx)\n",
 | 
						|
        BaseAddress,
 | 
						|
        Length
 | 
						|
        ));
 | 
						|
      return FALSE;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return TRUE;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Merge continuous entries whose type is EfiGcdMemoryTypeMemoryMappedIo.
 | 
						|
 | 
						|
  @param[in, out]  GcdMemoryMap           A pointer to the buffer in which firmware places
 | 
						|
                                          the current GCD memory map.
 | 
						|
  @param[in, out]  NumberOfDescriptors    A pointer to the number of the
 | 
						|
                                          GcdMemoryMap buffer. On input, this is the number of
 | 
						|
                                          the current GCD memory map.  On output,
 | 
						|
                                          it is the number of new GCD memory map after merge.
 | 
						|
**/
 | 
						|
STATIC
 | 
						|
VOID
 | 
						|
MergeGcdMmioEntry (
 | 
						|
  IN OUT EFI_GCD_MEMORY_SPACE_DESCRIPTOR  *GcdMemoryMap,
 | 
						|
  IN OUT UINTN                            *NumberOfDescriptors
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_GCD_MEMORY_SPACE_DESCRIPTOR       *GcdMemoryMapEntry;
 | 
						|
  EFI_GCD_MEMORY_SPACE_DESCRIPTOR       *GcdMemoryMapEnd;
 | 
						|
  EFI_GCD_MEMORY_SPACE_DESCRIPTOR       *NewGcdMemoryMapEntry;
 | 
						|
  EFI_GCD_MEMORY_SPACE_DESCRIPTOR       *NextGcdMemoryMapEntry;
 | 
						|
 | 
						|
  GcdMemoryMapEntry = GcdMemoryMap;
 | 
						|
  NewGcdMemoryMapEntry = GcdMemoryMap;
 | 
						|
  GcdMemoryMapEnd = (EFI_GCD_MEMORY_SPACE_DESCRIPTOR *) ((UINT8 *) GcdMemoryMap + (*NumberOfDescriptors) * sizeof(EFI_GCD_MEMORY_SPACE_DESCRIPTOR));
 | 
						|
  while ((UINTN)GcdMemoryMapEntry < (UINTN)GcdMemoryMapEnd) {
 | 
						|
    CopyMem (NewGcdMemoryMapEntry, GcdMemoryMapEntry, sizeof(EFI_GCD_MEMORY_SPACE_DESCRIPTOR));
 | 
						|
    NextGcdMemoryMapEntry = GcdMemoryMapEntry + 1;
 | 
						|
 | 
						|
    do {
 | 
						|
      if (((UINTN)NextGcdMemoryMapEntry < (UINTN)GcdMemoryMapEnd) &&
 | 
						|
          (GcdMemoryMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) && (NextGcdMemoryMapEntry->GcdMemoryType == EfiGcdMemoryTypeMemoryMappedIo) &&
 | 
						|
          ((GcdMemoryMapEntry->BaseAddress + GcdMemoryMapEntry->Length) == NextGcdMemoryMapEntry->BaseAddress)) {
 | 
						|
        GcdMemoryMapEntry->Length += NextGcdMemoryMapEntry->Length;
 | 
						|
        if (NewGcdMemoryMapEntry != GcdMemoryMapEntry) {
 | 
						|
          NewGcdMemoryMapEntry->Length += NextGcdMemoryMapEntry->Length;
 | 
						|
        }
 | 
						|
 | 
						|
        NextGcdMemoryMapEntry = NextGcdMemoryMapEntry + 1;
 | 
						|
        continue;
 | 
						|
      } else {
 | 
						|
        GcdMemoryMapEntry = NextGcdMemoryMapEntry - 1;
 | 
						|
        break;
 | 
						|
      }
 | 
						|
    } while (TRUE);
 | 
						|
 | 
						|
    GcdMemoryMapEntry = GcdMemoryMapEntry + 1;
 | 
						|
    NewGcdMemoryMapEntry = NewGcdMemoryMapEntry + 1;
 | 
						|
  }
 | 
						|
 | 
						|
  *NumberOfDescriptors = ((UINTN)NewGcdMemoryMapEntry - (UINTN)GcdMemoryMap) / sizeof(EFI_GCD_MEMORY_SPACE_DESCRIPTOR);
 | 
						|
 | 
						|
  return ;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  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.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  No enough resources to save GCD MMIO map.
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
EFIAPI
 | 
						|
SmmIoLibInternalEndOfDxeNotify (
 | 
						|
  IN CONST EFI_GUID  *Protocol,
 | 
						|
  IN VOID            *Interface,
 | 
						|
  IN EFI_HANDLE      Handle
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN                            NumberOfDescriptors;
 | 
						|
  EFI_GCD_MEMORY_SPACE_DESCRIPTOR  *MemSpaceMap;
 | 
						|
  EFI_STATUS                       Status;
 | 
						|
 | 
						|
  Status = gDS->GetMemorySpaceMap (&NumberOfDescriptors, &MemSpaceMap);
 | 
						|
  if (!EFI_ERROR (Status)) {
 | 
						|
 | 
						|
    MergeGcdMmioEntry (MemSpaceMap, &NumberOfDescriptors);
 | 
						|
 | 
						|
    mSmmIoLibGcdMemSpace = AllocateCopyPool (NumberOfDescriptors * sizeof (EFI_GCD_MEMORY_SPACE_DESCRIPTOR), MemSpaceMap);
 | 
						|
    ASSERT (mSmmIoLibGcdMemSpace != NULL);
 | 
						|
    if (mSmmIoLibGcdMemSpace == NULL) {
 | 
						|
      gBS->FreePool (MemSpaceMap);
 | 
						|
      return EFI_OUT_OF_RESOURCES;
 | 
						|
    }
 | 
						|
 | 
						|
    mSmmIoLibGcdMemNumberOfDesc = NumberOfDescriptors;
 | 
						|
    gBS->FreePool (MemSpaceMap);
 | 
						|
  }
 | 
						|
 | 
						|
  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
 | 
						|
SmmIoLibInternalReadyToLockNotify (
 | 
						|
  IN CONST EFI_GUID  *Protocol,
 | 
						|
  IN VOID            *Interface,
 | 
						|
  IN EFI_HANDLE      Handle
 | 
						|
  )
 | 
						|
{
 | 
						|
  mSmmIoLibReadyToLock = TRUE;
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The constructor function initializes the Smm IO 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
 | 
						|
SmmIoLibConstructor (
 | 
						|
  IN EFI_HANDLE        ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE  *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS                    Status;
 | 
						|
 | 
						|
  //
 | 
						|
  // Calculate and save maximum support address
 | 
						|
  //
 | 
						|
  SmmIoLibInternalCalculateMaximumSupportAddress ();
 | 
						|
 | 
						|
  //
 | 
						|
  // Register EndOfDxe to get GCD resource map
 | 
						|
  //
 | 
						|
  Status = gSmst->SmmRegisterProtocolNotify (&gEfiSmmEndOfDxeProtocolGuid, SmmIoLibInternalEndOfDxeNotify, &mSmmIoLibRegistrationEndOfDxe);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  //
 | 
						|
  // Register ready to lock so that we can know when to check valid resource region
 | 
						|
  //
 | 
						|
  Status = gSmst->SmmRegisterProtocolNotify (&gEfiSmmReadyToLockProtocolGuid, SmmIoLibInternalReadyToLockNotify, &mSmmIoLibRegistrationReadyToLock);
 | 
						|
  ASSERT_EFI_ERROR (Status);
 | 
						|
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The destructor function frees resource used in the Smm IO 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
 | 
						|
SmmIoLibDestructor (
 | 
						|
  IN EFI_HANDLE        ImageHandle,
 | 
						|
  IN EFI_SYSTEM_TABLE  *SystemTable
 | 
						|
  )
 | 
						|
{
 | 
						|
  gSmst->SmmRegisterProtocolNotify (&gEfiSmmEndOfDxeProtocolGuid, NULL, &mSmmIoLibRegistrationEndOfDxe);
 | 
						|
  gSmst->SmmRegisterProtocolNotify (&gEfiSmmReadyToLockProtocolGuid, NULL, &mSmmIoLibRegistrationReadyToLock);
 | 
						|
  return EFI_SUCCESS;
 | 
						|
}
 |