3 Responsibility of this module is to load the DXE Core from a Firmware Volume.
5 Copyright (c) 2006 - 2007 Intel Corporation
6 All rights reserved. This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
17 #include <Ppi/GuidedSectionExtraction.h>
18 #include <FrameworkPei.h>
21 CustomDecompressExtractSection (
22 IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI
*This
,
23 IN CONST VOID
*InputSection
,
24 OUT VOID
**OutputBuffer
,
25 OUT UINTN
*OutputSize
,
26 OUT UINT32
*AuthenticationStatus
33 IN CONST EFI_PEI_DECOMPRESS_PPI
*This
,
34 IN CONST EFI_COMPRESSION_SECTION
*InputSection
,
35 OUT VOID
**OutputBuffer
,
40 BOOLEAN gInMemory
= FALSE
;
43 // Module Globals used in the DXE to PEI handoff
44 // These must be module globals, so the stack can be switched
46 static EFI_DXE_IPL_PPI mDxeIplPpi
= {
50 STATIC EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI mCustomDecompressExtractiongPpi
= {
51 CustomDecompressExtractSection
54 STATIC EFI_PEI_DECOMPRESS_PPI mDecompressPpi
= {
58 static EFI_PEI_PPI_DESCRIPTOR mPpiList
[] = {
60 EFI_PEI_PPI_DESCRIPTOR_PPI
,
65 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
66 &gEfiPeiDecompressPpiGuid
,
71 static EFI_PEI_PPI_DESCRIPTOR mPpiSignal
= {
72 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
73 &gEfiEndOfPeiSignalPpiGuid
,
78 Initializes the Dxe Ipl PPI
80 @param FfsHandle The handle of FFS file.
81 @param PeiServices General purpose services available to
87 PeimInitializeDxeIpl (
88 IN EFI_PEI_FILE_HANDLE FfsHandle
,
89 IN EFI_PEI_SERVICES
**PeiServices
93 EFI_BOOT_MODE BootMode
;
94 EFI_GUID
**DecompressGuidList
;
95 UINT32 DecompressMethodNumber
;
96 EFI_PEI_PPI_DESCRIPTOR
*GuidPpi
;
98 Status
= PeiServicesGetBootMode (&BootMode
);
99 ASSERT_EFI_ERROR (Status
);
101 if (BootMode
!= BOOT_ON_S3_RESUME
) {
102 Status
= PeiServicesRegisterForShadow (FfsHandle
);
103 if (Status
== EFI_SUCCESS
) {
105 // EFI_SUCESS means the first time call register for shadow
108 } else if (Status
== EFI_ALREADY_STARTED
) {
113 // Get custom decompress method guid list
115 DecompressGuidList
= NULL
;
116 DecompressMethodNumber
= 0;
117 Status
= CustomDecompressGetAlgorithms (DecompressGuidList
, &DecompressMethodNumber
);
118 if (Status
== EFI_OUT_OF_RESOURCES
) {
119 DecompressGuidList
= (EFI_GUID
**) AllocatePages (EFI_SIZE_TO_PAGES (DecompressMethodNumber
* sizeof (EFI_GUID
*)));
120 ASSERT (DecompressGuidList
!= NULL
);
121 Status
= CustomDecompressGetAlgorithms (DecompressGuidList
, &DecompressMethodNumber
);
123 ASSERT_EFI_ERROR(Status
);
126 // Install custom decompress extraction guid ppi
128 if (DecompressMethodNumber
> 0) {
130 GuidPpi
= (EFI_PEI_PPI_DESCRIPTOR
*) AllocatePages (EFI_SIZE_TO_PAGES (DecompressMethodNumber
* sizeof (EFI_PEI_PPI_DESCRIPTOR
)));
131 ASSERT (GuidPpi
!= NULL
);
132 while (DecompressMethodNumber
-- > 0) {
133 GuidPpi
->Flags
= EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
;
134 GuidPpi
->Ppi
= &mCustomDecompressExtractiongPpi
;
135 GuidPpi
->Guid
= DecompressGuidList
[DecompressMethodNumber
];
136 Status
= PeiServicesInstallPpi (GuidPpi
++);
137 ASSERT_EFI_ERROR(Status
);
141 ASSERT_EFI_ERROR (FALSE
);
146 // Install FvFileLoader and DxeIpl PPIs.
148 Status
= PeiServicesInstallPpi (mPpiList
);
149 ASSERT_EFI_ERROR(Status
);
155 Main entry point to last PEIM
157 @param This Entry point for DXE IPL PPI
158 @param PeiServices General purpose services available to every PEIM.
159 @param HobList Address to the Pei HOB list
161 @return EFI_SUCCESS DXE core was successfully loaded.
162 @return EFI_OUT_OF_RESOURCES There are not enough resources to load DXE core.
167 IN EFI_DXE_IPL_PPI
*This
,
168 IN EFI_PEI_SERVICES
**PeiServices
,
169 IN EFI_PEI_HOB_POINTERS HobList
173 EFI_GUID DxeCoreFileName
;
174 EFI_PHYSICAL_ADDRESS DxeCoreAddress
;
176 EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint
;
177 EFI_PEI_PE_COFF_LOADER_PROTOCOL
*PeiEfiPeiPeCoffLoader
;
178 EFI_BOOT_MODE BootMode
;
179 EFI_PEI_FV_HANDLE VolumeHandle
;
180 EFI_PEI_FILE_HANDLE FileHandle
;
184 // if in S3 Resume, restore configure
186 Status
= PeiServicesGetBootMode (&BootMode
);
187 ASSERT_EFI_ERROR(Status
);
189 if (BootMode
== BOOT_ON_S3_RESUME
) {
190 Status
= AcpiS3ResumeOs();
191 ASSERT_EFI_ERROR (Status
);
192 } else if (BootMode
== BOOT_IN_RECOVERY_MODE
) {
193 Status
= PeiRecoverFirmware ();
194 if (EFI_ERROR (Status
)) {
195 DEBUG ((EFI_D_ERROR
, "Load Recovery Capsule Failed.(Status = %r)\n", Status
));
200 // Now should have a HOB with the DXE core w/ the old HOB destroyed
205 // Install the PEI Protocols that are shared between PEI and DXE
207 PeiEfiPeiPeCoffLoader
= (EFI_PEI_PE_COFF_LOADER_PROTOCOL
*) GetPeCoffLoaderProtocol ();
208 ASSERT (PeiEfiPeiPeCoffLoader
!= NULL
);
211 // If any FV contains an encapsulated FV extract that FV
213 DxeIplAddEncapsulatedFirmwareVolumes ();
216 // Look in all the FVs present in PEI and find the DXE Core
219 Status
= DxeIplFindFirmwareVolumeInstance (&Instance
, EFI_FV_FILETYPE_DXE_CORE
, &VolumeHandle
, &FileHandle
);
220 ASSERT_EFI_ERROR (Status
);
222 CopyMem(&DxeCoreFileName
, &(((EFI_FFS_FILE_HEADER
*)FileHandle
)->Name
), sizeof (EFI_GUID
));
225 // Load the DXE Core from a Firmware Volume
227 Status
= PeiLoadFile (
234 ASSERT_EFI_ERROR (Status
);
237 // Add HOB for the DXE Core
247 // Add HOB for the PE/COFF Loader Protocol
250 &gEfiPeiPeCoffLoaderGuid
,
251 (VOID
*)&PeiEfiPeiPeCoffLoader
,
255 // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT
259 EFI_SOFTWARE_PEI_MODULE
| EFI_SW_PEI_CORE_PC_HANDOFF_TO_NEXT
263 // Transfer control to the DXE Core
264 // The handoff state is simply a pointer to the HOB list
266 DEBUG ((EFI_D_INFO
, "DXE Core Entry Point 0x%08x\n", (UINTN
) DxeCoreEntryPoint
));
267 HandOffToDxeCore (DxeCoreEntryPoint
, HobList
, &mPpiSignal
);
269 // If we get here, then the DXE Core returned. This is an error
270 // Dxe Core should not return.
275 return EFI_OUT_OF_RESOURCES
;
282 IN EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
,
283 OUT UINT32
*FvAlignment
287 // Because FvLength in FvHeader is UINT64 type,
288 // so FvHeader must meed at least 8 bytes alignment.
289 // Get the appropriate alignment requirement.
291 if ((FvHeader
->Attributes
& EFI_FVB2_ALIGNMENT
) < EFI_FVB2_ALIGNMENT_8
) {
292 return EFI_UNSUPPORTED
;
295 *FvAlignment
= 1 << ((FvHeader
->Attributes
& EFI_FVB2_ALIGNMENT
) >> 16);
300 Search EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE image and expand
303 @return EFI_OUT_OF_RESOURCES There are no memory space to exstract FV
304 @return EFI_SUCESS Sucess to find the FV
307 DxeIplAddEncapsulatedFirmwareVolumes (
312 EFI_STATUS VolumeStatus
;
314 EFI_FV_INFO VolumeInfo
;
315 EFI_PEI_FV_HANDLE VolumeHandle
;
316 EFI_PEI_FILE_HANDLE FileHandle
;
317 UINT32 SectionLength
;
318 EFI_FIRMWARE_VOLUME_HEADER
*FvHeader
;
319 EFI_FIRMWARE_VOLUME_IMAGE_SECTION
*SectionHeader
;
323 Status
= EFI_NOT_FOUND
;
327 VolumeStatus
= DxeIplFindFirmwareVolumeInstance (
329 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
,
334 if (!EFI_ERROR (VolumeStatus
)) {
335 Status
= PeiServicesFfsFindSectionData (
336 EFI_SECTION_FIRMWARE_VOLUME_IMAGE
,
337 (EFI_FFS_FILE_HEADER
*)FileHandle
,
341 if (!EFI_ERROR (Status
)) {
342 if (FvHeader
->Signature
== EFI_FVH_SIGNATURE
) {
344 // Because FvLength in FvHeader is UINT64 type,
345 // so FvHeader must meed at least 8 bytes alignment.
346 // If current FvImage base address doesn't meet its alignment,
347 // we need to reload this FvImage to another correct memory address.
349 Status
= GetFvAlignment(FvHeader
, &FvAlignment
);
350 if (EFI_ERROR(Status
)) {
353 if (((UINTN
) FvHeader
% FvAlignment
) != 0) {
354 SectionHeader
= (EFI_FIRMWARE_VOLUME_IMAGE_SECTION
*)((UINTN
)FvHeader
- sizeof(EFI_FIRMWARE_VOLUME_IMAGE_SECTION
));
355 SectionLength
= *(UINT32
*)SectionHeader
->Size
& 0x00FFFFFF;
357 DstBuffer
= AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINTN
) SectionLength
- sizeof (EFI_COMMON_SECTION_HEADER
)), FvAlignment
);
358 if (DstBuffer
== NULL
) {
359 return EFI_OUT_OF_RESOURCES
;
361 CopyMem (DstBuffer
, FvHeader
, (UINTN
) SectionLength
- sizeof (EFI_COMMON_SECTION_HEADER
));
362 FvHeader
= (EFI_FIRMWARE_VOLUME_HEADER
*) DstBuffer
;
366 // This new Firmware Volume comes from a firmware file within a firmware volume.
367 // Record the original Firmware Volume Name.
369 PeiServicesFfsGetVolumeInfo (&VolumeHandle
, &VolumeInfo
);
371 PeiPiLibBuildPiFvInfoPpi (
372 (EFI_PHYSICAL_ADDRESS
) FvHeader
,
374 &(VolumeInfo
.FvName
),
375 &(((EFI_FFS_FILE_HEADER
*)FileHandle
)->Name
)
378 ASSERT_EFI_ERROR (Status
);
381 // Makes the encapsulated volume show up in DXE phase to skip processing of
382 // encapsulated file again.
385 (EFI_PHYSICAL_ADDRESS
)(UINTN
)FvHeader
,
388 &(((EFI_FFS_FILE_HEADER
*)FileHandle
)->Name
)
394 } while (!EFI_ERROR (VolumeStatus
));
400 Find the First Volume that contains the first FileType.
402 @param Instance The Fv instance.
403 @param SeachType The type of file to search.
404 @param VolumeHandle Pointer to Fv which contains the file to search.
405 @param FileHandle Pointer to FFS file to search.
407 @return EFI_SUCESS Success to find the FFS in specificed FV
408 @return others Fail to find the FFS in specificed FV
411 DxeIplFindFirmwareVolumeInstance (
412 IN OUT UINTN
*Instance
,
413 IN EFI_FV_FILETYPE SeachType
,
414 OUT EFI_PEI_FV_HANDLE
*VolumeHandle
,
415 OUT EFI_PEI_FILE_HANDLE
*FileHandle
419 EFI_STATUS VolumeStatus
;
422 VolumeStatus
= PeiServicesFfsFindNextVolume (*Instance
, VolumeHandle
);
423 if (!EFI_ERROR (VolumeStatus
)) {
425 Status
= PeiServicesFfsFindNextFile (SeachType
, *VolumeHandle
, FileHandle
);
426 if (!EFI_ERROR (Status
)) {
431 } while (!EFI_ERROR (VolumeStatus
));
437 Loads and relocates a PE/COFF image into memory.
439 @param FileHandle The image file handle
440 @param ImageAddress The base address of the relocated PE/COFF image
441 @param ImageSize The size of the relocated PE/COFF image
442 @param EntryPoint The entry point of the relocated PE/COFF image
444 @return EFI_SUCCESS The file was loaded and relocated
445 @return EFI_OUT_OF_RESOURCES There was not enough memory to load and relocate the PE/COFF file
449 IN EFI_PEI_FILE_HANDLE FileHandle
,
450 OUT EFI_PHYSICAL_ADDRESS
*ImageAddress
,
451 OUT UINT64
*ImageSize
,
452 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
457 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
459 EFI_PEI_PE_COFF_LOADER_PROTOCOL
*PeiEfiPeiPeCoffLoader
;
461 PeiEfiPeiPeCoffLoader
= (EFI_PEI_PE_COFF_LOADER_PROTOCOL
*)GetPeCoffLoaderProtocol ();
463 // First try to find the required section in this ffs file.
465 Status
= PeiServicesFfsFindSectionData (
471 if (EFI_ERROR (Status
)) {
472 Status
= PeiServicesFfsFindSectionData (
479 if (EFI_ERROR (Status
)) {
481 // NO image types we support so exit.
486 ZeroMem (&ImageContext
, sizeof (ImageContext
));
487 ImageContext
.Handle
= Pe32Data
;
488 Status
= GetImageReadFunction (&ImageContext
);
490 ASSERT_EFI_ERROR (Status
);
492 Status
= PeiEfiPeiPeCoffLoader
->GetImageInfo (PeiEfiPeiPeCoffLoader
, &ImageContext
);
493 if (EFI_ERROR (Status
)) {
497 // Allocate Memory for the image
499 ImageContext
.ImageAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32
) ImageContext
.ImageSize
));
500 ASSERT (ImageContext
.ImageAddress
!= 0);
503 // Load the image to our new buffer
505 Status
= PeiEfiPeiPeCoffLoader
->LoadImage (PeiEfiPeiPeCoffLoader
, &ImageContext
);
506 if (EFI_ERROR (Status
)) {
510 // Relocate the image in our new buffer
512 Status
= PeiEfiPeiPeCoffLoader
->RelocateImage (PeiEfiPeiPeCoffLoader
, &ImageContext
);
513 if (EFI_ERROR (Status
)) {
518 // Flush the instruction cache so the image data is written before we execute it
520 InvalidateInstructionCacheRange ((VOID
*)(UINTN
)ImageContext
.ImageAddress
, (UINTN
)ImageContext
.ImageSize
);
522 *ImageAddress
= ImageContext
.ImageAddress
;
523 *ImageSize
= ImageContext
.ImageSize
;
524 *EntryPoint
= ImageContext
.EntryPoint
;
530 The ExtractSection() function processes the input section and
531 returns a pointer to the section contents. If the section being
532 extracted does not require processing (if the section
533 GuidedSectionHeader.Attributes has the
534 EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then
535 OutputBuffer is just updated to point to the start of the
536 section's contents. Otherwise, *Buffer must be allocated
537 from PEI permanent memory.
539 @param This Indicates the
540 EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance.
541 Buffer containing the input GUIDed section to be
542 processed. OutputBuffer OutputBuffer is
543 allocated from PEI permanent memory and contains
544 the new section stream.
546 @param OutputSize A pointer to a caller-allocated
547 UINTN in which the size of *OutputBuffer
548 allocation is stored. If the function
549 returns anything other than EFI_SUCCESS,
550 the value of OutputSize is undefined.
552 @param AuthenticationStatus A pointer to a caller-allocated
553 UINT32 that indicates the
554 authentication status of the
555 output buffer. If the input
556 section's GuidedSectionHeader.
557 Attributes field has the
558 EFI_GUIDED_SECTION_AUTH_STATUS_VALID
560 AuthenticationStatus must return
561 zero. These bits reflect the
562 status of the extraction
563 operation. If the function
564 returns anything other than
565 EFI_SUCCESS, the value of
566 AuthenticationStatus is
569 @retval EFI_SUCCESS The InputSection was
570 successfully processed and the
571 section contents were returned.
573 @retval EFI_OUT_OF_RESOURCES The system has insufficient
574 resources to process the request.
576 @reteval EFI_INVALID_PARAMETER The GUID in InputSection does
577 not match this instance of the
578 GUIDed Section Extraction PPI.
581 CustomDecompressExtractSection (
582 IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI
*This
,
583 IN CONST VOID
*InputSection
,
584 OUT VOID
**OutputBuffer
,
585 OUT UINTN
*OutputSize
,
586 OUT UINT32
*AuthenticationStatus
590 UINT8
*ScratchBuffer
;
592 UINT32 SectionLength
;
593 UINT32 DestinationSize
;
596 // Set authentic value to zero.
598 *AuthenticationStatus
= 0;
600 // Calculate Section data Size
602 SectionLength
= *(UINT32
*) (((EFI_COMMON_SECTION_HEADER
*) InputSection
)->Size
) & 0x00ffffff;
604 // Get compressed data information
606 Status
= CustomDecompressGetInfo (
607 (GUID
*) ((UINT8
*) InputSection
+ sizeof (EFI_COMMON_SECTION_HEADER
)),
608 (UINT8
*) InputSection
+ sizeof (EFI_GUID_DEFINED_SECTION
),
609 SectionLength
- sizeof (EFI_GUID_DEFINED_SECTION
),
613 if (EFI_ERROR (Status
)) {
617 DEBUG ((EFI_D_ERROR
, "Extract guided section Failed - %r\n", Status
));
622 // Allocate scratch buffer
624 ScratchBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (ScratchSize
));
625 if (ScratchBuffer
== NULL
) {
626 return EFI_OUT_OF_RESOURCES
;
629 // Allocate destination buffer
631 *OutputSize
= (UINTN
) DestinationSize
;
632 *OutputBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (*OutputSize
));
633 if (*OutputBuffer
== NULL
) {
634 return EFI_OUT_OF_RESOURCES
;
638 // Call decompress function
640 Status
= CustomDecompress (
641 (GUID
*) ((UINT8
*) InputSection
+ sizeof (EFI_COMMON_SECTION_HEADER
)),
642 (UINT8
*) InputSection
+ sizeof (EFI_GUID_DEFINED_SECTION
),
647 if (EFI_ERROR (Status
)) {
651 DEBUG ((EFI_D_ERROR
, "Extract guided section Failed - %r\n", Status
));
662 IN CONST EFI_PEI_DECOMPRESS_PPI
*This
,
663 IN CONST EFI_COMPRESSION_SECTION
*CompressionSection
,
664 OUT VOID
**OutputBuffer
,
665 OUT UINTN
*OutputSize
670 UINT8
*ScratchBuffer
;
672 UINT32 ScratchBufferSize
;
673 EFI_COMMON_SECTION_HEADER
*Section
;
676 if (CompressionSection
->CommonHeader
.Type
!= EFI_SECTION_COMPRESSION
) {
678 return EFI_INVALID_PARAMETER
;
681 Section
= (EFI_COMMON_SECTION_HEADER
*) CompressionSection
;
682 SectionLength
= *(UINT32
*) (Section
->Size
) & 0x00ffffff;
685 // This is a compression set, expand it
687 switch (CompressionSection
->CompressionType
) {
688 case EFI_STANDARD_COMPRESSION
:
690 // Load EFI standard compression.
691 // For compressed data, decompress them to dstbuffer.
693 Status
= UefiDecompressGetInfo (
694 (UINT8
*) ((EFI_COMPRESSION_SECTION
*) Section
+ 1),
695 (UINT32
) SectionLength
- sizeof (EFI_COMPRESSION_SECTION
),
696 (UINT32
*) &DstBufferSize
,
699 if (EFI_ERROR (Status
)) {
703 DEBUG ((EFI_D_ERROR
, "Decompress GetInfo Failed - %r\n", Status
));
704 return EFI_NOT_FOUND
;
707 // Allocate scratch buffer
709 ScratchBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize
));
710 if (ScratchBuffer
== NULL
) {
711 return EFI_OUT_OF_RESOURCES
;
714 // Allocate destination buffer
716 DstBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize
));
717 if (DstBuffer
== NULL
) {
718 return EFI_OUT_OF_RESOURCES
;
721 // Call decompress function
723 Status
= UefiDecompress (
724 (CHAR8
*) ((EFI_COMPRESSION_SECTION
*) Section
+ 1),
728 if (EFI_ERROR (Status
)) {
732 DEBUG ((EFI_D_ERROR
, "Decompress Failed - %r\n", Status
));
733 return EFI_NOT_FOUND
;
737 // porting note the original branch for customized compress is removed, it should be change to use GUID compress
739 case EFI_NOT_COMPRESSED
:
741 // Allocate destination buffer
743 DstBufferSize
= CompressionSection
->UncompressedLength
;
744 DstBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize
));
745 if (DstBuffer
== NULL
) {
746 return EFI_OUT_OF_RESOURCES
;
749 // stream is not actually compressed, just encapsulated. So just copy it.
751 CopyMem (DstBuffer
, CompressionSection
+ 1, DstBufferSize
);
756 // Don't support other unknown compression type.
759 return EFI_NOT_FOUND
;
762 *OutputSize
= DstBufferSize
;
763 *OutputBuffer
= DstBuffer
;