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.
17 #include <Ppi/GuidedSectionExtraction.h>
20 CustomGuidedSectionExtract (
21 IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI
*This
,
22 IN CONST VOID
*InputSection
,
23 OUT VOID
**OutputBuffer
,
24 OUT UINTN
*OutputSize
,
25 OUT UINT32
*AuthenticationStatus
32 IN CONST EFI_PEI_DECOMPRESS_PPI
*This
,
33 IN CONST EFI_COMPRESSION_SECTION
*InputSection
,
34 OUT VOID
**OutputBuffer
,
39 BOOLEAN gInMemory
= FALSE
;
42 // Module Globals used in the DXE to PEI handoff
43 // These must be module globals, so the stack can be switched
45 static EFI_DXE_IPL_PPI mDxeIplPpi
= {
49 STATIC EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI mCustomGuidedSectionExtractionPpi
= {
50 CustomGuidedSectionExtract
53 STATIC EFI_PEI_DECOMPRESS_PPI mDecompressPpi
= {
57 static EFI_PEI_PPI_DESCRIPTOR mPpiList
[] = {
59 EFI_PEI_PPI_DESCRIPTOR_PPI
,
64 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
65 &gEfiPeiDecompressPpiGuid
,
70 static EFI_PEI_PPI_DESCRIPTOR mPpiSignal
= {
71 (EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
),
72 &gEfiEndOfPeiSignalPpiGuid
,
77 Initializes the Dxe Ipl PPI
79 @param FfsHandle The handle of FFS file.
80 @param PeiServices General purpose services available to
86 PeimInitializeDxeIpl (
87 IN EFI_PEI_FILE_HANDLE FfsHandle
,
88 IN EFI_PEI_SERVICES
**PeiServices
92 EFI_BOOT_MODE BootMode
;
93 EFI_GUID
*ExtractHandlerGuidTable
;
94 UINTN ExtractHandlerNumber
;
95 EFI_PEI_PPI_DESCRIPTOR
*GuidPpi
;
97 Status
= PeiServicesGetBootMode (&BootMode
);
98 ASSERT_EFI_ERROR (Status
);
100 if (BootMode
!= BOOT_ON_S3_RESUME
) {
101 Status
= PeiServicesRegisterForShadow (FfsHandle
);
102 if (Status
== EFI_SUCCESS
) {
104 // EFI_SUCESS means the first time call register for shadow
107 } else if (Status
== EFI_ALREADY_STARTED
) {
112 // Get custom extract guided section method guid list
114 ExtractHandlerNumber
= ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable
);
117 // Install custom extraction guid ppi
119 if (ExtractHandlerNumber
> 0) {
121 GuidPpi
= (EFI_PEI_PPI_DESCRIPTOR
*) AllocatePool (ExtractHandlerNumber
* sizeof (EFI_PEI_PPI_DESCRIPTOR
));
122 ASSERT (GuidPpi
!= NULL
);
123 while (ExtractHandlerNumber
-- > 0) {
124 GuidPpi
->Flags
= EFI_PEI_PPI_DESCRIPTOR_PPI
| EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST
;
125 GuidPpi
->Ppi
= &mCustomGuidedSectionExtractionPpi
;
126 GuidPpi
->Guid
= &(ExtractHandlerGuidTable
[ExtractHandlerNumber
]);
127 Status
= PeiServicesInstallPpi (GuidPpi
++);
128 ASSERT_EFI_ERROR(Status
);
137 // Install DxeIpl and Decompress PPIs.
139 Status
= PeiServicesInstallPpi (mPpiList
);
140 ASSERT_EFI_ERROR(Status
);
146 Main entry point to last PEIM
148 @param This Entry point for DXE IPL PPI
149 @param PeiServices General purpose services available to every PEIM.
150 @param HobList Address to the Pei HOB list
152 @return EFI_SUCCESS DXE core was successfully loaded.
153 @return EFI_OUT_OF_RESOURCES There are not enough resources to load DXE core.
158 IN EFI_DXE_IPL_PPI
*This
,
159 IN EFI_PEI_SERVICES
**PeiServices
,
160 IN EFI_PEI_HOB_POINTERS HobList
164 EFI_GUID DxeCoreFileName
;
165 EFI_PHYSICAL_ADDRESS DxeCoreAddress
;
167 EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint
;
168 EFI_BOOT_MODE BootMode
;
169 EFI_PEI_FILE_HANDLE FileHandle
;
170 EFI_PEI_READ_ONLY_VARIABLE2_PPI
*Variable
;
172 EFI_MEMORY_TYPE_INFORMATION MemoryData
[EfiMaxMemoryType
+ 1];
175 // if in S3 Resume, restore configure
177 Status
= PeiServicesGetBootMode (&BootMode
);
178 ASSERT_EFI_ERROR(Status
);
180 if (BootMode
== BOOT_ON_S3_RESUME
) {
181 Status
= AcpiS3ResumeOs();
182 ASSERT_EFI_ERROR (Status
);
183 } else if (BootMode
== BOOT_IN_RECOVERY_MODE
) {
184 Status
= PeiRecoverFirmware ();
185 if (EFI_ERROR (Status
)) {
186 DEBUG ((EFI_D_ERROR
, "Load Recovery Capsule Failed.(Status = %r)\n", Status
));
191 // Now should have a HOB with the DXE core w/ the old HOB destroyed
195 Status
= PeiServicesLocatePpi (
196 &gEfiPeiReadOnlyVariable2PpiGuid
,
201 ASSERT_EFI_ERROR (Status
);
203 DataSize
= sizeof (MemoryData
);
204 Status
= Variable
->GetVariable (
206 EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME
,
207 &gEfiMemoryTypeInformationGuid
,
213 if (!EFI_ERROR (Status
)) {
215 // Build the GUID'd HOB for DXE
218 &gEfiMemoryTypeInformationGuid
,
225 // Look in all the FVs present in PEI and find the DXE Core
228 Status
= DxeIplFindDxeCore (&FileHandle
);
229 ASSERT_EFI_ERROR (Status
);
231 CopyMem(&DxeCoreFileName
, &(((EFI_FFS_FILE_HEADER
*)FileHandle
)->Name
), sizeof (EFI_GUID
));
234 // Load the DXE Core from a Firmware Volume, may use LoadFile ppi to do this for save code size.
236 Status
= PeiLoadFile (
243 ASSERT_EFI_ERROR (Status
);
246 // Add HOB for the DXE Core
251 EFI_SIZE_TO_PAGES ((UINT32
) DxeCoreSize
) * EFI_PAGE_SIZE
,
256 // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT
260 PcdGet32(PcdStatusCodeValuePeiHandoffToDxe
)
265 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION PtrPeImage
;
266 PtrPeImage
.Pe32
= (EFI_IMAGE_NT_HEADERS32
*) ((UINTN
) DxeCoreAddress
+ ((EFI_IMAGE_DOS_HEADER
*) (UINTN
) DxeCoreAddress
)->e_lfanew
);
268 if (PtrPeImage
.Pe32
->FileHeader
.Machine
!= IMAGE_FILE_MACHINE_IA64
) {
269 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Loading DXE CORE at 0x%10p EntryPoint=0x%10p\n", (VOID
*)(UINTN
)DxeCoreAddress
, (VOID
*)(UINTN
)DxeCoreEntryPoint
));
272 // For IPF Image, the real entry point should be print.
274 DEBUG ((EFI_D_INFO
| EFI_D_LOAD
, "Loading DXE CORE at 0x%10p EntryPoint=0x%10p\n", (VOID
*)(UINTN
)DxeCoreAddress
, (VOID
*)(UINTN
)(*(UINT64
*)(UINTN
)DxeCoreEntryPoint
)));
279 // Transfer control to the DXE Core
280 // The handoff state is simply a pointer to the HOB list
282 HandOffToDxeCore (DxeCoreEntryPoint
, HobList
, &mPpiSignal
);
284 // If we get here, then the DXE Core returned. This is an error
285 // Dxe Core should not return.
290 return EFI_OUT_OF_RESOURCES
;
294 Find DxeCore driver from all First Volumes.
296 @param FileHandle Pointer to FFS file to search.
298 @return EFI_SUCESS Success to find the FFS in specificed FV
299 @return others Fail to find the FFS in specificed FV
303 OUT EFI_PEI_FILE_HANDLE
*FileHandle
307 EFI_STATUS FileStatus
;
309 EFI_PEI_FV_HANDLE VolumeHandle
;
315 Status
= PeiServicesFfsFindNextVolume (Instance
++, &VolumeHandle
);
316 if (!EFI_ERROR (Status
)) {
317 FileStatus
= PeiServicesFfsFindNextFile (EFI_FV_FILETYPE_DXE_CORE
, VolumeHandle
, FileHandle
);
318 if (!EFI_ERROR (FileStatus
)) {
322 } while (!EFI_ERROR (Status
));
324 return EFI_NOT_FOUND
;
328 Loads and relocates a PE/COFF image into memory.
330 @param FileHandle The image file handle
331 @param ImageAddress The base address of the relocated PE/COFF image
332 @param ImageSize The size of the relocated PE/COFF image
333 @param EntryPoint The entry point of the relocated PE/COFF image
335 @return EFI_SUCCESS The file was loaded and relocated
336 @return EFI_OUT_OF_RESOURCES There was not enough memory to load and relocate the PE/COFF file
340 IN EFI_PEI_FILE_HANDLE FileHandle
,
341 OUT EFI_PHYSICAL_ADDRESS
*ImageAddress
,
342 OUT UINT64
*ImageSize
,
343 OUT EFI_PHYSICAL_ADDRESS
*EntryPoint
348 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext
;
351 // First try to find the PE32 section in this ffs file.
353 Status
= PeiServicesFfsFindSectionData (
359 if (EFI_ERROR (Status
)) {
361 // NO image types we support so exit.
366 ZeroMem (&ImageContext
, sizeof (ImageContext
));
367 ImageContext
.Handle
= Pe32Data
;
368 Status
= GetImageReadFunction (&ImageContext
);
370 ASSERT_EFI_ERROR (Status
);
372 Status
= PeCoffLoaderGetImageInfo (&ImageContext
);
373 if (EFI_ERROR (Status
)) {
377 // Allocate Memory for the image
379 ImageContext
.ImageAddress
= (EFI_PHYSICAL_ADDRESS
)(UINTN
) AllocatePages (EFI_SIZE_TO_PAGES ((UINT32
) ImageContext
.ImageSize
));
380 ASSERT (ImageContext
.ImageAddress
!= 0);
383 // Load the image to our new buffer
385 Status
= PeCoffLoaderLoadImage (&ImageContext
);
386 if (EFI_ERROR (Status
)) {
390 // Relocate the image in our new buffer
392 Status
= PeCoffLoaderRelocateImage (&ImageContext
);
393 if (EFI_ERROR (Status
)) {
398 // Flush the instruction cache so the image data is written before we execute it
400 InvalidateInstructionCacheRange ((VOID
*)(UINTN
)ImageContext
.ImageAddress
, (UINTN
)ImageContext
.ImageSize
);
402 *ImageAddress
= ImageContext
.ImageAddress
;
403 *ImageSize
= ImageContext
.ImageSize
;
404 *EntryPoint
= ImageContext
.EntryPoint
;
410 The ExtractSection() function processes the input section and
411 returns a pointer to the section contents. If the section being
412 extracted does not require processing (if the section
413 GuidedSectionHeader.Attributes has the
414 EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then
415 OutputBuffer is just updated to point to the start of the
416 section's contents. Otherwise, *Buffer must be allocated
417 from PEI permanent memory.
419 @param This Indicates the
420 EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance.
421 Buffer containing the input GUIDed section to be
422 processed. OutputBuffer OutputBuffer is
423 allocated from PEI permanent memory and contains
424 the new section stream.
426 @param OutputSize A pointer to a caller-allocated
427 UINTN in which the size of *OutputBuffer
428 allocation is stored. If the function
429 returns anything other than EFI_SUCCESS,
430 the value of OutputSize is undefined.
432 @param AuthenticationStatus A pointer to a caller-allocated
433 UINT32 that indicates the
434 authentication status of the
435 output buffer. If the input
436 section's GuidedSectionHeader.
437 Attributes field has the
438 EFI_GUIDED_SECTION_AUTH_STATUS_VALID
440 AuthenticationStatus must return
441 zero. These bits reflect the
442 status of the extraction
443 operation. If the function
444 returns anything other than
445 EFI_SUCCESS, the value of
446 AuthenticationStatus is
449 @retval EFI_SUCCESS The InputSection was
450 successfully processed and the
451 section contents were returned.
453 @retval EFI_OUT_OF_RESOURCES The system has insufficient
454 resources to process the request.
456 @reteval EFI_INVALID_PARAMETER The GUID in InputSection does
457 not match this instance of the
458 GUIDed Section Extraction PPI.
461 CustomGuidedSectionExtract (
462 IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI
*This
,
463 IN CONST VOID
*InputSection
,
464 OUT VOID
**OutputBuffer
,
465 OUT UINTN
*OutputSize
,
466 OUT UINT32
*AuthenticationStatus
470 UINT8
*ScratchBuffer
;
471 UINT32 ScratchBufferSize
;
472 UINT32 OutputBufferSize
;
473 UINT16 SectionAttribute
;
476 // Init local variable
478 ScratchBuffer
= NULL
;
481 // Call GetInfo to get the size and attribute of input guided section data.
483 Status
= ExtractGuidedSectionGetInfo (
490 if (EFI_ERROR (Status
)) {
491 DEBUG ((EFI_D_ERROR
, "GetInfo from guided section Failed - %r\n", Status
));
495 if (ScratchBufferSize
!= 0) {
497 // Allocate scratch buffer
499 ScratchBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize
));
500 if (ScratchBuffer
== NULL
) {
501 return EFI_OUT_OF_RESOURCES
;
505 if ((SectionAttribute
& EFI_GUIDED_SECTION_PROCESSING_REQUIRED
) && OutputBufferSize
> 0) {
507 // Allocate output buffer
509 *OutputBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (OutputBufferSize
) + 1);
510 if (*OutputBuffer
== NULL
) {
511 return EFI_OUT_OF_RESOURCES
;
513 DEBUG ((EFI_D_INFO
, "Customed Guided section Memory Size required is 0x%x and address is 0x%p\n", OutputBufferSize
, *OutputBuffer
));
515 // *OutputBuffer still is one section. Adjust *OutputBuffer offset,
516 // skip EFI section header to make section data at page alignment.
518 *OutputBuffer
= (VOID
*)((UINT8
*) *OutputBuffer
+ EFI_PAGE_SIZE
- sizeof (EFI_COMMON_SECTION_HEADER
));
521 Status
= ExtractGuidedSectionDecode (
528 if (EFI_ERROR (Status
)) {
532 DEBUG ((EFI_D_ERROR
, "Extract guided section Failed - %r\n", Status
));
536 *OutputSize
= (UINTN
) OutputBufferSize
;
545 IN CONST EFI_PEI_DECOMPRESS_PPI
*This
,
546 IN CONST EFI_COMPRESSION_SECTION
*CompressionSection
,
547 OUT VOID
**OutputBuffer
,
548 OUT UINTN
*OutputSize
553 UINT8
*ScratchBuffer
;
555 UINT32 ScratchBufferSize
;
556 EFI_COMMON_SECTION_HEADER
*Section
;
559 if (CompressionSection
->CommonHeader
.Type
!= EFI_SECTION_COMPRESSION
) {
561 return EFI_INVALID_PARAMETER
;
564 Section
= (EFI_COMMON_SECTION_HEADER
*) CompressionSection
;
565 SectionLength
= *(UINT32
*) (Section
->Size
) & 0x00ffffff;
568 // This is a compression set, expand it
570 switch (CompressionSection
->CompressionType
) {
571 case EFI_STANDARD_COMPRESSION
:
573 // Load EFI standard compression.
574 // For compressed data, decompress them to dstbuffer.
576 Status
= UefiDecompressGetInfo (
577 (UINT8
*) ((EFI_COMPRESSION_SECTION
*) Section
+ 1),
578 (UINT32
) SectionLength
- sizeof (EFI_COMPRESSION_SECTION
),
579 (UINT32
*) &DstBufferSize
,
582 if (EFI_ERROR (Status
)) {
586 DEBUG ((EFI_D_ERROR
, "Decompress GetInfo Failed - %r\n", Status
));
587 return EFI_NOT_FOUND
;
590 // Allocate scratch buffer
592 ScratchBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize
));
593 if (ScratchBuffer
== NULL
) {
594 return EFI_OUT_OF_RESOURCES
;
597 // Allocate destination buffer, extra one page for adjustment
599 DstBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize
) + 1);
600 if (DstBuffer
== NULL
) {
601 return EFI_OUT_OF_RESOURCES
;
604 // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header
605 // to make section data at page alignment.
607 DstBuffer
= DstBuffer
+ EFI_PAGE_SIZE
- sizeof (EFI_COMMON_SECTION_HEADER
);
609 // Call decompress function
611 Status
= UefiDecompress (
612 (CHAR8
*) ((EFI_COMPRESSION_SECTION
*) Section
+ 1),
616 if (EFI_ERROR (Status
)) {
620 DEBUG ((EFI_D_ERROR
, "Decompress Failed - %r\n", Status
));
621 return EFI_NOT_FOUND
;
625 case EFI_NOT_COMPRESSED
:
627 // Allocate destination buffer
629 DstBufferSize
= CompressionSection
->UncompressedLength
;
630 DstBuffer
= AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize
) + 1);
631 if (DstBuffer
== NULL
) {
632 return EFI_OUT_OF_RESOURCES
;
635 // Adjust DstBuffer offset, skip EFI section header
636 // to make section data at page alignment.
638 DstBuffer
= DstBuffer
+ EFI_PAGE_SIZE
- sizeof (EFI_COMMON_SECTION_HEADER
);
640 // stream is not actually compressed, just encapsulated. So just copy it.
642 CopyMem (DstBuffer
, CompressionSection
+ 1, DstBufferSize
);
647 // Don't support other unknown compression type.
650 return EFI_NOT_FOUND
;
653 *OutputSize
= DstBufferSize
;
654 *OutputBuffer
= DstBuffer
;
661 IN EFI_PHYSICAL_ADDRESS BaseAddress
,
665 EFI_PEI_HOB_POINTERS Hob
;
667 Hob
.Raw
= GetHobList ();
668 while ((Hob
.Raw
= GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION
, Hob
.Raw
)) != NULL
) {
669 if (CompareGuid (&gEfiHobMemoryAllocStackGuid
, &(Hob
.MemoryAllocationStack
->AllocDescriptor
.Name
))) {
671 // Build a new memory allocation HOB with old stack info with EfiConventionalMemory type
672 // to be reclaimed by DXE core.
674 BuildMemoryAllocationHob (
675 Hob
.MemoryAllocationStack
->AllocDescriptor
.MemoryBaseAddress
,
676 Hob
.MemoryAllocationStack
->AllocDescriptor
.MemoryLength
,
677 EfiConventionalMemory
680 // Update the BSP Stack Hob to reflect the new stack info.
682 Hob
.MemoryAllocationStack
->AllocDescriptor
.MemoryBaseAddress
= BaseAddress
;
683 Hob
.MemoryAllocationStack
->AllocDescriptor
.MemoryLength
= Length
;
686 Hob
.Raw
= GET_NEXT_HOB (Hob
);