From nobody Mon Feb 9 19:53:04 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) client-ip=66.175.222.108; envelope-from=bounce+27952+84807+1787277+3901457@groups.io; helo=mail02.groups.io; Authentication-Results: mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+84807+1787277+3901457@groups.io; dmarc=fail(p=none dis=none) header.from=intel.com ARC-Seal: i=1; a=rsa-sha256; t=1639489322; cv=none; d=zohomail.com; s=zohoarc; b=ID8T8wy2s5xNRSWoWtciavLj6xVikrzJ/MwnlDfvdzvjJPe+PCcZ6azyuqBIY1AssIBqHoZkGpbOxllDHFtL9Z7fDMcPjsy5C8zmVHb+IqoKddSjiOXGWInKxC9Xm+v2WyuLh2PWbVkfO0ptJtecJFbgFHUxAgthNhVf6qCyAsg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1639489322; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:List-Subscribe:List-Id:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:References:Sender:Subject:To; bh=ip/ZEvFfGO+1Z23WD4kq5OkGwmh1Cy81A0OozmODvb0=; b=LA3Cw9WO5dJgVr7JiP0/HR0AtD5QzmFLHM7KvmTZldQT8E+9fUuHrrJ2Tb9EumHnzlzDlu3eSq5gb67fDwOBkga9OVJg3BgbPgGadtvbb/LTXKN6U+u1xxPME5oGFSRiXa7DI9jv8K7qUr2yUvEHdm7tmsT/dXeXoKk7POXxZAM= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=pass; spf=pass (zohomail.com: domain of groups.io designates 66.175.222.108 as permitted sender) smtp.mailfrom=bounce+27952+84807+1787277+3901457@groups.io; dmarc=fail header.from= (p=none dis=none) Received: from mail02.groups.io (mail02.groups.io [66.175.222.108]) by mx.zohomail.com with SMTPS id 1639489322332617.3799561517437; Tue, 14 Dec 2021 05:42:02 -0800 (PST) Return-Path: X-Received: by 127.0.0.2 with SMTP id bPVRYY1788612x5FCdJDOsVW; Tue, 14 Dec 2021 05:42:02 -0800 X-Received: from mga12.intel.com (mga12.intel.com [192.55.52.136]) by mx.groups.io with SMTP id smtpd.web10.25718.1639489320336796392 for ; Tue, 14 Dec 2021 05:42:00 -0800 X-IronPort-AV: E=McAfee;i="6200,9189,10197"; a="218993587" X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="218993587" X-Received: from orsmga006.jf.intel.com ([10.7.209.51]) by fmsmga106.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Dec 2021 05:41:51 -0800 X-IronPort-AV: E=Sophos;i="5.88,205,1635231600"; d="scan'208";a="465094031" X-Received: from mxu9-mobl1.ccr.corp.intel.com ([10.255.30.115]) by orsmga006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 14 Dec 2021 05:41:47 -0800 From: "Min Xu" To: devel@edk2.groups.io Cc: Min Xu , Michael D Kinney , Brijesh Singh , Erdem Aktas , James Bottomley , Jiewen Yao , Tom Lendacky , Gerd Hoffmann , Leif Lindholm , Ard Biesheuvel , Abner Chang , Daniel Schaefer Subject: [edk2-devel] [PATCH 02/10] EmbeddedPkg/PrePiLib: Update PrePiLib Date: Tue, 14 Dec 2021 21:41:18 +0800 Message-Id: <20211214134126.869-3-min.m.xu@intel.com> In-Reply-To: <20211214134126.869-1-min.m.xu@intel.com> References: <20211214134126.869-1-min.m.xu@intel.com> MIME-Version: 1.0 Precedence: Bulk List-Unsubscribe: List-Subscribe: List-Help: Sender: devel@edk2.groups.io List-Id: Mailing-List: list devel@edk2.groups.io; contact devel+owner@edk2.groups.io Reply-To: devel@edk2.groups.io,min.m.xu@intel.com X-Gm-Message-State: uG9cuPf0AGdeLcYNEEfxFf3nx1787277AA= Content-Transfer-Encoding: quoted-printable DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=groups.io; q=dns/txt; s=20140610; t=1639489322; bh=uykghbSsELKRDFeUfEsBqF8cASrwvxu0TfNGp8gHD4A=; h=Cc:Date:From:Reply-To:Subject:To; b=GcVANZRUMIFAM/CNjlvG+lU596xrJu3QS5HIQlYD31EXjVu30WaJ5EcZ0BvkoQNydKz 2/fzg2FG9wYeM2+fsO4qwJGEZG5WqxGmLXOKq0Y/EGaIUX8dYTrQsifbqevj7Fw14LiED cCbACGrn6O9qQv8A42DwZ7pD+606olkVXBo= X-ZohoMail-DKIM: pass (identity @groups.io) X-ZM-MESSAGEID: 1639489323788100014 Content-Type: text/plain; charset="utf-8" RFC: https://bugzilla.tianocore.org/show_bug.cgi?id=3D3429 There are below new functions added in EmbeddedPkg/PrePiLib. 1. FfsAnyFvFindFileByName This function is to find the file by name in the FvImage. 2. FfsDecompressSection This function is to decompress a compressed section. 3. FfsProcessFvFileEx This function is to decompress a compressed section and create FvHob/Fv2Hob for all the FvImages. Cc: Michael D Kinney Cc: Brijesh Singh Cc: Erdem Aktas Cc: James Bottomley Cc: Jiewen Yao Cc: Tom Lendacky Cc: Gerd Hoffmann Cc: Leif Lindholm Cc: Ard Biesheuvel Cc: Abner Chang Cc: Daniel Schaefer Signed-off-by: Min Xu --- EmbeddedPkg/Include/Library/PrePiLib.h | 21 +- EmbeddedPkg/Library/PrePiLib/FwVol.c | 399 ++++++++++++++++++++++++- 2 files changed, 418 insertions(+), 2 deletions(-) diff --git a/EmbeddedPkg/Include/Library/PrePiLib.h b/EmbeddedPkg/Include/L= ibrary/PrePiLib.h index 7b2cea296f1c..80698e559cdf 100644 --- a/EmbeddedPkg/Include/Library/PrePiLib.h +++ b/EmbeddedPkg/Include/Library/PrePiLib.h @@ -180,6 +180,9 @@ FfsAnyFvFindFirstFile ( =20 /** Get Fv image from the FV type file, then add FV & FV2 Hob. + This function can handle the situation that a compressed + section contains multi-FvImages and create FV/FV2 Hob for + all the FvImages. =20 @param FileHandle File handle of a Fv type file. =20 @@ -190,7 +193,7 @@ FfsAnyFvFindFirstFile ( **/ EFI_STATUS EFIAPI -FfsProcessFvFile ( +FfsProcessFvFileEx ( IN EFI_PEI_FILE_HANDLE FvFileHandle ); =20 @@ -735,4 +738,20 @@ DecompressFirstFv ( VOID ); =20 +/** + * This function find the file by GUID name from a FvImage. + * + * @param Name GUID name of the file + * @param VolumeHandle The handle of the Fv + * @param FileHandle The handle of the File + * @return EFI_STATUS Successfully find the file. + */ +EFI_STATUS +EFIAPI +FfsAnyFvFindFileByName ( + IN CONST EFI_GUID *Name, + OUT EFI_PEI_FV_HANDLE *VolumeHandle, + OUT EFI_PEI_FILE_HANDLE *FileHandle + ); + #endif diff --git a/EmbeddedPkg/Library/PrePiLib/FwVol.c b/EmbeddedPkg/Library/Pre= PiLib/FwVol.c index 92ae68f0d382..e714f4876ff5 100644 --- a/EmbeddedPkg/Library/PrePiLib/FwVol.c +++ b/EmbeddedPkg/Library/PrePiLib/FwVol.c @@ -335,7 +335,7 @@ FfsProcessSection ( =20 Status =3D UefiDecompressGetInfo ( CompressedData, - CompressedDataLength, + (UINT32)CompressedDataLength, &DstBufferSize, &ScratchBufferSize ); @@ -850,6 +850,403 @@ FfsProcessFvFile ( &FvImageInfo.FvName, &(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name) ); + return EFI_SUCCESS; +} + +/** + * This function find the file by GUID name from a FvImage. + * + * @param Name GUID name of the file + * @param VolumeHandle The handle of the Fv + * @param FileHandle The handle of the File + * @return EFI_STATUS Successfully find the file. + */ +EFI_STATUS +EFIAPI +FfsAnyFvFindFileByName ( + IN CONST EFI_GUID *Name, + OUT EFI_PEI_FV_HANDLE *VolumeHandle, + OUT EFI_PEI_FILE_HANDLE *FileHandle + ) +{ + EFI_STATUS Status; + UINTN Instance; + + // + // Search every FV for the file by name + // + Instance =3D 0; + *FileHandle =3D NULL; + + while (1) { + Status =3D FfsFindNextVolume (Instance++, VolumeHandle); + if (EFI_ERROR (Status)) { + break; + } + + Status =3D FfsFindFileByName (Name, *VolumeHandle, FileHandle); + if (!EFI_ERROR (Status)) { + break; + } + } + + DEBUG ((DEBUG_INFO, "FfsAnyFvFindFileByName with name =3D %g, %r\n", Nam= e, Status)); + + return Status; +} + +/** + * This function decompress the compressed section. + * + * @param FileHandle File handle + * @param OutputBuffer Pointer to the decompressed data + * @param OutputBufferSize Pointer to the size of the decompressed data + * @return EFI_STATUS + */ +EFI_STATUS +FfsDecompressSection ( + IN VOID *FileHandle, + OUT VOID **OutputBuffer, + OUT UINT32 *OutputBufferSize + ) +{ + EFI_STATUS Status; + UINT32 SectionLength; + UINT32 ParsedLength; + EFI_COMPRESSION_SECTION *CompressionSection; + EFI_COMPRESSION_SECTION2 *CompressionSection2; + UINT32 DstBufferSize; + VOID *ScratchBuffer; + UINT32 ScratchBufferSize; + VOID *DstBuffer; + UINT16 SectionAttribute; + UINT32 AuthenticationStatus; + CHAR8 *CompressedData; + UINTN CompressedDataLength; + EFI_COMMON_SECTION_HEADER *Section; + UINT32 SectionSize; + EFI_FFS_FILE_HEADER *FfsFileHeader; + + *OutputBuffer =3D NULL; + *OutputBufferSize =3D 0; + ParsedLength =3D 0; + Status =3D EFI_NOT_FOUND; + + FfsFileHeader =3D (EFI_FFS_FILE_HEADER *)(FileHandle); + // + // Size is 24 bits wide so mask upper 8 bits. + // Does not include FfsFileHeader header size + // FileSize is adjusted to FileOccupiedSize as it is 8 byte aligned. + // + Section =3D (EFI_COMMON_SECTION_HEADER *)(FfsFileHeader + 1); + SectionSize =3D *(UINT32 *)(FfsFileHeader->Size) & 0x00FFFFFF; + SectionSize -=3D sizeof (EFI_FFS_FILE_HEADER); + + while (ParsedLength < SectionSize) { + if (IS_SECTION2 (Section)) { + ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF); + } + + DEBUG ((DEBUG_INFO, "Check section type=3D%x\n", Section->Type)); + + if ((Section->Type =3D=3D EFI_SECTION_COMPRESSION) || (Section->Type = =3D=3D EFI_SECTION_GUID_DEFINED)) { + DEBUG ((DEBUG_INFO, "It is a compressed section.\n")); + + if (Section->Type =3D=3D EFI_SECTION_COMPRESSION) { + if (IS_SECTION2 (Section)) { + CompressionSection2 =3D (EFI_COMPRESSION_SECTION2 *)Section; + SectionLength =3D SECTION2_SIZE (Section); + + if (CompressionSection2->CompressionType !=3D EFI_STANDARD_COMPR= ESSION) { + return EFI_UNSUPPORTED; + } + + CompressedData =3D (CHAR8 *)((EFI_COMPRESSION_SECTION2 *)S= ection + 1); + CompressedDataLength =3D (UINT32)SectionLength - sizeof (EFI_COM= PRESSION_SECTION2); + } else { + CompressionSection =3D (EFI_COMPRESSION_SECTION *)Section; + SectionLength =3D SECTION_SIZE (Section); + + if (CompressionSection->CompressionType !=3D EFI_STANDARD_COMPRE= SSION) { + return EFI_UNSUPPORTED; + } + + CompressedData =3D (CHAR8 *)((EFI_COMPRESSION_SECTION *)Se= ction + 1); + CompressedDataLength =3D (UINT32)SectionLength - sizeof (EFI_COM= PRESSION_SECTION); + } + + Status =3D UefiDecompressGetInfo ( + CompressedData, + (UINT32)CompressedDataLength, + &DstBufferSize, + &ScratchBufferSize + ); + } else if (Section->Type =3D=3D EFI_SECTION_GUID_DEFINED) { + Status =3D ExtractGuidedSectionGetInfo ( + Section, + &DstBufferSize, + &ScratchBufferSize, + &SectionAttribute + ); + } + + if (EFI_ERROR (Status)) { + // + // GetInfo failed + // + DEBUG ((DEBUG_ERROR, "Decompress GetInfo Failed - %r\n", Status)); + return EFI_NOT_FOUND; + } + + // + // Allocate scratch buffer + // + ScratchBuffer =3D (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (S= cratchBufferSize)); + if (ScratchBuffer =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Allocate destination buffer, extra one page for adjustment + // + DstBuffer =3D (VOID *)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (DstBu= fferSize) + 1); + if (DstBuffer =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // DstBuffer still is one section. Adjust DstBuffer offset, skip EFI= section header + // to make section data at page alignment. + // + if (IS_SECTION2 (Section)) { + DstBuffer =3D (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COM= MON_SECTION_HEADER2); + } else { + DstBuffer =3D (UINT8 *)DstBuffer + EFI_PAGE_SIZE - sizeof (EFI_COM= MON_SECTION_HEADER); + } + + // + // Call decompress function + // + if (Section->Type =3D=3D EFI_SECTION_COMPRESSION) { + if (IS_SECTION2 (Section)) { + CompressedData =3D (CHAR8 *)((EFI_COMPRESSION_SECTION2 *)Section= + 1); + } else { + CompressedData =3D (CHAR8 *)((EFI_COMPRESSION_SECTION *)Section = + 1); + } + + Status =3D UefiDecompress ( + CompressedData, + DstBuffer, + ScratchBuffer + ); + } else if (Section->Type =3D=3D EFI_SECTION_GUID_DEFINED) { + Status =3D ExtractGuidedSectionDecode ( + Section, + &DstBuffer, + ScratchBuffer, + &AuthenticationStatus + ); + } + + if (EFI_ERROR (Status)) { + // + // Decompress failed + // + DEBUG ((DEBUG_ERROR, "Decompress Failed - %r\n", Status)); + return EFI_NOT_FOUND; + } else { + *OutputBuffer =3D DstBuffer; + *OutputBufferSize =3D DstBufferSize; + DEBUG (( + DEBUG_INFO, + "Decompressed data is at %x, %x\n", + DstBuffer, + DstBufferSize + )); + return EFI_SUCCESS; + } + } + + if (IS_SECTION2 (Section)) { + SectionLength =3D SECTION2_SIZE (Section); + } else { + SectionLength =3D SECTION_SIZE (Section); + } + + // + // SectionLength is adjusted it is 4 byte aligned. + // Go to the next section + // + SectionLength =3D GET_OCCUPIED_SIZE (SectionLength, 4); + ASSERT (SectionLength !=3D 0); + ParsedLength +=3D SectionLength; + Section =3D (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + Sec= tionLength); + DEBUG ((DEBUG_INFO, "Go to next section.\n")); + } + + return EFI_NOT_FOUND; +} + +#define MAX_FV_IMAGES 8 +/** + Get Fv image from the FV type file, then add FV & FV2 Hob. + This function can handle the situation that a compressed + section contains multi-FvImages and create FV/FV2 Hob for + all the FvImages. + + We assume there are at most MAX_FV_IMAGES (8) FvImages in + a compressed section. If it is not the case, it can be + expanded to a larger one. + + @param FileHandle File handle of a Fv type file. + + + @retval EFI_NOT_FOUND FV image can't be found. + @retval EFI_SUCCESS Successfully to process it. + +**/ +EFI_STATUS +EFIAPI +FfsProcessFvFileEx ( + IN EFI_PEI_FILE_HANDLE FvFileHandle + ) +{ + EFI_STATUS Status; + EFI_FV_INFO FvImageInfo; + UINT32 FvAlignment; + VOID *FvBuffer; + EFI_PEI_HOB_POINTERS HobFv2; + UINT32 ParsedLength; + VOID *DecompressBuffer; + UINT32 DecompressBufferSize; + UINT32 FvImagesCnt; + UINT32 SectionLength; + UINTN FvImageHandles[MAX_FV_IMAGES]; + UINT32 Index; + IN EFI_COMMON_SECTION_HEADER *Section; + + FvBuffer =3D NULL; + DecompressBuffer =3D NULL; + DecompressBufferSize =3D 0; + + // + // Check if this EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE file has already + // been extracted. + // + HobFv2.Raw =3D GetHobList (); + while ((HobFv2.Raw =3D GetNextHob (EFI_HOB_TYPE_FV2, HobFv2.Raw)) !=3D N= ULL) { + if (CompareGuid (&(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name), &HobF= v2.FirmwareVolume2->FileName)) { + // + // this FILE has been dispatched, it will not be dispatched again. + // + return EFI_SUCCESS; + } + + HobFv2.Raw =3D GET_NEXT_HOB (HobFv2); + } + + // + // Decompress section + // + Status =3D FfsDecompressSection (FvFileHandle, (VOID **)&DecompressBuffe= r, &DecompressBufferSize); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Failed to decompress section. %r\n", Status)); + ASSERT (FALSE); + return Status; + } + + // + // Find all the FvImages in the decompressed buffer + // + ParsedLength =3D 0; + FvImagesCnt =3D 0; + Section =3D (EFI_COMMON_SECTION_HEADER *)(DecompressBuffer); + + while (ParsedLength < DecompressBufferSize && FvImagesCnt < MAX_FV_IMAGE= S) { + if (IS_SECTION2 (Section)) { + ASSERT (SECTION2_SIZE (Section) > 0x00FFFFFF); + } + + if (Section->Type =3D=3D EFI_SECTION_FIRMWARE_VOLUME_IMAGE) { + if (IS_SECTION2 (Section)) { + FvImageHandles[FvImagesCnt++] =3D (UINTN)(VOID *)((UINT8 *)Section= + sizeof (EFI_COMMON_SECTION_HEADER2)); + } else { + FvImageHandles[FvImagesCnt++] =3D (UINTN)(VOID *)((UINT8 *)Section= + sizeof (EFI_COMMON_SECTION_HEADER)); + } + } + + if (IS_SECTION2 (Section)) { + SectionLength =3D SECTION2_SIZE (Section); + } else { + SectionLength =3D SECTION_SIZE (Section); + } + + // + // SectionLength is adjusted it is 4 byte aligned. + // Go to the next section + // + SectionLength =3D GET_OCCUPIED_SIZE (SectionLength, 4); + ASSERT (SectionLength !=3D 0); + ParsedLength +=3D SectionLength; + Section =3D (EFI_COMMON_SECTION_HEADER *)((UINT8 *)Section + Sec= tionLength); + } + + if (FvImagesCnt =3D=3D 0) { + ASSERT (FALSE); + DEBUG ((DEBUG_ERROR, "Cannot find FvImages.\n")); + return EFI_NOT_FOUND; + } + + DEBUG ((DEBUG_INFO, "Collect FvImageInfo\n")); + for (Index =3D 0; Index < FvImagesCnt; Index++) { + // + // Collect FvImage Info. + // + ZeroMem (&FvImageInfo, sizeof (FvImageInfo)); + Status =3D FfsGetVolumeInfo ((VOID *)FvImageHandles[Index], &FvImageIn= fo); + ASSERT_EFI_ERROR (Status); + DEBUG ((DEBUG_INFO, " Fv Name=3D%g, Format=3D%g, Size=3D0x%x\n", FvIm= ageInfo.FvName, FvImageInfo.FvFormat, FvImageInfo.FvSize)); + + // + // FvAlignment must be more than 8 bytes required by FvHeader structur= e. + // + FvAlignment =3D 1 << ((FvImageInfo.FvAttributes & EFI_FVB2_ALIGNMENT) = >> 16); + if (FvAlignment < 8) { + FvAlignment =3D 8; + } + + // + // Check FvImage + // + if ((UINTN)FvImageInfo.FvStart % FvAlignment !=3D 0) { + FvBuffer =3D AllocateAlignedPages (EFI_SIZE_TO_PAGES ((UINT32)FvImag= eInfo.FvSize), FvAlignment); + if (FvBuffer =3D=3D NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (FvBuffer, FvImageInfo.FvStart, (UINTN)FvImageInfo.FvSize); + // + // Update FvImageInfo after reload FvImage to new aligned memory + // + FfsGetVolumeInfo ((EFI_PEI_FV_HANDLE)FvBuffer, &FvImageInfo); + } + + // + // Inform HOB consumer phase, i.e. DXE core, the existence of this FV + // + BuildFvHob ((EFI_PHYSICAL_ADDRESS)(UINTN)FvImageInfo.FvStart, FvImageI= nfo.FvSize); + + // + // Makes the encapsulated volume show up in DXE phase to skip processi= ng of + // encapsulated file again. + // + BuildFv2Hob ( + (EFI_PHYSICAL_ADDRESS)(UINTN)FvImageInfo.FvStart, + FvImageInfo.FvSize, + &FvImageInfo.FvName, + &(((EFI_FFS_FILE_HEADER *)FvFileHandle)->Name) + ); + } =20 return EFI_SUCCESS; } --=20 2.29.2.windows.2 -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D- Groups.io Links: You receive all messages sent to this group. View/Reply Online (#84807): https://edk2.groups.io/g/devel/message/84807 Mute This Topic: https://groups.io/mt/87720796/1787277 Group Owner: devel+owner@edk2.groups.io Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org] -=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-=3D-