]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c
MdeModule cleanup for PI:
[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 - 2007, Intel Corporation
30 All rights reserved. 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 static EFI_FV_FILETYPE mDxeFileTypes[] = {
80 EFI_FV_FILETYPE_DRIVER,
81 EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,
82 EFI_FV_FILETYPE_DXE_CORE,
83 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
84 };
85
86 typedef struct {
87 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH File;
88 EFI_DEVICE_PATH_PROTOCOL End;
89 } FV_FILEPATH_DEVICE_PATH;
90
91 FV_FILEPATH_DEVICE_PATH mFvDevicePath;
92
93
94 //
95 // Function Prototypes
96 //
97 STATIC
98 VOID
99 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
100 IN EFI_CORE_DRIVER_ENTRY *InsertedDriverEntry
101 );
102
103 STATIC
104 VOID
105 EFIAPI
106 CoreFwVolEventProtocolNotify (
107 IN EFI_EVENT Event,
108 IN VOID *Context
109 );
110
111 STATIC
112 EFI_DEVICE_PATH_PROTOCOL *
113 CoreFvToDevicePath (
114 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
115 IN EFI_HANDLE FvHandle,
116 IN EFI_GUID *DriverName
117 );
118
119 STATIC
120 EFI_STATUS
121 CoreAddToDriverList (
122 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
123 IN EFI_HANDLE FvHandle,
124 IN EFI_GUID *DriverName
125 );
126
127 STATIC
128 EFI_STATUS
129 CoreProcessFvImageFile (
130 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
131 IN EFI_HANDLE FvHandle,
132 IN EFI_GUID *DriverName
133 );
134
135 STATIC
136 VOID
137 CoreAcquireDispatcherLock (
138 VOID
139 )
140 /*++
141
142 Routine Description:
143
144 Enter critical section by gaining lock on mDispatcherLock
145
146 Arguments:
147
148 None
149
150 Returns:
151
152 None
153
154 --*/
155
156 {
157 CoreAcquireLock (&mDispatcherLock);
158 }
159
160 STATIC
161 VOID
162 CoreReleaseDispatcherLock (
163 VOID
164 )
165 /*++
166
167 Routine Description:
168
169 Exit critical section by releasing lock on mDispatcherLock
170
171 Arguments:
172
173 None
174
175 Returns:
176
177 None
178
179 --*/
180 {
181 CoreReleaseLock (&mDispatcherLock);
182 }
183
184 STATIC
185 EFI_STATUS
186 CoreGetDepexSectionAndPreProccess (
187 IN EFI_CORE_DRIVER_ENTRY *DriverEntry
188 )
189 /*++
190
191 Routine Description:
192
193 Read Depex and pre-process the Depex for Before and After. If Section Extraction
194 protocol returns an error via ReadSection defer the reading of the Depex.
195
196 Arguments:
197
198 DriverEntry - Driver to work on.
199
200 Returns:
201
202 EFI_SUCCESS - Depex read and preprossesed
203
204 EFI_PROTOCOL_ERROR - The section extraction protocol returned an error and
205 Depex reading needs to be retried.
206
207 Other Error - DEPEX not found.
208
209 --*/
210 {
211 EFI_STATUS Status;
212 EFI_SECTION_TYPE SectionType;
213 UINT32 AuthenticationStatus;
214 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
215
216
217 Fv = DriverEntry->Fv;
218
219 //
220 // Grab Depex info, it will never be free'ed.
221 //
222 SectionType = EFI_SECTION_DXE_DEPEX;
223 Status = Fv->ReadSection (
224 DriverEntry->Fv,
225 &DriverEntry->FileName,
226 SectionType,
227 0,
228 &DriverEntry->Depex,
229 (UINTN *)&DriverEntry->DepexSize,
230 &AuthenticationStatus
231 );
232 if (EFI_ERROR (Status)) {
233 if (Status == EFI_PROTOCOL_ERROR) {
234 //
235 // The section extraction protocol failed so set protocol error flag
236 //
237 DriverEntry->DepexProtocolError = TRUE;
238 } else {
239 //
240 // If no Depex assume UEFI 2.0 driver model
241 //
242 DriverEntry->Depex = NULL;
243 DriverEntry->Dependent = TRUE;
244 DriverEntry->DepexProtocolError = FALSE;
245 }
246 } else {
247 //
248 // Set Before, After, and Unrequested state information based on Depex
249 // Driver will be put in Dependent or Unrequested state
250 //
251 CorePreProcessDepex (DriverEntry);
252 DriverEntry->DepexProtocolError = FALSE;
253 }
254
255 return Status;
256 }
257
258 EFI_DXESERVICE
259 EFI_STATUS
260 EFIAPI
261 CoreSchedule (
262 IN EFI_HANDLE FirmwareVolumeHandle,
263 IN EFI_GUID *DriverName
264 )
265 /*++
266
267 Routine Description:
268
269 Check every driver and locate a matching one. If the driver is found, the Unrequested
270 state flag is cleared.
271
272 Arguments:
273
274 FirmwareVolumeHandle - The handle of the Firmware Volume that contains the firmware
275 file specified by DriverName.
276
277 DriverName - The Driver name to put in the Dependent state.
278
279 Returns:
280
281 EFI_SUCCESS - The DriverName was found and it's SOR bit was cleared
282
283 EFI_NOT_FOUND - The DriverName does not exist or it's SOR bit was not set.
284
285 --*/
286 {
287 LIST_ENTRY *Link;
288 EFI_CORE_DRIVER_ENTRY *DriverEntry;
289
290 //
291 // Check every driver
292 //
293 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
294 DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
295 if (DriverEntry->FvHandle == FirmwareVolumeHandle &&
296 DriverEntry->Unrequested &&
297 CompareGuid (DriverName, &DriverEntry->FileName)) {
298 //
299 // Move the driver from the Unrequested to the Dependent state
300 //
301 CoreAcquireDispatcherLock ();
302 DriverEntry->Unrequested = FALSE;
303 DriverEntry->Dependent = TRUE;
304 CoreReleaseDispatcherLock ();
305
306 return EFI_SUCCESS;
307 }
308 }
309 return EFI_NOT_FOUND;
310 }
311
312
313 EFI_DXESERVICE
314 EFI_STATUS
315 EFIAPI
316 CoreTrust (
317 IN EFI_HANDLE FirmwareVolumeHandle,
318 IN EFI_GUID *DriverName
319 )
320 /*++
321
322 Routine Description:
323
324 Convert a driver from the Untrused back to the Scheduled state
325
326 Arguments:
327
328 FirmwareVolumeHandle - The handle of the Firmware Volume that contains the firmware
329 file specified by DriverName.
330
331 DriverName - The Driver name to put in the Scheduled state
332
333 Returns:
334
335 EFI_SUCCESS - The file was found in the untrusted state, and it was promoted
336 to the trusted state.
337
338 EFI_NOT_FOUND - The file was not found in the untrusted state.
339
340 --*/
341 {
342 LIST_ENTRY *Link;
343 EFI_CORE_DRIVER_ENTRY *DriverEntry;
344
345 //
346 // Check every driver
347 //
348 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
349 DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
350 if (DriverEntry->FvHandle == FirmwareVolumeHandle &&
351 DriverEntry->Untrusted &&
352 CompareGuid (DriverName, &DriverEntry->FileName)) {
353 //
354 // Transition driver from Untrusted to Scheduled state.
355 //
356 CoreAcquireDispatcherLock ();
357 DriverEntry->Untrusted = FALSE;
358 DriverEntry->Scheduled = TRUE;
359 InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);
360 CoreReleaseDispatcherLock ();
361
362 return EFI_SUCCESS;
363 }
364 }
365 return EFI_NOT_FOUND;
366 }
367
368
369 EFI_DXESERVICE
370 EFI_STATUS
371 EFIAPI
372 CoreDispatcher (
373 VOID
374 )
375 /*++
376
377 Routine Description:
378
379 This is the main Dispatcher for DXE and it exits when there are no more
380 drivers to run. Drain the mScheduledQueue and load and start a PE
381 image for each driver. Search the mDiscoveredList to see if any driver can
382 be placed on the mScheduledQueue. If no drivers are placed on the
383 mScheduledQueue exit the function. On exit it is assumed the Bds()
384 will be called, and when the Bds() exits the Dispatcher will be called
385 again.
386
387 Arguments:
388
389 NONE
390
391 Returns:
392
393 EFI_ALREADY_STARTED - The DXE Dispatcher is already running
394
395 EFI_NOT_FOUND - No DXE Drivers were dispatched
396
397 EFI_SUCCESS - One or more DXE Drivers were dispatched
398
399 --*/
400 {
401 EFI_STATUS Status;
402 EFI_STATUS ReturnStatus;
403 LIST_ENTRY *Link;
404 EFI_CORE_DRIVER_ENTRY *DriverEntry;
405 BOOLEAN ReadyToRun;
406
407 if (gDispatcherRunning) {
408 //
409 // If the dispatcher is running don't let it be restarted.
410 //
411 return EFI_ALREADY_STARTED;
412 }
413
414 gDispatcherRunning = TRUE;
415
416
417 ReturnStatus = EFI_NOT_FOUND;
418 do {
419 //
420 // Drain the Scheduled Queue
421 //
422 while (!IsListEmpty (&mScheduledQueue)) {
423 DriverEntry = CR (
424 mScheduledQueue.ForwardLink,
425 EFI_CORE_DRIVER_ENTRY,
426 ScheduledLink,
427 EFI_CORE_DRIVER_ENTRY_SIGNATURE
428 );
429
430 //
431 // Load the DXE Driver image into memory. If the Driver was transitioned from
432 // Untrused to Scheduled it would have already been loaded so we may need to
433 // skip the LoadImage
434 //
435 if (DriverEntry->ImageHandle == NULL) {
436 Status = CoreLoadImage (
437 FALSE,
438 gDxeCoreImageHandle,
439 DriverEntry->FvFileDevicePath,
440 NULL,
441 0,
442 &DriverEntry->ImageHandle
443 );
444
445 //
446 // Update the driver state to reflect that it's been loaded
447 //
448 if (EFI_ERROR (Status)) {
449 CoreAcquireDispatcherLock ();
450
451 if (Status == EFI_SECURITY_VIOLATION) {
452 //
453 // Take driver from Scheduled to Untrused state
454 //
455 DriverEntry->Untrusted = TRUE;
456 } else {
457 //
458 // The DXE Driver could not be loaded, and do not attempt to load or start it again.
459 // Take driver from Scheduled to Initialized.
460 //
461 // This case include the Never Trusted state if EFI_ACCESS_DENIED is returned
462 //
463 DriverEntry->Initialized = TRUE;
464 }
465
466 DriverEntry->Scheduled = FALSE;
467 RemoveEntryList (&DriverEntry->ScheduledLink);
468
469 CoreReleaseDispatcherLock ();
470
471 //
472 // If it's an error don't try the StartImage
473 //
474 continue;
475 }
476 }
477
478 CoreAcquireDispatcherLock ();
479
480 DriverEntry->Scheduled = FALSE;
481 DriverEntry->Initialized = TRUE;
482 RemoveEntryList (&DriverEntry->ScheduledLink);
483
484 CoreReleaseDispatcherLock ();
485
486 CoreReportProgressCodeSpecific (
487 FixedPcdGet32(PcdStatusCodeValueDxeDriverBegin),
488 DriverEntry->ImageHandle
489 );
490 Status = CoreStartImage (DriverEntry->ImageHandle, NULL, NULL);
491 CoreReportProgressCodeSpecific (
492 FixedPcdGet32(PcdStatusCodeValueDxeDriverEnd),
493 DriverEntry->ImageHandle
494 );
495
496 ReturnStatus = EFI_SUCCESS;
497 }
498
499 //
500 // Search DriverList for items to place on Scheduled Queue
501 //
502 ReadyToRun = FALSE;
503 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
504 DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
505
506 if (DriverEntry->DepexProtocolError){
507 //
508 // If Section Extraction Protocol did not let the Depex be read before retry the read
509 //
510 Status = CoreGetDepexSectionAndPreProccess (DriverEntry);
511 }
512
513 if (DriverEntry->Dependent) {
514 if (CoreIsSchedulable (DriverEntry)) {
515 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
516 ReadyToRun = TRUE;
517 }
518 }
519 }
520 } while (ReadyToRun);
521
522 gDispatcherRunning = FALSE;
523
524 return ReturnStatus;
525 }
526
527 STATIC
528 VOID
529 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
530 IN EFI_CORE_DRIVER_ENTRY *InsertedDriverEntry
531 )
532 /*++
533
534 Routine Description:
535
536 Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
537 must add any driver with a before dependency on InsertedDriverEntry first.
538 You do this by recursively calling this routine. After all the Befores are
539 processed you can add InsertedDriverEntry to the mScheduledQueue.
540 Then you can add any driver with an After dependency on InsertedDriverEntry
541 by recursively calling this routine.
542
543 Arguments:
544
545 InsertedDriverEntry - The driver to insert on the ScheduledLink Queue
546
547 Returns:
548
549 NONE
550
551 --*/
552 {
553 LIST_ENTRY *Link;
554 EFI_CORE_DRIVER_ENTRY *DriverEntry;
555
556 //
557 // Process Before Dependency
558 //
559 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
560 DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
561 if (DriverEntry->Before && DriverEntry->Dependent) {
562 if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
563 //
564 // Recursively process BEFORE
565 //
566 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
567 }
568 }
569 }
570
571 //
572 // Convert driver from Dependent to Scheduled state
573 //
574 CoreAcquireDispatcherLock ();
575
576 InsertedDriverEntry->Dependent = FALSE;
577 InsertedDriverEntry->Scheduled = TRUE;
578 InsertTailList (&mScheduledQueue, &InsertedDriverEntry->ScheduledLink);
579
580 CoreReleaseDispatcherLock ();
581
582 //
583 // Process After Dependency
584 //
585 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
586 DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
587 if (DriverEntry->After && DriverEntry->Dependent) {
588 if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
589 //
590 // Recursively process AFTER
591 //
592 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
593 }
594 }
595 }
596 }
597
598 STATIC
599 BOOLEAN
600 FvHasBeenProcessed (
601 IN EFI_HANDLE FvHandle
602 )
603 /*++
604
605 Routine Description:
606
607 Return TRUE if the Fv has been processed, FALSE if not.
608
609 Arguments:
610
611 FvHandle - The handle of a FV that's being tested
612
613 Returns:
614
615 TRUE - Fv protocol on FvHandle has been processed
616
617 FALSE - Fv protocol on FvHandle has not yet been processed
618
619 --*/
620 {
621 LIST_ENTRY *Link;
622 KNOWN_HANDLE *KnownHandle;
623
624 for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) {
625 KnownHandle = CR(Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE);
626 if (KnownHandle->Handle == FvHandle) {
627 return TRUE;
628 }
629 }
630 return FALSE;
631 }
632
633 STATIC
634 VOID
635 FvIsBeingProcesssed (
636 IN EFI_HANDLE FvHandle
637 )
638 /*++
639
640 Routine Description:
641
642 Remember that Fv protocol on FvHandle has had it's drivers placed on the
643 mDiscoveredList. This fucntion adds entries on the mFvHandleList. Items are
644 never removed/freed from the mFvHandleList.
645
646 Arguments:
647
648 FvHandle - The handle of a FV that has been processed
649
650 Returns:
651
652 None
653
654 --*/
655 {
656 KNOWN_HANDLE *KnownHandle;
657
658 KnownHandle = CoreAllocateBootServicesPool (sizeof (KNOWN_HANDLE));
659 ASSERT (KnownHandle != NULL);
660
661 KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE;
662 KnownHandle->Handle = FvHandle;
663 InsertTailList (&mFvHandleList, &KnownHandle->Link);
664 }
665
666
667
668 STATIC
669 EFI_DEVICE_PATH_PROTOCOL *
670 CoreFvToDevicePath (
671 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
672 IN EFI_HANDLE FvHandle,
673 IN EFI_GUID *DriverName
674 )
675 /*++
676
677 Routine Description:
678
679 Convert FvHandle and DriverName into an EFI device path
680
681 Arguments:
682
683 Fv - Fv protocol, needed to read Depex info out of FLASH.
684
685 FvHandle - Handle for Fv, needed in the EFI_CORE_DRIVER_ENTRY so that the
686 PE image can be read out of the FV at a later time.
687
688 DriverName - Name of driver to add to mDiscoveredList.
689
690 Returns:
691
692 Pointer to device path constructed from FvHandle and DriverName
693
694 --*/
695 {
696 EFI_STATUS Status;
697 EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;
698 EFI_DEVICE_PATH_PROTOCOL *FileNameDevicePath;
699
700 //
701 // Remember the device path of the FV
702 //
703 Status = CoreHandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
704 if (EFI_ERROR (Status)) {
705 FileNameDevicePath = NULL;
706 } else {
707 //
708 // Build a device path to the file in the FV to pass into gBS->LoadImage
709 //
710 EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, DriverName);
711 mFvDevicePath.End.Type = EFI_END_ENTIRE_DEVICE_PATH;
712 mFvDevicePath.End.SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
713 SetDevicePathNodeLength (&mFvDevicePath.End, sizeof (EFI_DEVICE_PATH_PROTOCOL));
714
715 FileNameDevicePath = CoreAppendDevicePath (
716 FvDevicePath,
717 (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath
718 );
719 }
720
721 return FileNameDevicePath;
722 }
723
724
725
726 EFI_STATUS
727 CoreAddToDriverList (
728 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
729 IN EFI_HANDLE FvHandle,
730 IN EFI_GUID *DriverName
731 )
732 /*++
733
734 Routine Description:
735
736 Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
737 and initilize any state variables. Read the Depex from the FV and store it
738 in DriverEntry. Pre-process the Depex to set the SOR, Before and After state.
739 The Discovered list is never free'ed and contains booleans that represent the
740 other possible DXE driver states.
741
742 Arguments:
743
744 Fv - Fv protocol, needed to read Depex info out of FLASH.
745
746 FvHandle - Handle for Fv, needed in the EFI_CORE_DRIVER_ENTRY so that the
747 PE image can be read out of the FV at a later time.
748
749 DriverName - Name of driver to add to mDiscoveredList.
750
751 Returns:
752
753 EFI_SUCCESS - If driver was added to the mDiscoveredList.
754
755 EFI_ALREADY_STARTED - The driver has already been started. Only one DriverName
756 may be active in the system at any one time.
757
758 --*/
759 {
760 EFI_CORE_DRIVER_ENTRY *DriverEntry;
761
762
763 //
764 // Create the Driver Entry for the list. ZeroPool initializes lots of variables to
765 // NULL or FALSE.
766 //
767 DriverEntry = CoreAllocateZeroBootServicesPool (sizeof (EFI_CORE_DRIVER_ENTRY));
768 ASSERT (DriverEntry != NULL);
769
770 DriverEntry->Signature = EFI_CORE_DRIVER_ENTRY_SIGNATURE;
771 CopyMem (&DriverEntry->FileName, DriverName, sizeof (EFI_GUID));
772 DriverEntry->FvHandle = FvHandle;
773 DriverEntry->Fv = Fv;
774 DriverEntry->FvFileDevicePath = CoreFvToDevicePath (Fv, FvHandle, DriverName);
775
776 CoreGetDepexSectionAndPreProccess (DriverEntry);
777
778 CoreAcquireDispatcherLock ();
779
780 InsertTailList (&mDiscoveredList, &DriverEntry->Link);
781
782 CoreReleaseDispatcherLock ();
783
784 return EFI_SUCCESS;
785 }
786
787 STATIC
788 BOOLEAN
789 FvFoundInHobFv2 (
790 IN EFI_HANDLE FvHandle,
791 IN CONST EFI_GUID *DriverName
792 )
793 /*++
794
795 Routine Description:
796
797 Check if a FV Image type file (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) is
798 described by a EFI_HOB_FIRMWARE_VOLUME2 Hob.
799
800 Arguments:
801
802 FvHandle - The handle which FVB protocol installed on.
803 DriverName - The driver guid specified.
804
805 Returns:
806
807 TRUE - This file is found in a EFI_HOB_FIRMWARE_VOLUME2 Hob.
808
809 FALSE - Not found.
810
811
812 --*/
813 {
814 EFI_PEI_HOB_POINTERS HobFv2;
815
816 HobFv2.Raw = GetHobList ();
817
818 while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) {
819 if (CompareGuid (DriverName, &HobFv2.FirmwareVolume2->FileName)) {
820 return TRUE;
821 }
822 HobFv2.Raw = GET_NEXT_HOB (HobFv2);
823 }
824
825 return FALSE;
826 }
827
828
829 EFI_STATUS
830 CoreProcessFvImageFile (
831 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
832 IN EFI_HANDLE FvHandle,
833 IN EFI_GUID *DriverName
834 )
835 /*++
836
837 Routine Description:
838
839 Get the driver from the FV through driver name, and produce a FVB protocol on FvHandle.
840
841 Arguments:
842
843 Fv - The FIRMWARE_VOLUME protocol installed on the FV.
844 FvHandle - The handle which FVB protocol installed on.
845 DriverName - The driver guid specified.
846
847 Returns:
848
849 EFI_OUT_OF_RESOURCES - No enough memory or other resource.
850
851 EFI_VOLUME_CORRUPTED - Corrupted volume.
852
853 EFI_SUCCESS - Function successfully returned.
854
855
856 --*/
857 {
858 EFI_STATUS Status;
859 EFI_SECTION_TYPE SectionType;
860 UINT32 AuthenticationStatus;
861 VOID *Buffer;
862 UINTN BufferSize;
863
864 //
865 // Read the first (and only the first) firmware volume section
866 //
867 SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;
868 Buffer = NULL;
869 BufferSize = 0;
870 Status = Fv->ReadSection (
871 Fv,
872 DriverName,
873 SectionType,
874 0,
875 &Buffer,
876 &BufferSize,
877 &AuthenticationStatus
878 );
879 if (!EFI_ERROR (Status)) {
880 //
881 // Produce a FVB protocol for the file
882 //
883 Status = ProduceFVBProtocolOnBuffer (
884 (EFI_PHYSICAL_ADDRESS) (UINTN) Buffer,
885 (UINT64)BufferSize,
886 FvHandle,
887 NULL
888 );
889 }
890
891 if (EFI_ERROR (Status) && (Buffer != NULL)) {
892 //
893 // ReadSection or Produce FVB failed, Free data buffer
894 //
895 CoreFreePool (Buffer);
896
897 }
898
899 return Status;
900 }
901
902 STATIC
903 VOID
904 EFIAPI
905 CoreFwVolEventProtocolNotify (
906 IN EFI_EVENT Event,
907 IN VOID *Context
908 )
909 /*++
910
911 Routine Description:
912
913 Event notification that is fired every time a FV dispatch protocol is added.
914 More than one protocol may have been added when this event is fired, so you
915 must loop on CoreLocateHandle () to see how many protocols were added and
916 do the following to each FV:
917
918 If the Fv has already been processed, skip it. If the Fv has not been
919 processed then mark it as being processed, as we are about to process it.
920
921 Read the Fv and add any driver in the Fv to the mDiscoveredList.The
922 mDiscoveredList is never free'ed and contains variables that define
923 the other states the DXE driver transitions to..
924
925 While you are at it read the A Priori file into memory.
926 Place drivers in the A Priori list onto the mScheduledQueue.
927
928 Arguments:
929
930 Event - The Event that is being processed, not used.
931
932 Context - Event Context, not used.
933
934 Returns:
935
936 None
937
938 --*/
939 {
940 EFI_STATUS Status;
941 EFI_STATUS GetNextFileStatus;
942 EFI_STATUS SecurityStatus;
943 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
944 EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;
945 EFI_HANDLE FvHandle;
946 UINTN BufferSize;
947 EFI_GUID NameGuid;
948 UINTN Key;
949 EFI_FV_FILETYPE Type;
950 EFI_FV_FILE_ATTRIBUTES Attributes;
951 UINTN Size;
952 EFI_CORE_DRIVER_ENTRY *DriverEntry;
953 EFI_GUID *AprioriFile;
954 UINTN AprioriEntryCount;
955 UINTN Index;
956 LIST_ENTRY *Link;
957 UINT32 AuthenticationStatus;
958 UINTN SizeOfBuffer;
959
960
961 while (TRUE) {
962 BufferSize = sizeof (EFI_HANDLE);
963 Status = CoreLocateHandle (
964 ByRegisterNotify,
965 NULL,
966 mFwVolEventRegistration,
967 &BufferSize,
968 &FvHandle
969 );
970 if (EFI_ERROR (Status)) {
971 //
972 // If no more notification events exit
973 //
974 return;
975 }
976
977 if (FvHasBeenProcessed (FvHandle)) {
978 //
979 // This Fv has already been processed so lets skip it!
980 //
981 continue;
982 }
983
984 Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolumeDispatchProtocolGuid, (VOID **)&Fv);
985 if (EFI_ERROR (Status)) {
986 //
987 // If no dispatch protocol then skip, but do not marked as being processed as it
988 // may show up later.
989 //
990 continue;
991 }
992
993 //
994 // Since we are about to process this Fv mark it as processed.
995 //
996 FvIsBeingProcesssed (FvHandle);
997
998
999 Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);
1000 if (EFI_ERROR (Status)) {
1001 //
1002 // The Handle has a FirmwareVolumeDispatch protocol and should also contiain
1003 // a FirmwareVolume protocol thus we should never get here.
1004 //
1005 ASSERT (FALSE);
1006 continue;
1007 }
1008
1009 Status = CoreHandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
1010 if (EFI_ERROR (Status)) {
1011 //
1012 // The Firmware volume doesn't have device path, can't be dispatched.
1013 //
1014 continue;
1015 }
1016
1017 //
1018 // Evaluate the authentication status of the Firmware Volume through
1019 // Security Architectural Protocol
1020 //
1021 if (gSecurity != NULL) {
1022 SecurityStatus = gSecurity->FileAuthenticationState (
1023 gSecurity,
1024 0,
1025 FvDevicePath
1026 );
1027 if (SecurityStatus != EFI_SUCCESS) {
1028 //
1029 // Security check failed. The firmware volume should not be used for any purpose.
1030 //
1031 continue;
1032 }
1033 }
1034
1035 //
1036 // Discover Drivers in FV and add them to the Discovered Driver List.
1037 // Process EFI_FV_FILETYPE_DRIVER type and then EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER
1038 // EFI_FV_FILETYPE_DXE_CORE is processed to produce a Loaded Image protocol for the core
1039 // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE is processed to create a Fvb
1040 //
1041 for (Index = 0; Index < sizeof (mDxeFileTypes)/sizeof (EFI_FV_FILETYPE); Index++) {
1042 //
1043 // Initialize the search key
1044 //
1045 Key = 0;
1046 do {
1047 Type = mDxeFileTypes[Index];
1048 GetNextFileStatus = Fv->GetNextFile (
1049 Fv,
1050 &Key,
1051 &Type,
1052 &NameGuid,
1053 &Attributes,
1054 &Size
1055 );
1056 if (!EFI_ERROR (GetNextFileStatus)) {
1057 if (Type == EFI_FV_FILETYPE_DXE_CORE) {
1058 //
1059 // If this is the DXE core fill in it's DevicePath & DeviceHandle
1060 //
1061 if (gDxeCoreLoadedImage->FilePath == NULL) {
1062 if (CompareGuid (&NameGuid, gDxeCoreFileName)) {
1063 //
1064 // Maybe One specail Fv cantains only one DXE_CORE module, so its device path must
1065 // be initialized completely.
1066 //
1067 EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid);
1068 mFvDevicePath.End.Type = EFI_END_ENTIRE_DEVICE_PATH;
1069 mFvDevicePath.End.SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;
1070 SetDevicePathNodeLength (&mFvDevicePath.End, sizeof (EFI_DEVICE_PATH_PROTOCOL));
1071
1072 gDxeCoreLoadedImage->FilePath = CoreDuplicateDevicePath (
1073 (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath
1074 );
1075 gDxeCoreLoadedImage->DeviceHandle = FvHandle;
1076 }
1077 }
1078 } else if (Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
1079 //
1080 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already
1081 // been extracted.
1082 //
1083 if (FvFoundInHobFv2 (FvHandle, &NameGuid)) {
1084 continue;
1085 }
1086 //
1087 // Found a firmware volume image. Produce a firmware volume block
1088 // protocol for it so it gets dispatched from. This is usually a
1089 // capsule.
1090 //
1091 CoreProcessFvImageFile (Fv, FvHandle, &NameGuid);
1092 } else {
1093 //
1094 // Transition driver from Undiscovered to Discovered state
1095 //
1096 CoreAddToDriverList (Fv, FvHandle, &NameGuid);
1097 }
1098 }
1099 } while (!EFI_ERROR (GetNextFileStatus));
1100 }
1101
1102 //
1103 // Read the array of GUIDs from the Apriori file if it is present in the firmware volume
1104 //
1105 AprioriFile = NULL;
1106 Status = Fv->ReadSection (
1107 Fv,
1108 &gAprioriGuid,
1109 EFI_SECTION_RAW,
1110 0,
1111 (VOID **)&AprioriFile,
1112 &SizeOfBuffer,
1113 &AuthenticationStatus
1114 );
1115 if (!EFI_ERROR (Status)) {
1116 AprioriEntryCount = SizeOfBuffer / sizeof (EFI_GUID);
1117 } else {
1118 AprioriEntryCount = 0;
1119 }
1120
1121 //
1122 // Put drivers on Apriori List on the Scheduled queue. The Discovered List includes
1123 // drivers not in the current FV and these must be skipped since the a priori list
1124 // is only valid for the FV that it resided in.
1125 //
1126 CoreAcquireDispatcherLock ();
1127
1128 for (Index = 0; Index < AprioriEntryCount; Index++) {
1129 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
1130 DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
1131 if (CompareGuid (&DriverEntry->FileName, &AprioriFile[Index]) &&
1132 (FvHandle == DriverEntry->FvHandle)) {
1133 DriverEntry->Dependent = FALSE;
1134 DriverEntry->Scheduled = TRUE;
1135 InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);
1136 break;
1137 }
1138 }
1139 }
1140
1141 CoreReleaseDispatcherLock ();
1142
1143 //
1144 // Free data allocated by Fv->ReadSection ()
1145 //
1146 CoreFreePool (AprioriFile);
1147 }
1148 }
1149
1150
1151 VOID
1152 CoreInitializeDispatcher (
1153 VOID
1154 )
1155 /*++
1156
1157 Routine Description:
1158
1159 Initialize the dispatcher. Initialize the notification function that runs when
1160 a FV protocol is added to the system.
1161
1162 Arguments:
1163
1164 NONE
1165
1166 Returns:
1167
1168 NONE
1169
1170 --*/
1171 {
1172 mFwVolEvent = CoreCreateProtocolNotifyEvent (
1173 &gEfiFirmwareVolume2ProtocolGuid,
1174 TPL_CALLBACK,
1175 CoreFwVolEventProtocolNotify,
1176 NULL,
1177 &mFwVolEventRegistration,
1178 TRUE
1179 );
1180 }
1181
1182 //
1183 // Function only used in debug builds
1184 //
1185 VOID
1186 CoreDisplayDiscoveredNotDispatched (
1187 VOID
1188 )
1189 /*++
1190
1191 Routine Description:
1192
1193 Traverse the discovered list for any drivers that were discovered but not loaded
1194 because the dependency experessions evaluated to false
1195
1196 Arguments:
1197
1198 NONE
1199
1200 Returns:
1201
1202 NONE
1203
1204 --*/
1205 {
1206 LIST_ENTRY *Link;
1207 EFI_CORE_DRIVER_ENTRY *DriverEntry;
1208
1209 for (Link = mDiscoveredList.ForwardLink;Link !=&mDiscoveredList; Link = Link->ForwardLink) {
1210 DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);
1211 if (DriverEntry->Dependent) {
1212 DEBUG ((EFI_D_LOAD, "Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName));
1213 }
1214 }
1215 }