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: Hao Wu <hao.a.wu@intel.com> Reviewed-by: Jian J Wang <jian.j.wang@intel.com>
		
			
				
	
	
		
			1494 lines
		
	
	
		
			52 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1494 lines
		
	
	
		
			52 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   SMM Driver Dispatcher.
 | |
| 
 | |
|   Step #1 - When a FV protocol is added to the system every driver in the FV
 | |
|             is added to the mDiscoveredList. The Before, and After Depex are
 | |
|             pre-processed as drivers are added to the mDiscoveredList. If an Apriori
 | |
|             file exists in the FV those drivers are addeded to the
 | |
|             mScheduledQueue. The mFvHandleList is used to make sure a
 | |
|             FV is only processed once.
 | |
| 
 | |
|   Step #2 - Dispatch. Remove driver from the mScheduledQueue and load and
 | |
|             start it. After mScheduledQueue is drained check the
 | |
|             mDiscoveredList to see if any item has a Depex that is ready to
 | |
|             be placed on the mScheduledQueue.
 | |
| 
 | |
|   Step #3 - Adding to the mScheduledQueue requires that you process Before
 | |
|             and After dependencies. This is done recursively as the call to add
 | |
|             to the mScheduledQueue checks for Before and recursively adds
 | |
|             all Befores. It then addes the item that was passed in and then
 | |
|             processess the After dependecies by recursively calling the routine.
 | |
| 
 | |
|   Dispatcher Rules:
 | |
|   The rules for the dispatcher are similar to the DXE dispatcher.
 | |
| 
 | |
|   The rules for DXE dispatcher are in chapter 10 of the DXE CIS. Figure 10-3
 | |
|   is the state diagram for the DXE dispatcher
 | |
| 
 | |
|   Depex - Dependency Expresion.
 | |
| 
 | |
|   Copyright (c) 2014, Hewlett-Packard Development Company, L.P.
 | |
|   Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
|   SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "PiSmmCore.h"
 | |
| 
 | |
| //
 | |
| // SMM Dispatcher Data structures
 | |
| //
 | |
| #define KNOWN_HANDLE_SIGNATURE  SIGNATURE_32('k','n','o','w')
 | |
| typedef struct {
 | |
|   UINTN           Signature;
 | |
|   LIST_ENTRY      Link;         // mFvHandleList
 | |
|   EFI_HANDLE      Handle;
 | |
| } KNOWN_HANDLE;
 | |
| 
 | |
| //
 | |
| // Function Prototypes
 | |
| //
 | |
| 
 | |
| /**
 | |
|   Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
 | |
|   must add any driver with a before dependency on InsertedDriverEntry first.
 | |
|   You do this by recursively calling this routine. After all the Befores are
 | |
|   processed you can add InsertedDriverEntry to the mScheduledQueue.
 | |
|   Then you can add any driver with an After dependency on InsertedDriverEntry
 | |
|   by recursively calling this routine.
 | |
| 
 | |
|   @param  InsertedDriverEntry   The driver to insert on the ScheduledLink Queue
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
 | |
|   IN  EFI_SMM_DRIVER_ENTRY   *InsertedDriverEntry
 | |
|   );
 | |
| 
 | |
| //
 | |
| // The Driver List contains one copy of every driver that has been discovered.
 | |
| // Items are never removed from the driver list. List of EFI_SMM_DRIVER_ENTRY
 | |
| //
 | |
| LIST_ENTRY  mDiscoveredList = INITIALIZE_LIST_HEAD_VARIABLE (mDiscoveredList);
 | |
| 
 | |
| //
 | |
| // Queue of drivers that are ready to dispatch. This queue is a subset of the
 | |
| // mDiscoveredList.list of EFI_SMM_DRIVER_ENTRY.
 | |
| //
 | |
| LIST_ENTRY  mScheduledQueue = INITIALIZE_LIST_HEAD_VARIABLE (mScheduledQueue);
 | |
| 
 | |
| //
 | |
| // List of handles who's Fv's have been parsed and added to the mFwDriverList.
 | |
| //
 | |
| LIST_ENTRY  mFvHandleList = INITIALIZE_LIST_HEAD_VARIABLE (mFvHandleList);
 | |
| 
 | |
| //
 | |
| // Flag for the SMM Dispacher.  TRUE if dispatcher is execuing.
 | |
| //
 | |
| BOOLEAN  gDispatcherRunning = FALSE;
 | |
| 
 | |
| //
 | |
| // Flag for the SMM Dispacher.  TRUE if there is one or more SMM drivers ready to be dispatched
 | |
| //
 | |
| BOOLEAN  gRequestDispatch = FALSE;
 | |
| 
 | |
| //
 | |
| // List of file types supported by dispatcher
 | |
| //
 | |
| EFI_FV_FILETYPE mSmmFileTypes[] = {
 | |
|   EFI_FV_FILETYPE_SMM,
 | |
|   EFI_FV_FILETYPE_COMBINED_SMM_DXE,
 | |
|   EFI_FV_FILETYPE_SMM_CORE,
 | |
|   //
 | |
|   // Note: DXE core will process the FV image file, so skip it in SMM core
 | |
|   // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
 | |
|   //
 | |
| };
 | |
| 
 | |
| typedef struct {
 | |
|   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH  File;
 | |
|   EFI_DEVICE_PATH_PROTOCOL           End;
 | |
| } FV_FILEPATH_DEVICE_PATH;
 | |
| 
 | |
| FV_FILEPATH_DEVICE_PATH  mFvDevicePath;
 | |
| 
 | |
| //
 | |
| // DXE Architecture Protocols
 | |
| //
 | |
| EFI_SECURITY_ARCH_PROTOCOL  *mSecurity = NULL;
 | |
| EFI_SECURITY2_ARCH_PROTOCOL *mSecurity2 = NULL;
 | |
| 
 | |
| //
 | |
| // The global variable is defined for Loading modules at fixed address feature to track the SMM code
 | |
| // memory range usage. It is a bit mapped array in which every bit indicates the corresponding
 | |
| // memory page available or not.
 | |
| //
 | |
| GLOBAL_REMOVE_IF_UNREFERENCED    UINT64                *mSmmCodeMemoryRangeUsageBitMap=NULL;
 | |
| 
 | |
| /**
 | |
|   To check memory usage bit map array to figure out if the memory range in which the image will be loaded is available or not. If
 | |
|   memory range is available, the function will mark the corresponding bits to 1 which indicates the memory range is used.
 | |
|   The function is only invoked when load modules at fixed address feature is enabled.
 | |
| 
 | |
|   @param  ImageBase                The base address the image will be loaded at.
 | |
|   @param  ImageSize                The size of the image
 | |
| 
 | |
|   @retval EFI_SUCCESS              The memory range the image will be loaded in is available
 | |
|   @retval EFI_NOT_FOUND            The memory range the image will be loaded in is not available
 | |
| **/
 | |
| EFI_STATUS
 | |
| CheckAndMarkFixLoadingMemoryUsageBitMap (
 | |
|   IN  EFI_PHYSICAL_ADDRESS          ImageBase,
 | |
|   IN  UINTN                         ImageSize
 | |
|   )
 | |
