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