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