| 1 | /*++\r |
| 2 | \r |
| 3 | Copyright (c) 2006, Intel Corporation \r |
| 4 | All rights reserved. This program and the accompanying materials \r |
| 5 | are licensed and made available under the terms and conditions of the BSD License \r |
| 6 | which accompanies this distribution. The full text of the license may be found at \r |
| 7 | http://opensource.org/licenses/bsd-license.php \r |
| 8 | \r |
| 9 | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r |
| 10 | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r |
| 11 | \r |
| 12 | Module Name:\r |
| 13 | \r |
| 14 | DxeLoad.c\r |
| 15 | \r |
| 16 | Abstract:\r |
| 17 | \r |
| 18 | Last PEIM.\r |
| 19 | Responsibility of this module is to load the DXE Core from a Firmware Volume.\r |
| 20 | \r |
| 21 | --*/\r |
| 22 | \r |
| 23 | #include <DxeIpl.h>\r |
| 24 | \r |
| 25 | #pragma warning( disable : 4305 )\r |
| 26 | \r |
| 27 | BOOLEAN gInMemory = FALSE;\r |
| 28 | \r |
| 29 | //\r |
| 30 | // GUID for EM64T\r |
| 31 | //\r |
| 32 | #define EFI_PPI_NEEDED_BY_DXE \\r |
| 33 | { \\r |
| 34 | 0x4d37da42, 0x3a0c, 0x4eda, 0xb9, 0xeb, 0xbc, 0x0e, 0x1d, 0xb4, 0x71, 0x3b \\r |
| 35 | }\r |
| 36 | EFI_GUID mPpiNeededByDxeGuid = EFI_PPI_NEEDED_BY_DXE;\r |
| 37 | \r |
| 38 | //\r |
| 39 | // Module Globals used in the DXE to PEI handoff\r |
| 40 | // These must be module globals, so the stack can be switched\r |
| 41 | //\r |
| 42 | static EFI_DXE_IPL_PPI mDxeIplPpi = {\r |
| 43 | DxeLoadCore\r |
| 44 | };\r |
| 45 | \r |
| 46 | static EFI_PEI_FV_FILE_LOADER_PPI mLoadFilePpi = {\r |
| 47 | DxeIplLoadFile\r |
| 48 | };\r |
| 49 | \r |
| 50 | static EFI_PEI_PPI_DESCRIPTOR mPpiLoadFile = {\r |
| 51 | (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r |
| 52 | &gEfiPeiFvFileLoaderPpiGuid,\r |
| 53 | &mLoadFilePpi\r |
| 54 | };\r |
| 55 | \r |
| 56 | static EFI_PEI_PPI_DESCRIPTOR mPpiList = {\r |
| 57 | (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r |
| 58 | &gEfiDxeIplPpiGuid,\r |
| 59 | &mDxeIplPpi\r |
| 60 | };\r |
| 61 | \r |
| 62 | static EFI_PEI_PPI_DESCRIPTOR mPpiPeiInMemory = {\r |
| 63 | (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r |
| 64 | &gPeiInMemoryGuid,\r |
| 65 | NULL\r |
| 66 | };\r |
| 67 | \r |
| 68 | static EFI_PEI_PPI_DESCRIPTOR mPpiSignal = {\r |
| 69 | (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r |
| 70 | &gEfiEndOfPeiSignalPpiGuid,\r |
| 71 | NULL\r |
| 72 | };\r |
| 73 | \r |
| 74 | DECOMPRESS_LIBRARY gEfiDecompress = {\r |
| 75 | UefiDecompressGetInfo,\r |
| 76 | UefiDecompress\r |
| 77 | };\r |
| 78 | \r |
| 79 | DECOMPRESS_LIBRARY gTianoDecompress = {\r |
| 80 | TianoDecompressGetInfo,\r |
| 81 | TianoDecompress\r |
| 82 | };\r |
| 83 | \r |
| 84 | DECOMPRESS_LIBRARY gCustomDecompress = {\r |
| 85 | CustomDecompressGetInfo,\r |
| 86 | CustomDecompress\r |
| 87 | };\r |
| 88 | \r |
| 89 | STATIC\r |
| 90 | UINTN\r |
| 91 | GetOccupiedSize (\r |
| 92 | IN UINTN ActualSize,\r |
| 93 | IN UINTN Alignment\r |
| 94 | )\r |
| 95 | {\r |
| 96 | UINTN OccupiedSize;\r |
| 97 | \r |
| 98 | OccupiedSize = ActualSize;\r |
| 99 | while ((OccupiedSize & (Alignment - 1)) != 0) {\r |
| 100 | OccupiedSize++;\r |
| 101 | }\r |
| 102 | \r |
| 103 | return OccupiedSize;\r |
| 104 | }\r |
| 105 | \r |
| 106 | EFI_STATUS\r |
| 107 | EFIAPI\r |
| 108 | PeimInitializeDxeIpl (\r |
| 109 | IN EFI_FFS_FILE_HEADER *FfsHeader,\r |
| 110 | IN EFI_PEI_SERVICES **PeiServices\r |
| 111 | )\r |
| 112 | /*++\r |
| 113 | \r |
| 114 | Routine Description:\r |
| 115 | \r |
| 116 | Initializes the Dxe Ipl PPI\r |
| 117 | \r |
| 118 | Arguments:\r |
| 119 | \r |
| 120 | FfsHeader - Pointer to FFS file header\r |
| 121 | PeiServices - General purpose services available to every PEIM.\r |
| 122 | \r |
| 123 | Returns:\r |
| 124 | \r |
| 125 | EFI_SUCCESS\r |
| 126 | \r |
| 127 | --*/\r |
| 128 | {\r |
| 129 | EFI_STATUS Status;\r |
| 130 | EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;\r |
| 131 | EFI_BOOT_MODE BootMode;\r |
| 132 | \r |
| 133 | Status = PeiCoreGetBootMode (&BootMode);\r |
| 134 | \r |
| 135 | ASSERT_EFI_ERROR (Status);\r |
| 136 | \r |
| 137 | Status = PeiCoreLocatePpi (\r |
| 138 | &gPeiInMemoryGuid,\r |
| 139 | 0,\r |
| 140 | NULL,\r |
| 141 | NULL\r |
| 142 | );\r |
| 143 | \r |
| 144 | if (EFI_ERROR (Status) && (BootMode != BOOT_ON_S3_RESUME)) { \r |
| 145 | //\r |
| 146 | // The DxeIpl has not yet been shadowed\r |
| 147 | //\r |
| 148 | PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();\r |
| 149 | \r |
| 150 | //\r |
| 151 | // Shadow DxeIpl and then re-run its entry point\r |
| 152 | //\r |
| 153 | Status = ShadowDxeIpl (FfsHeader, PeiEfiPeiPeCoffLoader);\r |
| 154 | if (EFI_ERROR (Status)) {\r |
| 155 | return Status;\r |
| 156 | }\r |
| 157 | \r |
| 158 | } else {\r |
| 159 | if (BootMode != BOOT_ON_S3_RESUME) {\r |
| 160 | //\r |
| 161 | // The DxeIpl has been shadowed\r |
| 162 | //\r |
| 163 | gInMemory = TRUE;\r |
| 164 | \r |
| 165 | //\r |
| 166 | // Install LoadFile PPI\r |
| 167 | //\r |
| 168 | Status = PeiCoreInstallPpi (&mPpiLoadFile);\r |
| 169 | \r |
| 170 | if (EFI_ERROR (Status)) {\r |
| 171 | return Status;\r |
| 172 | }\r |
| 173 | }\r |
| 174 | //\r |
| 175 | // Install DxeIpl PPI\r |
| 176 | //\r |
| 177 | PeiCoreInstallPpi (&mPpiList);\r |
| 178 | \r |
| 179 | if (EFI_ERROR (Status)) {\r |
| 180 | return Status;\r |
| 181 | }\r |
| 182 | \r |
| 183 | }\r |
| 184 | \r |
| 185 | return EFI_SUCCESS;\r |
| 186 | }\r |
| 187 | \r |
| 188 | EFI_STATUS\r |
| 189 | EFIAPI\r |
| 190 | DxeLoadCore (\r |
| 191 | IN EFI_DXE_IPL_PPI *This,\r |
| 192 | IN EFI_PEI_SERVICES **PeiServices,\r |
| 193 | IN EFI_PEI_HOB_POINTERS HobList\r |
| 194 | )\r |
| 195 | /*++\r |
| 196 | \r |
| 197 | Routine Description:\r |
| 198 | \r |
| 199 | Main entry point to last PEIM\r |
| 200 | \r |
| 201 | Arguments:\r |
| 202 | \r |
| 203 | This - Entry point for DXE IPL PPI\r |
| 204 | PeiServices - General purpose services available to every PEIM.\r |
| 205 | HobList - Address to the Pei HOB list\r |
| 206 | \r |
| 207 | Returns:\r |
| 208 | \r |
| 209 | EFI_SUCCESS - DEX core was successfully loaded.\r |
| 210 | EFI_OUT_OF_RESOURCES - There are not enough resources to load DXE core.\r |
| 211 | \r |
| 212 | --*/\r |
| 213 | {\r |
| 214 | EFI_STATUS Status;\r |
| 215 | EFI_PHYSICAL_ADDRESS TopOfStack;\r |
| 216 | EFI_PHYSICAL_ADDRESS BaseOfStack;\r |
| 217 | EFI_PHYSICAL_ADDRESS BspStore;\r |
| 218 | EFI_GUID DxeCoreFileName;\r |
| 219 | VOID *DxeCorePe32Data;\r |
| 220 | EFI_PHYSICAL_ADDRESS DxeCoreAddress;\r |
| 221 | UINT64 DxeCoreSize;\r |
| 222 | EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint;\r |
| 223 | VOID *PpisNeededByDxePe32Data;\r |
| 224 | EFI_PHYSICAL_ADDRESS PpisNeededByDxeAddress;\r |
| 225 | UINT64 PpisNeededByDxeSize;\r |
| 226 | EFI_PHYSICAL_ADDRESS PpisNeededByDxeEntryPoint;\r |
| 227 | EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;\r |
| 228 | EFI_BOOT_MODE BootMode;\r |
| 229 | EFI_PEI_RECOVERY_MODULE_PPI *PeiRecovery;\r |
| 230 | EFI_PEI_S3_RESUME_PPI *S3Resume;\r |
| 231 | EFI_PHYSICAL_ADDRESS PageTables;\r |
| 232 | \r |
| 233 | TopOfStack = 0;\r |
| 234 | BaseOfStack = 0;\r |
| 235 | BspStore = 0;\r |
| 236 | Status = EFI_SUCCESS;\r |
| 237 | \r |
| 238 | //\r |
| 239 | // if in S3 Resume, restore configure\r |
| 240 | //\r |
| 241 | Status = PeiCoreGetBootMode (&BootMode);\r |
| 242 | \r |
| 243 | if (!EFI_ERROR (Status) && (BootMode == BOOT_ON_S3_RESUME)) {\r |
| 244 | Status = PeiCoreLocatePpi (\r |
| 245 | &gEfiPeiS3ResumePpiGuid,\r |
| 246 | 0,\r |
| 247 | NULL,\r |
| 248 | (VOID **)&S3Resume\r |
| 249 | );\r |
| 250 | \r |
| 251 | ASSERT_EFI_ERROR (Status);\r |
| 252 | \r |
| 253 | Status = S3Resume->S3RestoreConfig (PeiServices);\r |
| 254 | \r |
| 255 | ASSERT_EFI_ERROR (Status);\r |
| 256 | }\r |
| 257 | \r |
| 258 | Status = EFI_SUCCESS;\r |
| 259 | \r |
| 260 | //\r |
| 261 | // Install the PEI Protocols that are shared between PEI and DXE\r |
| 262 | //\r |
| 263 | #ifdef EFI_NT_EMULATOR\r |
| 264 | PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();\r |
| 265 | ASSERT (PeiEfiPeiPeCoffLoader != NULL);\r |
| 266 | #else\r |
| 267 | PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderX64Protocol ();\r |
| 268 | #endif \r |
| 269 | \r |
| 270 | #if 0\r |
| 271 | Status = InstallEfiPeiPeCoffLoader64 (PeiServices, &PeiEfiPeiPeCoffLoader, NULL);\r |
| 272 | ASSERT_EFI_ERROR (Status);\r |
| 273 | #endif\r |
| 274 | //\r |
| 275 | // Allocate 128KB for the Stack\r |
| 276 | //\r |
| 277 | PeiCoreAllocatePages (EfiBootServicesData, EFI_SIZE_TO_PAGES (STACK_SIZE), &BaseOfStack);\r |
| 278 | ASSERT (BaseOfStack != 0);\r |
| 279 | \r |
| 280 | //\r |
| 281 | // Compute the top of the stack we were allocated. Pre-allocate a 32 bytes\r |
| 282 | // for safety (PpisNeededByDxe and DxeCore).\r |
| 283 | //\r |
| 284 | TopOfStack = BaseOfStack + EFI_SIZE_TO_PAGES (STACK_SIZE) * EFI_PAGE_SIZE - 32;\r |
| 285 | \r |
| 286 | //\r |
| 287 | // Add architecture-specifc HOBs (including the BspStore HOB)\r |
| 288 | //\r |
| 289 | Status = CreateArchSpecificHobs (&BspStore);\r |
| 290 | ASSERT_EFI_ERROR (Status);\r |
| 291 | \r |
| 292 | //\r |
| 293 | // See if we are in crisis recovery\r |
| 294 | //\r |
| 295 | Status = PeiCoreGetBootMode (&BootMode);\r |
| 296 | if (!EFI_ERROR (Status) && (BootMode == BOOT_IN_RECOVERY_MODE)) {\r |
| 297 | Status = PeiCoreLocatePpi (\r |
| 298 | &gEfiPeiRecoveryModulePpiGuid,\r |
| 299 | 0,\r |
| 300 | NULL,\r |
| 301 | (VOID **)&PeiRecovery\r |
| 302 | );\r |
| 303 | \r |
| 304 | ASSERT_EFI_ERROR (Status);\r |
| 305 | Status = PeiRecovery->LoadRecoveryCapsule (PeiServices, PeiRecovery);\r |
| 306 | ASSERT_EFI_ERROR (Status);\r |
| 307 | }\r |
| 308 | \r |
| 309 | //\r |
| 310 | // Find the DXE Core in a Firmware Volume\r |
| 311 | //\r |
| 312 | Status = PeiFindFile (\r |
| 313 | EFI_FV_FILETYPE_DXE_CORE,\r |
| 314 | EFI_SECTION_PE32,\r |
| 315 | &DxeCoreFileName,\r |
| 316 | &DxeCorePe32Data\r |
| 317 | );\r |
| 318 | ASSERT_EFI_ERROR (Status);\r |
| 319 | \r |
| 320 | //\r |
| 321 | // Find the PpisNeededByDxe in a Firmware Volume\r |
| 322 | //\r |
| 323 | Status = PeiFindFile (\r |
| 324 | EFI_FV_FILETYPE_ALL,\r |
| 325 | EFI_SECTION_PE32,\r |
| 326 | &mPpiNeededByDxeGuid,\r |
| 327 | &PpisNeededByDxePe32Data\r |
| 328 | );\r |
| 329 | ASSERT_EFI_ERROR (Status);\r |
| 330 | \r |
| 331 | //\r |
| 332 | // Transfer control to the DXE Core\r |
| 333 | // The handoff state is simply a pointer to the HOB list\r |
| 334 | //\r |
| 335 | // PEI_PERF_END (PeiServices, L"DxeIpl", NULL, 0);\r |
| 336 | \r |
| 337 | Status = PeiCoreInstallPpi (&mPpiSignal);\r |
| 338 | ASSERT_EFI_ERROR (Status);\r |
| 339 | \r |
| 340 | //\r |
| 341 | // Load the GDT of Go64. Since the GDT of 32-bit Tiano locates in the BS_DATA \\r |
| 342 | // memory, it may be corrupted when copying FV to high-end memory \r |
| 343 | LoadGo64Gdt();\r |
| 344 | \r |
| 345 | //\r |
| 346 | // Limit to 36 bits of addressing for debug. Should get it from CPU\r |
| 347 | //\r |
| 348 | PageTables = CreateIdentityMappingPageTables (36);\r |
| 349 | \r |
| 350 | //\r |
| 351 | // Load the PpiNeededByDxe from a Firmware Volume\r |
| 352 | //\r |
| 353 | Status = PeiLoadx64File (\r |
| 354 | PeiEfiPeiPeCoffLoader,\r |
| 355 | PpisNeededByDxePe32Data,\r |
| 356 | EfiBootServicesData,\r |
| 357 | &PpisNeededByDxeAddress,\r |
| 358 | &PpisNeededByDxeSize,\r |
| 359 | &PpisNeededByDxeEntryPoint\r |
| 360 | );\r |
| 361 | ASSERT_EFI_ERROR (Status);\r |
| 362 | \r |
| 363 | \r |
| 364 | //\r |
| 365 | // Load the DXE Core from a Firmware Volume\r |
| 366 | //\r |
| 367 | Status = PeiLoadx64File (\r |
| 368 | PeiEfiPeiPeCoffLoader,\r |
| 369 | DxeCorePe32Data,\r |
| 370 | EfiBootServicesData,\r |
| 371 | &DxeCoreAddress,\r |
| 372 | &DxeCoreSize,\r |
| 373 | &DxeCoreEntryPoint\r |
| 374 | );\r |
| 375 | ASSERT_EFI_ERROR (Status);\r |
| 376 | \r |
| 377 | //\r |
| 378 | //\r |
| 379 | // Add HOB for the DXE Core\r |
| 380 | //\r |
| 381 | BuildModuleHob (\r |
| 382 | &DxeCoreFileName,\r |
| 383 | DxeCoreAddress,\r |
| 384 | DxeCoreSize,\r |
| 385 | DxeCoreEntryPoint\r |
| 386 | );\r |
| 387 | \r |
| 388 | //\r |
| 389 | // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT\r |
| 390 | //\r |
| 391 | REPORT_STATUS_CODE (\r |
| 392 | EFI_PROGRESS_CODE,\r |
| 393 | EFI_SOFTWARE_PEI_MODULE | EFI_SW_PEI_CORE_PC_HANDOFF_TO_NEXT\r |
| 394 | );\r |
| 395 | \r |
| 396 | DEBUG ((EFI_D_INFO, "DXE Core Entry\n"));\r |
| 397 | //\r |
| 398 | // Go to Long Mode. Interrupts will not get turned on until the CPU AP is loaded.\r |
| 399 | // Call x64 drivers passing in single argument, a pointer to the HOBs.\r |
| 400 | //\r |
| 401 | ActivateLongMode (\r |
| 402 | PageTables, \r |
| 403 | (EFI_PHYSICAL_ADDRESS)(UINTN)(HobList.Raw), \r |
| 404 | TopOfStack,\r |
| 405 | PpisNeededByDxeEntryPoint,\r |
| 406 | DxeCoreEntryPoint\r |
| 407 | );\r |
| 408 | \r |
| 409 | //\r |
| 410 | // If we get here, then the DXE Core returned. This is an error\r |
| 411 | //\r |
| 412 | ASSERT_EFI_ERROR (Status);\r |
| 413 | \r |
| 414 | return EFI_OUT_OF_RESOURCES;\r |
| 415 | }\r |
| 416 | \r |
| 417 | EFI_STATUS\r |
| 418 | PeiFindFile (\r |
| 419 | IN UINT8 Type,\r |
| 420 | IN UINT16 SectionType,\r |
| 421 | OUT EFI_GUID *FileName,\r |
| 422 | OUT VOID **Pe32Data\r |
| 423 | )\r |
| 424 | /*++\r |
| 425 | \r |
| 426 | Routine Description:\r |
| 427 | \r |
| 428 | Finds a PE/COFF of a specific Type and SectionType in the Firmware Volumes\r |
| 429 | described in the HOB list. Able to search in a compression set in a FFS file.\r |
| 430 | But only one level of compression is supported, that is, not able to search\r |
| 431 | in a compression set that is within another compression set.\r |
| 432 | \r |
| 433 | Arguments:\r |
| 434 | \r |
| 435 | Type - The Type of file to retrieve\r |
| 436 | \r |
| 437 | SectionType - The type of section to retrieve from a file\r |
| 438 | \r |
| 439 | FileName - The name of the file found in the Firmware Volume\r |
| 440 | \r |
| 441 | Pe32Data - Pointer to the beginning of the PE/COFF file found in the Firmware Volume\r |
| 442 | \r |
| 443 | Returns:\r |
| 444 | \r |
| 445 | EFI_SUCCESS - The file was found, and the name is returned in FileName, and a pointer to\r |
| 446 | the PE/COFF image is returned in Pe32Data\r |
| 447 | \r |
| 448 | EFI_NOT_FOUND - The file was not found in the Firmware Volumes present in the HOB List\r |
| 449 | \r |
| 450 | --*/\r |
| 451 | {\r |
| 452 | EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r |
| 453 | EFI_FFS_FILE_HEADER *FfsFileHeader;\r |
| 454 | VOID *SectionData;\r |
| 455 | EFI_STATUS Status;\r |
| 456 | EFI_PEI_HOB_POINTERS Hob;\r |
| 457 | \r |
| 458 | \r |
| 459 | FwVolHeader = NULL;\r |
| 460 | FfsFileHeader = NULL;\r |
| 461 | SectionData = NULL;\r |
| 462 | \r |
| 463 | //\r |
| 464 | // Foreach Firmware Volume, look for a specified type\r |
| 465 | // of file and break out when one is found\r |
| 466 | //\r |
| 467 | Hob.Raw = GetHobList ();\r |
| 468 | while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_FV, Hob.Raw)) != NULL) {\r |
| 469 | FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (Hob.FirmwareVolume->BaseAddress);\r |
| 470 | Status = PeiCoreFfsFindNextFile (\r |
| 471 | Type,\r |
| 472 | FwVolHeader,\r |
| 473 | &FfsFileHeader\r |
| 474 | );\r |
| 475 | if (!EFI_ERROR (Status)) {\r |
| 476 | CopyMem (FileName, &FfsFileHeader->Name, sizeof (EFI_GUID));\r |
| 477 | Status = PeiProcessFile (\r |
| 478 | SectionType,\r |
| 479 | FfsFileHeader,\r |
| 480 | Pe32Data\r |
| 481 | );\r |
| 482 | return Status;\r |
| 483 | }\r |
| 484 | Hob.Raw = GET_NEXT_HOB (Hob);\r |
| 485 | }\r |
| 486 | return EFI_NOT_FOUND;\r |
| 487 | }\r |
| 488 | \r |
| 489 | EFI_STATUS\r |
| 490 | PeiLoadx64File (\r |
| 491 | IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader,\r |
| 492 | IN VOID *Pe32Data,\r |
| 493 | IN EFI_MEMORY_TYPE MemoryType,\r |
| 494 | OUT EFI_PHYSICAL_ADDRESS *ImageAddress,\r |
| 495 | OUT UINT64 *ImageSize,\r |
| 496 | OUT EFI_PHYSICAL_ADDRESS *EntryPoint\r |
| 497 | )\r |
| 498 | /*++\r |
| 499 | \r |
| 500 | Routine Description:\r |
| 501 | \r |
| 502 | Loads and relocates a PE/COFF image into memory.\r |
| 503 | \r |
| 504 | Arguments:\r |
| 505 | \r |
| 506 | PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol\r |
| 507 | \r |
| 508 | Pe32Data - The base address of the PE/COFF file that is to be loaded and relocated\r |
| 509 | \r |
| 510 | ImageAddress - The base address of the relocated PE/COFF image\r |
| 511 | \r |
| 512 | ImageSize - The size of the relocated PE/COFF image\r |
| 513 | \r |
| 514 | EntryPoint - The entry point of the relocated PE/COFF image\r |
| 515 | \r |
| 516 | Returns:\r |
| 517 | \r |
| 518 | EFI_SUCCESS - The file was loaded and relocated\r |
| 519 | EFI_OUT_OF_RESOURCES - There was not enough memory to load and relocate the PE/COFF file\r |
| 520 | \r |
| 521 | --*/\r |
| 522 | {\r |
| 523 | EFI_STATUS Status;\r |
| 524 | PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r |
| 525 | EFI_PHYSICAL_ADDRESS MemoryBuffer;\r |
| 526 | \r |
| 527 | ZeroMem (&ImageContext, sizeof (ImageContext));\r |
| 528 | ImageContext.Handle = Pe32Data;\r |
| 529 | Status = GetImageReadFunction (&ImageContext);\r |
| 530 | \r |
| 531 | ASSERT_EFI_ERROR (Status);\r |
| 532 | \r |
| 533 | Status = PeiEfiPeiPeCoffLoader->GetImageInfo (PeiEfiPeiPeCoffLoader, &ImageContext);\r |
| 534 | if (EFI_ERROR (Status)) {\r |
| 535 | return Status;\r |
| 536 | }\r |
| 537 | //\r |
| 538 | // Allocate Memory for the image\r |
| 539 | //\r |
| 540 | //\r |
| 541 | // Allocate Memory for the image\r |
| 542 | //\r |
| 543 | PeiCoreAllocatePages (MemoryType, EFI_SIZE_TO_PAGES ((UINT32) ImageContext.ImageSize), &MemoryBuffer);\r |
| 544 | ImageContext.ImageAddress = MemoryBuffer;\r |
| 545 | ASSERT (ImageContext.ImageAddress != 0);\r |
| 546 | \r |
| 547 | //\r |
| 548 | // Load the image to our new buffer\r |
| 549 | //\r |
| 550 | \r |
| 551 | Status = PeiEfiPeiPeCoffLoader->LoadImage (PeiEfiPeiPeCoffLoader, &ImageContext);\r |
| 552 | if (EFI_ERROR (Status)) {\r |
| 553 | return Status;\r |
| 554 | }\r |
| 555 | \r |
| 556 | //\r |
| 557 | // Relocate the image in our new buffer\r |
| 558 | //\r |
| 559 | Status = PeiEfiPeiPeCoffLoader->RelocateImage (PeiEfiPeiPeCoffLoader, &ImageContext);\r |
| 560 | if (EFI_ERROR (Status)) {\r |
| 561 | return Status;\r |
| 562 | }\r |
| 563 | \r |
| 564 | //\r |
| 565 | // Flush the instruction cache so the image data is written before we execute it\r |
| 566 | //\r |
| 567 | InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);\r |
| 568 | \r |
| 569 | *ImageAddress = ImageContext.ImageAddress;\r |
| 570 | *ImageSize = ImageContext.ImageSize;\r |
| 571 | *EntryPoint = ImageContext.EntryPoint;\r |
| 572 | \r |
| 573 | return EFI_SUCCESS;\r |
| 574 | }\r |
| 575 | \r |
| 576 | EFI_STATUS\r |
| 577 | ShadowDxeIpl (\r |
| 578 | IN EFI_FFS_FILE_HEADER *DxeIplFileHeader,\r |
| 579 | IN EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader\r |
| 580 | )\r |
| 581 | /*++\r |
| 582 | \r |
| 583 | Routine Description:\r |
| 584 | \r |
| 585 | Shadow the DXE IPL to a different memory location. This occurs after permanent\r |
| 586 | memory has been discovered.\r |
| 587 | \r |
| 588 | Arguments:\r |
| 589 | \r |
| 590 | DxeIplFileHeader - Pointer to the FFS file header of the DXE IPL driver\r |
| 591 | \r |
| 592 | PeiEfiPeiPeCoffLoader - Pointer to a PE COFF loader protocol\r |
| 593 | \r |
| 594 | Returns:\r |
| 595 | \r |
| 596 | EFI_SUCCESS - DXE IPL was successfully shadowed to a different memory location.\r |
| 597 | \r |
| 598 | EFI_ ERROR - The shadow was unsuccessful.\r |
| 599 | \r |
| 600 | \r |
| 601 | --*/\r |
| 602 | {\r |
| 603 | UINTN SectionLength;\r |
| 604 | UINTN OccupiedSectionLength;\r |
| 605 | EFI_PHYSICAL_ADDRESS DxeIplAddress;\r |
| 606 | UINT64 DxeIplSize;\r |
| 607 | EFI_PHYSICAL_ADDRESS DxeIplEntryPoint;\r |
| 608 | EFI_STATUS Status;\r |
| 609 | EFI_COMMON_SECTION_HEADER *Section;\r |
| 610 | \r |
| 611 | Section = (EFI_COMMON_SECTION_HEADER *) (DxeIplFileHeader + 1);\r |
| 612 | \r |
| 613 | while ((Section->Type != EFI_SECTION_PE32) && (Section->Type != EFI_SECTION_TE)) {\r |
| 614 | SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff;\r |
| 615 | OccupiedSectionLength = GetOccupiedSize (SectionLength, 4);\r |
| 616 | Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength);\r |
| 617 | }\r |
| 618 | \r |
| 619 | //\r |
| 620 | // Relocate DxeIpl into memory by using loadfile service\r |
| 621 | //\r |
| 622 | Status = PeiLoadx64File (\r |
| 623 | PeiEfiPeiPeCoffLoader,\r |
| 624 | (VOID *) (Section + 1),\r |
| 625 | EfiBootServicesData,\r |
| 626 | &DxeIplAddress,\r |
| 627 | &DxeIplSize,\r |
| 628 | &DxeIplEntryPoint\r |
| 629 | );\r |
| 630 | \r |
| 631 | if (Status == EFI_SUCCESS) {\r |
| 632 | //\r |
| 633 | // Install PeiInMemory to indicate the Dxeipl is shadowed\r |
| 634 | //\r |
| 635 | Status = PeiCoreInstallPpi (&mPpiPeiInMemory);\r |
| 636 | \r |
| 637 | if (EFI_ERROR (Status)) {\r |
| 638 | return Status;\r |
| 639 | }\r |
| 640 | \r |
| 641 | Status = ((EFI_PEIM_ENTRY_POINT) (UINTN) DxeIplEntryPoint) (DxeIplFileHeader, GetPeiServicesTablePointer());\r |
| 642 | }\r |
| 643 | \r |
| 644 | return Status;\r |
| 645 | }\r |
| 646 | \r |
| 647 | EFI_STATUS\r |
| 648 | EFIAPI\r |
| 649 | DxeIplLoadFile (\r |
| 650 | IN EFI_PEI_FV_FILE_LOADER_PPI *This,\r |
| 651 | IN EFI_FFS_FILE_HEADER *FfsHeader,\r |
| 652 | OUT EFI_PHYSICAL_ADDRESS *ImageAddress,\r |
| 653 | OUT UINT64 *ImageSize,\r |
| 654 | OUT EFI_PHYSICAL_ADDRESS *EntryPoint\r |
| 655 | )\r |
| 656 | /*++\r |
| 657 | \r |
| 658 | Routine Description:\r |
| 659 | \r |
| 660 | Given a pointer to an FFS file containing a PE32 image, get the\r |
| 661 | information on the PE32 image, and then "load" it so that it\r |
| 662 | can be executed.\r |
| 663 | \r |
| 664 | Arguments:\r |
| 665 | \r |
| 666 | This - pointer to our file loader protocol\r |
| 667 | FfsHeader - pointer to the FFS file header of the FFS file that\r |
| 668 | contains the PE32 image we want to load\r |
| 669 | ImageAddress - returned address where the PE32 image is loaded\r |
| 670 | ImageSize - returned size of the loaded PE32 image\r |
| 671 | EntryPoint - entry point to the loaded PE32 image\r |
| 672 | \r |
| 673 | Returns:\r |
| 674 | \r |
| 675 | EFI_SUCCESS - The FFS file was successfully loaded.\r |
| 676 | EFI_ERROR - Unable to load the FFS file.\r |
| 677 | \r |
| 678 | --*/\r |
| 679 | {\r |
| 680 | EFI_PEI_PE_COFF_LOADER_PROTOCOL *PeiEfiPeiPeCoffLoader;\r |
| 681 | EFI_STATUS Status;\r |
| 682 | VOID *Pe32Data;\r |
| 683 | \r |
| 684 | Pe32Data = NULL;\r |
| 685 | PeiEfiPeiPeCoffLoader = (EFI_PEI_PE_COFF_LOADER_PROTOCOL *)GetPeCoffLoaderProtocol ();\r |
| 686 | \r |
| 687 | //\r |
| 688 | // Preprocess the FFS file to get a pointer to the PE32 information\r |
| 689 | // in the enclosed PE32 image.\r |
| 690 | //\r |
| 691 | Status = PeiProcessFile (\r |
| 692 | EFI_SECTION_PE32,\r |
| 693 | FfsHeader,\r |
| 694 | &Pe32Data\r |
| 695 | );\r |
| 696 | \r |
| 697 | if (EFI_ERROR (Status)) {\r |
| 698 | return Status;\r |
| 699 | }\r |
| 700 | //\r |
| 701 | // Load the PE image from the FFS file\r |
| 702 | //\r |
| 703 | Status = PeiLoadx64File (\r |
| 704 | PeiEfiPeiPeCoffLoader,\r |
| 705 | Pe32Data,\r |
| 706 | EfiBootServicesData,\r |
| 707 | ImageAddress,\r |
| 708 | ImageSize,\r |
| 709 | EntryPoint\r |
| 710 | );\r |
| 711 | \r |
| 712 | return Status;\r |
| 713 | }\r |
| 714 | \r |
| 715 | EFI_STATUS\r |
| 716 | PeiProcessFile (\r |
| 717 | IN UINT16 SectionType,\r |
| 718 | IN EFI_FFS_FILE_HEADER *FfsFileHeader,\r |
| 719 | OUT VOID **Pe32Data\r |
| 720 | )\r |
| 721 | /*++\r |
| 722 | \r |
| 723 | Routine Description:\r |
| 724 | \r |
| 725 | Arguments:\r |
| 726 | \r |
| 727 | SectionType - The type of section in the FFS file to process.\r |
| 728 | \r |
| 729 | FfsFileHeader - Pointer to the FFS file to process, looking for the\r |
| 730 | specified SectionType\r |
| 731 | \r |
| 732 | Pe32Data - returned pointer to the start of the PE32 image found\r |
| 733 | in the FFS file.\r |
| 734 | \r |
| 735 | Returns:\r |
| 736 | \r |
| 737 | EFI_SUCCESS - found the PE32 section in the FFS file\r |
| 738 | \r |
| 739 | --*/\r |
| 740 | {\r |
| 741 | EFI_STATUS Status;\r |
| 742 | VOID *SectionData;\r |
| 743 | DECOMPRESS_LIBRARY *DecompressLibrary;\r |
| 744 | UINT8 *DstBuffer;\r |
| 745 | UINT8 *ScratchBuffer;\r |
| 746 | UINT32 DstBufferSize;\r |
| 747 | UINT32 ScratchBufferSize;\r |
| 748 | EFI_COMMON_SECTION_HEADER *CmpSection;\r |
| 749 | UINTN CmpSectionLength;\r |
| 750 | UINTN OccupiedCmpSectionLength;\r |
| 751 | VOID *CmpFileData;\r |
| 752 | UINTN CmpFileSize;\r |
| 753 | EFI_COMMON_SECTION_HEADER *Section;\r |
| 754 | UINTN SectionLength;\r |
| 755 | UINTN OccupiedSectionLength;\r |
| 756 | UINT64 FileSize;\r |
| 757 | EFI_GUID_DEFINED_SECTION *GuidedSectionHeader;\r |
| 758 | UINT32 AuthenticationStatus;\r |
| 759 | EFI_PEI_SECTION_EXTRACTION_PPI *SectionExtract;\r |
| 760 | UINT32 BufferSize;\r |
| 761 | UINT8 *Buffer;\r |
| 762 | EFI_PEI_SECURITY_PPI *Security;\r |
| 763 | BOOLEAN StartCrisisRecovery;\r |
| 764 | EFI_GUID TempGuid;\r |
| 765 | EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r |
| 766 | EFI_COMPRESSION_SECTION *CompressionSection;\r |
| 767 | \r |
| 768 | Status = PeiCoreFfsFindSectionData (\r |
| 769 | EFI_SECTION_COMPRESSION,\r |
| 770 | FfsFileHeader,\r |
| 771 | &SectionData\r |
| 772 | );\r |
| 773 | \r |
| 774 | //\r |
| 775 | // Upon finding a DXE Core file, see if there is first a compression section\r |
| 776 | //\r |
| 777 | if (!EFI_ERROR (Status)) {\r |
| 778 | //\r |
| 779 | // Yes, there is a compression section, so extract the contents\r |
| 780 | // Decompress the image here\r |
| 781 | //\r |
| 782 | Section = (EFI_COMMON_SECTION_HEADER *) (UINTN) (VOID *) ((UINT8 *) (FfsFileHeader) + (UINTN) sizeof (EFI_FFS_FILE_HEADER));\r |
| 783 | \r |
| 784 | do {\r |
| 785 | SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff;\r |
| 786 | OccupiedSectionLength = GetOccupiedSize (SectionLength, 4);\r |
| 787 | \r |
| 788 | //\r |
| 789 | // Was the DXE Core file encapsulated in a GUID'd section?\r |
| 790 | //\r |
| 791 | if (Section->Type == EFI_SECTION_GUID_DEFINED) {\r |
| 792 | //\r |
| 793 | // Locate the GUID'd Section Extractor\r |
| 794 | //\r |
| 795 | GuidedSectionHeader = (VOID *) (Section + 1);\r |
| 796 | \r |
| 797 | //\r |
| 798 | // This following code constitutes the addition of the security model\r |
| 799 | // to the DXE IPL.\r |
| 800 | //\r |
| 801 | //\r |
| 802 | // Set a default authenticatino state\r |
| 803 | //\r |
| 804 | AuthenticationStatus = 0;\r |
| 805 | \r |
| 806 | Status = PeiCoreLocatePpi (\r |
| 807 | &gEfiPeiSectionExtractionPpiGuid,\r |
| 808 | 0,\r |
| 809 | NULL,\r |
| 810 | (VOID **)&SectionExtract\r |
| 811 | );\r |
| 812 | \r |
| 813 | if (EFI_ERROR (Status)) {\r |
| 814 | return Status;\r |
| 815 | }\r |
| 816 | //\r |
| 817 | // Verify Authentication State\r |
| 818 | //\r |
| 819 | CopyMem (&TempGuid, Section + 1, sizeof (EFI_GUID));\r |
| 820 | \r |
| 821 | Status = SectionExtract->PeiGetSection (\r |
| 822 | GetPeiServicesTablePointer(),\r |
| 823 | SectionExtract,\r |
| 824 | (EFI_SECTION_TYPE *) &SectionType,\r |
| 825 | &TempGuid,\r |
| 826 | 0,\r |
| 827 | (VOID **) &Buffer,\r |
| 828 | &BufferSize,\r |
| 829 | &AuthenticationStatus\r |
| 830 | );\r |
| 831 | \r |
| 832 | if (EFI_ERROR (Status)) {\r |
| 833 | return Status;\r |
| 834 | }\r |
| 835 | //\r |
| 836 | // If not ask the Security PPI, if exists, for disposition\r |
| 837 | //\r |
| 838 | //\r |
| 839 | Status = PeiCoreLocatePpi (\r |
| 840 | &gEfiPeiSecurityPpiGuid,\r |
| 841 | 0,\r |
| 842 | NULL,\r |
| 843 | (VOID **)&Security\r |
| 844 | );\r |
| 845 | if (EFI_ERROR (Status)) {\r |
| 846 | return Status;\r |
| 847 | }\r |
| 848 | \r |
| 849 | Status = Security->AuthenticationState (\r |
| 850 | GetPeiServicesTablePointer(),\r |
| 851 | (struct _EFI_PEI_SECURITY_PPI *) Security,\r |
| 852 | AuthenticationStatus,\r |
| 853 | FfsFileHeader,\r |
| 854 | &StartCrisisRecovery\r |
| 855 | );\r |
| 856 | \r |
| 857 | if (EFI_ERROR (Status)) {\r |
| 858 | return Status;\r |
| 859 | }\r |
| 860 | //\r |
| 861 | // If there is a security violation, report to caller and have\r |
| 862 | // the upper-level logic possible engender a crisis recovery\r |
| 863 | //\r |
| 864 | if (StartCrisisRecovery) {\r |
| 865 | return EFI_SECURITY_VIOLATION;\r |
| 866 | }\r |
| 867 | }\r |
| 868 | \r |
| 869 | if (Section->Type == EFI_SECTION_PE32) {\r |
| 870 | //\r |
| 871 | // This is what we want\r |
| 872 | //\r |
| 873 | *Pe32Data = (VOID *) (Section + 1);\r |
| 874 | return EFI_SUCCESS;\r |
| 875 | } else if (Section->Type == EFI_SECTION_COMPRESSION) {\r |
| 876 | //\r |
| 877 | // This is a compression set, expand it\r |
| 878 | //\r |
| 879 | CompressionSection = (EFI_COMPRESSION_SECTION *) Section;\r |
| 880 | \r |
| 881 | switch (CompressionSection->CompressionType) {\r |
| 882 | case EFI_STANDARD_COMPRESSION:\r |
| 883 | DecompressLibrary = &gTianoDecompress;\r |
| 884 | break;\r |
| 885 | \r |
| 886 | case EFI_CUSTOMIZED_COMPRESSION:\r |
| 887 | //\r |
| 888 | // Load user customized compression protocol.\r |
| 889 | //\r |
| 890 | DecompressLibrary = &gCustomDecompress;\r |
| 891 | break;\r |
| 892 | \r |
| 893 | case EFI_NOT_COMPRESSED:\r |
| 894 | default:\r |
| 895 | //\r |
| 896 | // Need to support not compressed file\r |
| 897 | //\r |
| 898 | ASSERT_EFI_ERROR (Status);\r |
| 899 | return EFI_NOT_FOUND;\r |
| 900 | }\r |
| 901 | \r |
| 902 | Status = DecompressLibrary->GetInfo (\r |
| 903 | (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),\r |
| 904 | (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION),\r |
| 905 | &DstBufferSize,\r |
| 906 | &ScratchBufferSize\r |
| 907 | );\r |
| 908 | if (EFI_ERROR (Status)) {\r |
| 909 | //\r |
| 910 | // GetInfo failed\r |
| 911 | //\r |
| 912 | return EFI_NOT_FOUND;\r |
| 913 | }\r |
| 914 | \r |
| 915 | //\r |
| 916 | // Allocate scratch buffer\r |
| 917 | //\r |
| 918 | ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));\r |
| 919 | if (ScratchBuffer == NULL) {\r |
| 920 | return EFI_OUT_OF_RESOURCES;\r |
| 921 | }\r |
| 922 | \r |
| 923 | //\r |
| 924 | // Allocate destination buffer\r |
| 925 | //\r |
| 926 | DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize));\r |
| 927 | if (DstBuffer == NULL) {\r |
| 928 | return EFI_OUT_OF_RESOURCES;\r |
| 929 | }\r |
| 930 | \r |
| 931 | //\r |
| 932 | // Call decompress function\r |
| 933 | //\r |
| 934 | Status = DecompressLibrary->Decompress (\r |
| 935 | (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),\r |
| 936 | DstBuffer,\r |
| 937 | ScratchBuffer\r |
| 938 | );\r |
| 939 | \r |
| 940 | CmpSection = (EFI_COMMON_SECTION_HEADER *) DstBuffer;\r |
| 941 | if (CmpSection->Type == EFI_SECTION_RAW) {\r |
| 942 | //\r |
| 943 | // Skip the section header and\r |
| 944 | // adjust the pointer alignment to 16\r |
| 945 | //\r |
| 946 | FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (DstBuffer + 16);\r |
| 947 | \r |
| 948 | if (FvHeader->Signature == EFI_FVH_SIGNATURE) {\r |
| 949 | FfsFileHeader = NULL;\r |
| 950 | BuildFvHob ((EFI_PHYSICAL_ADDRESS) (UINTN) FvHeader, FvHeader->FvLength);\r |
| 951 | Status = PeiCoreFfsFindNextFile (\r |
| 952 | EFI_FV_FILETYPE_DXE_CORE,\r |
| 953 | FvHeader,\r |
| 954 | &FfsFileHeader\r |
| 955 | );\r |
| 956 | \r |
| 957 | if (EFI_ERROR (Status)) {\r |
| 958 | return EFI_NOT_FOUND;\r |
| 959 | }\r |
| 960 | \r |
| 961 | return PeiProcessFile (SectionType, FfsFileHeader, Pe32Data);\r |
| 962 | }\r |
| 963 | }\r |
| 964 | //\r |
| 965 | // Decompress successfully.\r |
| 966 | // Loop the decompressed data searching for expected section.\r |
| 967 | //\r |
| 968 | CmpFileData = (VOID *) DstBuffer;\r |
| 969 | CmpFileSize = DstBufferSize;\r |
| 970 | do {\r |
| 971 | CmpSectionLength = *(UINT32 *) (CmpSection->Size) & 0x00ffffff;\r |
| 972 | if (CmpSection->Type == EFI_SECTION_PE32) {\r |
| 973 | //\r |
| 974 | // This is what we want\r |
| 975 | //\r |
| 976 | *Pe32Data = (VOID *) (CmpSection + 1);\r |
| 977 | return EFI_SUCCESS;\r |
| 978 | }\r |
| 979 | \r |
| 980 | OccupiedCmpSectionLength = GetOccupiedSize (CmpSectionLength, 4);\r |
| 981 | CmpSection = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) CmpSection + OccupiedCmpSectionLength);\r |
| 982 | } while (CmpSection->Type != 0 && (UINTN) ((UINT8 *) CmpSection - (UINT8 *) CmpFileData) < CmpFileSize);\r |
| 983 | }\r |
| 984 | \r |
| 985 | Section = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) Section + OccupiedSectionLength);\r |
| 986 | FileSize = FfsFileHeader->Size[0] & 0xFF;\r |
| 987 | FileSize += (FfsFileHeader->Size[1] << 8) & 0xFF00;\r |
| 988 | FileSize += (FfsFileHeader->Size[2] << 16) & 0xFF0000;\r |
| 989 | FileSize &= 0x00FFFFFF;\r |
| 990 | } while (Section->Type != 0 && (UINTN) ((UINT8 *) Section - (UINT8 *) FfsFileHeader) < FileSize);\r |
| 991 | \r |
| 992 | //\r |
| 993 | // End of the decompression activity\r |
| 994 | //\r |
| 995 | } else {\r |
| 996 | \r |
| 997 | Status = PeiCoreFfsFindSectionData (\r |
| 998 | EFI_SECTION_PE32,\r |
| 999 | FfsFileHeader,\r |
| 1000 | &SectionData\r |
| 1001 | );\r |
| 1002 | \r |
| 1003 | if (EFI_ERROR (Status)) {\r |
| 1004 | Status = PeiCoreFfsFindSectionData (\r |
| 1005 | EFI_SECTION_TE,\r |
| 1006 | FfsFileHeader,\r |
| 1007 | &SectionData\r |
| 1008 | );\r |
| 1009 | if (EFI_ERROR (Status)) {\r |
| 1010 | return Status;\r |
| 1011 | }\r |
| 1012 | }\r |
| 1013 | }\r |
| 1014 | \r |
| 1015 | *Pe32Data = SectionData;\r |
| 1016 | \r |
| 1017 | return EFI_SUCCESS;\r |
| 1018 | } |