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