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