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