REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the MdeModulePkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Liming Gao <gaoliming@byosoft.com.cn>
		
			
				
	
	
		
			1537 lines
		
	
	
		
			52 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1537 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
 | 
						|
            processes the After dependencies 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 Expression.
 | 
						|
 | 
						|
  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 Dispatcher.  TRUE if dispatcher is executing.
 | 
						|
//
 | 
						|
BOOLEAN  gDispatcherRunning = FALSE;
 | 
						|
 | 
						|
//
 | 
						|
// Flag for the SMM Dispatcher.  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 available 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 ((DEBUG_INFO|DEBUG_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 already 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 ((DEBUG_INFO|DEBUG_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 redundant 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 preprocessed
 | 
						|
  @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)) {
 | 
						|
        DEBUG ((
 | 
						|
          DEBUG_ERROR,
 | 
						|
          "Error: SMM image at %11p start failed: %r\n",
 | 
						|
          DriverEntry->SmmLoadedImage.ImageBase,
 | 
						|
          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 its drivers placed on the
 | 
						|
  mDiscoveredList. This function 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
 | 
						|
FvIsBeingProcessed (
 | 
						|
  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 initialize 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.
 | 
						|
    //
 | 
						|
    FvIsBeingProcessed (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 expressions 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));
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 |