3 Responsibility of this module is to load the DXE Core from a Firmware Volume.
5 Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
6 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.
20 // Module Globals used in the DXE to PEI hand off
21 // These must be module globals, so the stack can be switched
23 CONST EFI_DXE_IPL_PPI mDxeIplPpi
= {
27 CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI mCustomGuidedSectionExtractionPpi
= {
28 CustomGuidedSectionExtract
31 CONST EFI_PEI_DECOMPRESS_PPI mDecompressPpi
= {
35 CONST EFI_PEI_PPI_DESCRIPTOR mPpiList
[] = {
37 EFI_PEI_PPI_DESCRIPTOR_PPI
,
42 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
43 &gEfiPeiDecompressPpiGuid
,
44 (VOID
*) &mDecompressPpi
48 CONST EFI_PEI_PPI_DESCRIPTOR gEndOfPeiSignalPpi
= {
49 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
50 &gEfiEndOfPeiSignalPpiGuid
,
55 Entry point of DXE IPL PEIM.
57 This function installs DXE IPL PPI and Decompress PPI. It also reloads
58 itself to memory on non-S3 resume boot path.
60 @param FileHandle Handle of the file being invoked.
61 @param PeiServices Describes the list of possible PEI Services.
63 @retval EFI_SUCESS The entry point of DXE IPL PEIM executes successfully.
64 @retval Others Some error occurs during the execution of this function.
69 PeimInitializeDxeIpl (
70 IN EFI_PEI_FILE_HANDLE FileHandle
,
71 IN CONST EFI_PEI_SERVICES
**PeiServices
75 EFI_BOOT_MODE BootMode
;
76 EFI_GUID
*ExtractHandlerGuidTable
;
77 UINTN ExtractHandlerNumber
;
78 EFI_PEI_PPI_DESCRIPTOR
*GuidPpi
;
80 BootMode
= GetBootModeHob ();
82 if (BootMode
!= BOOT_ON_S3_RESUME
) {
83 Status
= PeiServicesRegisterForShadow (FileHandle
);
84 if (Status
== EFI_SUCCESS
) {
86 // EFI_SUCESS means it is the first time to call register for shadow.
92 // Ensure that DXE IPL is shadowed to permanent memory.
94 ASSERT (Status
== EFI_ALREADY_STARTED
);
97 // Get custom extract guided section method guid list
99 ExtractHandlerNumber
= ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable
);
102 // Install custom extraction guid PPI
104 if (ExtractHandlerNumber
> 0) {
105 GuidPpi
= (EFI_PEI_PPI_DESCRIPTOR
*) AllocatePool (ExtractHandlerNumber
* sizeof (EFI_PEI_PPI_DESCRIPTOR
));
106 ASSERT (GuidPpi
!= NULL
);
107 while (ExtractHandlerNumber
-- > 0) {
108 GuidPpi
->Flags
= EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
;
109 GuidPpi
->Ppi
= (VOID
*) &mCustomGuidedSectionExtractionPpi
;
110 GuidPpi
->Guid
= &ExtractHandlerGuidTable
[ExtractHandlerNumber
];
111 Status
= PeiServicesInstallPpi (GuidPpi
++);
112 ASSERT_EFI_ERROR(Status
);
119 // Install DxeIpl and Decompress PPIs.
121 Status
= PeiServicesInstallPpi (mPpiList
);
122 ASSERT_EFI_ERROR(Status
);
128 Validate variable data for the MemoryTypeInformation.
130 @param MemoryData Variable data.
131 @param MemoryDataSize Variable data length.
133 @return TRUE The variable data is valid.
134 @return FALSE The variable data is invalid.
138 ValidateMemoryTypeInfoVariable (
139 IN EFI_MEMORY_TYPE_INFORMATION
*MemoryData
,
140 IN UINTN MemoryDataSize
146 // Check the input parameter.
147 if (MemoryData
== NULL
) {
152 Count
= MemoryDataSize
/ sizeof (*MemoryData
);
155 if (Count
* sizeof(*MemoryData
) != MemoryDataSize
) {
159 // Check last entry type filed.
160 if (MemoryData
[Count
- 1].Type
!= EfiMaxMemoryType
) {
164 // Check the type filed.
165 for (Index
= 0; Index
< Count
- 1; Index
++) {
166 if (MemoryData
[Index
].Type
>= EfiMaxMemoryType
) {
175 Main entry point to last PEIM.
177 This function finds DXE Core in the firmware volume and transfer the control to
180 @param This Entry point for DXE IPL PPI.
181 @param PeiServices General purpose services available to every PEIM.
182 @param HobList Address to the Pei HOB list.
184 @return EFI_SUCCESS DXE core was successfully loaded.
185 @return EFI_OUT_OF_RESOURCES There are not enough resources to load DXE core.
191 IN CONST EFI_DXE_IPL_PPI
*This
,
192 IN EFI_PEI_SERVICES
**PeiServices
,
193 IN EFI_PEI_HOB_POINTERS HobList
197 EFI_FV_FILE_INFO DxeCoreFileInfo
;
198 EFI_PHYSICAL_ADDRESS DxeCoreAddress
;
200 EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint
;
201 EFI_BOOT_MODE BootMode
;
202 EFI_PEI_FILE_HANDLE FileHandle
;
203 EFI_PEI_READ_ONLY_VARIABLE2_PPI
*Variable
;
204 EFI_PEI_LOAD_FILE_PPI
*LoadFile
;
206 UINT32 AuthenticationState
;
208 EFI_PEI_S3_RESUME2_PPI
*S3Resume
;
209 EFI_PEI_RECOVERY_MODULE_PPI
*PeiRecovery
;
210 EFI_MEMORY_TYPE_INFORMATION MemoryData
[EfiMaxMemoryType
+ 1];
213 // if in S3 Resume, restore configure
215 BootMode
= GetBootModeHob ();
217 if (BootMode
== BOOT_ON_S3_RESUME
) {
218 Status
= PeiServicesLocatePpi (
219 &gEfiPeiS3Resume2PpiGuid
,
224 if (EFI_ERROR (Status
)) {
226 // Report Status code that S3Resume PPI can not be found
229 EFI_ERROR_CODE
| EFI_ERROR_MAJOR
,
230 (EFI_SOFTWARE_PEI_MODULE
| EFI_SW_PEI_EC_S3_RESUME_PPI_NOT_FOUND
)
233 ASSERT_EFI_ERROR (Status
);
235 Status
= S3Resume
->S3RestoreConfig2 (S3Resume
);
236 ASSERT_EFI_ERROR (Status
);
237 } else if (BootMode
== BOOT_IN_RECOVERY_MODE
) {
238 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_PEI_MODULE
| EFI_SW_PEI_PC_RECOVERY_BEGIN
));
239 Status
= PeiServicesLocatePpi (
240 &gEfiPeiRecoveryModulePpiGuid
,
243 (VOID
**) &PeiRecovery
246 // Report Status code the failure of locating Recovery PPI
249 EFI_ERROR_CODE
| EFI_ERROR_MAJOR
,
250 (EFI_SOFTWARE_PEI_MODULE
| EFI_SW_PEI_EC_RECOVERY_PPI_NOT_FOUND
)
252 ASSERT_EFI_ERROR (Status
);
253 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_PEI_MODULE
| EFI_SW_PEI_PC_CAPSULE_LOAD
));
254 Status
= PeiRecovery
->LoadRecoveryCapsule (PeiServices
, PeiRecovery
);
255 if (EFI_ERROR (Status
)) {
256 DEBUG ((DEBUG_ERROR
, "Load Recovery Capsule Failed.(Status = %r)\n", Status
));
258 // Report Status code that S3Resume PPI can not be found
261 EFI_ERROR_CODE
| EFI_ERROR_MAJOR
,
262 (EFI_SOFTWARE_PEI_MODULE
| EFI_SW_PEI_EC_NO_RECOVERY_CAPSULE
)
266 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_PEI_MODULE
| EFI_SW_PEI_PC_CAPSULE_START
));
268 // Now should have a HOB with the DXE core
272 Status
= PeiServicesLocatePpi (
273 &gEfiPeiReadOnlyVariable2PpiGuid
,
278 if (!EFI_ERROR (Status
)) {
279 DataSize
= sizeof (MemoryData
);
280 Status
= Variable
->GetVariable (
282 EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME
,
283 &gEfiMemoryTypeInformationGuid
,
288 if (!EFI_ERROR (Status
) && ValidateMemoryTypeInfoVariable(MemoryData
, DataSize
)) {
290 // Build the GUID'd HOB for DXE
293 &gEfiMemoryTypeInformationGuid
,
301 // Look in all the FVs present in PEI and find the DXE Core FileHandle
303 FileHandle
= DxeIplFindDxeCore ();
306 // Load the DXE Core from a Firmware Volume.
310 Status
= PeiServicesLocatePpi (&gEfiPeiLoadFilePpiGuid
, Instance
++, NULL
, (VOID
**) &LoadFile
);
312 // These must exist an instance of EFI_PEI_LOAD_FILE_PPI to support to load DxeCore file handle successfully.
314 ASSERT_EFI_ERROR (Status
);
316 Status
= LoadFile
->LoadFile (
324 } while (EFI_ERROR (Status
));
327 // Get the DxeCore File Info from the FileHandle for the DxeCore GUID file name.
329 Status
= PeiServicesFfsGetFileInfo (FileHandle
, &DxeCoreFileInfo
);
330 ASSERT_EFI_ERROR (Status
);
333 // Add HOB for the DXE Core
336 &DxeCoreFileInfo
.FileName
,
338 ALIGN_VALUE (DxeCoreSize
, EFI_PAGE_SIZE
),
343 // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT
345 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_PEI_CORE
| EFI_SW_PEI_CORE_PC_HANDOFF_TO_NEXT
));
347 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Loading DXE CORE at 0x%11p EntryPoint=0x%11p\n", (VOID
*)(UINTN
)DxeCoreAddress
, FUNCTION_ENTRY_POINT (DxeCoreEntryPoint
)));
350 // Transfer control to the DXE Core
351 // The hand off state is simply a pointer to the HOB list
353 HandOffToDxeCore (DxeCoreEntryPoint
, HobList
);
355 // If we get here, then the DXE Core returned. This is an error
356 // DxeCore should not return.
361 return EFI_OUT_OF_RESOURCES
;
366 Searches DxeCore in all firmware Volumes and loads the first
367 instance that contains DxeCore.
369 @return FileHandle of DxeCore to load DxeCore.
379 EFI_PEI_FV_HANDLE VolumeHandle
;
380 EFI_PEI_FILE_HANDLE FileHandle
;
385 // Traverse all firmware volume instances
387 Status
= PeiServicesFfsFindNextVolume (Instance
, &VolumeHandle
);
389 // If some error occurs here, then we cannot find any firmware
390 // volume that may contain DxeCore.
392 if (EFI_ERROR (Status
)) {
393 REPORT_STATUS_CODE (EFI_PROGRESS_CODE
, (EFI_SOFTWARE_PEI_MODULE
| EFI_SW_PEI_CORE_EC_DXE_CORRUPT
));
395 ASSERT_EFI_ERROR (Status
);
398 // Find the DxeCore file type from the beginning in this firmware volume.
401 Status
= PeiServicesFfsFindNextFile (EFI_FV_FILETYPE_DXE_CORE
, VolumeHandle
, &FileHandle
);
402 if (!EFI_ERROR (Status
)) {
404 // Find DxeCore FileHandle in this volume, then we skip other firmware volume and
405 // return the FileHandle.
410 // We cannot find DxeCore in this firmware volume, then search the next volume.
419 The ExtractSection() function processes the input section and
420 returns a pointer to the section contents. If the section being
421 extracted does not require processing (if the section
422 GuidedSectionHeader.Attributes has the
423 EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then
424 OutputBuffer is just updated to point to the start of the
425 section's contents. Otherwise, *Buffer must be allocated
426 from PEI permanent memory.
428 @param This Indicates the
429 EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance.
430 Buffer containing the input GUIDed section to be
431 processed. OutputBuffer OutputBuffer is
432 allocated from PEI permanent memory and contains
433 the new section stream.
434 @param InputSection A pointer to the input buffer, which contains
435 the input section to be processed.
436 @param OutputBuffer A pointer to a caller-allocated buffer, whose
437 size is specified by the contents of OutputSize.
438 @param OutputSize A pointer to a caller-allocated
439 UINTN in which the size of *OutputBuffer
440 allocation is stored. If the function
441 returns anything other than EFI_SUCCESS,
442 the value of OutputSize is undefined.
443 @param AuthenticationStatus A pointer to a caller-allocated
444 UINT32 that indicates the
445 authentication status of the
446 output buffer. If the input
447 section's GuidedSectionHeader.
448 Attributes field has the
449 EFI_GUIDED_SECTION_AUTH_STATUS_VALID
451 AuthenticationStatus must return
452 zero. These bits reflect the
453 status of the extraction
454 operation. If the function
455 returns anything other than
456 EFI_SUCCESS, the value of
457 AuthenticationStatus is
460 @retval EFI_SUCCESS The InputSection was
461 successfully processed and the
462 section contents were returned.
464 @retval EFI_OUT_OF_RESOURCES The system has insufficient
465 resources to process the request.
467 @retval EFI_INVALID_PARAMETER The GUID in InputSection does
468 not match this instance of the
469 GUIDed Section Extraction PPI.
474 CustomGuidedSectionExtract (
475 IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI
*This
,
476 IN CONST VOID
*InputSection
,
477 OUT VOID
**OutputBuffer
,
478 OUT UINTN
*OutputSize
,
479 OUT UINT32
*AuthenticationStatus
483 UINT8
*ScratchBuffer
;
484 UINT32 ScratchBufferSize
;
485 UINT32 OutputBufferSize
;
486 UINT16 SectionAttribute
;
489 // Init local variable
491 ScratchBuffer
= NULL
;
494 // Call GetInfo to get the size and attribute of input guided section data.
496 Status
= ExtractGuidedSectionGetInfo (
503 if (EFI_ERROR (Status
)) {
504 DEBUG ((DEBUG_ERROR
, "GetInfo from guided section Failed - %r\n", Status
));
508 if (ScratchBufferSize
!= 0) {
510 // Allocate scratch buffer
512 ScratchBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize
));
513 if (ScratchBuffer
== NULL
) {
514 return EFI_OUT_OF_RESOURCES
;
518 if (((SectionAttribute
& EFI_GUIDED_SECTION_PROCESSING_REQUIRED
) != 0) && OutputBufferSize
> 0) {
520 // Allocate output buffer
522 *OutputBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (OutputBufferSize
) + 1);
523 if (*OutputBuffer
== NULL
) {
524 return EFI_OUT_OF_RESOURCES
;
526 DEBUG ((DEBUG_INFO
, "Customized Guided section Memory Size required is 0x%x and address is 0x%p\n", OutputBufferSize
, *OutputBuffer
));
528 // *OutputBuffer still is one section. Adjust *OutputBuffer offset,
529 // skip EFI section header to make section data at page alignment.
531 *OutputBuffer
= (VOID
*)((UINT8
*) *OutputBuffer
+ EFI_PAGE_SIZE
- sizeof (EFI_COMMON_SECTION_HEADER
));
534 Status
= ExtractGuidedSectionDecode (
540 if (EFI_ERROR (Status
)) {
544 DEBUG ((DEBUG_ERROR
, "Extract guided section Failed - %r\n", Status
));
548 *OutputSize
= (UINTN
) OutputBufferSize
;
556 Decompresses a section to the output buffer.
558 This function looks up the compression type field in the input section and
559 applies the appropriate compression algorithm to compress the section to a
560 callee allocated buffer.
562 @param This Points to this instance of the
563 EFI_PEI_DECOMPRESS_PEI PPI.
564 @param CompressionSection Points to the compressed section.
565 @param OutputBuffer Holds the returned pointer to the decompressed
567 @param OutputSize Holds the returned size of the decompress
570 @retval EFI_SUCCESS The section was decompressed successfully.
571 OutputBuffer contains the resulting data and
572 OutputSize contains the resulting size.
578 IN CONST EFI_PEI_DECOMPRESS_PPI
*This
,
579 IN CONST EFI_COMPRESSION_SECTION
*CompressionSection
,
580 OUT VOID
**OutputBuffer
,
581 OUT UINTN
*OutputSize
586 UINT8
*ScratchBuffer
;
587 UINT32 DstBufferSize
;
588 UINT32 ScratchBufferSize
;
589 VOID
*CompressionSource
;
590 UINT32 CompressionSourceSize
;
591 UINT32 UncompressedLength
;
592 UINT8 CompressionType
;
594 if (CompressionSection
->CommonHeader
.Type
!= EFI_SECTION_COMPRESSION
) {
596 return EFI_INVALID_PARAMETER
;
599 if (IS_SECTION2 (CompressionSection
)) {
600 CompressionSource
= (VOID
*) ((UINT8
*) CompressionSection
+ sizeof (EFI_COMPRESSION_SECTION2
));
601 CompressionSourceSize
= (UINT32
) (SECTION2_SIZE (CompressionSection
) - sizeof (EFI_COMPRESSION_SECTION2
));
602 UncompressedLength
= ((EFI_COMPRESSION_SECTION2
*) CompressionSection
)->UncompressedLength
;
603 CompressionType
= ((EFI_COMPRESSION_SECTION2
*) CompressionSection
)->CompressionType
;
605 CompressionSource
= (VOID
*) ((UINT8
*) CompressionSection
+ sizeof (EFI_COMPRESSION_SECTION
));
606 CompressionSourceSize
= (UINT32
) (SECTION_SIZE (CompressionSection
) - sizeof (EFI_COMPRESSION_SECTION
));
607 UncompressedLength
= CompressionSection
->UncompressedLength
;
608 CompressionType
= CompressionSection
->CompressionType
;
612 // This is a compression set, expand it
614 switch (CompressionType
) {
615 case EFI_STANDARD_COMPRESSION
:
616 if (FeaturePcdGet(PcdDxeIplSupportUefiDecompress
)) {
618 // Load EFI standard compression.
619 // For compressed data, decompress them to destination buffer.
621 Status
= UefiDecompressGetInfo (
623 CompressionSourceSize
,
627 if (EFI_ERROR (Status
)) {
631 DEBUG ((DEBUG_ERROR
, "Decompress GetInfo Failed - %r\n", Status
));
632 return EFI_NOT_FOUND
;
635 // Allocate scratch buffer
637 ScratchBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize
));
638 if (ScratchBuffer
== NULL
) {
639 return EFI_OUT_OF_RESOURCES
;
642 // Allocate destination buffer, extra one page for adjustment
644 DstBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize
) + 1);
645 if (DstBuffer
== NULL
) {
646 return EFI_OUT_OF_RESOURCES
;
649 // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header
650 // to make section data at page alignment.
652 DstBuffer
= DstBuffer
+ EFI_PAGE_SIZE
- sizeof (EFI_COMMON_SECTION_HEADER
);
654 // Call decompress function
656 Status
= UefiDecompress (
661 if (EFI_ERROR (Status
)) {
665 DEBUG ((DEBUG_ERROR
, "Decompress Failed - %r\n", Status
));
666 return EFI_NOT_FOUND
;
671 // PcdDxeIplSupportUefiDecompress is FALSE
672 // Don't support UEFI decompression algorithm.
675 return EFI_NOT_FOUND
;
678 case EFI_NOT_COMPRESSED
:
680 // Allocate destination buffer
682 DstBufferSize
= UncompressedLength
;
683 DstBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize
) + 1);
684 if (DstBuffer
== NULL
) {
685 return EFI_OUT_OF_RESOURCES
;
688 // Adjust DstBuffer offset, skip EFI section header
689 // to make section data at page alignment.
691 DstBuffer
= DstBuffer
+ EFI_PAGE_SIZE
- sizeof (EFI_COMMON_SECTION_HEADER
);
693 // stream is not actually compressed, just encapsulated. So just copy it.
695 CopyMem (DstBuffer
, CompressionSource
, DstBufferSize
);
700 // Don't support other unknown compression type.
703 return EFI_NOT_FOUND
;
706 *OutputSize
= DstBufferSize
;
707 *OutputBuffer
= DstBuffer
;
714 Updates the Stack HOB passed to DXE phase.
716 This function traverses the whole HOB list and update the stack HOB to
717 reflect the real stack that is used by DXE core.
719 @param BaseAddress The lower address of stack used by DxeCore.
720 @param Length The length of stack used by DxeCore.
725 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
729 EFI_PEI_HOB_POINTERS Hob
;
731 Hob
.Raw
= GetHobList ();
732 while ((Hob
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, Hob
.Raw
)) != NULL
) {
733 if (CompareGuid (&gEfiHobMemoryAllocStackGuid
, &(Hob
.MemoryAllocationStack
->AllocDescriptor
.Name
))) {
735 // Build a new memory allocation HOB with old stack info with EfiBootServicesData type. Need to
736 // avoid this region be reclaimed by DXE core as the IDT built in SEC might be on stack, and some
737 // PEIMs may also keep key information on stack
739 BuildMemoryAllocationHob (
740 Hob
.MemoryAllocationStack
->AllocDescriptor
.MemoryBaseAddress
,
741 Hob
.MemoryAllocationStack
->AllocDescriptor
.MemoryLength
,
745 // Update the BSP Stack Hob to reflect the new stack info.
747 Hob
.MemoryAllocationStack
->AllocDescriptor
.MemoryBaseAddress
= BaseAddress
;
748 Hob
.MemoryAllocationStack
->AllocDescriptor
.MemoryLength
= Length
;
751 Hob
.Raw
= GET_NEXT_HOB (Hob
);