]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c
MdeModulePkg DXE Core: Add Idle event during BootServices WaitForEvent
[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 - 2011, 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 //
96 // Function Prototypes
97 //
98 /**
99 Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
100 must add any driver with a before dependency on InsertedDriverEntry first.
101 You do this by recursively calling this routine. After all the Befores are
102 processed you can add InsertedDriverEntry to the mScheduledQueue.
103 Then you can add any driver with an After dependency on InsertedDriverEntry
104 by recursively calling this routine.
105
106 @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue
107
108 **/
109 VOID
110 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
111 IN EFI_CORE_DRIVER_ENTRY *InsertedDriverEntry
112 );
113
114 /**
115 Event notification that is fired every time a FV dispatch protocol is added.
116 More than one protocol may have been added when this event is fired, so you
117 must loop on CoreLocateHandle () to see how many protocols were added and
118 do the following to each FV:
119 If the Fv has already been processed, skip it. If the Fv has not been
120 processed then mark it as being processed, as we are about to process it.
121 Read the Fv and add any driver in the Fv to the mDiscoveredList.The
122 mDiscoveredList is never free'ed and contains variables that define
123 the other states the DXE driver transitions to..
124 While you are at it read the A Priori file into memory.
125 Place drivers in the A Priori list onto the mScheduledQueue.
126
127 @param Event The Event that is being processed, not used.
128 @param Context Event Context, not used.
129
130 **/
131 VOID
132 EFIAPI
133 CoreFwVolEventProtocolNotify (
134 IN EFI_EVENT Event,
135 IN VOID *Context
136 );
137
138 /**
139 Convert FvHandle and DriverName into an EFI device path
140
141 @param Fv Fv protocol, needed to read Depex info out of
142 FLASH.
143 @param FvHandle Handle for Fv, needed in the
144 EFI_CORE_DRIVER_ENTRY so that the PE image can be
145 read out of the FV at a later time.
146 @param DriverName Name of driver to add to mDiscoveredList.
147
148 @return Pointer to device path constructed from FvHandle and DriverName
149
150 **/
151 EFI_DEVICE_PATH_PROTOCOL *
152 CoreFvToDevicePath (
153 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
154 IN EFI_HANDLE FvHandle,
155 IN EFI_GUID *DriverName
156 );
157
158 /**
159 Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
160 and initilize any state variables. Read the Depex from the FV and store it
161 in DriverEntry. Pre-process the Depex to set the SOR, Before and After state.
162 The Discovered list is never free'ed and contains booleans that represent the
163 other possible DXE driver states.
164
165 @param Fv Fv protocol, needed to read Depex info out of
166 FLASH.
167 @param FvHandle Handle for Fv, needed in the
168 EFI_CORE_DRIVER_ENTRY so that the PE image can be
169 read out of the FV at a later time.
170 @param DriverName Name of driver 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 );
184
185 /**
186 Get the driver from the FV through driver name, and produce a FVB protocol on FvHandle.
187
188 @param Fv The FIRMWARE_VOLUME protocol installed on the FV.
189 @param FvHandle The handle which FVB protocol installed on.
190 @param DriverName The driver guid specified.
191
192 @retval EFI_OUT_OF_RESOURCES No enough memory or other resource.
193 @retval EFI_VOLUME_CORRUPTED Corrupted volume.
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 *DriverName
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 /**
396 An empty function to pass error checking of CreateEventEx ().
397
398 @param Event Event whose notification function is being invoked.
399 @param Context Pointer to the notification function's context,
400 which is implementation-dependent.
401
402 **/
403 VOID
404 EFIAPI
405 CoreEmptyCallbackFunction (
406 IN EFI_EVENT Event,
407 IN VOID *Context
408 )
409 {
410 return;
411 }
412
413 /**
414 This is the main Dispatcher for DXE and it exits when there are no more
415 drivers to run. Drain the mScheduledQueue and load and start a PE
416 image for each driver. Search the mDiscoveredList to see if any driver can
417 be placed on the mScheduledQueue. If no drivers are placed on the
418 mScheduledQueue exit the function. On exit it is assumed the Bds()
419 will be called, and when the Bds() exits the Dispatcher will be called
420 again.
421
422 @retval EFI_ALREADY_STARTED The DXE Dispatcher is already running
423 @retval EFI_NOT_FOUND No DXE Drivers were dispatched
424 @retval EFI_SUCCESS One or more DXE Drivers were dispatched
425
426 **/
427 EFI_STATUS
428 EFIAPI
429 CoreDispatcher (
430 VOID
431 )
432 {
433 EFI_STATUS Status;
434 EFI_STATUS ReturnStatus;
435 LIST_ENTRY *Link;
436 EFI_CORE_DRIVER_ENTRY *DriverEntry;
437 BOOLEAN ReadyToRun;
438 EFI_EVENT DxeDispatchEvent;
439
440
441 if (gDispatcherRunning) {
442 //
443 // If the dispatcher is running don't let it be restarted.
444 //
445 return EFI_ALREADY_STARTED;
446 }
447
448 gDispatcherRunning = TRUE;
449
450 Status = CoreCreateEventEx (
451 EVT_NOTIFY_SIGNAL,
452 TPL_NOTIFY,
453 CoreEmptyCallbackFunction,
454 NULL,
455 &gEfiEventDxeDispatchGuid,
456 &DxeDispatchEvent
457 );
458 if (EFI_ERROR (Status)) {
459 return Status;
460 }
461
462 ReturnStatus = EFI_NOT_FOUND;
463 do {
464 //
465 // Drain the Scheduled Queue
466 //
467 while (!IsListEmpty (&mScheduledQueue)) {
468 DriverEntry = CR (
469 mScheduledQueue.ForwardLink,
470 EFI_CORE_DRIVER_ENTRY,
471 ScheduledLink,
472 EFI_CORE_DRIVER_ENTRY_SIGNATURE
473 );
474
475 //
476 // Load the DXE Driver image into memory. If the Driver was transitioned from
477 // Untrused to Scheduled it would have already been loaded so we may need to
478 // skip the LoadImage
479 //
480 if (DriverEntry->ImageHandle == NULL) {
481 DEBUG ((DEBUG_INFO, "Loading driver %g\n", &DriverEntry->FileName));
482 Status = CoreLoadImage (
483 FALSE,
484 gDxeCoreImageHandle,
485 DriverEntry->FvFileDevicePath,
486 NULL,
487 0,
488 &DriverEntry->ImageHandle
489 );
490
491 //
492 // Update the driver state to reflect that it's been loaded
493 //
494 if (EFI_ERROR (Status)) {
495 CoreAcquireDispatcherLock ();
496
497 if (Status == EFI_SECURITY_VIOLATION) {
498 //
499 // Take driver from Scheduled to Untrused state
500 //
501 DriverEntry->Untrusted = TRUE;
502 } else {
503 //
504 // The DXE Driver could not be loaded, and do not attempt to load or start it again.
505 // Take driver from Scheduled to Initialized.
506 //
507 // This case include the Never Trusted state if EFI_ACCESS_DENIED is returned
508 //
509 DriverEntry->Initialized = TRUE;
510 }
511
512 DriverEntry->Scheduled = FALSE;
513 RemoveEntryList (&DriverEntry->ScheduledLink);
514
515 CoreReleaseDispatcherLock ();
516
517 //
518 // If it's an error don't try the StartImage
519 //
520 continue;
521 }
522 }
523
524 CoreAcquireDispatcherLock ();
525
526 DriverEntry->Scheduled = FALSE;
527 DriverEntry->Initialized = TRUE;
528 RemoveEntryList (&DriverEntry->ScheduledLink);
529
530 CoreReleaseDispatcherLock ();
531
532
533 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
534 EFI_PROGRESS_CODE,
535 (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_BEGIN),
536 &DriverEntry->ImageHandle,
537 sizeof (DriverEntry->ImageHandle)
538 );
539
540 Status = CoreStartImage (DriverEntry->ImageHandle, NULL, NULL);
541
542 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
543 EFI_PROGRESS_CODE,
544 (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_END),
545 &DriverEntry->ImageHandle,
546 sizeof (DriverEntry->ImageHandle)
547 );
548
549 ReturnStatus = EFI_SUCCESS;
550 }
551
552 //
553 // Now DXE Dispatcher finished one round of dispatch, signal an event group
554 // so that SMM Dispatcher get chance to dispatch SMM Drivers which depend
555 // on UEFI protocols
556 //
557 if (!EFI_ERROR (ReturnStatus)) {
558 CoreSignalEvent (DxeDispatchEvent);
559 }
560
561 //
562 // Search DriverList for items to place on Scheduled Queue
563 //
564 ReadyToRun = FALSE;
565 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
566 DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
567
568 if (DriverEntry->DepexProtocolError){
569 //
570 // If Section Extraction Protocol did not let the Depex be read before retry the read
571 //
572 Status = CoreGetDepexSectionAndPreProccess (DriverEntry);
573 }
574
575 if (DriverEntry->Dependent) {
576 if (CoreIsSchedulable (DriverEntry)) {
577 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
578 ReadyToRun = TRUE;
579 }
580 } else {
581 if (DriverEntry->Unrequested) {
582 DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
583 DEBUG ((DEBUG_DISPATCH, " SOR = Not Requested\n"));
584 DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE\n"));
585 }
586 }
587 }
588 } while (ReadyToRun);
589
590 //
591 // Close DXE dispatch Event
592 //
593 CoreCloseEvent (DxeDispatchEvent);
594
595 gDispatcherRunning = FALSE;
596
597 return ReturnStatus;
598 }
599
600
601 /**
602 Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
603 must add any driver with a before dependency on InsertedDriverEntry first.
604 You do this by recursively calling this routine. After all the Befores are
605 processed you can add InsertedDriverEntry to the mScheduledQueue.
606 Then you can add any driver with an After dependency on InsertedDriverEntry
607 by recursively calling this routine.
608
609 @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue
610
611 **/
612 VOID
613 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
614 IN EFI_CORE_DRIVER_ENTRY *InsertedDriverEntry
615 )
616 {
617 LIST_ENTRY *Link;
618 EFI_CORE_DRIVER_ENTRY *DriverEntry;
619
620 //
621 // Process Before Dependency
622 //
623 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
624 DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
625 if (DriverEntry->Before && DriverEntry->Dependent && DriverEntry != InsertedDriverEntry) {
626 DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
627 DEBUG ((DEBUG_DISPATCH, " BEFORE FFS(%g) = ", &DriverEntry->BeforeAfterGuid));
628 if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
629 //
630 // Recursively process BEFORE
631 //
632 DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n"));
633 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
634 } else {
635 DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));
636 }
637 }
638 }
639
640 //
641 // Convert driver from Dependent to Scheduled state
642 //
643 CoreAcquireDispatcherLock ();
644
645 InsertedDriverEntry->Dependent = FALSE;
646 InsertedDriverEntry->Scheduled = TRUE;
647 InsertTailList (&mScheduledQueue, &InsertedDriverEntry->ScheduledLink);
648
649 CoreReleaseDispatcherLock ();
650
651 //
652 // Process After Dependency
653 //
654 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
655 DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
656 if (DriverEntry->After && DriverEntry->Dependent && DriverEntry != InsertedDriverEntry) {
657 DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
658 DEBUG ((DEBUG_DISPATCH, " AFTER FFS(%g) = ", &DriverEntry->BeforeAfterGuid));
659 if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
660 //
661 // Recursively process AFTER
662 //
663 DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n"));
664 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
665 } else {
666 DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));
667 }
668 }
669 }
670 }
671
672
673 /**
674 Return TRUE if the Fv has been processed, FALSE if not.
675
676 @param FvHandle The handle of a FV that's being tested
677
678 @retval TRUE Fv protocol on FvHandle has been processed
679 @retval FALSE Fv protocol on FvHandle has not yet been processed
680
681 **/
682 BOOLEAN
683 FvHasBeenProcessed (
684 IN EFI_HANDLE FvHandle
685 )
686 {
687 LIST_ENTRY *Link;
688 KNOWN_HANDLE *KnownHandle;
689
690 for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) {
691 KnownHandle = CR(Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE);
692 if (KnownHandle->Handle == FvHandle) {
693 return TRUE;
694 }
695 }
696 return FALSE;
697 }
698
699
700 /**
701 Remember that Fv protocol on FvHandle has had it's drivers placed on the
702 mDiscoveredList. This fucntion adds entries on the mFvHandleList. Items are
703 never removed/freed from the mFvHandleList.
704
705 @param FvHandle The handle of a FV that has been processed
706
707 **/
708 VOID
709 FvIsBeingProcesssed (
710 IN EFI_HANDLE FvHandle
711 )
712 {
713 KNOWN_HANDLE *KnownHandle;
714
715 KnownHandle = AllocatePool (sizeof (KNOWN_HANDLE));
716 ASSERT (KnownHandle != NULL);
717
718 KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE;
719 KnownHandle->Handle = FvHandle;
720 InsertTailList (&mFvHandleList, &KnownHandle->Link);
721 }
722
723
724
725
726 /**
727 Convert FvHandle and DriverName into an EFI device path
728
729 @param Fv Fv protocol, needed to read Depex info out of
730 FLASH.
731 @param FvHandle Handle for Fv, needed in the
732 EFI_CORE_DRIVER_ENTRY so that the PE image can be
733 read out of the FV at a later time.
734 @param DriverName Name of driver to add to mDiscoveredList.
735
736 @return Pointer to device path constructed from FvHandle and DriverName
737
738 **/
739 EFI_DEVICE_PATH_PROTOCOL *
740 CoreFvToDevicePath (
741 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
742 IN EFI_HANDLE FvHandle,
743 IN EFI_GUID *DriverName
744 )
745 {
746 EFI_STATUS Status;
747 EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;
748 EFI_DEVICE_PATH_PROTOCOL *FileNameDevicePath;
749
750 //
751 // Remember the device path of the FV
752 //
753 Status = CoreHandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
754 if (EFI_ERROR (Status)) {
755 FileNameDevicePath = NULL;
756 } else {
757 //
758 // Build a device path to the file in the FV to pass into gBS->LoadImage
759 //
760 EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, DriverName);
761 SetDevicePathEndNode (&mFvDevicePath.End);
762
763 FileNameDevicePath = AppendDevicePath (
764 FvDevicePath,
765 (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath
766 );
767 }
768
769 return FileNameDevicePath;
770 }
771
772
773
774 /**
775 Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
776 and initilize any state variables. Read the Depex from the FV and store it
777 in DriverEntry. Pre-process the Depex to set the SOR, Before and After state.
778 The Discovered list is never free'ed and contains booleans that represent the
779 other possible DXE driver states.
780
781 @param Fv Fv protocol, needed to read Depex info out of
782 FLASH.
783 @param FvHandle Handle for Fv, needed in the
784 EFI_CORE_DRIVER_ENTRY so that the PE image can be
785 read out of the FV at a later time.
786 @param DriverName Name of driver to add to mDiscoveredList.
787
788 @retval EFI_SUCCESS If driver was added to the mDiscoveredList.
789 @retval EFI_ALREADY_STARTED The driver has already been started. Only one
790 DriverName may be active in the system at any one
791 time.
792
793 **/
794 EFI_STATUS
795 CoreAddToDriverList (
796 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
797 IN EFI_HANDLE FvHandle,
798 IN EFI_GUID *DriverName
799 )
800 {
801 EFI_CORE_DRIVER_ENTRY *DriverEntry;
802
803
804 //
805 // Create the Driver Entry for the list. ZeroPool initializes lots of variables to
806 // NULL or FALSE.
807 //
808 DriverEntry = AllocateZeroPool (sizeof (EFI_CORE_DRIVER_ENTRY));
809 ASSERT (DriverEntry != NULL);
810
811 DriverEntry->Signature = EFI_CORE_DRIVER_ENTRY_SIGNATURE;
812 CopyGuid (&DriverEntry->FileName, DriverName);
813 DriverEntry->FvHandle = FvHandle;
814 DriverEntry->Fv = Fv;
815 DriverEntry->FvFileDevicePath = CoreFvToDevicePath (Fv, FvHandle, DriverName);
816
817 CoreGetDepexSectionAndPreProccess (DriverEntry);
818
819 CoreAcquireDispatcherLock ();
820
821 InsertTailList (&mDiscoveredList, &DriverEntry->Link);
822
823 CoreReleaseDispatcherLock ();
824
825 return EFI_SUCCESS;
826 }
827
828
829 /**
830 Check if a FV Image type file (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) is
831 described by a EFI_HOB_FIRMWARE_VOLUME2 Hob.
832
833 @param FvHandle The handle which FVB protocol installed on.
834 @param DriverName The driver guid specified.
835
836 @retval TRUE This file is found in a EFI_HOB_FIRMWARE_VOLUME2
837 Hob.
838 @retval FALSE Not found.
839
840 **/
841 BOOLEAN
842 FvFoundInHobFv2 (
843 IN EFI_HANDLE FvHandle,
844 IN CONST EFI_GUID *DriverName
845 )
846 {
847 EFI_PEI_HOB_POINTERS HobFv2;
848
849 HobFv2.Raw = GetHobList ();
850
851 while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) {
852 if (CompareGuid (DriverName, &HobFv2.FirmwareVolume2->FileName)) {
853 return TRUE;
854 }
855 HobFv2.Raw = GET_NEXT_HOB (HobFv2);
856 }
857
858 return FALSE;
859 }
860
861
862
863 /**
864 Get the driver from the FV through driver name, and produce a FVB protocol on FvHandle.
865
866 @param Fv The FIRMWARE_VOLUME protocol installed on the FV.
867 @param FvHandle The handle which FVB protocol installed on.
868 @param DriverName The driver guid specified.
869
870 @retval EFI_OUT_OF_RESOURCES No enough memory or other resource.
871 @retval EFI_VOLUME_CORRUPTED Corrupted volume.
872 @retval EFI_SUCCESS Function successfully returned.
873
874 **/
875 EFI_STATUS
876 CoreProcessFvImageFile (
877 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
878 IN EFI_HANDLE FvHandle,
879 IN EFI_GUID *DriverName
880 )
881 {
882 EFI_STATUS Status;
883 EFI_SECTION_TYPE SectionType;
884 UINT32 AuthenticationStatus;
885 VOID *Buffer;
886 VOID *AlignedBuffer;
887 UINTN BufferSize;
888 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
889 UINT32 FvAlignment;
890
891 //
892 // Read the first (and only the first) firmware volume section
893 //
894 SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;
895 FvHeader = NULL;
896 FvAlignment = 0;
897 Buffer = NULL;
898 BufferSize = 0;
899 AlignedBuffer = NULL;
900 Status = Fv->ReadSection (
901 Fv,
902 DriverName,
903 SectionType,
904 0,
905 &Buffer,
906 &BufferSize,
907 &AuthenticationStatus
908 );
909 if (!EFI_ERROR (Status)) {
910 //
911 // FvImage should be at its required alignment.
912 //
913 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) Buffer;
914 //
915 // Get FvHeader alignment
916 //
917 FvAlignment = 1 << ((FvHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16);
918 //
919 // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
920 //
921 if (FvAlignment < 8) {
922 FvAlignment = 8;
923 }
924 //
925 // Allocate the aligned buffer for the FvImage.
926 //
927 AlignedBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), (UINTN) FvAlignment);
928 if (AlignedBuffer == NULL) {
929 Status = EFI_OUT_OF_RESOURCES;
930 } else {
931 //
932 // Move FvImage into the aligned buffer and release the original buffer.
933 //
934 CopyMem (AlignedBuffer, Buffer, BufferSize);
935 CoreFreePool (Buffer);
936 Buffer = NULL;
937 //
938 // Produce a FVB protocol for the file
939 //
940 Status = ProduceFVBProtocolOnBuffer (
941 (EFI_PHYSICAL_ADDRESS) (UINTN) AlignedBuffer,
942 (UINT64)BufferSize,
943 FvHandle,
944 NULL
945 );
946 }
947 }
948
949 if (EFI_ERROR (Status)) {
950 //
951 // ReadSection or Produce FVB failed, Free data buffer
952 //
953 if (Buffer != NULL) {
954 FreePool (Buffer);
955 }
956
957 if (AlignedBuffer != NULL) {
958 FreeAlignedPages (AlignedBuffer, EFI_SIZE_TO_PAGES (BufferSize));
959 }
960 }
961
962 return Status;
963 }
964
965
966 /**
967 Event notification that is fired every time a FV dispatch protocol is added.
968 More than one protocol may have been added when this event is fired, so you
969 must loop on CoreLocateHandle () to see how many protocols were added and
970 do the following to each FV:
971 If the Fv has already been processed, skip it. If the Fv has not been
972 processed then mark it as being processed, as we are about to process it.
973 Read the Fv and add any driver in the Fv to the mDiscoveredList.The
974 mDiscoveredList is never free'ed and contains variables that define
975 the other states the DXE driver transitions to..
976 While you are at it read the A Priori file into memory.
977 Place drivers in the A Priori list onto the mScheduledQueue.
978
979 @param Event The Event that is being processed, not used.
980 @param Context Event Context, not used.
981
982 **/
983 VOID
984 EFIAPI
985 CoreFwVolEventProtocolNotify (
986 IN EFI_EVENT Event,
987 IN VOID *Context
988 )
989 {
990 EFI_STATUS Status;
991 EFI_STATUS GetNextFileStatus;
992 EFI_STATUS SecurityStatus;
993 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
994 EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;
995 EFI_HANDLE FvHandle;
996 UINTN BufferSize;
997 EFI_GUID NameGuid;
998 UINTN Key;
999 EFI_FV_FILETYPE Type;
1000 EFI_FV_FILE_ATTRIBUTES Attributes;
1001 UINTN Size;
1002 EFI_CORE_DRIVER_ENTRY *DriverEntry;
1003 EFI_GUID *AprioriFile;
1004 UINTN AprioriEntryCount;
1005 UINTN Index;
1006 LIST_ENTRY *Link;
1007 UINT32 AuthenticationStatus;
1008 UINTN SizeOfBuffer;
1009
1010
1011 while (TRUE) {
1012 BufferSize = sizeof (EFI_HANDLE);
1013 Status = CoreLocateHandle (
1014 ByRegisterNotify,
1015 NULL,
1016 mFwVolEventRegistration,
1017 &BufferSize,
1018 &FvHandle
1019 );
1020 if (EFI_ERROR (Status)) {
1021 //
1022 // If no more notification events exit
1023 //
1024 return;
1025 }
1026
1027 if (FvHasBeenProcessed (FvHandle)) {
1028 //
1029 // This Fv has already been processed so lets skip it!
1030 //
1031 continue;
1032 }
1033
1034 //
1035 // Since we are about to process this Fv mark it as processed.
1036 //
1037 FvIsBeingProcesssed (FvHandle);
1038
1039 Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);
1040 if (EFI_ERROR (Status) || Fv == NULL) {
1041 //
1042 // FvHandle must have Firmware Volume2 protocol thus we should never get here.
1043 //
1044 ASSERT (FALSE);
1045 continue;
1046 }
1047
1048 Status = CoreHandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
1049 if (EFI_ERROR (Status)) {
1050 //
1051 // The Firmware volume doesn't have device path, can't be dispatched.
1052 //
1053 continue;
1054 }
1055
1056 //
1057 // Evaluate the authentication status of the Firmware Volume through
1058 // Security Architectural Protocol
1059 //
1060 if (gSecurity != NULL) {
1061 SecurityStatus = gSecurity->FileAuthenticationState (
1062 gSecurity,
1063 0,
1064 FvDevicePath
1065 );
1066 if (SecurityStatus != EFI_SUCCESS) {
1067 //
1068 // Security check failed. The firmware volume should not be used for any purpose.
1069 //
1070 continue;
1071 }
1072 }
1073
1074 //
1075 // Discover Drivers in FV and add them to the Discovered Driver List.
1076 // Process EFI_FV_FILETYPE_DRIVER type and then EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
1077 // EFI_FV_FILETYPE_DXE_CORE is processed to produce a Loaded Image protocol for the core
1078 // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE is processed to create a Fvb
1079 //
1080 for (Index = 0; Index < sizeof (mDxeFileTypes) / sizeof (EFI_FV_FILETYPE); Index++) {
1081 //
1082 // Initialize the search key
1083 //
1084 Key = 0;
1085 do {
1086 Type = mDxeFileTypes[Index];
1087 GetNextFileStatus = Fv->GetNextFile (
1088 Fv,
1089 &Key,
1090 &Type,
1091 &NameGuid,
1092 &Attributes,
1093 &Size
1094 );
1095 if (!EFI_ERROR (GetNextFileStatus)) {
1096 if (Type == EFI_FV_FILETYPE_DXE_CORE) {
1097 //
1098 // If this is the DXE core fill in it's DevicePath & DeviceHandle
1099 //
1100 if (gDxeCoreLoadedImage->FilePath == NULL) {
1101 if (CompareGuid (&NameGuid, gDxeCoreFileName)) {
1102 //
1103 // Maybe One specail Fv cantains only one DXE_CORE module, so its device path must
1104 // be initialized completely.
1105 //
1106 EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid);
1107 SetDevicePathEndNode (&mFvDevicePath.End);
1108
1109 gDxeCoreLoadedImage->FilePath = DuplicateDevicePath (
1110 (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath
1111 );
1112 gDxeCoreLoadedImage->DeviceHandle = FvHandle;
1113 }
1114 }
1115 } else if (Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
1116 //
1117 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
1118 // been extracted.
1119 //
1120 if (FvFoundInHobFv2 (FvHandle, &NameGuid)) {
1121 continue;
1122 }
1123 //
1124 // Found a firmware volume image. Produce a firmware volume block
1125 // protocol for it so it gets dispatched from. This is usually a
1126 // capsule.
1127 //
1128 CoreProcessFvImageFile (Fv, FvHandle, &NameGuid);
1129 } else {
1130 //
1131 // Transition driver from Undiscovered to Discovered state
1132 //
1133 CoreAddToDriverList (Fv, FvHandle, &NameGuid);
1134 }
1135 }
1136 } while (!EFI_ERROR (GetNextFileStatus));
1137 }
1138
1139 //
1140 // Read the array of GUIDs from the Apriori file if it is present in the firmware volume
1141 //
1142 AprioriFile = NULL;
1143 Status = Fv->ReadSection (
1144 Fv,
1145 &gAprioriGuid,
1146 EFI_SECTION_RAW,
1147 0,
1148 (VOID **)&AprioriFile,
1149 &SizeOfBuffer,
1150 &AuthenticationStatus
1151 );
1152 if (!EFI_ERROR (Status)) {
1153 AprioriEntryCount = SizeOfBuffer / sizeof (EFI_GUID);
1154 } else {
1155 AprioriEntryCount = 0;
1156 }
1157
1158 //
1159 // Put drivers on Apriori List on the Scheduled queue. The Discovered List includes
1160 // drivers not in the current FV and these must be skipped since the a priori list
1161 // is only valid for the FV that it resided in.
1162 //
1163
1164 for (Index = 0; Index < AprioriEntryCount; Index++) {
1165 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
1166 DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
1167 if (CompareGuid (&DriverEntry->FileName, &AprioriFile[Index]) &&
1168 (FvHandle == DriverEntry->FvHandle)) {
1169 CoreAcquireDispatcherLock ();
1170 DriverEntry->Dependent = FALSE;
1171 DriverEntry->Scheduled = TRUE;
1172 InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);
1173 CoreReleaseDispatcherLock ();
1174 DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));
1175 DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (Apriori)\n"));
1176 break;
1177 }
1178 }
1179 }
1180
1181 //
1182 // Free data allocated by Fv->ReadSection ()
1183 //
1184 CoreFreePool (AprioriFile);
1185 }
1186 }
1187
1188
1189
1190 /**
1191 Initialize the dispatcher. Initialize the notification function that runs when
1192 an FV2 protocol is added to the system.
1193
1194 **/
1195 VOID
1196 CoreInitializeDispatcher (
1197 VOID
1198 )
1199 {
1200 mFwVolEvent = EfiCreateProtocolNotifyEvent (
1201 &gEfiFirmwareVolume2ProtocolGuid,
1202 TPL_CALLBACK,
1203 CoreFwVolEventProtocolNotify,
1204 NULL,
1205 &mFwVolEventRegistration
1206 );
1207 }
1208
1209 //
1210 // Function only used in debug builds
1211 //
1212
1213 /**
1214 Traverse the discovered list for any drivers that were discovered but not loaded
1215 because the dependency experessions evaluated to false.
1216
1217 **/
1218 VOID
1219 CoreDisplayDiscoveredNotDispatched (
1220 VOID
1221 )
1222 {
1223 LIST_ENTRY *Link;
1224 EFI_CORE_DRIVER_ENTRY *DriverEntry;
1225
1226 for (Link = mDiscoveredList.ForwardLink;Link !=&mDiscoveredList; Link = Link->ForwardLink) {
1227 DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
1228 if (DriverEntry->Dependent) {
1229 DEBUG ((DEBUG_LOAD, "Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName));
1230 }
1231 }
1232 }