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