__FUNCTION__ is a pre-standard extension that gcc and Visual C++ among others support, while __func__ was standardized in C99. Since it's more standard, replace __FUNCTION__ with __func__ throughout MdeModulePkg. Signed-off-by: Rebecca Cran <rebecca@bsdio.com> Reviewed-by: Michael D Kinney <michael.d.kinney@intel.com> Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
		
			
				
	
	
		
			1485 lines
		
	
	
		
			50 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			1485 lines
		
	
	
		
			50 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /** @file
 | |
|   DXE Dispatcher.
 | |
| 
 | |
|   Step #1 - When a FV protocol is added to the system every driver in the FV
 | |
|             is added to the mDiscoveredList. The SOR, 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 in chapter 10 of the DXE CIS. Figure 10-3
 | |
|   is the state diagram for the DXE dispatcher
 | |
| 
 | |
|   Depex - Dependency Expresion.
 | |
|   SOR   - Schedule On Request - Don't schedule if this bit is set.
 | |
| 
 | |
| Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
 | |
| SPDX-License-Identifier: BSD-2-Clause-Patent
 | |
| 
 | |
| **/
 | |
| 
 | |
| #include "DxeMain.h"
 | |
| 
 | |
| //
 | |
| // The Driver List contains one copy of every driver that has been discovered.
 | |
| // Items are never removed from the driver list. List of EFI_CORE_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_CORE_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);           // list of KNOWN_HANDLE
 | |
| 
 | |
| //
 | |
| // Lock for mDiscoveredList, mScheduledQueue, gDispatcherRunning.
 | |
| //
 | |
| EFI_LOCK  mDispatcherLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);
 | |
| 
 | |
| //
 | |
| // Flag for the DXE Dispacher.  TRUE if dispatcher is execuing.
 | |
| //
 | |
| BOOLEAN  gDispatcherRunning = FALSE;
 | |
| 
 | |
| //
 | |
| // Module globals to manage the FwVol registration notification event
 | |
| //
 | |
| EFI_EVENT  mFwVolEvent;
 | |
| VOID       *mFwVolEventRegistration;
 | |
| 
 | |
| //
 | |
| // List of file types supported by dispatcher
 | |
| //
 | |
| EFI_FV_FILETYPE  mDxeFileTypes[] = {
 | |
|   EFI_FV_FILETYPE_DRIVER,
 | |
|   EFI_FV_FILETYPE_COMBINED_SMM_DXE,
 | |
|   EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,
 | |
|   EFI_FV_FILETYPE_DXE_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;
 | |
| 
 | |
| //
 | |
| // 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
 | |
| CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
 | |
|   IN  EFI_CORE_DRIVER_ENTRY  *InsertedDriverEntry
 | |
|   );
 | |
| 
 | |