| {
 | |
|    UINT32                             SmmCodePageNumber;
 | |
|    UINT64                             SmmCodeSize;
 | |
|    EFI_PHYSICAL_ADDRESS               SmmCodeBase;
 | |
|    UINTN                              BaseOffsetPageNumber;
 | |
|    UINTN                              TopOffsetPageNumber;
 | |
|    UINTN                              Index;
 | |
|    //
 | |
|    // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
 | |
|    //
 | |
|    SmmCodePageNumber = PcdGet32(PcdLoadFixAddressSmmCodePageNumber);
 | |
|    SmmCodeSize = EFI_PAGES_TO_SIZE (SmmCodePageNumber);
 | |
|    SmmCodeBase = gLoadModuleAtFixAddressSmramBase;
 | |
| 
 | |
|    //
 | |
|    // If the memory usage bit map is not initialized,  do it. Every bit in the array
 | |
|    // indicate the status of the corresponding memory page, available or not
 | |
|    //
 | |
|    if (mSmmCodeMemoryRangeUsageBitMap == NULL) {
 | |
|      mSmmCodeMemoryRangeUsageBitMap = AllocateZeroPool(((SmmCodePageNumber / 64) + 1)*sizeof(UINT64));
 | |
|    }
 | |
|    //
 | |
|    // If the Dxe code memory range is not allocated or the bit map array allocation failed, return EFI_NOT_FOUND
 | |
|    //
 | |
|    if (mSmmCodeMemoryRangeUsageBitMap == NULL) {
 | |
|      return EFI_NOT_FOUND;
 | |
|    }
 | |
|    //
 | |
|    // see if the memory range for loading the image is in the SMM code range.
 | |
|    //
 | |
|    if (SmmCodeBase + SmmCodeSize <  ImageBase + ImageSize || SmmCodeBase >  ImageBase) {
 | |
|      return EFI_NOT_FOUND;
 | |
|    }
 | |
|    //
 | |
|    // Test if the memory is avalaible or not.
 | |
|    //
 | |
|    BaseOffsetPageNumber = EFI_SIZE_TO_PAGES((UINT32)(ImageBase - SmmCodeBase));
 | |
|    TopOffsetPageNumber  = EFI_SIZE_TO_PAGES((UINT32)(ImageBase + ImageSize - SmmCodeBase));
 | |
|    for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
 | |
|      if ((mSmmCodeMemoryRangeUsageBitMap[Index / 64] & LShiftU64(1, (Index % 64))) != 0) {
 | |
|        //
 | |
|        // This page is already used.
 | |
|        //
 | |
|        return EFI_NOT_FOUND;
 | |
|      }
 | |
|    }
 | |
| 
 | |
|    //
 | |
|    // Being here means the memory range is available.  So mark the bits for the memory range
 | |
|    //
 | |
|    for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index ++) {
 | |
|      mSmmCodeMemoryRangeUsageBitMap[Index / 64] |= LShiftU64(1, (Index % 64));
 | |
|    }
 | |
|    return  EFI_SUCCESS;
 | |
| }
 | |
