X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=OvmfPkg%2FSec%2FFindPeiCore.c;h=01cd70f5baf0dab6d3aa2b0c6ba5f616b36e8e62;hp=7d13ebb4bcb41645796d0851fdafcc9149e0d467;hb=c1c2669c6bb3ed4e23c06a93e60450a4fc3eccf2;hpb=8cf01cae78c1e7b823587aac1b672a8c5adccaa9 diff --git a/OvmfPkg/Sec/FindPeiCore.c b/OvmfPkg/Sec/FindPeiCore.c index 7d13ebb4bc..01cd70f5ba 100644 --- a/OvmfPkg/Sec/FindPeiCore.c +++ b/OvmfPkg/Sec/FindPeiCore.c @@ -1,7 +1,7 @@ /** @file Locate the entry point for the PEI Core - Copyright (c) 2008 - 2009, Intel Corporation + Copyright (c) 2008 - 2010, Intel Corporation All rights reserved. This program and the accompanying materials are licensed and made available under the terms and conditions of the BSD License @@ -15,16 +15,151 @@ #include #include +#include +#include +#include +#include #include #include "SecMain.h" -VOID +/** + Locates the main boot firmware volume. + + @param[in,out] BootFv On input, the base of the BootFv + On output, the decompressed main firmware volume + + @retval EFI_SUCCESS The main firmware volume was located and decompressed + @retval EFI_NOT_FOUND The main firmware volume was not found + +**/ +EFI_STATUS +FindMainFv ( + IN OUT EFI_FIRMWARE_VOLUME_HEADER **BootFv + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *Fv; + UINTN Distance; + BOOLEAN Found; + + ASSERT (((UINTN) *BootFv & EFI_PAGE_MASK) == 0); + + Found = FALSE; + Fv = *BootFv; + Distance = (UINTN) (*BootFv)->FvLength; + do { + Fv = (EFI_FIRMWARE_VOLUME_HEADER*) ((UINT8*) Fv - EFI_PAGE_SIZE); + Distance += EFI_PAGE_SIZE; + if (Distance > SIZE_32MB) { + return EFI_NOT_FOUND; + } + + if (Fv->Signature != EFI_FVH_SIGNATURE) { + continue; + } + + if ((UINTN) Fv->FvLength > Distance) { + continue; + } + + *BootFv = Fv; + return EFI_SUCCESS; + + } while (TRUE); +} + + +/** + Locates a section within a series of sections + with the specified section type. + + @param[in] Sections The sections to search + @param[in] SizeOfSections Total size of all sections + @param[in] SectionType The section type to locate + @param[out] FoundSection The FFS section if found + + @retval EFI_SUCCESS The file and section was found + @retval EFI_NOT_FOUND The file and section was not found + @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted + +**/ +EFI_STATUS +FindFfsSectionInSections ( + IN VOID *Sections, + IN UINTN SizeOfSections, + IN EFI_SECTION_TYPE SectionType, + OUT EFI_COMMON_SECTION_HEADER **FoundSection + ) +{ + EFI_PHYSICAL_ADDRESS CurrentAddress; + UINT32 Size; + EFI_PHYSICAL_ADDRESS EndOfSections; + EFI_COMMON_SECTION_HEADER *Section; + EFI_PHYSICAL_ADDRESS EndOfSection; + + // + // Loop through the FFS file sections within the PEI Core FFS file + // + EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN) Sections; + EndOfSections = EndOfSection + SizeOfSections; + for (;;) { + if (EndOfSection == EndOfSections) { + break; + } + CurrentAddress = (EndOfSection + 3) & ~(3ULL); + if (CurrentAddress >= EndOfSections) { + return EFI_VOLUME_CORRUPTED; + } + + Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress; + DEBUG ((EFI_D_INFO, "Section->Type: 0x%x\n", Section->Type)); + + Size = SECTION_SIZE (Section); + if (Size < sizeof (*Section)) { + return EFI_VOLUME_CORRUPTED; + } + + EndOfSection = CurrentAddress + Size; + if (EndOfSection > EndOfSections) { + return EFI_VOLUME_CORRUPTED; + } + + // + // Look for the requested section type + // + if (Section->Type == SectionType) { + *FoundSection = Section; + return EFI_SUCCESS; + } + DEBUG ((EFI_D_INFO, "Section->Type (0x%x) != SectionType (0x%x)\n", Section->Type, SectionType)); + } + + return EFI_NOT_FOUND; +} + + +/** + Locates a FFS file with the specified file type and a section + within that file with the specified section type. + + @param[in] Fv The firmware volume to search + @param[in] FileType The file type to locate + @param[in] SectionType The section type to locate + @param[out] FoundSection The FFS section if found + + @retval EFI_SUCCESS The file and section was found + @retval EFI_NOT_FOUND The file and section was not found + @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted + +**/ +EFI_STATUS EFIAPI -FindPeiCoreEntryPoint ( - IN EFI_FIRMWARE_VOLUME_HEADER *BootFirmwareVolumePtr, - OUT VOID **PeiCoreEntryPoint +FindFfsFileAndSection ( + IN EFI_FIRMWARE_VOLUME_HEADER *Fv, + IN EFI_FV_FILETYPE FileType, + IN EFI_SECTION_TYPE SectionType, + OUT EFI_COMMON_SECTION_HEADER **FoundSection ) { EFI_STATUS Status; @@ -33,71 +168,219 @@ FindPeiCoreEntryPoint ( EFI_FFS_FILE_HEADER *File; UINT32 Size; EFI_PHYSICAL_ADDRESS EndOfFile; - EFI_COMMON_SECTION_HEADER *Section; - EFI_PHYSICAL_ADDRESS EndOfSection; - *PeiCoreEntryPoint = NULL; + if (Fv->Signature != EFI_FVH_SIGNATURE) { + DEBUG ((EFI_D_INFO, "FV at %p does not have FV header signature\n", Fv)); + return EFI_VOLUME_CORRUPTED; + } - CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) BootFirmwareVolumePtr; - EndOfFirmwareVolume = CurrentAddress + BootFirmwareVolumePtr->FvLength; + CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Fv; + EndOfFirmwareVolume = CurrentAddress + Fv->FvLength; // // Loop through the FFS files in the Boot Firmware Volume // - for (EndOfFile = CurrentAddress + BootFirmwareVolumePtr->HeaderLength; ; ) { + for (EndOfFile = CurrentAddress + Fv->HeaderLength; ; ) { - CurrentAddress = (EndOfFile + 7) & 0xfffffffffffffff8ULL; + CurrentAddress = (EndOfFile + 7) & ~(7ULL); if (CurrentAddress > EndOfFirmwareVolume) { - return; + return EFI_VOLUME_CORRUPTED; } File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress; Size = *(UINT32*) File->Size & 0xffffff; - if (Size < (sizeof (*File) + sizeof (*Section))) { - return; + if (Size < (sizeof (*File) + sizeof (EFI_COMMON_SECTION_HEADER))) { + return EFI_VOLUME_CORRUPTED; } + DEBUG ((EFI_D_INFO, "File->Type: 0x%x\n", File->Type)); EndOfFile = CurrentAddress + Size; if (EndOfFile > EndOfFirmwareVolume) { - return; + return EFI_VOLUME_CORRUPTED; } // - // Look for PEI Core files + // Look for the request file type // - if (File->Type != EFI_FV_FILETYPE_PEI_CORE) { + if (File->Type != FileType) { + DEBUG ((EFI_D_INFO, "File->Type (0x%x) != FileType (0x%x)\n", File->Type, FileType)); continue; } - // - // Loop through the FFS file sections within the PEI Core FFS file - // - EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN) (File + 1); - for (;;) { - CurrentAddress = (EndOfSection + 3) & 0xfffffffffffffffcULL; - Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress; - - Size = *(UINT32*) Section->Size & 0xffffff; - if (Size < sizeof (*Section)) { - return; - } - - EndOfSection = CurrentAddress + Size; - if (EndOfSection > EndOfFile) { - return; - } - - // - // Look for executable sections - // - if (Section->Type == EFI_SECTION_PE32) { - Status = PeCoffLoaderGetEntryPoint ((VOID*) (Section + 1), PeiCoreEntryPoint); - if (!EFI_ERROR (Status)) { - return; - } - } + Status = FindFfsSectionInSections ( + (VOID*) (File + 1), + (UINTN) EndOfFile - (UINTN) (File + 1), + SectionType, + FoundSection + ); + if (!EFI_ERROR (Status) || (Status == EFI_VOLUME_CORRUPTED)) { + return Status; } + } + + return EFI_NOT_FOUND; +} + + +/** + Locates the compressed main firmware volume and decompresses it. + + @param[in,out] Fv On input, the firmware volume to search + On output, the decompressed main FV + + @retval EFI_SUCCESS The file and section was found + @retval EFI_NOT_FOUND The file and section was not found + @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted + +**/ +EFI_STATUS +EFIAPI +DecompressGuidedFv ( + IN OUT EFI_FIRMWARE_VOLUME_HEADER **Fv + ) +{ + EFI_STATUS Status; + EFI_GUID_DEFINED_SECTION *Section; + UINT32 OutputBufferSize; + UINT32 ScratchBufferSize; + UINT16 SectionAttribute; + UINT32 AuthenticationStatus; + VOID *OutputBuffer; + VOID *ScratchBuffer; + EFI_FIRMWARE_VOLUME_IMAGE_SECTION *NewFvSection; + EFI_FIRMWARE_VOLUME_HEADER *NewFv; + NewFvSection = (EFI_FIRMWARE_VOLUME_IMAGE_SECTION*) NULL; + + Status = FindFfsFileAndSection ( + *Fv, + EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, + EFI_SECTION_GUID_DEFINED, + (EFI_COMMON_SECTION_HEADER**) &Section + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Unable to find GUID defined section\n")); + return Status; + } + + Status = ExtractGuidedSectionGetInfo ( + Section, + &OutputBufferSize, + &ScratchBufferSize, + &SectionAttribute + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Unable to GetInfo for GUIDed section\n")); + return Status; + } + + //PcdGet32 (PcdOvmfMemFvBase), PcdGet32 (PcdOvmfMemFvSize) + OutputBuffer = (VOID*) ((UINT8*)(UINTN) PcdGet32 (PcdOvmfMemFvBase) + SIZE_1MB); + ScratchBuffer = ALIGN_POINTER ((UINT8*) OutputBuffer + OutputBufferSize, SIZE_1MB); + Status = ExtractGuidedSectionDecode ( + Section, + &OutputBuffer, + ScratchBuffer, + &AuthenticationStatus + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Error during GUID section decode\n")); + return Status; + } + + Status = FindFfsSectionInSections ( + OutputBuffer, + OutputBufferSize, + EFI_SECTION_FIRMWARE_VOLUME_IMAGE, + (EFI_COMMON_SECTION_HEADER**) &NewFvSection + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Unable to find FV image in extracted data\n")); + return Status; } + + NewFv = (EFI_FIRMWARE_VOLUME_HEADER*)(UINTN) PcdGet32 (PcdOvmfMemFvBase); + CopyMem (NewFv, (VOID*) (NewFvSection + 1), PcdGet32 (PcdOvmfMemFvSize)); + + if (NewFv->Signature != EFI_FVH_SIGNATURE) { + DEBUG ((EFI_D_ERROR, "Extracted FV at %p does not have FV header signature\n", NewFv)); + CpuDeadLoop (); + return EFI_VOLUME_CORRUPTED; + } + + *Fv = NewFv; + return EFI_SUCCESS; +} + + +/** + Locates the PEI Core entry point address + + @param[in] Fv The firmware volume to search + @param[out] PeiCoreEntryPoint The entry point of the PEI Core image + + @retval EFI_SUCCESS The file and section was found + @retval EFI_NOT_FOUND The file and section was not found + @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted + +**/ +EFI_STATUS +EFIAPI +FindPeiCoreEntryPointInFv ( + IN EFI_FIRMWARE_VOLUME_HEADER *Fv, + OUT VOID **PeiCoreEntryPoint + ) +{ + EFI_STATUS Status; + EFI_COMMON_SECTION_HEADER *Section; + + Status = FindFfsFileAndSection ( + Fv, + EFI_FV_FILETYPE_PEI_CORE, + EFI_SECTION_PE32, + &Section + ); + if (EFI_ERROR (Status)) { + Status = FindFfsFileAndSection ( + Fv, + EFI_FV_FILETYPE_PEI_CORE, + EFI_SECTION_TE, + &Section + ); + if (EFI_ERROR (Status)) { + DEBUG ((EFI_D_ERROR, "Unable to find PEI Core image\n")); + return Status; + } + } + + return PeCoffLoaderGetEntryPoint ((VOID*) (Section + 1), PeiCoreEntryPoint); +} + + +/** + Locates the PEI Core entry point address + + @param[in,out] Fv The firmware volume to search + @param[out] PeiCoreEntryPoint The entry point of the PEI Core image + + @retval EFI_SUCCESS The file and section was found + @retval EFI_NOT_FOUND The file and section was not found + @retval EFI_VOLUME_CORRUPTED The firmware volume was corrupted + +**/ +VOID +EFIAPI +FindPeiCoreEntryPoint ( + IN OUT EFI_FIRMWARE_VOLUME_HEADER **BootFv, + OUT VOID **PeiCoreEntryPoint + ) +{ + *PeiCoreEntryPoint = NULL; + + FindMainFv (BootFv); + + DecompressGuidedFv (BootFv); + + FindPeiCoreEntryPointInFv (*BootFv, PeiCoreEntryPoint); }