]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Core/Dxe/Dispatcher/Dispatcher.c
MdeModulePkg: Change use of EFI_D_* to DEBUG_*
[mirror_edk2.git] / MdeModulePkg / Core / Dxe / Dispatcher / Dispatcher.c
CommitLineData
162ed594 1/** @file\r
797a9d67 2 DXE Dispatcher.\r
28a00297 3\r
4 Step #1 - When a FV protocol is added to the system every driver in the FV\r
022c6d45 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
28a00297 9 FV is only processed once.\r
10\r
11 Step #2 - Dispatch. Remove driver from the mScheduledQueue and load and\r
022c6d45 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
28a00297 14 be placed on the mScheduledQueue.\r
15\r
022c6d45 16 Step #3 - Adding to the mScheduledQueue requires that you process Before\r
28a00297 17 and After dependencies. This is done recursively as the call to add\r
022c6d45 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
28a00297 20 processess the After dependecies by recursively calling the routine.\r
21\r
22 Dispatcher Rules:\r
022c6d45 23 The rules for the dispatcher are in chapter 10 of the DXE CIS. Figure 10-3\r
28a00297 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
d1102dba 29Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
9d510e61 30SPDX-License-Identifier: BSD-2-Clause-Patent\r
797a9d67 31\r
32**/\r
28a00297 33\r
9c4ac31c 34#include "DxeMain.h"\r
28a00297 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
022c6d45 40LIST_ENTRY mDiscoveredList = INITIALIZE_LIST_HEAD_VARIABLE (mDiscoveredList);\r
28a00297 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
022c6d45 73EFI_FV_FILETYPE mDxeFileTypes[] = {\r
74 EFI_FV_FILETYPE_DRIVER,\r
202c3279 75 EFI_FV_FILETYPE_COMBINED_SMM_DXE,\r
022c6d45 76 EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,\r
28a00297 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
e407ceec
LG
86FV_FILEPATH_DEVICE_PATH mFvDevicePath;\r
87\r
28a00297 88//\r
89// Function Prototypes\r
90//\r
162ed594 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
28a00297 102VOID\r
103CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (\r
104 IN EFI_CORE_DRIVER_ENTRY *InsertedDriverEntry\r
105 );\r
022c6d45 106\r
162ed594 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
022c6d45 120 @param Event The Event that is being processed, not used.\r
162ed594 121 @param Context Event Context, not used.\r
122\r
123**/\r
28a00297 124VOID\r
125EFIAPI\r
126CoreFwVolEventProtocolNotify (\r
127 IN EFI_EVENT Event,\r
128 IN VOID *Context\r
129 );\r
130\r
162ed594 131/**\r
022c6d45 132 Convert FvHandle and DriverName into an EFI device path\r
162ed594 133\r
022c6d45 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
162ed594 140\r
141 @return Pointer to device path constructed from FvHandle and DriverName\r
142\r
143**/\r
28a00297 144EFI_DEVICE_PATH_PROTOCOL *\r
145CoreFvToDevicePath (\r
0c2b5da8 146 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,\r
28a00297 147 IN EFI_HANDLE FvHandle,\r
148 IN EFI_GUID *DriverName\r
149 );\r
150\r
162ed594 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
022c6d45 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
d3592549 164 @param Type Fv File Type of file to add to mDiscoveredList.\r
162ed594 165\r
022c6d45 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
162ed594 169 time.\r
170\r
171**/\r
28a00297 172EFI_STATUS\r
173CoreAddToDriverList (\r
23c98c94 174 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,\r
175 IN EFI_HANDLE FvHandle,\r
d3592549
LG
176 IN EFI_GUID *DriverName,\r
177 IN EFI_FV_FILETYPE Type\r
28a00297 178 );\r
179\r
162ed594 180/**\r
e3b9ab43 181 Get Fv image(s) from the FV through file name, and produce FVB protocol for every Fv image(s).\r
162ed594 182\r
022c6d45 183 @param Fv The FIRMWARE_VOLUME protocol installed on the FV.\r
184 @param FvHandle The handle which FVB protocol installed on.\r
e3b9ab43 185 @param FileName The file name guid specified.\r
162ed594 186\r
022c6d45 187 @retval EFI_OUT_OF_RESOURCES No enough memory or other resource.\r
162ed594 188 @retval EFI_SUCCESS Function successfully returned.\r
189\r
190**/\r
022c6d45 191EFI_STATUS\r
28a00297 192CoreProcessFvImageFile (\r
0c2b5da8 193 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,\r
28a00297 194 IN EFI_HANDLE FvHandle,\r
e3b9ab43 195 IN EFI_GUID *FileName\r
28a00297 196 );\r
197\r
162ed594 198\r
199/**\r
200 Enter critical section by gaining lock on mDispatcherLock.\r
201\r
202**/\r
28a00297 203VOID\r
204CoreAcquireDispatcherLock (\r
205 VOID\r
206 )\r
28a00297 207{\r
208 CoreAcquireLock (&mDispatcherLock);\r
209}\r
210\r
162ed594 211\r
212/**\r
213 Exit critical section by releasing lock on mDispatcherLock.\r
214\r
215**/\r
28a00297 216VOID\r
217CoreReleaseDispatcherLock (\r
218 VOID\r
219 )\r
28a00297 220{\r
221 CoreReleaseLock (&mDispatcherLock);\r
222}\r
223\r
28a00297 224\r
162ed594 225/**\r
28a00297 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
022c6d45 229 @param DriverEntry Driver to work on.\r
28a00297 230\r
022c6d45 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
162ed594 234 @retval Error DEPEX not found.\r
28a00297 235\r
162ed594 236**/\r
162ed594 237EFI_STATUS\r
238CoreGetDepexSectionAndPreProccess (\r
239 IN EFI_CORE_DRIVER_ENTRY *DriverEntry\r
240 )\r
28a00297 241{\r
242 EFI_STATUS Status;\r
243 EFI_SECTION_TYPE SectionType;\r
244 UINT32 AuthenticationStatus;\r
0c2b5da8 245 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
28a00297 246\r
022c6d45 247\r
28a00297 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
022c6d45 255 DriverEntry->Fv,\r
28a00297 256 &DriverEntry->FileName,\r
022c6d45 257 SectionType,\r
258 0,\r
259 &DriverEntry->Depex,\r
28a00297 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
8a7d75b0 271 // If no Depex assume UEFI 2.0 driver model\r
28a00297 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
022c6d45 284 }\r
28a00297 285\r
286 return Status;\r
287}\r
288\r
162ed594 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
022c6d45 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
162ed594 297\r
022c6d45 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
162ed594 302\r
303**/\r
28a00297 304EFI_STATUS\r
305EFIAPI\r
306CoreSchedule (\r
307 IN EFI_HANDLE FirmwareVolumeHandle,\r
308 IN EFI_GUID *DriverName\r
309 )\r
28a00297 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
022c6d45 320 DriverEntry->Unrequested &&\r
28a00297 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
022c6d45 329\r
6a55eea3 330 DEBUG ((DEBUG_DISPATCH, "Schedule FFS(%g) - EFI_SUCCESS\n", DriverName));\r
d1102dba 331\r
28a00297 332 return EFI_SUCCESS;\r
333 }\r
334 }\r
d1102dba 335\r
6a55eea3 336 DEBUG ((DEBUG_DISPATCH, "Schedule FFS(%g) - EFI_NOT_FOUND\n", DriverName));\r
d1102dba 337\r
022c6d45 338 return EFI_NOT_FOUND;\r
28a00297 339}\r
340\r
341\r
162ed594 342\r
343/**\r
e94a9ff7 344 Convert a driver from the Untrused back to the Scheduled state.\r
162ed594 345\r
022c6d45 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
162ed594 349\r
022c6d45 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
162ed594 353\r
354**/\r
28a00297 355EFI_STATUS\r
356EFIAPI\r
357CoreTrust (\r
358 IN EFI_HANDLE FirmwareVolumeHandle,\r
359 IN EFI_GUID *DriverName\r
360 )\r
28a00297 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
022c6d45 371 DriverEntry->Untrusted &&\r
28a00297 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
022c6d45 381\r
28a00297 382 return EFI_SUCCESS;\r
383 }\r
384 }\r
022c6d45 385 return EFI_NOT_FOUND;\r
28a00297 386}\r
387\r
162ed594 388/**\r
389 This is the main Dispatcher for DXE and it exits when there are no more\r
28a00297 390 drivers to run. Drain the mScheduledQueue and load and start a PE\r
162ed594 391 image for each driver. Search the mDiscoveredList to see if any driver can\r
28a00297 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
162ed594 394 will be called, and when the Bds() exits the Dispatcher will be called\r
28a00297 395 again.\r
396\r
022c6d45 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
28a00297 400\r
162ed594 401**/\r
162ed594 402EFI_STATUS\r
403EFIAPI\r
404CoreDispatcher (\r
405 VOID\r
406 )\r
28a00297 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
202c3279 413 EFI_EVENT DxeDispatchEvent;\r
d1102dba 414\r
67e9ab84 415 PERF_FUNCTION_BEGIN ();\r
28a00297 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
202c3279 426 Status = CoreCreateEventEx (\r
427 EVT_NOTIFY_SIGNAL,\r
428 TPL_NOTIFY,\r
ac72474d 429 EfiEventEmptyFunction,\r
202c3279 430 NULL,\r
431 &gEfiEventDxeDispatchGuid,\r
432 &DxeDispatchEvent\r
433 );\r
434 if (EFI_ERROR (Status)) {\r
435 return Status;\r
436 }\r
28a00297 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
d3592549 456 if (DriverEntry->ImageHandle == NULL && !DriverEntry->IsFvImage) {\r
94903510 457 DEBUG ((DEBUG_INFO, "Loading driver %g\n", &DriverEntry->FileName));\r
28a00297 458 Status = CoreLoadImage (\r
022c6d45 459 FALSE,\r
460 gDxeCoreImageHandle,\r
28a00297 461 DriverEntry->FvFileDevicePath,\r
022c6d45 462 NULL,\r
463 0,\r
28a00297 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
022c6d45 481 // Take driver from Scheduled to Initialized.\r
28a00297 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
022c6d45 490\r
28a00297 491 CoreReleaseDispatcherLock ();\r
022c6d45 492\r
28a00297 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
022c6d45 505\r
28a00297 506 CoreReleaseDispatcherLock ();\r
507\r
d1102dba 508\r
d3592549
LG
509 if (DriverEntry->IsFvImage) {\r
510 //\r
d1102dba 511 // Produce a firmware volume block protocol for FvImage so it gets dispatched from.\r
d3592549
LG
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
328ce03e 521 ASSERT (DriverEntry->ImageHandle != NULL);\r
d1102dba 522\r
d3592549 523 Status = CoreStartImage (DriverEntry->ImageHandle, NULL, NULL);\r
d1102dba 524\r
d3592549
LG
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
28a00297 532\r
533 ReturnStatus = EFI_SUCCESS;\r
534 }\r
535\r
0e4483bc
LG
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
28a00297 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
022c6d45 557 }\r
28a00297 558\r
559 if (DriverEntry->Dependent) {\r
560 if (CoreIsSchedulable (DriverEntry)) {\r
022c6d45 561 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);\r
28a00297 562 ReadyToRun = TRUE;\r
022c6d45 563 }\r
6a55eea3 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
28a00297 570 }\r
571 }\r
572 } while (ReadyToRun);\r
573\r
202c3279 574 //\r
575 // Close DXE dispatch Event\r
576 //\r
577 CoreCloseEvent (DxeDispatchEvent);\r
578\r
28a00297 579 gDispatcherRunning = FALSE;\r
580\r
67e9ab84
BD
581 PERF_FUNCTION_END ();\r
582\r
28a00297 583 return ReturnStatus;\r
584}\r
585\r
28a00297 586\r
162ed594 587/**\r
588 Insert InsertedDriverEntry onto the mScheduledQueue. To do this you\r
28a00297 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
162ed594 591 processed you can add InsertedDriverEntry to the mScheduledQueue.\r
592 Then you can add any driver with an After dependency on InsertedDriverEntry\r
28a00297 593 by recursively calling this routine.\r
594\r
162ed594 595 @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue\r
28a00297 596\r
162ed594 597**/\r
162ed594 598VOID\r
599CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (\r
600 IN EFI_CORE_DRIVER_ENTRY *InsertedDriverEntry\r
601 )\r
28a00297 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
6a55eea3 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
28a00297 614 if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {\r
615 //\r
616 // Recursively process BEFORE\r
617 //\r
6a55eea3 618 DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n"));\r
28a00297 619 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);\r
6a55eea3 620 } else {\r
621 DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));\r
28a00297 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
022c6d45 634\r
28a00297 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
6a55eea3 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
28a00297 645 if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {\r
646 //\r
647 // Recursively process AFTER\r
648 //\r
6a55eea3 649 DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n"));\r
28a00297 650 CoreInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);\r
6a55eea3 651 } else {\r
652 DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));\r
28a00297 653 }\r
654 }\r
655 }\r
656}\r
657\r
28a00297 658\r
162ed594 659/**\r
28a00297 660 Return TRUE if the Fv has been processed, FALSE if not.\r
661\r
022c6d45 662 @param FvHandle The handle of a FV that's being tested\r
28a00297 663\r
022c6d45 664 @retval TRUE Fv protocol on FvHandle has been processed\r
e94a9ff7 665 @retval FALSE Fv protocol on FvHandle has not yet been processed\r
28a00297 666\r
162ed594 667**/\r
162ed594 668BOOLEAN\r
669FvHasBeenProcessed (\r
670 IN EFI_HANDLE FvHandle\r
671 )\r
28a00297 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
28a00297 685\r
162ed594 686/**\r
28a00297 687 Remember that Fv protocol on FvHandle has had it's drivers placed on the\r
d1102dba 688 mDiscoveredList. This fucntion adds entries on the mFvHandleList if new\r
2fc46f86
LG
689 entry is different from one in mFvHandleList by checking FvImage Guid.\r
690 Items are never removed/freed from the mFvHandleList.\r
28a00297 691\r
162ed594 692 @param FvHandle The handle of a FV that has been processed\r
28a00297 693\r
2fc46f86 694 @return A point to new added FvHandle entry. If FvHandle with the same FvImage guid\r
d1102dba 695 has been added, NULL will return.\r
2fc46f86 696\r
162ed594 697**/\r
d1102dba 698KNOWN_HANDLE *\r
b0570b48 699FvIsBeingProcessed (\r
162ed594 700 IN EFI_HANDLE FvHandle\r
701 )\r
28a00297 702{\r
2fc46f86
LG
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
ac30bca0
SZ
716 FwVolHeader = NULL;\r
717\r
2fc46f86
LG
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
bdc9d5a5 727 ASSERT (Fvb != NULL);\r
2fc46f86 728 Status = GetFwVolHeader (Fvb, &FwVolHeader);\r
bdc9d5a5
LG
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
2fc46f86
LG
752 }\r
753 //\r
bdc9d5a5 754 // Read FvNameGuid from FV extension header.\r
2fc46f86 755 //\r
bdc9d5a5
LG
756 Status = ReadFvbData (Fvb, &LbaIndex, &LbaOffset, sizeof (FvNameGuid), (UINT8 *) &FvNameGuid);\r
757 if (!EFI_ERROR (Status)) {\r
758 FvNameGuidIsFound = TRUE;\r
2fc46f86 759 }\r
2fc46f86 760 }\r
bdc9d5a5 761 CoreFreePool (FwVolHeader);\r
2fc46f86 762 }\r
2fc46f86
LG
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
87000d77 772 DEBUG ((DEBUG_ERROR, "FvImage on FvHandle %p and %p has the same FvNameGuid %g.\n", FvHandle, KnownHandle->Handle, &FvNameGuid));\r
2fc46f86
LG
773 return NULL;\r
774 }\r
775 }\r
776 }\r
28a00297 777\r
2fc46f86 778 KnownHandle = AllocateZeroPool (sizeof (KNOWN_HANDLE));\r
28a00297 779 ASSERT (KnownHandle != NULL);\r
780\r
781 KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE;\r
782 KnownHandle->Handle = FvHandle;\r
2fc46f86
LG
783 if (FvNameGuidIsFound) {\r
784 CopyGuid (&KnownHandle->FvNameGuid, &FvNameGuid);\r
785 }\r
28a00297 786 InsertTailList (&mFvHandleList, &KnownHandle->Link);\r
2fc46f86 787 return KnownHandle;\r
28a00297 788}\r
789\r
790\r
791\r
162ed594 792\r
793/**\r
794 Convert FvHandle and DriverName into an EFI device path\r
795\r
022c6d45 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
162ed594 802\r
803 @return Pointer to device path constructed from FvHandle and DriverName\r
804\r
805**/\r
28a00297 806EFI_DEVICE_PATH_PROTOCOL *\r
807CoreFvToDevicePath (\r
0c2b5da8 808 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,\r
28a00297 809 IN EFI_HANDLE FvHandle,\r
810 IN EFI_GUID *DriverName\r
811 )\r
28a00297 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
1232b214 828 SetDevicePathEndNode (&mFvDevicePath.End);\r
28a00297 829\r
9c4ac31c 830 FileNameDevicePath = AppendDevicePath (\r
022c6d45 831 FvDevicePath,\r
28a00297 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
162ed594 841/**\r
842 Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,\r
28a00297 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
022c6d45 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
d3592549 854 @param Type Fv File Type of file to add to mDiscoveredList.\r
28a00297 855\r
022c6d45 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
162ed594 859 time.\r
28a00297 860\r
162ed594 861**/\r
862EFI_STATUS\r
863CoreAddToDriverList (\r
864 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,\r
865 IN EFI_HANDLE FvHandle,\r
d3592549
LG
866 IN EFI_GUID *DriverName,\r
867 IN EFI_FV_FILETYPE Type\r
162ed594 868 )\r
28a00297 869{\r
870 EFI_CORE_DRIVER_ENTRY *DriverEntry;\r
871\r
022c6d45 872\r
28a00297 873 //\r
022c6d45 874 // Create the Driver Entry for the list. ZeroPool initializes lots of variables to\r
28a00297 875 // NULL or FALSE.\r
876 //\r
9c4ac31c 877 DriverEntry = AllocateZeroPool (sizeof (EFI_CORE_DRIVER_ENTRY));\r
28a00297 878 ASSERT (DriverEntry != NULL);\r
d3592549
LG
879 if (Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {\r
880 DriverEntry->IsFvImage = TRUE;\r
881 }\r
28a00297 882\r
883 DriverEntry->Signature = EFI_CORE_DRIVER_ENTRY_SIGNATURE;\r
e94a9ff7 884 CopyGuid (&DriverEntry->FileName, DriverName);\r
28a00297 885 DriverEntry->FvHandle = FvHandle;\r
886 DriverEntry->Fv = Fv;\r
887 DriverEntry->FvFileDevicePath = CoreFvToDevicePath (Fv, FvHandle, DriverName);\r
888\r
889 CoreGetDepexSectionAndPreProccess (DriverEntry);\r
022c6d45 890\r
28a00297 891 CoreAcquireDispatcherLock ();\r
022c6d45 892\r
28a00297 893 InsertTailList (&mDiscoveredList, &DriverEntry->Link);\r
894\r
895 CoreReleaseDispatcherLock ();\r
896\r
897 return EFI_SUCCESS;\r
898}\r
899\r
bbc0f1bb 900\r
162ed594 901/**\r
bbc0f1bb 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
2fc46f86 905 @param FvNameGuid The FV image guid specified.\r
022c6d45 906 @param DriverName The driver guid specified.\r
bbc0f1bb 907\r
022c6d45 908 @retval TRUE This file is found in a EFI_HOB_FIRMWARE_VOLUME2\r
909 Hob.\r
162ed594 910 @retval FALSE Not found.\r
bbc0f1bb 911\r
162ed594 912**/\r
162ed594 913BOOLEAN\r
914FvFoundInHobFv2 (\r
2fc46f86 915 IN CONST EFI_GUID *FvNameGuid,\r
162ed594 916 IN CONST EFI_GUID *DriverName\r
917 )\r
bbc0f1bb 918{\r
919 EFI_PEI_HOB_POINTERS HobFv2;\r
022c6d45 920\r
bbc0f1bb 921 HobFv2.Raw = GetHobList ();\r
022c6d45 922\r
bbc0f1bb 923 while ((HobFv2.Raw = GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) != NULL) {\r
2fc46f86
LG
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
b0d803fe 929 return TRUE;\r
bbc0f1bb 930 }\r
931 HobFv2.Raw = GET_NEXT_HOB (HobFv2);\r
932 }\r
933\r
934 return FALSE;\r
935}\r
28a00297 936\r
a82e52b3
SZ
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
28a00297 992\r
a82e52b3
SZ
993 //\r
994 // No USED_SIZE FV_EXT_TYPE entry found.\r
995 //\r
996 return FALSE;\r
997}\r
162ed594 998\r
999/**\r
e3b9ab43 1000 Get Fv image(s) from the FV through file name, and produce FVB protocol for every Fv image(s).\r
162ed594 1001\r
022c6d45 1002 @param Fv The FIRMWARE_VOLUME protocol installed on the FV.\r
1003 @param FvHandle The handle which FVB protocol installed on.\r
e3b9ab43 1004 @param FileName The file name guid specified.\r
162ed594 1005\r
022c6d45 1006 @retval EFI_OUT_OF_RESOURCES No enough memory or other resource.\r
162ed594 1007 @retval EFI_SUCCESS Function successfully returned.\r
1008\r
1009**/\r
022c6d45 1010EFI_STATUS\r
28a00297 1011CoreProcessFvImageFile (\r
0c2b5da8 1012 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,\r
28a00297 1013 IN EFI_HANDLE FvHandle,\r
e3b9ab43 1014 IN EFI_GUID *FileName\r
28a00297 1015 )\r
28a00297 1016{\r
1017 EFI_STATUS Status;\r
1018 EFI_SECTION_TYPE SectionType;\r
1019 UINT32 AuthenticationStatus;\r
1020 VOID *Buffer;\r
38837959 1021 VOID *AlignedBuffer;\r
28a00297 1022 UINTN BufferSize;\r
38837959 1023 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
022c6d45 1024 UINT32 FvAlignment;\r
022ff6bb 1025 EFI_DEVICE_PATH_PROTOCOL *FvFileDevicePath;\r
a82e52b3
SZ
1026 UINT32 FvUsedSize;\r
1027 UINT8 EraseByte;\r
e3b9ab43 1028 UINTN Index;\r
28a00297 1029\r
1030 //\r
e3b9ab43 1031 // Read firmware volume section(s)\r
28a00297 1032 //\r
e94a9ff7 1033 SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;\r
022ff6bb 1034\r
e3b9ab43
SZ
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
022ff6bb 1075 }\r
022ff6bb 1076 }\r
022ff6bb 1077\r
38837959 1078 //\r
e3b9ab43 1079 // FvImage should be at its required alignment.\r
38837959 1080 //\r
e3b9ab43 1081 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) Buffer;\r
38837959 1082 //\r
e3b9ab43
SZ
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
38837959 1086 //\r
e3b9ab43
SZ
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
5d0b4eb4 1098\r
e3b9ab43
SZ
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
a82e52b3 1106\r
3837e91c 1107 //\r
e3b9ab43 1108 // Check FvImage alignment.\r
3837e91c 1109 //\r
e3b9ab43 1110 if ((UINTN) FvHeader % FvAlignment != 0) {\r
5d0b4eb4 1111 //\r
e3b9ab43 1112 // Allocate the aligned buffer for the FvImage.\r
5d0b4eb4 1113 //\r
e3b9ab43
SZ
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
a82e52b3 1120 //\r
e3b9ab43 1121 // Move FvImage into the aligned buffer and release the original buffer.\r
a82e52b3 1122 //\r
e3b9ab43
SZ
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
a82e52b3 1139 }\r
5d0b4eb4 1140 }\r
3837e91c 1141 }\r
e3b9ab43
SZ
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
38837959 1152 }\r
28a00297 1153\r
e3b9ab43
SZ
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
022c6d45 1165\r
e3b9ab43
SZ
1166 break;\r
1167 } else {\r
1168 Index++;\r
38837959 1169 }\r
e3b9ab43 1170 } while (TRUE);\r
28a00297 1171\r
e3b9ab43
SZ
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
28a00297 1180}\r
1181\r
28a00297 1182\r
162ed594 1183/**\r
1184 Event notification that is fired every time a FV dispatch protocol is added.\r
28a00297 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
162ed594 1188 If the Fv has already been processed, skip it. If the Fv has not been\r
28a00297 1189 processed then mark it as being processed, as we are about to process it.\r
162ed594 1190 Read the Fv and add any driver in the Fv to the mDiscoveredList.The\r
28a00297 1191 mDiscoveredList is never free'ed and contains variables that define\r
162ed594 1192 the other states the DXE driver transitions to..\r
28a00297 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
022c6d45 1196 @param Event The Event that is being processed, not used.\r
162ed594 1197 @param Context Event Context, not used.\r
28a00297 1198\r
162ed594 1199**/\r
162ed594 1200VOID\r
1201EFIAPI\r
1202CoreFwVolEventProtocolNotify (\r
1203 IN EFI_EVENT Event,\r
1204 IN VOID *Context\r
1205 )\r
28a00297 1206{\r
1207 EFI_STATUS Status;\r
1208 EFI_STATUS GetNextFileStatus;\r
0c2b5da8 1209 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;\r
28a00297 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
d3592549 1225 VOID *DepexBuffer;\r
2fc46f86 1226 KNOWN_HANDLE *KnownHandle;\r
28a00297 1227\r
4e1005ec
ED
1228 FvHandle = NULL;\r
1229\r
28a00297 1230 while (TRUE) {\r
1231 BufferSize = sizeof (EFI_HANDLE);\r
1232 Status = CoreLocateHandle (\r
e94a9ff7 1233 ByRegisterNotify,\r
1234 NULL,\r
1235 mFwVolEventRegistration,\r
1236 &BufferSize,\r
1237 &FvHandle\r
1238 );\r
28a00297 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
28a00297 1253 //\r
1254 // Since we are about to process this Fv mark it as processed.\r
1255 //\r
b0570b48 1256 KnownHandle = FvIsBeingProcessed (FvHandle);\r
2fc46f86
LG
1257 if (KnownHandle == NULL) {\r
1258 //\r
d1102dba 1259 // The FV with the same FV name guid has already been processed.\r
2fc46f86
LG
1260 // So lets skip it!\r
1261 //\r
1262 continue;\r
1263 }\r
28a00297 1264\r
0c2b5da8 1265 Status = CoreHandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);\r
d2fbaaab 1266 if (EFI_ERROR (Status) || Fv == NULL) {\r
28a00297 1267 //\r
cd539d48 1268 // FvHandle must have Firmware Volume2 protocol thus we should never get here.\r
28a00297 1269 //\r
1270 ASSERT (FALSE);\r
1271 continue;\r
1272 }\r
022c6d45 1273\r
28a00297 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
022c6d45 1281\r
28a00297 1282 //\r
022c6d45 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
28a00297 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
e94a9ff7 1288 for (Index = 0; Index < sizeof (mDxeFileTypes) / sizeof (EFI_FV_FILETYPE); Index++) {\r
28a00297 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
022c6d45 1296 Fv,\r
28a00297 1297 &Key,\r
022c6d45 1298 &Type,\r
1299 &NameGuid,\r
1300 &Attributes,\r
28a00297 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
1232b214 1315 SetDevicePathEndNode (&mFvDevicePath.End);\r
28a00297 1316\r
9c4ac31c 1317 gDxeCoreLoadedImage->FilePath = DuplicateDevicePath (\r
28a00297 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
bbc0f1bb 1324 //\r
022c6d45 1325 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already\r
bbc0f1bb 1326 // been extracted.\r
1327 //\r
2fc46f86 1328 if (FvFoundInHobFv2 (&KnownHandle->FvNameGuid, &NameGuid)) {\r
bbc0f1bb 1329 continue;\r
1330 }\r
d3592549 1331\r
28a00297 1332 //\r
d3592549 1333 // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has SMM depex section.\r
28a00297 1334 //\r
d3592549
LG
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
c74a25f0 1348 // If SMM depex section is found, this FV image is invalid to be supported.\r
d1102dba 1349 // ASSERT FALSE to report this FV image.\r
d3592549
LG
1350 //\r
1351 FreePool (DepexBuffer);\r
c74a25f0 1352 ASSERT (FALSE);\r
d3592549
LG
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
d1102dba 1371 // If no depex section, produce a firmware volume block protocol for it so it gets dispatched from.\r
d3592549
LG
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
28a00297 1381 } else {\r
1382 //\r
1383 // Transition driver from Undiscovered to Discovered state\r
1384 //\r
d3592549 1385 CoreAddToDriverList (Fv, FvHandle, &NameGuid, Type);\r
28a00297 1386 }\r
1387 }\r
1388 } while (!EFI_ERROR (GetNextFileStatus));\r
1389 }\r
022c6d45 1390\r
28a00297 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
022c6d45 1415\r
28a00297 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
6a55eea3 1421 CoreAcquireDispatcherLock ();\r
28a00297 1422 DriverEntry->Dependent = FALSE;\r
1423 DriverEntry->Scheduled = TRUE;\r
1424 InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);\r
6a55eea3 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
28a00297 1428 break;\r
1429 }\r
1430 }\r
1431 }\r
1432\r
28a00297 1433 //\r
022c6d45 1434 // Free data allocated by Fv->ReadSection ()\r
28a00297 1435 //\r
022c6d45 1436 CoreFreePool (AprioriFile);\r
28a00297 1437 }\r
1438}\r
1439\r
1440\r
28a00297 1441\r
162ed594 1442/**\r
28a00297 1443 Initialize the dispatcher. Initialize the notification function that runs when\r
e94a9ff7 1444 an FV2 protocol is added to the system.\r
28a00297 1445\r
162ed594 1446**/\r
1447VOID\r
1448CoreInitializeDispatcher (\r
1449 VOID\r
1450 )\r
28a00297 1451{\r
67e9ab84
BD
1452 PERF_FUNCTION_BEGIN ();\r
1453\r
7899b797 1454 mFwVolEvent = EfiCreateProtocolNotifyEvent (\r
022c6d45 1455 &gEfiFirmwareVolume2ProtocolGuid,\r
28a00297 1456 TPL_CALLBACK,\r
1457 CoreFwVolEventProtocolNotify,\r
1458 NULL,\r
7899b797 1459 &mFwVolEventRegistration\r
28a00297 1460 );\r
67e9ab84
BD
1461\r
1462 PERF_FUNCTION_END ();\r
28a00297 1463}\r
1464\r
1465//\r
1466// Function only used in debug builds\r
1467//\r
162ed594 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
28a00297 1474VOID\r
1475CoreDisplayDiscoveredNotDispatched (\r
1476 VOID\r
1477 )\r
28a00297 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
162ed594 1485 DEBUG ((DEBUG_LOAD, "Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName));\r
28a00297 1486 }\r
1487 }\r
1488}\r