Home | History | Annotate | Download | only in Dispatcher
      1 /** @file
      2   DXE Dispatcher.
      3 
      4   Step #1 - When a FV protocol is added to the system every driver in the FV
      5             is added to the mDiscoveredList. The SOR, Before, and After Depex are
      6             pre-processed as drivers are added to the mDiscoveredList. If an Apriori
      7             file exists in the FV those drivers are addeded to the
      8             mScheduledQueue. The mFvHandleList is used to make sure a
      9             FV is only processed once.
     10 
     11   Step #2 - Dispatch. Remove driver from the mScheduledQueue and load and
     12             start it. After mScheduledQueue is drained check the
     13             mDiscoveredList to see if any item has a Depex that is ready to
     14             be placed on the mScheduledQueue.
     15 
     16   Step #3 - Adding to the mScheduledQueue requires that you process Before
     17             and After dependencies. This is done recursively as the call to add
     18             to the mScheduledQueue checks for Before and recursively adds
     19             all Befores. It then addes the item that was passed in and then
     20             processess the After dependecies by recursively calling the routine.
     21 
     22   Dispatcher Rules:
     23   The rules for the dispatcher are in chapter 10 of the DXE CIS. Figure 10-3
     24   is the state diagram for the DXE dispatcher
     25 
     26   Depex - Dependency Expresion.
     27   SOR   - Schedule On Request - Don't schedule if this bit is set.
     28 
     29 Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
     30 This program and the accompanying materials
     31 are licensed and made available under the terms and conditions of the BSD License
     32 which accompanies this distribution.  The full text of the license may be found at
     33 http://opensource.org/licenses/bsd-license.php
     34 
     35 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     36 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     37 
     38 **/
     39 
     40 #include "DxeMain.h"
     41 
     42 //
     43 // The Driver List contains one copy of every driver that has been discovered.
     44 // Items are never removed from the driver list. List of EFI_CORE_DRIVER_ENTRY
     45 //
     46 LIST_ENTRY  mDiscoveredList = INITIALIZE_LIST_HEAD_VARIABLE (mDiscoveredList);
     47 
     48 //
     49 // Queue of drivers that are ready to dispatch. This queue is a subset of the
     50 // mDiscoveredList.list of EFI_CORE_DRIVER_ENTRY.
     51 //
     52 LIST_ENTRY  mScheduledQueue = INITIALIZE_LIST_HEAD_VARIABLE (mScheduledQueue);
     53 
     54 //
     55 // List of handles who's Fv's have been parsed and added to the mFwDriverList.
     56 //
     57 LIST_ENTRY  mFvHandleList = INITIALIZE_LIST_HEAD_VARIABLE (mFvHandleList);           // list of KNOWN_HANDLE
     58 
     59 //
     60 // Lock for mDiscoveredList, mScheduledQueue, gDispatcherRunning.
     61 //
     62 EFI_LOCK  mDispatcherLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);
     63 
     64 
     65 //
     66 // Flag for the DXE Dispacher.  TRUE if dispatcher is execuing.
     67 //
     68 BOOLEAN  gDispatcherRunning = FALSE;
     69 
     70 //
     71 // Module globals to manage the FwVol registration notification event
     72 //
     73 EFI_EVENT       mFwVolEvent;
     74 VOID            *mFwVolEventRegistration;
     75 
     76 //
     77 // List of file types supported by dispatcher
     78 //
     79 EFI_FV_FILETYPE mDxeFileTypes[] = {
     80   EFI_FV_FILETYPE_DRIVER,
     81   EFI_FV_FILETYPE_COMBINED_SMM_DXE,
     82   EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,
     83   EFI_FV_FILETYPE_DXE_CORE,
     84   EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
     85 };
     86 
     87 typedef struct {
     88   MEDIA_FW_VOL_FILEPATH_DEVICE_PATH   File;
     89   EFI_DEVICE_PATH_PROTOCOL            End;
     90 } FV_FILEPATH_DEVICE_PATH;
     91 
     92 FV_FILEPATH_DEVICE_PATH mFvDevicePath;
     93 
     94 //
     95 // Function Prototypes
     96 //
     97 /**
     98   Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
     99   must add any driver with a before dependency on InsertedDriverEntry first.
    100   You do this by recursively calling this routine. After all the Befores are
    101   processed you can add InsertedDriverEntry to the mScheduledQueue.
    102   Then you can add any driver with an After dependency on InsertedDriverEntry
    103   by recursively calling this routine.
    104 
    105   @param  InsertedDriverEntry   The driver to insert on the ScheduledLink Queue
    106 
    107 **/
    108 VOID
    109 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
    110   IN  EFI_CORE_DRIVER_ENTRY   *InsertedDriverEntry
    111   );
    112 
    113 /**
    114   Event notification that is fired every time a FV dispatch protocol is added.
    115   More than one protocol may have been added when this event is fired, so you
    116   must loop on CoreLocateHandle () to see how many protocols were added and
    117   do the following to each FV:
    118   If the Fv has already been processed, skip it. If the Fv has not been
    119   processed then mark it as being processed, as we are about to process it.
    120   Read the Fv and add any driver in the Fv to the mDiscoveredList.The
    121   mDiscoveredList is never free'ed and contains variables that define
    122   the other states the DXE driver transitions to..
    123   While you are at it read the A Priori file into memory.
    124   Place drivers in the A Priori list onto the mScheduledQueue.
    125 
    126   @param  Event                 The Event that is being processed, not used.
    127   @param  Context               Event Context, not used.
    128 
    129 **/
    130 VOID
    131 EFIAPI
    132 CoreFwVolEventProtocolNotify (
    133   IN  EFI_EVENT       Event,
    134   IN  VOID            *Context
    135   );
    136 
    137 /**
    138   Convert FvHandle and DriverName into an EFI device path
    139 
    140   @param  Fv                    Fv protocol, needed to read Depex info out of
    141                                 FLASH.
    142   @param  FvHandle              Handle for Fv, needed in the
    143                                 EFI_CORE_DRIVER_ENTRY so that the PE image can be
    144                                 read out of the FV at a later time.
    145   @param  DriverName            Name of driver to add to mDiscoveredList.
    146 
    147   @return Pointer to device path constructed from FvHandle and DriverName
    148 
    149 **/
    150 EFI_DEVICE_PATH_PROTOCOL *
    151 CoreFvToDevicePath (
    152   IN  EFI_FIRMWARE_VOLUME2_PROTOCOL   *Fv,
    153   IN  EFI_HANDLE                      FvHandle,
    154   IN  EFI_GUID                        *DriverName
    155   );
    156 
    157 /**
    158   Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
    159   and initilize any state variables. Read the Depex from the FV and store it
    160   in DriverEntry. Pre-process the Depex to set the SOR, Before and After state.
    161   The Discovered list is never free'ed and contains booleans that represent the
    162   other possible DXE driver states.
    163 
    164   @param  Fv                    Fv protocol, needed to read Depex info out of
    165                                 FLASH.
    166   @param  FvHandle              Handle for Fv, needed in the
    167                                 EFI_CORE_DRIVER_ENTRY so that the PE image can be
    168                                 read out of the FV at a later time.
    169   @param  DriverName            Name of driver to add to mDiscoveredList.
    170   @param  Type                  Fv File Type of file to add to mDiscoveredList.
    171 
    172   @retval EFI_SUCCESS           If driver was added to the mDiscoveredList.
    173   @retval EFI_ALREADY_STARTED   The driver has already been started. Only one
    174                                 DriverName may be active in the system at any one
    175                                 time.
    176 
    177 **/
    178 EFI_STATUS
    179 CoreAddToDriverList (
    180   IN  EFI_FIRMWARE_VOLUME2_PROTOCOL   *Fv,
    181   IN  EFI_HANDLE                      FvHandle,
    182   IN  EFI_GUID                        *DriverName,
    183   IN  EFI_FV_FILETYPE                 Type
    184   );
    185 
    186 /**
    187   Get the driver from the FV through driver name, and produce a FVB protocol on FvHandle.
    188 
    189   @param  Fv                    The FIRMWARE_VOLUME protocol installed on the FV.
    190   @param  FvHandle              The handle which FVB protocol installed on.
    191   @param  DriverName            The driver guid specified.
    192 
    193   @retval EFI_OUT_OF_RESOURCES  No enough memory or other resource.
    194   @retval EFI_VOLUME_CORRUPTED  Corrupted volume.
    195   @retval EFI_SUCCESS           Function successfully returned.
    196 
    197 **/
    198 EFI_STATUS
    199 CoreProcessFvImageFile (
    200   IN  EFI_FIRMWARE_VOLUME2_PROTOCOL   *Fv,
    201   IN  EFI_HANDLE                      FvHandle,
    202   IN  EFI_GUID                        *DriverName
    203   );
    204 
    205 
    206 /**
    207   Enter critical section by gaining lock on mDispatcherLock.
    208 
    209 **/
    210 VOID
    211 CoreAcquireDispatcherLock (
    212   VOID
    213   )
    214 {
    215   CoreAcquireLock (&mDispatcherLock);
    216 }
    217 
    218 
    219 /**
    220   Exit critical section by releasing lock on mDispatcherLock.
    221 
    222 **/
    223 VOID
    224 CoreReleaseDispatcherLock (
    225   VOID
    226   )
    227 {
    228   CoreReleaseLock (&mDispatcherLock);
    229 }
    230 
    231 
    232 /**
    233   Read Depex and pre-process the Depex for Before and After. If Section Extraction
    234   protocol returns an error via ReadSection defer the reading of the Depex.
    235 
    236   @param  DriverEntry           Driver to work on.
    237 
    238   @retval EFI_SUCCESS           Depex read and preprossesed
    239   @retval EFI_PROTOCOL_ERROR    The section extraction protocol returned an error
    240                                 and  Depex reading needs to be retried.
    241   @retval Error                 DEPEX not found.
    242 
    243 **/
    244 EFI_STATUS
    245 CoreGetDepexSectionAndPreProccess (
    246   IN  EFI_CORE_DRIVER_ENTRY   *DriverEntry
    247   )
    248 {
    249   EFI_STATUS                    Status;
    250   EFI_SECTION_TYPE              SectionType;
    251   UINT32                        AuthenticationStatus;
    252   EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
    253 
    254 
    255   Fv = DriverEntry->Fv;
    256 
    257   //
    258   // Grab Depex info, it will never be free'ed.
    259   //
    260   SectionType         = EFI_SECTION_DXE_DEPEX;
    261   Status = Fv->ReadSection (
    262                 DriverEntry->Fv,
    263                 &DriverEntry->FileName,
    264                 SectionType,
    265                 0,
    266                 &DriverEntry->Depex,
    267                 (UINTN *)&DriverEntry->DepexSize,
    268                 &AuthenticationStatus
    269                 );
    270   if (EFI_ERROR (Status)) {
    271     if (Status == EFI_PROTOCOL_ERROR) {
    272       //
    273       // The section extraction protocol failed so set protocol error flag
    274       //
    275       DriverEntry->DepexProtocolError = TRUE;
    276     } else {
    277       //
    278       // If no Depex assume UEFI 2.0 driver model
    279       //
    280       DriverEntry->Depex = NULL;
    281       DriverEntry->Dependent = TRUE;
    282       DriverEntry->DepexProtocolError = FALSE;
    283     }
    284   } else {
    285     //
    286     // Set Before, After, and Unrequested state information based on Depex
    287     // Driver will be put in Dependent or Unrequested state
    288     //
    289     CorePreProcessDepex (DriverEntry);
    290     DriverEntry->DepexProtocolError = FALSE;
    291   }
    292 
    293   return Status;
    294 }
    295 
    296 
    297 /**
    298   Check every driver and locate a matching one. If the driver is found, the Unrequested
    299   state flag is cleared.
    300 
    301   @param  FirmwareVolumeHandle  The handle of the Firmware Volume that contains
    302                                 the firmware  file specified by DriverName.
    303   @param  DriverName            The Driver name to put in the Dependent state.
    304 
    305   @retval EFI_SUCCESS           The DriverName was found and it's SOR bit was
    306                                 cleared
    307   @retval EFI_NOT_FOUND         The DriverName does not exist or it's SOR bit was
    308                                 not set.
    309 
    310 **/
    311 EFI_STATUS
    312 EFIAPI
    313 CoreSchedule (
    314   IN  EFI_HANDLE  FirmwareVolumeHandle,
    315   IN  EFI_GUID    *DriverName
    316   )
    317 {
    318   LIST_ENTRY            *Link;
    319   EFI_CORE_DRIVER_ENTRY *DriverEntry;
    320 
    321   //
    322   // Check every driver
    323   //
    324   for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
    325     DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
    326     if (DriverEntry->FvHandle == FirmwareVolumeHandle &&
    327         DriverEntry->Unrequested &&
    328         CompareGuid (DriverName, &DriverEntry->FileName)) {
    329       //
    330       // Move the driver from the Unrequested to the Dependent state
    331       //
    332       CoreAcquireDispatcherLock ();
    333       DriverEntry->Unrequested  = FALSE;
    334       DriverEntry->Dependent    = TRUE;
    335       CoreReleaseDispatcherLock ();
    336 
    337       DEBUG ((DEBUG_DISPATCH, "Schedule FFS(%g) - EFI_SUCCESS\n", DriverName));
    338 
    339       return EFI_SUCCESS;
    340     }
    341   }
    342 
    343   DEBUG ((DEBUG_DISPATCH, "Schedule FFS(%g) - EFI_NOT_FOUND\n", DriverName));
    344 
    345   return EFI_NOT_FOUND;
    346 }
    347 
    348 
    349 
    350 /**
    351   Convert a driver from the Untrused back to the Scheduled state.
    352 
    353   @param  FirmwareVolumeHandle  The handle of the Firmware Volume that contains
    354                                 the firmware  file specified by DriverName.
    355   @param  DriverName            The Driver name to put in the Scheduled state
    356 
    357   @retval EFI_SUCCESS           The file was found in the untrusted state, and it
    358                                 was promoted  to the trusted state.
    359   @retval EFI_NOT_FOUND         The file was not found in the untrusted state.
    360 
    361 **/
    362 EFI_STATUS
    363 EFIAPI
    364 CoreTrust (
    365   IN  EFI_HANDLE  FirmwareVolumeHandle,
    366   IN  EFI_GUID    *DriverName
    367   )
    368 {
    369   LIST_ENTRY            *Link;
    370   EFI_CORE_DRIVER_ENTRY *DriverEntry;
    371 
    372   //
    373   // Check every driver
    374   //
    375   for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
    376     DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
    377     if (DriverEntry->FvHandle == FirmwareVolumeHandle &&
    378         DriverEntry->Untrusted &&
    379         CompareGuid (DriverName, &DriverEntry->FileName)) {
    380       //
    381       // Transition driver from Untrusted to Scheduled state.
    382       //
    383       CoreAcquireDispatcherLock ();
    384       DriverEntry->Untrusted = FALSE;
    385       DriverEntry->Scheduled = TRUE;
    386       InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);
    387       CoreReleaseDispatcherLock ();
    388 
    389       return EFI_SUCCESS;
    390     }
    391   }
    392   return EFI_NOT_FOUND;
    393 }
    394 
    395 
    396 /**
    397   An empty function to pass error checking of CreateEventEx ().
    398 
    399   @param  Event                 Event whose notification function is being invoked.
    400   @param  Context               Pointer to the notification function's context,
    401                                 which is implementation-dependent.
    402 
    403 **/
    404 VOID
    405 EFIAPI
    406 CoreEmptyCallbackFunction (
    407   IN EFI_EVENT                Event,
    408   IN VOID                     *Context
    409   )
    410 {
    411   return;
    412 }
    413 
    414 /**
    415   This is the main Dispatcher for DXE and it exits when there are no more
    416   drivers to run. Drain the mScheduledQueue and load and start a PE
    417   image for each driver. Search the mDiscoveredList to see if any driver can
    418   be placed on the mScheduledQueue. If no drivers are placed on the
    419   mScheduledQueue exit the function. On exit it is assumed the Bds()
    420   will be called, and when the Bds() exits the Dispatcher will be called
    421   again.
    422 
    423   @retval EFI_ALREADY_STARTED   The DXE Dispatcher is already running
    424   @retval EFI_NOT_FOUND         No DXE Drivers were dispatched
    425   @retval EFI_SUCCESS           One or more DXE Drivers were dispatched
    426 
    427 **/
    428 EFI_STATUS
    429 EFIAPI
    430 CoreDispatcher (
    431   VOID
    432   )
    433 {
    434   EFI_STATUS                      Status;
    435   EFI_STATUS                      ReturnStatus;
    436   LIST_ENTRY                      *Link;
    437   EFI_CORE_DRIVER_ENTRY           *DriverEntry;
    438   BOOLEAN                         ReadyToRun;
    439   EFI_EVENT                       DxeDispatchEvent;
    440 
    441 
    442   if (gDispatcherRunning) {
    443     //
    444     // If the dispatcher is running don't let it be restarted.
    445     //
    446     return EFI_ALREADY_STARTED;
    447   }
    448 
    449   gDispatcherRunning = TRUE;
    450 
    451   Status = CoreCreateEventEx (
    452              EVT_NOTIFY_SIGNAL,
    453              TPL_NOTIFY,
    454              CoreEmptyCallbackFunction,
    455              NULL,
    456              &gEfiEventDxeDispatchGuid,
    457              &DxeDispatchEvent
    458              );
    459   if (EFI_ERROR (Status)) {
    460     return Status;
    461   }
    462 
    463   ReturnStatus = EFI_NOT_FOUND;
    464   do {
    465     //
    466     // Drain the Scheduled Queue
    467     //
    468     while (!IsListEmpty (&mScheduledQueue)) {
    469       DriverEntry = CR (
    470                       mScheduledQueue.ForwardLink,
    471                       EFI_CORE_DRIVER_ENTRY,
    472                       ScheduledLink,
    473                       EFI_CORE_DRIVER_ENTRY_SIGNATURE
    474                       );
    475 
    476       //
    477       // Load the DXE Driver image into memory. If the Driver was transitioned from
    478       // Untrused to Scheduled it would have already been loaded so we may need to
    479       // skip the LoadImage
    480       //
    481       if (DriverEntry->ImageHandle == NULL && !DriverEntry->IsFvImage) {
    482         DEBUG ((DEBUG_INFO, "Loading driver %g\n", &DriverEntry->FileName));
    483         Status = CoreLoadImage (
    484                         FALSE,
    485                         gDxeCoreImageHandle,
    486                         DriverEntry->FvFileDevicePath,
    487                         NULL,
    488                         0,
    489                         &DriverEntry->ImageHandle
    490                         );
    491 
    492         //
    493         // Update the driver state to reflect that it's been loaded
    494         //
    495         if (EFI_ERROR (Status)) {
    496           CoreAcquireDispatcherLock ();
    497 
    498           if (Status == EFI_SECURITY_VIOLATION) {
    499             //
    500             // Take driver from Scheduled to Untrused state
    501             //
    502             DriverEntry->Untrusted = TRUE;
    503           } else {
    504             //
    505             // The DXE Driver could not be loaded, and do not attempt to load or start it again.
    506             // Take driver from Scheduled to Initialized.
    507             //
    508             // This case include the Never Trusted state if EFI_ACCESS_DENIED is returned
    509             //
    510             DriverEntry->Initialized  = TRUE;
    511           }
    512 
    513           DriverEntry->Scheduled = FALSE;
    514           RemoveEntryList (&DriverEntry->ScheduledLink);
    515 
    516           CoreReleaseDispatcherLock ();
    517 
    518           //
    519           // If it's an error don't try the StartImage
    520           //
    521           continue;
    522         }
    523       }
    524 
    525       CoreAcquireDispatcherLock ();
    526 
    527       DriverEntry->Scheduled    = FALSE;
    528       DriverEntry->Initialized  = TRUE;
    529       RemoveEntryList (&DriverEntry->ScheduledLink);
    530 
    531       CoreReleaseDispatcherLock ();
    532 
    533 
    534       if (DriverEntry->IsFvImage) {
    535         //
    536         // Produce a firmware volume block protocol for FvImage so it gets dispatched from.
    537         //
    538         Status = CoreProcessFvImageFile (DriverEntry->Fv, DriverEntry->FvHandle, &DriverEntry->FileName);
    539       } else {
    540         REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
    541           EFI_PROGRESS_CODE,
    542           (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_BEGIN),
    543           &DriverEntry->ImageHandle,
    544           sizeof (DriverEntry->ImageHandle)
    545           );
    546         ASSERT (DriverEntry->ImageHandle != NULL);
    547 
    548         Status = CoreStartImage (DriverEntry->ImageHandle, NULL, NULL);
    549 
    550         REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
    551           EFI_PROGRESS_CODE,
    552           (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_END),
    553           &DriverEntry->ImageHandle,
    554           sizeof (DriverEntry->ImageHandle)
    555           );
    556       }
    557 
    558       ReturnStatus = EFI_SUCCESS;
    559     }
    560 
    561     //
    562     // Now DXE Dispatcher finished one round of dispatch, signal an event group
    563     // so that SMM Dispatcher get chance to dispatch SMM Drivers which depend
    564     // on UEFI protocols
    565     //
    566     if (!EFI_ERROR (ReturnStatus)) {
    567       CoreSignalEvent (DxeDispatchEvent);
    568     }
    569 
    570     //
    571     // Search DriverList for items to place on Scheduled Queue
    572     //
    573     ReadyToRun = FALSE;
    574     for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
    575       DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
    576 
    577       if (DriverEntry->DepexProtocolError){
    578         //
    579         // If Section Extraction Protocol did not let the Depex be read before retry the read
    580         //
    581         Status = CoreGetDepexSectionAndPreProccess (DriverEntry);
    582       }
    583 
    584       if (DriverEntry->Dependent) {
    585         if (CoreIsSchedulable (DriverEntry)) {
    586           CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
    587           ReadyToRun = TRUE;
    588         }
    589       } else {
    590         if (DriverEntry->Unrequested) {
    591           DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
    592           DEBUG ((DEBUG_DISPATCH, "  SOR                                             = Not Requested\n"));
    593           DEBUG ((DEBUG_DISPATCH, "  RESULT = FALSE\n"));
    594         }
    595       }
    596     }
    597   } while (ReadyToRun);
    598 
    599   //
    600   // Close DXE dispatch Event
    601   //
    602   CoreCloseEvent (DxeDispatchEvent);
    603 
    604   gDispatcherRunning = FALSE;
    605 
    606   return ReturnStatus;
    607 }
    608 
    609 
    610 /**
    611   Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
    612   must add any driver with a before dependency on InsertedDriverEntry first.
    613   You do this by recursively calling this routine. After all the Befores are
    614   processed you can add InsertedDriverEntry to the mScheduledQueue.
    615   Then you can add any driver with an After dependency on InsertedDriverEntry
    616   by recursively calling this routine.
    617 
    618   @param  InsertedDriverEntry   The driver to insert on the ScheduledLink Queue
    619 
    620 **/
    621 VOID
    622 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
    623   IN  EFI_CORE_DRIVER_ENTRY   *InsertedDriverEntry
    624   )
    625 {
    626   LIST_ENTRY            *Link;
    627   EFI_CORE_DRIVER_ENTRY *DriverEntry;
    628 
    629   //
    630   // Process Before Dependency
    631   //
    632   for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
    633     DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
    634     if (DriverEntry->Before && DriverEntry->Dependent && DriverEntry != InsertedDriverEntry) {
    635       DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
    636       DEBUG ((DEBUG_DISPATCH, "  BEFORE FFS(%g) = ", &DriverEntry->BeforeAfterGuid));
    637       if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
    638         //
    639         // Recursively process BEFORE
    640         //
    641         DEBUG ((DEBUG_DISPATCH, "TRUE\n  END\n  RESULT = TRUE\n"));
    642         CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
    643       } else {
    644         DEBUG ((DEBUG_DISPATCH, "FALSE\n  END\n  RESULT = FALSE\n"));
    645       }
    646     }
    647   }
    648 
    649   //
    650   // Convert driver from Dependent to Scheduled state
    651   //
    652   CoreAcquireDispatcherLock ();
    653 
    654   InsertedDriverEntry->Dependent = FALSE;
    655   InsertedDriverEntry->Scheduled = TRUE;
    656   InsertTailList (&mScheduledQueue, &InsertedDriverEntry->ScheduledLink);
    657 
    658   CoreReleaseDispatcherLock ();
    659 
    660   //
    661   // Process After Dependency
    662   //
    663   for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
    664     DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
    665     if (DriverEntry->After && DriverEntry->Dependent && DriverEntry != InsertedDriverEntry) {
    666       DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
    667       DEBUG ((DEBUG_DISPATCH, "  AFTER FFS(%g) = ", &DriverEntry->BeforeAfterGuid));
    668       if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
    669         //
    670         // Recursively process AFTER
    671         //
    672         DEBUG ((DEBUG_DISPATCH, "TRUE\n  END\n  RESULT = TRUE\n"));
    673         CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
    674       } else {
    675         DEBUG ((DEBUG_DISPATCH, "FALSE\n  END\n  RESULT = FALSE\n"));
    676       }
    677     }
    678   }
    679 }
    680 
    681 
    682 /**
    683   Return TRUE if the Fv has been processed, FALSE if not.
    684 
    685   @param  FvHandle              The handle of a FV that's being tested
    686 
    687   @retval TRUE                  Fv protocol on FvHandle has been processed
    688   @retval FALSE                 Fv protocol on FvHandle has not yet been processed
    689 
    690 **/
    691 BOOLEAN
    692 FvHasBeenProcessed (
    693   IN  EFI_HANDLE      FvHandle
    694   )
    695 {
    696   LIST_ENTRY      *Link;
    697   KNOWN_HANDLE    *KnownHandle;
    698 
    699   for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) {
    700     KnownHandle = CR(Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE);
    701     if (KnownHandle->Handle == FvHandle) {
    702       return TRUE;
    703     }
    704   }
    705   return FALSE;
    706 }
    707 
    708 
    709 /**
    710   Remember that Fv protocol on FvHandle has had it's drivers placed on the
    711   mDiscoveredList. This fucntion adds entries on the mFvHandleList if new
    712   entry is different from one in mFvHandleList by checking FvImage Guid.
    713   Items are never removed/freed from the mFvHandleList.
    714 
    715   @param  FvHandle              The handle of a FV that has been processed
    716 
    717   @return A point to new added FvHandle entry. If FvHandle with the same FvImage guid
    718           has been added, NULL will return.
    719 
    720 **/
    721 KNOWN_HANDLE *
    722 FvIsBeingProcesssed (
    723   IN  EFI_HANDLE    FvHandle
    724   )
    725 {
    726   EFI_STATUS                            Status;
    727   EFI_GUID                              FvNameGuid;
    728   BOOLEAN                               FvNameGuidIsFound;
    729   UINT32                                ExtHeaderOffset;
    730   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *Fvb;
    731   EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;
    732   EFI_FV_BLOCK_MAP_ENTRY                *BlockMap;
    733   UINTN                                 LbaOffset;
    734   UINTN                                 Index;
    735   EFI_LBA                               LbaIndex;
    736   LIST_ENTRY                            *Link;
    737   KNOWN_HANDLE                          *KnownHandle;
    738 
    739   FwVolHeader = NULL;
    740 
    741   //
    742   // Get the FirmwareVolumeBlock protocol on that handle
    743   //
    744   FvNameGuidIsFound = FALSE;
    745   Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);
    746   if (!EFI_ERROR (Status)) {
    747     //
    748     // Get the full FV header based on FVB protocol.
    749     //
    750     ASSERT (Fvb != NULL);
    751     Status = GetFwVolHeader (Fvb, &FwVolHeader);
    752     if (!EFI_ERROR (Status)) {
    753       ASSERT (FwVolHeader != NULL);
    754       if (VerifyFvHeaderChecksum (FwVolHeader) && FwVolHeader->ExtHeaderOffset != 0) {
    755         ExtHeaderOffset = (UINT32) FwVolHeader->ExtHeaderOffset;
    756         BlockMap  = FwVolHeader->BlockMap;
    757         LbaIndex  = 0;
    758         LbaOffset = 0;
    759         //
    760         // Find LbaIndex and LbaOffset for FV extension header based on BlockMap.
    761         //
    762         while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {
    763           for (Index = 0; Index < BlockMap->NumBlocks && ExtHeaderOffset >= BlockMap->Length; Index ++) {
    764             ExtHeaderOffset -= BlockMap->Length;
    765             LbaIndex ++;
    766           }
    767           //
    768           // Check whether FvExtHeader is crossing the multi block range.
    769           //
    770           if (Index < BlockMap->NumBlocks) {
    771             LbaOffset = ExtHeaderOffset;
    772             break;
    773           }
    774           BlockMap++;
    775         }
    776         //
    777         // Read FvNameGuid from FV extension header.
    778         //
    779         Status = ReadFvbData (Fvb, &LbaIndex, &LbaOffset, sizeof (FvNameGuid), (UINT8 *) &FvNameGuid);
    780         if (!EFI_ERROR (Status)) {
    781           FvNameGuidIsFound = TRUE;
    782         }
    783       }
    784       CoreFreePool (FwVolHeader);
    785     }
    786   }
    787 
    788   if (FvNameGuidIsFound) {
    789     //
    790     // Check whether the FV image with the found FvNameGuid has been processed.
    791     //
    792     for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) {
    793       KnownHandle = CR(Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE);
    794       if (CompareGuid (&FvNameGuid, &KnownHandle->FvNameGuid)) {
    795         DEBUG ((EFI_D_ERROR, "FvImage on FvHandle %p and %p has the same FvNameGuid %g.\n", FvHandle, KnownHandle->Handle, FvNameGuid));
    796         return NULL;
    797       }
    798     }
    799   }
    800 
    801   KnownHandle = AllocateZeroPool (sizeof (KNOWN_HANDLE));
    802   ASSERT (KnownHandle != NULL);
    803 
    804   KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE;
    805   KnownHandle->Handle = FvHandle;
    806   if (FvNameGuidIsFound) {
    807     CopyGuid (&KnownHandle->FvNameGuid, &FvNameGuid);
    808   }
    809   InsertTailList (&mFvHandleList, &KnownHandle->Link);
    810   return KnownHandle;
    811 }
    812 
    813 
    814 
    815 
    816 /**
    817   Convert FvHandle and DriverName into an EFI device path
    818 
    819   @param  Fv                    Fv protocol, needed to read Depex info out of
    820                                 FLASH.
    821   @param  FvHandle              Handle for Fv, needed in the
    822                                 EFI_CORE_DRIVER_ENTRY so that the PE image can be
    823                                 read out of the FV at a later time.
    824   @param  DriverName            Name of driver to add to mDiscoveredList.
    825 
    826   @return Pointer to device path constructed from FvHandle and DriverName
    827 
    828 **/
    829 EFI_DEVICE_PATH_PROTOCOL *
    830 CoreFvToDevicePath (
    831   IN  EFI_FIRMWARE_VOLUME2_PROTOCOL   *Fv,
    832   IN  EFI_HANDLE                      FvHandle,
    833   IN  EFI_GUID                        *DriverName
    834   )
    835 {
    836   EFI_STATUS                          Status;
    837   EFI_DEVICE_PATH_PROTOCOL            *FvDevicePath;
    838   EFI_DEVICE_PATH_PROTOCOL            *FileNameDevicePath;
    839 
    840   //
    841   // Remember the device path of the FV
    842   //
    843   Status = CoreHandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
    844   if (EFI_ERROR (Status)) {
    845     FileNameDevicePath = NULL;
    846   } else {
    847     //
    848     // Build a device path to the file in the FV to pass into gBS->LoadImage
    849     //
    850     EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, DriverName);
    851     SetDevicePathEndNode (&mFvDevicePath.End);
    852 
    853     FileNameDevicePath = AppendDevicePath (
    854                             FvDevicePath,
    855                             (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath
    856                             );
    857   }
    858 
    859   return FileNameDevicePath;
    860 }
    861 
    862 
    863 
    864 /**
    865   Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
    866   and initilize any state variables. Read the Depex from the FV and store it
    867   in DriverEntry. Pre-process the Depex to set the SOR, Before and After state.
    868   The Discovered list is never free'ed and contains booleans that represent the
    869   other possible DXE driver states.
    870 
    871   @param  Fv                    Fv protocol, needed to read Depex info out of
    872                                 FLASH.
    873   @param  FvHandle              Handle for Fv, needed in the
    874                                 EFI_CORE_DRIVER_ENTRY so that the PE image can be
    875                                 read out of the FV at a later time.
    876   @param  DriverName            Name of driver to add to mDiscoveredList.
    877   @param  Type                  Fv File Type of file to add to mDiscoveredList.
    878 
    879   @retval EFI_SUCCESS           If driver was added to the mDiscoveredList.
    880   @retval EFI_ALREADY_STARTED   The driver has already been started. Only one
    881                                 DriverName may be active in the system at any one
    882                                 time.
    883 
    884 **/
    885 EFI_STATUS
    886 CoreAddToDriverList (
    887   IN  EFI_FIRMWARE_VOLUME2_PROTOCOL   *Fv,
    888   IN  EFI_HANDLE                      FvHandle,
    889   IN  EFI_GUID                        *DriverName,
    890   IN  EFI_FV_FILETYPE                 Type
    891   )
    892 {
    893   EFI_CORE_DRIVER_ENTRY               *DriverEntry;
    894 
    895 
    896   //
    897   // Create the Driver Entry for the list. ZeroPool initializes lots of variables to
    898   // NULL or FALSE.
    899   //
    900   DriverEntry = AllocateZeroPool (sizeof (EFI_CORE_DRIVER_ENTRY));
    901   ASSERT (DriverEntry != NULL);
    902   if (Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
    903     DriverEntry->IsFvImage = TRUE;
    904   }
    905 
    906   DriverEntry->Signature        = EFI_CORE_DRIVER_ENTRY_SIGNATURE;
    907   CopyGuid (&DriverEntry->FileName, DriverName);
    908   DriverEntry->FvHandle         = FvHandle;
    909   DriverEntry->Fv               = Fv;
    910   DriverEntry->FvFileDevicePath = CoreFvToDevicePath (Fv, FvHandle, DriverName);
    911 
    912   CoreGetDepexSectionAndPreProccess (DriverEntry);
    913 
    914   CoreAcquireDispatcherLock ();
    915 
    916   InsertTailList (&mDiscoveredList, &DriverEntry->Link);
    917 
    918   CoreReleaseDispatcherLock ();
    919 
    920   return EFI_SUCCESS;
    921 }
    922 
    923 
    924 /**
    925   Check if a FV Image type file (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) is
    926   described by a EFI_HOB_FIRMWARE_VOLUME2 Hob.
    927 
    928   @param  FvNameGuid            The FV image guid specified.
    929   @param  DriverName            The driver guid specified.
    930 
    931   @retval TRUE                  This file is found in a EFI_HOB_FIRMWARE_VOLUME2
    932                                 Hob.
    933   @retval FALSE                 Not found.
    934 
    935 **/
    936 BOOLEAN
    937 FvFoundInHobFv2 (
    938   IN  CONST EFI_GUID                  *FvNameGuid,
    939   IN  CONST EFI_GUID                  *DriverName
    940   )
    941 {
    942   EFI_PEI_HOB_POINTERS                HobFv2;
    943 
    944   HobFv2.Raw = GetHobList ();
    945 
    946   while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) {
    947     //
    948     // Compare parent FvNameGuid and FileGuid both.
    949     //
    950     if (CompareGuid (DriverName, &HobFv2.FirmwareVolume2->FileName) &&
    951         CompareGuid (FvNameGuid, &HobFv2.FirmwareVolume2->FvName)) {
    952       return TRUE;
    953     }
    954     HobFv2.Raw = GET_NEXT_HOB (HobFv2);
    955   }
    956 
    957   return FALSE;
    958 }
    959 
    960 
    961 
    962 /**
    963   Get the driver from the FV through driver name, and produce a FVB protocol on FvHandle.
    964 
    965   @param  Fv                    The FIRMWARE_VOLUME protocol installed on the FV.
    966   @param  FvHandle              The handle which FVB protocol installed on.
    967   @param  DriverName            The driver guid specified.
    968 
    969   @retval EFI_OUT_OF_RESOURCES  No enough memory or other resource.
    970   @retval EFI_VOLUME_CORRUPTED  Corrupted volume.
    971   @retval EFI_SUCCESS           Function successfully returned.
    972 
    973 **/
    974 EFI_STATUS
    975 CoreProcessFvImageFile (
    976   IN  EFI_FIRMWARE_VOLUME2_PROTOCOL   *Fv,
    977   IN  EFI_HANDLE                      FvHandle,
    978   IN  EFI_GUID                        *DriverName
    979   )
    980 {
    981   EFI_STATUS                          Status;
    982   EFI_SECTION_TYPE                    SectionType;
    983   UINT32                              AuthenticationStatus;
    984   VOID                                *Buffer;
    985   VOID                                *AlignedBuffer;
    986   UINTN                               BufferSize;
    987   EFI_FIRMWARE_VOLUME_HEADER          *FvHeader;
    988   UINT32                              FvAlignment;
    989   EFI_DEVICE_PATH_PROTOCOL            *FvFileDevicePath;
    990 
    991   //
    992   // Read the first (and only the first) firmware volume section
    993   //
    994   SectionType   = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;
    995   FvHeader      = NULL;
    996   FvAlignment   = 0;
    997   Buffer        = NULL;
    998   BufferSize    = 0;
    999   AlignedBuffer = NULL;
   1000   Status = Fv->ReadSection (
   1001                  Fv,
   1002                  DriverName,
   1003                  SectionType,
   1004                  0,
   1005                  &Buffer,
   1006                  &BufferSize,
   1007                  &AuthenticationStatus
   1008                  );
   1009   if (!EFI_ERROR (Status)) {
   1010      //
   1011     // Evaluate the authentication status of the Firmware Volume through
   1012     // Security Architectural Protocol
   1013     //
   1014     if (gSecurity != NULL) {
   1015       FvFileDevicePath = CoreFvToDevicePath (Fv, FvHandle, DriverName);
   1016       Status = gSecurity->FileAuthenticationState (
   1017                             gSecurity,
   1018                             AuthenticationStatus,
   1019                             FvFileDevicePath
   1020                             );
   1021       if (FvFileDevicePath != NULL) {
   1022         FreePool (FvFileDevicePath);
   1023       }
   1024 
   1025       if (Status != EFI_SUCCESS) {
   1026         //
   1027         // Security check failed. The firmware volume should not be used for any purpose.
   1028         //
   1029         if (Buffer != NULL) {
   1030           FreePool (Buffer);
   1031         }
   1032         return Status;
   1033       }
   1034     }
   1035 
   1036     //
   1037     // FvImage should be at its required alignment.
   1038     //
   1039     FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) Buffer;
   1040     //
   1041     // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
   1042     // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
   1043     // its initial linked location and maintain its alignment.
   1044     //
   1045     if ((FvHeader->Attributes & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {
   1046       //
   1047       // Get FvHeader alignment
   1048       //
   1049       FvAlignment = 1 << ((FvHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16);
   1050       //
   1051       // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
   1052       //
   1053       if (FvAlignment < 8) {
   1054         FvAlignment = 8;
   1055       }
   1056       //
   1057       // Allocate the aligned buffer for the FvImage.
   1058       //
   1059       AlignedBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), (UINTN) FvAlignment);
   1060       if (AlignedBuffer == NULL) {
   1061         FreePool (Buffer);
   1062         return EFI_OUT_OF_RESOURCES;
   1063       } else {
   1064         //
   1065         // Move FvImage into the aligned buffer and release the original buffer.
   1066         //
   1067         CopyMem (AlignedBuffer, Buffer, BufferSize);
   1068         FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) AlignedBuffer;
   1069         CoreFreePool (Buffer);
   1070         Buffer = NULL;
   1071       }
   1072     }
   1073     //
   1074     // Produce a FVB protocol for the file
   1075     //
   1076     Status = ProduceFVBProtocolOnBuffer (
   1077               (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader,
   1078               (UINT64)BufferSize,
   1079               FvHandle,
   1080               AuthenticationStatus,
   1081               NULL
   1082               );
   1083   }
   1084 
   1085   if (EFI_ERROR (Status)) {
   1086     //
   1087     // ReadSection or Produce FVB failed, Free data buffer
   1088     //
   1089     if (Buffer != NULL) {
   1090       FreePool (Buffer);
   1091     }
   1092 
   1093     if (AlignedBuffer != NULL) {
   1094       FreeAlignedPages (AlignedBuffer, EFI_SIZE_TO_PAGES (BufferSize));
   1095     }
   1096   }
   1097 
   1098   return Status;
   1099 }
   1100 
   1101 
   1102 /**
   1103   Event notification that is fired every time a FV dispatch protocol is added.
   1104   More than one protocol may have been added when this event is fired, so you
   1105   must loop on CoreLocateHandle () to see how many protocols were added and
   1106   do the following to each FV:
   1107   If the Fv has already been processed, skip it. If the Fv has not been
   1108   processed then mark it as being processed, as we are about to process it.
   1109   Read the Fv and add any driver in the Fv to the mDiscoveredList.The
   1110   mDiscoveredList is never free'ed and contains variables that define
   1111   the other states the DXE driver transitions to..
   1112   While you are at it read the A Priori file into memory.
   1113   Place drivers in the A Priori list onto the mScheduledQueue.
   1114 
   1115   @param  Event                 The Event that is being processed, not used.
   1116   @param  Context               Event Context, not used.
   1117 
   1118 **/
   1119 VOID
   1120 EFIAPI
   1121 CoreFwVolEventProtocolNotify (
   1122   IN  EFI_EVENT       Event,
   1123   IN  VOID            *Context
   1124   )
   1125 {
   1126   EFI_STATUS                    Status;
   1127   EFI_STATUS                    GetNextFileStatus;
   1128   EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
   1129   EFI_DEVICE_PATH_PROTOCOL      *FvDevicePath;
   1130   EFI_HANDLE                    FvHandle;
   1131   UINTN                         BufferSize;
   1132   EFI_GUID                      NameGuid;
   1133   UINTN                         Key;
   1134   EFI_FV_FILETYPE               Type;
   1135   EFI_FV_FILE_ATTRIBUTES        Attributes;
   1136   UINTN                         Size;
   1137   EFI_CORE_DRIVER_ENTRY         *DriverEntry;
   1138   EFI_GUID                      *AprioriFile;
   1139   UINTN                         AprioriEntryCount;
   1140   UINTN                         Index;
   1141   LIST_ENTRY                    *Link;
   1142   UINT32                        AuthenticationStatus;
   1143   UINTN                         SizeOfBuffer;
   1144   VOID                          *DepexBuffer;
   1145   KNOWN_HANDLE                  *KnownHandle;
   1146 
   1147   FvHandle = NULL;
   1148 
   1149   while (TRUE) {
   1150     BufferSize = sizeof (EFI_HANDLE);
   1151     Status = CoreLocateHandle (
   1152                ByRegisterNotify,
   1153                NULL,
   1154                mFwVolEventRegistration,
   1155                &BufferSize,
   1156                &FvHandle
   1157                );
   1158     if (EFI_ERROR (Status)) {
   1159       //
   1160       // If no more notification events exit
   1161       //
   1162       return;
   1163     }
   1164 
   1165     if (FvHasBeenProcessed (FvHandle)) {
   1166       //
   1167       // This Fv has already been processed so lets skip it!
   1168       //
   1169       continue;
   1170     }
   1171 
   1172     //
   1173     // Since we are about to process this Fv mark it as processed.
   1174     //
   1175     KnownHandle = FvIsBeingProcesssed (FvHandle);
   1176     if (KnownHandle == NULL) {
   1177       //
   1178       // The FV with the same FV name guid has already been processed.
   1179       // So lets skip it!
   1180       //
   1181       continue;
   1182     }
   1183 
   1184     Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);
   1185     if (EFI_ERROR (Status) || Fv == NULL) {
   1186       //
   1187       // FvHandle must have Firmware Volume2 protocol thus we should never get here.
   1188       //
   1189       ASSERT (FALSE);
   1190       continue;
   1191     }
   1192 
   1193     Status = CoreHandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
   1194     if (EFI_ERROR (Status)) {
   1195       //
   1196       // The Firmware volume doesn't have device path, can't be dispatched.
   1197       //
   1198       continue;
   1199     }
   1200 
   1201     //
   1202     // Discover Drivers in FV and add them to the Discovered Driver List.
   1203     // Process EFI_FV_FILETYPE_DRIVER type and then EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
   1204     //  EFI_FV_FILETYPE_DXE_CORE is processed to produce a Loaded Image protocol for the core
   1205     //  EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE is processed to create a Fvb
   1206     //
   1207     for (Index = 0; Index < sizeof (mDxeFileTypes) / sizeof (EFI_FV_FILETYPE); Index++) {
   1208       //
   1209       // Initialize the search key
   1210       //
   1211       Key = 0;
   1212       do {
   1213         Type = mDxeFileTypes[Index];
   1214         GetNextFileStatus = Fv->GetNextFile (
   1215                                   Fv,
   1216                                   &Key,
   1217                                   &Type,
   1218                                   &NameGuid,
   1219                                   &Attributes,
   1220                                   &Size
   1221                                   );
   1222         if (!EFI_ERROR (GetNextFileStatus)) {
   1223           if (Type == EFI_FV_FILETYPE_DXE_CORE) {
   1224             //
   1225             // If this is the DXE core fill in it's DevicePath & DeviceHandle
   1226             //
   1227             if (gDxeCoreLoadedImage->FilePath == NULL) {
   1228               if (CompareGuid (&NameGuid, gDxeCoreFileName)) {
   1229                 //
   1230                 // Maybe One specail Fv cantains only one DXE_CORE module, so its device path must
   1231                 // be initialized completely.
   1232                 //
   1233                 EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid);
   1234                 SetDevicePathEndNode (&mFvDevicePath.End);
   1235 
   1236                 gDxeCoreLoadedImage->FilePath = DuplicateDevicePath (
   1237                                                   (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath
   1238                                                   );
   1239                 gDxeCoreLoadedImage->DeviceHandle = FvHandle;
   1240               }
   1241             }
   1242           } else if (Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
   1243             //
   1244             // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
   1245             // been extracted.
   1246             //
   1247             if (FvFoundInHobFv2 (&KnownHandle->FvNameGuid, &NameGuid)) {
   1248               continue;
   1249             }
   1250 
   1251             //
   1252             // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has PEI depex section.
   1253             //
   1254             DepexBuffer  = NULL;
   1255             SizeOfBuffer = 0;
   1256             Status = Fv->ReadSection (
   1257                            Fv,
   1258                            &NameGuid,
   1259                            EFI_SECTION_PEI_DEPEX,
   1260                            0,
   1261                            &DepexBuffer,
   1262                            &SizeOfBuffer,
   1263                            &AuthenticationStatus
   1264                            );
   1265             if (!EFI_ERROR (Status)) {
   1266               //
   1267               // If PEI depex section is found, this FV image will be ignored in DXE phase.
   1268               // Now, DxeCore doesn't support FV image with more one type DEPEX section.
   1269               //
   1270               FreePool (DepexBuffer);
   1271               continue;
   1272             }
   1273 
   1274             //
   1275             // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has SMM depex section.
   1276             //
   1277             DepexBuffer  = NULL;
   1278             SizeOfBuffer = 0;
   1279             Status = Fv->ReadSection (
   1280                            Fv,
   1281                            &NameGuid,
   1282                            EFI_SECTION_SMM_DEPEX,
   1283                            0,
   1284                            &DepexBuffer,
   1285                            &SizeOfBuffer,
   1286                            &AuthenticationStatus
   1287                            );
   1288             if (!EFI_ERROR (Status)) {
   1289               //
   1290               // If SMM depex section is found, this FV image will be ignored in DXE phase.
   1291               // Now, DxeCore doesn't support FV image with more one type DEPEX section.
   1292               //
   1293               FreePool (DepexBuffer);
   1294               continue;
   1295             }
   1296 
   1297             //
   1298             // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has DXE depex section.
   1299             //
   1300             DepexBuffer  = NULL;
   1301             SizeOfBuffer = 0;
   1302             Status = Fv->ReadSection (
   1303                            Fv,
   1304                            &NameGuid,
   1305                            EFI_SECTION_DXE_DEPEX,
   1306                            0,
   1307                            &DepexBuffer,
   1308                            &SizeOfBuffer,
   1309                            &AuthenticationStatus
   1310                            );
   1311             if (EFI_ERROR (Status)) {
   1312               //
   1313               // If no depex section, produce a firmware volume block protocol for it so it gets dispatched from.
   1314               //
   1315               CoreProcessFvImageFile (Fv, FvHandle, &NameGuid);
   1316             } else {
   1317               //
   1318               // If depex section is found, this FV image will be dispatched until its depex is evaluated to TRUE.
   1319               //
   1320               FreePool (DepexBuffer);
   1321               CoreAddToDriverList (Fv, FvHandle, &NameGuid, Type);
   1322             }
   1323           } else {
   1324             //
   1325             // Transition driver from Undiscovered to Discovered state
   1326             //
   1327             CoreAddToDriverList (Fv, FvHandle, &NameGuid, Type);
   1328           }
   1329         }
   1330       } while (!EFI_ERROR (GetNextFileStatus));
   1331     }
   1332 
   1333     //
   1334     // Read the array of GUIDs from the Apriori file if it is present in the firmware volume
   1335     //
   1336     AprioriFile = NULL;
   1337     Status = Fv->ReadSection (
   1338                   Fv,
   1339                   &gAprioriGuid,
   1340                   EFI_SECTION_RAW,
   1341                   0,
   1342                   (VOID **)&AprioriFile,
   1343                   &SizeOfBuffer,
   1344                   &AuthenticationStatus
   1345                   );
   1346     if (!EFI_ERROR (Status)) {
   1347       AprioriEntryCount = SizeOfBuffer / sizeof (EFI_GUID);
   1348     } else {
   1349       AprioriEntryCount = 0;
   1350     }
   1351 
   1352     //
   1353     // Put drivers on Apriori List on the Scheduled queue. The Discovered List includes
   1354     // drivers not in the current FV and these must be skipped since the a priori list
   1355     // is only valid for the FV that it resided in.
   1356     //
   1357 
   1358     for (Index = 0; Index < AprioriEntryCount; Index++) {
   1359       for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
   1360         DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
   1361         if (CompareGuid (&DriverEntry->FileName, &AprioriFile[Index]) &&
   1362             (FvHandle == DriverEntry->FvHandle)) {
   1363           CoreAcquireDispatcherLock ();
   1364           DriverEntry->Dependent = FALSE;
   1365           DriverEntry->Scheduled = TRUE;
   1366           InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);
   1367           CoreReleaseDispatcherLock ();
   1368           DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
   1369           DEBUG ((DEBUG_DISPATCH, "  RESULT = TRUE (Apriori)\n"));
   1370           break;
   1371         }
   1372       }
   1373     }
   1374 
   1375     //
   1376     // Free data allocated by Fv->ReadSection ()
   1377     //
   1378     CoreFreePool (AprioriFile);
   1379   }
   1380 }
   1381 
   1382 
   1383 
   1384 /**
   1385   Initialize the dispatcher. Initialize the notification function that runs when
   1386   an FV2 protocol is added to the system.
   1387 
   1388 **/
   1389 VOID
   1390 CoreInitializeDispatcher (
   1391   VOID
   1392   )
   1393 {
   1394   mFwVolEvent = EfiCreateProtocolNotifyEvent (
   1395                   &gEfiFirmwareVolume2ProtocolGuid,
   1396                   TPL_CALLBACK,
   1397                   CoreFwVolEventProtocolNotify,
   1398                   NULL,
   1399                   &mFwVolEventRegistration
   1400                   );
   1401 }
   1402 
   1403 //
   1404 // Function only used in debug builds
   1405 //
   1406 
   1407 /**
   1408   Traverse the discovered list for any drivers that were discovered but not loaded
   1409   because the dependency experessions evaluated to false.
   1410 
   1411 **/
   1412 VOID
   1413 CoreDisplayDiscoveredNotDispatched (
   1414   VOID
   1415   )
   1416 {
   1417   LIST_ENTRY                    *Link;
   1418   EFI_CORE_DRIVER_ENTRY         *DriverEntry;
   1419 
   1420   for (Link = mDiscoveredList.ForwardLink;Link !=&mDiscoveredList; Link = Link->ForwardLink) {
   1421     DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
   1422     if (DriverEntry->Dependent) {
   1423       DEBUG ((DEBUG_LOAD, "Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName));
   1424     }
   1425   }
   1426 }
   1427