]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c
MdeModulePkg: Change use of EFI_D_* to DEBUG_*
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Dispatcher / Dispatcher.c
... / ...
CommitLineData
1/** @file\r
2 DXE Dispatcher.\r
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
29Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
30SPDX-License-Identifier: BSD-2-Clause-Patent\r
31\r
32**/\r
33\r
34#include "DxeMain.h"\r
35\r
36//\r
37// The Driver List contains one copy of every driver that has been discovered.\r
38// Items are never removed from the driver list. List of EFI_CORE_DRIVER_ENTRY\r
39//\r
40LIST_ENTRY mDiscoveredList = INITIALIZE_LIST_HEAD_VARIABLE (mDiscoveredList);\r
41\r
42//\r
43// Queue of drivers that are ready to dispatch. This queue is a subset of the\r
44// mDiscoveredList.list of EFI_CORE_DRIVER_ENTRY.\r
45//\r
46LIST_ENTRY mScheduledQueue = INITIALIZE_LIST_HEAD_VARIABLE (mScheduledQueue);\r
47\r
48//\r
49// List of handles who's Fv's have been parsed and added to the mFwDriverList.\r
50//\r
51LIST_ENTRY mFvHandleList = INITIALIZE_LIST_HEAD_VARIABLE (mFvHandleList); // list of KNOWN_HANDLE\r
52\r
53//\r
54// Lock for mDiscoveredList, mScheduledQueue, gDispatcherRunning.\r
55//\r
56EFI_LOCK mDispatcherLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_HIGH_LEVEL);\r
57\r
58\r
59//\r
60// Flag for the DXE Dispacher. TRUE if dispatcher is execuing.\r
61//\r
62BOOLEAN gDispatcherRunning = FALSE;\r
63\r
64//\r
65// Module globals to manage the FwVol registration notification event\r
66//\r
67EFI_EVENT mFwVolEvent;\r
68VOID *mFwVolEventRegistration;\r
69\r
70//\r
71// List of file types supported by dispatcher\r
72//\r
73EFI_FV_FILETYPE mDxeFileTypes[] = {\r
74 EFI_FV_FILETYPE_DRIVER,\r
75 EFI_FV_FILETYPE_COMBINED_SMM_DXE,\r
76 EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,\r
77 EFI_FV_FILETYPE_DXE_CORE,\r
78 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE\r
79};\r
80\r
81typedef struct {\r
82 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH File;\r
83 EFI_DEVICE_PATH_PROTOCOL End;\r
84} FV_FILEPATH_DEVICE_PATH;\r
85\r
86FV_FILEPATH_DEVICE_PATH mFvDevicePath;\r
87\r
88//\r
89// Function Prototypes\r
90//\r
91/**\r
92 Insert InsertedDriverEntry onto the mScheduledQueue. To do this you\r
93 must add any driver with a before dependency on InsertedDriverEntry first.\r
94 You do this by recursively calling this routine. After all the Befores are\r
95 processed you can add InsertedDriverEntry to the mScheduledQueue.\r
96 Then you can add any driver with an After dependency on InsertedDriverEntry\r
97 by recursively calling this routine.\r
98\r
99 @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue\r
100\r
101**/\r
102VOID\r
103CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (\r
104 IN EFI_CORE_DRIVER_ENTRY *InsertedDriverEntry\r
105 );\r
106\r
107/**\r
108 Event notification that is fired every time a FV dispatch protocol is added.\r
109 More than one protocol may have been added when this event is fired, so you\r
110 must loop on CoreLocateHandle () to see how many protocols were added and\r
111 do the following to each FV:\r
112 If the Fv has already been processed, skip it. If the Fv has not been\r
113 processed then mark it as being processed, as we are about to process it.\r
114 Read the Fv and add any driver in the Fv to the mDiscoveredList.The\r
115 mDiscoveredList is never free'ed and contains variables that define\r
116 the other states the DXE driver transitions to..\r
117 While you are at it read the A Priori file into memory.\r
118 Place drivers in the A Priori list onto the mScheduledQueue.\r
119\r
120 @param Event The Event that is being processed, not used.\r
121 @param Context Event Context, not used.\r
122\r
123**/\r
124VOID\r
125EFIAPI\r
126CoreFwVolEventProtocolNotify (\r
127 IN EFI_EVENT Event,\r
128 IN VOID *Context\r
129 );\r
130\r
131/**\r
132 Convert FvHandle and DriverName into an EFI device path\r
133\r
134 @param Fv Fv protocol, needed to read Depex info out of\r
135 FLASH.\r
136 @param FvHandle Handle for Fv, needed in the\r
137 EFI_CORE_DRIVER_ENTRY so that the PE image can be\r
138 read out of the FV at a later time.\r
139 @param DriverName Name of driver to add to mDiscoveredList.\r
140\r
141 @return Pointer to device path constructed from FvHandle and DriverName\r
142\r
143**/\r
144EFI_DEVICE_PATH_PROTOCOL *\r
145CoreFvToDevicePath (\r
146 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,\r
147 IN EFI_HANDLE FvHandle,\r
148 IN EFI_GUID *DriverName\r
149 );\r
150\r
151/**\r
152 Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,\r
153 and initilize any state variables. Read the Depex from the FV and store it\r
154 in DriverEntry. Pre-process the Depex to set the SOR, Before and After state.\r
155 The Discovered list is never free'ed and contains booleans that represent the\r
156 other possible DXE driver states.\r
157\r
158 @param Fv Fv protocol, needed to read Depex info out of\r
159 FLASH.\r
160 @param FvHandle Handle for Fv, needed in the\r
161 EFI_CORE_DRIVER_ENTRY so that the PE image can be\r
162 read out of the FV at a later time.\r
163 @param DriverName Name of driver to add to mDiscoveredList.\r
164 @param Type Fv File Type of file to add to mDiscoveredList.\r
165\r
166 @retval EFI_SUCCESS If driver was added to the mDiscoveredList.\r
167 @retval EFI_ALREADY_STARTED The driver has already been started. Only one\r
168 DriverName may be active in the system at any one\r
169 time.\r
170\r
171**/\r
172EFI_STATUS\r
173CoreAddToDriverList (\r
174 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,\r
175 IN EFI_HANDLE FvHandle,\r
176 IN EFI_GUID *DriverName,\r
177 IN EFI_FV_FILETYPE Type\r
178 );\r
179\r
180/**\r
181 Get Fv image(s) from the FV through file name, and produce FVB protocol for every Fv image(s).\r
182\r
183 @param Fv The FIRMWARE_VOLUME protocol installed on the FV.\r
184 @param FvHandle The handle which FVB protocol installed on.\r
185 @param FileName The file name guid specified.\r
186\r
187 @retval EFI_OUT_OF_RESOURCES No enough memory or other resource.\r
188 @retval EFI_SUCCESS Function successfully returned.\r
189\r
190**/\r
191EFI_STATUS\r
192CoreProcessFvImageFile (\r
193 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,\r
194 IN EFI_HANDLE FvHandle,\r
195 IN EFI_GUID *FileName\r
196 );\r
197\r
198\r
199/**\r
200 Enter critical section by gaining lock on mDispatcherLock.\r
201\r
202**/\r
203VOID\r
204CoreAcquireDispatcherLock (\r
205 VOID\r
206 )\r
207{\r
208 CoreAcquireLock (&mDispatcherLock);\r
209}\r
210\r
211\r
212/**\r
213 Exit critical section by releasing lock on mDispatcherLock.\r
214\r
215**/\r
216VOID\r
217CoreReleaseDispatcherLock (\r
218 VOID\r
219 )\r
220{\r
221 CoreReleaseLock (&mDispatcherLock);\r
222}\r
223\r
224\r
225/**\r
226 Read Depex and pre-process the Depex for Before and After. If Section Extraction\r
227 protocol returns an error via ReadSection defer the reading of the Depex.\r
228\r
229 @param DriverEntry Driver to work on.\r
230\r
231 @retval EFI_SUCCESS Depex read and preprossesed\r
232 @retval EFI_PROTOCOL_ERROR The section extraction protocol returned an error\r
233 and Depex reading needs to be retried.\r
234 @retval Error DEPEX not found.\r
235\r
236**/\r
237EFI_STATUS\r
238CoreGetDepexSectionAndPreProccess (\r
239 IN EFI_CORE_DRIVER_ENTRY *DriverEntry\r
240 )\r
241{\r
242 EFI_STATUS Status;\r
243 EFI_SECTION_TYPE SectionType;\r
244 UINT32 AuthenticationStatus;\r
245 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
246\r
247\r
248 Fv = DriverEntry->Fv;\r
249\r
250 //\r
251 // Grab Depex info, it will never be free'ed.\r
252 //\r
253 SectionType = EFI_SECTION_DXE_DEPEX;\r
254 Status = Fv->ReadSection (\r
255 DriverEntry->Fv,\r
256 &DriverEntry->FileName,\r
257 SectionType,\r
258 0,\r
259 &DriverEntry->Depex,\r
260 (UINTN *)&DriverEntry->DepexSize,\r
261 &AuthenticationStatus\r
262 );\r
263 if (EFI_ERROR (Status)) {\r
264 if (Status == EFI_PROTOCOL_ERROR) {\r
265 //\r
266 // The section extraction protocol failed so set protocol error flag\r
267 //\r
268 DriverEntry->DepexProtocolError = TRUE;\r
269 } else {\r
270 //\r
271 // If no Depex assume UEFI 2.0 driver model\r
272 //\r
273 DriverEntry->Depex = NULL;\r
274 DriverEntry->Dependent = TRUE;\r
275 DriverEntry->DepexProtocolError = FALSE;\r
276 }\r
277 } else {\r
278 //\r
279 // Set Before, After, and Unrequested state information based on Depex\r
280 // Driver will be put in Dependent or Unrequested state\r
281 //\r
282 CorePreProcessDepex (DriverEntry);\r
283 DriverEntry->DepexProtocolError = FALSE;\r
284 }\r
285\r
286 return Status;\r
287}\r
288\r
289\r
290/**\r
291 Check every driver and locate a matching one. If the driver is found, the Unrequested\r
292 state flag is cleared.\r
293\r
294 @param FirmwareVolumeHandle The handle of the Firmware Volume that contains\r
295 the firmware file specified by DriverName.\r
296 @param DriverName The Driver name to put in the Dependent state.\r
297\r
298 @retval EFI_SUCCESS The DriverName was found and it's SOR bit was\r
299 cleared\r
300 @retval EFI_NOT_FOUND The DriverName does not exist or it's SOR bit was\r
301 not set.\r
302\r
303**/\r
304EFI_STATUS\r
305EFIAPI\r
306CoreSchedule (\r
307 IN EFI_HANDLE FirmwareVolumeHandle,\r
308 IN EFI_GUID *DriverName\r
309 )\r
310{\r
311 LIST_ENTRY *Link;\r
312 EFI_CORE_DRIVER_ENTRY *DriverEntry;\r
313\r
314 //\r
315 // Check every driver\r
316 //\r
317 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
318 DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);\r
319 if (DriverEntry->FvHandle == FirmwareVolumeHandle &&\r
320 DriverEntry->Unrequested &&\r
321 CompareGuid (DriverName, &DriverEntry->FileName)) {\r
322 //\r
323 // Move the driver from the Unrequested to the Dependent state\r
324 //\r
325 CoreAcquireDispatcherLock ();\r
326 DriverEntry->Unrequested = FALSE;\r
327 DriverEntry->Dependent = TRUE;\r
328 CoreReleaseDispatcherLock ();\r
329\r
330 DEBUG ((DEBUG_DISPATCH, "Schedule FFS(%g) - EFI_SUCCESS\n", DriverName));\r
331\r
332 return EFI_SUCCESS;\r
333 }\r
334 }\r
335\r
336 DEBUG ((DEBUG_DISPATCH, "Schedule FFS(%g) - EFI_NOT_FOUND\n", DriverName));\r
337\r
338 return EFI_NOT_FOUND;\r
339}\r
340\r
341\r
342\r
343/**\r
344 Convert a driver from the Untrused back to the Scheduled state.\r
345\r
346 @param FirmwareVolumeHandle The handle of the Firmware Volume that contains\r
347 the firmware file specified by DriverName.\r
348 @param DriverName The Driver name to put in the Scheduled state\r
349\r
350 @retval EFI_SUCCESS The file was found in the untrusted state, and it\r
351 was promoted to the trusted state.\r
352 @retval EFI_NOT_FOUND The file was not found in the untrusted state.\r
353\r
354**/\r
355EFI_STATUS\r
356EFIAPI\r
357CoreTrust (\r
358 IN EFI_HANDLE FirmwareVolumeHandle,\r
359 IN EFI_GUID *DriverName\r
360 )\r
361{\r
362 LIST_ENTRY *Link;\r
363 EFI_CORE_DRIVER_ENTRY *DriverEntry;\r
364\r
365 //\r
366 // Check every driver\r
367 //\r
368 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
369 DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);\r
370 if (DriverEntry->FvHandle == FirmwareVolumeHandle &&\r
371 DriverEntry->Untrusted &&\r
372 CompareGuid (DriverName, &DriverEntry->FileName)) {\r
373 //\r
374 // Transition driver from Untrusted to Scheduled state.\r
375 //\r
376 CoreAcquireDispatcherLock ();\r
377 DriverEntry->Untrusted = FALSE;\r
378 DriverEntry->Scheduled = TRUE;\r
379 InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);\r
380 CoreReleaseDispatcherLock ();\r
381\r
382 return EFI_SUCCESS;\r
383 }\r
384 }\r
385 return EFI_NOT_FOUND;\r
386}\r
387\r
388/**\r
389 This is the main Dispatcher for DXE and it exits when there are no more\r
390 drivers to run. Drain the mScheduledQueue and load and start a PE\r
391 image for each driver. Search the mDiscoveredList to see if any driver can\r
392 be placed on the mScheduledQueue. If no drivers are placed on the\r
393 mScheduledQueue exit the function. On exit it is assumed the Bds()\r
394 will be called, and when the Bds() exits the Dispatcher will be called\r
395 again.\r
396\r
397 @retval EFI_ALREADY_STARTED The DXE Dispatcher is already running\r
398 @retval EFI_NOT_FOUND No DXE Drivers were dispatched\r
399 @retval EFI_SUCCESS One or more DXE Drivers were dispatched\r
400\r
401**/\r
402EFI_STATUS\r
403EFIAPI\r
404CoreDispatcher (\r
405 VOID\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 EFI_EVENT DxeDispatchEvent;\r
414\r
415 PERF_FUNCTION_BEGIN ();\r
416\r
417 if (gDispatcherRunning) {\r
418 //\r
419 // If the dispatcher is running don't let it be restarted.\r
420 //\r
421 return EFI_ALREADY_STARTED;\r
422 }\r
423\r
424 gDispatcherRunning = TRUE;\r
425\r
426 Status = CoreCreateEventEx (\r
427 EVT_NOTIFY_SIGNAL,\r
428 TPL_NOTIFY,\r
429 EfiEventEmptyFunction,\r
430 NULL,\r
431 &gEfiEventDxeDispatchGuid,\r
432 &DxeDispatchEvent\r
433 );\r
434 if (EFI_ERROR (Status)) {\r
435 return Status;\r
436 }\r
437\r
438 ReturnStatus = EFI_NOT_FOUND;\r
439 do {\r
440 //\r
441 // Drain the Scheduled Queue\r
442 //\r
443 while (!IsListEmpty (&mScheduledQueue)) {\r
444 DriverEntry = CR (\r
445 mScheduledQueue.ForwardLink,\r
446 EFI_CORE_DRIVER_ENTRY,\r
447 ScheduledLink,\r
448 EFI_CORE_DRIVER_ENTRY_SIGNATURE\r
449 );\r
450\r
451 //\r
452 // Load the DXE Driver image into memory. If the Driver was transitioned from\r
453 // Untrused to Scheduled it would have already been loaded so we may need to\r
454 // skip the LoadImage\r
455 //\r
456 if (DriverEntry->ImageHandle == NULL && !DriverEntry->IsFvImage) {\r
457 DEBUG ((DEBUG_INFO, "Loading driver %g\n", &DriverEntry->FileName));\r
458 Status = CoreLoadImage (\r
459 FALSE,\r
460 gDxeCoreImageHandle,\r
461 DriverEntry->FvFileDevicePath,\r
462 NULL,\r
463 0,\r
464 &DriverEntry->ImageHandle\r
465 );\r
466\r
467 //\r
468 // Update the driver state to reflect that it's been loaded\r
469 //\r
470 if (EFI_ERROR (Status)) {\r
471 CoreAcquireDispatcherLock ();\r
472\r
473 if (Status == EFI_SECURITY_VIOLATION) {\r
474 //\r
475 // Take driver from Scheduled to Untrused state\r
476 //\r
477 DriverEntry->Untrusted = TRUE;\r
478 } else {\r
479 //\r
480 // The DXE Driver could not be loaded, and do not attempt to load or start it again.\r
481 // Take driver from Scheduled to Initialized.\r
482 //\r
483 // This case include the Never Trusted state if EFI_ACCESS_DENIED is returned\r
484 //\r
485 DriverEntry->Initialized = TRUE;\r
486 }\r
487\r
488 DriverEntry->Scheduled = FALSE;\r
489 RemoveEntryList (&DriverEntry->ScheduledLink);\r
490\r
491 CoreReleaseDispatcherLock ();\r
492\r
493 //\r
494 // If it's an error don't try the StartImage\r
495 //\r
496 continue;\r
497 }\r
498 }\r
499\r
500 CoreAcquireDispatcherLock ();\r
501\r
502 DriverEntry->Scheduled = FALSE;\r
503 DriverEntry->Initialized = TRUE;\r
504 RemoveEntryList (&DriverEntry->ScheduledLink);\r
505\r
506 CoreReleaseDispatcherLock ();\r
507\r
508\r
509 if (DriverEntry->IsFvImage) {\r
510 //\r
511 // Produce a firmware volume block protocol for FvImage so it gets dispatched from.\r
512 //\r
513 Status = CoreProcessFvImageFile (DriverEntry->Fv, DriverEntry->FvHandle, &DriverEntry->FileName);\r
514 } else {\r
515 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (\r
516 EFI_PROGRESS_CODE,\r
517 (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_BEGIN),\r
518 &DriverEntry->ImageHandle,\r
519 sizeof (DriverEntry->ImageHandle)\r
520 );\r
521 ASSERT (DriverEntry->ImageHandle != NULL);\r
522\r
523 Status = CoreStartImage (DriverEntry->ImageHandle, NULL, NULL);\r
524\r
525 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (\r
526 EFI_PROGRESS_CODE,\r
527 (EFI_SOFTWARE_DXE_CORE | EFI_SW_PC_INIT_END),\r
528 &DriverEntry->ImageHandle,\r
529 sizeof (DriverEntry->ImageHandle)\r
530 );\r
531 }\r
532\r
533 ReturnStatus = EFI_SUCCESS;\r
534 }\r
535\r
536 //\r
537 // Now DXE Dispatcher finished one round of dispatch, signal an event group\r
538 // so that SMM Dispatcher get chance to dispatch SMM Drivers which depend\r
539 // on UEFI protocols\r
540 //\r
541 if (!EFI_ERROR (ReturnStatus)) {\r
542 CoreSignalEvent (DxeDispatchEvent);\r
543 }\r
544\r
545 //\r
546 // Search DriverList for items to place on Scheduled Queue\r
547 //\r
548 ReadyToRun = FALSE;\r
549 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
550 DriverEntry = CR (Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);\r
551\r
552 if (DriverEntry->DepexProtocolError){\r
553 //\r
554 // If Section Extraction Protocol did not let the Depex be read before retry the read\r
555 //\r
556 Status = CoreGetDepexSectionAndPreProccess (DriverEntry);\r
557 }\r
558\r
559 if (DriverEntry->Dependent) {\r
560 if (CoreIsSchedulable (DriverEntry)) {\r
561 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);\r
562 ReadyToRun = TRUE;\r
563 }\r
564 } else {\r
565 if (DriverEntry->Unrequested) {\r
566 DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));\r
567 DEBUG ((DEBUG_DISPATCH, " SOR = Not Requested\n"));\r
568 DEBUG ((DEBUG_DISPATCH, " RESULT = FALSE\n"));\r
569 }\r
570 }\r
571 }\r
572 } while (ReadyToRun);\r
573\r
574 //\r
575 // Close DXE dispatch Event\r
576 //\r
577 CoreCloseEvent (DxeDispatchEvent);\r
578\r
579 gDispatcherRunning = FALSE;\r
580\r
581 PERF_FUNCTION_END ();\r
582\r
583 return ReturnStatus;\r
584}\r
585\r
586\r
587/**\r
588 Insert InsertedDriverEntry onto the mScheduledQueue. To do this you\r
589 must add any driver with a before dependency on InsertedDriverEntry first.\r
590 You do this by recursively calling this routine. After all the Befores are\r
591 processed you can add InsertedDriverEntry to the mScheduledQueue.\r
592 Then you can add any driver with an After dependency on InsertedDriverEntry\r
593 by recursively calling this routine.\r
594\r
595 @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue\r
596\r
597**/\r
598VOID\r
599CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (\r
600 IN EFI_CORE_DRIVER_ENTRY *InsertedDriverEntry\r
601 )\r
602{\r
603 LIST_ENTRY *Link;\r
604 EFI_CORE_DRIVER_ENTRY *DriverEntry;\r
605\r
606 //\r
607 // Process Before Dependency\r
608 //\r
609 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
610 DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);\r
611 if (DriverEntry->Before && DriverEntry->Dependent && DriverEntry != InsertedDriverEntry) {\r
612 DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));\r
613 DEBUG ((DEBUG_DISPATCH, " BEFORE FFS(%g) = ", &DriverEntry->BeforeAfterGuid));\r
614 if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {\r
615 //\r
616 // Recursively process BEFORE\r
617 //\r
618 DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n"));\r
619 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);\r
620 } else {\r
621 DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));\r
622 }\r
623 }\r
624 }\r
625\r
626 //\r
627 // Convert driver from Dependent to Scheduled state\r
628 //\r
629 CoreAcquireDispatcherLock ();\r
630\r
631 InsertedDriverEntry->Dependent = FALSE;\r
632 InsertedDriverEntry->Scheduled = TRUE;\r
633 InsertTailList (&mScheduledQueue, &InsertedDriverEntry->ScheduledLink);\r
634\r
635 CoreReleaseDispatcherLock ();\r
636\r
637 //\r
638 // Process After Dependency\r
639 //\r
640 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
641 DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);\r
642 if (DriverEntry->After && DriverEntry->Dependent && DriverEntry != InsertedDriverEntry) {\r
643 DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));\r
644 DEBUG ((DEBUG_DISPATCH, " AFTER FFS(%g) = ", &DriverEntry->BeforeAfterGuid));\r
645 if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {\r
646 //\r
647 // Recursively process AFTER\r
648 //\r
649 DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n"));\r
650 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);\r
651 } else {\r
652 DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));\r
653 }\r
654 }\r
655 }\r
656}\r
657\r
658\r
659/**\r
660 Return TRUE if the Fv has been processed, FALSE if not.\r
661\r
662 @param FvHandle The handle of a FV that's being tested\r
663\r
664 @retval TRUE Fv protocol on FvHandle has been processed\r
665 @retval FALSE Fv protocol on FvHandle has not yet been processed\r
666\r
667**/\r
668BOOLEAN\r
669FvHasBeenProcessed (\r
670 IN EFI_HANDLE FvHandle\r
671 )\r
672{\r
673 LIST_ENTRY *Link;\r
674 KNOWN_HANDLE *KnownHandle;\r
675\r
676 for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) {\r
677 KnownHandle = CR(Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE);\r
678 if (KnownHandle->Handle == FvHandle) {\r
679 return TRUE;\r
680 }\r
681 }\r
682 return FALSE;\r
683}\r
684\r
685\r
686/**\r
687 Remember that Fv protocol on FvHandle has had it's drivers placed on the\r
688 mDiscoveredList. This fucntion adds entries on the mFvHandleList if new\r
689 entry is different from one in mFvHandleList by checking FvImage Guid.\r
690 Items are never removed/freed from the mFvHandleList.\r
691\r
692 @param FvHandle The handle of a FV that has been processed\r
693\r
694 @return A point to new added FvHandle entry. If FvHandle with the same FvImage guid\r
695 has been added, NULL will return.\r
696\r
697**/\r
698KNOWN_HANDLE *\r
699FvIsBeingProcessed (\r
700 IN EFI_HANDLE FvHandle\r
701 )\r
702{\r
703 EFI_STATUS Status;\r
704 EFI_GUID FvNameGuid;\r
705 BOOLEAN FvNameGuidIsFound;\r
706 UINT32 ExtHeaderOffset;\r
707 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
708 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
709 EFI_FV_BLOCK_MAP_ENTRY *BlockMap;\r
710 UINTN LbaOffset;\r
711 UINTN Index;\r
712 EFI_LBA LbaIndex;\r
713 LIST_ENTRY *Link;\r
714 KNOWN_HANDLE *KnownHandle;\r
715\r
716 FwVolHeader = NULL;\r
717\r
718 //\r
719 // Get the FirmwareVolumeBlock protocol on that handle\r
720 //\r
721 FvNameGuidIsFound = FALSE;\r
722 Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolumeBlockProtocolGuid, (VOID **)&Fvb);\r
723 if (!EFI_ERROR (Status)) {\r
724 //\r
725 // Get the full FV header based on FVB protocol.\r
726 //\r
727 ASSERT (Fvb != NULL);\r
728 Status = GetFwVolHeader (Fvb, &FwVolHeader);\r
729 if (!EFI_ERROR (Status)) {\r
730 ASSERT (FwVolHeader != NULL);\r
731 if (VerifyFvHeaderChecksum (FwVolHeader) && FwVolHeader->ExtHeaderOffset != 0) {\r
732 ExtHeaderOffset = (UINT32) FwVolHeader->ExtHeaderOffset;\r
733 BlockMap = FwVolHeader->BlockMap;\r
734 LbaIndex = 0;\r
735 LbaOffset = 0;\r
736 //\r
737 // Find LbaIndex and LbaOffset for FV extension header based on BlockMap.\r
738 //\r
739 while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {\r
740 for (Index = 0; Index < BlockMap->NumBlocks && ExtHeaderOffset >= BlockMap->Length; Index ++) {\r
741 ExtHeaderOffset -= BlockMap->Length;\r
742 LbaIndex ++;\r
743 }\r
744 //\r
745 // Check whether FvExtHeader is crossing the multi block range.\r
746 //\r
747 if (Index < BlockMap->NumBlocks) {\r
748 LbaOffset = ExtHeaderOffset;\r
749 break;\r
750 }\r
751 BlockMap++;\r
752 }\r
753 //\r
754 // Read FvNameGuid from FV extension header.\r
755 //\r
756 Status = ReadFvbData (Fvb, &LbaIndex, &LbaOffset, sizeof (FvNameGuid), (UINT8 *) &FvNameGuid);\r
757 if (!EFI_ERROR (Status)) {\r
758 FvNameGuidIsFound = TRUE;\r
759 }\r
760 }\r
761 CoreFreePool (FwVolHeader);\r
762 }\r
763 }\r
764\r
765 if (FvNameGuidIsFound) {\r
766 //\r
767 // Check whether the FV image with the found FvNameGuid has been processed.\r
768 //\r
769 for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) {\r
770 KnownHandle = CR(Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE);\r
771 if (CompareGuid (&FvNameGuid, &KnownHandle->FvNameGuid)) {\r
772 DEBUG ((DEBUG_ERROR, "FvImage on FvHandle %p and %p has the same FvNameGuid %g.\n", FvHandle, KnownHandle->Handle, &FvNameGuid));\r
773 return NULL;\r
774 }\r
775 }\r
776 }\r
777\r
778 KnownHandle = AllocateZeroPool (sizeof (KNOWN_HANDLE));\r
779 ASSERT (KnownHandle != NULL);\r
780\r
781 KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE;\r
782 KnownHandle->Handle = FvHandle;\r
783 if (FvNameGuidIsFound) {\r
784 CopyGuid (&KnownHandle->FvNameGuid, &FvNameGuid);\r
785 }\r
786 InsertTailList (&mFvHandleList, &KnownHandle->Link);\r
787 return KnownHandle;\r
788}\r
789\r
790\r
791\r
792\r
793/**\r
794 Convert FvHandle and DriverName into an EFI device path\r
795\r
796 @param Fv Fv protocol, needed to read Depex info out of\r
797 FLASH.\r
798 @param FvHandle Handle for Fv, needed in the\r
799 EFI_CORE_DRIVER_ENTRY so that the PE image can be\r
800 read out of the FV at a later time.\r
801 @param DriverName Name of driver to add to mDiscoveredList.\r
802\r
803 @return Pointer to device path constructed from FvHandle and DriverName\r
804\r
805**/\r
806EFI_DEVICE_PATH_PROTOCOL *\r
807CoreFvToDevicePath (\r
808 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,\r
809 IN EFI_HANDLE FvHandle,\r
810 IN EFI_GUID *DriverName\r
811 )\r
812{\r
813 EFI_STATUS Status;\r
814 EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;\r
815 EFI_DEVICE_PATH_PROTOCOL *FileNameDevicePath;\r
816\r
817 //\r
818 // Remember the device path of the FV\r
819 //\r
820 Status = CoreHandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);\r
821 if (EFI_ERROR (Status)) {\r
822 FileNameDevicePath = NULL;\r
823 } else {\r
824 //\r
825 // Build a device path to the file in the FV to pass into gBS->LoadImage\r
826 //\r
827 EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, DriverName);\r
828 SetDevicePathEndNode (&mFvDevicePath.End);\r
829\r
830 FileNameDevicePath = AppendDevicePath (\r
831 FvDevicePath,\r
832 (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath\r
833 );\r
834 }\r
835\r
836 return FileNameDevicePath;\r
837}\r
838\r
839\r
840\r
841/**\r
842 Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,\r
843 and initilize any state variables. Read the Depex from the FV and store it\r
844 in DriverEntry. Pre-process the Depex to set the SOR, Before and After state.\r
845 The Discovered list is never free'ed and contains booleans that represent the\r
846 other possible DXE driver states.\r
847\r
848 @param Fv Fv protocol, needed to read Depex info out of\r
849 FLASH.\r
850 @param FvHandle Handle for Fv, needed in the\r
851 EFI_CORE_DRIVER_ENTRY so that the PE image can be\r
852 read out of the FV at a later time.\r
853 @param DriverName Name of driver to add to mDiscoveredList.\r
854 @param Type Fv File Type of file to add to mDiscoveredList.\r
855\r
856 @retval EFI_SUCCESS If driver was added to the mDiscoveredList.\r
857 @retval EFI_ALREADY_STARTED The driver has already been started. Only one\r
858 DriverName may be active in the system at any one\r
859 time.\r
860\r
861**/\r
862EFI_STATUS\r
863CoreAddToDriverList (\r
864 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,\r
865 IN EFI_HANDLE FvHandle,\r
866 IN EFI_GUID *DriverName,\r
867 IN EFI_FV_FILETYPE Type\r
868 )\r
869{\r
870 EFI_CORE_DRIVER_ENTRY *DriverEntry;\r
871\r
872\r
873 //\r
874 // Create the Driver Entry for the list. ZeroPool initializes lots of variables to\r
875 // NULL or FALSE.\r
876 //\r
877 DriverEntry = AllocateZeroPool (sizeof (EFI_CORE_DRIVER_ENTRY));\r
878 ASSERT (DriverEntry != NULL);\r
879 if (Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {\r
880 DriverEntry->IsFvImage = TRUE;\r
881 }\r
882\r
883 DriverEntry->Signature = EFI_CORE_DRIVER_ENTRY_SIGNATURE;\r
884 CopyGuid (&DriverEntry->FileName, DriverName);\r
885 DriverEntry->FvHandle = FvHandle;\r
886 DriverEntry->Fv = Fv;\r
887 DriverEntry->FvFileDevicePath = CoreFvToDevicePath (Fv, FvHandle, DriverName);\r
888\r
889 CoreGetDepexSectionAndPreProccess (DriverEntry);\r
890\r
891 CoreAcquireDispatcherLock ();\r
892\r
893 InsertTailList (&mDiscoveredList, &DriverEntry->Link);\r
894\r
895 CoreReleaseDispatcherLock ();\r
896\r
897 return EFI_SUCCESS;\r
898}\r
899\r
900\r
901/**\r
902 Check if a FV Image type file (EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) is\r
903 described by a EFI_HOB_FIRMWARE_VOLUME2 Hob.\r
904\r
905 @param FvNameGuid The FV image guid specified.\r
906 @param DriverName The driver guid specified.\r
907\r
908 @retval TRUE This file is found in a EFI_HOB_FIRMWARE_VOLUME2\r
909 Hob.\r
910 @retval FALSE Not found.\r
911\r
912**/\r
913BOOLEAN\r
914FvFoundInHobFv2 (\r
915 IN CONST EFI_GUID *FvNameGuid,\r
916 IN CONST EFI_GUID *DriverName\r
917 )\r
918{\r
919 EFI_PEI_HOB_POINTERS HobFv2;\r
920\r
921 HobFv2.Raw = GetHobList ();\r
922\r
923 while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) {\r
924 //\r
925 // Compare parent FvNameGuid and FileGuid both.\r
926 //\r
927 if (CompareGuid (DriverName, &HobFv2.FirmwareVolume2->FileName) &&\r
928 CompareGuid (FvNameGuid, &HobFv2.FirmwareVolume2->FvName)) {\r
929 return TRUE;\r
930 }\r
931 HobFv2.Raw = GET_NEXT_HOB (HobFv2);\r
932 }\r
933\r
934 return FALSE;\r
935}\r
936\r
937/**\r
938 Find USED_SIZE FV_EXT_TYPE entry in FV extension header and get the FV used size.\r
939\r
940 @param[in] FvHeader Pointer to FV header.\r
941 @param[out] FvUsedSize Pointer to FV used size returned,\r
942 only valid if USED_SIZE FV_EXT_TYPE entry is found.\r
943 @param[out] EraseByte Pointer to erase byte returned,\r
944 only valid if USED_SIZE FV_EXT_TYPE entry is found.\r
945\r
946 @retval TRUE USED_SIZE FV_EXT_TYPE entry is found,\r
947 FV used size and erase byte are returned.\r
948 @retval FALSE No USED_SIZE FV_EXT_TYPE entry found.\r
949\r
950**/\r
951BOOLEAN\r
952GetFvUsedSize (\r
953 IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader,\r
954 OUT UINT32 *FvUsedSize,\r
955 OUT UINT8 *EraseByte\r
956 )\r
957{\r
958 UINT16 ExtHeaderOffset;\r
959 EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtHeader;\r
960 EFI_FIRMWARE_VOLUME_EXT_ENTRY *ExtEntryList;\r
961 EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE *ExtEntryUsedSize;\r
962\r
963 ExtHeaderOffset = ReadUnaligned16 (&FvHeader->ExtHeaderOffset);\r
964 if (ExtHeaderOffset != 0) {\r
965 ExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) ((UINT8 *) FvHeader + ExtHeaderOffset);\r
966 ExtEntryList = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *) (ExtHeader + 1);\r
967 while ((UINTN) ExtEntryList < ((UINTN) ExtHeader + ReadUnaligned32 (&ExtHeader->ExtHeaderSize))) {\r
968 if (ReadUnaligned16 (&ExtEntryList->ExtEntryType) == EFI_FV_EXT_TYPE_USED_SIZE_TYPE) {\r
969 //\r
970 // USED_SIZE FV_EXT_TYPE entry is found.\r
971 //\r
972 ExtEntryUsedSize = (EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE *) ExtEntryList;\r
973 *FvUsedSize = ReadUnaligned32 (&ExtEntryUsedSize->UsedSize);\r
974 if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ERASE_POLARITY) != 0) {\r
975 *EraseByte = 0xFF;\r
976 } else {\r
977 *EraseByte = 0;\r
978 }\r
979 DEBUG ((\r
980 DEBUG_INFO,\r
981 "FV at 0x%x has 0x%x used size, and erase byte is 0x%02x\n",\r
982 FvHeader,\r
983 *FvUsedSize,\r
984 *EraseByte\r
985 ));\r
986 return TRUE;\r
987 }\r
988 ExtEntryList = (EFI_FIRMWARE_VOLUME_EXT_ENTRY *)\r
989 ((UINT8 *) ExtEntryList + ReadUnaligned16 (&ExtEntryList->ExtEntrySize));\r
990 }\r
991 }\r
992\r
993 //\r
994 // No USED_SIZE FV_EXT_TYPE entry found.\r
995 //\r
996 return FALSE;\r
997}\r
998\r
999/**\r
1000 Get Fv image(s) from the FV through file name, and produce FVB protocol for every Fv image(s).\r
1001\r
1002 @param Fv The FIRMWARE_VOLUME protocol installed on the FV.\r
1003 @param FvHandle The handle which FVB protocol installed on.\r
1004 @param FileName The file name guid specified.\r
1005\r
1006 @retval EFI_OUT_OF_RESOURCES No enough memory or other resource.\r
1007 @retval EFI_SUCCESS Function successfully returned.\r
1008\r
1009**/\r
1010EFI_STATUS\r
1011CoreProcessFvImageFile (\r
1012 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,\r
1013 IN EFI_HANDLE FvHandle,\r
1014 IN EFI_GUID *FileName\r
1015 )\r
1016{\r
1017 EFI_STATUS Status;\r
1018 EFI_SECTION_TYPE SectionType;\r
1019 UINT32 AuthenticationStatus;\r
1020 VOID *Buffer;\r
1021 VOID *AlignedBuffer;\r
1022 UINTN BufferSize;\r
1023 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
1024 UINT32 FvAlignment;\r
1025 EFI_DEVICE_PATH_PROTOCOL *FvFileDevicePath;\r
1026 UINT32 FvUsedSize;\r
1027 UINT8 EraseByte;\r
1028 UINTN Index;\r
1029\r
1030 //\r
1031 // Read firmware volume section(s)\r
1032 //\r
1033 SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;\r
1034\r
1035 Index = 0;\r
1036 do {\r
1037 FvHeader = NULL;\r
1038 FvAlignment = 0;\r
1039 Buffer = NULL;\r
1040 BufferSize = 0;\r
1041 AlignedBuffer = NULL;\r
1042 Status = Fv->ReadSection (\r
1043 Fv,\r
1044 FileName,\r
1045 SectionType,\r
1046 Index,\r
1047 &Buffer,\r
1048 &BufferSize,\r
1049 &AuthenticationStatus\r
1050 );\r
1051 if (!EFI_ERROR (Status)) {\r
1052 //\r
1053 // Evaluate the authentication status of the Firmware Volume through\r
1054 // Security Architectural Protocol\r
1055 //\r
1056 if (gSecurity != NULL) {\r
1057 FvFileDevicePath = CoreFvToDevicePath (Fv, FvHandle, FileName);\r
1058 Status = gSecurity->FileAuthenticationState (\r
1059 gSecurity,\r
1060 AuthenticationStatus,\r
1061 FvFileDevicePath\r
1062 );\r
1063 if (FvFileDevicePath != NULL) {\r
1064 FreePool (FvFileDevicePath);\r
1065 }\r
1066\r
1067 if (Status != EFI_SUCCESS) {\r
1068 //\r
1069 // Security check failed. The firmware volume should not be used for any purpose.\r
1070 //\r
1071 if (Buffer != NULL) {\r
1072 FreePool (Buffer);\r
1073 }\r
1074 break;\r
1075 }\r
1076 }\r
1077\r
1078 //\r
1079 // FvImage should be at its required alignment.\r
1080 //\r
1081 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) Buffer;\r
1082 //\r
1083 // If EFI_FVB2_WEAK_ALIGNMENT is set in the volume header then the first byte of the volume\r
1084 // can be aligned on any power-of-two boundary. A weakly aligned volume can not be moved from\r
1085 // its initial linked location and maintain its alignment.\r
1086 //\r
1087 if ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) {\r
1088 //\r
1089 // Get FvHeader alignment\r
1090 //\r
1091 FvAlignment = 1 << ((ReadUnaligned32 (&FvHeader->Attributes) & EFI_FVB2_ALIGNMENT) >> 16);\r
1092 //\r
1093 // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.\r
1094 //\r
1095 if (FvAlignment < 8) {\r
1096 FvAlignment = 8;\r
1097 }\r
1098\r
1099 DEBUG ((\r
1100 DEBUG_INFO,\r
1101 "%a() FV at 0x%x, FvAlignment required is 0x%x\n",\r
1102 __FUNCTION__,\r
1103 FvHeader,\r
1104 FvAlignment\r
1105 ));\r
1106\r
1107 //\r
1108 // Check FvImage alignment.\r
1109 //\r
1110 if ((UINTN) FvHeader % FvAlignment != 0) {\r
1111 //\r
1112 // Allocate the aligned buffer for the FvImage.\r
1113 //\r
1114 AlignedBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), (UINTN) FvAlignment);\r
1115 if (AlignedBuffer == NULL) {\r
1116 FreePool (Buffer);\r
1117 Status = EFI_OUT_OF_RESOURCES;\r
1118 break;\r
1119 } else {\r
1120 //\r
1121 // Move FvImage into the aligned buffer and release the original buffer.\r
1122 //\r
1123 if (GetFvUsedSize (FvHeader, &FvUsedSize, &EraseByte)) {\r
1124 //\r
1125 // Copy the used bytes and fill the rest with the erase value.\r
1126 //\r
1127 CopyMem (AlignedBuffer, FvHeader, (UINTN) FvUsedSize);\r
1128 SetMem (\r
1129 (UINT8 *) AlignedBuffer + FvUsedSize,\r
1130 (UINTN) (BufferSize - FvUsedSize),\r
1131 EraseByte\r
1132 );\r
1133 } else {\r
1134 CopyMem (AlignedBuffer, Buffer, BufferSize);\r
1135 }\r
1136 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) AlignedBuffer;\r
1137 FreePool (Buffer);\r
1138 Buffer = NULL;\r
1139 }\r
1140 }\r
1141 }\r
1142 //\r
1143 // Produce a FVB protocol for the file\r
1144 //\r
1145 Status = ProduceFVBProtocolOnBuffer (\r
1146 (EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader,\r
1147 (UINT64)BufferSize,\r
1148 FvHandle,\r
1149 AuthenticationStatus,\r
1150 NULL\r
1151 );\r
1152 }\r
1153\r
1154 if (EFI_ERROR (Status)) {\r
1155 //\r
1156 // ReadSection or Produce FVB failed, Free data buffer\r
1157 //\r
1158 if (Buffer != NULL) {\r
1159 FreePool (Buffer);\r
1160 }\r
1161\r
1162 if (AlignedBuffer != NULL) {\r
1163 FreeAlignedPages (AlignedBuffer, EFI_SIZE_TO_PAGES (BufferSize));\r
1164 }\r
1165\r
1166 break;\r
1167 } else {\r
1168 Index++;\r
1169 }\r
1170 } while (TRUE);\r
1171\r
1172 if (Index > 0) {\r
1173 //\r
1174 // At least one FvImage has been processed successfully.\r
1175 //\r
1176 return EFI_SUCCESS;\r
1177 } else {\r
1178 return Status;\r
1179 }\r
1180}\r
1181\r
1182\r
1183/**\r
1184 Event notification that is fired every time a FV dispatch protocol is added.\r
1185 More than one protocol may have been added when this event is fired, so you\r
1186 must loop on CoreLocateHandle () to see how many protocols were added and\r
1187 do the following to each FV:\r
1188 If the Fv has already been processed, skip it. If the Fv has not been\r
1189 processed then mark it as being processed, as we are about to process it.\r
1190 Read the Fv and add any driver in the Fv to the mDiscoveredList.The\r
1191 mDiscoveredList is never free'ed and contains variables that define\r
1192 the other states the DXE driver transitions to..\r
1193 While you are at it read the A Priori file into memory.\r
1194 Place drivers in the A Priori list onto the mScheduledQueue.\r
1195\r
1196 @param Event The Event that is being processed, not used.\r
1197 @param Context Event Context, not used.\r
1198\r
1199**/\r
1200VOID\r
1201EFIAPI\r
1202CoreFwVolEventProtocolNotify (\r
1203 IN EFI_EVENT Event,\r
1204 IN VOID *Context\r
1205 )\r
1206{\r
1207 EFI_STATUS Status;\r
1208 EFI_STATUS GetNextFileStatus;\r
1209 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
1210 EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;\r
1211 EFI_HANDLE FvHandle;\r
1212 UINTN BufferSize;\r
1213 EFI_GUID NameGuid;\r
1214 UINTN Key;\r
1215 EFI_FV_FILETYPE Type;\r
1216 EFI_FV_FILE_ATTRIBUTES Attributes;\r
1217 UINTN Size;\r
1218 EFI_CORE_DRIVER_ENTRY *DriverEntry;\r
1219 EFI_GUID *AprioriFile;\r
1220 UINTN AprioriEntryCount;\r
1221 UINTN Index;\r
1222 LIST_ENTRY *Link;\r
1223 UINT32 AuthenticationStatus;\r
1224 UINTN SizeOfBuffer;\r
1225 VOID *DepexBuffer;\r
1226 KNOWN_HANDLE *KnownHandle;\r
1227\r
1228 FvHandle = NULL;\r
1229\r
1230 while (TRUE) {\r
1231 BufferSize = sizeof (EFI_HANDLE);\r
1232 Status = CoreLocateHandle (\r
1233 ByRegisterNotify,\r
1234 NULL,\r
1235 mFwVolEventRegistration,\r
1236 &BufferSize,\r
1237 &FvHandle\r
1238 );\r
1239 if (EFI_ERROR (Status)) {\r
1240 //\r
1241 // If no more notification events exit\r
1242 //\r
1243 return;\r
1244 }\r
1245\r
1246 if (FvHasBeenProcessed (FvHandle)) {\r
1247 //\r
1248 // This Fv has already been processed so lets skip it!\r
1249 //\r
1250 continue;\r
1251 }\r
1252\r
1253 //\r
1254 // Since we are about to process this Fv mark it as processed.\r
1255 //\r
1256 KnownHandle = FvIsBeingProcessed (FvHandle);\r
1257 if (KnownHandle == NULL) {\r
1258 //\r
1259 // The FV with the same FV name guid has already been processed.\r
1260 // So lets skip it!\r
1261 //\r
1262 continue;\r
1263 }\r
1264\r
1265 Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);\r
1266 if (EFI_ERROR (Status) || Fv == NULL) {\r
1267 //\r
1268 // FvHandle must have Firmware Volume2 protocol thus we should never get here.\r
1269 //\r
1270 ASSERT (FALSE);\r
1271 continue;\r
1272 }\r
1273\r
1274 Status = CoreHandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);\r
1275 if (EFI_ERROR (Status)) {\r
1276 //\r
1277 // The Firmware volume doesn't have device path, can't be dispatched.\r
1278 //\r
1279 continue;\r
1280 }\r
1281\r
1282 //\r
1283 // Discover Drivers in FV and add them to the Discovered Driver List.\r
1284 // Process EFI_FV_FILETYPE_DRIVER type and then EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER\r
1285 // EFI_FV_FILETYPE_DXE_CORE is processed to produce a Loaded Image protocol for the core\r
1286 // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE is processed to create a Fvb\r
1287 //\r
1288 for (Index = 0; Index < sizeof (mDxeFileTypes) / sizeof (EFI_FV_FILETYPE); Index++) {\r
1289 //\r
1290 // Initialize the search key\r
1291 //\r
1292 Key = 0;\r
1293 do {\r
1294 Type = mDxeFileTypes[Index];\r
1295 GetNextFileStatus = Fv->GetNextFile (\r
1296 Fv,\r
1297 &Key,\r
1298 &Type,\r
1299 &NameGuid,\r
1300 &Attributes,\r
1301 &Size\r
1302 );\r
1303 if (!EFI_ERROR (GetNextFileStatus)) {\r
1304 if (Type == EFI_FV_FILETYPE_DXE_CORE) {\r
1305 //\r
1306 // If this is the DXE core fill in it's DevicePath & DeviceHandle\r
1307 //\r
1308 if (gDxeCoreLoadedImage->FilePath == NULL) {\r
1309 if (CompareGuid (&NameGuid, gDxeCoreFileName)) {\r
1310 //\r
1311 // Maybe One specail Fv cantains only one DXE_CORE module, so its device path must\r
1312 // be initialized completely.\r
1313 //\r
1314 EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid);\r
1315 SetDevicePathEndNode (&mFvDevicePath.End);\r
1316\r
1317 gDxeCoreLoadedImage->FilePath = DuplicateDevicePath (\r
1318 (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath\r
1319 );\r
1320 gDxeCoreLoadedImage->DeviceHandle = FvHandle;\r
1321 }\r
1322 }\r
1323 } else if (Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {\r
1324 //\r
1325 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already\r
1326 // been extracted.\r
1327 //\r
1328 if (FvFoundInHobFv2 (&KnownHandle->FvNameGuid, &NameGuid)) {\r
1329 continue;\r
1330 }\r
1331\r
1332 //\r
1333 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has SMM depex section.\r
1334 //\r
1335 DepexBuffer = NULL;\r
1336 SizeOfBuffer = 0;\r
1337 Status = Fv->ReadSection (\r
1338 Fv,\r
1339 &NameGuid,\r
1340 EFI_SECTION_SMM_DEPEX,\r
1341 0,\r
1342 &DepexBuffer,\r
1343 &SizeOfBuffer,\r
1344 &AuthenticationStatus\r
1345 );\r
1346 if (!EFI_ERROR (Status)) {\r
1347 //\r
1348 // If SMM depex section is found, this FV image is invalid to be supported.\r
1349 // ASSERT FALSE to report this FV image.\r
1350 //\r
1351 FreePool (DepexBuffer);\r
1352 ASSERT (FALSE);\r
1353 }\r
1354\r
1355 //\r
1356 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has DXE depex section.\r
1357 //\r
1358 DepexBuffer = NULL;\r
1359 SizeOfBuffer = 0;\r
1360 Status = Fv->ReadSection (\r
1361 Fv,\r
1362 &NameGuid,\r
1363 EFI_SECTION_DXE_DEPEX,\r
1364 0,\r
1365 &DepexBuffer,\r
1366 &SizeOfBuffer,\r
1367 &AuthenticationStatus\r
1368 );\r
1369 if (EFI_ERROR (Status)) {\r
1370 //\r
1371 // If no depex section, produce a firmware volume block protocol for it so it gets dispatched from.\r
1372 //\r
1373 CoreProcessFvImageFile (Fv, FvHandle, &NameGuid);\r
1374 } else {\r
1375 //\r
1376 // If depex section is found, this FV image will be dispatched until its depex is evaluated to TRUE.\r
1377 //\r
1378 FreePool (DepexBuffer);\r
1379 CoreAddToDriverList (Fv, FvHandle, &NameGuid, Type);\r
1380 }\r
1381 } else {\r
1382 //\r
1383 // Transition driver from Undiscovered to Discovered state\r
1384 //\r
1385 CoreAddToDriverList (Fv, FvHandle, &NameGuid, Type);\r
1386 }\r
1387 }\r
1388 } while (!EFI_ERROR (GetNextFileStatus));\r
1389 }\r
1390\r
1391 //\r
1392 // Read the array of GUIDs from the Apriori file if it is present in the firmware volume\r
1393 //\r
1394 AprioriFile = NULL;\r
1395 Status = Fv->ReadSection (\r
1396 Fv,\r
1397 &gAprioriGuid,\r
1398 EFI_SECTION_RAW,\r
1399 0,\r
1400 (VOID **)&AprioriFile,\r
1401 &SizeOfBuffer,\r
1402 &AuthenticationStatus\r
1403 );\r
1404 if (!EFI_ERROR (Status)) {\r
1405 AprioriEntryCount = SizeOfBuffer / sizeof (EFI_GUID);\r
1406 } else {\r
1407 AprioriEntryCount = 0;\r
1408 }\r
1409\r
1410 //\r
1411 // Put drivers on Apriori List on the Scheduled queue. The Discovered List includes\r
1412 // drivers not in the current FV and these must be skipped since the a priori list\r
1413 // is only valid for the FV that it resided in.\r
1414 //\r
1415\r
1416 for (Index = 0; Index < AprioriEntryCount; Index++) {\r
1417 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {\r
1418 DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);\r
1419 if (CompareGuid (&DriverEntry->FileName, &AprioriFile[Index]) &&\r
1420 (FvHandle == DriverEntry->FvHandle)) {\r
1421 CoreAcquireDispatcherLock ();\r
1422 DriverEntry->Dependent = FALSE;\r
1423 DriverEntry->Scheduled = TRUE;\r
1424 InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);\r
1425 CoreReleaseDispatcherLock ();\r
1426 DEBUG ((DEBUG_DISPATCH, "Evaluate DXE DEPEX for FFS(%g)\n", &DriverEntry->FileName));\r
1427 DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (Apriori)\n"));\r
1428 break;\r
1429 }\r
1430 }\r
1431 }\r
1432\r
1433 //\r
1434 // Free data allocated by Fv->ReadSection ()\r
1435 //\r
1436 CoreFreePool (AprioriFile);\r
1437 }\r
1438}\r
1439\r
1440\r
1441\r
1442/**\r
1443 Initialize the dispatcher. Initialize the notification function that runs when\r
1444 an FV2 protocol is added to the system.\r
1445\r
1446**/\r
1447VOID\r
1448CoreInitializeDispatcher (\r
1449 VOID\r
1450 )\r
1451{\r
1452 PERF_FUNCTION_BEGIN ();\r
1453\r
1454 mFwVolEvent = EfiCreateProtocolNotifyEvent (\r
1455 &gEfiFirmwareVolume2ProtocolGuid,\r
1456 TPL_CALLBACK,\r
1457 CoreFwVolEventProtocolNotify,\r
1458 NULL,\r
1459 &mFwVolEventRegistration\r
1460 );\r
1461\r
1462 PERF_FUNCTION_END ();\r
1463}\r
1464\r
1465//\r
1466// Function only used in debug builds\r
1467//\r
1468\r
1469/**\r
1470 Traverse the discovered list for any drivers that were discovered but not loaded\r
1471 because the dependency experessions evaluated to false.\r
1472\r
1473**/\r
1474VOID\r
1475CoreDisplayDiscoveredNotDispatched (\r
1476 VOID\r
1477 )\r
1478{\r
1479 LIST_ENTRY *Link;\r
1480 EFI_CORE_DRIVER_ENTRY *DriverEntry;\r
1481\r
1482 for (Link = mDiscoveredList.ForwardLink;Link !=&mDiscoveredList; Link = Link->ForwardLink) {\r
1483 DriverEntry = CR(Link, EFI_CORE_DRIVER_ENTRY, Link, EFI_CORE_DRIVER_ENTRY_SIGNATURE);\r
1484 if (DriverEntry->Dependent) {\r
1485 DEBUG ((DEBUG_LOAD, "Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName));\r
1486 }\r
1487 }\r
1488}\r