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