| /**
 | |
|   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 CoreLocateHandle () 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 DXE 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  Event                 The Event that is being processed, not used.
 | |
|   @param  Context               Event Context, not used.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| CoreFwVolEventProtocolNotify (
 | |
|   IN  EFI_EVENT  Event,
 | |
|   IN  VOID       *Context
 | |
|   );
 | |
| 
 | |
| /**
 | |
|   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_CORE_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 *
 | |
| CoreFvToDevicePath (
 | |
|   IN  EFI_FIRMWARE_VOLUME2_PROTOCOL  *Fv,
 | |
|   IN  EFI_HANDLE                     FvHandle,
 | |
|   IN  EFI_GUID                       *DriverName
 | |
|   );
 | |
| 
 | |
| /**
 | |
|   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 SOR, Before and After state.
 | |
|   The Discovered list is never free'ed and contains booleans that represent the
 | |
|   other possible DXE driver states.
 | |
| 
 | |
|   @param  Fv                    Fv protocol, needed to read Depex info out of
 | |
|                                 FLASH.
 | |
|   @param  FvHandle              Handle for Fv, needed in the
 | |
|                                 EFI_CORE_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.
 | |
|   @param  Type                  Fv File Type of file 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
 | |
| CoreAddToDriverList (
 | |
|   IN  EFI_FIRMWARE_VOLUME2_PROTOCOL  *Fv,
 | |
|   IN  EFI_HANDLE                     FvHandle,
 | |
|   IN  EFI_GUID                       *DriverName,
 | |
|   IN  EFI_FV_FILETYPE                Type
 | |
|   );
 | |
| 
 | |
| /**
 | |
|   Get Fv image(s) from the FV through file name, and produce FVB protocol for every Fv image(s).
 | |
| 
 | |
|   @param  Fv                    The FIRMWARE_VOLUME protocol installed on the FV.
 | |
|   @param  FvHandle              The handle which FVB protocol installed on.
 | |
|   @param  FileName              The file name guid specified.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES  No enough memory or other resource.
 | |
|   @retval EFI_SUCCESS           Function successfully returned.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| CoreProcessFvImageFile (
 | |
|   IN  EFI_FIRMWARE_VOLUME2_PROTOCOL  *Fv,
 | |
|   IN  EFI_HANDLE                     FvHandle,
 | |
|   IN  EFI_GUID                       *FileName
 | |
|   );
 | |
| 
 | |
| /**
 | |
|   Enter critical section by gaining lock on mDispatcherLock.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| CoreAcquireDispatcherLock (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   CoreAcquireLock (&mDispatcherLock);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Exit critical section by releasing lock on mDispatcherLock.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| CoreReleaseDispatcherLock (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   CoreReleaseLock (&mDispatcherLock);
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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
 | |
| CoreGetDepexSectionAndPreProccess (
 | |
|   IN  EFI_CORE_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.
 | |
|   //
 | |
|   SectionType = EFI_SECTION_DXE_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 UEFI 2.0 driver model
 | |
|       //
 | |
|       DriverEntry->Depex              = NULL;
 | |
|       DriverEntry->Dependent          = TRUE;
 | |
|       DriverEntry->DepexProtocolError = FALSE;
 | |
|     }
 | |
|   } else {
 | |
|     //
 | |
|     // Set Before, After, and Unrequested state information based on Depex
 | |
|     // Driver will be put in Dependent or Unrequested state
 | |
|     //
 | |
|     CorePreProcessDepex (DriverEntry);
 | |
|     DriverEntry->DepexProtocolError = FALSE;
 | |
|   }
 | |
| 
 | |
|   return Status;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check every driver and locate a matching one. If the driver is found, the Unrequested
 | |
|   state flag is cleared.
 | |
| 
 | |
|   @param  FirmwareVolumeHandle  The handle of the Firmware Volume that contains
 | |
|                                 the firmware  file specified by DriverName.
 | |
|   @param  DriverName            The Driver name to put in the Dependent state.
 | |
| 
 | |
|   @retval EFI_SUCCESS           The DriverName was found and it's SOR bit was
 | |
|                                 cleared
 | |
|   @retval EFI_NOT_FOUND         The DriverName does not exist or it's SOR bit was
 | |
|                                 not set.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| CoreSchedule (
 | |
|   IN  EFI_HANDLE  FirmwareVolumeHandle,
 | |
|   IN  EFI_GUID    *DriverName
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY             *Link;
 | |
|   EFI_CORE_DRIVER_ENTRY  *DriverEntry;
 | |
| 
 | |
|   //
 | |
|   // Check every driver
 | |
|   //
 | |
|   for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
 | |
|     DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
 | |
|     if ((DriverEntry->FvHandle == FirmwareVolumeHandle) &&
 | |
|         DriverEntry->Unrequested &&
 | |
|         CompareGuid (DriverName, &DriverEntry->FileName))
 | |
|     {
 | |
|       //
 | |
|       // Move the driver from the Unrequested to the Dependent state
 | |
|       //
 | |
|       CoreAcquireDispatcherLock ();
 | |
|       DriverEntry->Unrequested = FALSE;
 | |
|       DriverEntry->Dependent   = TRUE;
 | |
|       CoreReleaseDispatcherLock ();
 | |
| 
 | |
|       DEBUG ((DEBUG_DISPATCH, "Schedule FFS(%g) - EFI_SUCCESS\n", DriverName));
 | |
| 
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   DEBUG ((DEBUG_DISPATCH, "Schedule FFS(%g) - EFI_NOT_FOUND\n", DriverName));
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Convert a driver from the Untrused back to the Scheduled state.
 | |
| 
 | |
|   @param  FirmwareVolumeHandle  The handle of the Firmware Volume that contains
 | |
|                                 the firmware  file specified by DriverName.
 | |
|   @param  DriverName            The Driver name to put in the Scheduled state
 | |
| 
 | |
|   @retval EFI_SUCCESS           The file was found in the untrusted state, and it
 | |
|                                 was promoted  to the trusted state.
 | |
|   @retval EFI_NOT_FOUND         The file was not found in the untrusted state.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| CoreTrust (
 | |
|   IN  EFI_HANDLE  FirmwareVolumeHandle,
 | |
|   IN  EFI_GUID    *DriverName
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY             *Link;
 | |
|   EFI_CORE_DRIVER_ENTRY  *DriverEntry;
 | |
| 
 | |
|   //
 | |
|   // Check every driver
 | |
|   //
 | |
|   for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
 | |
|     DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
 | |
|     if ((DriverEntry->FvHandle == FirmwareVolumeHandle) &&
 | |
|         DriverEntry->Untrusted &&
 | |
|         CompareGuid (DriverName, &DriverEntry->FileName))
 | |
|     {
 | |
|       //
 | |
|       // Transition driver from Untrusted to Scheduled state.
 | |
|       //
 | |
|       CoreAcquireDispatcherLock ();
 | |
|       DriverEntry->Untrusted = FALSE;
 | |
|       DriverEntry->Scheduled = TRUE;
 | |
|       InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);
 | |
|       CoreReleaseDispatcherLock ();
 | |
| 
 | |
|       return EFI_SUCCESS;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return EFI_NOT_FOUND;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   This is the main Dispatcher for DXE 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. On exit it is assumed the Bds()
 | |
|   will be called, and when the Bds() exits the Dispatcher will be called
 | |
|   again.
 | |
| 
 | |
|   @retval EFI_ALREADY_STARTED   The DXE Dispatcher is already running
 | |
|   @retval EFI_NOT_FOUND         No DXE Drivers were dispatched
 | |
|   @retval EFI_SUCCESS           One or more DXE Drivers were dispatched
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| EFIAPI
 | |
| CoreDispatcher (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS             Status;
 | |
|   EFI_STATUS             ReturnStatus;
 | |
|   LIST_ENTRY             *Link;
 | |
|   EFI_CORE_DRIVER_ENTRY  *DriverEntry;
 | |
|   BOOLEAN                ReadyToRun;
 | |
|   EFI_EVENT              DxeDispatchEvent;
 | |
| 
 | |
|   PERF_FUNCTION_BEGIN ();
 | |
| 
 | |
|   if (gDispatcherRunning) {
 | |
|     //
 | |
|     // If the dispatcher is running don't let it be restarted.
 | |
|     //
 | |
|     return EFI_ALREADY_STARTED;
 | |
|   }
 | |
| 
 | |
|   gDispatcherRunning = TRUE;
 | |
| 
 | |
|   Status = CoreCreateEventEx (
 | |
|              EVT_NOTIFY_SIGNAL,
 | |
|              TPL_NOTIFY,
 | |
|              EfiEventEmptyFunction,
 | |
|              NULL,
 | |
|              &gEfiEventDxeDispatchGuid,
 | |
|              &DxeDispatchEvent
 | |
|              );
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   ReturnStatus = EFI_NOT_FOUND;
 | |
|   do {
 | |
|     //
 | |
|     // Drain the Scheduled Queue
 | |
|     //
 | |
|     while (!IsListEmpty (&mScheduledQueue)) {
 | |
|       DriverEntry = CR (
 | |
|                       mScheduledQueue.ForwardLink,
 | |
|                       EFI_CORE_DRIVER_ENTRY,
 | |
|                       ScheduledLink,
 | |
|                       EFI_CORE_DRIVER_ENTRY_SIGNATURE
 | |
|                       );
 | |
| 
 | |
|       //
 | |
|       // Load the DXE 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) && !DriverEntry->IsFvImage) {
 | |
|         DEBUG ((DEBUG_INFO, "Loading driver %g\n", &DriverEntry->FileName));
 | |
|         Status = CoreLoadImage (
 | |
|                    FALSE,
 | |
|                    gDxeCoreImageHandle,
 | |
|                    DriverEntry->FvFileDevicePath,
 | |
|                    NULL,
 | |
|                    0,
 | |
|                    &DriverEntry->ImageHandle
 | |
|                    );
 | |
| 
 | |
|         //
 | |
|         // Update the driver state to reflect that it's been loaded
 | |
|         //
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           CoreAcquireDispatcherLock ();
 | |
| 
 | |
|           if (Status == EFI_SECURITY_VIOLATION) {
 | |
|             //
 | |
|             // Take driver from Scheduled to Untrused state
 | |
|             //
 | |
|             DriverEntry->Untrusted = TRUE;
 | |
|           } else {
 | |
|             //
 | |
|             // The DXE Driver could not be loaded, and do not attempt to load or start it again.
 | |
|             // Take driver from Scheduled to Initialized.
 | |
|             //
 | |
|             // This case include the Never Trusted state if EFI_ACCESS_DENIED is returned
 | |
|             //
 | |
|             DriverEntry->Initialized = TRUE;
 | |
|           }
 | |
| 
 | |
|           DriverEntry->Scheduled = FALSE;
 | |
|           RemoveEntryList (&DriverEntry->ScheduledLink);
 | |
| 
 | |
|           CoreReleaseDispatcherLock ();
 | |
| 
 | |
|           //
 | |
|           // If it's an error don't try the StartImage
 | |
|           //
 | |
|           continue;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       CoreAcquireDispatcherLock ();
 | |
| 
 | |
|       DriverEntry->Scheduled   = FALSE;
 | |
|       DriverEntry->Initialized = TRUE;
 | |
|       RemoveEntryList (&DriverEntry->ScheduledLink);
 | |
| 
 | |
|       CoreReleaseDispatcherLock ();
 | |
| 
 | |
|       if (DriverEntry->IsFvImage) {
 | |
|         //
 | |
|         // Produce a firmware volume block protocol for FvImage so it gets dispatched from.
 | |
|         //
 | |
|         Status = CoreProcessFvImageFile (DriverEntry->Fv, DriverEntry->FvHandle, &DriverEntry->FileName);
 | |
|       } else {
 | |
|         REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
 | |
|           EFI_PROGRESS_CODE,
 | |
|           (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_BEGIN),
 | |
|           &DriverEntry->ImageHandle,
 | |
|           sizeof (DriverEntry->ImageHandle)
 | |
|           );
 | |
|         ASSERT (DriverEntry->ImageHandle != NULL);
 | |
| 
 | |
|         Status = CoreStartImage (DriverEntry->ImageHandle, NULL, NULL);
 | |
| 
 | |
|         REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
 | |
|           EFI_PROGRESS_CODE,
 | |
|           (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_END),
 | |
|           &DriverEntry->ImageHandle,
 | |
|           sizeof (DriverEntry->ImageHandle)
 | |
|           );
 | |
|       }
 | |
| 
 | |
|       ReturnStatus = EFI_SUCCESS;
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Now DXE Dispatcher finished one round of dispatch, signal an event group
 | |
|     // so that SMM Dispatcher get chance to dispatch SMM Drivers which depend
 | |
|     // on UEFI protocols
 | |
|     //
 | |
|     if (!EFI_ERROR (ReturnStatus)) {
 | |
|       CoreSignalEvent (DxeDispatchEvent);
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Search DriverList for items to place on Scheduled Queue
 | |
|     //
 | |
|     ReadyToRun = FALSE;
 | |
|     for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
 | |
|       DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
 | |
| 
 | |
|       if (DriverEntry->DepexProtocolError) {
 | |
|         //
 | |
|         // If Section Extraction Protocol did not let the Depex be read before retry the read
 | |
|         //
 | |
|         Status = CoreGetDepexSectionAndPreProccess (DriverEntry);
 | |
|       }
 | |
| 
 | |
|       if (DriverEntry->Dependent) {
 | |
|         if (CoreIsSchedulable (DriverEntry)) {
 | |
|           CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
 | |
|           ReadyToRun = TRUE;
 | |
|         }
 | |
|       } else {
 | |
|         if (DriverEntry->Unrequested) {
 | |
|           DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
 | |
|           DEBUG ((DEBUG_DISPATCH, "  SOR                                             = Not Requested\n"));
 | |
|           DEBUG ((DEBUG_DISPATCH, "  RESULT = FALSE\n"));
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   } while (ReadyToRun);
 | |
| 
 | |
|   //
 | |
|   // Close DXE dispatch Event
 | |
|   //
 | |
|   CoreCloseEvent (DxeDispatchEvent);
 | |
| 
 | |
|   gDispatcherRunning = FALSE;
 | |
| 
 | |
|   PERF_FUNCTION_END ();
 | |
| 
 | |
|   return ReturnStatus;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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
 | |
| CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
 | |
|   IN  EFI_CORE_DRIVER_ENTRY  *InsertedDriverEntry
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY             *Link;
 | |
|   EFI_CORE_DRIVER_ENTRY  *DriverEntry;
 | |
| 
 | |
|   //
 | |
|   // Process Before Dependency
 | |
|   //
 | |
|   for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
 | |
|     DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
 | |
|     if (DriverEntry->Before && DriverEntry->Dependent && (DriverEntry != InsertedDriverEntry)) {
 | |
|       DEBUG ((DEBUG_DISPATCH, "Evaluate DXE 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"));
 | |
|         CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
 | |
|       } else {
 | |
|         DEBUG ((DEBUG_DISPATCH, "FALSE\n  END\n  RESULT = FALSE\n"));
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // Convert driver from Dependent to Scheduled state
 | |
|   //
 | |
|   CoreAcquireDispatcherLock ();
 | |
| 
 | |
|   InsertedDriverEntry->Dependent = FALSE;
 | |
|   InsertedDriverEntry->Scheduled = TRUE;
 | |
|   InsertTailList (&mScheduledQueue, &InsertedDriverEntry->ScheduledLink);
 | |
| 
 | |
|   CoreReleaseDispatcherLock ();
 | |
| 
 | |
|   //
 | |
|   // Process After Dependency
 | |
|   //
 | |
|   for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
 | |
|     DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
 | |
|     if (DriverEntry->After && DriverEntry->Dependent && (DriverEntry != InsertedDriverEntry)) {
 | |
|       DEBUG ((DEBUG_DISPATCH, "Evaluate DXE 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"));
 | |
|         CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (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 if new
 | |
|   entry is different from one in mFvHandleList by checking FvImage Guid.
 | |
|   Items are never removed/freed from the mFvHandleList.
 | |
| 
 | |
|   @param  FvHandle              The handle of a FV that has been processed
 | |
| 
 | |
|   @return A point to new added FvHandle entry. If FvHandle with the same FvImage guid
 | |
|           has been added, NULL will return.
 | |
| 
 | |
| **/
 | |
