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