| /**
 | |
|   Get the fixed loading address from image header assigned by build tool. This function only be called
 | |
|   when Loading module at Fixed address feature enabled.
 | |
| 
 | |
|   @param  ImageContext              Pointer to the image context structure that describes the PE/COFF
 | |
|                                     image that needs to be examined by this function.
 | |
|   @retval EFI_SUCCESS               An fixed loading address is assigned to this image by build tools .
 | |
|   @retval EFI_NOT_FOUND             The image has no assigned fixed loading address.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| GetPeCoffImageFixLoadingAssignedAddress(
 | |
|   IN OUT PE_COFF_LOADER_IMAGE_CONTEXT  *ImageContext
 | |
|   )
 | |
| {
 | |
|   UINTN                              SectionHeaderOffset;
 | |
|   EFI_STATUS                         Status;
 | |
|   EFI_IMAGE_SECTION_HEADER           SectionHeader;
 | |
|   EFI_IMAGE_OPTIONAL_HEADER_UNION    *ImgHdr;
 | |
|   EFI_PHYSICAL_ADDRESS               FixLoadingAddress;
 | |
|   UINT16                             Index;
 | |
|   UINTN                              Size;
 | |
|   UINT16                             NumberOfSections;
 | |
|   UINT64                             ValueInSectionHeader;
 | |
| 
 | |
|   FixLoadingAddress = 0;
 | |
|   Status = EFI_NOT_FOUND;
 | |
| 
 | |
|   //
 | |
|   // Get PeHeader pointer
 | |
|   //
 | |
|   ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8* )ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
 | |
|   SectionHeaderOffset = ImageContext->PeCoffHeaderOffset +
 | |
|                         sizeof (UINT32) +
 | |
|                         sizeof (EFI_IMAGE_FILE_HEADER) +
 | |
|                         ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader;
 | |
|   NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
 | |
| 
 | |
|   //
 | |
|   // Get base address from the first section header that doesn't point to code section.
 | |
|   //
 | |
|   for (Index = 0; Index < NumberOfSections; Index++) {
 | |
|     //
 | |
|     // Read section header from file
 | |
|     //
 | |
|     Size = sizeof (EFI_IMAGE_SECTION_HEADER);
 | |
|     Status = ImageContext->ImageRead (
 | |
|                               ImageContext->Handle,
 | |
|                               SectionHeaderOffset,
 | |
|                               &Size,
 | |
|                               &SectionHeader
 | |
|                               );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     Status = EFI_NOT_FOUND;
 | |
| 
 | |
|     if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
 | |
|       //
 | |
|       // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header
 | |
|       // that doesn't point to code section in image header.So there is an assumption that when the feature is enabled,
 | |
|       // if a module with a loading address assigned by tools, the PointerToRelocations & PointerToLineNumbers fields
 | |
|       // should not be Zero, or else, these 2 fields should be set to Zero
 | |
|       //
 | |
|       ValueInSectionHeader = ReadUnaligned64((UINT64*)&SectionHeader.PointerToRelocations);
 | |
|       if (ValueInSectionHeader != 0) {
 | |
|         //
 | |
|         // Found first section header that doesn't point to code section in which build tool saves the
 | |
|         // offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields
 | |
|         //
 | |
|         FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressSmramBase + (INT64)ValueInSectionHeader);
 | |
|         //
 | |
|         // Check if the memory range is available.
 | |
|         //
 | |
|         Status = CheckAndMarkFixLoadingMemoryUsageBitMap (FixLoadingAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment));
 | |
|         if (!EFI_ERROR(Status)) {
 | |
|           //
 | |
|           // The assigned address is valid. Return the specified loading address
 | |
|           //
 | |
|           ImageContext->ImageAddress = FixLoadingAddress;
 | |
|         }
 | |
|       }
 | |
|       break;
 | |
|     }
 | |
|     SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
 | |
|   }
 | |
|   DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address %x, Status = %r\n", FixLoadingAddress, Status));
 | |
|   return Status;
 | |
| }
 | |
| /**
 | |
|   Loads an EFI image into SMRAM.
 | |
| 
 | |
|   @param  DriverEntry             EFI_SMM_DRIVER_ENTRY instance
 | |
| 
 | |
|   @return EFI_STATUS
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| SmmLoadImage (
 | |
|   IN OUT EFI_SMM_DRIVER_ENTRY  *DriverEntry
 | |
|   )
 | |
| {
 | |
|   UINT32                         AuthenticationStatus;
 | |
|   UINTN                          FilePathSize;
 | |
|   VOID                           *Buffer;
 | |
|   UINTN                          Size;
 | |
|   UINTN                          PageCount;
 | |
|   EFI_GUID                       *NameGuid;
 | |
|   EFI_STATUS                     Status;
 | |
|   EFI_STATUS                     SecurityStatus;
 | |
|   EFI_HANDLE                     DeviceHandle;
 | |
|   EFI_PHYSICAL_ADDRESS           DstBuffer;
 | |
|   EFI_DEVICE_PATH_PROTOCOL       *FilePath;
 | |
|   EFI_DEVICE_PATH_PROTOCOL       *OriginalFilePath;
 | |
|   EFI_DEVICE_PATH_PROTOCOL       *HandleFilePath;
 | |
|   EFI_FIRMWARE_VOLUME2_PROTOCOL  *Fv;
 | |
|   PE_COFF_LOADER_IMAGE_CONTEXT   ImageContext;
 | |
| 
 | |
|   PERF_LOAD_IMAGE_BEGIN (DriverEntry->ImageHandle);
 | |
| 
 | |
|   Buffer               = NULL;
 | |
|   Size                 = 0;
 | |
|   Fv                   = DriverEntry->Fv;
 | |
|   NameGuid             = &DriverEntry->FileName;
 | |
|   FilePath             = DriverEntry->FvFileDevicePath;
 | |
| 
 | |
|   OriginalFilePath     = FilePath;
 | |
|   HandleFilePath       = FilePath;
 | |
|   DeviceHandle         = NULL;
 | |
|   SecurityStatus       = EFI_SUCCESS;
 | |
|   Status               = EFI_SUCCESS;
 | |
|   AuthenticationStatus = 0;
 | |
| 
 | |
|   //
 | |
|   // Try to get the image device handle by checking the match protocol.
 | |
|   //
 | |
|   Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle);
 | |
|   if (EFI_ERROR(Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // If the Security2 and Security Architectural Protocol has not been located yet, then attempt to locate it
 | |
|   //
 | |
|   if (mSecurity2 == NULL) {
 | |
|     gBS->LocateProtocol (&gEfiSecurity2ArchProtocolGuid, NULL, (VOID**)&mSecurity2);
 | |
|   }
 | |
|   if (mSecurity == NULL) {
 | |
|     gBS->LocateProtocol (&gEfiSecurityArchProtocolGuid, NULL, (VOID**)&mSecurity);
 | |
|   }
 | |
|   //
 | |
|   // When Security2 is installed, Security Architectural Protocol must be published.
 | |
|   //
 | |
|   ASSERT (mSecurity2 == NULL || mSecurity != NULL);
 | |
| 
 | |
|   //
 | |
|   // Pull out just the file portion of the DevicePath for the LoadedImage FilePath
 | |
|   //
 | |
|   FilePath = OriginalFilePath;
 | |
|   Status = gBS->HandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath);
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     FilePathSize = GetDevicePathSize (HandleFilePath) - sizeof(EFI_DEVICE_PATH_PROTOCOL);
 | |
|     FilePath = (EFI_DEVICE_PATH_PROTOCOL *) (((UINT8 *)FilePath) + FilePathSize );
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Try reading PE32 section firstly
 | |
|   //
 | |
|   Status = Fv->ReadSection (
 | |
|                  Fv,
 | |
|                  NameGuid,
 | |
|                  EFI_SECTION_PE32,
 | |
|                  0,
 | |
|                  &Buffer,
 | |
|                  &Size,
 | |
|                  &AuthenticationStatus
 | |
|                  );
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // Try reading TE section secondly
 | |
|     //
 | |
|     Buffer = NULL;
 | |
|     Size   = 0;
 | |
|     Status = Fv->ReadSection (
 | |
|                   Fv,
 | |
|                   NameGuid,
 | |
|                   EFI_SECTION_TE,
 | |
|                   0,
 | |
|                   &Buffer,
 | |
|                   &Size,
 | |
|                   &AuthenticationStatus
 | |
|                   );
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     if (Buffer != NULL) {
 | |
|       gBS->FreePool (Buffer);
 | |
|     }
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Verify File Authentication through the Security2 Architectural Protocol
 | |
|   //
 | |
|   if (mSecurity2 != NULL) {
 | |
|     SecurityStatus = mSecurity2->FileAuthentication (
 | |
|                                   mSecurity2,
 | |
|                                   OriginalFilePath,
 | |
|                                   Buffer,
 | |
|                                   Size,
 | |
|                                   FALSE
 | |
|                                   );
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Verify the Authentication Status through the Security Architectural Protocol
 | |
|   // Only on images that have been read using Firmware Volume protocol.
 | |
|   // All SMM images are from FV protocol.
 | |
|   //
 | |
|   if (!EFI_ERROR (SecurityStatus) && (mSecurity != NULL)) {
 | |
|     SecurityStatus = mSecurity->FileAuthenticationState (
 | |
|                                   mSecurity,
 | |
|                                   AuthenticationStatus,
 | |
|                                   OriginalFilePath
 | |
|                                   );
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (SecurityStatus) && SecurityStatus != EFI_SECURITY_VIOLATION) {
 | |
|     Status = SecurityStatus;
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Initialize ImageContext
 | |
|   //
 | |
|   ImageContext.Handle = Buffer;
 | |
|   ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
 | |
| 
 | |
|   //
 | |
|   // Get information about the image being loaded
 | |
|   //
 | |
|   Status = PeCoffLoaderGetImageInfo (&ImageContext);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     if (Buffer != NULL) {
 | |
|       gBS->FreePool (Buffer);
 | |
|     }
 | |
|     return Status;
 | |
|   }
 | |
|   //
 | |
|   // if Loading module at Fixed Address feature is enabled, then  cut out a memory range started from TESG BASE
 | |
|   // to hold the Smm driver code
 | |
|   //
 | |
|   if (PcdGet64(PcdLoadModuleAtFixAddressEnable) != 0) {
 | |
|     //
 | |
|     // Get the fixed loading address assigned by Build tool
 | |
|     //
 | |
|     Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext);
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // Since the memory range to load Smm core alreay been cut out, so no need to allocate and free this range
 | |
|       // following statements is to bypass SmmFreePages
 | |
|       //
 | |
|       PageCount = 0;
 | |
|       DstBuffer = (UINTN)gLoadModuleAtFixAddressSmramBase;
 | |
|     } else {
 | |
|        DEBUG ((EFI_D_INFO|EFI_D_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));
 | |
|        //
 | |
|        // allocate the memory to load the SMM driver
 | |
|        //
 | |
|        PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
 | |
|        DstBuffer = (UINTN)(-1);
 | |
| 
 | |
|        Status = SmmAllocatePages (
 | |
|                    AllocateMaxAddress,
 | |
|                    EfiRuntimeServicesCode,
 | |
|                    PageCount,
 | |
|                    &DstBuffer
 | |
|                    );
 | |
|        if (EFI_ERROR (Status)) {
 | |
|          if (Buffer != NULL) {
 | |
|            gBS->FreePool (Buffer);
 | |
|          }
 | |
|          return Status;
 | |
|        }
 | |
|       ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer;
 | |
|     }
 | |
|   } else {
 | |
|      PageCount = (UINTN)EFI_SIZE_TO_PAGES((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
 | |
|      DstBuffer = (UINTN)(-1);
 | |
| 
 | |
|      Status = SmmAllocatePages (
 | |
|                   AllocateMaxAddress,
 | |
|                   EfiRuntimeServicesCode,
 | |
|                   PageCount,
 | |
|                   &DstBuffer
 | |
|                   );
 | |
|      if (EFI_ERROR (Status)) {
 | |
|        if (Buffer != NULL) {
 | |
|          gBS->FreePool (Buffer);
 | |
|        }
 | |
|        return Status;
 | |
|      }
 | |
| 
 | |
|      ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer;
 | |
|   }
 | |
|   //
 | |
|   // Align buffer on section boundary
 | |
|   //
 | |
|   ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
 | |
|   ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
 | |
| 
 | |
|   //
 | |
|   // Load the image to our new buffer
 | |
|   //
 | |
|   Status = PeCoffLoaderLoadImage (&ImageContext);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     if (Buffer != NULL) {
 | |
|       gBS->FreePool (Buffer);
 | |
|     }
 | |
|     SmmFreePages (DstBuffer, PageCount);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Relocate the image in our new buffer
 | |
|   //
 | |
|   Status = PeCoffLoaderRelocateImage (&ImageContext);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     if (Buffer != NULL) {
 | |
|       gBS->FreePool (Buffer);
 | |
|     }
 | |
|     SmmFreePages (DstBuffer, PageCount);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Flush the instruction cache so the image data are written before we execute it
 | |
|   //
 | |
|   InvalidateInstructionCacheRange ((VOID *)(UINTN) ImageContext.ImageAddress, (UINTN) ImageContext.ImageSize);
 | |
| 
 | |
|   //
 | |
|   // Save Image EntryPoint in DriverEntry
 | |
|   //
 | |
|   DriverEntry->ImageEntryPoint  = ImageContext.EntryPoint;
 | |
|   DriverEntry->ImageBuffer      = DstBuffer;
 | |
|   DriverEntry->NumberOfPage     = PageCount;
 | |
| 
 | |
|   //
 | |
|   // Allocate a Loaded Image Protocol in EfiBootServicesData
 | |
|   //
 | |
|   Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_LOADED_IMAGE_PROTOCOL), (VOID **)&DriverEntry->LoadedImage);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     if (Buffer != NULL) {
 | |
|       gBS->FreePool (Buffer);
 | |
|     }
 | |
|     SmmFreePages (DstBuffer, PageCount);
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   ZeroMem (DriverEntry->LoadedImage, sizeof (EFI_LOADED_IMAGE_PROTOCOL));
 | |
|   //
 | |
|   // Fill in the remaining fields of the Loaded Image Protocol instance.
 | |
|   // Note: ImageBase is an SMRAM address that can not be accessed outside of SMRAM if SMRAM window is closed.
 | |
|   //
 | |
|   DriverEntry->LoadedImage->Revision      = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
 | |
|   DriverEntry->LoadedImage->ParentHandle  = gSmmCorePrivate->SmmIplImageHandle;
 | |
|   DriverEntry->LoadedImage->SystemTable   = gST;
 | |
|   DriverEntry->LoadedImage->DeviceHandle  = DeviceHandle;
 | |
| 
 | |
|   DriverEntry->SmmLoadedImage.Revision     = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
 | |
|   DriverEntry->SmmLoadedImage.ParentHandle = gSmmCorePrivate->SmmIplImageHandle;
 | |
|   DriverEntry->SmmLoadedImage.SystemTable  = gST;
 | |
|   DriverEntry->SmmLoadedImage.DeviceHandle = DeviceHandle;
 | |
| 
 | |
|   //
 | |
|   // Make an EfiBootServicesData buffer copy of FilePath
 | |
|   //
 | |
|   Status = gBS->AllocatePool (EfiBootServicesData, GetDevicePathSize (FilePath), (VOID **)&DriverEntry->LoadedImage->FilePath);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     if (Buffer != NULL) {
 | |
|       gBS->FreePool (Buffer);
 | |
|     }
 | |
|     SmmFreePages (DstBuffer, PageCount);
 | |
|     return Status;
 | |
|   }
 | |
|   CopyMem (DriverEntry->LoadedImage->FilePath, FilePath, GetDevicePathSize (FilePath));
 | |
| 
 | |
|   DriverEntry->LoadedImage->ImageBase     = (VOID *)(UINTN) ImageContext.ImageAddress;
 | |
|   DriverEntry->LoadedImage->ImageSize     = ImageContext.ImageSize;
 | |
|   DriverEntry->LoadedImage->ImageCodeType = EfiRuntimeServicesCode;
 | |
|   DriverEntry->LoadedImage->ImageDataType = EfiRuntimeServicesData;
 | |
| 
 | |
|   //
 | |
|   // Make a buffer copy of FilePath
 | |
|   //
 | |
|   Status = SmmAllocatePool (EfiRuntimeServicesData, GetDevicePathSize(FilePath), (VOID **)&DriverEntry->SmmLoadedImage.FilePath);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     if (Buffer != NULL) {
 | |
|       gBS->FreePool (Buffer);
 | |
|     }
 | |
|     gBS->FreePool (DriverEntry->LoadedImage->FilePath);
 | |
|     SmmFreePages (DstBuffer, PageCount);
 | |
|     return Status;
 | |
|   }
 | |
|   CopyMem (DriverEntry->SmmLoadedImage.FilePath, FilePath, GetDevicePathSize(FilePath));
 | |
| 
 | |
|   DriverEntry->SmmLoadedImage.ImageBase = (VOID *)(UINTN) ImageContext.ImageAddress;
 | |
|   DriverEntry->SmmLoadedImage.ImageSize = ImageContext.ImageSize;
 | |
|   DriverEntry->SmmLoadedImage.ImageCodeType = EfiRuntimeServicesCode;
 | |
|   DriverEntry->SmmLoadedImage.ImageDataType = EfiRuntimeServicesData;
 | |
| 
 | |
|   //
 | |
|   // Create a new image handle in the UEFI handle database for the SMM Driver
 | |
|   //
 | |
|   DriverEntry->ImageHandle = NULL;
 | |
|   Status = gBS->InstallMultipleProtocolInterfaces (
 | |
|                   &DriverEntry->ImageHandle,
 | |
|                   &gEfiLoadedImageProtocolGuid, DriverEntry->LoadedImage,
 | |
|                   NULL
 | |
|                   );
 | |
| 
 | |
|   //
 | |
|   // Create a new image handle in the SMM handle database for the SMM Driver
 | |
|   //
 | |
|   DriverEntry->SmmImageHandle = NULL;
 | |
|   Status = SmmInstallProtocolInterface (
 | |
|              &DriverEntry->SmmImageHandle,
 | |
|              &gEfiLoadedImageProtocolGuid,
 | |
|              EFI_NATIVE_INTERFACE,
 | |
|              &DriverEntry->SmmLoadedImage
 | |
|              );
 | |
| 
 | |
|   PERF_LOAD_IMAGE_END (DriverEntry->ImageHandle);
 | |
| 
 | |
|   //
 | |
|   // Print the load address and the PDB file name if it is available
 | |
|   //
 | |
| 
 | |
|   DEBUG_CODE_BEGIN ();
 | |
| 
 | |
|     UINTN Index;
 | |
|     UINTN StartIndex;
 | |
|     CHAR8 EfiFileName[256];
 | |
| 
 | |
| 
 | |
|     DEBUG ((DEBUG_INFO | DEBUG_LOAD,
 | |
|            "Loading SMM driver at 0x%11p EntryPoint=0x%11p ",
 | |
|            (VOID *)(UINTN) ImageContext.ImageAddress,
 | |
|            FUNCTION_ENTRY_POINT (ImageContext.EntryPoint)));
 | |
| 
 | |
| 
 | |
|     //
 | |
|     // Print Module Name by Pdb file path.
 | |
|     // Windows and Unix style file path are all trimmed correctly.
 | |
|     //
 | |
|     if (ImageContext.PdbPointer != NULL) {
 | |
|       StartIndex = 0;
 | |
|       for (Index = 0; ImageContext.PdbPointer[Index] != 0; Index++) {
 | |
|         if ((ImageContext.PdbPointer[Index] == '\\') || (ImageContext.PdbPointer[Index] == '/')) {
 | |
|           StartIndex = Index + 1;
 | |
|         }
 | |
|       }
 | |
|       //
 | |
|       // Copy the PDB file name to our temporary string, and replace .pdb with .efi
 | |
|       // The PDB file name is limited in the range of 0~255.
 | |
|       // If the length is bigger than 255, trim the redudant characters to avoid overflow in array boundary.
 | |
|       //
 | |
|       for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {
 | |
|         EfiFileName[Index] = ImageContext.PdbPointer[Index + StartIndex];
 | |
|         if (EfiFileName[Index] == 0) {
 | |
|           EfiFileName[Index] = '.';
 | |
|         }
 | |
|         if (EfiFileName[Index] == '.') {
 | |
|           EfiFileName[Index + 1] = 'e';
 | |
|           EfiFileName[Index + 2] = 'f';
 | |
|           EfiFileName[Index + 3] = 'i';
 | |
|           EfiFileName[Index + 4] = 0;
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (Index == sizeof (EfiFileName) - 4) {
 | |
|         EfiFileName[Index] = 0;
 | |
|       }
 | |
|       DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex]));
 | |
|     }
 | |
|     DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n"));
 | |
| 
 | |
|   DEBUG_CODE_END ();
 | |
| 
 | |
|   //
 | |
|   // Free buffer allocated by Fv->ReadSection.
 | |
|   //
 | |
|   // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection
 | |
|   // used the UEFI Boot Services AllocatePool() function
 | |
|   //
 | |
|   Status = gBS->FreePool(Buffer);
 | |
|   if (!EFI_ERROR (Status) && EFI_ERROR (SecurityStatus)) {
 | |
|     Status = SecurityStatus;
 | |
|   }
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Preprocess dependency expression and update DriverEntry to reflect the
 | |
|   state of  Before and After dependencies. If DriverEntry->Before
 | |
|   or DriverEntry->After is set it will never be cleared.
 | |
| 
 | |
|   @param  DriverEntry           DriverEntry element to update .
 | |
| 
 | |
|   @retval EFI_SUCCESS           It always works.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SmmPreProcessDepex (
 | |
|   IN EFI_SMM_DRIVER_ENTRY  *DriverEntry
 | |
|   )
 | |
| {
 | |
|   UINT8  *Iterator;
 | |
| 
 | |
|   Iterator = DriverEntry->Depex;
 | |
|   DriverEntry->Dependent = TRUE;
 | |
| 
 | |
|   if (*Iterator == EFI_DEP_BEFORE) {
 | |
|     DriverEntry->Before = TRUE;
 | |
|   } else if (*Iterator == EFI_DEP_AFTER) {
 | |
|     DriverEntry->After = TRUE;
 | |
|   }
 | |
| 
 | |
|   if (DriverEntry->Before || DriverEntry->After) {
 | |
|     CopyMem (&DriverEntry->BeforeAfterGuid, Iterator + 1, sizeof (EFI_GUID));
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Read Depex and pre-process the Depex for Before and After. If Section Extraction
 | |
|   protocol returns an error via ReadSection defer the reading of the Depex.
 | |
| 
 | |
|   @param  DriverEntry           Driver to work on.
 | |
| 
 | |
|   @retval EFI_SUCCESS           Depex read and preprossesed
 | |
|   @retval EFI_PROTOCOL_ERROR    The section extraction protocol returned an error
 | |
|                                 and  Depex reading needs to be retried.
 | |
|   @retval Error                 DEPEX not found.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SmmGetDepexSectionAndPreProccess (
 | |
|   IN EFI_SMM_DRIVER_ENTRY  *DriverEntry
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                     Status;
 | |
|   EFI_SECTION_TYPE               SectionType;
 | |
|   UINT32                         AuthenticationStatus;
 | |
|   EFI_FIRMWARE_VOLUME2_PROTOCOL  *Fv;
 | |
| 
 | |
|   Fv = DriverEntry->Fv;
 | |
| 
 | |
|   //
 | |
|   // Grab Depex info, it will never be free'ed.
 | |
|   // (Note: DriverEntry->Depex is in DXE memory)
 | |
|   //
 | |
|   SectionType         = EFI_SECTION_SMM_DEPEX;
 | |
|   Status = Fv->ReadSection (
 | |
|                 DriverEntry->Fv,
 | |
|                 &DriverEntry->FileName,
 | |
|                 SectionType,
 | |
|                 0,
 | |
|                 &DriverEntry->Depex,
 | |
|                 (UINTN *)&DriverEntry->DepexSize,
 | |
|                 &AuthenticationStatus
 | |
|                 );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     if (Status == EFI_PROTOCOL_ERROR) {
 | |
|       //
 | |
|       // The section extraction protocol failed so set protocol error flag
 | |
|       //
 | |
|       DriverEntry->DepexProtocolError = TRUE;
 | |
|     } else {
 | |
|       //
 | |
|       // If no Depex assume depend on all architectural protocols
 | |
|       //
 | |
|       DriverEntry->Depex = NULL;
 | |
|       DriverEntry->Dependent = TRUE;
 | |
|       DriverEntry->DepexProtocolError = FALSE;
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // Set Before and After state information based on Depex
 | |
|     // Driver will be put in Dependent state
 | |
|     //
 | |
|     SmmPreProcessDepex (DriverEntry);
 | |
|     DriverEntry->DepexProtocolError = FALSE;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This is the main Dispatcher for SMM and it exits when there are no more
 | |
|   drivers to run. Drain the mScheduledQueue and load and start a PE
 | |
|   image for each driver. Search the mDiscoveredList to see if any driver can
 | |
|   be placed on the mScheduledQueue. If no drivers are placed on the
 | |
|   mScheduledQueue exit the function.
 | |
| 
 | |
|   @retval EFI_SUCCESS           All of the SMM Drivers that could be dispatched
 | |
|                                 have been run and the SMM Entry Point has been
 | |
|                                 registered.
 | |
|   @retval EFI_NOT_READY         The SMM Driver that registered the SMM Entry Point
 | |
|                                 was just dispatched.
 | |
|   @retval EFI_NOT_FOUND         There are no SMM Drivers available to be dispatched.
 | |
|   @retval EFI_ALREADY_STARTED   The SMM Dispatcher is already running
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SmmDispatcher (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS            Status;
 | |
|   LIST_ENTRY            *Link;
 | |
|   EFI_SMM_DRIVER_ENTRY  *DriverEntry;
 | |
|   BOOLEAN               ReadyToRun;
 | |
|   BOOLEAN               PreviousSmmEntryPointRegistered;
 | |
| 
 | |
|   if (!gRequestDispatch) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   if (gDispatcherRunning) {
 | |
|     //
 | |
|     // If the dispatcher is running don't let it be restarted.
 | |
|     //
 | |
|     return EFI_ALREADY_STARTED;
 | |
|   }
 | |
| 
 | |
|   gDispatcherRunning = TRUE;
 | |
| 
 | |
|   do {
 | |
|     //
 | |
|     // Drain the Scheduled Queue
 | |
|     //
 | |
|     while (!IsListEmpty (&mScheduledQueue)) {
 | |
|       DriverEntry = CR (
 | |
|                       mScheduledQueue.ForwardLink,
 | |
|                       EFI_SMM_DRIVER_ENTRY,
 | |
|                       ScheduledLink,
 | |
|                       EFI_SMM_DRIVER_ENTRY_SIGNATURE
 | |
|                       );
 | |
| 
 | |
|       //
 | |
|       // Load the SMM Driver image into memory. If the Driver was transitioned from
 | |
|       // Untrused to Scheduled it would have already been loaded so we may need to
 | |
|       // skip the LoadImage
 | |
|       //
 | |
|       if (DriverEntry->ImageHandle == NULL) {
 | |
|         Status = SmmLoadImage (DriverEntry);
 | |
| 
 | |
|         //
 | |
|         // Update the driver state to reflect that it's been loaded
 | |
|         //
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           //
 | |
|           // The SMM Driver could not be loaded, and do not attempt to load or start it again.
 | |
|           // Take driver from Scheduled to Initialized.
 | |
|           //
 | |
|           DriverEntry->Initialized  = TRUE;
 | |
|           DriverEntry->Scheduled = FALSE;
 | |
|           RemoveEntryList (&DriverEntry->ScheduledLink);
 | |
| 
 | |
|           //
 | |
|           // If it's an error don't try the StartImage
 | |
|           //
 | |
|           continue;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       DriverEntry->Scheduled    = FALSE;
 | |
|       DriverEntry->Initialized  = TRUE;
 | |
|       RemoveEntryList (&DriverEntry->ScheduledLink);
 | |
| 
 | |
|       REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
 | |
|         EFI_PROGRESS_CODE,
 | |
|         EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_BEGIN,
 | |
|         &DriverEntry->ImageHandle,
 | |
|         sizeof (DriverEntry->ImageHandle)
 | |
|         );
 | |
| 
 | |
|       //
 | |
|       // Cache state of SmmEntryPointRegistered before calling entry point
 | |
|       //
 | |
|       PreviousSmmEntryPointRegistered = gSmmCorePrivate->SmmEntryPointRegistered;
 | |
| 
 | |
|       //
 | |
|       // For each SMM driver, pass NULL as ImageHandle
 | |
|       //
 | |
|       RegisterSmramProfileImage (DriverEntry, TRUE);
 | |
|       PERF_START_IMAGE_BEGIN (DriverEntry->ImageHandle);
 | |
|       Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, gST);
 | |
|       PERF_START_IMAGE_END (DriverEntry->ImageHandle);
 | |
|       if (EFI_ERROR(Status)){
 | |
|         UnregisterSmramProfileImage (DriverEntry, TRUE);
 | |
|         SmmFreePages(DriverEntry->ImageBuffer, DriverEntry->NumberOfPage);
 | |
|         //
 | |
|         // Uninstall LoadedImage
 | |
|         //
 | |
|         Status = gBS->UninstallProtocolInterface (
 | |
|                         DriverEntry->ImageHandle,
 | |
|                         &gEfiLoadedImageProtocolGuid,
 | |
|                         DriverEntry->LoadedImage
 | |
|                         );
 | |
|         if (!EFI_ERROR (Status)) {
 | |
|           if (DriverEntry->LoadedImage->FilePath != NULL) {
 | |
|             gBS->FreePool (DriverEntry->LoadedImage->FilePath);
 | |
|           }
 | |
|           gBS->FreePool (DriverEntry->LoadedImage);
 | |
|         }
 | |
|         Status = SmmUninstallProtocolInterface (
 | |
|                    DriverEntry->SmmImageHandle,
 | |
|                    &gEfiLoadedImageProtocolGuid,
 | |
|                    &DriverEntry->SmmLoadedImage
 | |
|                    );
 | |
|         if (!EFI_ERROR(Status)) {
 | |
|           if (DriverEntry->SmmLoadedImage.FilePath != NULL) {
 | |
|             SmmFreePool (DriverEntry->SmmLoadedImage.FilePath);
 | |
|           }
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
 | |
|         EFI_PROGRESS_CODE,
 | |
|         EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_END,
 | |
|         &DriverEntry->ImageHandle,
 | |
|         sizeof (DriverEntry->ImageHandle)
 | |
|         );
 | |
| 
 | |
|       if (!PreviousSmmEntryPointRegistered && gSmmCorePrivate->SmmEntryPointRegistered) {
 | |
|         //
 | |
|         // Return immediately if the SMM Entry Point was registered by the SMM
 | |
|         // Driver that was just dispatched.  The SMM IPL will reinvoke the SMM
 | |
|         // Core Dispatcher.  This is required so SMM Mode may be enabled as soon
 | |
|         // as all the dependent SMM Drivers for SMM Mode have been dispatched.
 | |
|         // Once the SMM Entry Point has been registered, then SMM Mode will be
 | |
|         // used.
 | |
|         //
 | |
|         gRequestDispatch = TRUE;
 | |
|         gDispatcherRunning = FALSE;
 | |
|         return EFI_NOT_READY;
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Search DriverList for items to place on Scheduled Queue
 | |
|     //
 | |
|     ReadyToRun = FALSE;
 | |
|     for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
 | |
|       DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
 | |
| 
 | |
|       if (DriverEntry->DepexProtocolError){
 | |
|         //
 | |
|         // If Section Extraction Protocol did not let the Depex be read before retry the read
 | |
|         //
 | |
|         Status = SmmGetDepexSectionAndPreProccess (DriverEntry);
 | |
|       }
 | |
| 
 | |
|       if (DriverEntry->Dependent) {
 | |
|         if (SmmIsSchedulable (DriverEntry)) {
 | |
|           SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
 | |
|           ReadyToRun = TRUE;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   } while (ReadyToRun);
 | |
| 
 | |
|   //
 | |
|   // If there is no more SMM driver to dispatch, stop the dispatch request
 | |
|   //
 | |
|   gRequestDispatch = FALSE;
 | |
|   for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
 | |
|     DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
 | |
| 
 | |
|     if (!DriverEntry->Initialized){
 | |
|       //
 | |
|       // We have SMM driver pending to dispatch
 | |
|       //
 | |
|       gRequestDispatch = TRUE;
 | |
|       break;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   gDispatcherRunning = FALSE;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
 | |
|   must add any driver with a before dependency on InsertedDriverEntry first.
 | |
|   You do this by recursively calling this routine. After all the Befores are
 | |
|   processed you can add InsertedDriverEntry to the mScheduledQueue.
 | |
|   Then you can add any driver with an After dependency on InsertedDriverEntry
 | |
|   by recursively calling this routine.
 | |
| 
 | |
|   @param  InsertedDriverEntry   The driver to insert on the ScheduledLink Queue
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
 | |
|   IN  EFI_SMM_DRIVER_ENTRY   *InsertedDriverEntry
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY            *Link;
 | |
|   EFI_SMM_DRIVER_ENTRY *DriverEntry;
 | |
| 
 | |
|   //
 | |
|   // Process Before Dependency
 | |
|   //
 | |
|   for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
 | |
|     DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
 | |
|     if (DriverEntry->Before && DriverEntry->Dependent && DriverEntry != InsertedDriverEntry) {
 | |
|       DEBUG ((DEBUG_DISPATCH, "Evaluate SMM DEPEX for FFS(%g)\n", &DriverEntry->FileName));
 | |
|       DEBUG ((DEBUG_DISPATCH, "  BEFORE FFS(%g) = ", &DriverEntry->BeforeAfterGuid));
 | |
|       if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
 | |
|         //
 | |
|         // Recursively process BEFORE
 | |
|         //
 | |
|         DEBUG ((DEBUG_DISPATCH, "TRUE\n  END\n  RESULT = TRUE\n"));
 | |
|         SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
 | |
|       } else {
 | |
|         DEBUG ((DEBUG_DISPATCH, "FALSE\n  END\n  RESULT = FALSE\n"));
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Convert driver from Dependent to Scheduled state
 | |
|   //
 | |
| 
 | |
|   InsertedDriverEntry->Dependent = FALSE;
 | |
|   InsertedDriverEntry->Scheduled = TRUE;
 | |
|   InsertTailList (&mScheduledQueue, &InsertedDriverEntry->ScheduledLink);
 | |
| 
 | |
| 
 | |
|   //
 | |
|   // Process After Dependency
 | |
|   //
 | |
|   for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
 | |
|     DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
 | |
|     if (DriverEntry->After && DriverEntry->Dependent && DriverEntry != InsertedDriverEntry) {
 | |
|       DEBUG ((DEBUG_DISPATCH, "Evaluate SMM DEPEX for FFS(%g)\n", &DriverEntry->FileName));
 | |
|       DEBUG ((DEBUG_DISPATCH, "  AFTER FFS(%g) = ", &DriverEntry->BeforeAfterGuid));
 | |
|       if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
 | |
|         //
 | |
|         // Recursively process AFTER
 | |
|         //
 | |
|         DEBUG ((DEBUG_DISPATCH, "TRUE\n  END\n  RESULT = TRUE\n"));
 | |
|         SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
 | |
|       } else {
 | |
|         DEBUG ((DEBUG_DISPATCH, "FALSE\n  END\n  RESULT = FALSE\n"));
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Return TRUE if the Fv has been processed, FALSE if not.
 | |
| 
 | |
|   @param  FvHandle              The handle of a FV that's being tested
 | |
| 
 | |
|   @retval TRUE                  Fv protocol on FvHandle has been processed
 | |
|   @retval FALSE                 Fv protocol on FvHandle has not yet been
 | |
|                                 processed
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| FvHasBeenProcessed (
 | |
|   IN EFI_HANDLE  FvHandle
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY    *Link;
 | |
|   KNOWN_HANDLE  *KnownHandle;
 | |
| 
 | |
|   for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) {
 | |
|     KnownHandle = CR(Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE);
 | |
|     if (KnownHandle->Handle == FvHandle) {
 | |
|       return TRUE;
 | |
|     }
 | |
|   }
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Remember that Fv protocol on FvHandle has had it's drivers placed on the
 | |
|   mDiscoveredList. This fucntion adds entries on the mFvHandleList. Items are
 | |
|   never removed/freed from the mFvHandleList.
 | |
| 
 | |
|   @param  FvHandle              The handle of a FV that has been processed
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| FvIsBeingProcesssed (
 | |
|   IN EFI_HANDLE  FvHandle
 | |
|   )
 | |
| {
 | |
|   KNOWN_HANDLE  *KnownHandle;
 | |
| 
 | |
|   KnownHandle = AllocatePool (sizeof (KNOWN_HANDLE));
 | |
|   ASSERT (KnownHandle != NULL);
 | |
| 
 | |
|   KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE;
 | |
|   KnownHandle->Handle = FvHandle;
 | |
|   InsertTailList (&mFvHandleList, &KnownHandle->Link);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Convert FvHandle and DriverName into an EFI device path
 | |
| 
 | |
|   @param  Fv                    Fv protocol, needed to read Depex info out of
 | |
|                                 FLASH.
 | |
|   @param  FvHandle              Handle for Fv, needed in the
 | |
|                                 EFI_SMM_DRIVER_ENTRY so that the PE image can be
 | |
|                                 read out of the FV at a later time.
 | |
|   @param  DriverName            Name of driver to add to mDiscoveredList.
 | |
| 
 | |
|   @return Pointer to device path constructed from FvHandle and DriverName
 | |
| 
 | |
| **/
 | |
