Update for ICC build.
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Core / Dxe / Dispatcher / Dispatcher.c
1 /*++\r
2 \r
3 Copyright (c) 2006, Intel Corporation                                                         \r
4 All rights reserved. This program and the accompanying materials                          \r
5 are licensed and made available under the terms and conditions of the BSD License         \r
6 which accompanies this distribution.  The full text of the license may be found at        \r
7 http://opensource.org/licenses/bsd-license.php                                            \r
8                                                                                           \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
11 \r
12 Module Name:\r
13 \r
14   Dispatcher.c\r
15 \r
16 Abstract:\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
53 LIST_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
59 LIST_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
64 LIST_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
69 EFI_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
75 BOOLEAN  gDispatcherRunning = FALSE;\r
76 \r
77 //\r
78 // Module globals to manage the FwVol registration notification event\r
79 //\r
80 EFI_EVENT       mFwVolEvent;\r
81 VOID            *mFwVolEventRegistration;\r
82 \r
83 //\r
84 // List of file types supported by dispatcher\r
85 //\r
86 static 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
93 typedef 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
98 FV_FILEPATH_DEVICE_PATH mFvDevicePath;\r
99 \r
100 \r
101 //\r
102 // Function Prototypes\r
103 //\r
104 STATIC\r
105 VOID\r
106 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (\r
107   IN  EFI_CORE_DRIVER_ENTRY   *InsertedDriverEntry\r
108   );\r
109  \r
110 STATIC\r
111 VOID\r
112 EFIAPI\r
113 CoreFwVolEventProtocolNotify (\r
114   IN  EFI_EVENT       Event,\r
115   IN  VOID            *Context\r
116   );\r
117 \r
118 STATIC\r
119 EFI_DEVICE_PATH_PROTOCOL *\r
120 CoreFvToDevicePath (\r
121   IN  EFI_FIRMWARE_VOLUME_PROTOCOL    *Fv,\r
122   IN  EFI_HANDLE                      FvHandle,\r
123   IN  EFI_GUID                        *DriverName\r
124   );\r
125 \r
126 STATIC \r
127 EFI_STATUS\r
128 CoreAddToDriverList (\r
129   IN  EFI_FIRMWARE_VOLUME_PROTOCOL  *Fv,\r
130   IN  EFI_HANDLE                    FvHandle,\r
131   IN  EFI_GUID                      *DriverName\r
132   );\r
133 \r
134 STATIC\r
135 EFI_STATUS \r
136 CoreProcessFvImageFile (\r
137   IN  EFI_FIRMWARE_VOLUME_PROTOCOL    *Fv,\r
138   IN  EFI_HANDLE                      FvHandle,\r
139   IN  EFI_GUID                        *DriverName\r
140   );\r
141 \r
142 STATIC\r
143 VOID\r
144 CoreAcquireDispatcherLock (\r
145   VOID\r
146   )\r
147 /*++\r
148 \r
149 Routine Description:\r
150 \r
151   Enter critical section by gaining lock on mDispatcherLock\r
152 \r
153 Arguments:\r
154 \r
155   None\r
156 \r
157 Returns:\r
158 \r
159   None\r
160 \r
161 --*/\r
162 \r
163 {\r
164   CoreAcquireLock (&mDispatcherLock);\r
165 }\r
166 \r
167 STATIC\r
168 VOID\r
169 CoreReleaseDispatcherLock (\r
170   VOID\r
171   )\r
172 /*++\r
173 \r
174 Routine Description:\r
175 \r
176   Exit critical section by releasing lock on mDispatcherLock\r
177 \r
178 Arguments:\r
179 \r
180   None\r
181 \r
182 Returns:\r
183 \r
184   None\r
185 \r
186 --*/\r
187 {\r
188   CoreReleaseLock (&mDispatcherLock);\r
189 }\r
190 \r
191 STATIC\r
192 EFI_STATUS\r
193 CoreGetDepexSectionAndPreProccess (\r
194   IN  EFI_CORE_DRIVER_ENTRY   *DriverEntry\r
195   )\r
196 /*++\r
197 \r
198 Routine 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
203 Arguments:\r
204 \r
205   DriverEntry - Driver to work on.\r
206   \r
207 Returns:\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
221   EFI_FIRMWARE_VOLUME_PROTOCOL  *Fv;\r
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
247       // If no Depex assume EFI 1.1 driver model\r
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
265 EFI_DXESERVICE\r
266 EFI_STATUS\r
267 EFIAPI\r
268 CoreSchedule (\r
269   IN  EFI_HANDLE  FirmwareVolumeHandle,\r
270   IN  EFI_GUID    *DriverName\r
271   )\r
272 /*++\r
273 \r
274 Routine 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
279 Arguments:\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
286 Returns:\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
320 EFI_DXESERVICE\r
321 EFI_STATUS\r
322 EFIAPI\r
323 CoreTrust (\r
324   IN  EFI_HANDLE  FirmwareVolumeHandle,\r
325   IN  EFI_GUID    *DriverName\r
326   )\r
327 /*++\r
328 \r
329 Routine Description:\r
330 \r
331   Convert a driver from the Untrused back to the Scheduled state\r
332 \r
333 Arguments:\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
340 Returns:\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
376 EFI_DXESERVICE\r
377 EFI_STATUS\r
378 EFIAPI\r
379 CoreDispatcher (\r
380   VOID\r
381   )\r
382 /*++\r
383 \r
384 Routine 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
394 Arguments:\r
395 \r
396   NONE\r
397 \r
398 Returns:\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
493 \r
494       CoreReportProgressCodeSpecific (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_BEGIN, DriverEntry->ImageHandle);\r
495       Status = CoreStartImage (DriverEntry->ImageHandle, NULL, NULL);\r
496       CoreReportProgressCodeSpecific (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_END, DriverEntry->ImageHandle);\r
497 \r
498       ReturnStatus = EFI_SUCCESS;\r
499     }\r
500 \r
501     //\r
502     // Search DriverList for items to place on Scheduled Queue\r
503     //\r
504     ReadyToRun = FALSE;\r
505     for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
506       DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);\r
507 \r
508       if (DriverEntry->DepexProtocolError){\r
509         //\r
510         // If Section Extraction Protocol did not let the Depex be read before retry the read\r
511         //\r
512         Status = CoreGetDepexSectionAndPreProccess (DriverEntry);\r
513       } \r
514 \r
515       if (DriverEntry->Dependent) {\r
516         if (CoreIsSchedulable (DriverEntry)) {\r
517           CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry); \r
518           ReadyToRun = TRUE;\r
519         } \r
520       }\r
521     }\r
522   } while (ReadyToRun);\r
523 \r
524   gDispatcherRunning = FALSE;\r
525 \r
526   return ReturnStatus;\r
527 }\r
528 \r
529 STATIC\r
530 VOID\r
531 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (\r
532   IN  EFI_CORE_DRIVER_ENTRY   *InsertedDriverEntry\r
533   )\r
534 /*++\r
535 \r
536 Routine Description:\r
537 \r
538   Insert InsertedDriverEntry onto the mScheduledQueue. To do this you \r
539   must add any driver with a before dependency on InsertedDriverEntry first.\r
540   You do this by recursively calling this routine. After all the Befores are\r
541   processed you can add InsertedDriverEntry to the mScheduledQueue. \r
542   Then you can add any driver with an After dependency on InsertedDriverEntry \r
543   by recursively calling this routine.\r
544 \r
545 Arguments:\r
546 \r
547   InsertedDriverEntry - The driver to insert on the ScheduledLink Queue\r
548 \r
549 Returns:\r
550 \r
551   NONE \r
552 \r
553 --*/\r
554 {\r
555   LIST_ENTRY            *Link;\r
556   EFI_CORE_DRIVER_ENTRY *DriverEntry;\r
557 \r
558   //\r
559   // Process Before Dependency\r
560   //\r
561   for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
562     DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);\r
563     if (DriverEntry->Before && DriverEntry->Dependent) {\r
564       if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {\r
565         //\r
566         // Recursively process BEFORE\r
567         //\r
568         CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);\r
569       }\r
570     }\r
571   }\r
572 \r
573   //\r
574   // Convert driver from Dependent to Scheduled state\r
575   //\r
576   CoreAcquireDispatcherLock ();\r
577 \r
578   InsertedDriverEntry->Dependent = FALSE;\r
579   InsertedDriverEntry->Scheduled = TRUE;\r
580   InsertTailList (&mScheduledQueue, &InsertedDriverEntry->ScheduledLink);\r
581   \r
582   CoreReleaseDispatcherLock ();\r
583 \r
584   //\r
585   // Process After Dependency\r
586   //\r
587   for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
588     DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);\r
589     if (DriverEntry->After && DriverEntry->Dependent) {\r
590       if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {\r
591         //\r
592         // Recursively process AFTER\r
593         //\r
594         CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);\r
595       }\r
596     }\r
597   }\r
598 }\r
599 \r
600 STATIC\r
601 BOOLEAN\r
602 FvHasBeenProcessed (\r
603   IN  EFI_HANDLE      FvHandle\r
604   )\r
605 /*++\r
606 \r
607 Routine Description:\r
608 \r
609   Return TRUE if the Fv has been processed, FALSE if not.\r
610 \r
611 Arguments:\r
612 \r
613   FvHandle - The handle of a FV that's being tested\r
614 \r
615 Returns:\r
616 \r
617   TRUE  - Fv protocol on FvHandle has been processed\r
618 \r
619   FALSE - Fv protocol on FvHandle has not yet been processed\r
620 \r
621 --*/\r
622 {\r
623   LIST_ENTRY      *Link;\r
624   KNOWN_HANDLE    *KnownHandle;\r
625 \r
626   for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) {\r
627     KnownHandle = CR(Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE);\r
628     if (KnownHandle->Handle == FvHandle) {\r
629       return TRUE;\r
630     }\r
631   }\r
632   return FALSE;\r
633 }\r
634 \r
635 STATIC\r
636 VOID\r
637 FvIsBeingProcesssed (\r
638   IN  EFI_HANDLE    FvHandle\r
639   )\r
640 /*++\r
641 \r
642 Routine Description:\r
643 \r
644   Remember that Fv protocol on FvHandle has had it's drivers placed on the\r
645   mDiscoveredList. This fucntion adds entries on the mFvHandleList. Items are\r
646   never removed/freed from the mFvHandleList.\r
647 \r
648 Arguments:\r
649 \r
650   FvHandle - The handle of a FV that has been processed\r
651 \r
652 Returns:\r
653 \r
654   None\r
655 \r
656 --*/\r
657 {\r
658   KNOWN_HANDLE  *KnownHandle;\r
659 \r
660   KnownHandle = CoreAllocateBootServicesPool (sizeof (KNOWN_HANDLE));\r
661   ASSERT (KnownHandle != NULL);\r
662 \r
663   KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE;\r
664   KnownHandle->Handle = FvHandle;\r
665   InsertTailList (&mFvHandleList, &KnownHandle->Link);\r
666 }\r
667 \r
668 \r
669 \r
670 STATIC\r
671 EFI_DEVICE_PATH_PROTOCOL *\r
672 CoreFvToDevicePath (\r
673   IN  EFI_FIRMWARE_VOLUME_PROTOCOL    *Fv,\r
674   IN  EFI_HANDLE                      FvHandle,\r
675   IN  EFI_GUID                        *DriverName\r
676   )\r
677 /*++\r
678 \r
679 Routine Description:\r
680 \r
681   Convert FvHandle and DriverName into an EFI device path\r
682 \r
683 Arguments:\r
684 \r
685   Fv         - Fv protocol, needed to read Depex info out of FLASH.\r
686   \r
687   FvHandle   - Handle for Fv, needed in the EFI_CORE_DRIVER_ENTRY so that the\r
688                PE image can be read out of the FV at a later time.\r
689 \r
690   DriverName - Name of driver to add to mDiscoveredList.\r
691 \r
692 Returns:\r
693 \r
694   Pointer to device path constructed from FvHandle and DriverName\r
695 \r
696 --*/\r
697 {\r
698   EFI_STATUS                          Status;\r
699   EFI_DEVICE_PATH_PROTOCOL            *FvDevicePath;\r
700   EFI_DEVICE_PATH_PROTOCOL            *FileNameDevicePath;\r
701 \r
702   //\r
703   // Remember the device path of the FV\r
704   //\r
705   Status = CoreHandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);\r
706   if (EFI_ERROR (Status)) {\r
707     FileNameDevicePath = NULL;\r
708   } else {\r
709     //\r
710     // Build a device path to the file in the FV to pass into gBS->LoadImage\r
711     //\r
712     EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, DriverName);\r
713     mFvDevicePath.End.Type = EFI_END_ENTIRE_DEVICE_PATH;\r
714     mFvDevicePath.End.SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;\r
715     SetDevicePathNodeLength (&mFvDevicePath.End, sizeof (EFI_DEVICE_PATH_PROTOCOL));\r
716 \r
717     FileNameDevicePath = CoreAppendDevicePath (\r
718                             FvDevicePath, \r
719                             (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath\r
720                             );\r
721   }\r
722 \r
723   return FileNameDevicePath;\r
724 }\r
725 \r
726 \r
727 \r
728 EFI_STATUS\r
729 CoreAddToDriverList (\r
730   IN  EFI_FIRMWARE_VOLUME_PROTOCOL    *Fv,\r
731   IN  EFI_HANDLE                      FvHandle,\r
732   IN  EFI_GUID                        *DriverName\r
733   )\r
734 /*++\r
735 \r
736 Routine Description:\r
737 \r
738   Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry, \r
739   and initilize any state variables. Read the Depex from the FV and store it\r
740   in DriverEntry. Pre-process the Depex to set the SOR, Before and After state.\r
741   The Discovered list is never free'ed and contains booleans that represent the\r
742   other possible DXE driver states.\r
743 \r
744 Arguments:\r
745 \r
746   Fv         - Fv protocol, needed to read Depex info out of FLASH.\r
747   \r
748   FvHandle   - Handle for Fv, needed in the EFI_CORE_DRIVER_ENTRY so that the\r
749                PE image can be read out of the FV at a later time.\r
750 \r
751   DriverName - Name of driver to add to mDiscoveredList.\r
752 \r
753 Returns:\r
754 \r
755   EFI_SUCCESS - If driver was added to the mDiscoveredList.\r
756 \r
757   EFI_ALREADY_STARTED - The driver has already been started. Only one DriverName\r
758                         may be active in the system at any one time.\r
759 \r
760 --*/\r
761 {\r
762   EFI_CORE_DRIVER_ENTRY               *DriverEntry;\r
763 \r
764  \r
765   //\r
766   // Create the Driver Entry for the list. ZeroPool initializes lots of variables to \r
767   // NULL or FALSE.\r
768   //\r
769   DriverEntry = CoreAllocateZeroBootServicesPool (sizeof (EFI_CORE_DRIVER_ENTRY));\r
770   ASSERT (DriverEntry != NULL);\r
771 \r
772   DriverEntry->Signature        = EFI_CORE_DRIVER_ENTRY_SIGNATURE;\r
773   CopyMem (&DriverEntry->FileName, DriverName, sizeof (EFI_GUID));\r
774   DriverEntry->FvHandle         = FvHandle;\r
775   DriverEntry->Fv               = Fv;\r
776   DriverEntry->FvFileDevicePath = CoreFvToDevicePath (Fv, FvHandle, DriverName);\r
777 \r
778   CoreGetDepexSectionAndPreProccess (DriverEntry);\r
779   \r
780   CoreAcquireDispatcherLock ();\r
781   \r
782   InsertTailList (&mDiscoveredList, &DriverEntry->Link);\r
783 \r
784   CoreReleaseDispatcherLock ();\r
785 \r
786   return EFI_SUCCESS;\r
787 }\r
788 \r
789 STATIC\r
790 BOOLEAN\r
791 FvFoundInHobFv2 (\r
792   IN  EFI_HANDLE                      FvHandle,\r
793   IN  CONST EFI_GUID                  *DriverName\r
794   )\r
795 /*++\r
796 \r
797 Routine Description:\r
798 \r
799   Check if a FV Image type file (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) is\r
800   described by a EFI_HOB_FIRMWARE_VOLUME2 Hob.\r
801 \r
802 Arguments:\r
803 \r
804   FvHandle    - The handle which FVB protocol installed on.\r
805   DriverName  - The driver guid specified.\r
806 \r
807 Returns:\r
808 \r
809   TRUE    - This file is found in a EFI_HOB_FIRMWARE_VOLUME2 Hob.\r
810 \r
811   FALSE   - Not found.\r
812   \r
813 \r
814 --*/\r
815 {\r
816   EFI_PEI_HOB_POINTERS                HobFv2;\r
817   EFI_STATUS                          Status;\r
818   EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *Fvb;\r
819   EFI_FIRMWARE_VOLUME_HEADER          *FvHeader;\r
820   EFI_PHYSICAL_ADDRESS                FvHeaderAddr;\r
821   \r
822   HobFv2.Raw = GetHobList ();\r
823   \r
824   while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) {\r
825     if (CompareGuid (DriverName, &HobFv2.FirmwareVolume2->FileName)) {\r
826       Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **) &Fvb);\r
827       if (!EFI_ERROR (Status)) {\r
828         Status = Fvb->GetPhysicalAddress (Fvb, &FvHeaderAddr);\r
829         if (!EFI_ERROR (Status)) {\r
830           FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FvHeaderAddr;\r
831           if (CompareGuid (&FvHeader->FileSystemGuid, &HobFv2.FirmwareVolume2->FvName)) {\r
832             return TRUE;\r
833           }\r
834         }\r
835       }\r
836     }\r
837     HobFv2.Raw = GET_NEXT_HOB (HobFv2);\r
838   }\r
839 \r
840   return FALSE;\r
841 }\r
842 \r
843 \r
844 EFI_STATUS \r
845 CoreProcessFvImageFile (\r
846   IN  EFI_FIRMWARE_VOLUME_PROTOCOL    *Fv,\r
847   IN  EFI_HANDLE                      FvHandle,\r
848   IN  EFI_GUID                        *DriverName\r
849   )\r
850 /*++\r
851 \r
852 Routine Description:\r
853 \r
854   Get the driver from the FV through driver name, and produce a FVB protocol on FvHandle.\r
855 \r
856 Arguments:\r
857 \r
858   Fv          - The FIRMWARE_VOLUME protocol installed on the FV.\r
859   FvHandle    - The handle which FVB protocol installed on.\r
860   DriverName  - The driver guid specified.\r
861 \r
862 Returns:\r
863 \r
864   EFI_OUT_OF_RESOURCES    - No enough memory or other resource.\r
865   \r
866   EFI_VOLUME_CORRUPTED    - Corrupted volume.\r
867   \r
868   EFI_SUCCESS             - Function successfully returned.\r
869   \r
870 \r
871 --*/\r
872 {\r
873   EFI_STATUS                          Status;\r
874   EFI_SECTION_TYPE                    SectionType;\r
875   UINT32                              AuthenticationStatus;\r
876   VOID                                *Buffer;\r
877   UINTN                               BufferSize;\r
878 \r
879   //\r
880   // Read the first (and only the first) firmware volume section\r
881   //\r
882   SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;\r
883   Buffer      = NULL;\r
884   BufferSize  = 0;\r
885   Status = Fv->ReadSection (\r
886                 Fv, \r
887                 DriverName, \r
888                 SectionType, \r
889                 0, \r
890                 &Buffer, \r
891                 &BufferSize,\r
892                 &AuthenticationStatus\r
893                 );\r
894   if (!EFI_ERROR (Status)) {\r
895     //\r
896     // Produce a FVB protocol for the file\r
897     //\r
898     Status = ProduceFVBProtocolOnBuffer (\r
899               (EFI_PHYSICAL_ADDRESS) (UINTN) Buffer,\r
900               (UINT64)BufferSize,\r
901               FvHandle,\r
902               NULL\r
903               );\r
904   }\r
905 \r
906   if (EFI_ERROR (Status) && (Buffer != NULL)) {    \r
907   //\r
908   // ReadSection or Produce FVB failed, Free data buffer\r
909   //\r
910   CoreFreePool (Buffer); \r
911 \r
912   }\r
913 \r
914   return Status;\r
915 }\r
916 \r
917 STATIC\r
918 VOID\r
919 EFIAPI\r
920 CoreFwVolEventProtocolNotify (\r
921   IN  EFI_EVENT       Event,\r
922   IN  VOID            *Context\r
923   )\r
924 /*++\r
925 \r
926 Routine Description:\r
927 \r
928   Event notification that is fired every time a FV dispatch protocol is added. \r
929   More than one protocol may have been added when this event is fired, so you\r
930   must loop on CoreLocateHandle () to see how many protocols were added and\r
931   do the following to each FV:\r
932 \r
933   If the Fv has already been processed, skip it. If the Fv has not been \r
934   processed then mark it as being processed, as we are about to process it.\r
935 \r
936   Read the Fv and add any driver in the Fv to the mDiscoveredList.The \r
937   mDiscoveredList is never free'ed and contains variables that define\r
938   the other states the DXE driver transitions to.. \r
939   \r
940   While you are at it read the A Priori file into memory.\r
941   Place drivers in the A Priori list onto the mScheduledQueue.\r
942 \r
943 Arguments:\r
944 \r
945   Event   - The Event that is being processed, not used.\r
946   \r
947   Context - Event Context, not used.\r
948 \r
949 Returns:\r
950 \r
951   None\r
952 \r
953 --*/\r
954 {\r
955   EFI_STATUS                    Status;\r
956   EFI_STATUS                    GetNextFileStatus;\r
957   EFI_STATUS                    SecurityStatus;\r
958   EFI_FIRMWARE_VOLUME_PROTOCOL  *Fv;\r
959   EFI_DEVICE_PATH_PROTOCOL      *FvDevicePath;\r
960   EFI_HANDLE                    FvHandle;\r
961   UINTN                         BufferSize;\r
962   EFI_GUID                      NameGuid;\r
963   UINTN                         Key;\r
964   EFI_FV_FILETYPE               Type;\r
965   EFI_FV_FILE_ATTRIBUTES        Attributes;\r
966   UINTN                         Size;\r
967   EFI_CORE_DRIVER_ENTRY         *DriverEntry;\r
968   EFI_GUID                      *AprioriFile;\r
969   UINTN                         AprioriEntryCount;\r
970   UINTN                         Index;\r
971   LIST_ENTRY                    *Link;\r
972   UINT32                        AuthenticationStatus;\r
973   UINTN                         SizeOfBuffer;\r
974 \r
975 \r
976   while (TRUE) {\r
977     BufferSize = sizeof (EFI_HANDLE);\r
978     Status = CoreLocateHandle (\r
979                     ByRegisterNotify,\r
980                     NULL,\r
981                     mFwVolEventRegistration,\r
982                     &BufferSize,\r
983                     &FvHandle\r
984                     );\r
985     if (EFI_ERROR (Status)) {\r
986       //\r
987       // If no more notification events exit\r
988       //\r
989       return;\r
990     }\r
991 \r
992     if (FvHasBeenProcessed (FvHandle)) {\r
993       //\r
994       // This Fv has already been processed so lets skip it!\r
995       //\r
996       continue;\r
997     }\r
998 \r
999     Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolumeDispatchProtocolGuid, (VOID **)&Fv);\r
1000     if (EFI_ERROR (Status)) {\r
1001       //\r
1002       // If no dispatch protocol then skip, but do not marked as being processed as it\r
1003       // may show up later.\r
1004       //\r
1005       continue;\r
1006     }\r
1007 \r
1008     //\r
1009     // Since we are about to process this Fv mark it as processed.\r
1010     //\r
1011     FvIsBeingProcesssed (FvHandle);\r
1012 \r
1013 \r
1014     Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolumeProtocolGuid, (VOID **)&Fv);\r
1015     if (EFI_ERROR (Status)) {\r
1016       //\r
1017       // The Handle has a FirmwareVolumeDispatch protocol and should also contiain\r
1018       // a FirmwareVolume protocol thus we should never get here.\r
1019       //\r
1020       ASSERT (FALSE);\r
1021       continue;\r
1022     }\r
1023     \r
1024     Status = CoreHandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);\r
1025     if (EFI_ERROR (Status)) {\r
1026       //\r
1027       // The Firmware volume doesn't have device path, can't be dispatched.\r
1028       //\r
1029       continue;\r
1030     }\r
1031     \r
1032     //\r
1033     // Evaluate the authentication status of the Firmware Volume through \r
1034     // Security Architectural Protocol\r
1035     //\r
1036     if (gSecurity != NULL) {\r
1037       SecurityStatus = gSecurity->FileAuthenticationState (\r
1038                                     gSecurity, \r
1039                                     0, \r
1040                                     FvDevicePath\r
1041                                     );\r
1042       if (SecurityStatus != EFI_SUCCESS) {\r
1043         //\r
1044         // Security check failed. The firmware volume should not be used for any purpose.\r
1045         //\r
1046         continue;\r
1047       }\r
1048     }   \r
1049     \r
1050     //\r
1051     // Discover Drivers in FV and add them to the Discovered Driver List. \r
1052     // Process EFI_FV_FILETYPE_DRIVER type and then EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER \r
1053     //  EFI_FV_FILETYPE_DXE_CORE is processed to produce a Loaded Image protocol for the core\r
1054     //  EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE is processed to create a Fvb\r
1055     //\r
1056     for (Index = 0; Index < sizeof (mDxeFileTypes)/sizeof (EFI_FV_FILETYPE); Index++) {\r
1057       //\r
1058       // Initialize the search key\r
1059       //\r
1060       Key = 0;\r
1061       do {\r
1062         Type = mDxeFileTypes[Index];\r
1063         GetNextFileStatus = Fv->GetNextFile (\r
1064                                   Fv, \r
1065                                   &Key,\r
1066                                   &Type,  \r
1067                                   &NameGuid, \r
1068                                   &Attributes, \r
1069                                   &Size\r
1070                                   );\r
1071         if (!EFI_ERROR (GetNextFileStatus)) {\r
1072           if (Type == EFI_FV_FILETYPE_DXE_CORE) {\r
1073             //\r
1074             // If this is the DXE core fill in it's DevicePath & DeviceHandle\r
1075             //\r
1076             if (gDxeCoreLoadedImage->FilePath == NULL) {\r
1077               if (CompareGuid (&NameGuid, gDxeCoreFileName)) {\r
1078                 //\r
1079                 // Maybe One specail Fv cantains only one DXE_CORE module, so its device path must\r
1080                 // be initialized completely.\r
1081                 //\r
1082                 EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid);\r
1083                 mFvDevicePath.End.Type = EFI_END_ENTIRE_DEVICE_PATH;\r
1084                 mFvDevicePath.End.SubType = END_ENTIRE_DEVICE_PATH_SUBTYPE;\r
1085                 SetDevicePathNodeLength (&mFvDevicePath.End, sizeof (EFI_DEVICE_PATH_PROTOCOL));\r
1086 \r
1087                 gDxeCoreLoadedImage->FilePath = CoreDuplicateDevicePath (\r
1088                                                   (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath\r
1089                                                   );\r
1090                 gDxeCoreLoadedImage->DeviceHandle = FvHandle;\r
1091               }\r
1092             }\r
1093           } else if (Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {\r
1094             //\r
1095             // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already \r
1096             // been extracted.\r
1097             //\r
1098             if (FvFoundInHobFv2 (FvHandle, &NameGuid)) {\r
1099               continue;\r
1100             }\r
1101             \r
1102             //\r
1103             // Found a firmware volume image. Produce a firmware volume block\r
1104             // protocol for it so it gets dispatched from. This is usually a \r
1105             // capsule.\r
1106             //\r
1107             CoreProcessFvImageFile (Fv, FvHandle, &NameGuid);\r
1108           } else {\r
1109             //\r
1110             // Transition driver from Undiscovered to Discovered state\r
1111             //\r
1112             CoreAddToDriverList (Fv, FvHandle, &NameGuid);\r
1113           }\r
1114         }\r
1115       } while (!EFI_ERROR (GetNextFileStatus));\r
1116     }\r
1117     \r
1118     //\r
1119     // Read the array of GUIDs from the Apriori file if it is present in the firmware volume\r
1120     //\r
1121     AprioriFile = NULL;\r
1122     Status = Fv->ReadSection (\r
1123                   Fv,\r
1124                   &gAprioriGuid,\r
1125                   EFI_SECTION_RAW,\r
1126                   0,\r
1127                   (VOID **)&AprioriFile,\r
1128                   &SizeOfBuffer,\r
1129                   &AuthenticationStatus\r
1130                   );\r
1131     if (!EFI_ERROR (Status)) {\r
1132       AprioriEntryCount = SizeOfBuffer / sizeof (EFI_GUID);\r
1133     } else {\r
1134       AprioriEntryCount = 0;\r
1135     }\r
1136 \r
1137     //\r
1138     // Put drivers on Apriori List on the Scheduled queue. The Discovered List includes\r
1139     // drivers not in the current FV and these must be skipped since the a priori list\r
1140     // is only valid for the FV that it resided in.\r
1141     //\r
1142     CoreAcquireDispatcherLock ();\r
1143     \r
1144     for (Index = 0; Index < AprioriEntryCount; Index++) {\r
1145       for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
1146         DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);\r
1147         if (CompareGuid (&DriverEntry->FileName, &AprioriFile[Index]) &&\r
1148             (FvHandle == DriverEntry->FvHandle)) {\r
1149           DriverEntry->Dependent = FALSE;\r
1150           DriverEntry->Scheduled = TRUE;\r
1151           InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);\r
1152           break;\r
1153         }\r
1154       }\r
1155     }\r
1156 \r
1157     CoreReleaseDispatcherLock ();\r
1158 \r
1159     //\r
1160     // Free data allocated by Fv->ReadSection () \r
1161     //\r
1162     CoreFreePool (AprioriFile);  \r
1163   }\r
1164 }\r
1165 \r
1166 \r
1167 VOID\r
1168 CoreInitializeDispatcher (\r
1169   VOID\r
1170   )\r
1171 /*++\r
1172 \r
1173 Routine Description:\r
1174 \r
1175   Initialize the dispatcher. Initialize the notification function that runs when\r
1176   a FV protocol is added to the system.\r
1177 \r
1178 Arguments:\r
1179 \r
1180   NONE\r
1181 \r
1182 Returns:\r
1183 \r
1184   NONE \r
1185 \r
1186 --*/\r
1187 {\r
1188   mFwVolEvent = CoreCreateProtocolNotifyEvent (\r
1189                   &gEfiFirmwareVolumeProtocolGuid, \r
1190                   TPL_CALLBACK,\r
1191                   CoreFwVolEventProtocolNotify,\r
1192                   NULL,\r
1193                   &mFwVolEventRegistration,\r
1194                   TRUE\r
1195                   );\r
1196 }\r
1197 \r
1198 //\r
1199 // Function only used in debug builds\r
1200 //\r
1201 VOID\r
1202 CoreDisplayDiscoveredNotDispatched (\r
1203   VOID\r
1204   )\r
1205 /*++\r
1206 \r
1207 Routine Description:\r
1208 \r
1209   Traverse the discovered list for any drivers that were discovered but not loaded \r
1210   because the dependency experessions evaluated to false\r
1211 \r
1212 Arguments:\r
1213 \r
1214   NONE\r
1215 \r
1216 Returns:\r
1217 \r
1218   NONE \r
1219 \r
1220 --*/\r
1221 {\r
1222   LIST_ENTRY                    *Link;\r
1223   EFI_CORE_DRIVER_ENTRY         *DriverEntry;\r
1224 \r
1225   for (Link = mDiscoveredList.ForwardLink;Link !=&mDiscoveredList; Link = Link->ForwardLink) {\r
1226     DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);\r
1227     if (DriverEntry->Dependent) {\r
1228       DEBUG ((EFI_D_LOAD, "Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName));\r
1229     }\r
1230   }\r
1231 }\r