]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c
Sync HII and Setupbrowser related header files with UEFI 2.1 spec.
[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
862 UINTN BufferSize;\r
863\r
864 //\r
865 // Read the first (and only the first) firmware volume section\r
866 //\r
867 SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;\r
868 Buffer = NULL;\r
869 BufferSize = 0;\r
870 Status = Fv->ReadSection (\r
871 Fv, \r
872 DriverName, \r
873 SectionType, \r
874 0, \r
875 &Buffer, \r
876 &BufferSize,\r
877 &AuthenticationStatus\r
878 );\r
879 if (!EFI_ERROR (Status)) {\r
880 //\r
881 // Produce a FVB protocol for the file\r
882 //\r
883 Status = ProduceFVBProtocolOnBuffer (\r
884 (EFI_PHYSICAL_ADDRESS) (UINTN) Buffer,\r
885 (UINT64)BufferSize,\r
886 FvHandle,\r
887 NULL\r
888 );\r
889 }\r
890\r
891 if (EFI_ERROR (Status) && (Buffer != NULL)) { \r
892 //\r
893 // ReadSection or Produce FVB failed, Free data buffer\r
894 //\r
895 CoreFreePool (Buffer); \r
896\r
897 }\r
898\r
899 return Status;\r
900}\r
901\r
902STATIC\r
903VOID\r
904EFIAPI\r
905CoreFwVolEventProtocolNotify (\r
906 IN EFI_EVENT Event,\r
907 IN VOID *Context\r
908 )\r
909/*++\r
910\r
911Routine Description:\r
912\r
913 Event notification that is fired every time a FV dispatch protocol is added. \r
914 More than one protocol may have been added when this event is fired, so you\r
915 must loop on CoreLocateHandle () to see how many protocols were added and\r
916 do the following to each FV:\r
917\r
918 If the Fv has already been processed, skip it. If the Fv has not been \r
919 processed then mark it as being processed, as we are about to process it.\r
920\r
921 Read the Fv and add any driver in the Fv to the mDiscoveredList.The \r
922 mDiscoveredList is never free'ed and contains variables that define\r
923 the other states the DXE driver transitions to.. \r
924 \r
925 While you are at it read the A Priori file into memory.\r
926 Place drivers in the A Priori list onto the mScheduledQueue.\r
927\r
928Arguments:\r
929\r
930 Event - The Event that is being processed, not used.\r
931 \r
932 Context - Event Context, not used.\r
933\r
934Returns:\r
935\r
936 None\r
937\r
938--*/\r
939{\r
940 EFI_STATUS Status;\r
941 EFI_STATUS GetNextFileStatus;\r
942 EFI_STATUS SecurityStatus;\r
0c2b5da8 943 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
28a00297 944 EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;\r
945 EFI_HANDLE FvHandle;\r
946 UINTN BufferSize;\r
947 EFI_GUID NameGuid;\r
948 UINTN Key;\r
949 EFI_FV_FILETYPE Type;\r
950 EFI_FV_FILE_ATTRIBUTES Attributes;\r
951 UINTN Size;\r
952 EFI_CORE_DRIVER_ENTRY *DriverEntry;\r
953 EFI_GUID *AprioriFile;\r
954 UINTN AprioriEntryCount;\r
955 UINTN Index;\r
956 LIST_ENTRY *Link;\r
957 UINT32 AuthenticationStatus;\r
958 UINTN SizeOfBuffer;\r
959\r
960\r
961 while (TRUE) {\r
962 BufferSize = sizeof (EFI_HANDLE);\r
963 Status = CoreLocateHandle (\r
964 ByRegisterNotify,\r
965 NULL,\r
966 mFwVolEventRegistration,\r
967 &BufferSize,\r
968 &FvHandle\r
969 );\r
970 if (EFI_ERROR (Status)) {\r
971 //\r
972 // If no more notification events exit\r
973 //\r
974 return;\r
975 }\r
976\r
977 if (FvHasBeenProcessed (FvHandle)) {\r
978 //\r
979 // This Fv has already been processed so lets skip it!\r
980 //\r
981 continue;\r
982 }\r
983\r
984 Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolumeDispatchProtocolGuid, (VOID **)&Fv);\r
985 if (EFI_ERROR (Status)) {\r
986 //\r
987 // If no dispatch protocol then skip, but do not marked as being processed as it\r
988 // may show up later.\r
989 //\r
990 continue;\r
991 }\r
992\r
993 //\r
994 // Since we are about to process this Fv mark it as processed.\r
995 //\r
996 FvIsBeingProcesssed (FvHandle);\r
997\r
998\r
0c2b5da8 999 Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);\r
28a00297 1000 if (EFI_ERROR (Status)) {\r
1001 //\r
1002 // The Handle has a FirmwareVolumeDispatch protocol and should also contiain\r
1003 // a FirmwareVolume protocol thus we should never get here.\r
1004 //\r
1005 ASSERT (FALSE);\r
1006 continue;\r
1007 }\r
1008 \r
1009 Status = CoreHandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);\r
1010 if (EFI_ERROR (Status)) {\r
1011 //\r
1012 // The Firmware volume doesn't have device path, can't be dispatched.\r
1013 //\r
1014 continue;\r
1015 }\r
1016 \r
1017 //\r
1018 // Evaluate the authentication status of the Firmware Volume through \r
1019 // Security Architectural Protocol\r
1020 //\r
1021 if (gSecurity != NULL) {\r
1022 SecurityStatus = gSecurity->FileAuthenticationState (\r
1023 gSecurity, \r
1024 0, \r
1025 FvDevicePath\r
1026 );\r
1027 if (SecurityStatus != EFI_SUCCESS) {\r
1028 //\r
1029 // Security check failed. The firmware volume should not be used for any purpose.\r
1030 //\r
1031 continue;\r
1032 }\r
1033 } \r
1034 \r
1035 //\r
1036 // Discover Drivers in FV and add them to the Discovered Driver List. \r
1037 // Process EFI_FV_FILETYPE_DRIVER type and then EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER \r
1038 // EFI_FV_FILETYPE_DXE_CORE is processed to produce a Loaded Image protocol for the core\r
1039 // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE is processed to create a Fvb\r
1040 //\r
1041 for (Index = 0; Index < sizeof (mDxeFileTypes)/sizeof (EFI_FV_FILETYPE); Index++) {\r
1042 //\r
1043 // Initialize the search key\r
1044 //\r
1045 Key = 0;\r
1046 do {\r
1047 Type = mDxeFileTypes[Index];\r
1048 GetNextFileStatus = Fv->GetNextFile (\r
1049 Fv, \r
1050 &Key,\r
1051 &Type, \r
1052 &NameGuid, \r
1053 &Attributes, \r
1054 &Size\r
1055 );\r
1056 if (!EFI_ERROR (GetNextFileStatus)) {\r
1057 if (Type == EFI_FV_FILETYPE_DXE_CORE) {\r
1058 //\r
1059 // If this is the DXE core fill in it's DevicePath & DeviceHandle\r
1060 //\r
1061 if (gDxeCoreLoadedImage->FilePath == NULL) {\r
1062 if (CompareGuid (&NameGuid, gDxeCoreFileName)) {\r
1063 //\r
1064 // Maybe One specail Fv cantains only one DXE_CORE module, so its device path must\r
1065 // be initialized completely.\r
1066 //\r
1067 EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid);\r
1068 mFvDevicePath.End.Type = EFI_END_ENTIRE_DEVICE_PATH;\r
1069 mFvDevicePath.End.SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;\r
1070 SetDevicePathNodeLength (&mFvDevicePath.End, sizeof (EFI_DEVICE_PATH_PROTOCOL));\r
1071\r
1072 gDxeCoreLoadedImage->FilePath = CoreDuplicateDevicePath (\r
1073 (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath\r
1074 );\r
1075 gDxeCoreLoadedImage->DeviceHandle = FvHandle;\r
1076 }\r
1077 }\r
1078 } else if (Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {\r
bbc0f1bb 1079 //\r
1080 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already \r
1081 // been extracted.\r
1082 //\r
1083 if (FvFoundInHobFv2 (FvHandle, &NameGuid)) {\r
1084 continue;\r
1085 }\r
28a00297 1086 //\r
1087 // Found a firmware volume image. Produce a firmware volume block\r
1088 // protocol for it so it gets dispatched from. This is usually a \r
1089 // capsule.\r
1090 //\r
1091 CoreProcessFvImageFile (Fv, FvHandle, &NameGuid);\r
1092 } else {\r
1093 //\r
1094 // Transition driver from Undiscovered to Discovered state\r
1095 //\r
1096 CoreAddToDriverList (Fv, FvHandle, &NameGuid);\r
1097 }\r
1098 }\r
1099 } while (!EFI_ERROR (GetNextFileStatus));\r
1100 }\r
1101 \r
1102 //\r
1103 // Read the array of GUIDs from the Apriori file if it is present in the firmware volume\r
1104 //\r
1105 AprioriFile = NULL;\r
1106 Status = Fv->ReadSection (\r
1107 Fv,\r
1108 &gAprioriGuid,\r
1109 EFI_SECTION_RAW,\r
1110 0,\r
1111 (VOID **)&AprioriFile,\r
1112 &SizeOfBuffer,\r
1113 &AuthenticationStatus\r
1114 );\r
1115 if (!EFI_ERROR (Status)) {\r
1116 AprioriEntryCount = SizeOfBuffer / sizeof (EFI_GUID);\r
1117 } else {\r
1118 AprioriEntryCount = 0;\r
1119 }\r
1120\r
1121 //\r
1122 // Put drivers on Apriori List on the Scheduled queue. The Discovered List includes\r
1123 // drivers not in the current FV and these must be skipped since the a priori list\r
1124 // is only valid for the FV that it resided in.\r
1125 //\r
1126 CoreAcquireDispatcherLock ();\r
1127 \r
1128 for (Index = 0; Index < AprioriEntryCount; Index++) {\r
1129 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
1130 DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);\r
1131 if (CompareGuid (&DriverEntry->FileName, &AprioriFile[Index]) &&\r
1132 (FvHandle == DriverEntry->FvHandle)) {\r
1133 DriverEntry->Dependent = FALSE;\r
1134 DriverEntry->Scheduled = TRUE;\r
1135 InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);\r
1136 break;\r
1137 }\r
1138 }\r
1139 }\r
1140\r
1141 CoreReleaseDispatcherLock ();\r
1142\r
1143 //\r
1144 // Free data allocated by Fv->ReadSection () \r
1145 //\r
1146 CoreFreePool (AprioriFile); \r
1147 }\r
1148}\r
1149\r
1150\r
1151VOID\r
1152CoreInitializeDispatcher (\r
1153 VOID\r
1154 )\r
1155/*++\r
1156\r
1157Routine Description:\r
1158\r
1159 Initialize the dispatcher. Initialize the notification function that runs when\r
1160 a FV protocol is added to the system.\r
1161\r
1162Arguments:\r
1163\r
1164 NONE\r
1165\r
1166Returns:\r
1167\r
1168 NONE \r
1169\r
1170--*/\r
1171{\r
1172 mFwVolEvent = CoreCreateProtocolNotifyEvent (\r
0c2b5da8 1173 &gEfiFirmwareVolume2ProtocolGuid, \r
28a00297 1174 TPL_CALLBACK,\r
1175 CoreFwVolEventProtocolNotify,\r
1176 NULL,\r
1177 &mFwVolEventRegistration,\r
1178 TRUE\r
1179 );\r
1180}\r
1181\r
1182//\r
1183// Function only used in debug builds\r
1184//\r
1185VOID\r
1186CoreDisplayDiscoveredNotDispatched (\r
1187 VOID\r
1188 )\r
1189/*++\r
1190\r
1191Routine Description:\r
1192\r
1193 Traverse the discovered list for any drivers that were discovered but not loaded \r
1194 because the dependency experessions evaluated to false\r
1195\r
1196Arguments:\r
1197\r
1198 NONE\r
1199\r
1200Returns:\r
1201\r
1202 NONE \r
1203\r
1204--*/\r
1205{\r
1206 LIST_ENTRY *Link;\r
1207 EFI_CORE_DRIVER_ENTRY *DriverEntry;\r
1208\r
1209 for (Link = mDiscoveredList.ForwardLink;Link !=&mDiscoveredList; Link = Link->ForwardLink) {\r
1210 DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);\r
1211 if (DriverEntry->Dependent) {\r
1212 DEBUG ((EFI_D_LOAD, "Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName));\r
1213 }\r
1214 }\r
1215}\r