| EFI_DEVICE_PATH_PROTOCOL *
 | |
| SmmFvToDevicePath (
 | |
|   IN  EFI_FIRMWARE_VOLUME2_PROTOCOL   *Fv,
 | |
|   IN  EFI_HANDLE                      FvHandle,
 | |
|   IN  EFI_GUID                        *DriverName
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                          Status;
 | |
|   EFI_DEVICE_PATH_PROTOCOL            *FvDevicePath;
 | |
|   EFI_DEVICE_PATH_PROTOCOL            *FileNameDevicePath;
 | |
| 
 | |
|   //
 | |
|   // Remember the device path of the FV
 | |
|   //
 | |
|   Status = gBS->HandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     FileNameDevicePath = NULL;
 | |
|   } else {
 | |
|     //
 | |
|     // Build a device path to the file in the FV to pass into gBS->LoadImage
 | |
|     //
 | |
|     EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, DriverName);
 | |
|     SetDevicePathEndNode (&mFvDevicePath.End);
 | |
| 
 | |
|     //
 | |
|     // Note: FileNameDevicePath is in DXE memory
 | |
|     //
 | |
|     FileNameDevicePath = AppendDevicePath (
 | |
|                             FvDevicePath,
 | |
|                             (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath
 | |
|                             );
 | |
|   }
 | |
