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
CoreAcquireDispatcherLock(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
CoreReleaseDispatcherLock(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
CoreGetDepexSectionAndPreProccess(IN EFI_CORE_DRIVER_ENTRY * DriverEntry)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
CoreSchedule(IN EFI_HANDLE FirmwareVolumeHandle,IN EFI_GUID * DriverName)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
CoreTrust(IN EFI_HANDLE FirmwareVolumeHandle,IN EFI_GUID * DriverName)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
CoreEmptyCallbackFunction(IN EFI_EVENT Event,IN VOID * Context)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
CoreDispatcher(VOID)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
CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter(IN EFI_CORE_DRIVER_ENTRY * InsertedDriverEntry)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
FvHasBeenProcessed(IN EFI_HANDLE FvHandle)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 *
FvIsBeingProcesssed(IN EFI_HANDLE FvHandle)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 *
CoreFvToDevicePath(IN EFI_FIRMWARE_VOLUME2_PROTOCOL * Fv,IN EFI_HANDLE FvHandle,IN EFI_GUID * DriverName)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
CoreAddToDriverList(IN EFI_FIRMWARE_VOLUME2_PROTOCOL * Fv,IN EFI_HANDLE FvHandle,IN EFI_GUID * DriverName,IN EFI_FV_FILETYPE Type)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
FvFoundInHobFv2(IN CONST EFI_GUID * FvNameGuid,IN CONST EFI_GUID * DriverName)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
CoreProcessFvImageFile(IN EFI_FIRMWARE_VOLUME2_PROTOCOL * Fv,IN EFI_HANDLE FvHandle,IN EFI_GUID * DriverName)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
CoreFwVolEventProtocolNotify(IN EFI_EVENT Event,IN VOID * Context)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
CoreInitializeDispatcher(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
CoreDisplayDiscoveredNotDispatched(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