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