|   return FileNameDevicePath;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
 | |
|   and initilize any state variables. Read the Depex from the FV and store it
 | |
|   in DriverEntry. Pre-process the Depex to set the Before and After state.
 | |
|   The Discovered list is never free'ed and contains booleans that represent the
 | |
|   other possible SMM driver states.
 | |
| 
 | |
|   @param  Fv                    Fv protocol, needed to read Depex info out of
 | |
|                                 FLASH.
 | |
|   @param  FvHandle              Handle for Fv, needed in the
 | |
|                                 EFI_SMM_DRIVER_ENTRY so that the PE image can be
 | |
|                                 read out of the FV at a later time.
 | |
|   @param  DriverName            Name of driver to add to mDiscoveredList.
 | |
| 
 | |
|   @retval EFI_SUCCESS           If driver was added to the mDiscoveredList.
 | |
|   @retval EFI_ALREADY_STARTED   The driver has already been started. Only one
 | |
|                                 DriverName may be active in the system at any one
 | |
|                                 time.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| SmmAddToDriverList (
 | |
|   IN EFI_FIRMWARE_VOLUME2_PROTOCOL  *Fv,
 | |
|   IN EFI_HANDLE                     FvHandle,
 | |
|   IN EFI_GUID                       *DriverName
 | |
|   )
 | |
