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 FileHandle Handle of the file being invoked.
63 @param PeiServices Describes the list of possible PEI Services.
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 the first time call register for shadow
89 } else if (Status
== EFI_ALREADY_STARTED
) {
92 // Get custom extract guided section method guid list
94 ExtractHandlerNumber
= ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable
);
97 // Install custom extraction guid ppi
99 if (ExtractHandlerNumber
> 0) {
100 GuidPpi
= (EFI_PEI_PPI_DESCRIPTOR
*) AllocatePool (ExtractHandlerNumber
* sizeof (EFI_PEI_PPI_DESCRIPTOR
));
101 ASSERT (GuidPpi
!= NULL
);
102 while (ExtractHandlerNumber
-- > 0) {
103 GuidPpi
->Flags
= EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
;
104 GuidPpi
->Ppi
= (VOID
*) &mCustomGuidedSectionExtractionPpi
;
105 GuidPpi
->Guid
= &(ExtractHandlerGuidTable
[ExtractHandlerNumber
]);
106 Status
= PeiServicesInstallPpi (GuidPpi
++);
107 ASSERT_EFI_ERROR(Status
);
116 // Install DxeIpl and Decompress PPIs.
118 Status
= PeiServicesInstallPpi (mPpiList
);
119 ASSERT_EFI_ERROR(Status
);
125 Main entry point to last PEIM.
127 @param This Entry point for DXE IPL PPI.
128 @param PeiServices General purpose services available to every PEIM.
129 @param HobList Address to the Pei HOB list.
131 @return EFI_SUCCESS DXE core was successfully loaded.
132 @return EFI_OUT_OF_RESOURCES There are not enough resources to load DXE core.
138 IN CONST EFI_DXE_IPL_PPI
*This
,
139 IN EFI_PEI_SERVICES
**PeiServices
,
140 IN EFI_PEI_HOB_POINTERS HobList
144 EFI_FV_FILE_INFO DxeCoreFileInfo
;
145 EFI_PHYSICAL_ADDRESS DxeCoreAddress
;
147 EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint
;
148 EFI_BOOT_MODE BootMode
;
149 EFI_PEI_FILE_HANDLE FileHandle
;
150 EFI_PEI_READ_ONLY_VARIABLE2_PPI
*Variable
;
152 EFI_MEMORY_TYPE_INFORMATION MemoryData
[EfiMaxMemoryType
+ 1];
155 // if in S3 Resume, restore configure
157 BootMode
= GetBootModeHob ();
159 if (BootMode
== BOOT_ON_S3_RESUME
) {
160 Status
= AcpiS3ResumeOs();
161 ASSERT_EFI_ERROR (Status
);
162 } else if (BootMode
== BOOT_IN_RECOVERY_MODE
) {
163 Status
= PeiRecoverFirmware ();
164 if (EFI_ERROR (Status
)) {
165 DEBUG ((DEBUG_ERROR
, "Load Recovery Capsule Failed.(Status = %r)\n", Status
));
170 // Now should have a HOB with the DXE core w/ the old HOB destroyed
174 Status
= PeiServicesLocatePpi (
175 &gEfiPeiReadOnlyVariable2PpiGuid
,
180 if (!EFI_ERROR (Status
)) {
181 DataSize
= sizeof (MemoryData
);
182 Status
= Variable
->GetVariable (
184 EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME
,
185 &gEfiMemoryTypeInformationGuid
,
190 if (!EFI_ERROR (Status
)) {
192 // Build the GUID'd HOB for DXE
195 &gEfiMemoryTypeInformationGuid
,
203 // Look in all the FVs present in PEI and find the DXE Core FileHandle
205 FileHandle
= DxeIplFindDxeCore ();
208 // Load the DXE Core from a Firmware Volume, may use LoadFile ppi to do this for save code size.
210 Status
= PeiLoadFile (
216 ASSERT_EFI_ERROR (Status
);
219 // Get the DxeCore File Info from the FileHandle for the DxeCore GUID file name.
221 Status
= PeiServicesFfsGetFileInfo (FileHandle
, &DxeCoreFileInfo
);
222 ASSERT_EFI_ERROR (Status
);
225 // Add HOB for the DXE Core
228 &DxeCoreFileInfo
.FileName
,
230 EFI_SIZE_TO_PAGES ((UINTN
) DxeCoreSize
) * EFI_PAGE_SIZE
,
235 // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT
239 PcdGet32(PcdStatusCodeValuePeiHandoffToDxe
)
242 DEBUG ((DEBUG_INFO
| DEBUG_LOAD
, "Loading DXE CORE at 0x%11p EntryPoint=0x%11p\n", (VOID
*)(UINTN
)DxeCoreAddress
, FUNCTION_ENTRY_POINT (DxeCoreEntryPoint
)));
245 // Transfer control to the DXE Core
246 // The handoff state is simply a pointer to the HOB list
248 HandOffToDxeCore (DxeCoreEntryPoint
, HobList
);
250 // If we get here, then the DXE Core returned. This is an error
251 // Dxe Core should not return.
256 return EFI_OUT_OF_RESOURCES
;
261 Searches DxeCore in all firmware Volumes and loads the first
262 instance that contains DxeCore.
264 @return FileHandle of DxeCore to load DxeCore.
274 EFI_PEI_FV_HANDLE VolumeHandle
;
275 EFI_PEI_FILE_HANDLE FileHandle
;
280 // Traverse all firmware volume instances
282 Status
= PeiServicesFfsFindNextVolume (Instance
, &VolumeHandle
);
284 // If some error occurs here, then we cannot find any firmware
285 // volume that may contain DxeCore.
287 ASSERT_EFI_ERROR (Status
);
290 // Find the DxeCore file type from the beginning in this firmware volume.
293 Status
= PeiServicesFfsFindNextFile (EFI_FV_FILETYPE_DXE_CORE
, VolumeHandle
, &FileHandle
);
294 if (!EFI_ERROR (Status
)) {
296 // Find DxeCore FileHandle in this volume, then we skip other firmware volume and
297 // return the FileHandle.
302 // We cannot find DxeCore in this firmware volume, then search the next volume.
310 Loads and relocates a PE/COFF image into memory.
312 @param FileHandle The image file handle
313 @param ImageAddress The base address of the relocated PE/COFF image
314 @param ImageSize The size of the relocated PE/COFF image
315 @param EntryPoint The entry point of the relocated PE/COFF image
317 @return EFI_SUCCESS The file was loaded and relocated
318 @return EFI_OUT_OF_RESOURCES There was not enough memory to load and relocate the PE/COFF file
323 IN EFI_PEI_FILE_HANDLE FileHandle
,
324 OUT EFI_PHYSICAL_ADDRESS
*ImageAddress
,
325 OUT UINT64
*ImageSize
,
326 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
331 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
335 // First try to find the PE32 section in this ffs file.
337 Status
= PeiServicesFfsFindSectionData (
342 if (EFI_ERROR (Status
)) {
344 // NO image types we support so exit.
349 ZeroMem (&ImageContext
, sizeof (ImageContext
));
350 ImageContext
.Handle
= Pe32Data
;
351 Status
= GetImageReadFunction (&ImageContext
);
353 ASSERT_EFI_ERROR (Status
);
355 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
356 if (EFI_ERROR (Status
)) {
360 // Allocate Memory for the image
362 Status
= PeiServicesAllocatePages (
364 EFI_SIZE_TO_PAGES ((UINT32
) ImageContext
.ImageSize
),
365 &ImageContext
.ImageAddress
367 ASSERT_EFI_ERROR (Status
);
368 ASSERT (ImageContext
.ImageAddress
!= 0);
371 // Load the image to our new buffer
373 Status
= PeCoffLoaderLoadImage (&ImageContext
);
374 if (EFI_ERROR (Status
)) {
378 // Relocate the image in our new buffer
380 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
381 if (EFI_ERROR (Status
)) {
386 // Flush the instruction cache so the image data is written before we execute it
388 InvalidateInstructionCacheRange ((VOID
*)(UINTN
)ImageContext
.ImageAddress
, (UINTN
)ImageContext
.ImageSize
);
390 *ImageAddress
= ImageContext
.ImageAddress
;
391 *ImageSize
= ImageContext
.ImageSize
;
392 *EntryPoint
= ImageContext
.EntryPoint
;
401 The ExtractSection() function processes the input section and
402 returns a pointer to the section contents. If the section being
403 extracted does not require processing (if the section
404 GuidedSectionHeader.Attributes has the
405 EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then
406 OutputBuffer is just updated to point to the start of the
407 section's contents. Otherwise, *Buffer must be allocated
408 from PEI permanent memory.
410 @param This Indicates the
411 EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance.
412 Buffer containing the input GUIDed section to be
413 processed. OutputBuffer OutputBuffer is
414 allocated from PEI permanent memory and contains
415 the new section stream.
416 @param InputSection A pointer to the input buffer, which contains
417 the input section to be processed.
418 @param OutputBuffer A pointer to a caller-allocated buffer, whose
419 size is specified by the contents of OutputSize.
420 @param OutputSize A pointer to a caller-allocated
421 UINTN in which the size of *OutputBuffer
422 allocation is stored. If the function
423 returns anything other than EFI_SUCCESS,
424 the value of OutputSize is undefined.
425 @param AuthenticationStatus A pointer to a caller-allocated
426 UINT32 that indicates the
427 authentication status of the
428 output buffer. If the input
429 section's GuidedSectionHeader.
430 Attributes field has the
431 EFI_GUIDED_SECTION_AUTH_STATUS_VALID
433 AuthenticationStatus must return
434 zero. These bits reflect the
435 status of the extraction
436 operation. If the function
437 returns anything other than
438 EFI_SUCCESS, the value of
439 AuthenticationStatus is
442 @retval EFI_SUCCESS The InputSection was
443 successfully processed and the
444 section contents were returned.
446 @retval EFI_OUT_OF_RESOURCES The system has insufficient
447 resources to process the request.
449 @retval EFI_INVALID_PARAMETER The GUID in InputSection does
450 not match this instance of the
451 GUIDed Section Extraction PPI.
455 CustomGuidedSectionExtract (
456 IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI
*This
,
457 IN CONST VOID
*InputSection
,
458 OUT VOID
**OutputBuffer
,
459 OUT UINTN
*OutputSize
,
460 OUT UINT32
*AuthenticationStatus
464 UINT8
*ScratchBuffer
;
465 UINT32 ScratchBufferSize
;
466 UINT32 OutputBufferSize
;
467 UINT16 SectionAttribute
;
470 // Init local variable
472 ScratchBuffer
= NULL
;
475 // Call GetInfo to get the size and attribute of input guided section data.
477 Status
= ExtractGuidedSectionGetInfo (
484 if (EFI_ERROR (Status
)) {
485 DEBUG ((DEBUG_ERROR
, "GetInfo from guided section Failed - %r\n", Status
));
489 if (ScratchBufferSize
!= 0) {
491 // Allocate scratch buffer
493 ScratchBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize
));
494 if (ScratchBuffer
== NULL
) {
495 return EFI_OUT_OF_RESOURCES
;
499 if (((SectionAttribute
& EFI_GUIDED_SECTION_PROCESSING_REQUIRED
) != 0) && OutputBufferSize
> 0) {
501 // Allocate output buffer
503 *OutputBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (OutputBufferSize
) + 1);
504 if (*OutputBuffer
== NULL
) {
505 return EFI_OUT_OF_RESOURCES
;
507 DEBUG ((DEBUG_INFO
, "Customed Guided section Memory Size required is 0x%x and address is 0x%p\n", OutputBufferSize
, *OutputBuffer
));
509 // *OutputBuffer still is one section. Adjust *OutputBuffer offset,
510 // skip EFI section header to make section data at page alignment.
512 *OutputBuffer
= (VOID
*)((UINT8
*) *OutputBuffer
+ EFI_PAGE_SIZE
- sizeof (EFI_COMMON_SECTION_HEADER
));
515 Status
= ExtractGuidedSectionDecode (
521 if (EFI_ERROR (Status
)) {
525 DEBUG ((DEBUG_ERROR
, "Extract guided section Failed - %r\n", Status
));
529 *OutputSize
= (UINTN
) OutputBufferSize
;
537 Decompresses a section to the output buffer.
539 This function lookes up the compression type field in the input section and
540 applies the appropriate compression algorithm to compress the section to a
541 callee allocated buffer.
543 @param This Points to this instance of the
544 EFI_PEI_DECOMPRESS_PEI PPI.
545 @param CompressionSection Points to the compressed section.
546 @param OutputBuffer Holds the returned pointer to the decompressed
548 @param OutputSize Holds the returned size of the decompress
551 @retval EFI_SUCCESS The section was decompressed successfully.
552 OutputBuffer contains the resulting data and
553 OutputSize contains the resulting size.
559 IN CONST EFI_PEI_DECOMPRESS_PPI
*This
,
560 IN CONST EFI_COMPRESSION_SECTION
*CompressionSection
,
561 OUT VOID
**OutputBuffer
,
562 OUT UINTN
*OutputSize
567 UINT8
*ScratchBuffer
;
569 UINT32 ScratchBufferSize
;
570 EFI_COMMON_SECTION_HEADER
*Section
;
573 if (CompressionSection
->CommonHeader
.Type
!= EFI_SECTION_COMPRESSION
) {
575 return EFI_INVALID_PARAMETER
;
578 Section
= (EFI_COMMON_SECTION_HEADER
*) CompressionSection
;
579 SectionLength
= *(UINT32
*) (Section
->Size
) & 0x00ffffff;
582 // This is a compression set, expand it
584 switch (CompressionSection
->CompressionType
) {
585 case EFI_STANDARD_COMPRESSION
:
587 // Load EFI standard compression.
588 // For compressed data, decompress them to dstbuffer.
590 Status
= UefiDecompressGetInfo (
591 (UINT8
*) ((EFI_COMPRESSION_SECTION
*) Section
+ 1),
592 (UINT32
) SectionLength
- sizeof (EFI_COMPRESSION_SECTION
),
593 (UINT32
*) &DstBufferSize
,
596 if (EFI_ERROR (Status
)) {
600 DEBUG ((DEBUG_ERROR
, "Decompress GetInfo Failed - %r\n", Status
));
601 return EFI_NOT_FOUND
;
604 // Allocate scratch buffer
606 ScratchBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize
));
607 if (ScratchBuffer
== NULL
) {
608 return EFI_OUT_OF_RESOURCES
;
611 // Allocate destination buffer, extra one page for adjustment
613 DstBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize
) + 1);
614 if (DstBuffer
== NULL
) {
615 return EFI_OUT_OF_RESOURCES
;
618 // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header
619 // to make section data at page alignment.
621 DstBuffer
= DstBuffer
+ EFI_PAGE_SIZE
- sizeof (EFI_COMMON_SECTION_HEADER
);
623 // Call decompress function
625 Status
= UefiDecompress (
626 (CHAR8
*) ((EFI_COMPRESSION_SECTION
*) Section
+ 1),
630 if (EFI_ERROR (Status
)) {
634 DEBUG ((DEBUG_ERROR
, "Decompress Failed - %r\n", Status
));
635 return EFI_NOT_FOUND
;
639 case EFI_NOT_COMPRESSED
:
641 // Allocate destination buffer
643 DstBufferSize
= CompressionSection
->UncompressedLength
;
644 DstBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize
) + 1);
645 if (DstBuffer
== NULL
) {
646 return EFI_OUT_OF_RESOURCES
;
649 // 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 // stream is not actually compressed, just encapsulated. So just copy it.
656 CopyMem (DstBuffer
, CompressionSection
+ 1, DstBufferSize
);
661 // Don't support other unknown compression type.
664 return EFI_NOT_FOUND
;
667 *OutputSize
= DstBufferSize
;
668 *OutputBuffer
= DstBuffer
;
677 Updates the Stack HOB passed to DXE phase.
679 This function traverses the whole HOB list and update the stack HOB to
680 reflect the real stack that is used by DXE core.
682 @param BaseAddress The lower address of stack used by DxeCore.
683 @param Length The length of stack used by DxeCore.
688 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
692 EFI_PEI_HOB_POINTERS Hob
;
694 Hob
.Raw
= GetHobList ();
695 while ((Hob
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, Hob
.Raw
)) != NULL
) {
696 if (CompareGuid (&gEfiHobMemoryAllocStackGuid
, &(Hob
.MemoryAllocationStack
->AllocDescriptor
.Name
))) {
698 // Build a new memory allocation HOB with old stack info with EfiConventionalMemory type
699 // to be reclaimed by DXE core.
701 BuildMemoryAllocationHob (
702 Hob
.MemoryAllocationStack
->AllocDescriptor
.MemoryBaseAddress
,
703 Hob
.MemoryAllocationStack
->AllocDescriptor
.MemoryLength
,
704 EfiConventionalMemory
707 // Update the BSP Stack Hob to reflect the new stack info.
709 Hob
.MemoryAllocationStack
->AllocDescriptor
.MemoryBaseAddress
= BaseAddress
;
710 Hob
.MemoryAllocationStack
->AllocDescriptor
.MemoryLength
= Length
;
713 Hob
.Raw
= GET_NEXT_HOB (Hob
);