mirror of
				https://git.proxmox.com/git/mirror_edk2
				synced 2025-10-31 18:47:58 +00:00 
			
		
		
		
	 9344f09215
			
		
	
	
		9344f09215
		
	
	
	
	
		
			
			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;
 | |
| }
 |