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