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.
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.
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.
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
26 Depex - Dependency Expresion.
27 SOR - Schedule On Request - Don't schedule if this bit is set.
29 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
30 SPDX-License-Identifier: BSD-2-Clause-Patent
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
40 LIST_ENTRY mDiscoveredList
= INITIALIZE_LIST_HEAD_VARIABLE (mDiscoveredList
);
43 // Queue of drivers that are ready to dispatch. This queue is a subset of the
44 // mDiscoveredList.list of EFI_CORE_DRIVER_ENTRY.
46 LIST_ENTRY mScheduledQueue
= INITIALIZE_LIST_HEAD_VARIABLE (mScheduledQueue
);
49 // List of handles who's Fv's have been parsed and added to the mFwDriverList.
51 LIST_ENTRY mFvHandleList
= INITIALIZE_LIST_HEAD_VARIABLE (mFvHandleList
); // list of KNOWN_HANDLE
54 // Lock for mDiscoveredList, mScheduledQueue, gDispatcherRunning.
56 EFI_LOCK mDispatcherLock
= EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL
);
60 // Flag for the DXE Dispacher. TRUE if dispatcher is execuing.
62 BOOLEAN gDispatcherRunning
= FALSE
;
65 // Module globals to manage the FwVol registration notification event
67 EFI_EVENT mFwVolEvent
;
68 VOID
*mFwVolEventRegistration
;
71 // List of file types supported by dispatcher
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
82 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH File
;
83 EFI_DEVICE_PATH_PROTOCOL End
;
84 } FV_FILEPATH_DEVICE_PATH
;
86 FV_FILEPATH_DEVICE_PATH mFvDevicePath
;
89 // Function Prototypes
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.
99 @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue
103 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
104 IN EFI_CORE_DRIVER_ENTRY
*InsertedDriverEntry
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.
120 @param Event The Event that is being processed, not used.
121 @param Context Event Context, not used.
126 CoreFwVolEventProtocolNotify (
132 Convert FvHandle and DriverName into an EFI device path
134 @param Fv Fv protocol, needed to read Depex info out of
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.
141 @return Pointer to device path constructed from FvHandle and DriverName
144 EFI_DEVICE_PATH_PROTOCOL
*
146 IN EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
,
147 IN EFI_HANDLE FvHandle
,
148 IN EFI_GUID
*DriverName
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.
158 @param Fv Fv protocol, needed to read Depex info out of
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.
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
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
181 Get Fv image(s) from the FV through file name, and produce FVB protocol for every Fv image(s).
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.
187 @retval EFI_OUT_OF_RESOURCES No enough memory or other resource.
188 @retval EFI_SUCCESS Function successfully returned.
192 CoreProcessFvImageFile (
193 IN EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
,
194 IN EFI_HANDLE FvHandle
,
195 IN EFI_GUID
*FileName
200 Enter critical section by gaining lock on mDispatcherLock.
204 CoreAcquireDispatcherLock (
208 CoreAcquireLock (&mDispatcherLock
);
213 Exit critical section by releasing lock on mDispatcherLock.
217 CoreReleaseDispatcherLock (
221 CoreReleaseLock (&mDispatcherLock
);
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.
229 @param DriverEntry Driver to work on.
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.
238 CoreGetDepexSectionAndPreProccess (
239 IN EFI_CORE_DRIVER_ENTRY
*DriverEntry
243 EFI_SECTION_TYPE SectionType
;
244 UINT32 AuthenticationStatus
;
245 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
248 Fv
= DriverEntry
->Fv
;
251 // Grab Depex info, it will never be free'ed.
253 SectionType
= EFI_SECTION_DXE_DEPEX
;
254 Status
= Fv
->ReadSection (
256 &DriverEntry
->FileName
,
260 (UINTN
*)&DriverEntry
->DepexSize
,
261 &AuthenticationStatus
263 if (EFI_ERROR (Status
)) {
264 if (Status
== EFI_PROTOCOL_ERROR
) {
266 // The section extraction protocol failed so set protocol error flag
268 DriverEntry
->DepexProtocolError
= TRUE
;
271 // If no Depex assume UEFI 2.0 driver model
273 DriverEntry
->Depex
= NULL
;
274 DriverEntry
->Dependent
= TRUE
;
275 DriverEntry
->DepexProtocolError
= FALSE
;
279 // Set Before, After, and Unrequested state information based on Depex
280 // Driver will be put in Dependent or Unrequested state
282 CorePreProcessDepex (DriverEntry
);
283 DriverEntry
->DepexProtocolError
= FALSE
;
291 Check every driver and locate a matching one. If the driver is found, the Unrequested
292 state flag is cleared.
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.
298 @retval EFI_SUCCESS The DriverName was found and it's SOR bit was
300 @retval EFI_NOT_FOUND The DriverName does not exist or it's SOR bit was
307 IN EFI_HANDLE FirmwareVolumeHandle
,
308 IN EFI_GUID
*DriverName
312 EFI_CORE_DRIVER_ENTRY
*DriverEntry
;
315 // Check every driver
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
)) {
323 // Move the driver from the Unrequested to the Dependent state
325 CoreAcquireDispatcherLock ();
326 DriverEntry
->Unrequested
= FALSE
;
327 DriverEntry
->Dependent
= TRUE
;
328 CoreReleaseDispatcherLock ();
330 DEBUG ((DEBUG_DISPATCH
, "Schedule FFS(%g) - EFI_SUCCESS\n", DriverName
));
336 DEBUG ((DEBUG_DISPATCH
, "Schedule FFS(%g) - EFI_NOT_FOUND\n", DriverName
));
338 return EFI_NOT_FOUND
;
344 Convert a driver from the Untrused back to the Scheduled state.
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
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.
358 IN EFI_HANDLE FirmwareVolumeHandle
,
359 IN EFI_GUID
*DriverName
363 EFI_CORE_DRIVER_ENTRY
*DriverEntry
;
366 // Check every driver
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
)) {
374 // Transition driver from Untrusted to Scheduled state.
376 CoreAcquireDispatcherLock ();
377 DriverEntry
->Untrusted
= FALSE
;
378 DriverEntry
->Scheduled
= TRUE
;
379 InsertTailList (&mScheduledQueue
, &DriverEntry
->ScheduledLink
);
380 CoreReleaseDispatcherLock ();
385 return EFI_NOT_FOUND
;
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
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
409 EFI_STATUS ReturnStatus
;
411 EFI_CORE_DRIVER_ENTRY
*DriverEntry
;
413 EFI_EVENT DxeDispatchEvent
;
415 PERF_FUNCTION_BEGIN ();
417 if (gDispatcherRunning
) {
419 // If the dispatcher is running don't let it be restarted.
421 return EFI_ALREADY_STARTED
;
424 gDispatcherRunning
= TRUE
;
426 Status
= CoreCreateEventEx (
429 EfiEventEmptyFunction
,
431 &gEfiEventDxeDispatchGuid
,
434 if (EFI_ERROR (Status
)) {
438 ReturnStatus
= EFI_NOT_FOUND
;
441 // Drain the Scheduled Queue
443 while (!IsListEmpty (&mScheduledQueue
)) {
445 mScheduledQueue
.ForwardLink
,
446 EFI_CORE_DRIVER_ENTRY
,
448 EFI_CORE_DRIVER_ENTRY_SIGNATURE
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
456 if (DriverEntry
->ImageHandle
== NULL
&& !DriverEntry
->IsFvImage
) {
457 DEBUG ((DEBUG_INFO
, "Loading driver %g\n", &DriverEntry
->FileName
));
458 Status
= CoreLoadImage (
461 DriverEntry
->FvFileDevicePath
,
464 &DriverEntry
->ImageHandle
468 // Update the driver state to reflect that it's been loaded
470 if (EFI_ERROR (Status
)) {
471 CoreAcquireDispatcherLock ();
473 if (Status
== EFI_SECURITY_VIOLATION
) {
475 // Take driver from Scheduled to Untrused state
477 DriverEntry
->Untrusted
= TRUE
;
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.
483 // This case include the Never Trusted state if EFI_ACCESS_DENIED is returned
485 DriverEntry
->Initialized
= TRUE
;
488 DriverEntry
->Scheduled
= FALSE
;
489 RemoveEntryList (&DriverEntry
->ScheduledLink
);
491 CoreReleaseDispatcherLock ();
494 // If it's an error don't try the StartImage
500 CoreAcquireDispatcherLock ();
502 DriverEntry
->Scheduled
= FALSE
;
503 DriverEntry
->Initialized
= TRUE
;
504 RemoveEntryList (&DriverEntry
->ScheduledLink
);
506 CoreReleaseDispatcherLock ();
509 if (DriverEntry
->IsFvImage
) {
511 // Produce a firmware volume block protocol for FvImage so it gets dispatched from.
513 Status
= CoreProcessFvImageFile (DriverEntry
->Fv
, DriverEntry
->FvHandle
, &DriverEntry
->FileName
);
515 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
517 (EFI_SOFTWARE_DXE_CORE
| EFI_SW_PC_INIT_BEGIN
),
518 &DriverEntry
->ImageHandle
,
519 sizeof (DriverEntry
->ImageHandle
)
521 ASSERT (DriverEntry
->ImageHandle
!= NULL
);
523 Status
= CoreStartImage (DriverEntry
->ImageHandle
, NULL
, NULL
);
525 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
527 (EFI_SOFTWARE_DXE_CORE
| EFI_SW_PC_INIT_END
),
528 &DriverEntry
->ImageHandle
,
529 sizeof (DriverEntry
->ImageHandle
)
533 ReturnStatus
= EFI_SUCCESS
;
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
541 if (!EFI_ERROR (ReturnStatus
)) {
542 CoreSignalEvent (DxeDispatchEvent
);
546 // Search DriverList for items to place on Scheduled Queue
549 for (Link
= mDiscoveredList
.ForwardLink
; Link
!= &mDiscoveredList
; Link
= Link
->ForwardLink
) {
550 DriverEntry
= CR (Link
, EFI_CORE_DRIVER_ENTRY
, Link
, EFI_CORE_DRIVER_ENTRY_SIGNATURE
);
552 if (DriverEntry
->DepexProtocolError
){
554 // If Section Extraction Protocol did not let the Depex be read before retry the read
556 Status
= CoreGetDepexSectionAndPreProccess (DriverEntry
);
559 if (DriverEntry
->Dependent
) {
560 if (CoreIsSchedulable (DriverEntry
)) {
561 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry
);
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"));
572 } while (ReadyToRun
);
575 // Close DXE dispatch Event
577 CoreCloseEvent (DxeDispatchEvent
);
579 gDispatcherRunning
= FALSE
;
581 PERF_FUNCTION_END ();
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.
595 @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue
599 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
600 IN EFI_CORE_DRIVER_ENTRY
*InsertedDriverEntry
604 EFI_CORE_DRIVER_ENTRY
*DriverEntry
;
607 // Process Before Dependency
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
)) {
616 // Recursively process BEFORE
618 DEBUG ((DEBUG_DISPATCH
, "TRUE\n END\n RESULT = TRUE\n"));
619 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry
);
621 DEBUG ((DEBUG_DISPATCH
, "FALSE\n END\n RESULT = FALSE\n"));
627 // Convert driver from Dependent to Scheduled state
629 CoreAcquireDispatcherLock ();
631 InsertedDriverEntry
->Dependent
= FALSE
;
632 InsertedDriverEntry
->Scheduled
= TRUE
;
633 InsertTailList (&mScheduledQueue
, &InsertedDriverEntry
->ScheduledLink
);
635 CoreReleaseDispatcherLock ();
638 // Process After Dependency
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
)) {
647 // Recursively process AFTER
649 DEBUG ((DEBUG_DISPATCH
, "TRUE\n END\n RESULT = TRUE\n"));
650 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry
);
652 DEBUG ((DEBUG_DISPATCH
, "FALSE\n END\n RESULT = FALSE\n"));
660 Return TRUE if the Fv has been processed, FALSE if not.
662 @param FvHandle The handle of a FV that's being tested
664 @retval TRUE Fv protocol on FvHandle has been processed
665 @retval FALSE Fv protocol on FvHandle has not yet been processed
670 IN EFI_HANDLE FvHandle
674 KNOWN_HANDLE
*KnownHandle
;
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
) {
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.
692 @param FvHandle The handle of a FV that has been processed
694 @return A point to new added FvHandle entry. If FvHandle with the same FvImage guid
695 has been added, NULL will return.
699 FvIsBeingProcesssed (
700 IN EFI_HANDLE FvHandle
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
;
714 KNOWN_HANDLE
*KnownHandle
;
719 // Get the FirmwareVolumeBlock protocol on that handle
721 FvNameGuidIsFound
= FALSE
;
722 Status
= CoreHandleProtocol (FvHandle
, &gEfiFirmwareVolumeBlockProtocolGuid
, (VOID
**)&Fvb
);
723 if (!EFI_ERROR (Status
)) {
725 // Get the full FV header based on FVB protocol.
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
;
737 // Find LbaIndex and LbaOffset for FV extension header based on BlockMap.
739 while ((BlockMap
->NumBlocks
!= 0) || (BlockMap
->Length
!= 0)) {
740 for (Index
= 0; Index
< BlockMap
->NumBlocks
&& ExtHeaderOffset
>= BlockMap
->Length
; Index
++) {
741 ExtHeaderOffset
-= BlockMap
->Length
;
745 // Check whether FvExtHeader is crossing the multi block range.
747 if (Index
< BlockMap
->NumBlocks
) {
748 LbaOffset
= ExtHeaderOffset
;
754 // Read FvNameGuid from FV extension header.
756 Status
= ReadFvbData (Fvb
, &LbaIndex
, &LbaOffset
, sizeof (FvNameGuid
), (UINT8
*) &FvNameGuid
);
757 if (!EFI_ERROR (Status
)) {
758 FvNameGuidIsFound
= TRUE
;
761 CoreFreePool (FwVolHeader
);
765 if (FvNameGuidIsFound
) {
767 // Check whether the FV image with the found FvNameGuid has been processed.
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
));
778 KnownHandle
= AllocateZeroPool (sizeof (KNOWN_HANDLE
));
779 ASSERT (KnownHandle
!= NULL
);
781 KnownHandle
->Signature
= KNOWN_HANDLE_SIGNATURE
;
782 KnownHandle
->Handle
= FvHandle
;
783 if (FvNameGuidIsFound
) {
784 CopyGuid (&KnownHandle
->FvNameGuid
, &FvNameGuid
);
786 InsertTailList (&mFvHandleList
, &KnownHandle
->Link
);
794 Convert FvHandle and DriverName into an EFI device path
796 @param Fv Fv protocol, needed to read Depex info out of
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.
803 @return Pointer to device path constructed from FvHandle and DriverName
806 EFI_DEVICE_PATH_PROTOCOL
*
808 IN EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
,
809 IN EFI_HANDLE FvHandle
,
810 IN EFI_GUID
*DriverName
814 EFI_DEVICE_PATH_PROTOCOL
*FvDevicePath
;
815 EFI_DEVICE_PATH_PROTOCOL
*FileNameDevicePath
;
818 // Remember the device path of the FV
820 Status
= CoreHandleProtocol (FvHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&FvDevicePath
);
821 if (EFI_ERROR (Status
)) {
822 FileNameDevicePath
= NULL
;
825 // Build a device path to the file in the FV to pass into gBS->LoadImage
827 EfiInitializeFwVolDevicepathNode (&mFvDevicePath
.File
, DriverName
);
828 SetDevicePathEndNode (&mFvDevicePath
.End
);
830 FileNameDevicePath
= AppendDevicePath (
832 (EFI_DEVICE_PATH_PROTOCOL
*)&mFvDevicePath
836 return FileNameDevicePath
;
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.
848 @param Fv Fv protocol, needed to read Depex info out of
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.
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
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
870 EFI_CORE_DRIVER_ENTRY
*DriverEntry
;
874 // Create the Driver Entry for the list. ZeroPool initializes lots of variables to
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
;
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
);
889 CoreGetDepexSectionAndPreProccess (DriverEntry
);
891 CoreAcquireDispatcherLock ();
893 InsertTailList (&mDiscoveredList
, &DriverEntry
->Link
);
895 CoreReleaseDispatcherLock ();
902 Check if a FV Image type file (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) is
903 described by a EFI_HOB_FIRMWARE_VOLUME2 Hob.
905 @param FvNameGuid The FV image guid specified.
906 @param DriverName The driver guid specified.
908 @retval TRUE This file is found in a EFI_HOB_FIRMWARE_VOLUME2
910 @retval FALSE Not found.
915 IN CONST EFI_GUID
*FvNameGuid
,
916 IN CONST EFI_GUID
*DriverName
919 EFI_PEI_HOB_POINTERS HobFv2
;
921 HobFv2
.Raw
= GetHobList ();
923 while ((HobFv2
.Raw
= GetNextHob (EFI_HOB_TYPE_FV2
, HobFv2
.Raw
)) != NULL
) {
925 // Compare parent FvNameGuid and FileGuid both.
927 if (CompareGuid (DriverName
, &HobFv2
.FirmwareVolume2
->FileName
) &&
928 CompareGuid (FvNameGuid
, &HobFv2
.FirmwareVolume2
->FvName
)) {
931 HobFv2
.Raw
= GET_NEXT_HOB (HobFv2
);
938 Find USED_SIZE FV_EXT_TYPE entry in FV extension header and get the FV used size.
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.
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.
953 IN EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
,
954 OUT UINT32
*FvUsedSize
,
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
;
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
) {
970 // USED_SIZE FV_EXT_TYPE entry is found.
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) {
981 "FV at 0x%x has 0x%x used size, and erase byte is 0x%02x\n",
988 ExtEntryList
= (EFI_FIRMWARE_VOLUME_EXT_ENTRY
*)
989 ((UINT8
*) ExtEntryList
+ ReadUnaligned16 (&ExtEntryList
->ExtEntrySize
));
994 // No USED_SIZE FV_EXT_TYPE entry found.
1000 Get Fv image(s) from the FV through file name, and produce FVB protocol for every Fv image(s).
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.
1006 @retval EFI_OUT_OF_RESOURCES No enough memory or other resource.
1007 @retval EFI_SUCCESS Function successfully returned.
1011 CoreProcessFvImageFile (
1012 IN EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
,
1013 IN EFI_HANDLE FvHandle
,
1014 IN EFI_GUID
*FileName
1018 EFI_SECTION_TYPE SectionType
;
1019 UINT32 AuthenticationStatus
;
1021 VOID
*AlignedBuffer
;
1023 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
1025 EFI_DEVICE_PATH_PROTOCOL
*FvFileDevicePath
;
1031 // Read firmware volume section(s)
1033 SectionType
= EFI_SECTION_FIRMWARE_VOLUME_IMAGE
;
1041 AlignedBuffer
= NULL
;
1042 Status
= Fv
->ReadSection (
1049 &AuthenticationStatus
1051 if (!EFI_ERROR (Status
)) {
1053 // Evaluate the authentication status of the Firmware Volume through
1054 // Security Architectural Protocol
1056 if (gSecurity
!= NULL
) {
1057 FvFileDevicePath
= CoreFvToDevicePath (Fv
, FvHandle
, FileName
);
1058 Status
= gSecurity
->FileAuthenticationState (
1060 AuthenticationStatus
,
1063 if (FvFileDevicePath
!= NULL
) {
1064 FreePool (FvFileDevicePath
);
1067 if (Status
!= EFI_SUCCESS
) {
1069 // Security check failed. The firmware volume should not be used for any purpose.
1071 if (Buffer
!= NULL
) {
1079 // FvImage should be at its required alignment.
1081 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) Buffer
;
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.
1087 if ((ReadUnaligned32 (&FvHeader
->Attributes
) & EFI_FVB2_WEAK_ALIGNMENT
) != EFI_FVB2_WEAK_ALIGNMENT
) {
1089 // Get FvHeader alignment
1091 FvAlignment
= 1 << ((ReadUnaligned32 (&FvHeader
->Attributes
) & EFI_FVB2_ALIGNMENT
) >> 16);
1093 // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
1095 if (FvAlignment
< 8) {
1101 "%a() FV at 0x%x, FvAlignment required is 0x%x\n",
1108 // Check FvImage alignment.
1110 if ((UINTN
) FvHeader
% FvAlignment
!= 0) {
1112 // Allocate the aligned buffer for the FvImage.
1114 AlignedBuffer
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize
), (UINTN
) FvAlignment
);
1115 if (AlignedBuffer
== NULL
) {
1117 Status
= EFI_OUT_OF_RESOURCES
;
1121 // Move FvImage into the aligned buffer and release the original buffer.
1123 if (GetFvUsedSize (FvHeader
, &FvUsedSize
, &EraseByte
)) {
1125 // Copy the used bytes and fill the rest with the erase value.
1127 CopyMem (AlignedBuffer
, FvHeader
, (UINTN
) FvUsedSize
);
1129 (UINT8
*) AlignedBuffer
+ FvUsedSize
,
1130 (UINTN
) (BufferSize
- FvUsedSize
),
1134 CopyMem (AlignedBuffer
, Buffer
, BufferSize
);
1136 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) AlignedBuffer
;
1143 // Produce a FVB protocol for the file
1145 Status
= ProduceFVBProtocolOnBuffer (
1146 (EFI_PHYSICAL_ADDRESS
) (UINTN
) FvHeader
,
1149 AuthenticationStatus
,
1154 if (EFI_ERROR (Status
)) {
1156 // ReadSection or Produce FVB failed, Free data buffer
1158 if (Buffer
!= NULL
) {
1162 if (AlignedBuffer
!= NULL
) {
1163 FreeAlignedPages (AlignedBuffer
, EFI_SIZE_TO_PAGES (BufferSize
));
1174 // At least one FvImage has been processed successfully.
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.
1196 @param Event The Event that is being processed, not used.
1197 @param Context Event Context, not used.
1202 CoreFwVolEventProtocolNotify (
1208 EFI_STATUS GetNextFileStatus
;
1209 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
1210 EFI_DEVICE_PATH_PROTOCOL
*FvDevicePath
;
1211 EFI_HANDLE FvHandle
;
1215 EFI_FV_FILETYPE Type
;
1216 EFI_FV_FILE_ATTRIBUTES Attributes
;
1218 EFI_CORE_DRIVER_ENTRY
*DriverEntry
;
1219 EFI_GUID
*AprioriFile
;
1220 UINTN AprioriEntryCount
;
1223 UINT32 AuthenticationStatus
;
1226 KNOWN_HANDLE
*KnownHandle
;
1231 BufferSize
= sizeof (EFI_HANDLE
);
1232 Status
= CoreLocateHandle (
1235 mFwVolEventRegistration
,
1239 if (EFI_ERROR (Status
)) {
1241 // If no more notification events exit
1246 if (FvHasBeenProcessed (FvHandle
)) {
1248 // This Fv has already been processed so lets skip it!
1254 // Since we are about to process this Fv mark it as processed.
1256 KnownHandle
= FvIsBeingProcesssed (FvHandle
);
1257 if (KnownHandle
== NULL
) {
1259 // The FV with the same FV name guid has already been processed.
1265 Status
= CoreHandleProtocol (FvHandle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&Fv
);
1266 if (EFI_ERROR (Status
) || Fv
== NULL
) {
1268 // FvHandle must have Firmware Volume2 protocol thus we should never get here.
1274 Status
= CoreHandleProtocol (FvHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&FvDevicePath
);
1275 if (EFI_ERROR (Status
)) {
1277 // The Firmware volume doesn't have device path, can't be dispatched.
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
1288 for (Index
= 0; Index
< sizeof (mDxeFileTypes
) / sizeof (EFI_FV_FILETYPE
); Index
++) {
1290 // Initialize the search key
1294 Type
= mDxeFileTypes
[Index
];
1295 GetNextFileStatus
= Fv
->GetNextFile (
1303 if (!EFI_ERROR (GetNextFileStatus
)) {
1304 if (Type
== EFI_FV_FILETYPE_DXE_CORE
) {
1306 // If this is the DXE core fill in it's DevicePath & DeviceHandle
1308 if (gDxeCoreLoadedImage
->FilePath
== NULL
) {
1309 if (CompareGuid (&NameGuid
, gDxeCoreFileName
)) {
1311 // Maybe One specail Fv cantains only one DXE_CORE module, so its device path must
1312 // be initialized completely.
1314 EfiInitializeFwVolDevicepathNode (&mFvDevicePath
.File
, &NameGuid
);
1315 SetDevicePathEndNode (&mFvDevicePath
.End
);
1317 gDxeCoreLoadedImage
->FilePath
= DuplicateDevicePath (
1318 (EFI_DEVICE_PATH_PROTOCOL
*)&mFvDevicePath
1320 gDxeCoreLoadedImage
->DeviceHandle
= FvHandle
;
1323 } else if (Type
== EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
) {
1325 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
1328 if (FvFoundInHobFv2 (&KnownHandle
->FvNameGuid
, &NameGuid
)) {
1333 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has SMM depex section.
1337 Status
= Fv
->ReadSection (
1340 EFI_SECTION_SMM_DEPEX
,
1344 &AuthenticationStatus
1346 if (!EFI_ERROR (Status
)) {
1348 // If SMM depex section is found, this FV image is invalid to be supported.
1349 // ASSERT FALSE to report this FV image.
1351 FreePool (DepexBuffer
);
1356 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has DXE depex section.
1360 Status
= Fv
->ReadSection (
1363 EFI_SECTION_DXE_DEPEX
,
1367 &AuthenticationStatus
1369 if (EFI_ERROR (Status
)) {
1371 // If no depex section, produce a firmware volume block protocol for it so it gets dispatched from.
1373 CoreProcessFvImageFile (Fv
, FvHandle
, &NameGuid
);
1376 // If depex section is found, this FV image will be dispatched until its depex is evaluated to TRUE.
1378 FreePool (DepexBuffer
);
1379 CoreAddToDriverList (Fv
, FvHandle
, &NameGuid
, Type
);
1383 // Transition driver from Undiscovered to Discovered state
1385 CoreAddToDriverList (Fv
, FvHandle
, &NameGuid
, Type
);
1388 } while (!EFI_ERROR (GetNextFileStatus
));
1392 // Read the array of GUIDs from the Apriori file if it is present in the firmware volume
1395 Status
= Fv
->ReadSection (
1400 (VOID
**)&AprioriFile
,
1402 &AuthenticationStatus
1404 if (!EFI_ERROR (Status
)) {
1405 AprioriEntryCount
= SizeOfBuffer
/ sizeof (EFI_GUID
);
1407 AprioriEntryCount
= 0;
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.
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"));
1434 // Free data allocated by Fv->ReadSection ()
1436 CoreFreePool (AprioriFile
);
1443 Initialize the dispatcher. Initialize the notification function that runs when
1444 an FV2 protocol is added to the system.
1448 CoreInitializeDispatcher (
1452 PERF_FUNCTION_BEGIN ();
1454 mFwVolEvent
= EfiCreateProtocolNotifyEvent (
1455 &gEfiFirmwareVolume2ProtocolGuid
,
1457 CoreFwVolEventProtocolNotify
,
1459 &mFwVolEventRegistration
1462 PERF_FUNCTION_END ();
1466 // Function only used in debug builds
1470 Traverse the discovered list for any drivers that were discovered but not loaded
1471 because the dependency experessions evaluated to false.
1475 CoreDisplayDiscoveredNotDispatched (
1480 EFI_CORE_DRIVER_ENTRY
*DriverEntry
;
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
));