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