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 This program and the accompanying materials
31 are licensed and made available under the terms and conditions of the BSD License
32 which accompanies this distribution. The full text of the license may be found at
33 http://opensource.org/licenses/bsd-license.php
35 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
36 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
43 // The Driver List contains one copy of every driver that has been discovered.
44 // Items are never removed from the driver list. List of EFI_CORE_DRIVER_ENTRY
46 LIST_ENTRY mDiscoveredList
= INITIALIZE_LIST_HEAD_VARIABLE (mDiscoveredList
);
49 // Queue of drivers that are ready to dispatch. This queue is a subset of the
50 // mDiscoveredList.list of EFI_CORE_DRIVER_ENTRY.
52 LIST_ENTRY mScheduledQueue
= INITIALIZE_LIST_HEAD_VARIABLE (mScheduledQueue
);
55 // List of handles who's Fv's have been parsed and added to the mFwDriverList.
57 LIST_ENTRY mFvHandleList
= INITIALIZE_LIST_HEAD_VARIABLE (mFvHandleList
); // list of KNOWN_HANDLE
60 // Lock for mDiscoveredList, mScheduledQueue, gDispatcherRunning.
62 EFI_LOCK mDispatcherLock
= EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL
);
66 // Flag for the DXE Dispacher. TRUE if dispatcher is execuing.
68 BOOLEAN gDispatcherRunning
= FALSE
;
71 // Module globals to manage the FwVol registration notification event
73 EFI_EVENT mFwVolEvent
;
74 VOID
*mFwVolEventRegistration
;
77 // List of file types supported by dispatcher
79 EFI_FV_FILETYPE mDxeFileTypes
[] = {
80 EFI_FV_FILETYPE_DRIVER
,
81 EFI_FV_FILETYPE_COMBINED_SMM_DXE
,
82 EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
,
83 EFI_FV_FILETYPE_DXE_CORE
,
84 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
88 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH File
;
89 EFI_DEVICE_PATH_PROTOCOL End
;
90 } FV_FILEPATH_DEVICE_PATH
;
92 FV_FILEPATH_DEVICE_PATH mFvDevicePath
;
95 // Function Prototypes
98 Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
99 must add any driver with a before dependency on InsertedDriverEntry first.
100 You do this by recursively calling this routine. After all the Befores are
101 processed you can add InsertedDriverEntry to the mScheduledQueue.
102 Then you can add any driver with an After dependency on InsertedDriverEntry
103 by recursively calling this routine.
105 @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue
109 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
110 IN EFI_CORE_DRIVER_ENTRY
*InsertedDriverEntry
114 Event notification that is fired every time a FV dispatch protocol is added.
115 More than one protocol may have been added when this event is fired, so you
116 must loop on CoreLocateHandle () to see how many protocols were added and
117 do the following to each FV:
118 If the Fv has already been processed, skip it. If the Fv has not been
119 processed then mark it as being processed, as we are about to process it.
120 Read the Fv and add any driver in the Fv to the mDiscoveredList.The
121 mDiscoveredList is never free'ed and contains variables that define
122 the other states the DXE driver transitions to..
123 While you are at it read the A Priori file into memory.
124 Place drivers in the A Priori list onto the mScheduledQueue.
126 @param Event The Event that is being processed, not used.
127 @param Context Event Context, not used.
132 CoreFwVolEventProtocolNotify (
138 Convert FvHandle and DriverName into an EFI device path
140 @param Fv Fv protocol, needed to read Depex info out of
142 @param FvHandle Handle for Fv, needed in the
143 EFI_CORE_DRIVER_ENTRY so that the PE image can be
144 read out of the FV at a later time.
145 @param DriverName Name of driver to add to mDiscoveredList.
147 @return Pointer to device path constructed from FvHandle and DriverName
150 EFI_DEVICE_PATH_PROTOCOL
*
152 IN EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
,
153 IN EFI_HANDLE FvHandle
,
154 IN EFI_GUID
*DriverName
158 Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
159 and initilize any state variables. Read the Depex from the FV and store it
160 in DriverEntry. Pre-process the Depex to set the SOR, Before and After state.
161 The Discovered list is never free'ed and contains booleans that represent the
162 other possible DXE driver states.
164 @param Fv Fv protocol, needed to read Depex info out of
166 @param FvHandle Handle for Fv, needed in the
167 EFI_CORE_DRIVER_ENTRY so that the PE image can be
168 read out of the FV at a later time.
169 @param DriverName Name of driver to add to mDiscoveredList.
170 @param Type Fv File Type of file to add to mDiscoveredList.
172 @retval EFI_SUCCESS If driver was added to the mDiscoveredList.
173 @retval EFI_ALREADY_STARTED The driver has already been started. Only one
174 DriverName may be active in the system at any one
179 CoreAddToDriverList (
180 IN EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
,
181 IN EFI_HANDLE FvHandle
,
182 IN EFI_GUID
*DriverName
,
183 IN EFI_FV_FILETYPE Type
187 Get Fv image(s) from the FV through file name, and produce FVB protocol for every Fv image(s).
189 @param Fv The FIRMWARE_VOLUME protocol installed on the FV.
190 @param FvHandle The handle which FVB protocol installed on.
191 @param FileName The file name guid specified.
193 @retval EFI_OUT_OF_RESOURCES No enough memory or other resource.
194 @retval EFI_SUCCESS Function successfully returned.
198 CoreProcessFvImageFile (
199 IN EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
,
200 IN EFI_HANDLE FvHandle
,
201 IN EFI_GUID
*FileName
206 Enter critical section by gaining lock on mDispatcherLock.
210 CoreAcquireDispatcherLock (
214 CoreAcquireLock (&mDispatcherLock
);
219 Exit critical section by releasing lock on mDispatcherLock.
223 CoreReleaseDispatcherLock (
227 CoreReleaseLock (&mDispatcherLock
);
232 Read Depex and pre-process the Depex for Before and After. If Section Extraction
233 protocol returns an error via ReadSection defer the reading of the Depex.
235 @param DriverEntry Driver to work on.
237 @retval EFI_SUCCESS Depex read and preprossesed
238 @retval EFI_PROTOCOL_ERROR The section extraction protocol returned an error
239 and Depex reading needs to be retried.
240 @retval Error DEPEX not found.
244 CoreGetDepexSectionAndPreProccess (
245 IN EFI_CORE_DRIVER_ENTRY
*DriverEntry
249 EFI_SECTION_TYPE SectionType
;
250 UINT32 AuthenticationStatus
;
251 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
254 Fv
= DriverEntry
->Fv
;
257 // Grab Depex info, it will never be free'ed.
259 SectionType
= EFI_SECTION_DXE_DEPEX
;
260 Status
= Fv
->ReadSection (
262 &DriverEntry
->FileName
,
266 (UINTN
*)&DriverEntry
->DepexSize
,
267 &AuthenticationStatus
269 if (EFI_ERROR (Status
)) {
270 if (Status
== EFI_PROTOCOL_ERROR
) {
272 // The section extraction protocol failed so set protocol error flag
274 DriverEntry
->DepexProtocolError
= TRUE
;
277 // If no Depex assume UEFI 2.0 driver model
279 DriverEntry
->Depex
= NULL
;
280 DriverEntry
->Dependent
= TRUE
;
281 DriverEntry
->DepexProtocolError
= FALSE
;
285 // Set Before, After, and Unrequested state information based on Depex
286 // Driver will be put in Dependent or Unrequested state
288 CorePreProcessDepex (DriverEntry
);
289 DriverEntry
->DepexProtocolError
= FALSE
;
297 Check every driver and locate a matching one. If the driver is found, the Unrequested
298 state flag is cleared.
300 @param FirmwareVolumeHandle The handle of the Firmware Volume that contains
301 the firmware file specified by DriverName.
302 @param DriverName The Driver name to put in the Dependent state.
304 @retval EFI_SUCCESS The DriverName was found and it's SOR bit was
306 @retval EFI_NOT_FOUND The DriverName does not exist or it's SOR bit was
313 IN EFI_HANDLE FirmwareVolumeHandle
,
314 IN EFI_GUID
*DriverName
318 EFI_CORE_DRIVER_ENTRY
*DriverEntry
;
321 // Check every driver
323 for (Link
= mDiscoveredList
.ForwardLink
; Link
!= &mDiscoveredList
; Link
= Link
->ForwardLink
) {
324 DriverEntry
= CR(Link
, EFI_CORE_DRIVER_ENTRY
, Link
, EFI_CORE_DRIVER_ENTRY_SIGNATURE
);
325 if (DriverEntry
->FvHandle
== FirmwareVolumeHandle
&&
326 DriverEntry
->Unrequested
&&
327 CompareGuid (DriverName
, &DriverEntry
->FileName
)) {
329 // Move the driver from the Unrequested to the Dependent state
331 CoreAcquireDispatcherLock ();
332 DriverEntry
->Unrequested
= FALSE
;
333 DriverEntry
->Dependent
= TRUE
;
334 CoreReleaseDispatcherLock ();
336 DEBUG ((DEBUG_DISPATCH
, "Schedule FFS(%g) - EFI_SUCCESS\n", DriverName
));
342 DEBUG ((DEBUG_DISPATCH
, "Schedule FFS(%g) - EFI_NOT_FOUND\n", DriverName
));
344 return EFI_NOT_FOUND
;
350 Convert a driver from the Untrused back to the Scheduled state.
352 @param FirmwareVolumeHandle The handle of the Firmware Volume that contains
353 the firmware file specified by DriverName.
354 @param DriverName The Driver name to put in the Scheduled state
356 @retval EFI_SUCCESS The file was found in the untrusted state, and it
357 was promoted to the trusted state.
358 @retval EFI_NOT_FOUND The file was not found in the untrusted state.
364 IN EFI_HANDLE FirmwareVolumeHandle
,
365 IN EFI_GUID
*DriverName
369 EFI_CORE_DRIVER_ENTRY
*DriverEntry
;
372 // Check every driver
374 for (Link
= mDiscoveredList
.ForwardLink
; Link
!= &mDiscoveredList
; Link
= Link
->ForwardLink
) {
375 DriverEntry
= CR(Link
, EFI_CORE_DRIVER_ENTRY
, Link
, EFI_CORE_DRIVER_ENTRY_SIGNATURE
);
376 if (DriverEntry
->FvHandle
== FirmwareVolumeHandle
&&
377 DriverEntry
->Untrusted
&&
378 CompareGuid (DriverName
, &DriverEntry
->FileName
)) {
380 // Transition driver from Untrusted to Scheduled state.
382 CoreAcquireDispatcherLock ();
383 DriverEntry
->Untrusted
= FALSE
;
384 DriverEntry
->Scheduled
= TRUE
;
385 InsertTailList (&mScheduledQueue
, &DriverEntry
->ScheduledLink
);
386 CoreReleaseDispatcherLock ();
391 return EFI_NOT_FOUND
;
395 This is the main Dispatcher for DXE and it exits when there are no more
396 drivers to run. Drain the mScheduledQueue and load and start a PE
397 image for each driver. Search the mDiscoveredList to see if any driver can
398 be placed on the mScheduledQueue. If no drivers are placed on the
399 mScheduledQueue exit the function. On exit it is assumed the Bds()
400 will be called, and when the Bds() exits the Dispatcher will be called
403 @retval EFI_ALREADY_STARTED The DXE Dispatcher is already running
404 @retval EFI_NOT_FOUND No DXE Drivers were dispatched
405 @retval EFI_SUCCESS One or more DXE Drivers were dispatched
415 EFI_STATUS ReturnStatus
;
417 EFI_CORE_DRIVER_ENTRY
*DriverEntry
;
419 EFI_EVENT DxeDispatchEvent
;
421 PERF_FUNCTION_BEGIN ();
423 if (gDispatcherRunning
) {
425 // If the dispatcher is running don't let it be restarted.
427 return EFI_ALREADY_STARTED
;
430 gDispatcherRunning
= TRUE
;
432 Status
= CoreCreateEventEx (
435 EfiEventEmptyFunction
,
437 &gEfiEventDxeDispatchGuid
,
440 if (EFI_ERROR (Status
)) {
444 ReturnStatus
= EFI_NOT_FOUND
;
447 // Drain the Scheduled Queue
449 while (!IsListEmpty (&mScheduledQueue
)) {
451 mScheduledQueue
.ForwardLink
,
452 EFI_CORE_DRIVER_ENTRY
,
454 EFI_CORE_DRIVER_ENTRY_SIGNATURE
458 // Load the DXE Driver image into memory. If the Driver was transitioned from
459 // Untrused to Scheduled it would have already been loaded so we may need to
460 // skip the LoadImage
462 if (DriverEntry
->ImageHandle
== NULL
&& !DriverEntry
->IsFvImage
) {
463 DEBUG ((DEBUG_INFO
, "Loading driver %g\n", &DriverEntry
->FileName
));
464 Status
= CoreLoadImage (
467 DriverEntry
->FvFileDevicePath
,
470 &DriverEntry
->ImageHandle
474 // Update the driver state to reflect that it's been loaded
476 if (EFI_ERROR (Status
)) {
477 CoreAcquireDispatcherLock ();
479 if (Status
== EFI_SECURITY_VIOLATION
) {
481 // Take driver from Scheduled to Untrused state
483 DriverEntry
->Untrusted
= TRUE
;
486 // The DXE Driver could not be loaded, and do not attempt to load or start it again.
487 // Take driver from Scheduled to Initialized.
489 // This case include the Never Trusted state if EFI_ACCESS_DENIED is returned
491 DriverEntry
->Initialized
= TRUE
;
494 DriverEntry
->Scheduled
= FALSE
;
495 RemoveEntryList (&DriverEntry
->ScheduledLink
);
497 CoreReleaseDispatcherLock ();
500 // If it's an error don't try the StartImage
506 CoreAcquireDispatcherLock ();
508 DriverEntry
->Scheduled
= FALSE
;
509 DriverEntry
->Initialized
= TRUE
;
510 RemoveEntryList (&DriverEntry
->ScheduledLink
);
512 CoreReleaseDispatcherLock ();
515 if (DriverEntry
->IsFvImage
) {
517 // Produce a firmware volume block protocol for FvImage so it gets dispatched from.
519 Status
= CoreProcessFvImageFile (DriverEntry
->Fv
, DriverEntry
->FvHandle
, &DriverEntry
->FileName
);
521 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
523 (EFI_SOFTWARE_DXE_CORE
| EFI_SW_PC_INIT_BEGIN
),
524 &DriverEntry
->ImageHandle
,
525 sizeof (DriverEntry
->ImageHandle
)
527 ASSERT (DriverEntry
->ImageHandle
!= NULL
);
529 Status
= CoreStartImage (DriverEntry
->ImageHandle
, NULL
, NULL
);
531 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
533 (EFI_SOFTWARE_DXE_CORE
| EFI_SW_PC_INIT_END
),
534 &DriverEntry
->ImageHandle
,
535 sizeof (DriverEntry
->ImageHandle
)
539 ReturnStatus
= EFI_SUCCESS
;
543 // Now DXE Dispatcher finished one round of dispatch, signal an event group
544 // so that SMM Dispatcher get chance to dispatch SMM Drivers which depend
547 if (!EFI_ERROR (ReturnStatus
)) {
548 CoreSignalEvent (DxeDispatchEvent
);
552 // Search DriverList for items to place on Scheduled Queue
555 for (Link
= mDiscoveredList
.ForwardLink
; Link
!= &mDiscoveredList
; Link
= Link
->ForwardLink
) {
556 DriverEntry
= CR (Link
, EFI_CORE_DRIVER_ENTRY
, Link
, EFI_CORE_DRIVER_ENTRY_SIGNATURE
);
558 if (DriverEntry
->DepexProtocolError
){
560 // If Section Extraction Protocol did not let the Depex be read before retry the read
562 Status
= CoreGetDepexSectionAndPreProccess (DriverEntry
);
565 if (DriverEntry
->Dependent
) {
566 if (CoreIsSchedulable (DriverEntry
)) {
567 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry
);
571 if (DriverEntry
->Unrequested
) {
572 DEBUG ((DEBUG_DISPATCH
, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry
->FileName
));
573 DEBUG ((DEBUG_DISPATCH
, " SOR = Not Requested\n"));
574 DEBUG ((DEBUG_DISPATCH
, " RESULT = FALSE\n"));
578 } while (ReadyToRun
);
581 // Close DXE dispatch Event
583 CoreCloseEvent (DxeDispatchEvent
);
585 gDispatcherRunning
= FALSE
;
587 PERF_FUNCTION_END ();
594 Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
595 must add any driver with a before dependency on InsertedDriverEntry first.
596 You do this by recursively calling this routine. After all the Befores are
597 processed you can add InsertedDriverEntry to the mScheduledQueue.
598 Then you can add any driver with an After dependency on InsertedDriverEntry
599 by recursively calling this routine.
601 @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue
605 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
606 IN EFI_CORE_DRIVER_ENTRY
*InsertedDriverEntry
610 EFI_CORE_DRIVER_ENTRY
*DriverEntry
;
613 // Process Before Dependency
615 for (Link
= mDiscoveredList
.ForwardLink
; Link
!= &mDiscoveredList
; Link
= Link
->ForwardLink
) {
616 DriverEntry
= CR(Link
, EFI_CORE_DRIVER_ENTRY
, Link
, EFI_CORE_DRIVER_ENTRY_SIGNATURE
);
617 if (DriverEntry
->Before
&& DriverEntry
->Dependent
&& DriverEntry
!= InsertedDriverEntry
) {
618 DEBUG ((DEBUG_DISPATCH
, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry
->FileName
));
619 DEBUG ((DEBUG_DISPATCH
, " BEFORE FFS(%g) = ", &DriverEntry
->BeforeAfterGuid
));
620 if (CompareGuid (&InsertedDriverEntry
->FileName
, &DriverEntry
->BeforeAfterGuid
)) {
622 // Recursively process BEFORE
624 DEBUG ((DEBUG_DISPATCH
, "TRUE\n END\n RESULT = TRUE\n"));
625 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry
);
627 DEBUG ((DEBUG_DISPATCH
, "FALSE\n END\n RESULT = FALSE\n"));
633 // Convert driver from Dependent to Scheduled state
635 CoreAcquireDispatcherLock ();
637 InsertedDriverEntry
->Dependent
= FALSE
;
638 InsertedDriverEntry
->Scheduled
= TRUE
;
639 InsertTailList (&mScheduledQueue
, &InsertedDriverEntry
->ScheduledLink
);
641 CoreReleaseDispatcherLock ();
644 // Process After Dependency
646 for (Link
= mDiscoveredList
.ForwardLink
; Link
!= &mDiscoveredList
; Link
= Link
->ForwardLink
) {
647 DriverEntry
= CR(Link
, EFI_CORE_DRIVER_ENTRY
, Link
, EFI_CORE_DRIVER_ENTRY_SIGNATURE
);
648 if (DriverEntry
->After
&& DriverEntry
->Dependent
&& DriverEntry
!= InsertedDriverEntry
) {
649 DEBUG ((DEBUG_DISPATCH
, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry
->FileName
));
650 DEBUG ((DEBUG_DISPATCH
, " AFTER FFS(%g) = ", &DriverEntry
->BeforeAfterGuid
));
651 if (CompareGuid (&InsertedDriverEntry
->FileName
, &DriverEntry
->BeforeAfterGuid
)) {
653 // Recursively process AFTER
655 DEBUG ((DEBUG_DISPATCH
, "TRUE\n END\n RESULT = TRUE\n"));
656 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry
);
658 DEBUG ((DEBUG_DISPATCH
, "FALSE\n END\n RESULT = FALSE\n"));
666 Return TRUE if the Fv has been processed, FALSE if not.
668 @param FvHandle The handle of a FV that's being tested
670 @retval TRUE Fv protocol on FvHandle has been processed
671 @retval FALSE Fv protocol on FvHandle has not yet been processed
676 IN EFI_HANDLE FvHandle
680 KNOWN_HANDLE
*KnownHandle
;
682 for (Link
= mFvHandleList
.ForwardLink
; Link
!= &mFvHandleList
; Link
= Link
->ForwardLink
) {
683 KnownHandle
= CR(Link
, KNOWN_HANDLE
, Link
, KNOWN_HANDLE_SIGNATURE
);
684 if (KnownHandle
->Handle
== FvHandle
) {
693 Remember that Fv protocol on FvHandle has had it's drivers placed on the
694 mDiscoveredList. This fucntion adds entries on the mFvHandleList if new
695 entry is different from one in mFvHandleList by checking FvImage Guid.
696 Items are never removed/freed from the mFvHandleList.
698 @param FvHandle The handle of a FV that has been processed
700 @return A point to new added FvHandle entry. If FvHandle with the same FvImage guid
701 has been added, NULL will return.
705 FvIsBeingProcesssed (
706 IN EFI_HANDLE FvHandle
711 BOOLEAN FvNameGuidIsFound
;
712 UINT32 ExtHeaderOffset
;
713 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL
*Fvb
;
714 EFI_FIRMWARE_VOLUME_HEADER
*FwVolHeader
;
715 EFI_FV_BLOCK_MAP_ENTRY
*BlockMap
;
720 KNOWN_HANDLE
*KnownHandle
;
725 // Get the FirmwareVolumeBlock protocol on that handle
727 FvNameGuidIsFound
= FALSE
;
728 Status
= CoreHandleProtocol (FvHandle
, &gEfiFirmwareVolumeBlockProtocolGuid
, (VOID
**)&Fvb
);
729 if (!EFI_ERROR (Status
)) {
731 // Get the full FV header based on FVB protocol.
733 ASSERT (Fvb
!= NULL
);
734 Status
= GetFwVolHeader (Fvb
, &FwVolHeader
);
735 if (!EFI_ERROR (Status
)) {
736 ASSERT (FwVolHeader
!= NULL
);
737 if (VerifyFvHeaderChecksum (FwVolHeader
) && FwVolHeader
->ExtHeaderOffset
!= 0) {
738 ExtHeaderOffset
= (UINT32
) FwVolHeader
->ExtHeaderOffset
;
739 BlockMap
= FwVolHeader
->BlockMap
;
743 // Find LbaIndex and LbaOffset for FV extension header based on BlockMap.
745 while ((BlockMap
->NumBlocks
!= 0) || (BlockMap
->Length
!= 0)) {
746 for (Index
= 0; Index
< BlockMap
->NumBlocks
&& ExtHeaderOffset
>= BlockMap
->Length
; Index
++) {
747 ExtHeaderOffset
-= BlockMap
->Length
;
751 // Check whether FvExtHeader is crossing the multi block range.
753 if (Index
< BlockMap
->NumBlocks
) {
754 LbaOffset
= ExtHeaderOffset
;
760 // Read FvNameGuid from FV extension header.
762 Status
= ReadFvbData (Fvb
, &LbaIndex
, &LbaOffset
, sizeof (FvNameGuid
), (UINT8
*) &FvNameGuid
);
763 if (!EFI_ERROR (Status
)) {
764 FvNameGuidIsFound
= TRUE
;
767 CoreFreePool (FwVolHeader
);
771 if (FvNameGuidIsFound
) {
773 // Check whether the FV image with the found FvNameGuid has been processed.
775 for (Link
= mFvHandleList
.ForwardLink
; Link
!= &mFvHandleList
; Link
= Link
->ForwardLink
) {
776 KnownHandle
= CR(Link
, KNOWN_HANDLE
, Link
, KNOWN_HANDLE_SIGNATURE
);
777 if (CompareGuid (&FvNameGuid
, &KnownHandle
->FvNameGuid
)) {
778 DEBUG ((EFI_D_ERROR
, "FvImage on FvHandle %p and %p has the same FvNameGuid %g.\n", FvHandle
, KnownHandle
->Handle
, &FvNameGuid
));
784 KnownHandle
= AllocateZeroPool (sizeof (KNOWN_HANDLE
));
785 ASSERT (KnownHandle
!= NULL
);
787 KnownHandle
->Signature
= KNOWN_HANDLE_SIGNATURE
;
788 KnownHandle
->Handle
= FvHandle
;
789 if (FvNameGuidIsFound
) {
790 CopyGuid (&KnownHandle
->FvNameGuid
, &FvNameGuid
);
792 InsertTailList (&mFvHandleList
, &KnownHandle
->Link
);
800 Convert FvHandle and DriverName into an EFI device path
802 @param Fv Fv protocol, needed to read Depex info out of
804 @param FvHandle Handle for Fv, needed in the
805 EFI_CORE_DRIVER_ENTRY so that the PE image can be
806 read out of the FV at a later time.
807 @param DriverName Name of driver to add to mDiscoveredList.
809 @return Pointer to device path constructed from FvHandle and DriverName
812 EFI_DEVICE_PATH_PROTOCOL
*
814 IN EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
,
815 IN EFI_HANDLE FvHandle
,
816 IN EFI_GUID
*DriverName
820 EFI_DEVICE_PATH_PROTOCOL
*FvDevicePath
;
821 EFI_DEVICE_PATH_PROTOCOL
*FileNameDevicePath
;
824 // Remember the device path of the FV
826 Status
= CoreHandleProtocol (FvHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&FvDevicePath
);
827 if (EFI_ERROR (Status
)) {
828 FileNameDevicePath
= NULL
;
831 // Build a device path to the file in the FV to pass into gBS->LoadImage
833 EfiInitializeFwVolDevicepathNode (&mFvDevicePath
.File
, DriverName
);
834 SetDevicePathEndNode (&mFvDevicePath
.End
);
836 FileNameDevicePath
= AppendDevicePath (
838 (EFI_DEVICE_PATH_PROTOCOL
*)&mFvDevicePath
842 return FileNameDevicePath
;
848 Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
849 and initilize any state variables. Read the Depex from the FV and store it
850 in DriverEntry. Pre-process the Depex to set the SOR, Before and After state.
851 The Discovered list is never free'ed and contains booleans that represent the
852 other possible DXE driver states.
854 @param Fv Fv protocol, needed to read Depex info out of
856 @param FvHandle Handle for Fv, needed in the
857 EFI_CORE_DRIVER_ENTRY so that the PE image can be
858 read out of the FV at a later time.
859 @param DriverName Name of driver to add to mDiscoveredList.
860 @param Type Fv File Type of file to add to mDiscoveredList.
862 @retval EFI_SUCCESS If driver was added to the mDiscoveredList.
863 @retval EFI_ALREADY_STARTED The driver has already been started. Only one
864 DriverName may be active in the system at any one
869 CoreAddToDriverList (
870 IN EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
,
871 IN EFI_HANDLE FvHandle
,
872 IN EFI_GUID
*DriverName
,
873 IN EFI_FV_FILETYPE Type
876 EFI_CORE_DRIVER_ENTRY
*DriverEntry
;
880 // Create the Driver Entry for the list. ZeroPool initializes lots of variables to
883 DriverEntry
= AllocateZeroPool (sizeof (EFI_CORE_DRIVER_ENTRY
));
884 ASSERT (DriverEntry
!= NULL
);
885 if (Type
== EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
) {
886 DriverEntry
->IsFvImage
= TRUE
;
889 DriverEntry
->Signature
= EFI_CORE_DRIVER_ENTRY_SIGNATURE
;
890 CopyGuid (&DriverEntry
->FileName
, DriverName
);
891 DriverEntry
->FvHandle
= FvHandle
;
892 DriverEntry
->Fv
= Fv
;
893 DriverEntry
->FvFileDevicePath
= CoreFvToDevicePath (Fv
, FvHandle
, DriverName
);
895 CoreGetDepexSectionAndPreProccess (DriverEntry
);
897 CoreAcquireDispatcherLock ();
899 InsertTailList (&mDiscoveredList
, &DriverEntry
->Link
);
901 CoreReleaseDispatcherLock ();
908 Check if a FV Image type file (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) is
909 described by a EFI_HOB_FIRMWARE_VOLUME2 Hob.
911 @param FvNameGuid The FV image guid specified.
912 @param DriverName The driver guid specified.
914 @retval TRUE This file is found in a EFI_HOB_FIRMWARE_VOLUME2
916 @retval FALSE Not found.
921 IN CONST EFI_GUID
*FvNameGuid
,
922 IN CONST EFI_GUID
*DriverName
925 EFI_PEI_HOB_POINTERS HobFv2
;
927 HobFv2
.Raw
= GetHobList ();
929 while ((HobFv2
.Raw
= GetNextHob (EFI_HOB_TYPE_FV2
, HobFv2
.Raw
)) != NULL
) {
931 // Compare parent FvNameGuid and FileGuid both.
933 if (CompareGuid (DriverName
, &HobFv2
.FirmwareVolume2
->FileName
) &&
934 CompareGuid (FvNameGuid
, &HobFv2
.FirmwareVolume2
->FvName
)) {
937 HobFv2
.Raw
= GET_NEXT_HOB (HobFv2
);
944 Find USED_SIZE FV_EXT_TYPE entry in FV extension header and get the FV used size.
946 @param[in] FvHeader Pointer to FV header.
947 @param[out] FvUsedSize Pointer to FV used size returned,
948 only valid if USED_SIZE FV_EXT_TYPE entry is found.
949 @param[out] EraseByte Pointer to erase byte returned,
950 only valid if USED_SIZE FV_EXT_TYPE entry is found.
952 @retval TRUE USED_SIZE FV_EXT_TYPE entry is found,
953 FV used size and erase byte are returned.
954 @retval FALSE No USED_SIZE FV_EXT_TYPE entry found.
959 IN EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
,
960 OUT UINT32
*FvUsedSize
,
964 UINT16 ExtHeaderOffset
;
965 EFI_FIRMWARE_VOLUME_EXT_HEADER
*ExtHeader
;
966 EFI_FIRMWARE_VOLUME_EXT_ENTRY
*ExtEntryList
;
967 EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE
*ExtEntryUsedSize
;
969 ExtHeaderOffset
= ReadUnaligned16 (&FvHeader
->ExtHeaderOffset
);
970 if (ExtHeaderOffset
!= 0) {
971 ExtHeader
= (EFI_FIRMWARE_VOLUME_EXT_HEADER
*) ((UINT8
*) FvHeader
+ ExtHeaderOffset
);
972 ExtEntryList
= (EFI_FIRMWARE_VOLUME_EXT_ENTRY
*) (ExtHeader
+ 1);
973 while ((UINTN
) ExtEntryList
< ((UINTN
) ExtHeader
+ ReadUnaligned32 (&ExtHeader
->ExtHeaderSize
))) {
974 if (ReadUnaligned16 (&ExtEntryList
->ExtEntryType
) == EFI_FV_EXT_TYPE_USED_SIZE_TYPE
) {
976 // USED_SIZE FV_EXT_TYPE entry is found.
978 ExtEntryUsedSize
= (EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE
*) ExtEntryList
;
979 *FvUsedSize
= ReadUnaligned32 (&ExtEntryUsedSize
->UsedSize
);
980 if ((ReadUnaligned32 (&FvHeader
->Attributes
) & EFI_FVB2_ERASE_POLARITY
) != 0) {
987 "FV at 0x%x has 0x%x used size, and erase byte is 0x%02x\n",
994 ExtEntryList
= (EFI_FIRMWARE_VOLUME_EXT_ENTRY
*)
995 ((UINT8
*) ExtEntryList
+ ReadUnaligned16 (&ExtEntryList
->ExtEntrySize
));
1000 // No USED_SIZE FV_EXT_TYPE entry found.
1006 Get Fv image(s) from the FV through file name, and produce FVB protocol for every Fv image(s).
1008 @param Fv The FIRMWARE_VOLUME protocol installed on the FV.
1009 @param FvHandle The handle which FVB protocol installed on.
1010 @param FileName The file name guid specified.
1012 @retval EFI_OUT_OF_RESOURCES No enough memory or other resource.
1013 @retval EFI_SUCCESS Function successfully returned.
1017 CoreProcessFvImageFile (
1018 IN EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
,
1019 IN EFI_HANDLE FvHandle
,
1020 IN EFI_GUID
*FileName
1024 EFI_SECTION_TYPE SectionType
;
1025 UINT32 AuthenticationStatus
;
1027 VOID
*AlignedBuffer
;
1029 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
1031 EFI_DEVICE_PATH_PROTOCOL
*FvFileDevicePath
;
1037 // Read firmware volume section(s)
1039 SectionType
= EFI_SECTION_FIRMWARE_VOLUME_IMAGE
;
1047 AlignedBuffer
= NULL
;
1048 Status
= Fv
->ReadSection (
1055 &AuthenticationStatus
1057 if (!EFI_ERROR (Status
)) {
1059 // Evaluate the authentication status of the Firmware Volume through
1060 // Security Architectural Protocol
1062 if (gSecurity
!= NULL
) {
1063 FvFileDevicePath
= CoreFvToDevicePath (Fv
, FvHandle
, FileName
);
1064 Status
= gSecurity
->FileAuthenticationState (
1066 AuthenticationStatus
,
1069 if (FvFileDevicePath
!= NULL
) {
1070 FreePool (FvFileDevicePath
);
1073 if (Status
!= EFI_SUCCESS
) {
1075 // Security check failed. The firmware volume should not be used for any purpose.
1077 if (Buffer
!= NULL
) {
1085 // FvImage should be at its required alignment.
1087 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) Buffer
;
1089 // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume
1090 // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from
1091 // its initial linked location and maintain its alignment.
1093 if ((ReadUnaligned32 (&FvHeader
->Attributes
) & EFI_FVB2_WEAK_ALIGNMENT
) != EFI_FVB2_WEAK_ALIGNMENT
) {
1095 // Get FvHeader alignment
1097 FvAlignment
= 1 << ((ReadUnaligned32 (&FvHeader
->Attributes
) & EFI_FVB2_ALIGNMENT
) >> 16);
1099 // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
1101 if (FvAlignment
< 8) {
1107 "%a() FV at 0x%x, FvAlignment required is 0x%x\n",
1114 // Check FvImage alignment.
1116 if ((UINTN
) FvHeader
% FvAlignment
!= 0) {
1118 // Allocate the aligned buffer for the FvImage.
1120 AlignedBuffer
= AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize
), (UINTN
) FvAlignment
);
1121 if (AlignedBuffer
== NULL
) {
1123 Status
= EFI_OUT_OF_RESOURCES
;
1127 // Move FvImage into the aligned buffer and release the original buffer.
1129 if (GetFvUsedSize (FvHeader
, &FvUsedSize
, &EraseByte
)) {
1131 // Copy the used bytes and fill the rest with the erase value.
1133 CopyMem (AlignedBuffer
, FvHeader
, (UINTN
) FvUsedSize
);
1135 (UINT8
*) AlignedBuffer
+ FvUsedSize
,
1136 (UINTN
) (BufferSize
- FvUsedSize
),
1140 CopyMem (AlignedBuffer
, Buffer
, BufferSize
);
1142 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) AlignedBuffer
;
1149 // Produce a FVB protocol for the file
1151 Status
= ProduceFVBProtocolOnBuffer (
1152 (EFI_PHYSICAL_ADDRESS
) (UINTN
) FvHeader
,
1155 AuthenticationStatus
,
1160 if (EFI_ERROR (Status
)) {
1162 // ReadSection or Produce FVB failed, Free data buffer
1164 if (Buffer
!= NULL
) {
1168 if (AlignedBuffer
!= NULL
) {
1169 FreeAlignedPages (AlignedBuffer
, EFI_SIZE_TO_PAGES (BufferSize
));
1180 // At least one FvImage has been processed successfully.
1190 Event notification that is fired every time a FV dispatch protocol is added.
1191 More than one protocol may have been added when this event is fired, so you
1192 must loop on CoreLocateHandle () to see how many protocols were added and
1193 do the following to each FV:
1194 If the Fv has already been processed, skip it. If the Fv has not been
1195 processed then mark it as being processed, as we are about to process it.
1196 Read the Fv and add any driver in the Fv to the mDiscoveredList.The
1197 mDiscoveredList is never free'ed and contains variables that define
1198 the other states the DXE driver transitions to..
1199 While you are at it read the A Priori file into memory.
1200 Place drivers in the A Priori list onto the mScheduledQueue.
1202 @param Event The Event that is being processed, not used.
1203 @param Context Event Context, not used.
1208 CoreFwVolEventProtocolNotify (
1214 EFI_STATUS GetNextFileStatus
;
1215 EFI_FIRMWARE_VOLUME2_PROTOCOL
*Fv
;
1216 EFI_DEVICE_PATH_PROTOCOL
*FvDevicePath
;
1217 EFI_HANDLE FvHandle
;
1221 EFI_FV_FILETYPE Type
;
1222 EFI_FV_FILE_ATTRIBUTES Attributes
;
1224 EFI_CORE_DRIVER_ENTRY
*DriverEntry
;
1225 EFI_GUID
*AprioriFile
;
1226 UINTN AprioriEntryCount
;
1229 UINT32 AuthenticationStatus
;
1232 KNOWN_HANDLE
*KnownHandle
;
1237 BufferSize
= sizeof (EFI_HANDLE
);
1238 Status
= CoreLocateHandle (
1241 mFwVolEventRegistration
,
1245 if (EFI_ERROR (Status
)) {
1247 // If no more notification events exit
1252 if (FvHasBeenProcessed (FvHandle
)) {
1254 // This Fv has already been processed so lets skip it!
1260 // Since we are about to process this Fv mark it as processed.
1262 KnownHandle
= FvIsBeingProcesssed (FvHandle
);
1263 if (KnownHandle
== NULL
) {
1265 // The FV with the same FV name guid has already been processed.
1271 Status
= CoreHandleProtocol (FvHandle
, &gEfiFirmwareVolume2ProtocolGuid
, (VOID
**)&Fv
);
1272 if (EFI_ERROR (Status
) || Fv
== NULL
) {
1274 // FvHandle must have Firmware Volume2 protocol thus we should never get here.
1280 Status
= CoreHandleProtocol (FvHandle
, &gEfiDevicePathProtocolGuid
, (VOID
**)&FvDevicePath
);
1281 if (EFI_ERROR (Status
)) {
1283 // The Firmware volume doesn't have device path, can't be dispatched.
1289 // Discover Drivers in FV and add them to the Discovered Driver List.
1290 // Process EFI_FV_FILETYPE_DRIVER type and then EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
1291 // EFI_FV_FILETYPE_DXE_CORE is processed to produce a Loaded Image protocol for the core
1292 // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE is processed to create a Fvb
1294 for (Index
= 0; Index
< sizeof (mDxeFileTypes
) / sizeof (EFI_FV_FILETYPE
); Index
++) {
1296 // Initialize the search key
1300 Type
= mDxeFileTypes
[Index
];
1301 GetNextFileStatus
= Fv
->GetNextFile (
1309 if (!EFI_ERROR (GetNextFileStatus
)) {
1310 if (Type
== EFI_FV_FILETYPE_DXE_CORE
) {
1312 // If this is the DXE core fill in it's DevicePath & DeviceHandle
1314 if (gDxeCoreLoadedImage
->FilePath
== NULL
) {
1315 if (CompareGuid (&NameGuid
, gDxeCoreFileName
)) {
1317 // Maybe One specail Fv cantains only one DXE_CORE module, so its device path must
1318 // be initialized completely.
1320 EfiInitializeFwVolDevicepathNode (&mFvDevicePath
.File
, &NameGuid
);
1321 SetDevicePathEndNode (&mFvDevicePath
.End
);
1323 gDxeCoreLoadedImage
->FilePath
= DuplicateDevicePath (
1324 (EFI_DEVICE_PATH_PROTOCOL
*)&mFvDevicePath
1326 gDxeCoreLoadedImage
->DeviceHandle
= FvHandle
;
1329 } else if (Type
== EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
) {
1331 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
1334 if (FvFoundInHobFv2 (&KnownHandle
->FvNameGuid
, &NameGuid
)) {
1339 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has SMM depex section.
1343 Status
= Fv
->ReadSection (
1346 EFI_SECTION_SMM_DEPEX
,
1350 &AuthenticationStatus
1352 if (!EFI_ERROR (Status
)) {
1354 // If SMM depex section is found, this FV image is invalid to be supported.
1355 // ASSERT FALSE to report this FV image.
1357 FreePool (DepexBuffer
);
1362 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has DXE depex section.
1366 Status
= Fv
->ReadSection (
1369 EFI_SECTION_DXE_DEPEX
,
1373 &AuthenticationStatus
1375 if (EFI_ERROR (Status
)) {
1377 // If no depex section, produce a firmware volume block protocol for it so it gets dispatched from.
1379 CoreProcessFvImageFile (Fv
, FvHandle
, &NameGuid
);
1382 // If depex section is found, this FV image will be dispatched until its depex is evaluated to TRUE.
1384 FreePool (DepexBuffer
);
1385 CoreAddToDriverList (Fv
, FvHandle
, &NameGuid
, Type
);
1389 // Transition driver from Undiscovered to Discovered state
1391 CoreAddToDriverList (Fv
, FvHandle
, &NameGuid
, Type
);
1394 } while (!EFI_ERROR (GetNextFileStatus
));
1398 // Read the array of GUIDs from the Apriori file if it is present in the firmware volume
1401 Status
= Fv
->ReadSection (
1406 (VOID
**)&AprioriFile
,
1408 &AuthenticationStatus
1410 if (!EFI_ERROR (Status
)) {
1411 AprioriEntryCount
= SizeOfBuffer
/ sizeof (EFI_GUID
);
1413 AprioriEntryCount
= 0;
1417 // Put drivers on Apriori List on the Scheduled queue. The Discovered List includes
1418 // drivers not in the current FV and these must be skipped since the a priori list
1419 // is only valid for the FV that it resided in.
1422 for (Index
= 0; Index
< AprioriEntryCount
; Index
++) {
1423 for (Link
= mDiscoveredList
.ForwardLink
; Link
!= &mDiscoveredList
; Link
= Link
->ForwardLink
) {
1424 DriverEntry
= CR(Link
, EFI_CORE_DRIVER_ENTRY
, Link
, EFI_CORE_DRIVER_ENTRY_SIGNATURE
);
1425 if (CompareGuid (&DriverEntry
->FileName
, &AprioriFile
[Index
]) &&
1426 (FvHandle
== DriverEntry
->FvHandle
)) {
1427 CoreAcquireDispatcherLock ();
1428 DriverEntry
->Dependent
= FALSE
;
1429 DriverEntry
->Scheduled
= TRUE
;
1430 InsertTailList (&mScheduledQueue
, &DriverEntry
->ScheduledLink
);
1431 CoreReleaseDispatcherLock ();
1432 DEBUG ((DEBUG_DISPATCH
, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry
->FileName
));
1433 DEBUG ((DEBUG_DISPATCH
, " RESULT = TRUE (Apriori)\n"));
1440 // Free data allocated by Fv->ReadSection ()
1442 CoreFreePool (AprioriFile
);
1449 Initialize the dispatcher. Initialize the notification function that runs when
1450 an FV2 protocol is added to the system.
1454 CoreInitializeDispatcher (
1458 PERF_FUNCTION_BEGIN ();
1460 mFwVolEvent
= EfiCreateProtocolNotifyEvent (
1461 &gEfiFirmwareVolume2ProtocolGuid
,
1463 CoreFwVolEventProtocolNotify
,
1465 &mFwVolEventRegistration
1468 PERF_FUNCTION_END ();
1472 // Function only used in debug builds
1476 Traverse the discovered list for any drivers that were discovered but not loaded
1477 because the dependency experessions evaluated to false.
1481 CoreDisplayDiscoveredNotDispatched (
1486 EFI_CORE_DRIVER_ENTRY
*DriverEntry
;
1488 for (Link
= mDiscoveredList
.ForwardLink
;Link
!=&mDiscoveredList
; Link
= Link
->ForwardLink
) {
1489 DriverEntry
= CR(Link
, EFI_CORE_DRIVER_ENTRY
, Link
, EFI_CORE_DRIVER_ENTRY_SIGNATURE
);
1490 if (DriverEntry
->Dependent
) {
1491 DEBUG ((DEBUG_LOAD
, "Driver %g was discovered but not loaded!!\n", &DriverEntry
->FileName
));