3 Responsibility of this module is to load the DXE Core from a Firmware Volume.
5 Copyright (c) 2006 - 2008, Intel Corporation. <BR>
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.
19 // This global variable indicates whether this module has been shadowed
22 BOOLEAN gInMemory
= FALSE
;
25 // Module Globals used in the DXE to PEI handoff
26 // These must be module globals, so the stack can be switched
28 CONST EFI_DXE_IPL_PPI mDxeIplPpi
= {
32 CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI mCustomGuidedSectionExtractionPpi
= {
33 CustomGuidedSectionExtract
36 CONST EFI_PEI_DECOMPRESS_PPI mDecompressPpi
= {
40 CONST EFI_PEI_PPI_DESCRIPTOR mPpiList
[] = {
42 EFI_PEI_PPI_DESCRIPTOR_PPI
,
47 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
48 &gEfiPeiDecompressPpiGuid
,
49 (VOID
*) &mDecompressPpi
53 CONST EFI_PEI_PPI_DESCRIPTOR gEndOfPeiSignalPpi
= {
54 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
55 &gEfiEndOfPeiSignalPpiGuid
,
60 Initializes the Dxe Ipl PPI
62 @param FfsHandle The handle of FFS file.
63 @param PeiServices General purpose services available to
70 PeimInitializeDxeIpl (
71 IN EFI_PEI_FILE_HANDLE FfsHandle
,
72 IN EFI_PEI_SERVICES
**PeiServices
76 EFI_BOOT_MODE BootMode
;
77 EFI_GUID
*ExtractHandlerGuidTable
;
78 UINTN ExtractHandlerNumber
;
79 EFI_PEI_PPI_DESCRIPTOR
*GuidPpi
;
81 BootMode
= GetBootModeHob ();
83 if (BootMode
!= BOOT_ON_S3_RESUME
) {
84 Status
= PeiServicesRegisterForShadow (FfsHandle
);
85 if (Status
== EFI_SUCCESS
) {
87 // EFI_SUCESS means the first time call register for shadow
90 } else if (Status
== EFI_ALREADY_STARTED
) {
93 // Get custom extract guided section method guid list
95 ExtractHandlerNumber
= ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable
);
98 // Install custom extraction guid ppi
100 if (ExtractHandlerNumber
> 0) {
101 GuidPpi
= (EFI_PEI_PPI_DESCRIPTOR
*) AllocatePool (ExtractHandlerNumber
* sizeof (EFI_PEI_PPI_DESCRIPTOR
));
102 ASSERT (GuidPpi
!= NULL
);
103 while (ExtractHandlerNumber
-- > 0) {
104 GuidPpi
->Flags
= EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
;
105 GuidPpi
->Ppi
= (VOID
*) &mCustomGuidedSectionExtractionPpi
;
106 GuidPpi
->Guid
= &(ExtractHandlerGuidTable
[ExtractHandlerNumber
]);
107 Status
= PeiServicesInstallPpi (GuidPpi
++);
108 ASSERT_EFI_ERROR(Status
);
117 // Install DxeIpl and Decompress PPIs.
119 Status
= PeiServicesInstallPpi (mPpiList
);
120 ASSERT_EFI_ERROR(Status
);
126 Main entry point to last PEIM.
128 @param This Entry point for DXE IPL PPI.
129 @param PeiServices General purpose services available to every PEIM.
130 @param HobList Address to the Pei HOB list.
132 @return EFI_SUCCESS DXE core was successfully loaded.
133 @return EFI_OUT_OF_RESOURCES There are not enough resources to load DXE core.
139 IN CONST EFI_DXE_IPL_PPI
*This
,
140 IN EFI_PEI_SERVICES
**PeiServices
,
141 IN EFI_PEI_HOB_POINTERS HobList
145 EFI_FV_FILE_INFO DxeCoreFileInfo
;
146 EFI_PHYSICAL_ADDRESS DxeCoreAddress
;
148 EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint
;
149 EFI_BOOT_MODE BootMode
;
150 EFI_PEI_FILE_HANDLE FileHandle
;
151 EFI_PEI_READ_ONLY_VARIABLE2_PPI
*Variable
;
153 EFI_MEMORY_TYPE_INFORMATION MemoryData
[EfiMaxMemoryType
+ 1];
156 // if in S3 Resume, restore configure
158 BootMode
= GetBootModeHob ();
160 if (BootMode
== BOOT_ON_S3_RESUME
) {
161 Status
= AcpiS3ResumeOs();
162 ASSERT_EFI_ERROR (Status
);
163 } else if (BootMode
== BOOT_IN_RECOVERY_MODE
) {
164 Status
= PeiRecoverFirmware ();
165 if (EFI_ERROR (Status
)) {
166 DEBUG ((DEBUG_ERROR
, "Load Recovery Capsule Failed.(Status = %r)\n", Status
));
171 // Now should have a HOB with the DXE core w/ the old HOB destroyed
175 Status
= PeiServicesLocatePpi (
176 &gEfiPeiReadOnlyVariable2PpiGuid
,
181 if (!EFI_ERROR (Status
)) {
182 DataSize
= sizeof (MemoryData
);
183 Status
= Variable
->GetVariable (
185 EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME
,
186 &gEfiMemoryTypeInformationGuid
,
191 if (!EFI_ERROR (Status
)) {
193 // Build the GUID'd HOB for DXE
196 &gEfiMemoryTypeInformationGuid
,
204 // Look in all the FVs present in PEI and find the DXE Core FileHandle
206 FileHandle
= DxeIplFindDxeCore ();
209 // Load the DXE Core from a Firmware Volume, may use LoadFile ppi to do this for save code size.
211 Status
= PeiLoadFile (
217 ASSERT_EFI_ERROR (Status
);
220 // Get the DxeCore File Info from the FileHandle for the DxeCore GUID file name.
222 Status
= PeiServicesFfsGetFileInfo (FileHandle
, &DxeCoreFileInfo
);
223 ASSERT_EFI_ERROR (Status
);
226 // Add HOB for the DXE Core
229 &DxeCoreFileInfo
.FileName
,
231 EFI_SIZE_TO_PAGES ((UINTN
) DxeCoreSize
) * EFI_PAGE_SIZE
,
236 // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT
240 PcdGet32(PcdStatusCodeValuePeiHandoffToDxe
)
243 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Loading DXE CORE at 0x%11p EntryPoint=0x%11p\n", (VOID
*)(UINTN
)DxeCoreAddress
, FUNCTION_ENTRY_POINT (DxeCoreEntryPoint
)));
246 // Transfer control to the DXE Core
247 // The handoff state is simply a pointer to the HOB list
249 HandOffToDxeCore (DxeCoreEntryPoint
, HobList
);
251 // If we get here, then the DXE Core returned. This is an error
252 // Dxe Core should not return.
257 return EFI_OUT_OF_RESOURCES
;
262 Searches DxeCore in all firmware Volumes and loads the first
263 instance that contains DxeCore.
265 @return FileHandle of DxeCore to load DxeCore.
275 EFI_PEI_FV_HANDLE VolumeHandle
;
276 EFI_PEI_FILE_HANDLE FileHandle
;
281 // Traverse all firmware volume instances
283 Status
= PeiServicesFfsFindNextVolume (Instance
, &VolumeHandle
);
285 // If some error occurs here, then we cannot find any firmware
286 // volume that may contain DxeCore.
288 ASSERT_EFI_ERROR (Status
);
291 // Find the DxeCore file type from the beginning in this firmware volume.
294 Status
= PeiServicesFfsFindNextFile (EFI_FV_FILETYPE_DXE_CORE
, VolumeHandle
, &FileHandle
);
295 if (!EFI_ERROR (Status
)) {
297 // Find DxeCore FileHandle in this volume, then we skip other firmware volume and
298 // return the FileHandle.
303 // We cannot find DxeCore in this firmware volume, then search the next volume.
311 Loads and relocates a PE/COFF image into memory.
313 @param FileHandle The image file handle
314 @param ImageAddress The base address of the relocated PE/COFF image
315 @param ImageSize The size of the relocated PE/COFF image
316 @param EntryPoint The entry point of the relocated PE/COFF image
318 @return EFI_SUCCESS The file was loaded and relocated
319 @return EFI_OUT_OF_RESOURCES There was not enough memory to load and relocate the PE/COFF file
324 IN EFI_PEI_FILE_HANDLE FileHandle
,
325 OUT EFI_PHYSICAL_ADDRESS
*ImageAddress
,
326 OUT UINT64
*ImageSize
,
327 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
332 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
336 // First try to find the PE32 section in this ffs file.
338 Status
= PeiServicesFfsFindSectionData (
343 if (EFI_ERROR (Status
)) {
345 // NO image types we support so exit.
350 ZeroMem (&ImageContext
, sizeof (ImageContext
));
351 ImageContext
.Handle
= Pe32Data
;
352 Status
= GetImageReadFunction (&ImageContext
);
354 ASSERT_EFI_ERROR (Status
);
356 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
357 if (EFI_ERROR (Status
)) {
361 // Allocate Memory for the image
363 Status
= PeiServicesAllocatePages (
365 EFI_SIZE_TO_PAGES ((UINT32
) ImageContext
.ImageSize
),
366 &ImageContext
.ImageAddress
368 ASSERT_EFI_ERROR (Status
);
369 ASSERT (ImageContext
.ImageAddress
!= 0);
372 // Load the image to our new buffer
374 Status
= PeCoffLoaderLoadImage (&ImageContext
);
375 if (EFI_ERROR (Status
)) {
379 // Relocate the image in our new buffer
381 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
382 if (EFI_ERROR (Status
)) {
387 // Flush the instruction cache so the image data is written before we execute it
389 InvalidateInstructionCacheRange ((VOID
*)(UINTN
)ImageContext
.ImageAddress
, (UINTN
)ImageContext
.ImageSize
);
391 *ImageAddress
= ImageContext
.ImageAddress
;
392 *ImageSize
= ImageContext
.ImageSize
;
393 *EntryPoint
= ImageContext
.EntryPoint
;
402 The ExtractSection() function processes the input section and
403 returns a pointer to the section contents. If the section being
404 extracted does not require processing (if the section
405 GuidedSectionHeader.Attributes has the
406 EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then
407 OutputBuffer is just updated to point to the start of the
408 section's contents. Otherwise, *Buffer must be allocated
409 from PEI permanent memory.
411 @param This Indicates the
412 EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance.
413 Buffer containing the input GUIDed section to be
414 processed. OutputBuffer OutputBuffer is
415 allocated from PEI permanent memory and contains
416 the new section stream.
417 @param InputSection A pointer to the input buffer, which contains
418 the input section to be processed.
419 @param OutputBuffer A pointer to a caller-allocated buffer, whose
420 size is specified by the contents of OutputSize.
421 @param OutputSize A pointer to a caller-allocated
422 UINTN in which the size of *OutputBuffer
423 allocation is stored. If the function
424 returns anything other than EFI_SUCCESS,
425 the value of OutputSize is undefined.
426 @param AuthenticationStatus A pointer to a caller-allocated
427 UINT32 that indicates the
428 authentication status of the
429 output buffer. If the input
430 section's GuidedSectionHeader.
431 Attributes field has the
432 EFI_GUIDED_SECTION_AUTH_STATUS_VALID
434 AuthenticationStatus must return
435 zero. These bits reflect the
436 status of the extraction
437 operation. If the function
438 returns anything other than
439 EFI_SUCCESS, the value of
440 AuthenticationStatus is
443 @retval EFI_SUCCESS The InputSection was
444 successfully processed and the
445 section contents were returned.
447 @retval EFI_OUT_OF_RESOURCES The system has insufficient
448 resources to process the request.
450 @retval EFI_INVALID_PARAMETER The GUID in InputSection does
451 not match this instance of the
452 GUIDed Section Extraction PPI.
456 CustomGuidedSectionExtract (
457 IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI
*This
,
458 IN CONST VOID
*InputSection
,
459 OUT VOID
**OutputBuffer
,
460 OUT UINTN
*OutputSize
,
461 OUT UINT32
*AuthenticationStatus
465 UINT8
*ScratchBuffer
;
466 UINT32 ScratchBufferSize
;
467 UINT32 OutputBufferSize
;
468 UINT16 SectionAttribute
;
471 // Init local variable
473 ScratchBuffer
= NULL
;
476 // Call GetInfo to get the size and attribute of input guided section data.
478 Status
= ExtractGuidedSectionGetInfo (
485 if (EFI_ERROR (Status
)) {
486 DEBUG ((DEBUG_ERROR
, "GetInfo from guided section Failed - %r\n", Status
));
490 if (ScratchBufferSize
!= 0) {
492 // Allocate scratch buffer
494 ScratchBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize
));
495 if (ScratchBuffer
== NULL
) {
496 return EFI_OUT_OF_RESOURCES
;
500 if (((SectionAttribute
& EFI_GUIDED_SECTION_PROCESSING_REQUIRED
) != 0) && OutputBufferSize
> 0) {
502 // Allocate output buffer
504 *OutputBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (OutputBufferSize
) + 1);
505 if (*OutputBuffer
== NULL
) {
506 return EFI_OUT_OF_RESOURCES
;
508 DEBUG ((DEBUG_INFO
, "Customed Guided section Memory Size required is 0x%x and address is 0x%p\n", OutputBufferSize
, *OutputBuffer
));
510 // *OutputBuffer still is one section. Adjust *OutputBuffer offset,
511 // skip EFI section header to make section data at page alignment.
513 *OutputBuffer
= (VOID
*)((UINT8
*) *OutputBuffer
+ EFI_PAGE_SIZE
- sizeof (EFI_COMMON_SECTION_HEADER
));
516 Status
= ExtractGuidedSectionDecode (
522 if (EFI_ERROR (Status
)) {
526 DEBUG ((DEBUG_ERROR
, "Extract guided section Failed - %r\n", Status
));
530 *OutputSize
= (UINTN
) OutputBufferSize
;
538 Decompresses a section to the output buffer.
540 This function lookes up the compression type field in the input section and
541 applies the appropriate compression algorithm to compress the section to a
542 callee allocated buffer.
544 @param This Points to this instance of the
545 EFI_PEI_DECOMPRESS_PEI PPI.
546 @param CompressionSection Points to the compressed section.
547 @param OutputBuffer Holds the returned pointer to the decompressed
549 @param OutputSize Holds the returned size of the decompress
552 @retval EFI_SUCCESS The section was decompressed successfully.
553 OutputBuffer contains the resulting data and
554 OutputSize contains the resulting size.
560 IN CONST EFI_PEI_DECOMPRESS_PPI
*This
,
561 IN CONST EFI_COMPRESSION_SECTION
*CompressionSection
,
562 OUT VOID
**OutputBuffer
,
563 OUT UINTN
*OutputSize
568 UINT8
*ScratchBuffer
;
570 UINT32 ScratchBufferSize
;
571 EFI_COMMON_SECTION_HEADER
*Section
;
574 if (CompressionSection
->CommonHeader
.Type
!= EFI_SECTION_COMPRESSION
) {
576 return EFI_INVALID_PARAMETER
;
579 Section
= (EFI_COMMON_SECTION_HEADER
*) CompressionSection
;
580 SectionLength
= *(UINT32
*) (Section
->Size
) & 0x00ffffff;
583 // This is a compression set, expand it
585 switch (CompressionSection
->CompressionType
) {
586 case EFI_STANDARD_COMPRESSION
:
588 // Load EFI standard compression.
589 // For compressed data, decompress them to dstbuffer.
591 Status
= UefiDecompressGetInfo (
592 (UINT8
*) ((EFI_COMPRESSION_SECTION
*) Section
+ 1),
593 (UINT32
) SectionLength
- sizeof (EFI_COMPRESSION_SECTION
),
594 (UINT32
*) &DstBufferSize
,
597 if (EFI_ERROR (Status
)) {
601 DEBUG ((DEBUG_ERROR
, "Decompress GetInfo Failed - %r\n", Status
));
602 return EFI_NOT_FOUND
;
605 // Allocate scratch buffer
607 ScratchBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize
));
608 if (ScratchBuffer
== NULL
) {
609 return EFI_OUT_OF_RESOURCES
;
612 // Allocate destination buffer, extra one page for adjustment
614 DstBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize
) + 1);
615 if (DstBuffer
== NULL
) {
616 return EFI_OUT_OF_RESOURCES
;
619 // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header
620 // to make section data at page alignment.
622 DstBuffer
= DstBuffer
+ EFI_PAGE_SIZE
- sizeof (EFI_COMMON_SECTION_HEADER
);
624 // Call decompress function
626 Status
= UefiDecompress (
627 (CHAR8
*) ((EFI_COMPRESSION_SECTION
*) Section
+ 1),
631 if (EFI_ERROR (Status
)) {
635 DEBUG ((DEBUG_ERROR
, "Decompress Failed - %r\n", Status
));
636 return EFI_NOT_FOUND
;
640 case EFI_NOT_COMPRESSED
:
642 // Allocate destination buffer
644 DstBufferSize
= CompressionSection
->UncompressedLength
;
645 DstBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize
) + 1);
646 if (DstBuffer
== NULL
) {
647 return EFI_OUT_OF_RESOURCES
;
650 // Adjust DstBuffer offset, skip EFI section header
651 // to make section data at page alignment.
653 DstBuffer
= DstBuffer
+ EFI_PAGE_SIZE
- sizeof (EFI_COMMON_SECTION_HEADER
);
655 // stream is not actually compressed, just encapsulated. So just copy it.
657 CopyMem (DstBuffer
, CompressionSection
+ 1, DstBufferSize
);
662 // Don't support other unknown compression type.
665 return EFI_NOT_FOUND
;
668 *OutputSize
= DstBufferSize
;
669 *OutputBuffer
= DstBuffer
;
678 Updates the Stack HOB passed to DXE phase.
680 This function traverses the whole HOB list and update the stack HOB to
681 reflect the real stack that is used by DXE core.
683 @param BaseAddress The lower address of stack used by DxeCore.
684 @param Length The length of stack used by DxeCore.
689 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
693 EFI_PEI_HOB_POINTERS Hob
;
695 Hob
.Raw
= GetHobList ();
696 while ((Hob
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, Hob
.Raw
)) != NULL
) {
697 if (CompareGuid (&gEfiHobMemoryAllocStackGuid
, &(Hob
.MemoryAllocationStack
->AllocDescriptor
.Name
))) {
699 // Build a new memory allocation HOB with old stack info with EfiConventionalMemory type
700 // to be reclaimed by DXE core.
702 BuildMemoryAllocationHob (
703 Hob
.MemoryAllocationStack
->AllocDescriptor
.MemoryBaseAddress
,
704 Hob
.MemoryAllocationStack
->AllocDescriptor
.MemoryLength
,
705 EfiConventionalMemory
708 // Update the BSP Stack Hob to reflect the new stack info.
710 Hob
.MemoryAllocationStack
->AllocDescriptor
.MemoryBaseAddress
= BaseAddress
;
711 Hob
.MemoryAllocationStack
->AllocDescriptor
.MemoryLength
= Length
;
714 Hob
.Raw
= GET_NEXT_HOB (Hob
);