| {
 | |
|   EFI_SMM_DRIVER_ENTRY  *DriverEntry;
 | |
| 
 | |
|   //
 | |
|   // Create the Driver Entry for the list. ZeroPool initializes lots of variables to
 | |
|   // NULL or FALSE.
 | |
|   //
 | |
|   DriverEntry = AllocateZeroPool (sizeof (EFI_SMM_DRIVER_ENTRY));
 | |
|   ASSERT (DriverEntry != NULL);
 | |
| 
 | |
|   DriverEntry->Signature        = EFI_SMM_DRIVER_ENTRY_SIGNATURE;
 | |
|   CopyGuid (&DriverEntry->FileName, DriverName);
 | |
|   DriverEntry->FvHandle         = FvHandle;
 | |
|   DriverEntry->Fv               = Fv;
 | |
|   DriverEntry->FvFileDevicePath = SmmFvToDevicePath (Fv, FvHandle, DriverName);
 | |
| 
 | |
|   SmmGetDepexSectionAndPreProccess (DriverEntry);
 | |
| 
 | |
|   InsertTailList (&mDiscoveredList, &DriverEntry->Link);
 | |
|   gRequestDispatch = TRUE;
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This function is the main entry point for an SMM handler dispatch
 | |
|   or communicate-based callback.
 | |
| 
 | |
|   Event notification that is fired every time a FV dispatch protocol is added.
 | |
|   More than one protocol may have been added when this event is fired, so you
 | |
|   must loop on SmmLocateHandle () to see how many protocols were added and
 | |
|   do the following to each FV:
 | |
|   If the Fv has already been processed, skip it. If the Fv has not been
 | |
|   processed then mark it as being processed, as we are about to process it.
 | |
|   Read the Fv and add any driver in the Fv to the mDiscoveredList.The
 | |
|   mDiscoveredList is never free'ed and contains variables that define
 | |
|   the other states the SMM driver transitions to..
 | |
|   While you are at it read the A Priori file into memory.
 | |
|   Place drivers in the A Priori list onto the mScheduledQueue.
 | |
| 
 | |
|   @param  DispatchHandle  The unique handle assigned to this handler by SmiHandlerRegister().
 | |
|   @param  Context         Points to an optional handler context which was specified when the handler was registered.
 | |
|   @param  CommBuffer      A pointer to a collection of data in memory that will
 | |
|                           be conveyed from a non-SMM environment into an SMM environment.
 | |
|   @param  CommBufferSize  The size of the CommBuffer.
 | |
| 
 | |
|   @return Status Code
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| SmmDriverDispatchHandler (
 | |
|   IN     EFI_HANDLE  DispatchHandle,
 | |
|   IN     CONST VOID  *Context,        OPTIONAL
 | |
|   IN OUT VOID        *CommBuffer,     OPTIONAL
 | |
|   IN OUT UINTN       *CommBufferSize  OPTIONAL
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                    Status;
 | |
|   UINTN                         HandleCount;
 | |
|   EFI_HANDLE                    *HandleBuffer;
 | |
|   EFI_STATUS                    GetNextFileStatus;
 | |
|   EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
 | |
|   EFI_DEVICE_PATH_PROTOCOL      *FvDevicePath;
 | |
|   EFI_HANDLE                    FvHandle;
 | |
|   EFI_GUID                      NameGuid;
 | |
|   UINTN                         Key;
 | |
|   EFI_FV_FILETYPE               Type;
 | |
|   EFI_FV_FILE_ATTRIBUTES        Attributes;
 | |
|   UINTN                         Size;
 | |
|   EFI_SMM_DRIVER_ENTRY          *DriverEntry;
 | |
|   EFI_GUID                      *AprioriFile;
 | |
|   UINTN                         AprioriEntryCount;
 | |
|   UINTN                         HandleIndex;
 | |
|   UINTN                         SmmTypeIndex;
 | |
|   UINTN                         AprioriIndex;
 | |
|   LIST_ENTRY                    *Link;
 | |
|   UINT32                        AuthenticationStatus;
 | |
|   UINTN                         SizeOfBuffer;
 | |
| 
 | |
|   HandleBuffer = NULL;
 | |
|   Status = gBS->LocateHandleBuffer (
 | |
|                   ByProtocol,
 | |
|                   &gEfiFirmwareVolume2ProtocolGuid,
 | |
|                   NULL,
 | |
|                   &HandleCount,
 | |
|                   &HandleBuffer
 | |
|                   );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return EFI_NOT_FOUND;
 | |
|   }
 | |
| 
 | |
|   for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
 | |
|     FvHandle = HandleBuffer[HandleIndex];
 | |
| 
 | |
|     if (FvHasBeenProcessed (FvHandle)) {
 | |
|       //
 | |
|       // This Fv has already been processed so lets skip it!
 | |
|       //
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Since we are about to process this Fv mark it as processed.
 | |
|     //
 | |
|     FvIsBeingProcesssed (FvHandle);
 | |
| 
 | |
|     Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // FvHandle must have a Firmware Volume2 Protocol thus we should never get here.
 | |
|       //
 | |
|       ASSERT (FALSE);
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     Status = gBS->HandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // The Firmware volume doesn't have device path, can't be dispatched.
 | |
|       //
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Discover Drivers in FV and add them to the Discovered Driver List.
 | |
|     // Process EFI_FV_FILETYPE_SMM type and then EFI_FV_FILETYPE_COMBINED_SMM_DXE
 | |
|     //  EFI_FV_FILETYPE_SMM_CORE is processed to produce a Loaded Image protocol for the core
 | |
|     //
 | |
|     for (SmmTypeIndex = 0; SmmTypeIndex < sizeof (mSmmFileTypes)/sizeof (EFI_FV_FILETYPE); SmmTypeIndex++) {
 | |
|       //
 | |
|       // Initialize the search key
 | |
|       //
 | |
|       Key = 0;
 | |
|       do {
 | |
|         Type = mSmmFileTypes[SmmTypeIndex];
 | |
|         GetNextFileStatus = Fv->GetNextFile (
 | |
|                                   Fv,
 | |
|                                   &Key,
 | |
|                                   &Type,
 | |
|                                   &NameGuid,
 | |
|                                   &Attributes,
 | |
|                                   &Size
 | |
|                                   );
 | |
|         if (!EFI_ERROR (GetNextFileStatus)) {
 | |
|           if (Type == EFI_FV_FILETYPE_SMM_CORE) {
 | |
|             //
 | |
|             // If this is the SMM core fill in it's DevicePath & DeviceHandle
 | |
|             //
 | |
|             if (mSmmCoreLoadedImage->FilePath == NULL) {
 | |
|               //
 | |
|               // Maybe one special FV contains only one SMM_CORE module, so its device path must
 | |
|               // be initialized completely.
 | |
|               //
 | |
|               EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid);
 | |
|               SetDevicePathEndNode (&mFvDevicePath.End);
 | |
| 
 | |
|               //
 | |
|               // Make an EfiBootServicesData buffer copy of FilePath
 | |
|               //
 | |
|               Status = gBS->AllocatePool (
 | |
|                               EfiBootServicesData,
 | |
|                               GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath),
 | |
|                               (VOID **)&mSmmCoreLoadedImage->FilePath
 | |
|                               );
 | |
|               ASSERT_EFI_ERROR (Status);
 | |
|               CopyMem (mSmmCoreLoadedImage->FilePath, &mFvDevicePath, GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath));
 | |
| 
 | |
|               mSmmCoreLoadedImage->DeviceHandle = FvHandle;
 | |
|             }
 | |
|             if (mSmmCoreDriverEntry->SmmLoadedImage.FilePath == NULL) {
 | |
|               //
 | |
|               // Maybe one special FV contains only one SMM_CORE module, so its device path must
 | |
|               // be initialized completely.
 | |
|               //
 | |
|               EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid);
 | |
|               SetDevicePathEndNode (&mFvDevicePath.End);
 | |
| 
 | |
|               //
 | |
|               // Make a buffer copy FilePath
 | |
|               //
 | |
|               Status = SmmAllocatePool (
 | |
|                          EfiRuntimeServicesData,
 | |
|                          GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath),
 | |
|                          (VOID **)&mSmmCoreDriverEntry->SmmLoadedImage.FilePath
 | |
|                          );
 | |
|               ASSERT_EFI_ERROR (Status);
 | |
|               CopyMem (mSmmCoreDriverEntry->SmmLoadedImage.FilePath, &mFvDevicePath, GetDevicePathSize((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath));
 | |
| 
 | |
|               mSmmCoreDriverEntry->SmmLoadedImage.DeviceHandle = FvHandle;
 | |
|             }
 | |
|           } else {
 | |
|             SmmAddToDriverList (Fv, FvHandle, &NameGuid);
 | |
|           }
 | |
|         }
 | |
