Fix warnings generated by GCC.
[edk2.git] / MdeModulePkg / Core / DxeIplPeim / DxeLoad.c
blob3c9ed7c23545a194389374f613d1fefdb88a90d0
1 /** @file
2 Last PEIM.
3 Responsibility of this module is to load the DXE Core from a Firmware Volume.
5 Copyright (c) 2006 - 2009, 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.
14 **/
16 #include "DxeIpl.h"
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 = {
24 DxeLoadCore
27 CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI mCustomGuidedSectionExtractionPpi = {
28 CustomGuidedSectionExtract
31 CONST EFI_PEI_DECOMPRESS_PPI mDecompressPpi = {
32 Decompress
35 CONST EFI_PEI_PPI_DESCRIPTOR mPpiList[] = {
37 EFI_PEI_PPI_DESCRIPTOR_PPI,
38 &gEfiDxeIplPpiGuid,
39 (VOID *) &mDxeIplPpi
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,
51 NULL
54 /**
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.
66 **/
67 EFI_STATUS
68 EFIAPI
69 PeimInitializeDxeIpl (
70 IN EFI_PEI_FILE_HANDLE FileHandle,
71 IN CONST EFI_PEI_SERVICES **PeiServices
74 EFI_STATUS Status;
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.
87 //
88 return Status;
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);
124 return Status;
128 Main entry point to last PEIM.
130 This function finds DXE Core in the firmware volume and transfer the control to
131 DXE core.
133 @param This Entry point for DXE IPL PPI.
134 @param PeiServices General purpose services available to every PEIM.
135 @param HobList Address to the Pei HOB list.
137 @return EFI_SUCCESS DXE core was successfully loaded.
138 @return EFI_OUT_OF_RESOURCES There are not enough resources to load DXE core.
141 EFI_STATUS
142 EFIAPI
143 DxeLoadCore (
144 IN CONST EFI_DXE_IPL_PPI *This,
145 IN EFI_PEI_SERVICES **PeiServices,
146 IN EFI_PEI_HOB_POINTERS HobList
149 EFI_STATUS Status;
150 EFI_FV_FILE_INFO DxeCoreFileInfo;
151 EFI_PHYSICAL_ADDRESS DxeCoreAddress;
152 UINT64 DxeCoreSize;
153 EFI_PHYSICAL_ADDRESS DxeCoreEntryPoint;
154 EFI_BOOT_MODE BootMode;
155 EFI_PEI_FILE_HANDLE FileHandle;
156 EFI_PEI_READ_ONLY_VARIABLE2_PPI *Variable;
157 EFI_PEI_LOAD_FILE_PPI *LoadFile;
158 UINTN Instance;
159 UINT32 AuthenticationState;
160 UINTN DataSize;
161 EFI_PEI_S3_RESUME_PPI *S3Resume;
162 EFI_PEI_RECOVERY_MODULE_PPI *PeiRecovery;
163 EFI_MEMORY_TYPE_INFORMATION MemoryData[EfiMaxMemoryType + 1];
166 // if in S3 Resume, restore configure
168 BootMode = GetBootModeHob ();
170 if (BootMode == BOOT_ON_S3_RESUME) {
171 Status = PeiServicesLocatePpi (
172 &gEfiPeiS3ResumePpiGuid,
174 NULL,
175 (VOID **) &S3Resume
177 ASSERT_EFI_ERROR (Status);
179 Status = S3Resume->S3RestoreConfig (PeiServices);
180 ASSERT_EFI_ERROR (Status);
181 } else if (BootMode == BOOT_IN_RECOVERY_MODE) {
182 Status = PeiServicesLocatePpi (
183 &gEfiPeiRecoveryModulePpiGuid,
185 NULL,
186 (VOID **) &PeiRecovery
188 ASSERT_EFI_ERROR (Status);
190 Status = PeiRecovery->LoadRecoveryCapsule (PeiServices, PeiRecovery);
191 if (EFI_ERROR (Status)) {
192 DEBUG ((DEBUG_ERROR, "Load Recovery Capsule Failed.(Status = %r)\n", Status));
193 CpuDeadLoop ();
197 // Now should have a HOB with the DXE core
201 Status = PeiServicesLocatePpi (
202 &gEfiPeiReadOnlyVariable2PpiGuid,
204 NULL,
205 (VOID **)&Variable
207 if (!EFI_ERROR (Status)) {
208 DataSize = sizeof (MemoryData);
209 Status = Variable->GetVariable (
210 Variable,
211 EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
212 &gEfiMemoryTypeInformationGuid,
213 NULL,
214 &DataSize,
215 &MemoryData
217 if (!EFI_ERROR (Status)) {
219 // Build the GUID'd HOB for DXE
221 BuildGuidDataHob (
222 &gEfiMemoryTypeInformationGuid,
223 MemoryData,
224 DataSize
230 // Look in all the FVs present in PEI and find the DXE Core FileHandle
232 FileHandle = DxeIplFindDxeCore ();
235 // Load the DXE Core from a Firmware Volume.
237 Instance = 0;
238 do {
239 Status = PeiServicesLocatePpi (&gEfiPeiLoadFilePpiGuid, Instance++, NULL, (VOID **) &LoadFile);
241 // These must exist an instance of EFI_PEI_LOAD_FILE_PPI to support to load DxeCore file handle successfully.
243 ASSERT_EFI_ERROR (Status);
245 Status = LoadFile->LoadFile (
246 LoadFile,
247 FileHandle,
248 &DxeCoreAddress,
249 &DxeCoreSize,
250 &DxeCoreEntryPoint,
251 &AuthenticationState
253 } while (EFI_ERROR (Status));
256 // Get the DxeCore File Info from the FileHandle for the DxeCore GUID file name.
258 Status = PeiServicesFfsGetFileInfo (FileHandle, &DxeCoreFileInfo);
259 ASSERT_EFI_ERROR (Status);
262 // Add HOB for the DXE Core
264 BuildModuleHob (
265 &DxeCoreFileInfo.FileName,
266 DxeCoreAddress,
267 ALIGN_VALUE (DxeCoreSize, EFI_PAGE_SIZE),
268 DxeCoreEntryPoint
272 // Report Status Code EFI_SW_PEI_PC_HANDOFF_TO_NEXT
274 REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdStatusCodeValuePeiHandoffToDxe));
276 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Loading DXE CORE at 0x%11p EntryPoint=0x%11p\n", (VOID *)(UINTN)DxeCoreAddress, FUNCTION_ENTRY_POINT (DxeCoreEntryPoint)));
279 // Transfer control to the DXE Core
280 // The hand off state is simply a pointer to the HOB list
282 HandOffToDxeCore (DxeCoreEntryPoint, HobList);
284 // If we get here, then the DXE Core returned. This is an error
285 // DxeCore should not return.
287 ASSERT (FALSE);
288 CpuDeadLoop ();
290 return EFI_OUT_OF_RESOURCES;
295 Searches DxeCore in all firmware Volumes and loads the first
296 instance that contains DxeCore.
298 @return FileHandle of DxeCore to load DxeCore.
301 EFI_PEI_FILE_HANDLE
302 DxeIplFindDxeCore (
303 VOID
306 EFI_STATUS Status;
307 UINTN Instance;
308 EFI_PEI_FV_HANDLE VolumeHandle;
309 EFI_PEI_FILE_HANDLE FileHandle;
311 Instance = 0;
312 while (TRUE) {
314 // Traverse all firmware volume instances
316 Status = PeiServicesFfsFindNextVolume (Instance, &VolumeHandle);
318 // If some error occurs here, then we cannot find any firmware
319 // volume that may contain DxeCore.
321 ASSERT_EFI_ERROR (Status);
324 // Find the DxeCore file type from the beginning in this firmware volume.
326 FileHandle = NULL;
327 Status = PeiServicesFfsFindNextFile (EFI_FV_FILETYPE_DXE_CORE, VolumeHandle, &FileHandle);
328 if (!EFI_ERROR (Status)) {
330 // Find DxeCore FileHandle in this volume, then we skip other firmware volume and
331 // return the FileHandle.
333 return FileHandle;
336 // We cannot find DxeCore in this firmware volume, then search the next volume.
338 Instance++;
345 The ExtractSection() function processes the input section and
346 returns a pointer to the section contents. If the section being
347 extracted does not require processing (if the section
348 GuidedSectionHeader.Attributes has the
349 EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then
350 OutputBuffer is just updated to point to the start of the
351 section's contents. Otherwise, *Buffer must be allocated
352 from PEI permanent memory.
354 @param This Indicates the
355 EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance.
356 Buffer containing the input GUIDed section to be
357 processed. OutputBuffer OutputBuffer is
358 allocated from PEI permanent memory and contains
359 the new section stream.
360 @param InputSection A pointer to the input buffer, which contains
361 the input section to be processed.
362 @param OutputBuffer A pointer to a caller-allocated buffer, whose
363 size is specified by the contents of OutputSize.
364 @param OutputSize A pointer to a caller-allocated
365 UINTN in which the size of *OutputBuffer
366 allocation is stored. If the function
367 returns anything other than EFI_SUCCESS,
368 the value of OutputSize is undefined.
369 @param AuthenticationStatus A pointer to a caller-allocated
370 UINT32 that indicates the
371 authentication status of the
372 output buffer. If the input
373 section's GuidedSectionHeader.
374 Attributes field has the
375 EFI_GUIDED_SECTION_AUTH_STATUS_VALID
376 bit as clear,
377 AuthenticationStatus must return
378 zero. These bits reflect the
379 status of the extraction
380 operation. If the function
381 returns anything other than
382 EFI_SUCCESS, the value of
383 AuthenticationStatus is
384 undefined.
386 @retval EFI_SUCCESS The InputSection was
387 successfully processed and the
388 section contents were returned.
390 @retval EFI_OUT_OF_RESOURCES The system has insufficient
391 resources to process the request.
393 @retval EFI_INVALID_PARAMETER The GUID in InputSection does
394 not match this instance of the
395 GUIDed Section Extraction PPI.
398 EFI_STATUS
399 EFIAPI
400 CustomGuidedSectionExtract (
401 IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *This,
402 IN CONST VOID *InputSection,
403 OUT VOID **OutputBuffer,
404 OUT UINTN *OutputSize,
405 OUT UINT32 *AuthenticationStatus
408 EFI_STATUS Status;
409 UINT8 *ScratchBuffer;
410 UINT32 ScratchBufferSize;
411 UINT32 OutputBufferSize;
412 UINT16 SectionAttribute;
415 // Init local variable
417 ScratchBuffer = NULL;
420 // Call GetInfo to get the size and attribute of input guided section data.
422 Status = ExtractGuidedSectionGetInfo (
423 InputSection,
424 &OutputBufferSize,
425 &ScratchBufferSize,
426 &SectionAttribute
429 if (EFI_ERROR (Status)) {
430 DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status));
431 return Status;
434 if (ScratchBufferSize != 0) {
436 // Allocate scratch buffer
438 ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
439 if (ScratchBuffer == NULL) {
440 return EFI_OUT_OF_RESOURCES;
444 if (((SectionAttribute & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) && OutputBufferSize > 0) {
446 // Allocate output buffer
448 *OutputBuffer = AllocatePages (EFI_SIZE_TO_PAGES (OutputBufferSize) + 1);
449 if (*OutputBuffer == NULL) {
450 return EFI_OUT_OF_RESOURCES;
452 DEBUG ((DEBUG_INFO, "Customized Guided section Memory Size required is 0x%x and address is 0x%p\n", OutputBufferSize, *OutputBuffer));
454 // *OutputBuffer still is one section. Adjust *OutputBuffer offset,
455 // skip EFI section header to make section data at page alignment.
457 *OutputBuffer = (VOID *)((UINT8 *) *OutputBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER));
460 Status = ExtractGuidedSectionDecode (
461 InputSection,
462 OutputBuffer,
463 ScratchBuffer,
464 AuthenticationStatus
466 if (EFI_ERROR (Status)) {
468 // Decode failed
470 DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status));
471 return Status;
474 *OutputSize = (UINTN) OutputBufferSize;
476 return EFI_SUCCESS;
482 Decompresses a section to the output buffer.
484 This function looks up the compression type field in the input section and
485 applies the appropriate compression algorithm to compress the section to a
486 callee allocated buffer.
488 @param This Points to this instance of the
489 EFI_PEI_DECOMPRESS_PEI PPI.
490 @param CompressionSection Points to the compressed section.
491 @param OutputBuffer Holds the returned pointer to the decompressed
492 sections.
493 @param OutputSize Holds the returned size of the decompress
494 section streams.
496 @retval EFI_SUCCESS The section was decompressed successfully.
497 OutputBuffer contains the resulting data and
498 OutputSize contains the resulting size.
501 EFI_STATUS
502 EFIAPI
503 Decompress (
504 IN CONST EFI_PEI_DECOMPRESS_PPI *This,
505 IN CONST EFI_COMPRESSION_SECTION *CompressionSection,
506 OUT VOID **OutputBuffer,
507 OUT UINTN *OutputSize
510 EFI_STATUS Status;
511 UINT8 *DstBuffer;
512 UINT8 *ScratchBuffer;
513 UINTN DstBufferSize;
514 UINT32 ScratchBufferSize;
515 EFI_COMMON_SECTION_HEADER *Section;
516 UINTN SectionLength;
518 if (CompressionSection->CommonHeader.Type != EFI_SECTION_COMPRESSION) {
519 ASSERT (FALSE);
520 return EFI_INVALID_PARAMETER;
523 Section = (EFI_COMMON_SECTION_HEADER *) CompressionSection;
524 SectionLength = *(UINT32 *) (Section->Size) & 0x00ffffff;
527 // This is a compression set, expand it
529 switch (CompressionSection->CompressionType) {
530 case EFI_STANDARD_COMPRESSION:
531 if (FeaturePcdGet(PcdDxeIplSupportUefiDecompress)) {
533 // Load EFI standard compression.
534 // For compressed data, decompress them to destination buffer.
536 Status = UefiDecompressGetInfo (
537 (UINT8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),
538 (UINT32) SectionLength - sizeof (EFI_COMPRESSION_SECTION),
539 (UINT32 *) &DstBufferSize,
540 &ScratchBufferSize
542 if (EFI_ERROR (Status)) {
544 // GetInfo failed
546 DEBUG ((DEBUG_ERROR, "Decompress GetInfo Failed - %r\n", Status));
547 return EFI_NOT_FOUND;
550 // Allocate scratch buffer
552 ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));
553 if (ScratchBuffer == NULL) {
554 return EFI_OUT_OF_RESOURCES;
557 // Allocate destination buffer, extra one page for adjustment
559 DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1);
560 if (DstBuffer == NULL) {
561 return EFI_OUT_OF_RESOURCES;
564 // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header
565 // to make section data at page alignment.
567 DstBuffer = DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER);
569 // Call decompress function
571 Status = UefiDecompress (
572 (CHAR8 *) ((EFI_COMPRESSION_SECTION *) Section + 1),
573 DstBuffer,
574 ScratchBuffer
576 if (EFI_ERROR (Status)) {
578 // Decompress failed
580 DEBUG ((DEBUG_ERROR, "Decompress Failed - %r\n", Status));
581 return EFI_NOT_FOUND;
583 break;
584 } else {
586 // PcdDxeIplSupportUefiDecompress is FALSE
587 // Don't support UEFI decompression algorithm.
589 ASSERT (FALSE);
590 return EFI_NOT_FOUND;
593 case EFI_NOT_COMPRESSED:
595 // Allocate destination buffer
597 DstBufferSize = CompressionSection->UncompressedLength;
598 DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1);
599 if (DstBuffer == NULL) {
600 return EFI_OUT_OF_RESOURCES;
603 // Adjust DstBuffer offset, skip EFI section header
604 // to make section data at page alignment.
606 DstBuffer = DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER);
608 // stream is not actually compressed, just encapsulated. So just copy it.
610 CopyMem (DstBuffer, CompressionSection + 1, DstBufferSize);
611 break;
613 default:
615 // Don't support other unknown compression type.
617 ASSERT (FALSE);
618 return EFI_NOT_FOUND;
621 *OutputSize = DstBufferSize;
622 *OutputBuffer = DstBuffer;
624 return EFI_SUCCESS;
629 Updates the Stack HOB passed to DXE phase.
631 This function traverses the whole HOB list and update the stack HOB to
632 reflect the real stack that is used by DXE core.
634 @param BaseAddress The lower address of stack used by DxeCore.
635 @param Length The length of stack used by DxeCore.
638 VOID
639 UpdateStackHob (
640 IN EFI_PHYSICAL_ADDRESS BaseAddress,
641 IN UINT64 Length
644 EFI_PEI_HOB_POINTERS Hob;
646 Hob.Raw = GetHobList ();
647 while ((Hob.Raw = GetNextHob (EFI_HOB_TYPE_MEMORY_ALLOCATION, Hob.Raw)) != NULL) {
648 if (CompareGuid (&gEfiHobMemoryAllocStackGuid, &(Hob.MemoryAllocationStack->AllocDescriptor.Name))) {
650 // Build a new memory allocation HOB with old stack info with EfiConventionalMemory type
651 // to be reclaimed by DXE core.
653 BuildMemoryAllocationHob (
654 Hob.MemoryAllocationStack->AllocDescriptor.MemoryBaseAddress,
655 Hob.MemoryAllocationStack->AllocDescriptor.MemoryLength,
656 EfiConventionalMemory
659 // Update the BSP Stack Hob to reflect the new stack info.
661 Hob.MemoryAllocationStack->AllocDescriptor.MemoryBaseAddress = BaseAddress;
662 Hob.MemoryAllocationStack->AllocDescriptor.MemoryLength = Length;
663 break;
665 Hob.Raw = GET_NEXT_HOB (Hob);