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