|       } while (!EFI_ERROR (GetNextFileStatus));
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Read the array of GUIDs from the Apriori file if it is present in the firmware volume
 | |
|     // (Note: AprioriFile is in DXE memory)
 | |
|     //
 | |
|     AprioriFile = NULL;
 | |
|     Status = Fv->ReadSection (
 | |
|                   Fv,
 | |
|                   &gAprioriGuid,
 | |
|                   EFI_SECTION_RAW,
 | |
|                   0,
 | |
|                   (VOID **)&AprioriFile,
 | |
|                   &SizeOfBuffer,
 | |
|                   &AuthenticationStatus
 | |
|                   );
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       AprioriEntryCount = SizeOfBuffer / sizeof (EFI_GUID);
 | |
|     } else {
 | |
|       AprioriEntryCount = 0;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Put drivers on Apriori List on the Scheduled queue. The Discovered List includes
 | |
|     // drivers not in the current FV and these must be skipped since the a priori list
 | |
|     // is only valid for the FV that it resided in.
 | |
|     //
 | |
| 
 | |
|     for (AprioriIndex = 0; AprioriIndex < AprioriEntryCount; AprioriIndex++) {
 | |
|       for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
 | |
|         DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
 | |
|         if (CompareGuid (&DriverEntry->FileName, &AprioriFile[AprioriIndex]) &&
 | |
|             (FvHandle == DriverEntry->FvHandle)) {
 | |
|           DriverEntry->Dependent = FALSE;
 | |
|           DriverEntry->Scheduled = TRUE;
 | |
|           InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);
 | |
|           DEBUG ((DEBUG_DISPATCH, "Evaluate SMM DEPEX for FFS(%g)\n", &DriverEntry->FileName));
 | |
|           DEBUG ((DEBUG_DISPATCH, "  RESULT = TRUE (Apriori)\n"));
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Free data allocated by Fv->ReadSection ()
 | |
|     //
 | |
|     // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection
 | |
|     // used the UEFI Boot Services AllocatePool() function
 | |
|     //
 | |
|     gBS->FreePool (AprioriFile);
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Execute the SMM Dispatcher on any newly discovered FVs and previously
 | |
|   // discovered SMM drivers that have been discovered but not dispatched.
 | |
|   //
 | |
|   Status = SmmDispatcher ();
 | |
| 
 | |
|   //
 | |
|   // Check to see if CommBuffer and CommBufferSize are valid
 | |
|   //
 | |
|   if (CommBuffer != NULL && CommBufferSize != NULL) {
 | |
|     if (*CommBufferSize > 0) {
 | |
|       if (Status == EFI_NOT_READY) {
 | |
|         //
 | |
|         // If a the SMM Core Entry Point was just registered, then set flag to
 | |
|         // request the SMM Dispatcher to be restarted.
 | |
|         //
 | |
|         *(UINT8 *)CommBuffer = COMM_BUFFER_SMM_DISPATCH_RESTART;
 | |
|       } else if (!EFI_ERROR (Status)) {
 | |
|         //
 | |
|         // Set the flag to show that the SMM Dispatcher executed without errors
 | |
|         //
 | |
|         *(UINT8 *)CommBuffer = COMM_BUFFER_SMM_DISPATCH_SUCCESS;
 | |
|       } else {
 | |
|         //
 | |
|         // Set the flag to show that the SMM Dispatcher encountered an error
 | |
|         //
 | |
|         *(UINT8 *)CommBuffer = COMM_BUFFER_SMM_DISPATCH_ERROR;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Traverse the discovered list for any drivers that were discovered but not loaded
 | |
|   because the dependency experessions evaluated to false.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| SmmDisplayDiscoveredNotDispatched (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY                   *Link;
 | |
|   EFI_SMM_DRIVER_ENTRY         *DriverEntry;
 | |
| 
 | |
|   for (Link = mDiscoveredList.ForwardLink;Link !=&mDiscoveredList; Link = Link->ForwardLink) {
 | |
|     DriverEntry = CR(Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
 | |
|     if (DriverEntry->Dependent) {
 | |
|       DEBUG ((DEBUG_LOAD, "SMM Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName));
 | |
|     }
 | |
|   }
 | |
| }
 |