--- /dev/null
+/** @file\r
+\r
+ Copyright (c) 2014, Intel Corporation. All rights reserved.<BR>\r
+ This program and the accompanying materials\r
+ are licensed and made available under the terms and conditions of the BSD License\r
+ which accompanies this distribution. The full text of the license may be found at\r
+ http://opensource.org/licenses/bsd-license.php.\r
+\r
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "DxeIpl.h"\r
+\r
+\r
+//\r
+// Module Globals used in the DXE to PEI hand off\r
+// These must be module globals, so the stack can be switched\r
+//\r
+CONST EFI_DXE_IPL_PPI mDxeIplPpi = {\r
+ DxeLoadCore\r
+};\r
+\r
+CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI mCustomGuidedSectionExtractionPpi = {\r
+ CustomGuidedSectionExtract\r
+};\r
+\r
+CONST EFI_PEI_DECOMPRESS_PPI mDecompressPpi = {\r
+ Decompress\r
+};\r
+\r
+CONST EFI_PEI_PPI_DESCRIPTOR mPpiList[] = {\r
+ {\r
+ EFI_PEI_PPI_DESCRIPTOR_PPI,\r
+ &gEfiDxeIplPpiGuid,\r
+ (VOID *) &mDxeIplPpi\r
+ },\r
+ {\r
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+ &gEfiPeiDecompressPpiGuid,\r
+ (VOID *) &mDecompressPpi\r
+ }\r
+};\r
+\r
+CONST EFI_PEI_PPI_DESCRIPTOR gEndOfPeiSignalPpi = {\r
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
+ &gEfiEndOfPeiSignalPpiGuid,\r
+ NULL\r
+};\r
+\r
+/**\r
+ Entry point of DXE IPL PEIM.\r
+\r
+ This function installs DXE IPL PPI and Decompress PPI. It also reloads\r
+ itself to memory on non-S3 resume boot path.\r
+\r
+ @param[in] FileHandle Handle of the file being invoked.\r
+ @param[in] PeiServices Describes the list of possible PEI Services.\r
+\r
+ @retval EFI_SUCESS The entry point of DXE IPL PEIM executes successfully.\r
+ @retval Others Some error occurs during the execution of this function.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+PeimInitializeDxeIpl (\r
+ IN EFI_PEI_FILE_HANDLE FileHandle,\r
+ IN CONST EFI_PEI_SERVICES **PeiServices\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_GUID *ExtractHandlerGuidTable;\r
+ UINTN ExtractHandlerNumber;\r
+ EFI_PEI_PPI_DESCRIPTOR *GuidPpi;\r
+\r
+ //\r
+ // Get custom extract guided section method guid list\r
+ //\r
+ ExtractHandlerNumber = ExtractGuidedSectionGetGuidList (&ExtractHandlerGuidTable);\r
+\r
+ //\r
+ // Install custom extraction guid PPI\r
+ //\r
+ if (ExtractHandlerNumber > 0) {\r
+ GuidPpi = (EFI_PEI_PPI_DESCRIPTOR *) AllocatePool (ExtractHandlerNumber * sizeof (EFI_PEI_PPI_DESCRIPTOR));\r
+ ASSERT (GuidPpi != NULL);\r
+ while (ExtractHandlerNumber-- > 0) {\r
+ GuidPpi->Flags = EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST;\r
+ GuidPpi->Ppi = (VOID *) &mCustomGuidedSectionExtractionPpi;\r
+ GuidPpi->Guid = &ExtractHandlerGuidTable[ExtractHandlerNumber];\r
+ Status = PeiServicesInstallPpi (GuidPpi++);\r
+ ASSERT_EFI_ERROR(Status);\r
+ }\r
+ }\r
+\r
+ //\r
+ // Install DxeIpl and Decompress PPIs.\r
+ //\r
+ Status = PeiServicesInstallPpi (mPpiList);\r
+ ASSERT_EFI_ERROR(Status);\r
+\r
+ return Status;\r
+}\r
+\r
+/**\r
+ The ExtractSection() function processes the input section and\r
+ returns a pointer to the section contents. If the section being\r
+ extracted does not require processing (if the section\r
+ GuidedSectionHeader.Attributes has the\r
+ EFI_GUIDED_SECTION_PROCESSING_REQUIRED field cleared), then\r
+ OutputBuffer is just updated to point to the start of the\r
+ section's contents. Otherwise, *Buffer must be allocated\r
+ from PEI permanent memory.\r
+\r
+ @param[in] This Indicates the\r
+ EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI instance.\r
+ Buffer containing the input GUIDed section to be\r
+ processed. OutputBuffer OutputBuffer is\r
+ allocated from PEI permanent memory and contains\r
+ the new section stream.\r
+ @param[in] InputSection A pointer to the input buffer, which contains\r
+ the input section to be processed.\r
+ @param[out] OutputBuffer A pointer to a caller-allocated buffer, whose\r
+ size is specified by the contents of OutputSize.\r
+ @param[out] OutputSize A pointer to a caller-allocated\r
+ UINTN in which the size of *OutputBuffer\r
+ allocation is stored. If the function\r
+ returns anything other than EFI_SUCCESS,\r
+ the value of OutputSize is undefined.\r
+ @param[out] AuthenticationStatus A pointer to a caller-allocated\r
+ UINT32 that indicates the\r
+ authentication status of the\r
+ output buffer. If the input\r
+ section's GuidedSectionHeader.\r
+ Attributes field has the\r
+ EFI_GUIDED_SECTION_AUTH_STATUS_VALID\r
+ bit as clear,\r
+ AuthenticationStatus must return\r
+ zero. These bits reflect the\r
+ status of the extraction\r
+ operation. If the function\r
+ returns anything other than\r
+ EFI_SUCCESS, the value of\r
+ AuthenticationStatus is\r
+ undefined.\r
+\r
+ @retval EFI_SUCCESS The InputSection was\r
+ successfully processed and the\r
+ section contents were returned.\r
+\r
+ @retval EFI_OUT_OF_RESOURCES The system has insufficient\r
+ resources to process the request.\r
+\r
+ @retval EFI_INVALID_PARAMETER The GUID in InputSection does\r
+ not match this instance of the\r
+ GUIDed Section Extraction PPI.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+CustomGuidedSectionExtract (\r
+ IN CONST EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI *This,\r
+ IN CONST VOID *InputSection,\r
+ OUT VOID **OutputBuffer,\r
+ OUT UINTN *OutputSize,\r
+ OUT UINT32 *AuthenticationStatus\r
+)\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 *ScratchBuffer;\r
+ UINT32 ScratchBufferSize;\r
+ UINT32 OutputBufferSize;\r
+ UINT16 SectionAttribute;\r
+\r
+ //\r
+ // Init local variable\r
+ //\r
+ ScratchBuffer = NULL;\r
+\r
+ //\r
+ // Call GetInfo to get the size and attribute of input guided section data.\r
+ //\r
+ Status = ExtractGuidedSectionGetInfo (\r
+ InputSection,\r
+ &OutputBufferSize,\r
+ &ScratchBufferSize,\r
+ &SectionAttribute\r
+ );\r
+\r
+ if (EFI_ERROR (Status)) {\r
+ DEBUG ((DEBUG_ERROR, "GetInfo from guided section Failed - %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ if (ScratchBufferSize != 0) {\r
+ //\r
+ // Allocate scratch buffer\r
+ //\r
+ ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));\r
+ if (ScratchBuffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ }\r
+\r
+ if (((SectionAttribute & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) != 0) && OutputBufferSize > 0) {\r
+ //\r
+ // Allocate output buffer\r
+ //\r
+ *OutputBuffer = AllocatePages (EFI_SIZE_TO_PAGES (OutputBufferSize) + 1);\r
+ if (*OutputBuffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ DEBUG ((DEBUG_INFO, "Customized Guided section Memory Size required is 0x%x and address is 0x%p\n", OutputBufferSize, *OutputBuffer));\r
+ //\r
+ // *OutputBuffer still is one section. Adjust *OutputBuffer offset,\r
+ // skip EFI section header to make section data at page alignment.\r
+ //\r
+ *OutputBuffer = (VOID *)((UINT8 *) *OutputBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER));\r
+ }\r
+\r
+ Status = ExtractGuidedSectionDecode (\r
+ InputSection,\r
+ OutputBuffer,\r
+ ScratchBuffer,\r
+ AuthenticationStatus\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Decode failed\r
+ //\r
+ DEBUG ((DEBUG_ERROR, "Extract guided section Failed - %r\n", Status));\r
+ return Status;\r
+ }\r
+\r
+ *OutputSize = (UINTN) OutputBufferSize;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
+/**\r
+ Decompresses a section to the output buffer.\r
+\r
+ This function looks up the compression type field in the input section and\r
+ applies the appropriate compression algorithm to compress the section to a\r
+ callee allocated buffer.\r
+\r
+ @param[in] This Points to this instance of the\r
+ EFI_PEI_DECOMPRESS_PEI PPI.\r
+ @param[in] CompressionSection Points to the compressed section.\r
+ @param[out] OutputBuffer Holds the returned pointer to the decompressed\r
+ sections.\r
+ @param[out] OutputSize Holds the returned size of the decompress\r
+ section streams.\r
+\r
+ @retval EFI_SUCCESS The section was decompressed successfully.\r
+ OutputBuffer contains the resulting data and\r
+ OutputSize contains the resulting size.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+Decompress (\r
+ IN CONST EFI_PEI_DECOMPRESS_PPI *This,\r
+ IN CONST EFI_COMPRESSION_SECTION *CompressionSection,\r
+ OUT VOID **OutputBuffer,\r
+ OUT UINTN *OutputSize\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ UINT8 *DstBuffer;\r
+ UINT8 *ScratchBuffer;\r
+ UINT32 DstBufferSize;\r
+ UINT32 ScratchBufferSize;\r
+ VOID *CompressionSource;\r
+ UINT32 CompressionSourceSize;\r
+ UINT32 UncompressedLength;\r
+ UINT8 CompressionType;\r
+\r
+ if (CompressionSection->CommonHeader.Type != EFI_SECTION_COMPRESSION) {\r
+ ASSERT (FALSE);\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ if (IS_SECTION2 (CompressionSection)) {\r
+ CompressionSource = (VOID *) ((UINT8 *) CompressionSection + sizeof (EFI_COMPRESSION_SECTION2));\r
+ CompressionSourceSize = (UINT32) (SECTION2_SIZE (CompressionSection) - sizeof (EFI_COMPRESSION_SECTION2));\r
+ UncompressedLength = ((EFI_COMPRESSION_SECTION2 *) CompressionSection)->UncompressedLength;\r
+ CompressionType = ((EFI_COMPRESSION_SECTION2 *) CompressionSection)->CompressionType;\r
+ } else {\r
+ CompressionSource = (VOID *) ((UINT8 *) CompressionSection + sizeof (EFI_COMPRESSION_SECTION));\r
+ CompressionSourceSize = (UINT32) (SECTION_SIZE (CompressionSection) - sizeof (EFI_COMPRESSION_SECTION));\r
+ UncompressedLength = CompressionSection->UncompressedLength;\r
+ CompressionType = CompressionSection->CompressionType;\r
+ }\r
+\r
+ //\r
+ // This is a compression set, expand it\r
+ //\r
+ switch (CompressionType) {\r
+ case EFI_STANDARD_COMPRESSION:\r
+ if (TRUE) {\r
+ //\r
+ // Load EFI standard compression.\r
+ // For compressed data, decompress them to destination buffer.\r
+ //\r
+ Status = UefiDecompressGetInfo (\r
+ CompressionSource,\r
+ CompressionSourceSize,\r
+ &DstBufferSize,\r
+ &ScratchBufferSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // GetInfo failed\r
+ //\r
+ DEBUG ((DEBUG_ERROR, "Decompress GetInfo Failed - %r\n", Status));\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ //\r
+ // Allocate scratch buffer\r
+ //\r
+ ScratchBuffer = AllocatePages (EFI_SIZE_TO_PAGES (ScratchBufferSize));\r
+ if (ScratchBuffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Allocate destination buffer, extra one page for adjustment\r
+ //\r
+ DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1);\r
+ if (DstBuffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI section header\r
+ // to make section data at page alignment.\r
+ //\r
+ DstBuffer = DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER);\r
+ //\r
+ // Call decompress function\r
+ //\r
+ Status = UefiDecompress (\r
+ CompressionSource,\r
+ DstBuffer,\r
+ ScratchBuffer\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ //\r
+ // Decompress failed\r
+ //\r
+ DEBUG ((DEBUG_ERROR, "Decompress Failed - %r\n", Status));\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ break;\r
+ } else {\r
+ //\r
+ // PcdDxeIplSupportUefiDecompress is FALSE\r
+ // Don't support UEFI decompression algorithm.\r
+ //\r
+ ASSERT (FALSE);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ case EFI_NOT_COMPRESSED:\r
+ //\r
+ // Allocate destination buffer\r
+ //\r
+ DstBufferSize = UncompressedLength;\r
+ DstBuffer = AllocatePages (EFI_SIZE_TO_PAGES (DstBufferSize) + 1);\r
+ if (DstBuffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ //\r
+ // Adjust DstBuffer offset, skip EFI section header\r
+ // to make section data at page alignment.\r
+ //\r
+ DstBuffer = DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COMMON_SECTION_HEADER);\r
+ //\r
+ // stream is not actually compressed, just encapsulated. So just copy it.\r
+ //\r
+ CopyMem (DstBuffer, CompressionSource, DstBufferSize);\r
+ break;\r
+\r
+ default:\r
+ //\r
+ // Don't support other unknown compression type.\r
+ //\r
+ ASSERT (FALSE);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+\r
+ *OutputSize = DstBufferSize;\r
+ *OutputBuffer = DstBuffer;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Main entry point to last PEIM.\r
+\r
+ This function finds DXE Core in the firmware volume and transfer the control to\r
+ DXE core.\r
+\r
+ @param[in] This Entry point for DXE IPL PPI.\r
+ @param[in] PeiServices General purpose services available to every PEIM.\r
+ @param[in] HobList Address to the Pei HOB list.\r
+\r
+ @return EFI_SUCCESS DXE core was successfully loaded.\r
+ @return EFI_OUT_OF_RESOURCES There are not enough resources to load DXE core.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DxeLoadCore (\r
+ IN CONST EFI_DXE_IPL_PPI *This,\r
+ IN EFI_PEI_SERVICES **PeiServices,\r
+ IN EFI_PEI_HOB_POINTERS HobList\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ DEBUG ((DEBUG_INFO | DEBUG_INIT, "FSP HOB is located at 0x%08X\n", HobList));\r
+\r
+ //\r
+ // Give control back to bootloader after FspInit\r
+ //\r
+ DEBUG ((DEBUG_INFO | DEBUG_INIT, "FSP is waiting for NOTIFY\n"));\r
+ FspInitDone ();\r
+\r
+ //\r
+ // Bootloader called FSP again through NotifyPhase\r
+ //\r
+ FspWaitForNotify ();\r
+\r
+ //\r
+ // End of PEI phase signal\r
+ //\r
+ Status = PeiServicesInstallPpi (&gEndOfPeiSignalPpi);\r
+ ASSERT_EFI_ERROR (Status);\r
+\r
+ //\r
+ // Give control back to the boot loader framework caller\r
+ //\r
+ DEBUG ((DEBUG_INFO | DEBUG_INIT, "============= PEIM FSP is Completed =============\n\n"));\r
+\r
+ SetFspApiReturnStatus(EFI_SUCCESS);\r
+\r
+ SetFspMeasurePoint (FSP_PERF_ID_API_NOTIFY_RDYBOOT_EXIT);\r
+\r
+ Pei2LoaderSwitchStack();\r
+\r
+ //\r
+ // Should not come here\r
+ //\r
+ while (TRUE) {\r
+ DEBUG ((DEBUG_ERROR, "No FSP API should be called after FSP is DONE!\n"));\r
+ SetFspApiReturnStatus(EFI_UNSUPPORTED);\r
+ Pei2LoaderSwitchStack();\r
+ }\r
+\r
+ return EFI_SUCCESS;\r
+}\r