| KNOWN_HANDLE *
 | |
| FvIsBeingProcessed (
 | |
|   IN  EFI_HANDLE  FvHandle
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                          Status;
 | |
|   EFI_GUID                            FvNameGuid;
 | |
|   BOOLEAN                             FvNameGuidIsFound;
 | |
|   UINT32                              ExtHeaderOffset;
 | |
|   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;
 | |
|   EFI_FIRMWARE_VOLUME_HEADER          *FwVolHeader;
 | |
|   EFI_FV_BLOCK_MAP_ENTRY              *BlockMap;
 | |
|   UINTN                               LbaOffset;
 | |
|   UINTN                               Index;
 | |
|   EFI_LBA                             LbaIndex;
 | |
|   LIST_ENTRY                          *Link;
 | |
|   KNOWN_HANDLE                        *KnownHandle;
 | |
| 
 | |
|   FwVolHeader = NULL;
 | |
| 
 | |
|   //
 | |
|   // Get the FirmwareVolumeBlock protocol on that handle
 | |
|   //
 | |
|   FvNameGuidIsFound = FALSE;
 | |
|   Status            = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);
 | |
|   if (!EFI_ERROR (Status)) {
 | |
|     //
 | |
|     // Get the full FV header based on FVB protocol.
 | |
|     //
 | |
|     ASSERT (Fvb != NULL);
 | |
|     Status = GetFwVolHeader (Fvb, &FwVolHeader);
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       ASSERT (FwVolHeader != NULL);
 | |
|       if (VerifyFvHeaderChecksum (FwVolHeader) && (FwVolHeader->ExtHeaderOffset != 0)) {
 | |
|         ExtHeaderOffset = (UINT32)FwVolHeader->ExtHeaderOffset;
 | |
|         BlockMap        = FwVolHeader->BlockMap;
 | |
|         LbaIndex        = 0;
 | |
|         LbaOffset       = 0;
 | |
|         //
 | |
|         // Find LbaIndex and LbaOffset for FV extension header based on BlockMap.
 | |
|         //
 | |
|         while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {
 | |
|           for (Index = 0; Index < BlockMap->NumBlocks && ExtHeaderOffset >= BlockMap->Length; Index++) {
 | |
|             ExtHeaderOffset -= BlockMap->Length;
 | |
|             LbaIndex++;
 | |
|           }
 | |
| 
 | |
|           //
 | |
|           // Check whether FvExtHeader is crossing the multi block range.
 | |
|           //
 | |
|           if (Index < BlockMap->NumBlocks) {
 | |
|             LbaOffset = ExtHeaderOffset;
 | |
|             break;
 | |
|           }
 | |
| 
 | |
|           BlockMap++;
 | |
|         }
 | |
| 
 | |
|         //
 | |
|         // Read FvNameGuid from FV extension header.
 | |
|         //
 | |
|         Status = ReadFvbData (Fvb, &LbaIndex, &LbaOffset, sizeof (FvNameGuid), (UINT8 *)&FvNameGuid);
 | |
|         if (!EFI_ERROR (Status)) {
 | |
|           FvNameGuidIsFound = TRUE;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       CoreFreePool (FwVolHeader);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   if (FvNameGuidIsFound) {
 | |
|     //
 | |
|     // Check whether the FV image with the found FvNameGuid has been processed.
 | |
|     //
 | |
|     for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) {
 | |
|       KnownHandle = CR (Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE);
 | |
|       if (CompareGuid (&FvNameGuid, &KnownHandle->FvNameGuid)) {
 | |
|         DEBUG ((DEBUG_ERROR, "FvImage on FvHandle %p and %p has the same FvNameGuid %g.\n", FvHandle, KnownHandle->Handle, &FvNameGuid));
 | |
|         return NULL;
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   KnownHandle = AllocateZeroPool (sizeof (KNOWN_HANDLE));
 | |
|   ASSERT (KnownHandle != NULL);
 | |
| 
 | |
|   KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE;
 | |
|   KnownHandle->Handle    = FvHandle;
 | |
|   if (FvNameGuidIsFound) {
 | |
|     CopyGuid (&KnownHandle->FvNameGuid, &FvNameGuid);
 | |
|   }
 | |
| 
 | |
|   InsertTailList (&mFvHandleList, &KnownHandle->Link);
 | |
|   return KnownHandle;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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_CORE_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 *
 | |
| CoreFvToDevicePath (
 | |
|   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 = CoreHandleProtocol (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);
 | |
| 
 | |
|     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 SOR, Before and After state.
 | |
|   The Discovered list is never free'ed and contains booleans that represent the
 | |
|   other possible DXE driver states.
 | |
| 
 | |
|   @param  Fv                    Fv protocol, needed to read Depex info out of
 | |
|                                 FLASH.
 | |
|   @param  FvHandle              Handle for Fv, needed in the
 | |
|                                 EFI_CORE_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.
 | |
|   @param  Type                  Fv File Type of file 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
 | |
| CoreAddToDriverList (
 | |
|   IN  EFI_FIRMWARE_VOLUME2_PROTOCOL  *Fv,
 | |
|   IN  EFI_HANDLE                     FvHandle,
 | |
|   IN  EFI_GUID                       *DriverName,
 | |
|   IN  EFI_FV_FILETYPE                Type
 | |
|   )
 | |
| {
 | |
|   EFI_CORE_DRIVER_ENTRY  *DriverEntry;
 | |
| 
 | |
|   //
 | |
|   // Create the Driver Entry for the list. ZeroPool initializes lots of variables to
 | |
|   // NULL or FALSE.
 | |
|   //
 | |
|   DriverEntry = AllocateZeroPool (sizeof (EFI_CORE_DRIVER_ENTRY));
 | |
|   ASSERT (DriverEntry != NULL);
 | |
|   if (Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
 | |
|     DriverEntry->IsFvImage = TRUE;
 | |
|   }
 | |
| 
 | |
|   DriverEntry->Signature = EFI_CORE_DRIVER_ENTRY_SIGNATURE;
 | |
|   CopyGuid (&DriverEntry->FileName, DriverName);
 | |
|   DriverEntry->FvHandle         = FvHandle;
 | |
|   DriverEntry->Fv               = Fv;
 | |
|   DriverEntry->FvFileDevicePath = CoreFvToDevicePath (Fv, FvHandle, DriverName);
 | |
| 
 | |
|   CoreGetDepexSectionAndPreProccess (DriverEntry);
 | |
| 
 | |
|   CoreAcquireDispatcherLock ();
 | |
| 
 | |
|   InsertTailList (&mDiscoveredList, &DriverEntry->Link);
 | |
| 
 | |
|   CoreReleaseDispatcherLock ();
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Check if a FV Image type file (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) is
 | |
|   described by a EFI_HOB_FIRMWARE_VOLUME2 Hob.
 | |
| 
 | |
|   @param  FvNameGuid            The FV image guid specified.
 | |
|   @param  DriverName            The driver guid specified.
 | |
| 
 | |
|   @retval TRUE                  This file is found in a EFI_HOB_FIRMWARE_VOLUME2
 | |
|                                 Hob.
 | |
|   @retval FALSE                 Not found.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| FvFoundInHobFv2 (
 | |
|   IN  CONST EFI_GUID  *FvNameGuid,
 | |
|   IN  CONST EFI_GUID  *DriverName
 | |
|   )
 | |
| {
 | |
|   EFI_PEI_HOB_POINTERS  HobFv2;
 | |
| 
 | |
|   HobFv2.Raw = GetHobList ();
 | |
| 
 | |
|   while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) {
 | |
|     //
 | |
|     // Compare parent FvNameGuid and FileGuid both.
 | |
|     //
 | |
|     if (CompareGuid (DriverName, &HobFv2.FirmwareVolume2->FileName) &&
 | |
|         CompareGuid (FvNameGuid, &HobFv2.FirmwareVolume2->FvName))
 | |
|     {
 | |
|       return TRUE;
 | |
|     }
 | |
| 
 | |
|     HobFv2.Raw = GET_NEXT_HOB (HobFv2);
 | |
|   }
 | |
| 
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Find USED_SIZE FV_EXT_TYPE entry in FV extension header and get the FV used size.
 | |
| 
 | |
|   @param[in]  FvHeader      Pointer to FV header.
 | |
|   @param[out] FvUsedSize    Pointer to FV used size returned,
 | |
|                             only valid if USED_SIZE FV_EXT_TYPE entry is found.
 | |
|   @param[out] EraseByte     Pointer to erase byte returned,
 | |
|                             only valid if USED_SIZE FV_EXT_TYPE entry is found.
 | |
| 
 | |
|   @retval TRUE              USED_SIZE FV_EXT_TYPE entry is found,
 | |
|                             FV used size and erase byte are returned.
 | |
|   @retval FALSE             No USED_SIZE FV_EXT_TYPE entry found.
 | |
| 
 | |
| **/
 | |
| BOOLEAN
 | |
| GetFvUsedSize (
 | |
|   IN EFI_FIRMWARE_VOLUME_HEADER  *FvHeader,
 | |
|   OUT UINT32                     *FvUsedSize,
 | |
|   OUT UINT8                      *EraseByte
 | |
|   )
 | |
| {
 | |
|   UINT16                                        ExtHeaderOffset;
 | |
|   EFI_FIRMWARE_VOLUME_EXT_HEADER                *ExtHeader;
 | |
|   EFI_FIRMWARE_VOLUME_EXT_ENTRY                 *ExtEntryList;
 | |
|   EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE  *ExtEntryUsedSize;
 | |
| 
 | |
|   ExtHeaderOffset = ReadUnaligned16 (&FvHeader->ExtHeaderOffset);
 | |
|   if (ExtHeaderOffset != 0) {
 | |
|     ExtHeader    = (EFI_FIRMWARE_VOLUME_EXT_HEADER *)((UINT8 *)FvHeader + ExtHeaderOffset);
 | |
|     ExtEntryList = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *)(ExtHeader + 1);
 | |
|     while ((UINTN)ExtEntryList < ((UINTN)ExtHeader + ReadUnaligned32 (&ExtHeader->ExtHeaderSize))) {
 | |
|       if (ReadUnaligned16 (&ExtEntryList->ExtEntryType) == EFI_FV_EXT_TYPE_USED_SIZE_TYPE) {
 | |
|         //
 | |
|         // USED_SIZE FV_EXT_TYPE entry is found.
 | |
|         //
 | |
|         ExtEntryUsedSize = (EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE *)ExtEntryList;
 | |
|         *FvUsedSize      = ReadUnaligned32 (&ExtEntryUsedSize->UsedSize);
 | |
|         if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ERASE_POLARITY) != 0) {
 | |
|           *EraseByte = 0xFF;
 | |
|         } else {
 | |
|           *EraseByte = 0;
 | |
|         }
 | |
| 
 | |
|         DEBUG ((
 | |
|           DEBUG_INFO,
 | |
|           "FV at 0x%x has 0x%x used size, and erase byte is 0x%02x\n",
 | |
|           FvHeader,
 | |
|           *FvUsedSize,
 | |
|           *EraseByte
 | |
|           ));
 | |
|         return TRUE;
 | |
|       }
 | |
| 
 | |
|       ExtEntryList = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *)
 | |
|                      ((UINT8 *)ExtEntryList + ReadUnaligned16 (&ExtEntryList->ExtEntrySize));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   //
 | |
|   // No USED_SIZE FV_EXT_TYPE entry found.
 | |
|   //
 | |
|   return FALSE;
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Get Fv image(s) from the FV through file name, and produce FVB protocol for every Fv image(s).
 | |
| 
 | |
|   @param  Fv                    The FIRMWARE_VOLUME protocol installed on the FV.
 | |
|   @param  FvHandle              The handle which FVB protocol installed on.
 | |
|   @param  FileName              The file name guid specified.
 | |
| 
 | |
|   @retval EFI_OUT_OF_RESOURCES  No enough memory or other resource.
 | |
|   @retval EFI_SUCCESS           Function successfully returned.
 | |
| 
 | |
| **/
 | |
| EFI_STATUS
 | |
| CoreProcessFvImageFile (
 | |
|   IN  EFI_FIRMWARE_VOLUME2_PROTOCOL  *Fv,
 | |
|   IN  EFI_HANDLE                     FvHandle,
 | |
|   IN  EFI_GUID                       *FileName
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                  Status;
 | |
|   EFI_SECTION_TYPE            SectionType;
 | |
|   UINT32                      AuthenticationStatus;
 | |
|   VOID                        *Buffer;
 | |
|   VOID                        *AlignedBuffer;
 | |
|   UINTN                       BufferSize;
 | |
|   EFI_FIRMWARE_VOLUME_HEADER  *FvHeader;
 | |
|   UINT32                      FvAlignment;
 | |
|   EFI_DEVICE_PATH_PROTOCOL    *FvFileDevicePath;
 | |
|   UINT32                      FvUsedSize;
 | |
|   UINT8                       EraseByte;
 | |
|   UINTN                       Index;
 | |
| 
 | |
|   //
 | |
|   // Read firmware volume section(s)
 | |
|   //
 | |
|   SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;
 | |
| 
 | |
|   Index = 0;
 | |
|   do {
 | |
|     FvHeader      = NULL;
 | |
|     FvAlignment   = 0;
 | |
|     Buffer        = NULL;
 | |
|     BufferSize    = 0;
 | |
|     AlignedBuffer = NULL;
 | |
|     Status        = Fv->ReadSection (
 | |
|                           Fv,
 | |
|                           FileName,
 | |
|                           SectionType,
 | |
|                           Index,
 | |
|                           &Buffer,
 | |
|                           &BufferSize,
 | |
|                           &AuthenticationStatus
 | |
|                           );
 | |
|     if (!EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // Evaluate the authentication status of the Firmware Volume through
 | |
|       // Security Architectural Protocol
 | |
|       //
 | |
|       if (gSecurity != NULL) {
 | |
|         FvFileDevicePath = CoreFvToDevicePath (Fv, FvHandle, FileName);
 | |
|         Status           = gSecurity->FileAuthenticationState (
 | |
|                                         gSecurity,
 | |
|                                         AuthenticationStatus,
 | |
|                                         FvFileDevicePath
 | |
|                                         );
 | |
|         if (FvFileDevicePath != NULL) {
 | |
|           FreePool (FvFileDevicePath);
 | |
|         }
 | |
| 
 | |
|         if (Status != EFI_SUCCESS) {
 | |
|           //
 | |
|           // Security check failed. The firmware volume should not be used for any purpose.
 | |
|           //
 | |
|           if (Buffer != NULL) {
 | |
|             FreePool (Buffer);
 | |
|           }
 | |
| 
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // FvImage should be at its required alignment.
 | |
|       //
 | |
|       FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)Buffer;
 | |
|       //
 | |
|       // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
 | |
|       // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
 | |
|       // its initial linked location and maintain its alignment.
 | |
|       //
 | |
|       if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {
 | |
|         //
 | |
|         // Get FvHeader alignment
 | |
|         //
 | |
|         FvAlignment = 1 << ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ALIGNMENT) >> 16);
 | |
|         //
 | |
|         // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
 | |
|         //
 | |
|         if (FvAlignment < 8) {
 | |
|           FvAlignment = 8;
 | |
|         }
 | |
| 
 | |
|         DEBUG ((
 | |
|           DEBUG_INFO,
 | |
|           "%a() FV at 0x%x, FvAlignment required is 0x%x\n",
 | |
|           __func__,
 | |
|           FvHeader,
 | |
|           FvAlignment
 | |
|           ));
 | |
| 
 | |
|         //
 | |
|         // Check FvImage alignment.
 | |
|         //
 | |
|         if ((UINTN)FvHeader % FvAlignment != 0) {
 | |
|           //
 | |
|           // Allocate the aligned buffer for the FvImage.
 | |
|           //
 | |
|           AlignedBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), (UINTN)FvAlignment);
 | |
|           if (AlignedBuffer == NULL) {
 | |
|             FreePool (Buffer);
 | |
|             Status = EFI_OUT_OF_RESOURCES;
 | |
|             break;
 | |
|           } else {
 | |
|             //
 | |
|             // Move FvImage into the aligned buffer and release the original buffer.
 | |
|             //
 | |
|             if (GetFvUsedSize (FvHeader, &FvUsedSize, &EraseByte)) {
 | |
|               //
 | |
|               // Copy the used bytes and fill the rest with the erase value.
 | |
|               //
 | |
|               CopyMem (AlignedBuffer, FvHeader, (UINTN)FvUsedSize);
 | |
|               SetMem (
 | |
|                 (UINT8 *)AlignedBuffer + FvUsedSize,
 | |
|                 (UINTN)(BufferSize - FvUsedSize),
 | |
|                 EraseByte
 | |
|                 );
 | |
|             } else {
 | |
|               CopyMem (AlignedBuffer, Buffer, BufferSize);
 | |
|             }
 | |
| 
 | |
|             FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)AlignedBuffer;
 | |
|             FreePool (Buffer);
 | |
|             Buffer = NULL;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       //
 | |
|       // Produce a FVB protocol for the file
 | |
|       //
 | |
|       Status = ProduceFVBProtocolOnBuffer (
 | |
|                  (EFI_PHYSICAL_ADDRESS)(UINTN)FvHeader,
 | |
|                  (UINT64)BufferSize,
 | |
|                  FvHandle,
 | |
|                  AuthenticationStatus,
 | |
|                  NULL
 | |
|                  );
 | |
|     }
 | |
| 
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // ReadSection or Produce FVB failed, Free data buffer
 | |
|       //
 | |
|       if (Buffer != NULL) {
 | |
|         FreePool (Buffer);
 | |
|       }
 | |
| 
 | |
|       if (AlignedBuffer != NULL) {
 | |
|         FreeAlignedPages (AlignedBuffer, EFI_SIZE_TO_PAGES (BufferSize));
 | |
|       }
 | |
| 
 | |
|       break;
 | |
|     } else {
 | |
|       Index++;
 | |
|     }
 | |
|   } while (TRUE);
 | |
| 
 | |
|   if (Index > 0) {
 | |
|     //
 | |
|     // At least one FvImage has been processed successfully.
 | |
|     //
 | |
|     return EFI_SUCCESS;
 | |
|   } else {
 | |
|     return Status;
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   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 CoreLocateHandle () 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 DXE 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  Event                 The Event that is being processed, not used.
 | |
|   @param  Context               Event Context, not used.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| EFIAPI
 | |
| CoreFwVolEventProtocolNotify (
 | |
|   IN  EFI_EVENT  Event,
 | |
|   IN  VOID       *Context
 | |
|   )
 | |
| {
 | |
|   EFI_STATUS                     Status;
 | |
|   EFI_STATUS                     GetNextFileStatus;
 | |
|   EFI_FIRMWARE_VOLUME2_PROTOCOL  *Fv;
 | |
|   EFI_DEVICE_PATH_PROTOCOL       *FvDevicePath;
 | |
|   EFI_HANDLE                     FvHandle;
 | |
|   UINTN                          BufferSize;
 | |
|   EFI_GUID                       NameGuid;
 | |
|   UINTN                          Key;
 | |
|   EFI_FV_FILETYPE                Type;
 | |
|   EFI_FV_FILE_ATTRIBUTES         Attributes;
 | |
|   UINTN                          Size;
 | |
|   EFI_CORE_DRIVER_ENTRY          *DriverEntry;
 | |
|   EFI_GUID                       *AprioriFile;
 | |
|   UINTN                          AprioriEntryCount;
 | |
|   UINTN                          Index;
 | |
|   LIST_ENTRY                     *Link;
 | |
|   UINT32                         AuthenticationStatus;
 | |
|   UINTN                          SizeOfBuffer;
 | |
|   VOID                           *DepexBuffer;
 | |
|   KNOWN_HANDLE                   *KnownHandle;
 | |
| 
 | |
|   FvHandle = NULL;
 | |
| 
 | |
|   while (TRUE) {
 | |
|     BufferSize = sizeof (EFI_HANDLE);
 | |
|     Status     = CoreLocateHandle (
 | |
|                    ByRegisterNotify,
 | |
|                    NULL,
 | |
|                    mFwVolEventRegistration,
 | |
|                    &BufferSize,
 | |
|                    &FvHandle
 | |
|                    );
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       //
 | |
|       // If no more notification events exit
 | |
|       //
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|     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.
 | |
|     //
 | |
|     KnownHandle = FvIsBeingProcessed (FvHandle);
 | |
|     if (KnownHandle == NULL) {
 | |
|       //
 | |
|       // The FV with the same FV name guid has already been processed.
 | |
|       // So lets skip it!
 | |
|       //
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);
 | |
|     if (EFI_ERROR (Status) || (Fv == NULL)) {
 | |
|       //
 | |
|       // FvHandle must have Firmware Volume2 protocol thus we should never get here.
 | |
|       //
 | |
|       ASSERT (FALSE);
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     Status = CoreHandleProtocol (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_DRIVER type and then EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
 | |
|     //  EFI_FV_FILETYPE_DXE_CORE is processed to produce a Loaded Image protocol for the core
 | |
|     //  EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE is processed to create a Fvb
 | |
|     //
 | |
|     for (Index = 0; Index < sizeof (mDxeFileTypes) / sizeof (EFI_FV_FILETYPE); Index++) {
 | |
|       //
 | |
|       // Initialize the search key
 | |
|       //
 | |
|       Key = 0;
 | |
|       do {
 | |
|         Type              = mDxeFileTypes[Index];
 | |
|         GetNextFileStatus = Fv->GetNextFile (
 | |
|                                   Fv,
 | |
|                                   &Key,
 | |
|                                   &Type,
 | |
|                                   &NameGuid,
 | |
|                                   &Attributes,
 | |
|                                   &Size
 | |
|                                   );
 | |
|         if (!EFI_ERROR (GetNextFileStatus)) {
 | |
|           if (Type == EFI_FV_FILETYPE_DXE_CORE) {
 | |
|             //
 | |
|             // If this is the DXE core fill in it's DevicePath & DeviceHandle
 | |
|             //
 | |
|             if (gDxeCoreLoadedImage->FilePath == NULL) {
 | |
|               if (CompareGuid (&NameGuid, gDxeCoreFileName)) {
 | |
|                 //
 | |
|                 // Maybe One specail Fv cantains only one DXE_CORE module, so its device path must
 | |
|                 // be initialized completely.
 | |
|                 //
 | |
|                 EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid);
 | |
|                 SetDevicePathEndNode (&mFvDevicePath.End);
 | |
| 
 | |
|                 gDxeCoreLoadedImage->FilePath = DuplicateDevicePath (
 | |
|                                                   (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath
 | |
|                                                   );
 | |
|                 gDxeCoreLoadedImage->DeviceHandle = FvHandle;
 | |
|               }
 | |
|             }
 | |
|           } else if (Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
 | |
|             //
 | |
|             // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
 | |
|             // been extracted.
 | |
|             //
 | |
|             if (FvFoundInHobFv2 (&KnownHandle->FvNameGuid, &NameGuid)) {
 | |
|               continue;
 | |
|             }
 | |
| 
 | |
|             //
 | |
|             // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has SMM depex section.
 | |
|             //
 | |
|             DepexBuffer  = NULL;
 | |
|             SizeOfBuffer = 0;
 | |
|             Status       = Fv->ReadSection (
 | |
|                                  Fv,
 | |
|                                  &NameGuid,
 | |
|                                  EFI_SECTION_SMM_DEPEX,
 | |
|                                  0,
 | |
|                                  &DepexBuffer,
 | |
|                                  &SizeOfBuffer,
 | |
|                                  &AuthenticationStatus
 | |
|                                  );
 | |
|             if (!EFI_ERROR (Status)) {
 | |
|               //
 | |
|               // If SMM depex section is found, this FV image is invalid to be supported.
 | |
|               // ASSERT FALSE to report this FV image.
 | |
|               //
 | |
|               FreePool (DepexBuffer);
 | |
|               ASSERT (FALSE);
 | |
|             }
 | |
| 
 | |
|             //
 | |
|             // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has DXE depex section.
 | |
|             //
 | |
|             DepexBuffer  = NULL;
 | |
|             SizeOfBuffer = 0;
 | |
|             Status       = Fv->ReadSection (
 | |
|                                  Fv,
 | |
|                                  &NameGuid,
 | |
|                                  EFI_SECTION_DXE_DEPEX,
 | |
|                                  0,
 | |
|                                  &DepexBuffer,
 | |
|                                  &SizeOfBuffer,
 | |
|                                  &AuthenticationStatus
 | |
|                                  );
 | |
|             if (EFI_ERROR (Status)) {
 | |
|               //
 | |
|               // If no depex section, produce a firmware volume block protocol for it so it gets dispatched from.
 | |
|               //
 | |
|               CoreProcessFvImageFile (Fv, FvHandle, &NameGuid);
 | |
|             } else {
 | |
|               //
 | |
|               // If depex section is found, this FV image will be dispatched until its depex is evaluated to TRUE.
 | |
|               //
 | |
|               FreePool (DepexBuffer);
 | |
|               CoreAddToDriverList (Fv, FvHandle, &NameGuid, Type);
 | |
|             }
 | |
|           } else {
 | |
|             //
 | |
|             // Transition driver from Undiscovered to Discovered state
 | |
|             //
 | |
|             CoreAddToDriverList (Fv, FvHandle, &NameGuid, Type);
 | |
|           }
 | |
|         }
 | |
|       } while (!EFI_ERROR (GetNextFileStatus));
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Read the array of GUIDs from the Apriori file if it is present in the firmware volume
 | |
|     //
 | |
|     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 (Index = 0; Index < AprioriEntryCount; Index++) {
 | |
|       for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
 | |
|         DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
 | |
|         if (CompareGuid (&DriverEntry->FileName, &AprioriFile[Index]) &&
 | |
|             (FvHandle == DriverEntry->FvHandle))
 | |
|         {
 | |
|           CoreAcquireDispatcherLock ();
 | |
|           DriverEntry->Dependent = FALSE;
 | |
|           DriverEntry->Scheduled = TRUE;
 | |
|           InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);
 | |
|           CoreReleaseDispatcherLock ();
 | |
|           DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
 | |
|           DEBUG ((DEBUG_DISPATCH, "  RESULT = TRUE (Apriori)\n"));
 | |
|           break;
 | |
|         }
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     //
 | |
|     // Free data allocated by Fv->ReadSection ()
 | |
|     //
 | |
|     CoreFreePool (AprioriFile);
 | |
|   }
 | |
| }
 | |
| 
 | |
| /**
 | |
|   Initialize the dispatcher. Initialize the notification function that runs when
 | |
|   an FV2 protocol is added to the system.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| CoreInitializeDispatcher (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   PERF_FUNCTION_BEGIN ();
 | |
| 
 | |
|   mFwVolEvent = EfiCreateProtocolNotifyEvent (
 | |
|                   &gEfiFirmwareVolume2ProtocolGuid,
 | |
|                   TPL_CALLBACK,
 | |
|                   CoreFwVolEventProtocolNotify,
 | |
|                   NULL,
 | |
|                   &mFwVolEventRegistration
 | |
|                   );
 | |
| 
 | |
|   PERF_FUNCTION_END ();
 | |
| }
 | |
| 
 | |
| //
 | |
| // Function only used in debug builds
 | |
| //
 | |
| 
 | |
| /**
 | |
|   Traverse the discovered list for any drivers that were discovered but not loaded
 | |
|   because the dependency experessions evaluated to false.
 | |
| 
 | |
| **/
 | |
| VOID
 | |
| CoreDisplayDiscoveredNotDispatched (
 | |
|   VOID
 | |
|   )
 | |
| {
 | |
|   LIST_ENTRY             *Link;
 | |
|   EFI_CORE_DRIVER_ENTRY  *DriverEntry;
 | |
| 
 | |
|   for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
 | |
|     DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
 | |
|     if (DriverEntry->Dependent) {
 | |
|       DEBUG ((DEBUG_LOAD, "Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName));
 | |
|     }
 | |
|   }
 | |
| }
 |