diff --git a/MdeModulePkg/Include/Guid/ParallelLzmaDecompress.h b/MdeModulePkg/Include/Guid/ParallelLzmaDecompress.h new file mode 100644 index 0000000000..1178876f3d --- /dev/null +++ b/MdeModulePkg/Include/Guid/ParallelLzmaDecompress.h @@ -0,0 +1,36 @@ +/** @file + Parallel Lzma Custom decompress algorithm Guid definition. + + This marker GUID is used for custom sections that are compressed with LZMA, + but are intended to be unpacked in parallel with other execution and so should + not be handled by the main LZMA GUIDed section extractor. + + Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef LZMA_PARALLEL_DECOMPRESS_GUID_H_ +#define LZMA_PARALLEL_DECOMPRESS_GUID_H_ + +/// +/// The Global ID used to identify a section of an FFS file of type +/// EFI_SECTION_GUID_DEFINED, whose contents have been compressed using LZMA. +/// +#define PARALLEL_LZMA_CUSTOM_DECOMPRESS_GUID \ + { 0xbd9921ea, 0xed91, 0x404a, { 0x8b, 0x2f, 0xb4, 0xd7, 0x24, 0x74, 0x7c, 0x8c } } + +extern GUID gParallelLzmaCustomDecompressGuid; + +#define PARALLEL_LZMA_CUSTOM_DECOMPRESS_HOB_GUID \ + { 0x21650a93, 0xed65, 0x4240, { 0x84, 0x37, 0x55, 0xba, 0xe2, 0x62, 0x98, 0x5b } } + +extern GUID gParallelLzmaCustomDecompressHobGuid; + +typedef struct { + VOID *SourceBuffer; + VOID *DecompressedBuffer; + UINTN DecompressedSize; +} PARALLEL_DECOMPRESSED_BUFFER; + +#endif diff --git a/MdeModulePkg/Library/ParallelLzmaCustomDecompressLib/ParallelLzmaCustomDecompressLib.c b/MdeModulePkg/Library/ParallelLzmaCustomDecompressLib/ParallelLzmaCustomDecompressLib.c new file mode 100644 index 0000000000..3462552ae8 --- /dev/null +++ b/MdeModulePkg/Library/ParallelLzmaCustomDecompressLib/ParallelLzmaCustomDecompressLib.c @@ -0,0 +1,250 @@ +/** @file + Parallel LZMA Decompress GUIDed Section Extraction Library. + + Copyright (c) Microsoft Corporation + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include +#include +#include +#include +#include + +#include + +// +// Forward declaration for routines used from LzmaDecompress library. +// +RETURN_STATUS +EFIAPI +LzmaUefiDecompressGetInfo ( + IN CONST VOID *Source, + IN UINT32 SourceSize, + OUT UINT32 *DestinationSize, + OUT UINT32 *ScratchSize + ); + +RETURN_STATUS +EFIAPI +LzmaUefiDecompress ( + IN CONST VOID *Source, + IN UINTN SourceSize, + IN OUT VOID *Destination, + IN OUT VOID *Scratch + ); + +/** + Examines a GUIDed section and returns the size of the decoded buffer and the + size of an optional scratch buffer required to actually decode the data in a GUIDed section. + + Examines a GUIDed section specified by InputSection. + If GUID for InputSection does not match the GUID that this handler supports, + then RETURN_UNSUPPORTED is returned. + If the required information can not be retrieved from InputSection, + then RETURN_INVALID_PARAMETER is returned. + If the GUID of InputSection does match the GUID that this handler supports, + then the size required to hold the decoded buffer is returned in OututBufferSize, + the size of an optional scratch buffer is returned in ScratchSize, and the Attributes field + from EFI_GUID_DEFINED_SECTION header of InputSection is returned in SectionAttribute. + + If InputSection is NULL, then ASSERT(). + If OutputBufferSize is NULL, then ASSERT(). + If ScratchBufferSize is NULL, then ASSERT(). + If SectionAttribute is NULL, then ASSERT(). + + + @param[in] InputSection A pointer to a GUIDed section of an FFS formatted file. + @param[out] OutputBufferSize A pointer to the size, in bytes, of an output buffer required + if the buffer specified by InputSection were decoded. + @param[out] ScratchBufferSize A pointer to the size, in bytes, required as scratch space + if the buffer specified by InputSection were decoded. + @param[out] SectionAttribute A pointer to the attributes of the GUIDed section. See the Attributes + field of EFI_GUID_DEFINED_SECTION in the PI Specification. + + @retval RETURN_SUCCESS The information about InputSection was returned. + @retval RETURN_UNSUPPORTED The section specified by InputSection does not match the GUID this handler supports. + @retval RETURN_INVALID_PARAMETER The information can not be retrieved from the section specified by InputSection. + +**/ +RETURN_STATUS +EFIAPI +ParallelLzmaGuidedSectionGetInfo ( + IN CONST VOID *InputSection, + OUT UINT32 *OutputBufferSize, + OUT UINT32 *ScratchBufferSize, + OUT UINT16 *SectionAttribute + ) +{ + ASSERT (InputSection != NULL); + ASSERT (OutputBufferSize != NULL); + ASSERT (ScratchBufferSize != NULL); + ASSERT (SectionAttribute != NULL); + + if (IS_SECTION2 (InputSection)) { + if (!CompareGuid ( + &gParallelLzmaCustomDecompressGuid, + &(((EFI_GUID_DEFINED_SECTION2 *)InputSection)->SectionDefinitionGuid) + )) + { + return RETURN_INVALID_PARAMETER; + } + + *SectionAttribute = ((EFI_GUID_DEFINED_SECTION2 *)InputSection)->Attributes; + return LzmaUefiDecompressGetInfo ( + (UINT8 *)InputSection + ((EFI_GUID_DEFINED_SECTION2 *)InputSection)->DataOffset, + SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *)InputSection)->DataOffset, + OutputBufferSize, + ScratchBufferSize + ); + } else { + if (!CompareGuid ( + &gParallelLzmaCustomDecompressGuid, + &(((EFI_GUID_DEFINED_SECTION *)InputSection)->SectionDefinitionGuid) + )) + { + return RETURN_INVALID_PARAMETER; + } + + *SectionAttribute = ((EFI_GUID_DEFINED_SECTION *)InputSection)->Attributes; + return LzmaUefiDecompressGetInfo ( + (UINT8 *)InputSection + ((EFI_GUID_DEFINED_SECTION *)InputSection)->DataOffset, + SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *)InputSection)->DataOffset, + OutputBufferSize, + ScratchBufferSize + ); + } +} + +/** + Decodes a GUIDed section into a caller allocated output buffer. + + Decodes the GUIDed section specified by InputSection. + If GUID for InputSection does not match the GUID that this handler supports, then RETURN_UNSUPPORTED is returned. + If the data in InputSection can not be decoded, then RETURN_INVALID_PARAMETER is returned. + If the GUID of InputSection does match the GUID that this handler supports, then InputSection + is decoded into the buffer specified by OutputBuffer and the authentication status of this + decode operation is returned in AuthenticationStatus. If the decoded buffer is identical to the + data in InputSection, then OutputBuffer is set to point at the data in InputSection. Otherwise, + the decoded data will be placed in caller allocated buffer specified by OutputBuffer. + + If InputSection is NULL, then ASSERT(). + If OutputBuffer is NULL, then ASSERT(). + If ScratchBuffer is NULL and this decode operation requires a scratch buffer, then ASSERT(). + If AuthenticationStatus is NULL, then ASSERT(). + + + @param[in] InputSection A pointer to a GUIDed section of an FFS formatted file. + @param[out] OutputBuffer A pointer to a buffer that contains the result of a decode operation. + @param[out] ScratchBuffer A caller allocated buffer that may be required by this function + as a scratch buffer to perform the decode operation. + @param[out] AuthenticationStatus + A pointer to the authentication status of the decoded output buffer. + See the definition of authentication status in the EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI + section of the PI Specification. EFI_AUTH_STATUS_PLATFORM_OVERRIDE must + never be set by this handler. + + @retval RETURN_SUCCESS The buffer specified by InputSection was decoded. + @retval RETURN_UNSUPPORTED The section specified by InputSection does not match the GUID this handler supports. + @retval RETURN_INVALID_PARAMETER The section specified by InputSection can not be decoded. + +**/ +RETURN_STATUS +EFIAPI +ParallelLzmaGuidedSectionExtraction ( + IN CONST VOID *InputSection, + OUT VOID **OutputBuffer, + OUT VOID *ScratchBuffer, OPTIONAL + OUT UINT32 *AuthenticationStatus + ) +{ + PARALLEL_DECOMPRESSED_BUFFER *DecompBufferInfo; + EFI_HOB_GUID_TYPE *GuidHob; + VOID *DataOffset; + UINTN DataSize; + + ASSERT (OutputBuffer != NULL); + ASSERT (InputSection != NULL); + ASSERT (ScratchBuffer != NULL); + ASSERT (AuthenticationStatus != NULL); + + // + // Authentication is set to Zero, which may be ignored. + // + *AuthenticationStatus = 0; + + // + // Validate the input section and calculate input data offset and size. + // + if (IS_SECTION2 (InputSection)) { + if (!CompareGuid ( + &gParallelLzmaCustomDecompressGuid, + &(((EFI_GUID_DEFINED_SECTION2 *)InputSection)->SectionDefinitionGuid) + )) + { + return RETURN_UNSUPPORTED; + } + + DataOffset = (UINT8 *)InputSection + ((EFI_GUID_DEFINED_SECTION2 *)InputSection)->DataOffset; + DataSize = SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *)InputSection)->DataOffset; + } else { + if (!CompareGuid ( + &gParallelLzmaCustomDecompressGuid, + &(((EFI_GUID_DEFINED_SECTION *)InputSection)->SectionDefinitionGuid) + )) + { + return RETURN_UNSUPPORTED; + } + + DataOffset = (UINT8 *)InputSection + ((EFI_GUID_DEFINED_SECTION *)InputSection)->DataOffset; + DataSize = SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *)InputSection)->DataOffset; + } + + // + // Iterate over any previously decompressed buffers. Copy and return if found. + // + for (GuidHob = GetFirstGuidHob (&gParallelLzmaCustomDecompressHobGuid); + GuidHob != NULL; + GuidHob = GetNextGuidHob (&gParallelLzmaCustomDecompressHobGuid, GET_NEXT_HOB (GuidHob))) + { + DecompBufferInfo = (PARALLEL_DECOMPRESSED_BUFFER *)GET_GUID_HOB_DATA (GuidHob); + + if (DecompBufferInfo->SourceBuffer == DataOffset) { + DEBUG (( + DEBUG_INFO, + "[%a] Matched source buffer %p. Copying decompressed buffer %p to ouput %p\n", + __FUNCTION__, + DecompBufferInfo->SourceBuffer, + DecompBufferInfo->DecompressedBuffer, + *OutputBuffer + )); + CopyMem (*OutputBuffer, DecompBufferInfo->DecompressedBuffer, DecompBufferInfo->DecompressedSize); + return RETURN_SUCCESS; + } + } + + // + // if we get here, no previously decompressed buffer was found, so passthru to LZMA decompress. + // + return LzmaUefiDecompress (DataOffset, DataSize, *OutputBuffer, ScratchBuffer); +} + +/** + Register ParallelLzmaDecompress and ParallelLzmaDecompressGetInfo handlers with ParallelLzmaCustomeDecompressGuid. + + @retval RETURN_SUCCESS Register successfully. + @retval RETURN_OUT_OF_RESOURCES No enough memory to store this handler. +**/ +RETURN_STATUS +EFIAPI +ParallelLzmaDecompressLibConstructor ( + VOID + ) +{ + return ExtractGuidedSectionRegisterHandlers ( + &gParallelLzmaCustomDecompressGuid, + ParallelLzmaGuidedSectionGetInfo, + ParallelLzmaGuidedSectionExtraction + ); +} diff --git a/MdeModulePkg/Library/ParallelLzmaCustomDecompressLib/ParallelLzmaCustomDecompressLib.inf b/MdeModulePkg/Library/ParallelLzmaCustomDecompressLib/ParallelLzmaCustomDecompressLib.inf new file mode 100644 index 0000000000..844a8a9dd8 --- /dev/null +++ b/MdeModulePkg/Library/ParallelLzmaCustomDecompressLib/ParallelLzmaCustomDecompressLib.inf @@ -0,0 +1,42 @@ +## @file +# ParallelLzmaCustomDecompressLib produces the Parallel LZMA custom decompression algorithm. +# +# This relies on the standard LzmaCustomDecompress lib to do the work and expects to be +# linked against it with a NULL| library instance. +# +# Copyright (c) Microsoft Corporation +# SPDX-License-Identifier: BSD-2-Clause-Patent +## + +[Defines] + INF_VERSION = 1.27 + BASE_NAME = ParallelLzmaDecompressLib + FILE_GUID = 16979EFB-EC84-4390-BC4E-923B69B02CDA + MODULE_TYPE = BASE + VERSION_STRING = 1.0 + LIBRARY_CLASS = NULL + CONSTRUCTOR = ParallelLzmaDecompressLibConstructor + +# +# The following information is for reference only and not required by the build tools. +# +# VALID_ARCHITECTURES = IA32 X64 AARCH64 ARM +# + +[Sources] + ParallelLzmaCustomDecompressLib.c + +[Packages] + MdePkg/MdePkg.dec + MdeModulePkg/MdeModulePkg.dec + +[Guids] + gParallelLzmaCustomDecompressGuid ## PRODUCES # specifies LZMA custom decompress algorithm. + gParallelLzmaCustomDecompressHobGuid ## CONSUMES + +[LibraryClasses] + BaseLib + BaseMemoryLib + DebugLib + ExtractGuidedSectionLib + HobLib diff --git a/MdeModulePkg/MdeModulePkg.dec b/MdeModulePkg/MdeModulePkg.dec index 5511947277..7b74deb53d 100644 --- a/MdeModulePkg/MdeModulePkg.dec +++ b/MdeModulePkg/MdeModulePkg.dec @@ -370,6 +370,14 @@ gLzmaCustomDecompressGuid = { 0xEE4E5898, 0x3914, 0x4259, { 0x9D, 0x6E, 0xDC, 0x7B, 0xD7, 0x94, 0x03, 0xCF }} gLzmaF86CustomDecompressGuid = { 0xD42AE6BD, 0x1352, 0x4bfb, { 0x90, 0x9A, 0xCA, 0x72, 0xA6, 0xEA, 0xE8, 0x89 }} + ## GUID to identify a customized "Parallel Decompress" LZMA section + # Include/Guid/ParallelLzmaDecompress.h + gParallelLzmaCustomDecompressGuid = { 0xbd9921ea, 0xed91, 0x404a, { 0x8b, 0x2f, 0xb4, 0xd7, 0x24, 0x74, 0x7c, 0x8c }} + + ## GUID to identify a customized "Parallel Decompress" LZMA DecompressionInfo Hob + # Include/Guid/ParallelLzmaDecompress.h + gParallelLzmaCustomDecompressHobGuid = {0x21650a93, 0xed65, 0x4240, {0x84, 0x37, 0x55, 0xba, 0xe2, 0x62, 0x98, 0x5b}} + ## Include/Guid/TtyTerm.h gEfiTtyTermGuid = { 0x7d916d80, 0x5bb1, 0x458c, {0xa4, 0x8f, 0xe2, 0x5f, 0xdd, 0x51, 0xef, 0x94 }} gEdkiiLinuxTermGuid = { 0xe4364a7f, 0xf825, 0x430e, {0x9d, 0x3a, 0x9c, 0x9b, 0xe6, 0x81, 0x7c, 0xa5 }} diff --git a/MdeModulePkg/MdeModulePkg.dsc b/MdeModulePkg/MdeModulePkg.dsc index 5e539988d0..7727ddb169 100644 --- a/MdeModulePkg/MdeModulePkg.dsc +++ b/MdeModulePkg/MdeModulePkg.dsc @@ -226,7 +226,7 @@ MdeModulePkg/Application/HelloWorld/HelloWorld.inf MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.inf MdeModulePkg/Application/MemoryProfileInfo/MemoryProfileInfo.inf - + MdeModulePkg/Library/ParallelLzmaCustomDecompressLib/ParallelLzmaCustomDecompressLib.inf ## MU_CHANGE MdeModulePkg/Library/UefiSortLib/UefiSortLib.inf MdeModulePkg/Logo/Logo.inf MdeModulePkg/Logo/LogoDxe.inf