diff options
Diffstat (limited to 'BaseTools/Source/C/Common')
38 files changed, 17965 insertions, 17965 deletions
diff --git a/BaseTools/Source/C/Common/BasePeCoff.c b/BaseTools/Source/C/Common/BasePeCoff.c index 038bb054e5..3de817813b 100644 --- a/BaseTools/Source/C/Common/BasePeCoff.c +++ b/BaseTools/Source/C/Common/BasePeCoff.c @@ -1,1417 +1,1417 @@ -/** @file
-
- Functions to get info and load PE/COFF image.
-
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
-Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
-Portions Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
-Portions Copyright (c) 2022, Loongson Technology Corporation Limited. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <Common/UefiBaseTypes.h>
-#include <CommonLib.h>
-#include <IndustryStandard/PeImage.h>
-#include "PeCoffLib.h"
-
-typedef union {
- VOID *Header;
- EFI_IMAGE_OPTIONAL_HEADER32 *Optional32;
- EFI_IMAGE_OPTIONAL_HEADER64 *Optional64;
-} EFI_IMAGE_OPTIONAL_HEADER_POINTER;
-
-STATIC
-RETURN_STATUS
-PeCoffLoaderGetPeHeader (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
- OUT EFI_IMAGE_OPTIONAL_HEADER_UNION **PeHdr,
- OUT EFI_TE_IMAGE_HEADER **TeHdr
- );
-
-STATIC
-RETURN_STATUS
-PeCoffLoaderCheckImageType (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
- IN EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr,
- IN EFI_TE_IMAGE_HEADER *TeHdr
- );
-
-STATIC
-VOID *
-PeCoffLoaderImageAddress (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
- IN UINTN Address
- );
-
-RETURN_STATUS
-PeCoffLoaderRelocateIa32Image (
- IN UINT16 *Reloc,
- IN OUT CHAR8 *Fixup,
- IN OUT CHAR8 **FixupData,
- IN UINT64 Adjust
- );
-
-
-RETURN_STATUS
-PeCoffLoaderRelocateArmImage (
- IN UINT16 **Reloc,
- IN OUT CHAR8 *Fixup,
- IN OUT CHAR8 **FixupData,
- IN UINT64 Adjust
- );
-
-RETURN_STATUS
-PeCoffLoaderRelocateRiscVImage (
- IN UINT16 *Reloc,
- IN OUT CHAR8 *Fixup,
- IN OUT CHAR8 **FixupData,
- IN UINT64 Adjust
- );
-
-RETURN_STATUS
-PeCoffLoaderRelocateLoongArch64Image (
- IN UINT16 *Reloc,
- IN OUT CHAR8 *Fixup,
- IN OUT CHAR8 **FixupData,
- IN UINT64 Adjust
- );
-
-/**
- Retrieves the PE or TE Header from a PE/COFF or TE image
-
- @param ImageContext The context of the image being loaded
- @param PeHdr The buffer in which to return the PE header
- @param TeHdr The buffer in which to return the TE header
-
- @return RETURN_SUCCESS if the PE or TE Header is read,
- Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function.
-**/
-STATIC
-RETURN_STATUS
-PeCoffLoaderGetPeHeader (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
- OUT EFI_IMAGE_OPTIONAL_HEADER_UNION **PeHdr,
- OUT EFI_TE_IMAGE_HEADER **TeHdr
- )
-{
- RETURN_STATUS Status;
- EFI_IMAGE_DOS_HEADER DosHdr;
- UINTN Size;
-
- ImageContext->IsTeImage = FALSE;
- //
- // Read the DOS image headers
- //
- Size = sizeof (EFI_IMAGE_DOS_HEADER);
- Status = ImageContext->ImageRead (
- ImageContext->Handle,
- 0,
- &Size,
- &DosHdr
- );
- if (RETURN_ERROR (Status)) {
- ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
- return Status;
- }
-
- ImageContext->PeCoffHeaderOffset = 0;
- if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) {
- //
- // DOS image header is present, so read the PE header after the DOS image header
- //
- ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew;
- }
- //
- // Get the PE/COFF Header pointer
- //
- *PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN)ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
- if ((*PeHdr)->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
- //
- // Check the PE/COFF Header Signature. If not, then try to get a TE header
- //
- *TeHdr = (EFI_TE_IMAGE_HEADER *)*PeHdr;
- if ((*TeHdr)->Signature != EFI_TE_IMAGE_HEADER_SIGNATURE) {
- return RETURN_UNSUPPORTED;
- }
- ImageContext->IsTeImage = TRUE;
- }
-
- return RETURN_SUCCESS;
-}
-
-/**
- Checks the PE or TE header of a PE/COFF or TE image to determine if it supported
-
- @param ImageContext The context of the image being loaded
- @param PeHdr The buffer in which to return the PE header
- @param TeHdr The buffer in which to return the TE header
-
- @retval RETURN_SUCCESS if the PE/COFF or TE image is supported
- @retval RETURN_UNSUPPORTED of the PE/COFF or TE image is not supported.
-
-**/
-STATIC
-RETURN_STATUS
-PeCoffLoaderCheckImageType (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
- IN EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr,
- IN EFI_TE_IMAGE_HEADER *TeHdr
- )
-{
- //
- // See if the machine type is supported.
- // We support a native machine type (IA-32/Itanium-based)
- //
- if (ImageContext->IsTeImage == FALSE) {
- ImageContext->Machine = PeHdr->Pe32.FileHeader.Machine;
- } else {
- ImageContext->Machine = TeHdr->Machine;
- }
-
- if (ImageContext->Machine != IMAGE_FILE_MACHINE_I386 && \
- ImageContext->Machine != IMAGE_FILE_MACHINE_X64 && \
- ImageContext->Machine != IMAGE_FILE_MACHINE_ARMTHUMB_MIXED && \
- ImageContext->Machine != IMAGE_FILE_MACHINE_EBC && \
- ImageContext->Machine != IMAGE_FILE_MACHINE_ARM64 && \
- ImageContext->Machine != IMAGE_FILE_MACHINE_RISCV64 && \
- ImageContext->Machine != IMAGE_FILE_MACHINE_LOONGARCH64) {
- //
- // unsupported PeImage machine type
- //
- return RETURN_UNSUPPORTED;
- }
-
- //
- // See if the image type is supported. We support EFI Applications,
- // EFI Boot Service Drivers, EFI Runtime Drivers and EFI SAL Drivers.
- //
- if (ImageContext->IsTeImage == FALSE) {
- ImageContext->ImageType = PeHdr->Pe32.OptionalHeader.Subsystem;
- } else {
- ImageContext->ImageType = (UINT16) (TeHdr->Subsystem);
- }
-
- if (ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION && \
- ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER && \
- ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER && \
- ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER) {
- //
- // unsupported PeImage subsystem type
- //
- return RETURN_UNSUPPORTED;
- }
-
- return RETURN_SUCCESS;
-}
-
-/**
- Retrieves information on a PE/COFF image
-
- @param This Calling context
- @param ImageContext The context of the image being loaded
-
- @retval RETURN_SUCCESS The information on the PE/COFF image was collected.
- @retval RETURN_INVALID_PARAMETER ImageContext is NULL.
- @retval RETURN_UNSUPPORTED The PE/COFF image is not supported.
- @retval Otherwise The error status from reading the PE/COFF image using the
- ImageContext->ImageRead() function
-
-**/
-RETURN_STATUS
-EFIAPI
-PeCoffLoaderGetImageInfo (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
- )
-{
- RETURN_STATUS Status;
- EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr;
- EFI_TE_IMAGE_HEADER *TeHdr;
- EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry;
- UINTN Size;
- UINTN Index;
- UINTN DebugDirectoryEntryRva;
- UINTN DebugDirectoryEntryFileOffset;
- UINTN SectionHeaderOffset;
- EFI_IMAGE_SECTION_HEADER SectionHeader;
- EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry;
- EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader;
-
- PeHdr = NULL;
- TeHdr = NULL;
- DebugDirectoryEntry = NULL;
- DebugDirectoryEntryRva = 0;
-
- if (NULL == ImageContext) {
- return RETURN_INVALID_PARAMETER;
- }
- //
- // Assume success
- //
- ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
-
- Status = PeCoffLoaderGetPeHeader (ImageContext, &PeHdr, &TeHdr);
- if (RETURN_ERROR (Status)) {
- return Status;
- }
-
- //
- // Verify machine type
- //
- Status = PeCoffLoaderCheckImageType (ImageContext, PeHdr, TeHdr);
- if (RETURN_ERROR (Status)) {
- return Status;
- }
- OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);
-
- //
- // Retrieve the base address of the image
- //
- if (!(ImageContext->IsTeImage)) {
- if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
- ImageContext->ImageAddress = (PHYSICAL_ADDRESS) OptionHeader.Optional32->ImageBase;
- } else {
- ImageContext->ImageAddress = (PHYSICAL_ADDRESS) OptionHeader.Optional64->ImageBase;
- }
- } else {
- ImageContext->ImageAddress = (PHYSICAL_ADDRESS) (TeHdr->ImageBase + TeHdr->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));
- }
- //
- // Initialize the alternate destination address to 0 indicating that it
- // should not be used.
- //
- ImageContext->DestinationAddress = 0;
-
- //
- // Initialize the codeview pointer.
- //
- ImageContext->CodeView = NULL;
- ImageContext->PdbPointer = NULL;
-
- //
- // Three cases with regards to relocations:
- // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable
- // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable
- // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but
- // has no base relocs to apply
- // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid.
- //
- // Look at the file header to determine if relocations have been stripped, and
- // save this info in the image context for later use.
- //
- if ((!(ImageContext->IsTeImage)) && ((PeHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) {
- ImageContext->RelocationsStripped = TRUE;
- } else if ((ImageContext->IsTeImage) && (TeHdr->DataDirectory[0].Size == 0) && (TeHdr->DataDirectory[0].VirtualAddress == 0)) {
- ImageContext->RelocationsStripped = TRUE;
- } else {
- ImageContext->RelocationsStripped = FALSE;
- }
-
- if (!(ImageContext->IsTeImage)) {
-
- if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
- ImageContext->ImageSize = (UINT64) OptionHeader.Optional32->SizeOfImage;
- ImageContext->SectionAlignment = OptionHeader.Optional32->SectionAlignment;
- ImageContext->SizeOfHeaders = OptionHeader.Optional32->SizeOfHeaders;
-
- //
- // Modify ImageSize to contain .PDB file name if required and initialize
- // PdbRVA field...
- //
- if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
- DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
- DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
- }
- } else {
- ImageContext->ImageSize = (UINT64) OptionHeader.Optional64->SizeOfImage;
- ImageContext->SectionAlignment = OptionHeader.Optional64->SectionAlignment;
- ImageContext->SizeOfHeaders = OptionHeader.Optional64->SizeOfHeaders;
-
- //
- // Modify ImageSize to contain .PDB file name if required and initialize
- // PdbRVA field...
- //
- if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) {
- DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
- DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
- }
- }
-
- if (DebugDirectoryEntryRva != 0) {
- //
- // Determine the file offset of the debug directory... This means we walk
- // the sections to find which section contains the RVA of the debug
- // directory
- //
- DebugDirectoryEntryFileOffset = 0;
-
- SectionHeaderOffset = (UINTN)(
- ImageContext->PeCoffHeaderOffset +
- sizeof (UINT32) +
- sizeof (EFI_IMAGE_FILE_HEADER) +
- PeHdr->Pe32.FileHeader.SizeOfOptionalHeader
- );
-
- for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++) {
- //
- // Read section header from file
- //
- Size = sizeof (EFI_IMAGE_SECTION_HEADER);
- Status = ImageContext->ImageRead (
- ImageContext->Handle,
- SectionHeaderOffset,
- &Size,
- &SectionHeader
- );
- if (RETURN_ERROR (Status)) {
- ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
- return Status;
- }
-
- if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
- DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
- DebugDirectoryEntryFileOffset =
- DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData;
- break;
- }
-
- SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
- }
-
- if (DebugDirectoryEntryFileOffset != 0) {
- for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
- //
- // Read next debug directory entry
- //
- Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
- Status = ImageContext->ImageRead (
- ImageContext->Handle,
- DebugDirectoryEntryFileOffset + Index,
- &Size,
- &DebugEntry
- );
- if (RETURN_ERROR (Status)) {
- ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
- return Status;
- }
-
- if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
- ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);
- if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) {
- ImageContext->ImageSize += DebugEntry.SizeOfData;
- }
-
- return RETURN_SUCCESS;
- }
- }
- }
- }
- } else {
- ImageContext->ImageSize = 0;
- ImageContext->SectionAlignment = 4096;
- ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN) TeHdr->BaseOfCode - (UINTN) TeHdr->StrippedSize;
-
- DebugDirectoryEntry = &TeHdr->DataDirectory[1];
- DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress;
- SectionHeaderOffset = (UINTN) (sizeof (EFI_TE_IMAGE_HEADER));
-
- DebugDirectoryEntryFileOffset = 0;
-
- for (Index = 0; Index < TeHdr->NumberOfSections;) {
- //
- // Read section header from file
- //
- Size = sizeof (EFI_IMAGE_SECTION_HEADER);
- Status = ImageContext->ImageRead (
- ImageContext->Handle,
- SectionHeaderOffset,
- &Size,
- &SectionHeader
- );
- if (RETURN_ERROR (Status)) {
- ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
- return Status;
- }
-
- if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress &&
- DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) {
- DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva -
- SectionHeader.VirtualAddress +
- SectionHeader.PointerToRawData +
- sizeof (EFI_TE_IMAGE_HEADER) -
- TeHdr->StrippedSize;
-
- //
- // File offset of the debug directory was found, if this is not the last
- // section, then skip to the last section for calculating the image size.
- //
- if (Index < (UINTN) TeHdr->NumberOfSections - 1) {
- SectionHeaderOffset += (TeHdr->NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER);
- Index = TeHdr->NumberOfSections - 1;
- continue;
- }
- }
-
- //
- // In Te image header there is not a field to describe the ImageSize.
- // Actually, the ImageSize equals the RVA plus the VirtualSize of
- // the last section mapped into memory (Must be rounded up to
- // a multiple of Section Alignment). Per the PE/COFF specification, the
- // section headers in the Section Table must appear in order of the RVA
- // values for the corresponding sections. So the ImageSize can be determined
- // by the RVA and the VirtualSize of the last section header in the
- // Section Table.
- //
- if ((++Index) == (UINTN) TeHdr->NumberOfSections) {
- ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize +
- ImageContext->SectionAlignment - 1) & ~(ImageContext->SectionAlignment - 1);
- }
-
- SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
- }
-
- if (DebugDirectoryEntryFileOffset != 0) {
- for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) {
- //
- // Read next debug directory entry
- //
- Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY);
- Status = ImageContext->ImageRead (
- ImageContext->Handle,
- DebugDirectoryEntryFileOffset,
- &Size,
- &DebugEntry
- );
- if (RETURN_ERROR (Status)) {
- ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
- return Status;
- }
-
- if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) {
- ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index);
- return RETURN_SUCCESS;
- }
- }
- }
- }
-
- return RETURN_SUCCESS;
-}
-
-/**
- Converts an image address to the loaded address
-
- @param ImageContext The context of the image being loaded
- @param Address The address to be converted to the loaded address
-
- @return NULL if the address can not be converted, otherwise, the converted address
-
---*/
-STATIC
-VOID *
-PeCoffLoaderImageAddress (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext,
- IN UINTN Address
- )
-{
- if (Address >= ImageContext->ImageSize) {
- ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
- return NULL;
- }
-
- return (UINT8 *) ((UINTN) ImageContext->ImageAddress + Address);
-}
-
-/**
- Relocates a PE/COFF image in memory
-
- @param This Calling context
- @param ImageContext Contains information on the loaded image to relocate
-
- @retval RETURN_SUCCESS if the PE/COFF image was relocated
- @retval RETURN_LOAD_ERROR if the image is not a valid PE/COFF image
- @retval RETURN_UNSUPPORTED not support
-
-**/
-RETURN_STATUS
-EFIAPI
-PeCoffLoaderRelocateImage (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
- )
-{
- RETURN_STATUS Status;
- EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr;
- EFI_TE_IMAGE_HEADER *TeHdr;
- EFI_IMAGE_DATA_DIRECTORY *RelocDir;
- UINT64 Adjust;
- EFI_IMAGE_BASE_RELOCATION *RelocBase;
- EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd;
- UINT16 *Reloc;
- UINT16 *RelocEnd;
- CHAR8 *Fixup;
- CHAR8 *FixupBase;
- UINT16 *F16;
- UINT32 *F32;
- UINT64 *F64;
- CHAR8 *FixupData;
- PHYSICAL_ADDRESS BaseAddress;
- UINT16 MachineType;
- EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader;
-
- PeHdr = NULL;
- TeHdr = NULL;
- //
- // Assume success
- //
- ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
-
- //
- // If there are no relocation entries, then we are done
- //
- if (ImageContext->RelocationsStripped) {
- return RETURN_SUCCESS;
- }
-
- //
- // Use DestinationAddress field of ImageContext as the relocation address even if it is 0.
- //
- BaseAddress = ImageContext->DestinationAddress;
-
- if (!(ImageContext->IsTeImage)) {
- PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN)ImageContext->ImageAddress +
- ImageContext->PeCoffHeaderOffset);
- OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);
- if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
- Adjust = (UINT64) BaseAddress - OptionHeader.Optional32->ImageBase;
- OptionHeader.Optional32->ImageBase = (UINT32) BaseAddress;
- MachineType = ImageContext->Machine;
- //
- // Find the relocation block
- //
- // Per the PE/COFF spec, you can't assume that a given data directory
- // is present in the image. You have to check the NumberOfRvaAndSizes in
- // the optional header to verify a desired directory entry is there.
- //
- if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
- RelocDir = &OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
- if ((RelocDir != NULL) && (RelocDir->Size > 0)) {
- RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);
- RelocBaseEnd = PeCoffLoaderImageAddress (
- ImageContext,
- RelocDir->VirtualAddress + RelocDir->Size - 1
- );
- if (RelocBase == NULL || RelocBaseEnd == NULL || RelocBaseEnd < RelocBase) {
- ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
- return RETURN_LOAD_ERROR;
- }
- } else {
- //
- // Set base and end to bypass processing below.
- //
- RelocBase = RelocBaseEnd = 0;
- }
- } else {
- //
- // Set base and end to bypass processing below.
- //
- RelocBase = RelocBaseEnd = 0;
- }
- } else {
- Adjust = (UINT64) BaseAddress - OptionHeader.Optional64->ImageBase;
- OptionHeader.Optional64->ImageBase = BaseAddress;
- MachineType = ImageContext->Machine;
- //
- // Find the relocation block
- //
- // Per the PE/COFF spec, you can't assume that a given data directory
- // is present in the image. You have to check the NumberOfRvaAndSizes in
- // the optional header to verify a desired directory entry is there.
- //
- if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
- RelocDir = &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
- if ((RelocDir != NULL) && (RelocDir->Size > 0)) {
- RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress);
- RelocBaseEnd = PeCoffLoaderImageAddress (
- ImageContext,
- RelocDir->VirtualAddress + RelocDir->Size - 1
- );
- if (RelocBase == NULL || RelocBaseEnd == NULL || RelocBaseEnd < RelocBase) {
- ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
- return RETURN_LOAD_ERROR;
- }
- } else {
- //
- // Set base and end to bypass processing below.
- //
- RelocBase = RelocBaseEnd = 0;
- }
- } else {
- //
- // Set base and end to bypass processing below.
- //
- RelocBase = RelocBaseEnd = 0;
- }
- }
- } else {
- TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);
- Adjust = (UINT64) (BaseAddress - TeHdr->ImageBase);
- TeHdr->ImageBase = (UINT64) (BaseAddress);
- MachineType = TeHdr->Machine;
-
- //
- // Find the relocation block
- //
- RelocDir = &TeHdr->DataDirectory[0];
- RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)(
- ImageContext->ImageAddress +
- RelocDir->VirtualAddress +
- sizeof(EFI_TE_IMAGE_HEADER) -
- TeHdr->StrippedSize
- );
- RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1);
- }
-
- //
- // Run the relocation information and apply the fixups
- //
- FixupData = ImageContext->FixupData;
- while (RelocBase < RelocBaseEnd) {
-
- Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION));
- RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock);
- if (!(ImageContext->IsTeImage)) {
- FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress);
- if (FixupBase == NULL) {
- ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
- return RETURN_LOAD_ERROR;
- }
- } else {
- FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress +
- RelocBase->VirtualAddress +
- sizeof(EFI_TE_IMAGE_HEADER) -
- TeHdr->StrippedSize
- );
- }
-
- if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) ||
- (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress +
- (UINTN)ImageContext->ImageSize)) {
- ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
- return RETURN_LOAD_ERROR;
- }
-
- //
- // Run this relocation record
- //
- while (Reloc < RelocEnd) {
-
- Fixup = FixupBase + (*Reloc & 0xFFF);
- switch ((*Reloc) >> 12) {
- case EFI_IMAGE_REL_BASED_ABSOLUTE:
- break;
-
- case EFI_IMAGE_REL_BASED_HIGH:
- F16 = (UINT16 *) Fixup;
- *F16 = (UINT16) (*F16 + ((UINT16) ((UINT32) Adjust >> 16)));
- if (FixupData != NULL) {
- *(UINT16 *) FixupData = *F16;
- FixupData = FixupData + sizeof (UINT16);
- }
- break;
-
- case EFI_IMAGE_REL_BASED_LOW:
- F16 = (UINT16 *) Fixup;
- *F16 = (UINT16) (*F16 + (UINT16) Adjust);
- if (FixupData != NULL) {
- *(UINT16 *) FixupData = *F16;
- FixupData = FixupData + sizeof (UINT16);
- }
- break;
-
- case EFI_IMAGE_REL_BASED_HIGHLOW:
- F32 = (UINT32 *) Fixup;
- *F32 = *F32 + (UINT32) Adjust;
- if (FixupData != NULL) {
- FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32));
- *(UINT32 *) FixupData = *F32;
- FixupData = FixupData + sizeof (UINT32);
- }
- break;
-
- case EFI_IMAGE_REL_BASED_DIR64:
- F64 = (UINT64 *) Fixup;
- *F64 = *F64 + (UINT64) Adjust;
- if (FixupData != NULL) {
- FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64));
- *(UINT64 *) FixupData = *F64;
- FixupData = FixupData + sizeof (UINT64);
- }
- break;
-
- case EFI_IMAGE_REL_BASED_HIGHADJ:
- //
- // Return the same EFI_UNSUPPORTED return code as
- // PeCoffLoaderRelocateImageEx() returns if it does not recognize
- // the relocation type.
- //
- ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
- return RETURN_UNSUPPORTED;
-
- default:
- switch (MachineType) {
- case IMAGE_FILE_MACHINE_I386:
- Status = PeCoffLoaderRelocateIa32Image (Reloc, Fixup, &FixupData, Adjust);
- break;
- case IMAGE_FILE_MACHINE_ARMTHUMB_MIXED:
- Status = PeCoffLoaderRelocateArmImage (&Reloc, Fixup, &FixupData, Adjust);
- break;
- case IMAGE_FILE_MACHINE_RISCV64:
- Status = PeCoffLoaderRelocateRiscVImage (Reloc, Fixup, &FixupData, Adjust);
- break;
- case IMAGE_FILE_MACHINE_LOONGARCH64:
- Status = PeCoffLoaderRelocateLoongArch64Image (Reloc, Fixup, &FixupData, Adjust);
- break;
- default:
- Status = RETURN_UNSUPPORTED;
- break;
- }
- if (RETURN_ERROR (Status)) {
- ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION;
- return Status;
- }
- }
-
- //
- // Next relocation record
- //
- Reloc += 1;
- }
-
- //
- // Next reloc block
- //
- RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd;
- }
-
- return RETURN_SUCCESS;
-}
-
-/**
- Loads a PE/COFF image into memory
-
- @param This Calling context
- @param ImageContext Contains information on image to load into memory
-
- @retval RETURN_SUCCESS if the PE/COFF image was loaded
- @retval RETURN_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer
- @retval RETURN_LOAD_ERROR if the image is a runtime driver with no relocations
- @retval RETURN_INVALID_PARAMETER if the image address is invalid
-
-**/
-RETURN_STATUS
-EFIAPI
-PeCoffLoaderLoadImage (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
- )
-{
- RETURN_STATUS Status;
- EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr;
- EFI_TE_IMAGE_HEADER *TeHdr;
- PE_COFF_LOADER_IMAGE_CONTEXT CheckContext;
- EFI_IMAGE_SECTION_HEADER *FirstSection;
- EFI_IMAGE_SECTION_HEADER *Section;
- UINTN NumberOfSections;
- UINTN Index;
- CHAR8 *Base;
- CHAR8 *End;
- CHAR8 *MaxEnd;
- EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
- EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
- UINTN Size;
- UINT32 TempDebugEntryRva;
- EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader;
-
- PeHdr = NULL;
- TeHdr = NULL;
- OptionHeader.Header = NULL;
- //
- // Assume success
- //
- ImageContext->ImageError = IMAGE_ERROR_SUCCESS;
-
- //
- // Copy the provided context info into our local version, get what we
- // can from the original image, and then use that to make sure everything
- // is legit.
- //
- CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
-
- Status = PeCoffLoaderGetImageInfo (&CheckContext);
- if (RETURN_ERROR (Status)) {
- return Status;
- }
-
- //
- // Make sure there is enough allocated space for the image being loaded
- //
- if (ImageContext->ImageSize < CheckContext.ImageSize) {
- ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE;
- return RETURN_BUFFER_TOO_SMALL;
- }
-
- //
- // If there's no relocations, then make sure it's not a runtime driver,
- // and that it's being loaded at the linked address.
- //
- if (CheckContext.RelocationsStripped) {
- //
- // If the image does not contain relocations and it is a runtime driver
- // then return an error.
- //
- if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) {
- ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM;
- return RETURN_LOAD_ERROR;
- }
- //
- // If the image does not contain relocations, and the requested load address
- // is not the linked address, then return an error.
- //
- if (CheckContext.ImageAddress != ImageContext->ImageAddress) {
- ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS;
- return RETURN_INVALID_PARAMETER;
- }
- }
- //
- // Make sure the allocated space has the proper section alignment
- //
- if (!(ImageContext->IsTeImage)) {
- if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) {
- ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT;
- return RETURN_INVALID_PARAMETER;
- }
- }
- //
- // Read the entire PE/COFF or TE header into memory
- //
- if (!(ImageContext->IsTeImage)) {
- Status = ImageContext->ImageRead (
- ImageContext->Handle,
- 0,
- &ImageContext->SizeOfHeaders,
- (VOID *) (UINTN) ImageContext->ImageAddress
- );
-
- PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)
- ((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset);
-
- OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader);
-
- FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
- (UINTN)ImageContext->ImageAddress +
- ImageContext->PeCoffHeaderOffset +
- sizeof(UINT32) +
- sizeof(EFI_IMAGE_FILE_HEADER) +
- PeHdr->Pe32.FileHeader.SizeOfOptionalHeader
- );
- NumberOfSections = (UINTN) (PeHdr->Pe32.FileHeader.NumberOfSections);
- } else {
- Status = ImageContext->ImageRead (
- ImageContext->Handle,
- 0,
- &ImageContext->SizeOfHeaders,
- (VOID *) (UINTN) ImageContext->ImageAddress
- );
-
- TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress);
-
- FirstSection = (EFI_IMAGE_SECTION_HEADER *) (
- (UINTN)ImageContext->ImageAddress +
- sizeof(EFI_TE_IMAGE_HEADER)
- );
- NumberOfSections = (UINTN) (TeHdr->NumberOfSections);
-
- }
-
- if (RETURN_ERROR (Status)) {
- ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
- return RETURN_LOAD_ERROR;
- }
-
- //
- // Load each section of the image
- //
- Section = FirstSection;
- for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) {
-
- //
- // Compute sections address
- //
- Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress);
- End = PeCoffLoaderImageAddress (
- ImageContext,
- Section->VirtualAddress + Section->Misc.VirtualSize - 1
- );
-
- //
- // If the base start or end address resolved to 0, then fail.
- //
- if ((Base == NULL) || (End == NULL)) {
- ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED;
- return RETURN_LOAD_ERROR;
- }
-
-
- if (ImageContext->IsTeImage) {
- Base = (CHAR8 *) ((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);
- End = (CHAR8 *) ((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize);
- }
-
- if (End > MaxEnd) {
- MaxEnd = End;
- }
-
- //
- // Read the section
- //
- Size = (UINTN) Section->Misc.VirtualSize;
- if ((Size == 0) || (Size > Section->SizeOfRawData)) {
- Size = (UINTN) Section->SizeOfRawData;
- }
-
- if (Section->SizeOfRawData) {
- if (!(ImageContext->IsTeImage)) {
- Status = ImageContext->ImageRead (
- ImageContext->Handle,
- Section->PointerToRawData,
- &Size,
- Base
- );
- } else {
- Status = ImageContext->ImageRead (
- ImageContext->Handle,
- Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize,
- &Size,
- Base
- );
- }
-
- if (RETURN_ERROR (Status)) {
- ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
- return Status;
- }
- }
-
- //
- // If raw size is less then virt size, zero fill the remaining
- //
-
- if (Size < Section->Misc.VirtualSize) {
- ZeroMem (Base + Size, Section->Misc.VirtualSize - Size);
- }
-
- //
- // Next Section
- //
- Section += 1;
- }
-
- //
- // Get image's entry point
- //
- if (!(ImageContext->IsTeImage)) {
- ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress (
- ImageContext,
- PeHdr->Pe32.OptionalHeader.AddressOfEntryPoint
- );
- } else {
- ImageContext->EntryPoint = (UINTN)ImageContext->ImageAddress +
- (UINTN)TeHdr->AddressOfEntryPoint +
- (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -
- (UINTN) TeHdr->StrippedSize;
- }
-
- //
- // Determine the size of the fixup data
- //
- // Per the PE/COFF spec, you can't assume that a given data directory
- // is present in the image. You have to check the NumberOfRvaAndSizes in
- // the optional header to verify a desired directory entry is there.
- //
- if (!(ImageContext->IsTeImage)) {
- if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
- if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
- DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)
- &OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
- ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
- } else {
- ImageContext->FixupDataSize = 0;
- }
- } else {
- if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) {
- DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)
- &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC];
- ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
- } else {
- ImageContext->FixupDataSize = 0;
- }
- }
- } else {
- DirectoryEntry = &TeHdr->DataDirectory[0];
- ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN);
- }
- //
- // Consumer must allocate a buffer for the relocation fixup log.
- // Only used for runtime drivers.
- //
- ImageContext->FixupData = NULL;
-
- //
- // Load the Codeview info if present
- //
- if (ImageContext->DebugDirectoryEntryRva != 0) {
- if (!(ImageContext->IsTeImage)) {
- DebugEntry = PeCoffLoaderImageAddress (
- ImageContext,
- ImageContext->DebugDirectoryEntryRva
- );
- } else {
- DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)(
- ImageContext->ImageAddress +
- ImageContext->DebugDirectoryEntryRva +
- sizeof(EFI_TE_IMAGE_HEADER) -
- TeHdr->StrippedSize
- );
- }
-
- if (DebugEntry != NULL) {
- TempDebugEntryRva = DebugEntry->RVA;
- if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) {
- Section--;
- if ((UINTN) Section->SizeOfRawData < Section->Misc.VirtualSize) {
- TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize;
- } else {
- TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData;
- }
- }
-
- if (TempDebugEntryRva != 0) {
- if (!(ImageContext->IsTeImage)) {
- ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva);
- } else {
- ImageContext->CodeView = (VOID *)(
- (UINTN)ImageContext->ImageAddress +
- (UINTN)TempDebugEntryRva +
- (UINTN)sizeof(EFI_TE_IMAGE_HEADER) -
- (UINTN) TeHdr->StrippedSize
- );
- }
-
- if (ImageContext->CodeView == NULL) {
- ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
- return RETURN_LOAD_ERROR;
- }
-
- if (DebugEntry->RVA == 0) {
- Size = DebugEntry->SizeOfData;
- if (!(ImageContext->IsTeImage)) {
- Status = ImageContext->ImageRead (
- ImageContext->Handle,
- DebugEntry->FileOffset,
- &Size,
- ImageContext->CodeView
- );
- } else {
- Status = ImageContext->ImageRead (
- ImageContext->Handle,
- DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - TeHdr->StrippedSize,
- &Size,
- ImageContext->CodeView
- );
- //
- // Should we apply fix up to this field according to the size difference between PE and TE?
- // Because now we maintain TE header fields unfixed, this field will also remain as they are
- // in original PE image.
- //
- }
-
- if (RETURN_ERROR (Status)) {
- ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ;
- return RETURN_LOAD_ERROR;
- }
-
- DebugEntry->RVA = TempDebugEntryRva;
- }
-
- switch (*(UINT32 *) ImageContext->CodeView) {
- case CODEVIEW_SIGNATURE_NB10:
- ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY);
- break;
-
- case CODEVIEW_SIGNATURE_RSDS:
- ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY);
- break;
-
- case CODEVIEW_SIGNATURE_MTOC:
- ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY);
-
- default:
- break;
- }
- }
- }
- }
-
- return Status;
-}
-
-/**
- Returns a pointer to the PDB file name for a raw PE/COFF image that is not
- loaded into system memory with the PE/COFF Loader Library functions.
-
- Returns the PDB file name for the PE/COFF image specified by Pe32Data. If
- the PE/COFF image specified by Pe32Data is not a valid, then NULL is
- returned. If the PE/COFF image specified by Pe32Data does not contain a
- debug directory entry, then NULL is returned. If the debug directory entry
- in the PE/COFF image specified by Pe32Data does not contain a PDB file name,
- then NULL is returned.
- If Pe32Data is NULL, then return NULL.
-
- @param Pe32Data Pointer to the PE/COFF image that is loaded in system
- memory.
-
- @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL
- if it cannot be retrieved.
-
-**/
-VOID *
-EFIAPI
-PeCoffLoaderGetPdbPointer (
- IN VOID *Pe32Data
- )
-{
- EFI_IMAGE_DOS_HEADER *DosHdr;
- EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
- EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry;
- EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry;
- UINTN DirCount;
- VOID *CodeViewEntryPointer;
- INTN TEImageAdjust;
- UINT32 NumberOfRvaAndSizes;
- UINT16 Magic;
- EFI_IMAGE_SECTION_HEADER *SectionHeader;
- UINT32 Index, Index1;
-
- if (Pe32Data == NULL) {
- return NULL;
- }
-
- TEImageAdjust = 0;
- DirectoryEntry = NULL;
- DebugEntry = NULL;
- NumberOfRvaAndSizes = 0;
- Index = 0;
- Index1 = 0;
- SectionHeader = NULL;
-
- DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
- if (EFI_IMAGE_DOS_SIGNATURE == DosHdr->e_magic) {
- //
- // DOS image header is present, so read the PE header after the DOS image header.
- //
- Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
- } else {
- //
- // DOS image header is not present, so PE header is at the image base.
- //
- Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
- }
-
- if (EFI_TE_IMAGE_HEADER_SIGNATURE == Hdr.Te->Signature) {
- if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) {
- DirectoryEntry = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG];
- TEImageAdjust = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize;
-
- //
- // Get the DebugEntry offset in the raw data image.
- //
- SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (Hdr.Te + 1);
- Index = Hdr.Te->NumberOfSections;
- for (Index1 = 0; Index1 < Index; Index1 ++) {
- if ((DirectoryEntry->VirtualAddress >= SectionHeader[Index1].VirtualAddress) &&
- (DirectoryEntry->VirtualAddress < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {
- DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) Hdr.Te +
- DirectoryEntry->VirtualAddress -
- SectionHeader [Index1].VirtualAddress +
- SectionHeader [Index1].PointerToRawData +
- TEImageAdjust);
- break;
- }
- }
- }
- } else if (EFI_IMAGE_NT_SIGNATURE == Hdr.Pe32->Signature) {
- //
- // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic.
- // It is due to backward-compatibility, for some system might
- // generate PE32+ image with PE32 Magic.
- //
- switch (Hdr.Pe32->FileHeader.Machine) {
- case IMAGE_FILE_MACHINE_I386:
- case IMAGE_FILE_MACHINE_ARMTHUMB_MIXED:
- //
- // Assume PE32 image with IA32 Machine field.
- //
- Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC;
- break;
- case IMAGE_FILE_MACHINE_X64:
- //
- // Assume PE32+ image with X64 Machine field
- //
- Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;
- break;
- default:
- //
- // For unknown Machine field, use Magic in optional Header
- //
- Magic = Hdr.Pe32->OptionalHeader.Magic;
- }
-
- SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (
- (UINT8 *) Hdr.Pe32 +
- sizeof (UINT32) +
- sizeof (EFI_IMAGE_FILE_HEADER) +
- Hdr.Pe32->FileHeader.SizeOfOptionalHeader
- );
- Index = Hdr.Pe32->FileHeader.NumberOfSections;
-
- if (EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC == Magic) {
- //
- // Use PE32 offset get Debug Directory Entry
- //
- NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes;
- DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
- } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
- //
- // Use PE32+ offset get Debug Directory Entry
- //
- NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;
- DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]);
- }
-
- if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG || DirectoryEntry->VirtualAddress == 0) {
- DirectoryEntry = NULL;
- DebugEntry = NULL;
- } else {
- //
- // Get the DebugEntry offset in the raw data image.
- //
- for (Index1 = 0; Index1 < Index; Index1 ++) {
- if ((DirectoryEntry->VirtualAddress >= SectionHeader[Index1].VirtualAddress) &&
- (DirectoryEntry->VirtualAddress < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {
- DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) (
- (UINTN) Pe32Data +
- DirectoryEntry->VirtualAddress -
- SectionHeader[Index1].VirtualAddress +
- SectionHeader[Index1].PointerToRawData);
- break;
- }
- }
- }
- } else {
- return NULL;
- }
-
- if (NULL == DebugEntry || NULL == DirectoryEntry) {
- return NULL;
- }
-
- //
- // Scan the directory to find the debug entry.
- //
- for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), DebugEntry++) {
- if (EFI_IMAGE_DEBUG_TYPE_CODEVIEW == DebugEntry->Type) {
- if (DebugEntry->SizeOfData > 0) {
- //
- // Get the DebugEntry offset in the raw data image.
- //
- CodeViewEntryPointer = NULL;
- for (Index1 = 0; Index1 < Index; Index1 ++) {
- if ((DebugEntry->RVA >= SectionHeader[Index1].VirtualAddress) &&
- (DebugEntry->RVA < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) {
- CodeViewEntryPointer = (VOID *) (
- ((UINTN)Pe32Data) +
- (UINTN) DebugEntry->RVA -
- SectionHeader[Index1].VirtualAddress +
- SectionHeader[Index1].PointerToRawData +
- (UINTN)TEImageAdjust);
- break;
- }
- }
- if (Index1 >= Index) {
- //
- // Can't find CodeViewEntryPointer in raw PE/COFF image.
- //
- continue;
- }
- switch (* (UINT32 *) CodeViewEntryPointer) {
- case CODEVIEW_SIGNATURE_NB10:
- return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY));
- case CODEVIEW_SIGNATURE_RSDS:
- return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY));
- case CODEVIEW_SIGNATURE_MTOC:
- return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY));
- default:
- break;
- }
- }
- }
- }
-
- return NULL;
-}
-
-
-RETURN_STATUS
-EFIAPI
-PeCoffLoaderGetEntryPoint (
- IN VOID *Pe32Data,
- OUT VOID **EntryPoint,
- OUT VOID **BaseOfImage
- )
-{
- EFI_IMAGE_DOS_HEADER *DosHdr;
- EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
-
- DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data;
- if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {
- //
- // DOS image header is present, so read the PE header after the DOS image header.
- //
- Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff));
- } else {
- //
- // DOS image header is not present, so PE header is at the image base.
- //
- Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data;
- }
-
- //
- // Calculate the entry point relative to the start of the image.
- // AddressOfEntryPoint is common for PE32 & PE32+
- //
- if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
- *BaseOfImage = (VOID *)(UINTN)(Hdr.Te->ImageBase + Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER));
- *EntryPoint = (VOID *)((UINTN)*BaseOfImage + (Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof(EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize);
- return RETURN_SUCCESS;
- } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) {
- *EntryPoint = (VOID *)(UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint;
- if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
- *BaseOfImage = (VOID *)(UINTN)Hdr.Pe32->OptionalHeader.ImageBase;
- } else {
- *BaseOfImage = (VOID *)(UINTN)Hdr.Pe32Plus->OptionalHeader.ImageBase;
- }
- *EntryPoint = (VOID *)(UINTN)((UINTN)*EntryPoint + (UINTN)*BaseOfImage);
- return RETURN_SUCCESS;
- }
-
- return RETURN_UNSUPPORTED;
-}
+/** @file + + Functions to get info and load PE/COFF image. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR> +Portions Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR> +Portions Copyright (c) 2022, Loongson Technology Corporation Limited. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <Common/UefiBaseTypes.h> +#include <CommonLib.h> +#include <IndustryStandard/PeImage.h> +#include "PeCoffLib.h" + +typedef union { + VOID *Header; + EFI_IMAGE_OPTIONAL_HEADER32 *Optional32; + EFI_IMAGE_OPTIONAL_HEADER64 *Optional64; +} EFI_IMAGE_OPTIONAL_HEADER_POINTER; + +STATIC +RETURN_STATUS +PeCoffLoaderGetPeHeader ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + OUT EFI_IMAGE_OPTIONAL_HEADER_UNION **PeHdr, + OUT EFI_TE_IMAGE_HEADER **TeHdr + ); + +STATIC +RETURN_STATUS +PeCoffLoaderCheckImageType ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr, + IN EFI_TE_IMAGE_HEADER *TeHdr + ); + +STATIC +VOID * +PeCoffLoaderImageAddress ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN UINTN Address + ); + +RETURN_STATUS +PeCoffLoaderRelocateIa32Image ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ); + + +RETURN_STATUS +PeCoffLoaderRelocateArmImage ( + IN UINT16 **Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ); + +RETURN_STATUS +PeCoffLoaderRelocateRiscVImage ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ); + +RETURN_STATUS +PeCoffLoaderRelocateLoongArch64Image ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ); + +/** + Retrieves the PE or TE Header from a PE/COFF or TE image + + @param ImageContext The context of the image being loaded + @param PeHdr The buffer in which to return the PE header + @param TeHdr The buffer in which to return the TE header + + @return RETURN_SUCCESS if the PE or TE Header is read, + Otherwise, the error status from reading the PE/COFF or TE image using the ImageRead function. +**/ +STATIC +RETURN_STATUS +PeCoffLoaderGetPeHeader ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + OUT EFI_IMAGE_OPTIONAL_HEADER_UNION **PeHdr, + OUT EFI_TE_IMAGE_HEADER **TeHdr + ) +{ + RETURN_STATUS Status; + EFI_IMAGE_DOS_HEADER DosHdr; + UINTN Size; + + ImageContext->IsTeImage = FALSE; + // + // Read the DOS image headers + // + Size = sizeof (EFI_IMAGE_DOS_HEADER); + Status = ImageContext->ImageRead ( + ImageContext->Handle, + 0, + &Size, + &DosHdr + ); + if (RETURN_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return Status; + } + + ImageContext->PeCoffHeaderOffset = 0; + if (DosHdr.e_magic == EFI_IMAGE_DOS_SIGNATURE) { + // + // DOS image header is present, so read the PE header after the DOS image header + // + ImageContext->PeCoffHeaderOffset = DosHdr.e_lfanew; + } + // + // Get the PE/COFF Header pointer + // + *PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN)ImageContext->Handle + ImageContext->PeCoffHeaderOffset); + if ((*PeHdr)->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) { + // + // Check the PE/COFF Header Signature. If not, then try to get a TE header + // + *TeHdr = (EFI_TE_IMAGE_HEADER *)*PeHdr; + if ((*TeHdr)->Signature != EFI_TE_IMAGE_HEADER_SIGNATURE) { + return RETURN_UNSUPPORTED; + } + ImageContext->IsTeImage = TRUE; + } + + return RETURN_SUCCESS; +} + +/** + Checks the PE or TE header of a PE/COFF or TE image to determine if it supported + + @param ImageContext The context of the image being loaded + @param PeHdr The buffer in which to return the PE header + @param TeHdr The buffer in which to return the TE header + + @retval RETURN_SUCCESS if the PE/COFF or TE image is supported + @retval RETURN_UNSUPPORTED of the PE/COFF or TE image is not supported. + +**/ +STATIC +RETURN_STATUS +PeCoffLoaderCheckImageType ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr, + IN EFI_TE_IMAGE_HEADER *TeHdr + ) +{ + // + // See if the machine type is supported. + // We support a native machine type (IA-32/Itanium-based) + // + if (ImageContext->IsTeImage == FALSE) { + ImageContext->Machine = PeHdr->Pe32.FileHeader.Machine; + } else { + ImageContext->Machine = TeHdr->Machine; + } + + if (ImageContext->Machine != IMAGE_FILE_MACHINE_I386 && \ + ImageContext->Machine != IMAGE_FILE_MACHINE_X64 && \ + ImageContext->Machine != IMAGE_FILE_MACHINE_ARMTHUMB_MIXED && \ + ImageContext->Machine != IMAGE_FILE_MACHINE_EBC && \ + ImageContext->Machine != IMAGE_FILE_MACHINE_ARM64 && \ + ImageContext->Machine != IMAGE_FILE_MACHINE_RISCV64 && \ + ImageContext->Machine != IMAGE_FILE_MACHINE_LOONGARCH64) { + // + // unsupported PeImage machine type + // + return RETURN_UNSUPPORTED; + } + + // + // See if the image type is supported. We support EFI Applications, + // EFI Boot Service Drivers, EFI Runtime Drivers and EFI SAL Drivers. + // + if (ImageContext->IsTeImage == FALSE) { + ImageContext->ImageType = PeHdr->Pe32.OptionalHeader.Subsystem; + } else { + ImageContext->ImageType = (UINT16) (TeHdr->Subsystem); + } + + if (ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION && \ + ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER && \ + ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER && \ + ImageContext->ImageType != EFI_IMAGE_SUBSYSTEM_SAL_RUNTIME_DRIVER) { + // + // unsupported PeImage subsystem type + // + return RETURN_UNSUPPORTED; + } + + return RETURN_SUCCESS; +} + +/** + Retrieves information on a PE/COFF image + + @param This Calling context + @param ImageContext The context of the image being loaded + + @retval RETURN_SUCCESS The information on the PE/COFF image was collected. + @retval RETURN_INVALID_PARAMETER ImageContext is NULL. + @retval RETURN_UNSUPPORTED The PE/COFF image is not supported. + @retval Otherwise The error status from reading the PE/COFF image using the + ImageContext->ImageRead() function + +**/ +RETURN_STATUS +EFIAPI +PeCoffLoaderGetImageInfo ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + RETURN_STATUS Status; + EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr; + EFI_TE_IMAGE_HEADER *TeHdr; + EFI_IMAGE_DATA_DIRECTORY *DebugDirectoryEntry; + UINTN Size; + UINTN Index; + UINTN DebugDirectoryEntryRva; + UINTN DebugDirectoryEntryFileOffset; + UINTN SectionHeaderOffset; + EFI_IMAGE_SECTION_HEADER SectionHeader; + EFI_IMAGE_DEBUG_DIRECTORY_ENTRY DebugEntry; + EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader; + + PeHdr = NULL; + TeHdr = NULL; + DebugDirectoryEntry = NULL; + DebugDirectoryEntryRva = 0; + + if (NULL == ImageContext) { + return RETURN_INVALID_PARAMETER; + } + // + // Assume success + // + ImageContext->ImageError = IMAGE_ERROR_SUCCESS; + + Status = PeCoffLoaderGetPeHeader (ImageContext, &PeHdr, &TeHdr); + if (RETURN_ERROR (Status)) { + return Status; + } + + // + // Verify machine type + // + Status = PeCoffLoaderCheckImageType (ImageContext, PeHdr, TeHdr); + if (RETURN_ERROR (Status)) { + return Status; + } + OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader); + + // + // Retrieve the base address of the image + // + if (!(ImageContext->IsTeImage)) { + if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + ImageContext->ImageAddress = (PHYSICAL_ADDRESS) OptionHeader.Optional32->ImageBase; + } else { + ImageContext->ImageAddress = (PHYSICAL_ADDRESS) OptionHeader.Optional64->ImageBase; + } + } else { + ImageContext->ImageAddress = (PHYSICAL_ADDRESS) (TeHdr->ImageBase + TeHdr->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER)); + } + // + // Initialize the alternate destination address to 0 indicating that it + // should not be used. + // + ImageContext->DestinationAddress = 0; + + // + // Initialize the codeview pointer. + // + ImageContext->CodeView = NULL; + ImageContext->PdbPointer = NULL; + + // + // Three cases with regards to relocations: + // - Image has base relocs, RELOCS_STRIPPED==0 => image is relocatable + // - Image has no base relocs, RELOCS_STRIPPED==1 => Image is not relocatable + // - Image has no base relocs, RELOCS_STRIPPED==0 => Image is relocatable but + // has no base relocs to apply + // Obviously having base relocations with RELOCS_STRIPPED==1 is invalid. + // + // Look at the file header to determine if relocations have been stripped, and + // save this info in the image context for later use. + // + if ((!(ImageContext->IsTeImage)) && ((PeHdr->Pe32.FileHeader.Characteristics & EFI_IMAGE_FILE_RELOCS_STRIPPED) != 0)) { + ImageContext->RelocationsStripped = TRUE; + } else if ((ImageContext->IsTeImage) && (TeHdr->DataDirectory[0].Size == 0) && (TeHdr->DataDirectory[0].VirtualAddress == 0)) { + ImageContext->RelocationsStripped = TRUE; + } else { + ImageContext->RelocationsStripped = FALSE; + } + + if (!(ImageContext->IsTeImage)) { + + if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + ImageContext->ImageSize = (UINT64) OptionHeader.Optional32->SizeOfImage; + ImageContext->SectionAlignment = OptionHeader.Optional32->SectionAlignment; + ImageContext->SizeOfHeaders = OptionHeader.Optional32->SizeOfHeaders; + + // + // Modify ImageSize to contain .PDB file name if required and initialize + // PdbRVA field... + // + if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { + DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); + DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress; + } + } else { + ImageContext->ImageSize = (UINT64) OptionHeader.Optional64->SizeOfImage; + ImageContext->SectionAlignment = OptionHeader.Optional64->SectionAlignment; + ImageContext->SizeOfHeaders = OptionHeader.Optional64->SizeOfHeaders; + + // + // Modify ImageSize to contain .PDB file name if required and initialize + // PdbRVA field... + // + if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { + DebugDirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) &(OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); + DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress; + } + } + + if (DebugDirectoryEntryRva != 0) { + // + // Determine the file offset of the debug directory... This means we walk + // the sections to find which section contains the RVA of the debug + // directory + // + DebugDirectoryEntryFileOffset = 0; + + SectionHeaderOffset = (UINTN)( + ImageContext->PeCoffHeaderOffset + + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER) + + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader + ); + + for (Index = 0; Index < PeHdr->Pe32.FileHeader.NumberOfSections; Index++) { + // + // Read section header from file + // + Size = sizeof (EFI_IMAGE_SECTION_HEADER); + Status = ImageContext->ImageRead ( + ImageContext->Handle, + SectionHeaderOffset, + &Size, + &SectionHeader + ); + if (RETURN_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return Status; + } + + if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress && + DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) { + DebugDirectoryEntryFileOffset = + DebugDirectoryEntryRva - SectionHeader.VirtualAddress + SectionHeader.PointerToRawData; + break; + } + + SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER); + } + + if (DebugDirectoryEntryFileOffset != 0) { + for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) { + // + // Read next debug directory entry + // + Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY); + Status = ImageContext->ImageRead ( + ImageContext->Handle, + DebugDirectoryEntryFileOffset + Index, + &Size, + &DebugEntry + ); + if (RETURN_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return Status; + } + + if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) { + ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index); + if (DebugEntry.RVA == 0 && DebugEntry.FileOffset != 0) { + ImageContext->ImageSize += DebugEntry.SizeOfData; + } + + return RETURN_SUCCESS; + } + } + } + } + } else { + ImageContext->ImageSize = 0; + ImageContext->SectionAlignment = 4096; + ImageContext->SizeOfHeaders = sizeof (EFI_TE_IMAGE_HEADER) + (UINTN) TeHdr->BaseOfCode - (UINTN) TeHdr->StrippedSize; + + DebugDirectoryEntry = &TeHdr->DataDirectory[1]; + DebugDirectoryEntryRva = DebugDirectoryEntry->VirtualAddress; + SectionHeaderOffset = (UINTN) (sizeof (EFI_TE_IMAGE_HEADER)); + + DebugDirectoryEntryFileOffset = 0; + + for (Index = 0; Index < TeHdr->NumberOfSections;) { + // + // Read section header from file + // + Size = sizeof (EFI_IMAGE_SECTION_HEADER); + Status = ImageContext->ImageRead ( + ImageContext->Handle, + SectionHeaderOffset, + &Size, + &SectionHeader + ); + if (RETURN_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return Status; + } + + if (DebugDirectoryEntryRva >= SectionHeader.VirtualAddress && + DebugDirectoryEntryRva < SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize) { + DebugDirectoryEntryFileOffset = DebugDirectoryEntryRva - + SectionHeader.VirtualAddress + + SectionHeader.PointerToRawData + + sizeof (EFI_TE_IMAGE_HEADER) - + TeHdr->StrippedSize; + + // + // File offset of the debug directory was found, if this is not the last + // section, then skip to the last section for calculating the image size. + // + if (Index < (UINTN) TeHdr->NumberOfSections - 1) { + SectionHeaderOffset += (TeHdr->NumberOfSections - 1 - Index) * sizeof (EFI_IMAGE_SECTION_HEADER); + Index = TeHdr->NumberOfSections - 1; + continue; + } + } + + // + // In Te image header there is not a field to describe the ImageSize. + // Actually, the ImageSize equals the RVA plus the VirtualSize of + // the last section mapped into memory (Must be rounded up to + // a multiple of Section Alignment). Per the PE/COFF specification, the + // section headers in the Section Table must appear in order of the RVA + // values for the corresponding sections. So the ImageSize can be determined + // by the RVA and the VirtualSize of the last section header in the + // Section Table. + // + if ((++Index) == (UINTN) TeHdr->NumberOfSections) { + ImageContext->ImageSize = (SectionHeader.VirtualAddress + SectionHeader.Misc.VirtualSize + + ImageContext->SectionAlignment - 1) & ~(ImageContext->SectionAlignment - 1); + } + + SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER); + } + + if (DebugDirectoryEntryFileOffset != 0) { + for (Index = 0; Index < DebugDirectoryEntry->Size; Index += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY)) { + // + // Read next debug directory entry + // + Size = sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY); + Status = ImageContext->ImageRead ( + ImageContext->Handle, + DebugDirectoryEntryFileOffset, + &Size, + &DebugEntry + ); + if (RETURN_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return Status; + } + + if (DebugEntry.Type == EFI_IMAGE_DEBUG_TYPE_CODEVIEW) { + ImageContext->DebugDirectoryEntryRva = (UINT32) (DebugDirectoryEntryRva + Index); + return RETURN_SUCCESS; + } + } + } + } + + return RETURN_SUCCESS; +} + +/** + Converts an image address to the loaded address + + @param ImageContext The context of the image being loaded + @param Address The address to be converted to the loaded address + + @return NULL if the address can not be converted, otherwise, the converted address + +--*/ +STATIC +VOID * +PeCoffLoaderImageAddress ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext, + IN UINTN Address + ) +{ + if (Address >= ImageContext->ImageSize) { + ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS; + return NULL; + } + + return (UINT8 *) ((UINTN) ImageContext->ImageAddress + Address); +} + +/** + Relocates a PE/COFF image in memory + + @param This Calling context + @param ImageContext Contains information on the loaded image to relocate + + @retval RETURN_SUCCESS if the PE/COFF image was relocated + @retval RETURN_LOAD_ERROR if the image is not a valid PE/COFF image + @retval RETURN_UNSUPPORTED not support + +**/ +RETURN_STATUS +EFIAPI +PeCoffLoaderRelocateImage ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + RETURN_STATUS Status; + EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr; + EFI_TE_IMAGE_HEADER *TeHdr; + EFI_IMAGE_DATA_DIRECTORY *RelocDir; + UINT64 Adjust; + EFI_IMAGE_BASE_RELOCATION *RelocBase; + EFI_IMAGE_BASE_RELOCATION *RelocBaseEnd; + UINT16 *Reloc; + UINT16 *RelocEnd; + CHAR8 *Fixup; + CHAR8 *FixupBase; + UINT16 *F16; + UINT32 *F32; + UINT64 *F64; + CHAR8 *FixupData; + PHYSICAL_ADDRESS BaseAddress; + UINT16 MachineType; + EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader; + + PeHdr = NULL; + TeHdr = NULL; + // + // Assume success + // + ImageContext->ImageError = IMAGE_ERROR_SUCCESS; + + // + // If there are no relocation entries, then we are done + // + if (ImageContext->RelocationsStripped) { + return RETURN_SUCCESS; + } + + // + // Use DestinationAddress field of ImageContext as the relocation address even if it is 0. + // + BaseAddress = ImageContext->DestinationAddress; + + if (!(ImageContext->IsTeImage)) { + PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN)ImageContext->ImageAddress + + ImageContext->PeCoffHeaderOffset); + OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader); + if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + Adjust = (UINT64) BaseAddress - OptionHeader.Optional32->ImageBase; + OptionHeader.Optional32->ImageBase = (UINT32) BaseAddress; + MachineType = ImageContext->Machine; + // + // Find the relocation block + // + // Per the PE/COFF spec, you can't assume that a given data directory + // is present in the image. You have to check the NumberOfRvaAndSizes in + // the optional header to verify a desired directory entry is there. + // + if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + RelocDir = &OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + if ((RelocDir != NULL) && (RelocDir->Size > 0)) { + RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress); + RelocBaseEnd = PeCoffLoaderImageAddress ( + ImageContext, + RelocDir->VirtualAddress + RelocDir->Size - 1 + ); + if (RelocBase == NULL || RelocBaseEnd == NULL || RelocBaseEnd < RelocBase) { + ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION; + return RETURN_LOAD_ERROR; + } + } else { + // + // Set base and end to bypass processing below. + // + RelocBase = RelocBaseEnd = 0; + } + } else { + // + // Set base and end to bypass processing below. + // + RelocBase = RelocBaseEnd = 0; + } + } else { + Adjust = (UINT64) BaseAddress - OptionHeader.Optional64->ImageBase; + OptionHeader.Optional64->ImageBase = BaseAddress; + MachineType = ImageContext->Machine; + // + // Find the relocation block + // + // Per the PE/COFF spec, you can't assume that a given data directory + // is present in the image. You have to check the NumberOfRvaAndSizes in + // the optional header to verify a desired directory entry is there. + // + if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + RelocDir = &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + if ((RelocDir != NULL) && (RelocDir->Size > 0)) { + RelocBase = PeCoffLoaderImageAddress (ImageContext, RelocDir->VirtualAddress); + RelocBaseEnd = PeCoffLoaderImageAddress ( + ImageContext, + RelocDir->VirtualAddress + RelocDir->Size - 1 + ); + if (RelocBase == NULL || RelocBaseEnd == NULL || RelocBaseEnd < RelocBase) { + ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION; + return RETURN_LOAD_ERROR; + } + } else { + // + // Set base and end to bypass processing below. + // + RelocBase = RelocBaseEnd = 0; + } + } else { + // + // Set base and end to bypass processing below. + // + RelocBase = RelocBaseEnd = 0; + } + } + } else { + TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress); + Adjust = (UINT64) (BaseAddress - TeHdr->ImageBase); + TeHdr->ImageBase = (UINT64) (BaseAddress); + MachineType = TeHdr->Machine; + + // + // Find the relocation block + // + RelocDir = &TeHdr->DataDirectory[0]; + RelocBase = (EFI_IMAGE_BASE_RELOCATION *)(UINTN)( + ImageContext->ImageAddress + + RelocDir->VirtualAddress + + sizeof(EFI_TE_IMAGE_HEADER) - + TeHdr->StrippedSize + ); + RelocBaseEnd = (EFI_IMAGE_BASE_RELOCATION *) ((UINTN) RelocBase + (UINTN) RelocDir->Size - 1); + } + + // + // Run the relocation information and apply the fixups + // + FixupData = ImageContext->FixupData; + while (RelocBase < RelocBaseEnd) { + + Reloc = (UINT16 *) ((CHAR8 *) RelocBase + sizeof (EFI_IMAGE_BASE_RELOCATION)); + RelocEnd = (UINT16 *) ((CHAR8 *) RelocBase + RelocBase->SizeOfBlock); + if (!(ImageContext->IsTeImage)) { + FixupBase = PeCoffLoaderImageAddress (ImageContext, RelocBase->VirtualAddress); + if (FixupBase == NULL) { + ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION; + return RETURN_LOAD_ERROR; + } + } else { + FixupBase = (CHAR8 *)(UINTN)(ImageContext->ImageAddress + + RelocBase->VirtualAddress + + sizeof(EFI_TE_IMAGE_HEADER) - + TeHdr->StrippedSize + ); + } + + if ((CHAR8 *) RelocEnd < (CHAR8 *) ((UINTN) ImageContext->ImageAddress) || + (CHAR8 *) RelocEnd > (CHAR8 *)((UINTN)ImageContext->ImageAddress + + (UINTN)ImageContext->ImageSize)) { + ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION; + return RETURN_LOAD_ERROR; + } + + // + // Run this relocation record + // + while (Reloc < RelocEnd) { + + Fixup = FixupBase + (*Reloc & 0xFFF); + switch ((*Reloc) >> 12) { + case EFI_IMAGE_REL_BASED_ABSOLUTE: + break; + + case EFI_IMAGE_REL_BASED_HIGH: + F16 = (UINT16 *) Fixup; + *F16 = (UINT16) (*F16 + ((UINT16) ((UINT32) Adjust >> 16))); + if (FixupData != NULL) { + *(UINT16 *) FixupData = *F16; + FixupData = FixupData + sizeof (UINT16); + } + break; + + case EFI_IMAGE_REL_BASED_LOW: + F16 = (UINT16 *) Fixup; + *F16 = (UINT16) (*F16 + (UINT16) Adjust); + if (FixupData != NULL) { + *(UINT16 *) FixupData = *F16; + FixupData = FixupData + sizeof (UINT16); + } + break; + + case EFI_IMAGE_REL_BASED_HIGHLOW: + F32 = (UINT32 *) Fixup; + *F32 = *F32 + (UINT32) Adjust; + if (FixupData != NULL) { + FixupData = ALIGN_POINTER (FixupData, sizeof (UINT32)); + *(UINT32 *) FixupData = *F32; + FixupData = FixupData + sizeof (UINT32); + } + break; + + case EFI_IMAGE_REL_BASED_DIR64: + F64 = (UINT64 *) Fixup; + *F64 = *F64 + (UINT64) Adjust; + if (FixupData != NULL) { + FixupData = ALIGN_POINTER (FixupData, sizeof (UINT64)); + *(UINT64 *) FixupData = *F64; + FixupData = FixupData + sizeof (UINT64); + } + break; + + case EFI_IMAGE_REL_BASED_HIGHADJ: + // + // Return the same EFI_UNSUPPORTED return code as + // PeCoffLoaderRelocateImageEx() returns if it does not recognize + // the relocation type. + // + ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION; + return RETURN_UNSUPPORTED; + + default: + switch (MachineType) { + case IMAGE_FILE_MACHINE_I386: + Status = PeCoffLoaderRelocateIa32Image (Reloc, Fixup, &FixupData, Adjust); + break; + case IMAGE_FILE_MACHINE_ARMTHUMB_MIXED: + Status = PeCoffLoaderRelocateArmImage (&Reloc, Fixup, &FixupData, Adjust); + break; + case IMAGE_FILE_MACHINE_RISCV64: + Status = PeCoffLoaderRelocateRiscVImage (Reloc, Fixup, &FixupData, Adjust); + break; + case IMAGE_FILE_MACHINE_LOONGARCH64: + Status = PeCoffLoaderRelocateLoongArch64Image (Reloc, Fixup, &FixupData, Adjust); + break; + default: + Status = RETURN_UNSUPPORTED; + break; + } + if (RETURN_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_FAILED_RELOCATION; + return Status; + } + } + + // + // Next relocation record + // + Reloc += 1; + } + + // + // Next reloc block + // + RelocBase = (EFI_IMAGE_BASE_RELOCATION *) RelocEnd; + } + + return RETURN_SUCCESS; +} + +/** + Loads a PE/COFF image into memory + + @param This Calling context + @param ImageContext Contains information on image to load into memory + + @retval RETURN_SUCCESS if the PE/COFF image was loaded + @retval RETURN_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer + @retval RETURN_LOAD_ERROR if the image is a runtime driver with no relocations + @retval RETURN_INVALID_PARAMETER if the image address is invalid + +**/ +RETURN_STATUS +EFIAPI +PeCoffLoaderLoadImage ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +{ + RETURN_STATUS Status; + EFI_IMAGE_OPTIONAL_HEADER_UNION *PeHdr; + EFI_TE_IMAGE_HEADER *TeHdr; + PE_COFF_LOADER_IMAGE_CONTEXT CheckContext; + EFI_IMAGE_SECTION_HEADER *FirstSection; + EFI_IMAGE_SECTION_HEADER *Section; + UINTN NumberOfSections; + UINTN Index; + CHAR8 *Base; + CHAR8 *End; + CHAR8 *MaxEnd; + EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry; + EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry; + UINTN Size; + UINT32 TempDebugEntryRva; + EFI_IMAGE_OPTIONAL_HEADER_POINTER OptionHeader; + + PeHdr = NULL; + TeHdr = NULL; + OptionHeader.Header = NULL; + // + // Assume success + // + ImageContext->ImageError = IMAGE_ERROR_SUCCESS; + + // + // Copy the provided context info into our local version, get what we + // can from the original image, and then use that to make sure everything + // is legit. + // + CopyMem (&CheckContext, ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT)); + + Status = PeCoffLoaderGetImageInfo (&CheckContext); + if (RETURN_ERROR (Status)) { + return Status; + } + + // + // Make sure there is enough allocated space for the image being loaded + // + if (ImageContext->ImageSize < CheckContext.ImageSize) { + ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_SIZE; + return RETURN_BUFFER_TOO_SMALL; + } + + // + // If there's no relocations, then make sure it's not a runtime driver, + // and that it's being loaded at the linked address. + // + if (CheckContext.RelocationsStripped) { + // + // If the image does not contain relocations and it is a runtime driver + // then return an error. + // + if (CheckContext.ImageType == EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER) { + ImageContext->ImageError = IMAGE_ERROR_INVALID_SUBSYSTEM; + return RETURN_LOAD_ERROR; + } + // + // If the image does not contain relocations, and the requested load address + // is not the linked address, then return an error. + // + if (CheckContext.ImageAddress != ImageContext->ImageAddress) { + ImageContext->ImageError = IMAGE_ERROR_INVALID_IMAGE_ADDRESS; + return RETURN_INVALID_PARAMETER; + } + } + // + // Make sure the allocated space has the proper section alignment + // + if (!(ImageContext->IsTeImage)) { + if ((ImageContext->ImageAddress & (CheckContext.SectionAlignment - 1)) != 0) { + ImageContext->ImageError = IMAGE_ERROR_INVALID_SECTION_ALIGNMENT; + return RETURN_INVALID_PARAMETER; + } + } + // + // Read the entire PE/COFF or TE header into memory + // + if (!(ImageContext->IsTeImage)) { + Status = ImageContext->ImageRead ( + ImageContext->Handle, + 0, + &ImageContext->SizeOfHeaders, + (VOID *) (UINTN) ImageContext->ImageAddress + ); + + PeHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) + ((UINTN)ImageContext->ImageAddress + ImageContext->PeCoffHeaderOffset); + + OptionHeader.Header = (VOID *) &(PeHdr->Pe32.OptionalHeader); + + FirstSection = (EFI_IMAGE_SECTION_HEADER *) ( + (UINTN)ImageContext->ImageAddress + + ImageContext->PeCoffHeaderOffset + + sizeof(UINT32) + + sizeof(EFI_IMAGE_FILE_HEADER) + + PeHdr->Pe32.FileHeader.SizeOfOptionalHeader + ); + NumberOfSections = (UINTN) (PeHdr->Pe32.FileHeader.NumberOfSections); + } else { + Status = ImageContext->ImageRead ( + ImageContext->Handle, + 0, + &ImageContext->SizeOfHeaders, + (VOID *) (UINTN) ImageContext->ImageAddress + ); + + TeHdr = (EFI_TE_IMAGE_HEADER *) (UINTN) (ImageContext->ImageAddress); + + FirstSection = (EFI_IMAGE_SECTION_HEADER *) ( + (UINTN)ImageContext->ImageAddress + + sizeof(EFI_TE_IMAGE_HEADER) + ); + NumberOfSections = (UINTN) (TeHdr->NumberOfSections); + + } + + if (RETURN_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return RETURN_LOAD_ERROR; + } + + // + // Load each section of the image + // + Section = FirstSection; + for (Index = 0, MaxEnd = NULL; Index < NumberOfSections; Index++) { + + // + // Compute sections address + // + Base = PeCoffLoaderImageAddress (ImageContext, Section->VirtualAddress); + End = PeCoffLoaderImageAddress ( + ImageContext, + Section->VirtualAddress + Section->Misc.VirtualSize - 1 + ); + + // + // If the base start or end address resolved to 0, then fail. + // + if ((Base == NULL) || (End == NULL)) { + ImageContext->ImageError = IMAGE_ERROR_SECTION_NOT_LOADED; + return RETURN_LOAD_ERROR; + } + + + if (ImageContext->IsTeImage) { + Base = (CHAR8 *) ((UINTN) Base + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize); + End = (CHAR8 *) ((UINTN) End + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize); + } + + if (End > MaxEnd) { + MaxEnd = End; + } + + // + // Read the section + // + Size = (UINTN) Section->Misc.VirtualSize; + if ((Size == 0) || (Size > Section->SizeOfRawData)) { + Size = (UINTN) Section->SizeOfRawData; + } + + if (Section->SizeOfRawData) { + if (!(ImageContext->IsTeImage)) { + Status = ImageContext->ImageRead ( + ImageContext->Handle, + Section->PointerToRawData, + &Size, + Base + ); + } else { + Status = ImageContext->ImageRead ( + ImageContext->Handle, + Section->PointerToRawData + sizeof (EFI_TE_IMAGE_HEADER) - (UINTN) TeHdr->StrippedSize, + &Size, + Base + ); + } + + if (RETURN_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return Status; + } + } + + // + // If raw size is less then virt size, zero fill the remaining + // + + if (Size < Section->Misc.VirtualSize) { + ZeroMem (Base + Size, Section->Misc.VirtualSize - Size); + } + + // + // Next Section + // + Section += 1; + } + + // + // Get image's entry point + // + if (!(ImageContext->IsTeImage)) { + ImageContext->EntryPoint = (PHYSICAL_ADDRESS) (UINTN) PeCoffLoaderImageAddress ( + ImageContext, + PeHdr->Pe32.OptionalHeader.AddressOfEntryPoint + ); + } else { + ImageContext->EntryPoint = (UINTN)ImageContext->ImageAddress + + (UINTN)TeHdr->AddressOfEntryPoint + + (UINTN)sizeof(EFI_TE_IMAGE_HEADER) - + (UINTN) TeHdr->StrippedSize; + } + + // + // Determine the size of the fixup data + // + // Per the PE/COFF spec, you can't assume that a given data directory + // is present in the image. You have to check the NumberOfRvaAndSizes in + // the optional header to verify a desired directory entry is there. + // + if (!(ImageContext->IsTeImage)) { + if (PeHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + if (OptionHeader.Optional32->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) + &OptionHeader.Optional32->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN); + } else { + ImageContext->FixupDataSize = 0; + } + } else { + if (OptionHeader.Optional64->NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *) + &OptionHeader.Optional64->DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC]; + ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN); + } else { + ImageContext->FixupDataSize = 0; + } + } + } else { + DirectoryEntry = &TeHdr->DataDirectory[0]; + ImageContext->FixupDataSize = DirectoryEntry->Size / sizeof (UINT16) * sizeof (UINTN); + } + // + // Consumer must allocate a buffer for the relocation fixup log. + // Only used for runtime drivers. + // + ImageContext->FixupData = NULL; + + // + // Load the Codeview info if present + // + if (ImageContext->DebugDirectoryEntryRva != 0) { + if (!(ImageContext->IsTeImage)) { + DebugEntry = PeCoffLoaderImageAddress ( + ImageContext, + ImageContext->DebugDirectoryEntryRva + ); + } else { + DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)(UINTN)( + ImageContext->ImageAddress + + ImageContext->DebugDirectoryEntryRva + + sizeof(EFI_TE_IMAGE_HEADER) - + TeHdr->StrippedSize + ); + } + + if (DebugEntry != NULL) { + TempDebugEntryRva = DebugEntry->RVA; + if (DebugEntry->RVA == 0 && DebugEntry->FileOffset != 0) { + Section--; + if ((UINTN) Section->SizeOfRawData < Section->Misc.VirtualSize) { + TempDebugEntryRva = Section->VirtualAddress + Section->Misc.VirtualSize; + } else { + TempDebugEntryRva = Section->VirtualAddress + Section->SizeOfRawData; + } + } + + if (TempDebugEntryRva != 0) { + if (!(ImageContext->IsTeImage)) { + ImageContext->CodeView = PeCoffLoaderImageAddress (ImageContext, TempDebugEntryRva); + } else { + ImageContext->CodeView = (VOID *)( + (UINTN)ImageContext->ImageAddress + + (UINTN)TempDebugEntryRva + + (UINTN)sizeof(EFI_TE_IMAGE_HEADER) - + (UINTN) TeHdr->StrippedSize + ); + } + + if (ImageContext->CodeView == NULL) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return RETURN_LOAD_ERROR; + } + + if (DebugEntry->RVA == 0) { + Size = DebugEntry->SizeOfData; + if (!(ImageContext->IsTeImage)) { + Status = ImageContext->ImageRead ( + ImageContext->Handle, + DebugEntry->FileOffset, + &Size, + ImageContext->CodeView + ); + } else { + Status = ImageContext->ImageRead ( + ImageContext->Handle, + DebugEntry->FileOffset + sizeof (EFI_TE_IMAGE_HEADER) - TeHdr->StrippedSize, + &Size, + ImageContext->CodeView + ); + // + // Should we apply fix up to this field according to the size difference between PE and TE? + // Because now we maintain TE header fields unfixed, this field will also remain as they are + // in original PE image. + // + } + + if (RETURN_ERROR (Status)) { + ImageContext->ImageError = IMAGE_ERROR_IMAGE_READ; + return RETURN_LOAD_ERROR; + } + + DebugEntry->RVA = TempDebugEntryRva; + } + + switch (*(UINT32 *) ImageContext->CodeView) { + case CODEVIEW_SIGNATURE_NB10: + ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY); + break; + + case CODEVIEW_SIGNATURE_RSDS: + ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY); + break; + + case CODEVIEW_SIGNATURE_MTOC: + ImageContext->PdbPointer = (CHAR8 *) ImageContext->CodeView + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY); + + default: + break; + } + } + } + } + + return Status; +} + +/** + Returns a pointer to the PDB file name for a raw PE/COFF image that is not + loaded into system memory with the PE/COFF Loader Library functions. + + Returns the PDB file name for the PE/COFF image specified by Pe32Data. If + the PE/COFF image specified by Pe32Data is not a valid, then NULL is + returned. If the PE/COFF image specified by Pe32Data does not contain a + debug directory entry, then NULL is returned. If the debug directory entry + in the PE/COFF image specified by Pe32Data does not contain a PDB file name, + then NULL is returned. + If Pe32Data is NULL, then return NULL. + + @param Pe32Data Pointer to the PE/COFF image that is loaded in system + memory. + + @return The PDB file name for the PE/COFF image specified by Pe32Data or NULL + if it cannot be retrieved. + +**/ +VOID * +EFIAPI +PeCoffLoaderGetPdbPointer ( + IN VOID *Pe32Data + ) +{ + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + EFI_IMAGE_DATA_DIRECTORY *DirectoryEntry; + EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *DebugEntry; + UINTN DirCount; + VOID *CodeViewEntryPointer; + INTN TEImageAdjust; + UINT32 NumberOfRvaAndSizes; + UINT16 Magic; + EFI_IMAGE_SECTION_HEADER *SectionHeader; + UINT32 Index, Index1; + + if (Pe32Data == NULL) { + return NULL; + } + + TEImageAdjust = 0; + DirectoryEntry = NULL; + DebugEntry = NULL; + NumberOfRvaAndSizes = 0; + Index = 0; + Index1 = 0; + SectionHeader = NULL; + + DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data; + if (EFI_IMAGE_DOS_SIGNATURE == DosHdr->e_magic) { + // + // DOS image header is present, so read the PE header after the DOS image header. + // + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff)); + } else { + // + // DOS image header is not present, so PE header is at the image base. + // + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data; + } + + if (EFI_TE_IMAGE_HEADER_SIGNATURE == Hdr.Te->Signature) { + if (Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) { + DirectoryEntry = &Hdr.Te->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG]; + TEImageAdjust = sizeof (EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize; + + // + // Get the DebugEntry offset in the raw data image. + // + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (Hdr.Te + 1); + Index = Hdr.Te->NumberOfSections; + for (Index1 = 0; Index1 < Index; Index1 ++) { + if ((DirectoryEntry->VirtualAddress >= SectionHeader[Index1].VirtualAddress) && + (DirectoryEntry->VirtualAddress < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) { + DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *)((UINTN) Hdr.Te + + DirectoryEntry->VirtualAddress - + SectionHeader [Index1].VirtualAddress + + SectionHeader [Index1].PointerToRawData + + TEImageAdjust); + break; + } + } + } + } else if (EFI_IMAGE_NT_SIGNATURE == Hdr.Pe32->Signature) { + // + // NOTE: We use Machine field to identify PE32/PE32+, instead of Magic. + // It is due to backward-compatibility, for some system might + // generate PE32+ image with PE32 Magic. + // + switch (Hdr.Pe32->FileHeader.Machine) { + case IMAGE_FILE_MACHINE_I386: + case IMAGE_FILE_MACHINE_ARMTHUMB_MIXED: + // + // Assume PE32 image with IA32 Machine field. + // + Magic = EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC; + break; + case IMAGE_FILE_MACHINE_X64: + // + // Assume PE32+ image with X64 Machine field + // + Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC; + break; + default: + // + // For unknown Machine field, use Magic in optional Header + // + Magic = Hdr.Pe32->OptionalHeader.Magic; + } + + SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ( + (UINT8 *) Hdr.Pe32 + + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER) + + Hdr.Pe32->FileHeader.SizeOfOptionalHeader + ); + Index = Hdr.Pe32->FileHeader.NumberOfSections; + + if (EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC == Magic) { + // + // Use PE32 offset get Debug Directory Entry + // + NumberOfRvaAndSizes = Hdr.Pe32->OptionalHeader.NumberOfRvaAndSizes; + DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); + } else if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + // + // Use PE32+ offset get Debug Directory Entry + // + NumberOfRvaAndSizes = Hdr.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes; + DirectoryEntry = (EFI_IMAGE_DATA_DIRECTORY *)&(Hdr.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG]); + } + + if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_DEBUG || DirectoryEntry->VirtualAddress == 0) { + DirectoryEntry = NULL; + DebugEntry = NULL; + } else { + // + // Get the DebugEntry offset in the raw data image. + // + for (Index1 = 0; Index1 < Index; Index1 ++) { + if ((DirectoryEntry->VirtualAddress >= SectionHeader[Index1].VirtualAddress) && + (DirectoryEntry->VirtualAddress < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) { + DebugEntry = (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY *) ( + (UINTN) Pe32Data + + DirectoryEntry->VirtualAddress - + SectionHeader[Index1].VirtualAddress + + SectionHeader[Index1].PointerToRawData); + break; + } + } + } + } else { + return NULL; + } + + if (NULL == DebugEntry || NULL == DirectoryEntry) { + return NULL; + } + + // + // Scan the directory to find the debug entry. + // + for (DirCount = 0; DirCount < DirectoryEntry->Size; DirCount += sizeof (EFI_IMAGE_DEBUG_DIRECTORY_ENTRY), DebugEntry++) { + if (EFI_IMAGE_DEBUG_TYPE_CODEVIEW == DebugEntry->Type) { + if (DebugEntry->SizeOfData > 0) { + // + // Get the DebugEntry offset in the raw data image. + // + CodeViewEntryPointer = NULL; + for (Index1 = 0; Index1 < Index; Index1 ++) { + if ((DebugEntry->RVA >= SectionHeader[Index1].VirtualAddress) && + (DebugEntry->RVA < (SectionHeader[Index1].VirtualAddress + SectionHeader[Index1].Misc.VirtualSize))) { + CodeViewEntryPointer = (VOID *) ( + ((UINTN)Pe32Data) + + (UINTN) DebugEntry->RVA - + SectionHeader[Index1].VirtualAddress + + SectionHeader[Index1].PointerToRawData + + (UINTN)TEImageAdjust); + break; + } + } + if (Index1 >= Index) { + // + // Can't find CodeViewEntryPointer in raw PE/COFF image. + // + continue; + } + switch (* (UINT32 *) CodeViewEntryPointer) { + case CODEVIEW_SIGNATURE_NB10: + return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_NB10_ENTRY)); + case CODEVIEW_SIGNATURE_RSDS: + return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_RSDS_ENTRY)); + case CODEVIEW_SIGNATURE_MTOC: + return (VOID *) ((CHAR8 *)CodeViewEntryPointer + sizeof (EFI_IMAGE_DEBUG_CODEVIEW_MTOC_ENTRY)); + default: + break; + } + } + } + } + + return NULL; +} + + +RETURN_STATUS +EFIAPI +PeCoffLoaderGetEntryPoint ( + IN VOID *Pe32Data, + OUT VOID **EntryPoint, + OUT VOID **BaseOfImage + ) +{ + EFI_IMAGE_DOS_HEADER *DosHdr; + EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr; + + DosHdr = (EFI_IMAGE_DOS_HEADER *)Pe32Data; + if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) { + // + // DOS image header is present, so read the PE header after the DOS image header. + // + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)((UINTN) Pe32Data + (UINTN) ((DosHdr->e_lfanew) & 0x0ffff)); + } else { + // + // DOS image header is not present, so PE header is at the image base. + // + Hdr.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)Pe32Data; + } + + // + // Calculate the entry point relative to the start of the image. + // AddressOfEntryPoint is common for PE32 & PE32+ + // + if (Hdr.Te->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) { + *BaseOfImage = (VOID *)(UINTN)(Hdr.Te->ImageBase + Hdr.Te->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER)); + *EntryPoint = (VOID *)((UINTN)*BaseOfImage + (Hdr.Te->AddressOfEntryPoint & 0x0ffffffff) + sizeof(EFI_TE_IMAGE_HEADER) - Hdr.Te->StrippedSize); + return RETURN_SUCCESS; + } else if (Hdr.Pe32->Signature == EFI_IMAGE_NT_SIGNATURE) { + *EntryPoint = (VOID *)(UINTN)Hdr.Pe32->OptionalHeader.AddressOfEntryPoint; + if (Hdr.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + *BaseOfImage = (VOID *)(UINTN)Hdr.Pe32->OptionalHeader.ImageBase; + } else { + *BaseOfImage = (VOID *)(UINTN)Hdr.Pe32Plus->OptionalHeader.ImageBase; + } + *EntryPoint = (VOID *)(UINTN)((UINTN)*EntryPoint + (UINTN)*BaseOfImage); + return RETURN_SUCCESS; + } + + return RETURN_UNSUPPORTED; +} diff --git a/BaseTools/Source/C/Common/BinderFuncs.c b/BaseTools/Source/C/Common/BinderFuncs.c index de835287e9..507b70aa38 100644 --- a/BaseTools/Source/C/Common/BinderFuncs.c +++ b/BaseTools/Source/C/Common/BinderFuncs.c @@ -1,74 +1,74 @@ -/** @file
-Binder function implementations for ANSI C libraries.
-
-Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "BinderFuncs.h"
-#include "CommonLib.h"
-#include <stdlib.h>
-#include <string.h>
-
-//
-// Binder Function Implementations
-//
-
-VOID *
-CommonLibBinderAllocate (
- IN UINTN Size
- )
-{
- return (VOID *) malloc (Size);
-}
-
-VOID
-CommonLibBinderFree (
- IN VOID *Pointer
- )
-{
- free (Pointer);
-}
-
-VOID
-CommonLibBinderCopyMem (
- IN VOID *Destination,
- IN VOID *Source,
- IN UINTN Length
- )
-{
- memmove (Destination, Source, Length);
-}
-
-VOID
-CommonLibBinderSetMem (
- IN VOID *Destination,
- IN UINTN Length,
- IN UINT8 Value
- )
-{
- memset (Destination, Value, Length);
-}
-
-INTN
-CommonLibBinderCompareMem (
- IN VOID *MemOne,
- IN VOID *MemTwo,
- IN UINTN Length
- )
-{
- return memcmp (MemOne, MemTwo, Length);
-}
-
-BOOLEAN
-CommonLibBinderCompareGuid (
- IN EFI_GUID *Guid1,
- IN EFI_GUID *Guid2
- )
-{
- return CompareGuid (Guid1, Guid2) ? FALSE : TRUE;
-}
-
-
-
+/** @file +Binder function implementations for ANSI C libraries. + +Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "BinderFuncs.h" +#include "CommonLib.h" +#include <stdlib.h> +#include <string.h> + +// +// Binder Function Implementations +// + +VOID * +CommonLibBinderAllocate ( + IN UINTN Size + ) +{ + return (VOID *) malloc (Size); +} + +VOID +CommonLibBinderFree ( + IN VOID *Pointer + ) +{ + free (Pointer); +} + +VOID +CommonLibBinderCopyMem ( + IN VOID *Destination, + IN VOID *Source, + IN UINTN Length + ) +{ + memmove (Destination, Source, Length); +} + +VOID +CommonLibBinderSetMem ( + IN VOID *Destination, + IN UINTN Length, + IN UINT8 Value + ) +{ + memset (Destination, Value, Length); +} + +INTN +CommonLibBinderCompareMem ( + IN VOID *MemOne, + IN VOID *MemTwo, + IN UINTN Length + ) +{ + return memcmp (MemOne, MemTwo, Length); +} + +BOOLEAN +CommonLibBinderCompareGuid ( + IN EFI_GUID *Guid1, + IN EFI_GUID *Guid2 + ) +{ + return CompareGuid (Guid1, Guid2) ? FALSE : TRUE; +} + + + diff --git a/BaseTools/Source/C/Common/BinderFuncs.h b/BaseTools/Source/C/Common/BinderFuncs.h index ceaa9cd318..accd22d148 100644 --- a/BaseTools/Source/C/Common/BinderFuncs.h +++ b/BaseTools/Source/C/Common/BinderFuncs.h @@ -1,61 +1,61 @@ -/** @file
-Prototypes for binder functions that allow common code to be written which then
-links to implementation of these functions which is appropriate for the specific
-environment that they are running under.
-
-Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef BinderFuncs_h_INCLUDED
-#define BinderFuncs_h_INCLUDED
-
-#include "Common/UefiBaseTypes.h"
-
-//
-// Binder Function Prototypes
-//
-// These binding functions must be implemented externally as appropriate for
-// the environment that the code will be running under.
-//
-
-VOID *
-CommonLibBinderAllocate (
- IN UINTN Size
- );
-
-VOID
-CommonLibBinderFree (
- IN VOID *Pointer
- );
-
-VOID
-CommonLibBinderCopyMem (
- IN VOID *Destination,
- IN VOID *Source,
- IN UINTN Length
- );
-
-VOID
-CommonLibBinderSetMem (
- IN VOID *Destination,
- IN UINTN Length,
- IN UINT8 Value
- );
-
-INTN
-CommonLibBinderCompareMem (
- IN VOID *MemOne,
- IN VOID *MemTwo,
- IN UINTN Length
- );
-
-BOOLEAN
-CommonLibBinderCompareGuid (
- IN EFI_GUID *Guid1,
- IN EFI_GUID *Guid2
- );
-
-#endif // #ifndef CommonLibs_h_INCLUDED
-
+/** @file +Prototypes for binder functions that allow common code to be written which then +links to implementation of these functions which is appropriate for the specific +environment that they are running under. + +Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef BinderFuncs_h_INCLUDED +#define BinderFuncs_h_INCLUDED + +#include "Common/UefiBaseTypes.h" + +// +// Binder Function Prototypes +// +// These binding functions must be implemented externally as appropriate for +// the environment that the code will be running under. +// + +VOID * +CommonLibBinderAllocate ( + IN UINTN Size + ); + +VOID +CommonLibBinderFree ( + IN VOID *Pointer + ); + +VOID +CommonLibBinderCopyMem ( + IN VOID *Destination, + IN VOID *Source, + IN UINTN Length + ); + +VOID +CommonLibBinderSetMem ( + IN VOID *Destination, + IN UINTN Length, + IN UINT8 Value + ); + +INTN +CommonLibBinderCompareMem ( + IN VOID *MemOne, + IN VOID *MemTwo, + IN UINTN Length + ); + +BOOLEAN +CommonLibBinderCompareGuid ( + IN EFI_GUID *Guid1, + IN EFI_GUID *Guid2 + ); + +#endif // #ifndef CommonLibs_h_INCLUDED + diff --git a/BaseTools/Source/C/Common/CommonLib.c b/BaseTools/Source/C/Common/CommonLib.c index b2cde6d481..e224cd014b 100644 --- a/BaseTools/Source/C/Common/CommonLib.c +++ b/BaseTools/Source/C/Common/CommonLib.c @@ -1,2090 +1,2090 @@ -/** @file
-Common basic Library Functions
-
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#ifdef __GNUC__
-#include <unistd.h>
-#else
-#include <direct.h>
-#endif
-#include "CommonLib.h"
-#include "EfiUtilityMsgs.h"
-
-#define SAFE_STRING_CONSTRAINT_CHECK(Expression, Status) \
- do { \
- ASSERT (Expression); \
- if (!(Expression)) { \
- return Status; \
- } \
- } while (FALSE)
-
-/**
- Set Buffer to zero for Size bytes.
-
- @param Buffer Memory to set.
- @param Size Number of bytes to set
-**/
-VOID
-PeiZeroMem (
- IN VOID *Buffer,
- IN UINTN Size
- )
-{
- INT8 *Ptr;
-
- Ptr = Buffer;
- while (Size--) {
- *(Ptr++) = 0;
- }
-}
-
-/**
- Copy Length bytes from Source to Destination.
-
- @param Destination Target of copy
- @param Source Place to copy from
- @param Length Number of bytes to copy
-**/
-VOID
-PeiCopyMem (
- IN VOID *Destination,
- IN VOID *Source,
- IN UINTN Length
- )
-{
- CHAR8 *Destination8;
- CHAR8 *Source8;
-
- Destination8 = Destination;
- Source8 = Source;
- while (Length--) {
- *(Destination8++) = *(Source8++);
- }
-}
-
-VOID
-ZeroMem (
- IN VOID *Buffer,
- IN UINTN Size
- )
-{
- PeiZeroMem (Buffer, Size);
-}
-
-VOID
-CopyMem (
- IN VOID *Destination,
- IN VOID *Source,
- IN UINTN Length
- )
-{
- PeiCopyMem (Destination, Source, Length);
-}
-
-/**
- Compares to GUIDs
-
- @param Guid1 guid to compare
- @param Guid2 guid to compare
-
- @retval = 0 if Guid1 == Guid2
- @retval != 0 if Guid1 != Guid2
-**/
-INTN
-CompareGuid (
- IN EFI_GUID *Guid1,
- IN EFI_GUID *Guid2
- )
-{
- INT32 *g1;
- INT32 *g2;
- INT32 r;
-
- //
- // Compare 32 bits at a time
- //
- g1 = (INT32 *) Guid1;
- g2 = (INT32 *) Guid2;
-
- r = g1[0] - g2[0];
- r |= g1[1] - g2[1];
- r |= g1[2] - g2[2];
- r |= g1[3] - g2[3];
-
- return r;
-}
-
-/**
- This function opens a file and reads it into a memory buffer. The function
- will allocate the memory buffer and returns the size of the buffer.
-
- @param InputFileName The name of the file to read.
- @param InputFileImage A pointer to the memory buffer.
- @param BytesRead The size of the memory buffer.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_INVALID_PARAMETER One of the input parameters was invalid.
- @retval EFI_ABORTED An error occurred.
- @retval EFI_OUT_OF_RESOURCES No resource to complete operations.
-**/
-EFI_STATUS
-GetFileImage (
- IN CHAR8 *InputFileName,
- OUT CHAR8 **InputFileImage,
- OUT UINT32 *BytesRead
- )
-{
- FILE *InputFile;
- UINT32 FileSize;
-
- //
- // Verify input parameters.
- //
- if (InputFileName == NULL || strlen (InputFileName) == 0 || InputFileImage == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Open the file and copy contents into a memory buffer.
- //
- //
- // Open the file
- //
- InputFile = fopen (LongFilePath (InputFileName), "rb");
- if (InputFile == NULL) {
- Error (NULL, 0, 0001, "Error opening the input file", InputFileName);
- return EFI_ABORTED;
- }
- //
- // Go to the end so that we can determine the file size
- //
- if (fseek (InputFile, 0, SEEK_END)) {
- Error (NULL, 0, 0004, "Error reading the input file", InputFileName);
- fclose (InputFile);
- return EFI_ABORTED;
- }
- //
- // Get the file size
- //
- FileSize = ftell (InputFile);
- if (FileSize == -1) {
- Error (NULL, 0, 0003, "Error parsing the input file", InputFileName);
- fclose (InputFile);
- return EFI_ABORTED;
- }
- //
- // Allocate a buffer
- //
- *InputFileImage = malloc (FileSize);
- if (*InputFileImage == NULL) {
- fclose (InputFile);
- return EFI_OUT_OF_RESOURCES;
- }
- //
- // Reset to the beginning of the file
- //
- if (fseek (InputFile, 0, SEEK_SET)) {
- Error (NULL, 0, 0004, "Error reading the input file", InputFileName);
- fclose (InputFile);
- free (*InputFileImage);
- *InputFileImage = NULL;
- return EFI_ABORTED;
- }
- //
- // Read all of the file contents.
- //
- *BytesRead = fread (*InputFileImage, sizeof (UINT8), FileSize, InputFile);
- if (*BytesRead != sizeof (UINT8) * FileSize) {
- Error (NULL, 0, 0004, "Error reading the input file", InputFileName);
- fclose (InputFile);
- free (*InputFileImage);
- *InputFileImage = NULL;
- return EFI_ABORTED;
- }
- //
- // Close the file
- //
- fclose (InputFile);
-
- return EFI_SUCCESS;
-}
-
-/**
- This function opens a file and writes OutputFileImage into the file.
-
- @param OutputFileName The name of the file to write.
- @param OutputFileImage A pointer to the memory buffer.
- @param BytesToWrite The size of the memory buffer.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_INVALID_PARAMETER One of the input parameters was invalid.
- @retval EFI_ABORTED An error occurred.
- @retval EFI_OUT_OF_RESOURCES No resource to complete operations.
-**/
-EFI_STATUS
-PutFileImage (
- IN CHAR8 *OutputFileName,
- IN CHAR8 *OutputFileImage,
- IN UINT32 BytesToWrite
- )
-{
- FILE *OutputFile;
- UINT32 BytesWrote;
-
- //
- // Verify input parameters.
- //
- if (OutputFileName == NULL || strlen (OutputFileName) == 0 || OutputFileImage == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Open the file and copy contents into a memory buffer.
- //
- //
- // Open the file
- //
- OutputFile = fopen (LongFilePath (OutputFileName), "wb");
- if (OutputFile == NULL) {
- Error (NULL, 0, 0001, "Error opening the output file", OutputFileName);
- return EFI_ABORTED;
- }
-
- //
- // Write all of the file contents.
- //
- BytesWrote = fwrite (OutputFileImage, sizeof (UINT8), BytesToWrite, OutputFile);
- if (BytesWrote != sizeof (UINT8) * BytesToWrite) {
- Error (NULL, 0, 0002, "Error writing the output file", OutputFileName);
- fclose (OutputFile);
- return EFI_ABORTED;
- }
- //
- // Close the file
- //
- fclose (OutputFile);
-
- return EFI_SUCCESS;
-}
-
-/**
- This function calculates the value needed for a valid UINT8 checksum
-
- @param Buffer Pointer to buffer containing byte data of component.
- @param Size Size of the buffer
-
- @return The 8 bit checksum value needed.
-**/
-UINT8
-CalculateChecksum8 (
- IN UINT8 *Buffer,
- IN UINTN Size
- )
-{
- return (UINT8) (0x100 - CalculateSum8 (Buffer, Size));
-}
-
-/**
- This function calculates the UINT8 sum for the requested region.
-
- @param Buffer Pointer to buffer containing byte data of component.
- @param Size Size of the buffer
-
- @return The 8 bit checksum value needed.
-**/
-UINT8
-CalculateSum8 (
- IN UINT8 *Buffer,
- IN UINTN Size
- )
-{
- UINTN Index;
- UINT8 Sum;
-
- Sum = 0;
-
- //
- // Perform the byte sum for buffer
- //
- for (Index = 0; Index < Size; Index++) {
- Sum = (UINT8) (Sum + Buffer[Index]);
- }
-
- return Sum;
-}
-
-/**
- This function calculates the value needed for a valid UINT16 checksum
-
- @param Buffer Pointer to buffer containing byte data of component.
- @param Size Size of the buffer
-
- @return The 16 bit checksum value needed.
-**/
-UINT16
-CalculateChecksum16 (
- IN UINT16 *Buffer,
- IN UINTN Size
- )
-{
- return (UINT16) (0x10000 - CalculateSum16 (Buffer, Size));
-}
-
-/**
- This function calculates the UINT16 sum for the requested region.
-
- @param Buffer Pointer to buffer containing byte data of component.
- @param Size Size of the buffer
-
- @return The 16 bit checksum
-**/
-UINT16
-CalculateSum16 (
- IN UINT16 *Buffer,
- IN UINTN Size
- )
-{
- UINTN Index;
- UINT16 Sum;
-
- Sum = 0;
-
- //
- // Perform the word sum for buffer
- //
- for (Index = 0; Index < Size; Index++) {
- Sum = (UINT16) (Sum + Buffer[Index]);
- }
-
- return (UINT16) Sum;
-}
-
-/**
- This function prints a GUID to STDOUT.
-
- @param Guid Pointer to a GUID to print.
-
- @retval EFI_SUCCESS The GUID was printed.
- @retval EFI_INVALID_PARAMETER The input was NULL.
-**/
-EFI_STATUS
-PrintGuid (
- IN EFI_GUID *Guid
- )
-{
- if (Guid == NULL) {
- Error (NULL, 0, 2000, "Invalid parameter", "PrintGuidToBuffer() called with a NULL value");
- return EFI_INVALID_PARAMETER;
- }
-
- printf (
- "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
- (unsigned) Guid->Data1,
- Guid->Data2,
- Guid->Data3,
- Guid->Data4[0],
- Guid->Data4[1],
- Guid->Data4[2],
- Guid->Data4[3],
- Guid->Data4[4],
- Guid->Data4[5],
- Guid->Data4[6],
- Guid->Data4[7]
- );
- return EFI_SUCCESS;
-}
-
-/**
- This function prints a GUID to a buffer
-
- @param Guid Pointer to a GUID to print.
- @param Buffer Pointer to a user-provided buffer to print to
- @param BufferLen Size of the Buffer
- @param Uppercase If use upper case.
-
- @retval EFI_SUCCESS The GUID was printed.
- @retval EFI_INVALID_PARAMETER The input was NULL.
- @retval EFI_BUFFER_TOO_SMALL The input buffer was not big enough
-**/
-EFI_STATUS
-PrintGuidToBuffer (
- IN EFI_GUID *Guid,
- IN OUT UINT8 *Buffer,
- IN UINT32 BufferLen,
- IN BOOLEAN Uppercase
- )
-{
- if (Guid == NULL) {
- Error (NULL, 0, 2000, "Invalid parameter", "PrintGuidToBuffer() called with a NULL value");
- return EFI_INVALID_PARAMETER;
- }
-
- if (BufferLen < PRINTED_GUID_BUFFER_SIZE) {
- Error (NULL, 0, 2000, "Invalid parameter", "PrintGuidToBuffer() called with invalid buffer size");
- return EFI_BUFFER_TOO_SMALL;
- }
-
- if (Uppercase) {
- sprintf (
- (CHAR8 *)Buffer,
- "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
- (unsigned) Guid->Data1,
- Guid->Data2,
- Guid->Data3,
- Guid->Data4[0],
- Guid->Data4[1],
- Guid->Data4[2],
- Guid->Data4[3],
- Guid->Data4[4],
- Guid->Data4[5],
- Guid->Data4[6],
- Guid->Data4[7]
- );
- } else {
- sprintf (
- (CHAR8 *)Buffer,
- "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
- (unsigned) Guid->Data1,
- Guid->Data2,
- Guid->Data3,
- Guid->Data4[0],
- Guid->Data4[1],
- Guid->Data4[2],
- Guid->Data4[3],
- Guid->Data4[4],
- Guid->Data4[5],
- Guid->Data4[6],
- Guid->Data4[7]
- );
- }
-
- return EFI_SUCCESS;
-}
-
-#ifdef __GNUC__
-
-size_t _filelength(int fd)
-{
- struct stat stat_buf;
- fstat(fd, &stat_buf);
- return stat_buf.st_size;
-}
-
-#ifndef __CYGWIN__
-char *strlwr(char *s)
-{
- char *p = s;
- for(;*s;s++) {
- *s = tolower(*s);
- }
- return p;
-}
-#endif
-#endif
-
-#define WINDOWS_EXTENSION_PATH "\\\\?\\"
-#define WINDOWS_UNC_EXTENSION_PATH "\\\\?\\UNC"
-
-//
-// Global data to store full file path. It is not required to be free.
-//
-CHAR8 mCommonLibFullPath[MAX_LONG_FILE_PATH];
-
-/**
- Convert FileName to the long file path, which can support larger than 260 length.
-
- @param FileName FileName.
-
- @return LongFilePath A pointer to the converted long file path.
-**/
-CHAR8 *
-LongFilePath (
- IN CHAR8 *FileName
- )
-{
-#ifdef __GNUC__
- //
- // __GNUC__ may not be good way to differentiate unix and windows. Need more investigation here.
- // unix has no limitation on file path. Just return FileName.
- //
- return FileName;
-#else
- CHAR8 *RootPath;
- CHAR8 *PathPointer;
- CHAR8 *NextPointer;
-
- PathPointer = (CHAR8 *) FileName;
-
- if (FileName != NULL) {
- //
- // Add the extension string first to support long file path.
- //
- mCommonLibFullPath[0] = 0;
- strcpy (mCommonLibFullPath, WINDOWS_EXTENSION_PATH);
-
- if (strlen (FileName) > 1 && FileName[0] == '\\' && FileName[1] == '\\') {
- //
- // network path like \\server\share to \\?\UNC\server\share
- //
- strcpy (mCommonLibFullPath, WINDOWS_UNC_EXTENSION_PATH);
- FileName ++;
- } else if (strlen (FileName) < 3 || FileName[1] != ':' || (FileName[2] != '\\' && FileName[2] != '/')) {
- //
- // Relative file path. Convert it to absolute path.
- //
- RootPath = getcwd (NULL, 0);
- if (RootPath != NULL) {
- if (strlen (mCommonLibFullPath) + strlen (RootPath) > MAX_LONG_FILE_PATH - 1) {
- Error (NULL, 0, 2000, "Invalid parameter", "RootPath is too long!");
- free (RootPath);
- return NULL;
- }
- strncat (mCommonLibFullPath, RootPath, MAX_LONG_FILE_PATH - strlen (mCommonLibFullPath) - 1);
- if (FileName[0] != '\\' && FileName[0] != '/') {
- if (strlen (mCommonLibFullPath) + 1 > MAX_LONG_FILE_PATH - 1) {
- Error (NULL, 0, 2000, "Invalid parameter", "RootPath is too long!");
- free (RootPath);
- return NULL;
- }
- //
- // Attach directory separator
- //
- strncat (mCommonLibFullPath, "\\", MAX_LONG_FILE_PATH - strlen (mCommonLibFullPath) - 1);
- }
- free (RootPath);
- }
- }
-
- //
- // Construct the full file path
- //
- if (strlen (mCommonLibFullPath) + strlen (FileName) > MAX_LONG_FILE_PATH - 1) {
- Error (NULL, 0, 2000, "Invalid parameter", "FileName %s is too long!", FileName);
- return NULL;
- }
- strncat (mCommonLibFullPath, FileName, MAX_LONG_FILE_PATH - strlen (mCommonLibFullPath) - 1);
-
- //
- // Convert directory separator '/' to '\\'
- //
- PathPointer = (CHAR8 *) mCommonLibFullPath;
- do {
- if (*PathPointer == '/') {
- *PathPointer = '\\';
- }
- } while (*PathPointer ++ != '\0');
-
- //
- // Convert ":\\\\" to ":\\", because it doesn't work with WINDOWS_EXTENSION_PATH.
- //
- if ((PathPointer = strstr (mCommonLibFullPath, ":\\\\")) != NULL) {
- *(PathPointer + 2) = '\0';
- strncat (mCommonLibFullPath, PathPointer + 3, MAX_LONG_FILE_PATH - strlen (mCommonLibFullPath) - 1);
- }
-
- //
- // Convert ".\\" to "", because it doesn't work with WINDOWS_EXTENSION_PATH.
- //
- while ((PathPointer = strstr (mCommonLibFullPath, ".\\")) != NULL) {
- *PathPointer = '\0';
- strncat (mCommonLibFullPath, PathPointer + 2, MAX_LONG_FILE_PATH - strlen (mCommonLibFullPath) - 1);
- }
-
- //
- // Convert "\\.\\" to "\\", because it doesn't work with WINDOWS_EXTENSION_PATH.
- //
- while ((PathPointer = strstr (mCommonLibFullPath, "\\.\\")) != NULL) {
- *PathPointer = '\0';
- strncat (mCommonLibFullPath, PathPointer + 2, MAX_LONG_FILE_PATH - strlen (mCommonLibFullPath) - 1);
- }
-
- //
- // Convert "\\..\\" to last directory, because it doesn't work with WINDOWS_EXTENSION_PATH.
- //
- while ((PathPointer = strstr (mCommonLibFullPath, "\\..\\")) != NULL) {
- NextPointer = PathPointer + 3;
- do {
- PathPointer --;
- } while (PathPointer > mCommonLibFullPath && *PathPointer != ':' && *PathPointer != '\\');
-
- if (*PathPointer == '\\') {
- //
- // Skip one directory
- //
- *PathPointer = '\0';
- strncat (mCommonLibFullPath, NextPointer, MAX_LONG_FILE_PATH - strlen (mCommonLibFullPath) - 1);
- } else {
- //
- // No directory is found. Just break.
- //
- break;
- }
- }
-
- PathPointer = mCommonLibFullPath;
- }
-
- return PathPointer;
-#endif
-}
-
-CHAR16
-InternalCharToUpper (
- CHAR16 Char
- )
-{
- if (Char >= L'a' && Char <= L'z') {
- return (CHAR16) (Char - (L'a' - L'A'));
- }
-
- return Char;
-}
-
-UINTN
-StrnLenS (
- CONST CHAR16 *String,
- UINTN MaxSize
- )
-{
- UINTN Length;
-
- ASSERT (((UINTN) String & BIT0) == 0);
-
- //
- // If String is a null pointer or MaxSize is 0, then the StrnLenS function returns zero.
- //
- if ((String == NULL) || (MaxSize == 0)) {
- return 0;
- }
-
- Length = 0;
- while (String[Length] != 0) {
- if (Length >= MaxSize - 1) {
- return MaxSize;
- }
- Length++;
- }
- return Length;
-}
-
-
-VOID *
-InternalAllocatePool (
- UINTN AllocationSize
- )
-{
- VOID * Memory;
-
- Memory = malloc(AllocationSize);
- ASSERT(Memory != NULL);
- return Memory;
-}
-
-
-VOID *
-InternalReallocatePool (
- UINTN OldSize,
- UINTN NewSize,
- VOID *OldBuffer OPTIONAL
- )
-{
- VOID *NewBuffer;
-
- NewBuffer = AllocateZeroPool (NewSize);
- if (NewBuffer != NULL && OldBuffer != NULL) {
- memcpy (NewBuffer, OldBuffer, MIN (OldSize, NewSize));
- free(OldBuffer);
- }
- return NewBuffer;
-}
-
-VOID *
-ReallocatePool (
- UINTN OldSize,
- UINTN NewSize,
- VOID *OldBuffer OPTIONAL
- )
-{
- return InternalReallocatePool (OldSize, NewSize, OldBuffer);
-}
-
-/**
- Returns the length of a Null-terminated Unicode string.
-
- This function returns the number of Unicode characters in the Null-terminated
- Unicode string specified by String.
-
- If String is NULL, then ASSERT().
- If String is not aligned on a 16-bit boundary, then ASSERT().
- If PcdMaximumUnicodeStringLength is not zero, and String contains more than
- PcdMaximumUnicodeStringLength Unicode characters, not including the
- Null-terminator, then ASSERT().
-
- @param String A pointer to a Null-terminated Unicode string.
-
- @return The length of String.
-
-**/
-UINTN
-StrLen (
- CONST CHAR16 *String
- )
-{
- UINTN Length;
-
- ASSERT (String != NULL);
- ASSERT (((UINTN) String & BIT0) == 0);
-
- for (Length = 0; *String != L'\0'; String++, Length++) {
- //
- // If PcdMaximumUnicodeStringLength is not zero,
- // length should not more than PcdMaximumUnicodeStringLength
- //
- }
- return Length;
-}
-
-BOOLEAN
-InternalSafeStringIsOverlap (
- IN VOID *Base1,
- IN UINTN Size1,
- IN VOID *Base2,
- IN UINTN Size2
- )
-{
- if ((((UINTN)Base1 >= (UINTN)Base2) && ((UINTN)Base1 < (UINTN)Base2 + Size2)) ||
- (((UINTN)Base2 >= (UINTN)Base1) && ((UINTN)Base2 < (UINTN)Base1 + Size1))) {
- return TRUE;
- }
- return FALSE;
-}
-
-BOOLEAN
-InternalSafeStringNoStrOverlap (
- IN CHAR16 *Str1,
- IN UINTN Size1,
- IN CHAR16 *Str2,
- IN UINTN Size2
- )
-{
- return !InternalSafeStringIsOverlap (Str1, Size1 * sizeof(CHAR16), Str2, Size2 * sizeof(CHAR16));
-}
-
-/**
- Convert a Null-terminated Unicode decimal string to a value of type UINT64.
-
- This function outputs a value of type UINT64 by interpreting the contents of
- the Unicode string specified by String as a decimal number. The format of the
- input Unicode string String is:
-
- [spaces] [decimal digits].
-
- The valid decimal digit character is in the range [0-9]. The function will
- ignore the pad space, which includes spaces or tab characters, before
- [decimal digits]. The running zero in the beginning of [decimal digits] will
- be ignored. Then, the function stops at the first character that is a not a
- valid decimal character or a Null-terminator, whichever one comes first.
-
- If String is NULL, then ASSERT().
- If Data is NULL, then ASSERT().
- If String is not aligned in a 16-bit boundary, then ASSERT().
- If PcdMaximumUnicodeStringLength is not zero, and String contains more than
- PcdMaximumUnicodeStringLength Unicode characters, not including the
- Null-terminator, then ASSERT().
-
- If String has no valid decimal digits in the above format, then 0 is stored
- at the location pointed to by Data.
- If the number represented by String exceeds the range defined by UINT64, then
- MAX_UINT64 is stored at the location pointed to by Data.
-
- If EndPointer is not NULL, a pointer to the character that stopped the scan
- is stored at the location pointed to by EndPointer. If String has no valid
- decimal digits right after the optional pad spaces, the value of String is
- stored at the location pointed to by EndPointer.
-
- @param String Pointer to a Null-terminated Unicode string.
- @param EndPointer Pointer to character that stops scan.
- @param Data Pointer to the converted value.
-
- @retval RETURN_SUCCESS Value is translated from String.
- @retval RETURN_INVALID_PARAMETER If String is NULL.
- If Data is NULL.
- If PcdMaximumUnicodeStringLength is not
- zero, and String contains more than
- PcdMaximumUnicodeStringLength Unicode
- characters, not including the
- Null-terminator.
- @retval RETURN_UNSUPPORTED If the number represented by String exceeds
- the range defined by UINT64.
-
-**/
-RETURN_STATUS
-StrDecimalToUint64S (
- CONST CHAR16 *String,
- CHAR16 **EndPointer, OPTIONAL
- UINT64 *Data
- )
-{
- ASSERT (((UINTN) String & BIT0) == 0);
-
- //
- // 1. Neither String nor Data shall be a null pointer.
- //
- SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER);
- SAFE_STRING_CONSTRAINT_CHECK ((Data != NULL), RETURN_INVALID_PARAMETER);
-
- //
- // 2. The length of String shall not be greater than RSIZE_MAX.
- //
- if (RSIZE_MAX != 0) {
- SAFE_STRING_CONSTRAINT_CHECK ((StrnLenS (String, RSIZE_MAX + 1) <= RSIZE_MAX), RETURN_INVALID_PARAMETER);
- }
-
- if (EndPointer != NULL) {
- *EndPointer = (CHAR16 *) String;
- }
-
- //
- // Ignore the pad spaces (space or tab)
- //
- while ((*String == L' ') || (*String == L'\t')) {
- String++;
- }
-
- //
- // Ignore leading Zeros after the spaces
- //
- while (*String == L'0') {
- String++;
- }
-
- *Data = 0;
-
- while (InternalIsDecimalDigitCharacter (*String)) {
- //
- // If the number represented by String overflows according to the range
- // defined by UINT64, then MAX_UINT64 is stored in *Data and
- // RETURN_UNSUPPORTED is returned.
- //
- if (*Data > ((MAX_UINT64 - (*String - L'0'))/10)) {
- *Data = MAX_UINT64;
- if (EndPointer != NULL) {
- *EndPointer = (CHAR16 *) String;
- }
- return RETURN_UNSUPPORTED;
- }
-
- *Data = (*Data) * 10 + (*String - L'0');
- String++;
- }
-
- if (EndPointer != NULL) {
- *EndPointer = (CHAR16 *) String;
- }
- return RETURN_SUCCESS;
-}
-
-/**
- Convert a Null-terminated Unicode hexadecimal string to a value of type
- UINT64.
-
- This function outputs a value of type UINT64 by interpreting the contents of
- the Unicode string specified by String as a hexadecimal number. The format of
- the input Unicode string String is:
-
- [spaces][zeros][x][hexadecimal digits].
-
- The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F].
- The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix.
- If "x" appears in the input string, it must be prefixed with at least one 0.
- The function will ignore the pad space, which includes spaces or tab
- characters, before [zeros], [x] or [hexadecimal digit]. The running zero
- before [x] or [hexadecimal digit] will be ignored. Then, the decoding starts
- after [x] or the first valid hexadecimal digit. Then, the function stops at
- the first character that is a not a valid hexadecimal character or NULL,
- whichever one comes first.
-
- If String is NULL, then ASSERT().
- If Data is NULL, then ASSERT().
- If String is not aligned in a 16-bit boundary, then ASSERT().
- If PcdMaximumUnicodeStringLength is not zero, and String contains more than
- PcdMaximumUnicodeStringLength Unicode characters, not including the
- Null-terminator, then ASSERT().
-
- If String has no valid hexadecimal digits in the above format, then 0 is
- stored at the location pointed to by Data.
- If the number represented by String exceeds the range defined by UINT64, then
- MAX_UINT64 is stored at the location pointed to by Data.
-
- If EndPointer is not NULL, a pointer to the character that stopped the scan
- is stored at the location pointed to by EndPointer. If String has no valid
- hexadecimal digits right after the optional pad spaces, the value of String
- is stored at the location pointed to by EndPointer.
-
- @param String Pointer to a Null-terminated Unicode string.
- @param EndPointer Pointer to character that stops scan.
- @param Data Pointer to the converted value.
-
- @retval RETURN_SUCCESS Value is translated from String.
- @retval RETURN_INVALID_PARAMETER If String is NULL.
- If Data is NULL.
- If PcdMaximumUnicodeStringLength is not
- zero, and String contains more than
- PcdMaximumUnicodeStringLength Unicode
- characters, not including the
- Null-terminator.
- @retval RETURN_UNSUPPORTED If the number represented by String exceeds
- the range defined by UINT64.
-
-**/
-RETURN_STATUS
-StrHexToUint64S (
- CONST CHAR16 *String,
- CHAR16 **EndPointer, OPTIONAL
- UINT64 *Data
- )
-{
- ASSERT (((UINTN) String & BIT0) == 0);
-
- //
- // 1. Neither String nor Data shall be a null pointer.
- //
- SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER);
- SAFE_STRING_CONSTRAINT_CHECK ((Data != NULL), RETURN_INVALID_PARAMETER);
-
- //
- // 2. The length of String shall not be greater than RSIZE_MAX.
- //
- if (RSIZE_MAX != 0) {
- SAFE_STRING_CONSTRAINT_CHECK ((StrnLenS (String, RSIZE_MAX + 1) <= RSIZE_MAX), RETURN_INVALID_PARAMETER);
- }
-
- if (EndPointer != NULL) {
- *EndPointer = (CHAR16 *) String;
- }
-
- //
- // Ignore the pad spaces (space or tab)
- //
- while ((*String == L' ') || (*String == L'\t')) {
- String++;
- }
-
- //
- // Ignore leading Zeros after the spaces
- //
- while (*String == L'0') {
- String++;
- }
-
- if (InternalCharToUpper (*String) == L'X') {
- if (*(String - 1) != L'0') {
- *Data = 0;
- return RETURN_SUCCESS;
- }
- //
- // Skip the 'X'
- //
- String++;
- }
-
- *Data = 0;
-
- while (InternalIsHexaDecimalDigitCharacter (*String)) {
- //
- // If the number represented by String overflows according to the range
- // defined by UINT64, then MAX_UINT64 is stored in *Data and
- // RETURN_UNSUPPORTED is returned.
- //
- if (*Data > ((MAX_UINT64 - InternalHexCharToUintn (*String))>>4)) {
- *Data = MAX_UINT64;
- if (EndPointer != NULL) {
- *EndPointer = (CHAR16 *) String;
- }
- return RETURN_UNSUPPORTED;
- }
-
- *Data = ((*Data) << 4) + InternalHexCharToUintn (*String);
- String++;
- }
-
- if (EndPointer != NULL) {
- *EndPointer = (CHAR16 *) String;
- }
- return RETURN_SUCCESS;
-}
-
-UINT64
-StrDecimalToUint64 (
- CONST CHAR16 *String
- )
-{
- UINT64 Result;
-
- StrDecimalToUint64S (String, (CHAR16 **) NULL, &Result);
- return Result;
-}
-
-
-UINT64
-StrHexToUint64 (
- CONST CHAR16 *String
- )
-{
- UINT64 Result;
-
- StrHexToUint64S (String, (CHAR16 **) NULL, &Result);
- return Result;
-}
-
-UINTN
-StrSize (
- CONST CHAR16 *String
- )
-{
- return (StrLen (String) + 1) * sizeof (*String);
-}
-
-
-UINT64
-ReadUnaligned64 (
- CONST UINT64 *Buffer
- )
-{
- ASSERT (Buffer != NULL);
-
- return *Buffer;
-}
-
-UINT64
-WriteUnaligned64 (
- UINT64 *Buffer,
- UINT64 Value
- )
-{
- ASSERT (Buffer != NULL);
-
- return *Buffer = Value;
-}
-
-
-EFI_GUID *
-CopyGuid (
- EFI_GUID *DestinationGuid,
- CONST EFI_GUID *SourceGuid
- )
-{
- WriteUnaligned64 (
- (UINT64*)DestinationGuid,
- ReadUnaligned64 ((CONST UINT64*)SourceGuid)
- );
- WriteUnaligned64 (
- (UINT64*)DestinationGuid + 1,
- ReadUnaligned64 ((CONST UINT64*)SourceGuid + 1)
- );
- return DestinationGuid;
-}
-
-UINT16
-SwapBytes16 (
- UINT16 Value
- )
-{
- return (UINT16) ((Value<< 8) | (Value>> 8));
-}
-
-
-UINT32
-SwapBytes32 (
- UINT32 Value
- )
-{
- UINT32 LowerBytes;
- UINT32 HigherBytes;
-
- LowerBytes = (UINT32) SwapBytes16 ((UINT16) Value);
- HigherBytes = (UINT32) SwapBytes16 ((UINT16) (Value >> 16));
- return (LowerBytes << 16 | HigherBytes);
-}
-
-BOOLEAN
-InternalIsDecimalDigitCharacter (
- CHAR16 Char
- )
-{
- return (BOOLEAN) (Char >= L'0' && Char <= L'9');
-}
-
-VOID *
-InternalAllocateCopyPool (
- UINTN AllocationSize,
- CONST VOID *Buffer
- )
-{
- VOID *Memory;
-
- ASSERT (Buffer != NULL);
-
- Memory = malloc (AllocationSize);
- if (Memory != NULL) {
- Memory = memcpy (Memory, Buffer, AllocationSize);
- }
- return Memory;
-}
-
-BOOLEAN
-InternalIsHexaDecimalDigitCharacter (
- CHAR16 Char
- )
-{
-
- return (BOOLEAN) (InternalIsDecimalDigitCharacter (Char) ||
- (Char >= L'A' && Char <= L'F') ||
- (Char >= L'a' && Char <= L'f'));
-}
-
-UINTN
-InternalHexCharToUintn (
- CHAR16 Char
- )
-{
- if (InternalIsDecimalDigitCharacter (Char)) {
- return Char - L'0';
- }
-
- return (10 + InternalCharToUpper (Char) - L'A');
-}
-
-
-/**
- Convert a Null-terminated Unicode hexadecimal string to a byte array.
-
- This function outputs a byte array by interpreting the contents of
- the Unicode string specified by String in hexadecimal format. The format of
- the input Unicode string String is:
-
- [XX]*
-
- X is a hexadecimal digit character in the range [0-9], [a-f] and [A-F].
- The function decodes every two hexadecimal digit characters as one byte. The
- decoding stops after Length of characters and outputs Buffer containing
- (Length / 2) bytes.
-
- If String is not aligned in a 16-bit boundary, then ASSERT().
-
- If String is NULL, then ASSERT().
-
- If Buffer is NULL, then ASSERT().
-
- If Length is not multiple of 2, then ASSERT().
-
- If PcdMaximumUnicodeStringLength is not zero and Length is greater than
- PcdMaximumUnicodeStringLength, then ASSERT().
-
- If MaxBufferSize is less than (Length / 2), then ASSERT().
-
- @param String Pointer to a Null-terminated Unicode string.
- @param Length The number of Unicode characters to decode.
- @param Buffer Pointer to the converted bytes array.
- @param MaxBufferSize The maximum size of Buffer.
-
- @retval RETURN_SUCCESS Buffer is translated from String.
- @retval RETURN_INVALID_PARAMETER If String is NULL.
- If Data is NULL.
- If Length is not multiple of 2.
- If PcdMaximumUnicodeStringLength is not zero,
- and Length is greater than
- PcdMaximumUnicodeStringLength.
- @retval RETURN_UNSUPPORTED If Length of characters from String contain
- a character that is not valid hexadecimal
- digit characters, or a Null-terminator.
- @retval RETURN_BUFFER_TOO_SMALL If MaxBufferSize is less than (Length / 2).
-**/
-RETURN_STATUS
-StrHexToBytes (
- CONST CHAR16 *String,
- UINTN Length,
- UINT8 *Buffer,
- UINTN MaxBufferSize
- )
-{
- UINTN Index;
-
- ASSERT (((UINTN) String & BIT0) == 0);
-
- //
- // 1. None of String or Buffer shall be a null pointer.
- //
- SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER);
- SAFE_STRING_CONSTRAINT_CHECK ((Buffer != NULL), RETURN_INVALID_PARAMETER);
-
- //
- // 2. Length shall not be greater than RSIZE_MAX.
- //
- if (RSIZE_MAX != 0) {
- SAFE_STRING_CONSTRAINT_CHECK ((Length <= RSIZE_MAX), RETURN_INVALID_PARAMETER);
- }
-
- //
- // 3. Length shall not be odd.
- //
- SAFE_STRING_CONSTRAINT_CHECK (((Length & BIT0) == 0), RETURN_INVALID_PARAMETER);
-
- //
- // 4. MaxBufferSize shall equal to or greater than Length / 2.
- //
- SAFE_STRING_CONSTRAINT_CHECK ((MaxBufferSize >= Length / 2), RETURN_BUFFER_TOO_SMALL);
-
- //
- // 5. String shall not contains invalid hexadecimal digits.
- //
- for (Index = 0; Index < Length; Index++) {
- if (!InternalIsHexaDecimalDigitCharacter (String[Index])) {
- break;
- }
- }
- if (Index != Length) {
- return RETURN_UNSUPPORTED;
- }
-
- //
- // Convert the hex string to bytes.
- //
- for(Index = 0; Index < Length; Index++) {
-
- //
- // For even characters, write the upper nibble for each buffer byte,
- // and for even characters, the lower nibble.
- //
- if ((Index & BIT0) == 0) {
- Buffer[Index / 2] = (UINT8) InternalHexCharToUintn (String[Index]) << 4;
- } else {
- Buffer[Index / 2] |= (UINT8) InternalHexCharToUintn (String[Index]);
- }
- }
- return RETURN_SUCCESS;
-}
-
-/**
- Convert a Null-terminated Unicode GUID string to a value of type
- EFI_GUID.
-
- This function outputs a GUID value by interpreting the contents of
- the Unicode string specified by String. The format of the input
- Unicode string String consists of 36 characters, as follows:
-
- aabbccdd-eeff-gghh-iijj-kkllmmnnoopp
-
- The pairs aa - pp are two characters in the range [0-9], [a-f] and
- [A-F], with each pair representing a single byte hexadecimal value.
-
- The mapping between String and the EFI_GUID structure is as follows:
- aa Data1[24:31]
- bb Data1[16:23]
- cc Data1[8:15]
- dd Data1[0:7]
- ee Data2[8:15]
- ff Data2[0:7]
- gg Data3[8:15]
- hh Data3[0:7]
- ii Data4[0:7]
- jj Data4[8:15]
- kk Data4[16:23]
- ll Data4[24:31]
- mm Data4[32:39]
- nn Data4[40:47]
- oo Data4[48:55]
- pp Data4[56:63]
-
- If String is NULL, then ASSERT().
- If Guid is NULL, then ASSERT().
- If String is not aligned in a 16-bit boundary, then ASSERT().
-
- @param String Pointer to a Null-terminated Unicode string.
- @param Guid Pointer to the converted GUID.
-
- @retval RETURN_SUCCESS Guid is translated from String.
- @retval RETURN_INVALID_PARAMETER If String is NULL.
- If Data is NULL.
- @retval RETURN_UNSUPPORTED If String is not as the above format.
-
-**/
-RETURN_STATUS
-StrToGuid (
- CONST CHAR16 *String,
- EFI_GUID *Guid
- )
-{
- RETURN_STATUS Status;
- EFI_GUID LocalGuid;
-
- ASSERT (((UINTN) String & BIT0) == 0);
-
- //
- // 1. None of String or Guid shall be a null pointer.
- //
- SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER);
- SAFE_STRING_CONSTRAINT_CHECK ((Guid != NULL), RETURN_INVALID_PARAMETER);
-
- //
- // Get aabbccdd in big-endian.
- //
- Status = StrHexToBytes (String, 2 * sizeof (LocalGuid.Data1), (UINT8 *) &LocalGuid.Data1, sizeof (LocalGuid.Data1));
- if (RETURN_ERROR (Status) || String[2 * sizeof (LocalGuid.Data1)] != L'-') {
- return RETURN_UNSUPPORTED;
- }
- //
- // Convert big-endian to little-endian.
- //
- LocalGuid.Data1 = SwapBytes32 (LocalGuid.Data1);
- String += 2 * sizeof (LocalGuid.Data1) + 1;
-
- //
- // Get eeff in big-endian.
- //
- Status = StrHexToBytes (String, 2 * sizeof (LocalGuid.Data2), (UINT8 *) &LocalGuid.Data2, sizeof (LocalGuid.Data2));
- if (RETURN_ERROR (Status) || String[2 * sizeof (LocalGuid.Data2)] != L'-') {
- return RETURN_UNSUPPORTED;
- }
- //
- // Convert big-endian to little-endian.
- //
- LocalGuid.Data2 = SwapBytes16 (LocalGuid.Data2);
- String += 2 * sizeof (LocalGuid.Data2) + 1;
-
- //
- // Get gghh in big-endian.
- //
- Status = StrHexToBytes (String, 2 * sizeof (LocalGuid.Data3), (UINT8 *) &LocalGuid.Data3, sizeof (LocalGuid.Data3));
- if (RETURN_ERROR (Status) || String[2 * sizeof (LocalGuid.Data3)] != L'-') {
- return RETURN_UNSUPPORTED;
- }
- //
- // Convert big-endian to little-endian.
- //
- LocalGuid.Data3 = SwapBytes16 (LocalGuid.Data3);
- String += 2 * sizeof (LocalGuid.Data3) + 1;
-
- //
- // Get iijj.
- //
- Status = StrHexToBytes (String, 2 * 2, &LocalGuid.Data4[0], 2);
- if (RETURN_ERROR (Status) || String[2 * 2] != L'-') {
- return RETURN_UNSUPPORTED;
- }
- String += 2 * 2 + 1;
-
- //
- // Get kkllmmnnoopp.
- //
- Status = StrHexToBytes (String, 2 * 6, &LocalGuid.Data4[2], 6);
- if (RETURN_ERROR (Status)) {
- return RETURN_UNSUPPORTED;
- }
-
- CopyGuid (Guid, &LocalGuid);
- return RETURN_SUCCESS;
-}
-
-/**
- Compares up to a specified length the contents of two Null-terminated Unicode strings,
- and returns the difference between the first mismatched Unicode characters.
-
- This function compares the Null-terminated Unicode string FirstString to the
- Null-terminated Unicode string SecondString. At most, Length Unicode
- characters will be compared. If Length is 0, then 0 is returned. If
- FirstString is identical to SecondString, then 0 is returned. Otherwise, the
- value returned is the first mismatched Unicode character in SecondString
- subtracted from the first mismatched Unicode character in FirstString.
-
- If Length > 0 and FirstString is NULL, then ASSERT().
- If Length > 0 and FirstString is not aligned on a 16-bit boundary, then ASSERT().
- If Length > 0 and SecondString is NULL, then ASSERT().
- If Length > 0 and SecondString is not aligned on a 16-bit boundary, then ASSERT().
- If PcdMaximumUnicodeStringLength is not zero, and Length is greater than
- PcdMaximumUnicodeStringLength, then ASSERT().
- If PcdMaximumUnicodeStringLength is not zero, and FirstString contains more than
- PcdMaximumUnicodeStringLength Unicode characters, not including the Null-terminator,
- then ASSERT().
- If PcdMaximumUnicodeStringLength is not zero, and SecondString contains more than
- PcdMaximumUnicodeStringLength Unicode characters, not including the Null-terminator,
- then ASSERT().
-
- @param FirstString A pointer to a Null-terminated Unicode string.
- @param SecondString A pointer to a Null-terminated Unicode string.
- @param Length The maximum number of Unicode characters to compare.
-
- @retval 0 FirstString is identical to SecondString.
- @return others FirstString is not identical to SecondString.
-
-**/
-INTN
-StrnCmp (
- CONST CHAR16 *FirstString,
- CONST CHAR16 *SecondString,
- UINTN Length
- )
-{
- if (Length == 0) {
- return 0;
- }
-
- //
- // ASSERT both strings are less long than PcdMaximumUnicodeStringLength.
- // Length tests are performed inside StrLen().
- //
- ASSERT (StrSize (FirstString) != 0);
- ASSERT (StrSize (SecondString) != 0);
-
- while ((*FirstString != L'\0') &&
- (*SecondString != L'\0') &&
- (*FirstString == *SecondString) &&
- (Length > 1)) {
- FirstString++;
- SecondString++;
- Length--;
- }
-
- return *FirstString - *SecondString;
-}
-
-VOID *
-AllocateCopyPool (
- UINTN AllocationSize,
- CONST VOID *Buffer
- )
-{
- return InternalAllocateCopyPool (AllocationSize, Buffer);
-}
-
-INTN
-StrCmp (
- CONST CHAR16 *FirstString,
- CONST CHAR16 *SecondString
- )
-{
- //
- // ASSERT both strings are less long than PcdMaximumUnicodeStringLength
- //
- ASSERT (StrSize (FirstString) != 0);
- ASSERT (StrSize (SecondString) != 0);
-
- while ((*FirstString != L'\0') && (*FirstString == *SecondString)) {
- FirstString++;
- SecondString++;
- }
- return *FirstString - *SecondString;
-}
-
-UINT64
-SwapBytes64 (
- UINT64 Value
- )
-{
- return InternalMathSwapBytes64 (Value);
-}
-
-UINT64
-InternalMathSwapBytes64 (
- UINT64 Operand
- )
-{
- UINT64 LowerBytes;
- UINT64 HigherBytes;
-
- LowerBytes = (UINT64) SwapBytes32 ((UINT32) Operand);
- HigherBytes = (UINT64) SwapBytes32 ((UINT32) (Operand >> 32));
-
- return (LowerBytes << 32 | HigherBytes);
-}
-
-RETURN_STATUS
-StrToIpv4Address (
- CONST CHAR16 *String,
- CHAR16 **EndPointer,
- EFI_IPv4_ADDRESS *Address,
- UINT8 *PrefixLength
- )
-{
- RETURN_STATUS Status;
- UINTN AddressIndex;
- UINT64 Uint64;
- EFI_IPv4_ADDRESS LocalAddress;
- UINT8 LocalPrefixLength;
- CHAR16 *Pointer;
-
- LocalPrefixLength = MAX_UINT8;
- LocalAddress.Addr[0] = 0;
-
- ASSERT (((UINTN) String & BIT0) == 0);
-
- //
- // 1. None of String or Guid shall be a null pointer.
- //
- SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER);
- SAFE_STRING_CONSTRAINT_CHECK ((Address != NULL), RETURN_INVALID_PARAMETER);
-
- for (Pointer = (CHAR16 *) String, AddressIndex = 0; AddressIndex < ARRAY_SIZE (Address->Addr) + 1;) {
- if (!InternalIsDecimalDigitCharacter (*Pointer)) {
- //
- // D or P contains invalid characters.
- //
- break;
- }
-
- //
- // Get D or P.
- //
- Status = StrDecimalToUint64S ((CONST CHAR16 *) Pointer, &Pointer, &Uint64);
- if (RETURN_ERROR (Status)) {
- return RETURN_UNSUPPORTED;
- }
- if (AddressIndex == ARRAY_SIZE (Address->Addr)) {
- //
- // It's P.
- //
- if (Uint64 > 32) {
- return RETURN_UNSUPPORTED;
- }
- LocalPrefixLength = (UINT8) Uint64;
- } else {
- //
- // It's D.
- //
- if (Uint64 > MAX_UINT8) {
- return RETURN_UNSUPPORTED;
- }
- LocalAddress.Addr[AddressIndex] = (UINT8) Uint64;
- AddressIndex++;
- }
-
- //
- // Check the '.' or '/', depending on the AddressIndex.
- //
- if (AddressIndex == ARRAY_SIZE (Address->Addr)) {
- if (*Pointer == L'/') {
- //
- // '/P' is in the String.
- // Skip "/" and get P in next loop.
- //
- Pointer++;
- } else {
- //
- // '/P' is not in the String.
- //
- break;
- }
- } else if (AddressIndex < ARRAY_SIZE (Address->Addr)) {
- if (*Pointer == L'.') {
- //
- // D should be followed by '.'
- //
- Pointer++;
- } else {
- return RETURN_UNSUPPORTED;
- }
- }
- }
-
- if (AddressIndex < ARRAY_SIZE (Address->Addr)) {
- return RETURN_UNSUPPORTED;
- }
-
- memcpy (Address, &LocalAddress, sizeof (*Address));
- if (PrefixLength != NULL) {
- *PrefixLength = LocalPrefixLength;
- }
- if (EndPointer != NULL) {
- *EndPointer = Pointer;
- }
-
- return RETURN_SUCCESS;
-}
-
-RETURN_STATUS
-StrToIpv6Address (
- CONST CHAR16 *String,
- CHAR16 **EndPointer,
- EFI_IPv6_ADDRESS *Address,
- UINT8 *PrefixLength
- )
-{
- RETURN_STATUS Status;
- UINTN AddressIndex;
- UINT64 Uint64;
- EFI_IPv6_ADDRESS LocalAddress;
- UINT8 LocalPrefixLength;
- CONST CHAR16 *Pointer;
- CHAR16 *End;
- UINTN CompressStart;
- BOOLEAN ExpectPrefix;
-
- LocalPrefixLength = MAX_UINT8;
- CompressStart = ARRAY_SIZE (Address->Addr);
- ExpectPrefix = FALSE;
-
- ASSERT (((UINTN) String & BIT0) == 0);
-
- //
- // 1. None of String or Guid shall be a null pointer.
- //
- SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER);
- SAFE_STRING_CONSTRAINT_CHECK ((Address != NULL), RETURN_INVALID_PARAMETER);
-
- for (Pointer = String, AddressIndex = 0; AddressIndex < ARRAY_SIZE (Address->Addr) + 1;) {
- if (!InternalIsHexaDecimalDigitCharacter (*Pointer)) {
- if (*Pointer != L':') {
- //
- // ":" or "/" should be followed by digit characters.
- //
- return RETURN_UNSUPPORTED;
- }
-
- //
- // Meet second ":" after previous ":" or "/"
- // or meet first ":" in the beginning of String.
- //
- if (ExpectPrefix) {
- //
- // ":" shall not be after "/"
- //
- return RETURN_UNSUPPORTED;
- }
-
- if (CompressStart != ARRAY_SIZE (Address->Addr) || AddressIndex == ARRAY_SIZE (Address->Addr)) {
- //
- // "::" can only appear once.
- // "::" can only appear when address is not full length.
- //
- return RETURN_UNSUPPORTED;
- } else {
- //
- // Remember the start of zero compressing.
- //
- CompressStart = AddressIndex;
- Pointer++;
-
- if (CompressStart == 0) {
- if (*Pointer != L':') {
- //
- // Single ":" shall not be in the beginning of String.
- //
- return RETURN_UNSUPPORTED;
- }
- Pointer++;
- }
- }
- }
-
- if (!InternalIsHexaDecimalDigitCharacter (*Pointer)) {
- if (*Pointer == L'/') {
- //
- // Might be optional "/P" after "::".
- //
- if (CompressStart != AddressIndex) {
- return RETURN_UNSUPPORTED;
- }
- } else {
- break;
- }
- } else {
- if (!ExpectPrefix) {
- //
- // Get X.
- //
- Status = StrHexToUint64S (Pointer, &End, &Uint64);
- if (RETURN_ERROR (Status) || End - Pointer > 4) {
- //
- // Number of hexadecimal digit characters is no more than 4.
- //
- return RETURN_UNSUPPORTED;
- }
- Pointer = End;
- //
- // Uint64 won't exceed MAX_UINT16 if number of hexadecimal digit characters is no more than 4.
- //
- ASSERT (AddressIndex + 1 < ARRAY_SIZE (Address->Addr));
- LocalAddress.Addr[AddressIndex] = (UINT8) ((UINT16) Uint64 >> 8);
- LocalAddress.Addr[AddressIndex + 1] = (UINT8) Uint64;
- AddressIndex += 2;
- } else {
- //
- // Get P, then exit the loop.
- //
- Status = StrDecimalToUint64S (Pointer, &End, &Uint64);
- if (RETURN_ERROR (Status) || End == Pointer || Uint64 > 128) {
- //
- // Prefix length should not exceed 128.
- //
- return RETURN_UNSUPPORTED;
- }
- LocalPrefixLength = (UINT8) Uint64;
- Pointer = End;
- break;
- }
- }
-
- //
- // Skip ':' or "/"
- //
- if (*Pointer == L'/') {
- ExpectPrefix = TRUE;
- } else if (*Pointer == L':') {
- if (AddressIndex == ARRAY_SIZE (Address->Addr)) {
- //
- // Meet additional ":" after all 8 16-bit address
- //
- break;
- }
- } else {
- //
- // Meet other character that is not "/" or ":" after all 8 16-bit address
- //
- break;
- }
- Pointer++;
- }
-
- if ((AddressIndex == ARRAY_SIZE (Address->Addr) && CompressStart != ARRAY_SIZE (Address->Addr)) ||
- (AddressIndex != ARRAY_SIZE (Address->Addr) && CompressStart == ARRAY_SIZE (Address->Addr))
- ) {
- //
- // Full length of address shall not have compressing zeros.
- // Non-full length of address shall have compressing zeros.
- //
- return RETURN_UNSUPPORTED;
- }
- memcpy (&Address->Addr[0], &LocalAddress.Addr[0], CompressStart);
- if (AddressIndex > CompressStart) {
- memset (&Address->Addr[CompressStart], 0, ARRAY_SIZE (Address->Addr) - AddressIndex);
- memcpy (
- &Address->Addr[CompressStart + ARRAY_SIZE (Address->Addr) - AddressIndex],
- &LocalAddress.Addr[CompressStart],
- AddressIndex - CompressStart
- );
- }
-
- if (PrefixLength != NULL) {
- *PrefixLength = LocalPrefixLength;
- }
- if (EndPointer != NULL) {
- *EndPointer = (CHAR16 *) Pointer;
- }
-
- return RETURN_SUCCESS;
-}
-
-
-RETURN_STATUS
-UnicodeStrToAsciiStrS (
- CONST CHAR16 *Source,
- CHAR8 *Destination,
- UINTN DestMax
- )
-{
- UINTN SourceLen;
-
- ASSERT (((UINTN) Source & BIT0) == 0);
-
- //
- // 1. Neither Destination nor Source shall be a null pointer.
- //
- SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER);
- SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER);
-
- //
- // 2. DestMax shall not be greater than ASCII_RSIZE_MAX or RSIZE_MAX.
- //
- if (ASCII_RSIZE_MAX != 0) {
- SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER);
- }
- if (RSIZE_MAX != 0) {
- SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= RSIZE_MAX), RETURN_INVALID_PARAMETER);
- }
-
- //
- // 3. DestMax shall not equal zero.
- //
- SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER);
-
- //
- // 4. DestMax shall be greater than StrnLenS (Source, DestMax).
- //
- SourceLen = StrnLenS (Source, DestMax);
- SAFE_STRING_CONSTRAINT_CHECK ((DestMax > SourceLen), RETURN_BUFFER_TOO_SMALL);
-
- //
- // 5. Copying shall not take place between objects that overlap.
- //
- SAFE_STRING_CONSTRAINT_CHECK (!InternalSafeStringIsOverlap (Destination, DestMax, (VOID *)Source, (SourceLen + 1) * sizeof(CHAR16)), RETURN_ACCESS_DENIED);
-
- //
- // convert string
- //
- while (*Source != '\0') {
- //
- // If any Unicode characters in Source contain
- // non-zero value in the upper 8 bits, then ASSERT().
- //
- ASSERT (*Source < 0x100);
- *(Destination++) = (CHAR8) *(Source++);
- }
- *Destination = '\0';
-
- return RETURN_SUCCESS;
-}
-
-RETURN_STATUS
-StrCpyS (
- CHAR16 *Destination,
- UINTN DestMax,
- CONST CHAR16 *Source
- )
-{
- UINTN SourceLen;
-
- ASSERT (((UINTN) Destination & BIT0) == 0);
- ASSERT (((UINTN) Source & BIT0) == 0);
-
- //
- // 1. Neither Destination nor Source shall be a null pointer.
- //
- SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER);
- SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER);
-
- //
- // 2. DestMax shall not be greater than RSIZE_MAX.
- //
- if (RSIZE_MAX != 0) {
- SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= RSIZE_MAX), RETURN_INVALID_PARAMETER);
- }
-
- //
- // 3. DestMax shall not equal zero.
- //
- SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER);
-
- //
- // 4. DestMax shall be greater than StrnLenS(Source, DestMax).
- //
- SourceLen = StrnLenS (Source, DestMax);
- SAFE_STRING_CONSTRAINT_CHECK ((DestMax > SourceLen), RETURN_BUFFER_TOO_SMALL);
-
- //
- // 5. Copying shall not take place between objects that overlap.
- //
- SAFE_STRING_CONSTRAINT_CHECK (InternalSafeStringNoStrOverlap (Destination, DestMax, (CHAR16 *)Source, SourceLen + 1), RETURN_ACCESS_DENIED);
-
- //
- // The StrCpyS function copies the string pointed to by Source (including the terminating
- // null character) into the array pointed to by Destination.
- //
- while (*Source != 0) {
- *(Destination++) = *(Source++);
- }
- *Destination = 0;
-
- return RETURN_SUCCESS;
-}
-
-VOID *
-AllocateZeroPool (
- UINTN AllocationSize
- )
-{
- VOID * Memory;
- Memory = malloc(AllocationSize);
- ASSERT (Memory != NULL);
- if (Memory == NULL) {
- fprintf(stderr, "Not memory for malloc\n");
- }
- memset(Memory, 0, AllocationSize);
- return Memory;
-}
-
-VOID *
-AllocatePool (
- UINTN AllocationSize
- )
-{
- return InternalAllocatePool (AllocationSize);
-}
-
-UINT16
-WriteUnaligned16 (
- UINT16 *Buffer,
- UINT16 Value
- )
-{
- ASSERT (Buffer != NULL);
-
- return *Buffer = Value;
-}
-
-UINT16
-ReadUnaligned16 (
- CONST UINT16 *Buffer
- )
-{
- ASSERT (Buffer != NULL);
-
- return *Buffer;
-}
-/**
- Return whether the integer string is a hex string.
-
- @param Str The integer string
-
- @retval TRUE Hex string
- @retval FALSE Decimal string
-
-**/
-BOOLEAN
-IsHexStr (
- CHAR16 *Str
- )
-{
- //
- // skip preceding white space
- //
- while ((*Str != 0) && *Str == L' ') {
- Str ++;
- }
- //
- // skip preceding zeros
- //
- while ((*Str != 0) && *Str == L'0') {
- Str ++;
- }
-
- return (BOOLEAN) (*Str == L'x' || *Str == L'X');
-}
-
-/**
-
- Convert integer string to uint.
-
- @param Str The integer string. If leading with "0x" or "0X", it's hexadecimal.
-
- @return A UINTN value represented by Str
-
-**/
-UINTN
-Strtoi (
- CHAR16 *Str
- )
-{
- if (IsHexStr (Str)) {
- return (UINTN)StrHexToUint64 (Str);
- } else {
- return (UINTN)StrDecimalToUint64 (Str);
- }
-}
-
-/**
-
- Convert integer string to 64 bit data.
-
- @param Str The integer string. If leading with "0x" or "0X", it's hexadecimal.
- @param Data A pointer to the UINT64 value represented by Str
-
-**/
-VOID
-Strtoi64 (
- CHAR16 *Str,
- UINT64 *Data
- )
-{
- if (IsHexStr (Str)) {
- *Data = StrHexToUint64 (Str);
- } else {
- *Data = StrDecimalToUint64 (Str);
- }
-}
-
-/**
- Converts a Unicode string to ASCII string.
-
- @param Str The equivalent Unicode string
- @param AsciiStr On input, it points to destination ASCII string buffer; on output, it points
- to the next ASCII string next to it
-
-**/
-VOID
-StrToAscii (
- CHAR16 *Str,
- CHAR8 **AsciiStr
- )
-{
- CHAR8 *Dest;
-
- Dest = *AsciiStr;
- while (!IS_NULL (*Str)) {
- *(Dest++) = (CHAR8) *(Str++);
- }
- *Dest = 0;
-
- //
- // Return the string next to it
- //
- *AsciiStr = Dest + 1;
-}
-
-/**
- Gets current sub-string from a string list, before return
- the list header is moved to next sub-string. The sub-string is separated
- by the specified character. For example, the separator is ',', the string
- list is "2,0,3", it returns "2", the remain list move to "0,3"
-
- @param List A string list separated by the specified separator
- @param Separator The separator character
-
- @return A pointer to the current sub-string
-
-**/
-CHAR16 *
-SplitStr (
- CHAR16 **List,
- CHAR16 Separator
- )
-{
- CHAR16 *Str;
- CHAR16 *ReturnStr;
-
- Str = *List;
- ReturnStr = Str;
-
- if (IS_NULL (*Str)) {
- return ReturnStr;
- }
-
- //
- // Find first occurrence of the separator
- //
- while (!IS_NULL (*Str)) {
- if (*Str == Separator) {
- break;
- }
- Str++;
- }
-
- if (*Str == Separator) {
- //
- // Find a sub-string, terminate it
- //
- *Str = L'\0';
- Str++;
- }
-
- //
- // Move to next sub-string
- //
- *List = Str;
- return ReturnStr;
-}
+/** @file +Common basic Library Functions + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> +#ifdef __GNUC__ +#include <unistd.h> +#else +#include <direct.h> +#endif +#include "CommonLib.h" +#include "EfiUtilityMsgs.h" + +#define SAFE_STRING_CONSTRAINT_CHECK(Expression, Status) \ + do { \ + ASSERT (Expression); \ + if (!(Expression)) { \ + return Status; \ + } \ + } while (FALSE) + +/** + Set Buffer to zero for Size bytes. + + @param Buffer Memory to set. + @param Size Number of bytes to set +**/ +VOID +PeiZeroMem ( + IN VOID *Buffer, + IN UINTN Size + ) +{ + INT8 *Ptr; + + Ptr = Buffer; + while (Size--) { + *(Ptr++) = 0; + } +} + +/** + Copy Length bytes from Source to Destination. + + @param Destination Target of copy + @param Source Place to copy from + @param Length Number of bytes to copy +**/ +VOID +PeiCopyMem ( + IN VOID *Destination, + IN VOID *Source, + IN UINTN Length + ) +{ + CHAR8 *Destination8; + CHAR8 *Source8; + + Destination8 = Destination; + Source8 = Source; + while (Length--) { + *(Destination8++) = *(Source8++); + } +} + +VOID +ZeroMem ( + IN VOID *Buffer, + IN UINTN Size + ) +{ + PeiZeroMem (Buffer, Size); +} + +VOID +CopyMem ( + IN VOID *Destination, + IN VOID *Source, + IN UINTN Length + ) +{ + PeiCopyMem (Destination, Source, Length); +} + +/** + Compares to GUIDs + + @param Guid1 guid to compare + @param Guid2 guid to compare + + @retval = 0 if Guid1 == Guid2 + @retval != 0 if Guid1 != Guid2 +**/ +INTN +CompareGuid ( + IN EFI_GUID *Guid1, + IN EFI_GUID *Guid2 + ) +{ + INT32 *g1; + INT32 *g2; + INT32 r; + + // + // Compare 32 bits at a time + // + g1 = (INT32 *) Guid1; + g2 = (INT32 *) Guid2; + + r = g1[0] - g2[0]; + r |= g1[1] - g2[1]; + r |= g1[2] - g2[2]; + r |= g1[3] - g2[3]; + + return r; +} + +/** + This function opens a file and reads it into a memory buffer. The function + will allocate the memory buffer and returns the size of the buffer. + + @param InputFileName The name of the file to read. + @param InputFileImage A pointer to the memory buffer. + @param BytesRead The size of the memory buffer. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER One of the input parameters was invalid. + @retval EFI_ABORTED An error occurred. + @retval EFI_OUT_OF_RESOURCES No resource to complete operations. +**/ +EFI_STATUS +GetFileImage ( + IN CHAR8 *InputFileName, + OUT CHAR8 **InputFileImage, + OUT UINT32 *BytesRead + ) +{ + FILE *InputFile; + UINT32 FileSize; + + // + // Verify input parameters. + // + if (InputFileName == NULL || strlen (InputFileName) == 0 || InputFileImage == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Open the file and copy contents into a memory buffer. + // + // + // Open the file + // + InputFile = fopen (LongFilePath (InputFileName), "rb"); + if (InputFile == NULL) { + Error (NULL, 0, 0001, "Error opening the input file", InputFileName); + return EFI_ABORTED; + } + // + // Go to the end so that we can determine the file size + // + if (fseek (InputFile, 0, SEEK_END)) { + Error (NULL, 0, 0004, "Error reading the input file", InputFileName); + fclose (InputFile); + return EFI_ABORTED; + } + // + // Get the file size + // + FileSize = ftell (InputFile); + if (FileSize == -1) { + Error (NULL, 0, 0003, "Error parsing the input file", InputFileName); + fclose (InputFile); + return EFI_ABORTED; + } + // + // Allocate a buffer + // + *InputFileImage = malloc (FileSize); + if (*InputFileImage == NULL) { + fclose (InputFile); + return EFI_OUT_OF_RESOURCES; + } + // + // Reset to the beginning of the file + // + if (fseek (InputFile, 0, SEEK_SET)) { + Error (NULL, 0, 0004, "Error reading the input file", InputFileName); + fclose (InputFile); + free (*InputFileImage); + *InputFileImage = NULL; + return EFI_ABORTED; + } + // + // Read all of the file contents. + // + *BytesRead = fread (*InputFileImage, sizeof (UINT8), FileSize, InputFile); + if (*BytesRead != sizeof (UINT8) * FileSize) { + Error (NULL, 0, 0004, "Error reading the input file", InputFileName); + fclose (InputFile); + free (*InputFileImage); + *InputFileImage = NULL; + return EFI_ABORTED; + } + // + // Close the file + // + fclose (InputFile); + + return EFI_SUCCESS; +} + +/** + This function opens a file and writes OutputFileImage into the file. + + @param OutputFileName The name of the file to write. + @param OutputFileImage A pointer to the memory buffer. + @param BytesToWrite The size of the memory buffer. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER One of the input parameters was invalid. + @retval EFI_ABORTED An error occurred. + @retval EFI_OUT_OF_RESOURCES No resource to complete operations. +**/ +EFI_STATUS +PutFileImage ( + IN CHAR8 *OutputFileName, + IN CHAR8 *OutputFileImage, + IN UINT32 BytesToWrite + ) +{ + FILE *OutputFile; + UINT32 BytesWrote; + + // + // Verify input parameters. + // + if (OutputFileName == NULL || strlen (OutputFileName) == 0 || OutputFileImage == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Open the file and copy contents into a memory buffer. + // + // + // Open the file + // + OutputFile = fopen (LongFilePath (OutputFileName), "wb"); + if (OutputFile == NULL) { + Error (NULL, 0, 0001, "Error opening the output file", OutputFileName); + return EFI_ABORTED; + } + + // + // Write all of the file contents. + // + BytesWrote = fwrite (OutputFileImage, sizeof (UINT8), BytesToWrite, OutputFile); + if (BytesWrote != sizeof (UINT8) * BytesToWrite) { + Error (NULL, 0, 0002, "Error writing the output file", OutputFileName); + fclose (OutputFile); + return EFI_ABORTED; + } + // + // Close the file + // + fclose (OutputFile); + + return EFI_SUCCESS; +} + +/** + This function calculates the value needed for a valid UINT8 checksum + + @param Buffer Pointer to buffer containing byte data of component. + @param Size Size of the buffer + + @return The 8 bit checksum value needed. +**/ +UINT8 +CalculateChecksum8 ( + IN UINT8 *Buffer, + IN UINTN Size + ) +{ + return (UINT8) (0x100 - CalculateSum8 (Buffer, Size)); +} + +/** + This function calculates the UINT8 sum for the requested region. + + @param Buffer Pointer to buffer containing byte data of component. + @param Size Size of the buffer + + @return The 8 bit checksum value needed. +**/ +UINT8 +CalculateSum8 ( + IN UINT8 *Buffer, + IN UINTN Size + ) +{ + UINTN Index; + UINT8 Sum; + + Sum = 0; + + // + // Perform the byte sum for buffer + // + for (Index = 0; Index < Size; Index++) { + Sum = (UINT8) (Sum + Buffer[Index]); + } + + return Sum; +} + +/** + This function calculates the value needed for a valid UINT16 checksum + + @param Buffer Pointer to buffer containing byte data of component. + @param Size Size of the buffer + + @return The 16 bit checksum value needed. +**/ +UINT16 +CalculateChecksum16 ( + IN UINT16 *Buffer, + IN UINTN Size + ) +{ + return (UINT16) (0x10000 - CalculateSum16 (Buffer, Size)); +} + +/** + This function calculates the UINT16 sum for the requested region. + + @param Buffer Pointer to buffer containing byte data of component. + @param Size Size of the buffer + + @return The 16 bit checksum +**/ +UINT16 +CalculateSum16 ( + IN UINT16 *Buffer, + IN UINTN Size + ) +{ + UINTN Index; + UINT16 Sum; + + Sum = 0; + + // + // Perform the word sum for buffer + // + for (Index = 0; Index < Size; Index++) { + Sum = (UINT16) (Sum + Buffer[Index]); + } + + return (UINT16) Sum; +} + +/** + This function prints a GUID to STDOUT. + + @param Guid Pointer to a GUID to print. + + @retval EFI_SUCCESS The GUID was printed. + @retval EFI_INVALID_PARAMETER The input was NULL. +**/ +EFI_STATUS +PrintGuid ( + IN EFI_GUID *Guid + ) +{ + if (Guid == NULL) { + Error (NULL, 0, 2000, "Invalid parameter", "PrintGuidToBuffer() called with a NULL value"); + return EFI_INVALID_PARAMETER; + } + + printf ( + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x\n", + (unsigned) Guid->Data1, + Guid->Data2, + Guid->Data3, + Guid->Data4[0], + Guid->Data4[1], + Guid->Data4[2], + Guid->Data4[3], + Guid->Data4[4], + Guid->Data4[5], + Guid->Data4[6], + Guid->Data4[7] + ); + return EFI_SUCCESS; +} + +/** + This function prints a GUID to a buffer + + @param Guid Pointer to a GUID to print. + @param Buffer Pointer to a user-provided buffer to print to + @param BufferLen Size of the Buffer + @param Uppercase If use upper case. + + @retval EFI_SUCCESS The GUID was printed. + @retval EFI_INVALID_PARAMETER The input was NULL. + @retval EFI_BUFFER_TOO_SMALL The input buffer was not big enough +**/ +EFI_STATUS +PrintGuidToBuffer ( + IN EFI_GUID *Guid, + IN OUT UINT8 *Buffer, + IN UINT32 BufferLen, + IN BOOLEAN Uppercase + ) +{ + if (Guid == NULL) { + Error (NULL, 0, 2000, "Invalid parameter", "PrintGuidToBuffer() called with a NULL value"); + return EFI_INVALID_PARAMETER; + } + + if (BufferLen < PRINTED_GUID_BUFFER_SIZE) { + Error (NULL, 0, 2000, "Invalid parameter", "PrintGuidToBuffer() called with invalid buffer size"); + return EFI_BUFFER_TOO_SMALL; + } + + if (Uppercase) { + sprintf ( + (CHAR8 *)Buffer, + "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + (unsigned) Guid->Data1, + Guid->Data2, + Guid->Data3, + Guid->Data4[0], + Guid->Data4[1], + Guid->Data4[2], + Guid->Data4[3], + Guid->Data4[4], + Guid->Data4[5], + Guid->Data4[6], + Guid->Data4[7] + ); + } else { + sprintf ( + (CHAR8 *)Buffer, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + (unsigned) Guid->Data1, + Guid->Data2, + Guid->Data3, + Guid->Data4[0], + Guid->Data4[1], + Guid->Data4[2], + Guid->Data4[3], + Guid->Data4[4], + Guid->Data4[5], + Guid->Data4[6], + Guid->Data4[7] + ); + } + + return EFI_SUCCESS; +} + +#ifdef __GNUC__ + +size_t _filelength(int fd) +{ + struct stat stat_buf; + fstat(fd, &stat_buf); + return stat_buf.st_size; +} + +#ifndef __CYGWIN__ +char *strlwr(char *s) +{ + char *p = s; + for(;*s;s++) { + *s = tolower(*s); + } + return p; +} +#endif +#endif + +#define WINDOWS_EXTENSION_PATH "\\\\?\\" +#define WINDOWS_UNC_EXTENSION_PATH "\\\\?\\UNC" + +// +// Global data to store full file path. It is not required to be free. +// +CHAR8 mCommonLibFullPath[MAX_LONG_FILE_PATH]; + +/** + Convert FileName to the long file path, which can support larger than 260 length. + + @param FileName FileName. + + @return LongFilePath A pointer to the converted long file path. +**/ +CHAR8 * +LongFilePath ( + IN CHAR8 *FileName + ) +{ +#ifdef __GNUC__ + // + // __GNUC__ may not be good way to differentiate unix and windows. Need more investigation here. + // unix has no limitation on file path. Just return FileName. + // + return FileName; +#else + CHAR8 *RootPath; + CHAR8 *PathPointer; + CHAR8 *NextPointer; + + PathPointer = (CHAR8 *) FileName; + + if (FileName != NULL) { + // + // Add the extension string first to support long file path. + // + mCommonLibFullPath[0] = 0; + strcpy (mCommonLibFullPath, WINDOWS_EXTENSION_PATH); + + if (strlen (FileName) > 1 && FileName[0] == '\\' && FileName[1] == '\\') { + // + // network path like \\server\share to \\?\UNC\server\share + // + strcpy (mCommonLibFullPath, WINDOWS_UNC_EXTENSION_PATH); + FileName ++; + } else if (strlen (FileName) < 3 || FileName[1] != ':' || (FileName[2] != '\\' && FileName[2] != '/')) { + // + // Relative file path. Convert it to absolute path. + // + RootPath = getcwd (NULL, 0); + if (RootPath != NULL) { + if (strlen (mCommonLibFullPath) + strlen (RootPath) > MAX_LONG_FILE_PATH - 1) { + Error (NULL, 0, 2000, "Invalid parameter", "RootPath is too long!"); + free (RootPath); + return NULL; + } + strncat (mCommonLibFullPath, RootPath, MAX_LONG_FILE_PATH - strlen (mCommonLibFullPath) - 1); + if (FileName[0] != '\\' && FileName[0] != '/') { + if (strlen (mCommonLibFullPath) + 1 > MAX_LONG_FILE_PATH - 1) { + Error (NULL, 0, 2000, "Invalid parameter", "RootPath is too long!"); + free (RootPath); + return NULL; + } + // + // Attach directory separator + // + strncat (mCommonLibFullPath, "\\", MAX_LONG_FILE_PATH - strlen (mCommonLibFullPath) - 1); + } + free (RootPath); + } + } + + // + // Construct the full file path + // + if (strlen (mCommonLibFullPath) + strlen (FileName) > MAX_LONG_FILE_PATH - 1) { + Error (NULL, 0, 2000, "Invalid parameter", "FileName %s is too long!", FileName); + return NULL; + } + strncat (mCommonLibFullPath, FileName, MAX_LONG_FILE_PATH - strlen (mCommonLibFullPath) - 1); + + // + // Convert directory separator '/' to '\\' + // + PathPointer = (CHAR8 *) mCommonLibFullPath; + do { + if (*PathPointer == '/') { + *PathPointer = '\\'; + } + } while (*PathPointer ++ != '\0'); + + // + // Convert ":\\\\" to ":\\", because it doesn't work with WINDOWS_EXTENSION_PATH. + // + if ((PathPointer = strstr (mCommonLibFullPath, ":\\\\")) != NULL) { + *(PathPointer + 2) = '\0'; + strncat (mCommonLibFullPath, PathPointer + 3, MAX_LONG_FILE_PATH - strlen (mCommonLibFullPath) - 1); + } + + // + // Convert ".\\" to "", because it doesn't work with WINDOWS_EXTENSION_PATH. + // + while ((PathPointer = strstr (mCommonLibFullPath, ".\\")) != NULL) { + *PathPointer = '\0'; + strncat (mCommonLibFullPath, PathPointer + 2, MAX_LONG_FILE_PATH - strlen (mCommonLibFullPath) - 1); + } + + // + // Convert "\\.\\" to "\\", because it doesn't work with WINDOWS_EXTENSION_PATH. + // + while ((PathPointer = strstr (mCommonLibFullPath, "\\.\\")) != NULL) { + *PathPointer = '\0'; + strncat (mCommonLibFullPath, PathPointer + 2, MAX_LONG_FILE_PATH - strlen (mCommonLibFullPath) - 1); + } + + // + // Convert "\\..\\" to last directory, because it doesn't work with WINDOWS_EXTENSION_PATH. + // + while ((PathPointer = strstr (mCommonLibFullPath, "\\..\\")) != NULL) { + NextPointer = PathPointer + 3; + do { + PathPointer --; + } while (PathPointer > mCommonLibFullPath && *PathPointer != ':' && *PathPointer != '\\'); + + if (*PathPointer == '\\') { + // + // Skip one directory + // + *PathPointer = '\0'; + strncat (mCommonLibFullPath, NextPointer, MAX_LONG_FILE_PATH - strlen (mCommonLibFullPath) - 1); + } else { + // + // No directory is found. Just break. + // + break; + } + } + + PathPointer = mCommonLibFullPath; + } + + return PathPointer; +#endif +} + +CHAR16 +InternalCharToUpper ( + CHAR16 Char + ) +{ + if (Char >= L'a' && Char <= L'z') { + return (CHAR16) (Char - (L'a' - L'A')); + } + + return Char; +} + +UINTN +StrnLenS ( + CONST CHAR16 *String, + UINTN MaxSize + ) +{ + UINTN Length; + + ASSERT (((UINTN) String & BIT0) == 0); + + // + // If String is a null pointer or MaxSize is 0, then the StrnLenS function returns zero. + // + if ((String == NULL) || (MaxSize == 0)) { + return 0; + } + + Length = 0; + while (String[Length] != 0) { + if (Length >= MaxSize - 1) { + return MaxSize; + } + Length++; + } + return Length; +} + + +VOID * +InternalAllocatePool ( + UINTN AllocationSize + ) +{ + VOID * Memory; + + Memory = malloc(AllocationSize); + ASSERT(Memory != NULL); + return Memory; +} + + +VOID * +InternalReallocatePool ( + UINTN OldSize, + UINTN NewSize, + VOID *OldBuffer OPTIONAL + ) +{ + VOID *NewBuffer; + + NewBuffer = AllocateZeroPool (NewSize); + if (NewBuffer != NULL && OldBuffer != NULL) { + memcpy (NewBuffer, OldBuffer, MIN (OldSize, NewSize)); + free(OldBuffer); + } + return NewBuffer; +} + +VOID * +ReallocatePool ( + UINTN OldSize, + UINTN NewSize, + VOID *OldBuffer OPTIONAL + ) +{ + return InternalReallocatePool (OldSize, NewSize, OldBuffer); +} + +/** + Returns the length of a Null-terminated Unicode string. + + This function returns the number of Unicode characters in the Null-terminated + Unicode string specified by String. + + If String is NULL, then ASSERT(). + If String is not aligned on a 16-bit boundary, then ASSERT(). + If PcdMaximumUnicodeStringLength is not zero, and String contains more than + PcdMaximumUnicodeStringLength Unicode characters, not including the + Null-terminator, then ASSERT(). + + @param String A pointer to a Null-terminated Unicode string. + + @return The length of String. + +**/ +UINTN +StrLen ( + CONST CHAR16 *String + ) +{ + UINTN Length; + + ASSERT (String != NULL); + ASSERT (((UINTN) String & BIT0) == 0); + + for (Length = 0; *String != L'\0'; String++, Length++) { + // + // If PcdMaximumUnicodeStringLength is not zero, + // length should not more than PcdMaximumUnicodeStringLength + // + } + return Length; +} + +BOOLEAN +InternalSafeStringIsOverlap ( + IN VOID *Base1, + IN UINTN Size1, + IN VOID *Base2, + IN UINTN Size2 + ) +{ + if ((((UINTN)Base1 >= (UINTN)Base2) && ((UINTN)Base1 < (UINTN)Base2 + Size2)) || + (((UINTN)Base2 >= (UINTN)Base1) && ((UINTN)Base2 < (UINTN)Base1 + Size1))) { + return TRUE; + } + return FALSE; +} + +BOOLEAN +InternalSafeStringNoStrOverlap ( + IN CHAR16 *Str1, + IN UINTN Size1, + IN CHAR16 *Str2, + IN UINTN Size2 + ) +{ + return !InternalSafeStringIsOverlap (Str1, Size1 * sizeof(CHAR16), Str2, Size2 * sizeof(CHAR16)); +} + +/** + Convert a Null-terminated Unicode decimal string to a value of type UINT64. + + This function outputs a value of type UINT64 by interpreting the contents of + the Unicode string specified by String as a decimal number. The format of the + input Unicode string String is: + + [spaces] [decimal digits]. + + The valid decimal digit character is in the range [0-9]. The function will + ignore the pad space, which includes spaces or tab characters, before + [decimal digits]. The running zero in the beginning of [decimal digits] will + be ignored. Then, the function stops at the first character that is a not a + valid decimal character or a Null-terminator, whichever one comes first. + + If String is NULL, then ASSERT(). + If Data is NULL, then ASSERT(). + If String is not aligned in a 16-bit boundary, then ASSERT(). + If PcdMaximumUnicodeStringLength is not zero, and String contains more than + PcdMaximumUnicodeStringLength Unicode characters, not including the + Null-terminator, then ASSERT(). + + If String has no valid decimal digits in the above format, then 0 is stored + at the location pointed to by Data. + If the number represented by String exceeds the range defined by UINT64, then + MAX_UINT64 is stored at the location pointed to by Data. + + If EndPointer is not NULL, a pointer to the character that stopped the scan + is stored at the location pointed to by EndPointer. If String has no valid + decimal digits right after the optional pad spaces, the value of String is + stored at the location pointed to by EndPointer. + + @param String Pointer to a Null-terminated Unicode string. + @param EndPointer Pointer to character that stops scan. + @param Data Pointer to the converted value. + + @retval RETURN_SUCCESS Value is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + If PcdMaximumUnicodeStringLength is not + zero, and String contains more than + PcdMaximumUnicodeStringLength Unicode + characters, not including the + Null-terminator. + @retval RETURN_UNSUPPORTED If the number represented by String exceeds + the range defined by UINT64. + +**/ +RETURN_STATUS +StrDecimalToUint64S ( + CONST CHAR16 *String, + CHAR16 **EndPointer, OPTIONAL + UINT64 *Data + ) +{ + ASSERT (((UINTN) String & BIT0) == 0); + + // + // 1. Neither String nor Data shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Data != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. The length of String shall not be greater than RSIZE_MAX. + // + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((StrnLenS (String, RSIZE_MAX + 1) <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + + // + // Ignore the pad spaces (space or tab) + // + while ((*String == L' ') || (*String == L'\t')) { + String++; + } + + // + // Ignore leading Zeros after the spaces + // + while (*String == L'0') { + String++; + } + + *Data = 0; + + while (InternalIsDecimalDigitCharacter (*String)) { + // + // If the number represented by String overflows according to the range + // defined by UINT64, then MAX_UINT64 is stored in *Data and + // RETURN_UNSUPPORTED is returned. + // + if (*Data > ((MAX_UINT64 - (*String - L'0'))/10)) { + *Data = MAX_UINT64; + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + return RETURN_UNSUPPORTED; + } + + *Data = (*Data) * 10 + (*String - L'0'); + String++; + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + return RETURN_SUCCESS; +} + +/** + Convert a Null-terminated Unicode hexadecimal string to a value of type + UINT64. + + This function outputs a value of type UINT64 by interpreting the contents of + the Unicode string specified by String as a hexadecimal number. The format of + the input Unicode string String is: + + [spaces][zeros][x][hexadecimal digits]. + + The valid hexadecimal digit character is in the range [0-9], [a-f] and [A-F]. + The prefix "0x" is optional. Both "x" and "X" is allowed in "0x" prefix. + If "x" appears in the input string, it must be prefixed with at least one 0. + The function will ignore the pad space, which includes spaces or tab + characters, before [zeros], [x] or [hexadecimal digit]. The running zero + before [x] or [hexadecimal digit] will be ignored. Then, the decoding starts + after [x] or the first valid hexadecimal digit. Then, the function stops at + the first character that is a not a valid hexadecimal character or NULL, + whichever one comes first. + + If String is NULL, then ASSERT(). + If Data is NULL, then ASSERT(). + If String is not aligned in a 16-bit boundary, then ASSERT(). + If PcdMaximumUnicodeStringLength is not zero, and String contains more than + PcdMaximumUnicodeStringLength Unicode characters, not including the + Null-terminator, then ASSERT(). + + If String has no valid hexadecimal digits in the above format, then 0 is + stored at the location pointed to by Data. + If the number represented by String exceeds the range defined by UINT64, then + MAX_UINT64 is stored at the location pointed to by Data. + + If EndPointer is not NULL, a pointer to the character that stopped the scan + is stored at the location pointed to by EndPointer. If String has no valid + hexadecimal digits right after the optional pad spaces, the value of String + is stored at the location pointed to by EndPointer. + + @param String Pointer to a Null-terminated Unicode string. + @param EndPointer Pointer to character that stops scan. + @param Data Pointer to the converted value. + + @retval RETURN_SUCCESS Value is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + If PcdMaximumUnicodeStringLength is not + zero, and String contains more than + PcdMaximumUnicodeStringLength Unicode + characters, not including the + Null-terminator. + @retval RETURN_UNSUPPORTED If the number represented by String exceeds + the range defined by UINT64. + +**/ +RETURN_STATUS +StrHexToUint64S ( + CONST CHAR16 *String, + CHAR16 **EndPointer, OPTIONAL + UINT64 *Data + ) +{ + ASSERT (((UINTN) String & BIT0) == 0); + + // + // 1. Neither String nor Data shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Data != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. The length of String shall not be greater than RSIZE_MAX. + // + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((StrnLenS (String, RSIZE_MAX + 1) <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + + // + // Ignore the pad spaces (space or tab) + // + while ((*String == L' ') || (*String == L'\t')) { + String++; + } + + // + // Ignore leading Zeros after the spaces + // + while (*String == L'0') { + String++; + } + + if (InternalCharToUpper (*String) == L'X') { + if (*(String - 1) != L'0') { + *Data = 0; + return RETURN_SUCCESS; + } + // + // Skip the 'X' + // + String++; + } + + *Data = 0; + + while (InternalIsHexaDecimalDigitCharacter (*String)) { + // + // If the number represented by String overflows according to the range + // defined by UINT64, then MAX_UINT64 is stored in *Data and + // RETURN_UNSUPPORTED is returned. + // + if (*Data > ((MAX_UINT64 - InternalHexCharToUintn (*String))>>4)) { + *Data = MAX_UINT64; + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + return RETURN_UNSUPPORTED; + } + + *Data = ((*Data) << 4) + InternalHexCharToUintn (*String); + String++; + } + + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) String; + } + return RETURN_SUCCESS; +} + +UINT64 +StrDecimalToUint64 ( + CONST CHAR16 *String + ) +{ + UINT64 Result; + + StrDecimalToUint64S (String, (CHAR16 **) NULL, &Result); + return Result; +} + + +UINT64 +StrHexToUint64 ( + CONST CHAR16 *String + ) +{ + UINT64 Result; + + StrHexToUint64S (String, (CHAR16 **) NULL, &Result); + return Result; +} + +UINTN +StrSize ( + CONST CHAR16 *String + ) +{ + return (StrLen (String) + 1) * sizeof (*String); +} + + +UINT64 +ReadUnaligned64 ( + CONST UINT64 *Buffer + ) +{ + ASSERT (Buffer != NULL); + + return *Buffer; +} + +UINT64 +WriteUnaligned64 ( + UINT64 *Buffer, + UINT64 Value + ) +{ + ASSERT (Buffer != NULL); + + return *Buffer = Value; +} + + +EFI_GUID * +CopyGuid ( + EFI_GUID *DestinationGuid, + CONST EFI_GUID *SourceGuid + ) +{ + WriteUnaligned64 ( + (UINT64*)DestinationGuid, + ReadUnaligned64 ((CONST UINT64*)SourceGuid) + ); + WriteUnaligned64 ( + (UINT64*)DestinationGuid + 1, + ReadUnaligned64 ((CONST UINT64*)SourceGuid + 1) + ); + return DestinationGuid; +} + +UINT16 +SwapBytes16 ( + UINT16 Value + ) +{ + return (UINT16) ((Value<< 8) | (Value>> 8)); +} + + +UINT32 +SwapBytes32 ( + UINT32 Value + ) +{ + UINT32 LowerBytes; + UINT32 HigherBytes; + + LowerBytes = (UINT32) SwapBytes16 ((UINT16) Value); + HigherBytes = (UINT32) SwapBytes16 ((UINT16) (Value >> 16)); + return (LowerBytes << 16 | HigherBytes); +} + +BOOLEAN +InternalIsDecimalDigitCharacter ( + CHAR16 Char + ) +{ + return (BOOLEAN) (Char >= L'0' && Char <= L'9'); +} + +VOID * +InternalAllocateCopyPool ( + UINTN AllocationSize, + CONST VOID *Buffer + ) +{ + VOID *Memory; + + ASSERT (Buffer != NULL); + + Memory = malloc (AllocationSize); + if (Memory != NULL) { + Memory = memcpy (Memory, Buffer, AllocationSize); + } + return Memory; +} + +BOOLEAN +InternalIsHexaDecimalDigitCharacter ( + CHAR16 Char + ) +{ + + return (BOOLEAN) (InternalIsDecimalDigitCharacter (Char) || + (Char >= L'A' && Char <= L'F') || + (Char >= L'a' && Char <= L'f')); +} + +UINTN +InternalHexCharToUintn ( + CHAR16 Char + ) +{ + if (InternalIsDecimalDigitCharacter (Char)) { + return Char - L'0'; + } + + return (10 + InternalCharToUpper (Char) - L'A'); +} + + +/** + Convert a Null-terminated Unicode hexadecimal string to a byte array. + + This function outputs a byte array by interpreting the contents of + the Unicode string specified by String in hexadecimal format. The format of + the input Unicode string String is: + + [XX]* + + X is a hexadecimal digit character in the range [0-9], [a-f] and [A-F]. + The function decodes every two hexadecimal digit characters as one byte. The + decoding stops after Length of characters and outputs Buffer containing + (Length / 2) bytes. + + If String is not aligned in a 16-bit boundary, then ASSERT(). + + If String is NULL, then ASSERT(). + + If Buffer is NULL, then ASSERT(). + + If Length is not multiple of 2, then ASSERT(). + + If PcdMaximumUnicodeStringLength is not zero and Length is greater than + PcdMaximumUnicodeStringLength, then ASSERT(). + + If MaxBufferSize is less than (Length / 2), then ASSERT(). + + @param String Pointer to a Null-terminated Unicode string. + @param Length The number of Unicode characters to decode. + @param Buffer Pointer to the converted bytes array. + @param MaxBufferSize The maximum size of Buffer. + + @retval RETURN_SUCCESS Buffer is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + If Length is not multiple of 2. + If PcdMaximumUnicodeStringLength is not zero, + and Length is greater than + PcdMaximumUnicodeStringLength. + @retval RETURN_UNSUPPORTED If Length of characters from String contain + a character that is not valid hexadecimal + digit characters, or a Null-terminator. + @retval RETURN_BUFFER_TOO_SMALL If MaxBufferSize is less than (Length / 2). +**/ +RETURN_STATUS +StrHexToBytes ( + CONST CHAR16 *String, + UINTN Length, + UINT8 *Buffer, + UINTN MaxBufferSize + ) +{ + UINTN Index; + + ASSERT (((UINTN) String & BIT0) == 0); + + // + // 1. None of String or Buffer shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Buffer != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. Length shall not be greater than RSIZE_MAX. + // + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((Length <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + // + // 3. Length shall not be odd. + // + SAFE_STRING_CONSTRAINT_CHECK (((Length & BIT0) == 0), RETURN_INVALID_PARAMETER); + + // + // 4. MaxBufferSize shall equal to or greater than Length / 2. + // + SAFE_STRING_CONSTRAINT_CHECK ((MaxBufferSize >= Length / 2), RETURN_BUFFER_TOO_SMALL); + + // + // 5. String shall not contains invalid hexadecimal digits. + // + for (Index = 0; Index < Length; Index++) { + if (!InternalIsHexaDecimalDigitCharacter (String[Index])) { + break; + } + } + if (Index != Length) { + return RETURN_UNSUPPORTED; + } + + // + // Convert the hex string to bytes. + // + for(Index = 0; Index < Length; Index++) { + + // + // For even characters, write the upper nibble for each buffer byte, + // and for even characters, the lower nibble. + // + if ((Index & BIT0) == 0) { + Buffer[Index / 2] = (UINT8) InternalHexCharToUintn (String[Index]) << 4; + } else { + Buffer[Index / 2] |= (UINT8) InternalHexCharToUintn (String[Index]); + } + } + return RETURN_SUCCESS; +} + +/** + Convert a Null-terminated Unicode GUID string to a value of type + EFI_GUID. + + This function outputs a GUID value by interpreting the contents of + the Unicode string specified by String. The format of the input + Unicode string String consists of 36 characters, as follows: + + aabbccdd-eeff-gghh-iijj-kkllmmnnoopp + + The pairs aa - pp are two characters in the range [0-9], [a-f] and + [A-F], with each pair representing a single byte hexadecimal value. + + The mapping between String and the EFI_GUID structure is as follows: + aa Data1[24:31] + bb Data1[16:23] + cc Data1[8:15] + dd Data1[0:7] + ee Data2[8:15] + ff Data2[0:7] + gg Data3[8:15] + hh Data3[0:7] + ii Data4[0:7] + jj Data4[8:15] + kk Data4[16:23] + ll Data4[24:31] + mm Data4[32:39] + nn Data4[40:47] + oo Data4[48:55] + pp Data4[56:63] + + If String is NULL, then ASSERT(). + If Guid is NULL, then ASSERT(). + If String is not aligned in a 16-bit boundary, then ASSERT(). + + @param String Pointer to a Null-terminated Unicode string. + @param Guid Pointer to the converted GUID. + + @retval RETURN_SUCCESS Guid is translated from String. + @retval RETURN_INVALID_PARAMETER If String is NULL. + If Data is NULL. + @retval RETURN_UNSUPPORTED If String is not as the above format. + +**/ +RETURN_STATUS +StrToGuid ( + CONST CHAR16 *String, + EFI_GUID *Guid + ) +{ + RETURN_STATUS Status; + EFI_GUID LocalGuid; + + ASSERT (((UINTN) String & BIT0) == 0); + + // + // 1. None of String or Guid shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Guid != NULL), RETURN_INVALID_PARAMETER); + + // + // Get aabbccdd in big-endian. + // + Status = StrHexToBytes (String, 2 * sizeof (LocalGuid.Data1), (UINT8 *) &LocalGuid.Data1, sizeof (LocalGuid.Data1)); + if (RETURN_ERROR (Status) || String[2 * sizeof (LocalGuid.Data1)] != L'-') { + return RETURN_UNSUPPORTED; + } + // + // Convert big-endian to little-endian. + // + LocalGuid.Data1 = SwapBytes32 (LocalGuid.Data1); + String += 2 * sizeof (LocalGuid.Data1) + 1; + + // + // Get eeff in big-endian. + // + Status = StrHexToBytes (String, 2 * sizeof (LocalGuid.Data2), (UINT8 *) &LocalGuid.Data2, sizeof (LocalGuid.Data2)); + if (RETURN_ERROR (Status) || String[2 * sizeof (LocalGuid.Data2)] != L'-') { + return RETURN_UNSUPPORTED; + } + // + // Convert big-endian to little-endian. + // + LocalGuid.Data2 = SwapBytes16 (LocalGuid.Data2); + String += 2 * sizeof (LocalGuid.Data2) + 1; + + // + // Get gghh in big-endian. + // + Status = StrHexToBytes (String, 2 * sizeof (LocalGuid.Data3), (UINT8 *) &LocalGuid.Data3, sizeof (LocalGuid.Data3)); + if (RETURN_ERROR (Status) || String[2 * sizeof (LocalGuid.Data3)] != L'-') { + return RETURN_UNSUPPORTED; + } + // + // Convert big-endian to little-endian. + // + LocalGuid.Data3 = SwapBytes16 (LocalGuid.Data3); + String += 2 * sizeof (LocalGuid.Data3) + 1; + + // + // Get iijj. + // + Status = StrHexToBytes (String, 2 * 2, &LocalGuid.Data4[0], 2); + if (RETURN_ERROR (Status) || String[2 * 2] != L'-') { + return RETURN_UNSUPPORTED; + } + String += 2 * 2 + 1; + + // + // Get kkllmmnnoopp. + // + Status = StrHexToBytes (String, 2 * 6, &LocalGuid.Data4[2], 6); + if (RETURN_ERROR (Status)) { + return RETURN_UNSUPPORTED; + } + + CopyGuid (Guid, &LocalGuid); + return RETURN_SUCCESS; +} + +/** + Compares up to a specified length the contents of two Null-terminated Unicode strings, + and returns the difference between the first mismatched Unicode characters. + + This function compares the Null-terminated Unicode string FirstString to the + Null-terminated Unicode string SecondString. At most, Length Unicode + characters will be compared. If Length is 0, then 0 is returned. If + FirstString is identical to SecondString, then 0 is returned. Otherwise, the + value returned is the first mismatched Unicode character in SecondString + subtracted from the first mismatched Unicode character in FirstString. + + If Length > 0 and FirstString is NULL, then ASSERT(). + If Length > 0 and FirstString is not aligned on a 16-bit boundary, then ASSERT(). + If Length > 0 and SecondString is NULL, then ASSERT(). + If Length > 0 and SecondString is not aligned on a 16-bit boundary, then ASSERT(). + If PcdMaximumUnicodeStringLength is not zero, and Length is greater than + PcdMaximumUnicodeStringLength, then ASSERT(). + If PcdMaximumUnicodeStringLength is not zero, and FirstString contains more than + PcdMaximumUnicodeStringLength Unicode characters, not including the Null-terminator, + then ASSERT(). + If PcdMaximumUnicodeStringLength is not zero, and SecondString contains more than + PcdMaximumUnicodeStringLength Unicode characters, not including the Null-terminator, + then ASSERT(). + + @param FirstString A pointer to a Null-terminated Unicode string. + @param SecondString A pointer to a Null-terminated Unicode string. + @param Length The maximum number of Unicode characters to compare. + + @retval 0 FirstString is identical to SecondString. + @return others FirstString is not identical to SecondString. + +**/ +INTN +StrnCmp ( + CONST CHAR16 *FirstString, + CONST CHAR16 *SecondString, + UINTN Length + ) +{ + if (Length == 0) { + return 0; + } + + // + // ASSERT both strings are less long than PcdMaximumUnicodeStringLength. + // Length tests are performed inside StrLen(). + // + ASSERT (StrSize (FirstString) != 0); + ASSERT (StrSize (SecondString) != 0); + + while ((*FirstString != L'\0') && + (*SecondString != L'\0') && + (*FirstString == *SecondString) && + (Length > 1)) { + FirstString++; + SecondString++; + Length--; + } + + return *FirstString - *SecondString; +} + +VOID * +AllocateCopyPool ( + UINTN AllocationSize, + CONST VOID *Buffer + ) +{ + return InternalAllocateCopyPool (AllocationSize, Buffer); +} + +INTN +StrCmp ( + CONST CHAR16 *FirstString, + CONST CHAR16 *SecondString + ) +{ + // + // ASSERT both strings are less long than PcdMaximumUnicodeStringLength + // + ASSERT (StrSize (FirstString) != 0); + ASSERT (StrSize (SecondString) != 0); + + while ((*FirstString != L'\0') && (*FirstString == *SecondString)) { + FirstString++; + SecondString++; + } + return *FirstString - *SecondString; +} + +UINT64 +SwapBytes64 ( + UINT64 Value + ) +{ + return InternalMathSwapBytes64 (Value); +} + +UINT64 +InternalMathSwapBytes64 ( + UINT64 Operand + ) +{ + UINT64 LowerBytes; + UINT64 HigherBytes; + + LowerBytes = (UINT64) SwapBytes32 ((UINT32) Operand); + HigherBytes = (UINT64) SwapBytes32 ((UINT32) (Operand >> 32)); + + return (LowerBytes << 32 | HigherBytes); +} + +RETURN_STATUS +StrToIpv4Address ( + CONST CHAR16 *String, + CHAR16 **EndPointer, + EFI_IPv4_ADDRESS *Address, + UINT8 *PrefixLength + ) +{ + RETURN_STATUS Status; + UINTN AddressIndex; + UINT64 Uint64; + EFI_IPv4_ADDRESS LocalAddress; + UINT8 LocalPrefixLength; + CHAR16 *Pointer; + + LocalPrefixLength = MAX_UINT8; + LocalAddress.Addr[0] = 0; + + ASSERT (((UINTN) String & BIT0) == 0); + + // + // 1. None of String or Guid shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Address != NULL), RETURN_INVALID_PARAMETER); + + for (Pointer = (CHAR16 *) String, AddressIndex = 0; AddressIndex < ARRAY_SIZE (Address->Addr) + 1;) { + if (!InternalIsDecimalDigitCharacter (*Pointer)) { + // + // D or P contains invalid characters. + // + break; + } + + // + // Get D or P. + // + Status = StrDecimalToUint64S ((CONST CHAR16 *) Pointer, &Pointer, &Uint64); + if (RETURN_ERROR (Status)) { + return RETURN_UNSUPPORTED; + } + if (AddressIndex == ARRAY_SIZE (Address->Addr)) { + // + // It's P. + // + if (Uint64 > 32) { + return RETURN_UNSUPPORTED; + } + LocalPrefixLength = (UINT8) Uint64; + } else { + // + // It's D. + // + if (Uint64 > MAX_UINT8) { + return RETURN_UNSUPPORTED; + } + LocalAddress.Addr[AddressIndex] = (UINT8) Uint64; + AddressIndex++; + } + + // + // Check the '.' or '/', depending on the AddressIndex. + // + if (AddressIndex == ARRAY_SIZE (Address->Addr)) { + if (*Pointer == L'/') { + // + // '/P' is in the String. + // Skip "/" and get P in next loop. + // + Pointer++; + } else { + // + // '/P' is not in the String. + // + break; + } + } else if (AddressIndex < ARRAY_SIZE (Address->Addr)) { + if (*Pointer == L'.') { + // + // D should be followed by '.' + // + Pointer++; + } else { + return RETURN_UNSUPPORTED; + } + } + } + + if (AddressIndex < ARRAY_SIZE (Address->Addr)) { + return RETURN_UNSUPPORTED; + } + + memcpy (Address, &LocalAddress, sizeof (*Address)); + if (PrefixLength != NULL) { + *PrefixLength = LocalPrefixLength; + } + if (EndPointer != NULL) { + *EndPointer = Pointer; + } + + return RETURN_SUCCESS; +} + +RETURN_STATUS +StrToIpv6Address ( + CONST CHAR16 *String, + CHAR16 **EndPointer, + EFI_IPv6_ADDRESS *Address, + UINT8 *PrefixLength + ) +{ + RETURN_STATUS Status; + UINTN AddressIndex; + UINT64 Uint64; + EFI_IPv6_ADDRESS LocalAddress; + UINT8 LocalPrefixLength; + CONST CHAR16 *Pointer; + CHAR16 *End; + UINTN CompressStart; + BOOLEAN ExpectPrefix; + + LocalPrefixLength = MAX_UINT8; + CompressStart = ARRAY_SIZE (Address->Addr); + ExpectPrefix = FALSE; + + ASSERT (((UINTN) String & BIT0) == 0); + + // + // 1. None of String or Guid shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((String != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Address != NULL), RETURN_INVALID_PARAMETER); + + for (Pointer = String, AddressIndex = 0; AddressIndex < ARRAY_SIZE (Address->Addr) + 1;) { + if (!InternalIsHexaDecimalDigitCharacter (*Pointer)) { + if (*Pointer != L':') { + // + // ":" or "/" should be followed by digit characters. + // + return RETURN_UNSUPPORTED; + } + + // + // Meet second ":" after previous ":" or "/" + // or meet first ":" in the beginning of String. + // + if (ExpectPrefix) { + // + // ":" shall not be after "/" + // + return RETURN_UNSUPPORTED; + } + + if (CompressStart != ARRAY_SIZE (Address->Addr) || AddressIndex == ARRAY_SIZE (Address->Addr)) { + // + // "::" can only appear once. + // "::" can only appear when address is not full length. + // + return RETURN_UNSUPPORTED; + } else { + // + // Remember the start of zero compressing. + // + CompressStart = AddressIndex; + Pointer++; + + if (CompressStart == 0) { + if (*Pointer != L':') { + // + // Single ":" shall not be in the beginning of String. + // + return RETURN_UNSUPPORTED; + } + Pointer++; + } + } + } + + if (!InternalIsHexaDecimalDigitCharacter (*Pointer)) { + if (*Pointer == L'/') { + // + // Might be optional "/P" after "::". + // + if (CompressStart != AddressIndex) { + return RETURN_UNSUPPORTED; + } + } else { + break; + } + } else { + if (!ExpectPrefix) { + // + // Get X. + // + Status = StrHexToUint64S (Pointer, &End, &Uint64); + if (RETURN_ERROR (Status) || End - Pointer > 4) { + // + // Number of hexadecimal digit characters is no more than 4. + // + return RETURN_UNSUPPORTED; + } + Pointer = End; + // + // Uint64 won't exceed MAX_UINT16 if number of hexadecimal digit characters is no more than 4. + // + ASSERT (AddressIndex + 1 < ARRAY_SIZE (Address->Addr)); + LocalAddress.Addr[AddressIndex] = (UINT8) ((UINT16) Uint64 >> 8); + LocalAddress.Addr[AddressIndex + 1] = (UINT8) Uint64; + AddressIndex += 2; + } else { + // + // Get P, then exit the loop. + // + Status = StrDecimalToUint64S (Pointer, &End, &Uint64); + if (RETURN_ERROR (Status) || End == Pointer || Uint64 > 128) { + // + // Prefix length should not exceed 128. + // + return RETURN_UNSUPPORTED; + } + LocalPrefixLength = (UINT8) Uint64; + Pointer = End; + break; + } + } + + // + // Skip ':' or "/" + // + if (*Pointer == L'/') { + ExpectPrefix = TRUE; + } else if (*Pointer == L':') { + if (AddressIndex == ARRAY_SIZE (Address->Addr)) { + // + // Meet additional ":" after all 8 16-bit address + // + break; + } + } else { + // + // Meet other character that is not "/" or ":" after all 8 16-bit address + // + break; + } + Pointer++; + } + + if ((AddressIndex == ARRAY_SIZE (Address->Addr) && CompressStart != ARRAY_SIZE (Address->Addr)) || + (AddressIndex != ARRAY_SIZE (Address->Addr) && CompressStart == ARRAY_SIZE (Address->Addr)) + ) { + // + // Full length of address shall not have compressing zeros. + // Non-full length of address shall have compressing zeros. + // + return RETURN_UNSUPPORTED; + } + memcpy (&Address->Addr[0], &LocalAddress.Addr[0], CompressStart); + if (AddressIndex > CompressStart) { + memset (&Address->Addr[CompressStart], 0, ARRAY_SIZE (Address->Addr) - AddressIndex); + memcpy ( + &Address->Addr[CompressStart + ARRAY_SIZE (Address->Addr) - AddressIndex], + &LocalAddress.Addr[CompressStart], + AddressIndex - CompressStart + ); + } + + if (PrefixLength != NULL) { + *PrefixLength = LocalPrefixLength; + } + if (EndPointer != NULL) { + *EndPointer = (CHAR16 *) Pointer; + } + + return RETURN_SUCCESS; +} + + +RETURN_STATUS +UnicodeStrToAsciiStrS ( + CONST CHAR16 *Source, + CHAR8 *Destination, + UINTN DestMax + ) +{ + UINTN SourceLen; + + ASSERT (((UINTN) Source & BIT0) == 0); + + // + // 1. Neither Destination nor Source shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. DestMax shall not be greater than ASCII_RSIZE_MAX or RSIZE_MAX. + // + if (ASCII_RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= ASCII_RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + // + // 3. DestMax shall not equal zero. + // + SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER); + + // + // 4. DestMax shall be greater than StrnLenS (Source, DestMax). + // + SourceLen = StrnLenS (Source, DestMax); + SAFE_STRING_CONSTRAINT_CHECK ((DestMax > SourceLen), RETURN_BUFFER_TOO_SMALL); + + // + // 5. Copying shall not take place between objects that overlap. + // + SAFE_STRING_CONSTRAINT_CHECK (!InternalSafeStringIsOverlap (Destination, DestMax, (VOID *)Source, (SourceLen + 1) * sizeof(CHAR16)), RETURN_ACCESS_DENIED); + + // + // convert string + // + while (*Source != '\0') { + // + // If any Unicode characters in Source contain + // non-zero value in the upper 8 bits, then ASSERT(). + // + ASSERT (*Source < 0x100); + *(Destination++) = (CHAR8) *(Source++); + } + *Destination = '\0'; + + return RETURN_SUCCESS; +} + +RETURN_STATUS +StrCpyS ( + CHAR16 *Destination, + UINTN DestMax, + CONST CHAR16 *Source + ) +{ + UINTN SourceLen; + + ASSERT (((UINTN) Destination & BIT0) == 0); + ASSERT (((UINTN) Source & BIT0) == 0); + + // + // 1. Neither Destination nor Source shall be a null pointer. + // + SAFE_STRING_CONSTRAINT_CHECK ((Destination != NULL), RETURN_INVALID_PARAMETER); + SAFE_STRING_CONSTRAINT_CHECK ((Source != NULL), RETURN_INVALID_PARAMETER); + + // + // 2. DestMax shall not be greater than RSIZE_MAX. + // + if (RSIZE_MAX != 0) { + SAFE_STRING_CONSTRAINT_CHECK ((DestMax <= RSIZE_MAX), RETURN_INVALID_PARAMETER); + } + + // + // 3. DestMax shall not equal zero. + // + SAFE_STRING_CONSTRAINT_CHECK ((DestMax != 0), RETURN_INVALID_PARAMETER); + + // + // 4. DestMax shall be greater than StrnLenS(Source, DestMax). + // + SourceLen = StrnLenS (Source, DestMax); + SAFE_STRING_CONSTRAINT_CHECK ((DestMax > SourceLen), RETURN_BUFFER_TOO_SMALL); + + // + // 5. Copying shall not take place between objects that overlap. + // + SAFE_STRING_CONSTRAINT_CHECK (InternalSafeStringNoStrOverlap (Destination, DestMax, (CHAR16 *)Source, SourceLen + 1), RETURN_ACCESS_DENIED); + + // + // The StrCpyS function copies the string pointed to by Source (including the terminating + // null character) into the array pointed to by Destination. + // + while (*Source != 0) { + *(Destination++) = *(Source++); + } + *Destination = 0; + + return RETURN_SUCCESS; +} + +VOID * +AllocateZeroPool ( + UINTN AllocationSize + ) +{ + VOID * Memory; + Memory = malloc(AllocationSize); + ASSERT (Memory != NULL); + if (Memory == NULL) { + fprintf(stderr, "Not memory for malloc\n"); + } + memset(Memory, 0, AllocationSize); + return Memory; +} + +VOID * +AllocatePool ( + UINTN AllocationSize + ) +{ + return InternalAllocatePool (AllocationSize); +} + +UINT16 +WriteUnaligned16 ( + UINT16 *Buffer, + UINT16 Value + ) +{ + ASSERT (Buffer != NULL); + + return *Buffer = Value; +} + +UINT16 +ReadUnaligned16 ( + CONST UINT16 *Buffer + ) +{ + ASSERT (Buffer != NULL); + + return *Buffer; +} +/** + Return whether the integer string is a hex string. + + @param Str The integer string + + @retval TRUE Hex string + @retval FALSE Decimal string + +**/ +BOOLEAN +IsHexStr ( + CHAR16 *Str + ) +{ + // + // skip preceding white space + // + while ((*Str != 0) && *Str == L' ') { + Str ++; + } + // + // skip preceding zeros + // + while ((*Str != 0) && *Str == L'0') { + Str ++; + } + + return (BOOLEAN) (*Str == L'x' || *Str == L'X'); +} + +/** + + Convert integer string to uint. + + @param Str The integer string. If leading with "0x" or "0X", it's hexadecimal. + + @return A UINTN value represented by Str + +**/ +UINTN +Strtoi ( + CHAR16 *Str + ) +{ + if (IsHexStr (Str)) { + return (UINTN)StrHexToUint64 (Str); + } else { + return (UINTN)StrDecimalToUint64 (Str); + } +} + +/** + + Convert integer string to 64 bit data. + + @param Str The integer string. If leading with "0x" or "0X", it's hexadecimal. + @param Data A pointer to the UINT64 value represented by Str + +**/ +VOID +Strtoi64 ( + CHAR16 *Str, + UINT64 *Data + ) +{ + if (IsHexStr (Str)) { + *Data = StrHexToUint64 (Str); + } else { + *Data = StrDecimalToUint64 (Str); + } +} + +/** + Converts a Unicode string to ASCII string. + + @param Str The equivalent Unicode string + @param AsciiStr On input, it points to destination ASCII string buffer; on output, it points + to the next ASCII string next to it + +**/ +VOID +StrToAscii ( + CHAR16 *Str, + CHAR8 **AsciiStr + ) +{ + CHAR8 *Dest; + + Dest = *AsciiStr; + while (!IS_NULL (*Str)) { + *(Dest++) = (CHAR8) *(Str++); + } + *Dest = 0; + + // + // Return the string next to it + // + *AsciiStr = Dest + 1; +} + +/** + Gets current sub-string from a string list, before return + the list header is moved to next sub-string. The sub-string is separated + by the specified character. For example, the separator is ',', the string + list is "2,0,3", it returns "2", the remain list move to "0,3" + + @param List A string list separated by the specified separator + @param Separator The separator character + + @return A pointer to the current sub-string + +**/ +CHAR16 * +SplitStr ( + CHAR16 **List, + CHAR16 Separator + ) +{ + CHAR16 *Str; + CHAR16 *ReturnStr; + + Str = *List; + ReturnStr = Str; + + if (IS_NULL (*Str)) { + return ReturnStr; + } + + // + // Find first occurrence of the separator + // + while (!IS_NULL (*Str)) { + if (*Str == Separator) { + break; + } + Str++; + } + + if (*Str == Separator) { + // + // Find a sub-string, terminate it + // + *Str = L'\0'; + Str++; + } + + // + // Move to next sub-string + // + *List = Str; + return ReturnStr; +} diff --git a/BaseTools/Source/C/Common/CommonLib.h b/BaseTools/Source/C/Common/CommonLib.h index a841029c2a..5a3f114940 100644 --- a/BaseTools/Source/C/Common/CommonLib.h +++ b/BaseTools/Source/C/Common/CommonLib.h @@ -1,469 +1,469 @@ -/** @file
-Common library assistance routines.
-
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _EFI_COMMON_LIB_H
-#define _EFI_COMMON_LIB_H
-
-#include <Common/UefiBaseTypes.h>
-#include <Common/BuildVersion.h>
-#include <assert.h>
-#ifndef _WIN32
-#include <limits.h>
-#endif
-
-#define PRINTED_GUID_BUFFER_SIZE 37 // including null-termination
-
-#ifdef PATH_MAX
-#define MAX_LONG_FILE_PATH PATH_MAX
-#else
-#define MAX_LONG_FILE_PATH 500
-#endif
-
-#define MAX_UINT64 ((UINT64)0xFFFFFFFFFFFFFFFFULL)
-#define MAX_UINT32 ((UINT32)0xFFFFFFFF)
-#define MAX_UINT16 ((UINT16)0xFFFF)
-#define MAX_UINT8 ((UINT8)0xFF)
-#define ARRAY_SIZE(Array) (sizeof (Array) / sizeof ((Array)[0]))
-#define ASCII_RSIZE_MAX 1000000
-#undef RSIZE_MAX
-#define RSIZE_MAX 1000000
-
-#define IS_COMMA(a) ((a) == L',')
-#define IS_HYPHEN(a) ((a) == L'-')
-#define IS_DOT(a) ((a) == L'.')
-#define IS_LEFT_PARENTH(a) ((a) == L'(')
-#define IS_RIGHT_PARENTH(a) ((a) == L')')
-#define IS_SLASH(a) ((a) == L'/')
-#define IS_NULL(a) ((a) == L'\0')
-
-#define ASSERT(x) assert(x)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-//
-// Function declarations
-//
-VOID
-PeiZeroMem (
- IN VOID *Buffer,
- IN UINTN Size
- )
-;
-
-VOID
-PeiCopyMem (
- IN VOID *Destination,
- IN VOID *Source,
- IN UINTN Length
- )
-;
-
-VOID
-ZeroMem (
- IN VOID *Buffer,
- IN UINTN Size
- )
-;
-
-VOID
-CopyMem (
- IN VOID *Destination,
- IN VOID *Source,
- IN UINTN Length
- )
-;
-
-INTN
-CompareGuid (
- IN EFI_GUID *Guid1,
- IN EFI_GUID *Guid2
- )
-;
-
-EFI_STATUS
-GetFileImage (
- IN CHAR8 *InputFileName,
- OUT CHAR8 **InputFileImage,
- OUT UINT32 *BytesRead
- )
-;
-
-/*++
-
-Routine Description:
-
- This function opens a file and writes OutputFileImage into the file.
-
-Arguments:
-
- OutputFileName The name of the file to write.
- OutputFileImage A pointer to the memory buffer.
- BytesToWrite The size of the memory buffer.
-
-Returns:
-
- EFI_SUCCESS The function completed successfully.
- EFI_INVALID_PARAMETER One of the input parameters was invalid.
- EFI_ABORTED An error occurred.
- EFI_OUT_OF_RESOURCES No resource to complete operations.
-
-**/
-EFI_STATUS
-PutFileImage (
- IN CHAR8 *OutputFileName,
- IN CHAR8 *OutputFileImage,
- IN UINT32 BytesToWrite
- )
-;
-
-UINT8
-CalculateChecksum8 (
- IN UINT8 *Buffer,
- IN UINTN Size
- )
-;
-
-UINT8
-CalculateSum8 (
- IN UINT8 *Buffer,
- IN UINTN Size
- )
-;
-
-UINT16
-CalculateChecksum16 (
- IN UINT16 *Buffer,
- IN UINTN Size
- )
-;
-
-UINT16
-CalculateSum16 (
- IN UINT16 *Buffer,
- IN UINTN Size
- )
-;
-
-EFI_STATUS
-PrintGuid (
- IN EFI_GUID *Guid
- )
-;
-
-#define PRINTED_GUID_BUFFER_SIZE 37 // including null-termination
-EFI_STATUS
-PrintGuidToBuffer (
- IN EFI_GUID *Guid,
- IN OUT UINT8 *Buffer,
- IN UINT32 BufferLen,
- IN BOOLEAN Uppercase
- )
-;
-
-CHAR8 *
-LongFilePath (
- IN CHAR8 *FileName
-);
-
-UINTN
-StrLen (
- CONST CHAR16 *String
- );
-
-VOID *
-AllocateCopyPool (
- UINTN AllocationSize,
- CONST VOID *Buffer
- );
-
-INTN
-StrnCmp (
- CONST CHAR16 *FirstString,
- CONST CHAR16 *SecondString,
- UINTN Length
- );
-
-RETURN_STATUS
-StrToGuid (
- CONST CHAR16 *String,
- EFI_GUID *Guid
- );
-
-RETURN_STATUS
-StrHexToBytes (
- CONST CHAR16 *String,
- UINTN Length,
- UINT8 *Buffer,
- UINTN MaxBufferSize
- );
-
-UINTN
-InternalHexCharToUintn (
- CHAR16 Char
- );
-
-VOID *
-InternalAllocateCopyPool (
- UINTN AllocationSize,
- CONST VOID *Buffer
- );
-
-BOOLEAN
-InternalIsDecimalDigitCharacter (
- CHAR16 Char
- );
-
-UINT32
-SwapBytes32 (
- UINT32 Value
- );
-
-UINT16
-SwapBytes16 (
- UINT16 Value
- );
-
-EFI_GUID *
-CopyGuid (
- EFI_GUID *DestinationGuid,
- CONST EFI_GUID *SourceGuid
- );
-
-UINT64
-WriteUnaligned64 (
- UINT64 *Buffer,
- UINT64 Value
- );
-
-UINT64
-ReadUnaligned64 (
- CONST UINT64 *Buffer
- );
-
-UINTN
-StrSize (
- CONST CHAR16 *String
- );
-
-UINT64
-StrHexToUint64 (
- CONST CHAR16 *String
- );
-
-UINT64
-StrDecimalToUint64 (
- CONST CHAR16 *String
- );
-
-RETURN_STATUS
-StrHexToUint64S (
- CONST CHAR16 *String,
- CHAR16 **EndPointer,
- UINT64 *Data
- );
-
-RETURN_STATUS
-StrDecimalToUint64S (
- CONST CHAR16 *String,
- CHAR16 **EndPointer, OPTIONAL
- UINT64 *Data
- );
-
-VOID *
-ReallocatePool (
- UINTN OldSize,
- UINTN NewSize,
- VOID *OldBuffer OPTIONAL
- );
-
-VOID *
-InternalReallocatePool (
- UINTN OldSize,
- UINTN NewSize,
- VOID *OldBuffer OPTIONAL
- );
-
-VOID *
-InternalAllocateZeroPool (
- UINTN AllocationSize
- ) ;
-
-VOID *
-InternalAllocatePool (
- UINTN AllocationSize
- );
-
-UINTN
-StrnLenS (
- CONST CHAR16 *String,
- UINTN MaxSize
- );
-
-CHAR16
-InternalCharToUpper (
- CHAR16 Char
- );
-
-INTN
-StrCmp (
- CONST CHAR16 *FirstString,
- CONST CHAR16 *SecondString
- );
-
-UINT64
-SwapBytes64 (
- UINT64 Value
- );
-
-UINT64
-InternalMathSwapBytes64 (
- UINT64 Operand
- );
-
-RETURN_STATUS
-StrToIpv4Address (
- CONST CHAR16 *String,
- CHAR16 **EndPointer,
- EFI_IPv4_ADDRESS *Address,
- UINT8 *PrefixLength
- );
-
-RETURN_STATUS
-StrToIpv6Address (
- CONST CHAR16 *String,
- CHAR16 **EndPointer,
- EFI_IPv6_ADDRESS *Address,
- UINT8 *PrefixLength
- );
-
-RETURN_STATUS
-StrCpyS (
- CHAR16 *Destination,
- UINTN DestMax,
- CONST CHAR16 *Source
- );
-
-RETURN_STATUS
-UnicodeStrToAsciiStrS (
- CONST CHAR16 *Source,
- CHAR8 *Destination,
- UINTN DestMax
- );
-VOID *
-AllocatePool (
- UINTN AllocationSize
- );
-
-UINT16
-WriteUnaligned16 (
- UINT16 *Buffer,
- UINT16 Value
- );
-
-UINT16
-ReadUnaligned16 (
- CONST UINT16 *Buffer
- );
-
-VOID *
-AllocateZeroPool (
- UINTN AllocationSize
- );
-
-BOOLEAN
-InternalIsHexaDecimalDigitCharacter (
- CHAR16 Char
- );
-
-BOOLEAN
-InternalSafeStringIsOverlap (
- IN VOID *Base1,
- IN UINTN Size1,
- IN VOID *Base2,
- IN UINTN Size2
- );
-
-BOOLEAN
-InternalSafeStringNoStrOverlap (
- IN CHAR16 *Str1,
- IN UINTN Size1,
- IN CHAR16 *Str2,
- IN UINTN Size2
- );
-
-BOOLEAN
-IsHexStr (
- CHAR16 *Str
- );
-
-UINTN
-Strtoi (
- CHAR16 *Str
- );
-
-VOID
-Strtoi64 (
- CHAR16 *Str,
- UINT64 *Data
- );
-
-VOID
-StrToAscii (
- CHAR16 *Str,
- CHAR8 **AsciiStr
- );
-
-CHAR16 *
-SplitStr (
- CHAR16 **List,
- CHAR16 Separator
- );
-
-/*++
-
-Routine Description:
- Convert FileName to the long file path, which can support larger than 260 length.
-
-Arguments:
- FileName - FileName.
-
-Returns:
- LongFilePath A pointer to the converted long file path.
-
---*/
-
-#ifdef __cplusplus
-}
-#endif
-
-#ifdef __GNUC__
-#include <stdio.h>
-#include <sys/stat.h>
-#define stricmp strcasecmp
-#define _stricmp strcasecmp
-#define strnicmp strncasecmp
-#define strcmpi strcasecmp
-size_t _filelength(int fd);
-#ifndef __CYGWIN__
-char *strlwr(char *s);
-#endif
-#endif
-
-//
-// On windows, mkdir only has one parameter.
-// On unix, it has two parameters
-//
-#if defined(__GNUC__)
-#define mkdir(dir, perm) mkdir(dir, perm)
-#else
-#define mkdir(dir, perm) mkdir(dir)
-#endif
-
-#endif
+/** @file +Common library assistance routines. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_COMMON_LIB_H +#define _EFI_COMMON_LIB_H + +#include <Common/UefiBaseTypes.h> +#include <Common/BuildVersion.h> +#include <assert.h> +#ifndef _WIN32 +#include <limits.h> +#endif + +#define PRINTED_GUID_BUFFER_SIZE 37 // including null-termination + +#ifdef PATH_MAX +#define MAX_LONG_FILE_PATH PATH_MAX +#else +#define MAX_LONG_FILE_PATH 500 +#endif + +#define MAX_UINT64 ((UINT64)0xFFFFFFFFFFFFFFFFULL) +#define MAX_UINT32 ((UINT32)0xFFFFFFFF) +#define MAX_UINT16 ((UINT16)0xFFFF) +#define MAX_UINT8 ((UINT8)0xFF) +#define ARRAY_SIZE(Array) (sizeof (Array) / sizeof ((Array)[0])) +#define ASCII_RSIZE_MAX 1000000 +#undef RSIZE_MAX +#define RSIZE_MAX 1000000 + +#define IS_COMMA(a) ((a) == L',') +#define IS_HYPHEN(a) ((a) == L'-') +#define IS_DOT(a) ((a) == L'.') +#define IS_LEFT_PARENTH(a) ((a) == L'(') +#define IS_RIGHT_PARENTH(a) ((a) == L')') +#define IS_SLASH(a) ((a) == L'/') +#define IS_NULL(a) ((a) == L'\0') + +#define ASSERT(x) assert(x) + +#ifdef __cplusplus +extern "C" { +#endif + +// +// Function declarations +// +VOID +PeiZeroMem ( + IN VOID *Buffer, + IN UINTN Size + ) +; + +VOID +PeiCopyMem ( + IN VOID *Destination, + IN VOID *Source, + IN UINTN Length + ) +; + +VOID +ZeroMem ( + IN VOID *Buffer, + IN UINTN Size + ) +; + +VOID +CopyMem ( + IN VOID *Destination, + IN VOID *Source, + IN UINTN Length + ) +; + +INTN +CompareGuid ( + IN EFI_GUID *Guid1, + IN EFI_GUID *Guid2 + ) +; + +EFI_STATUS +GetFileImage ( + IN CHAR8 *InputFileName, + OUT CHAR8 **InputFileImage, + OUT UINT32 *BytesRead + ) +; + +/*++ + +Routine Description: + + This function opens a file and writes OutputFileImage into the file. + +Arguments: + + OutputFileName The name of the file to write. + OutputFileImage A pointer to the memory buffer. + BytesToWrite The size of the memory buffer. + +Returns: + + EFI_SUCCESS The function completed successfully. + EFI_INVALID_PARAMETER One of the input parameters was invalid. + EFI_ABORTED An error occurred. + EFI_OUT_OF_RESOURCES No resource to complete operations. + +**/ +EFI_STATUS +PutFileImage ( + IN CHAR8 *OutputFileName, + IN CHAR8 *OutputFileImage, + IN UINT32 BytesToWrite + ) +; + +UINT8 +CalculateChecksum8 ( + IN UINT8 *Buffer, + IN UINTN Size + ) +; + +UINT8 +CalculateSum8 ( + IN UINT8 *Buffer, + IN UINTN Size + ) +; + +UINT16 +CalculateChecksum16 ( + IN UINT16 *Buffer, + IN UINTN Size + ) +; + +UINT16 +CalculateSum16 ( + IN UINT16 *Buffer, + IN UINTN Size + ) +; + +EFI_STATUS +PrintGuid ( + IN EFI_GUID *Guid + ) +; + +#define PRINTED_GUID_BUFFER_SIZE 37 // including null-termination +EFI_STATUS +PrintGuidToBuffer ( + IN EFI_GUID *Guid, + IN OUT UINT8 *Buffer, + IN UINT32 BufferLen, + IN BOOLEAN Uppercase + ) +; + +CHAR8 * +LongFilePath ( + IN CHAR8 *FileName +); + +UINTN +StrLen ( + CONST CHAR16 *String + ); + +VOID * +AllocateCopyPool ( + UINTN AllocationSize, + CONST VOID *Buffer + ); + +INTN +StrnCmp ( + CONST CHAR16 *FirstString, + CONST CHAR16 *SecondString, + UINTN Length + ); + +RETURN_STATUS +StrToGuid ( + CONST CHAR16 *String, + EFI_GUID *Guid + ); + +RETURN_STATUS +StrHexToBytes ( + CONST CHAR16 *String, + UINTN Length, + UINT8 *Buffer, + UINTN MaxBufferSize + ); + +UINTN +InternalHexCharToUintn ( + CHAR16 Char + ); + +VOID * +InternalAllocateCopyPool ( + UINTN AllocationSize, + CONST VOID *Buffer + ); + +BOOLEAN +InternalIsDecimalDigitCharacter ( + CHAR16 Char + ); + +UINT32 +SwapBytes32 ( + UINT32 Value + ); + +UINT16 +SwapBytes16 ( + UINT16 Value + ); + +EFI_GUID * +CopyGuid ( + EFI_GUID *DestinationGuid, + CONST EFI_GUID *SourceGuid + ); + +UINT64 +WriteUnaligned64 ( + UINT64 *Buffer, + UINT64 Value + ); + +UINT64 +ReadUnaligned64 ( + CONST UINT64 *Buffer + ); + +UINTN +StrSize ( + CONST CHAR16 *String + ); + +UINT64 +StrHexToUint64 ( + CONST CHAR16 *String + ); + +UINT64 +StrDecimalToUint64 ( + CONST CHAR16 *String + ); + +RETURN_STATUS +StrHexToUint64S ( + CONST CHAR16 *String, + CHAR16 **EndPointer, + UINT64 *Data + ); + +RETURN_STATUS +StrDecimalToUint64S ( + CONST CHAR16 *String, + CHAR16 **EndPointer, OPTIONAL + UINT64 *Data + ); + +VOID * +ReallocatePool ( + UINTN OldSize, + UINTN NewSize, + VOID *OldBuffer OPTIONAL + ); + +VOID * +InternalReallocatePool ( + UINTN OldSize, + UINTN NewSize, + VOID *OldBuffer OPTIONAL + ); + +VOID * +InternalAllocateZeroPool ( + UINTN AllocationSize + ) ; + +VOID * +InternalAllocatePool ( + UINTN AllocationSize + ); + +UINTN +StrnLenS ( + CONST CHAR16 *String, + UINTN MaxSize + ); + +CHAR16 +InternalCharToUpper ( + CHAR16 Char + ); + +INTN +StrCmp ( + CONST CHAR16 *FirstString, + CONST CHAR16 *SecondString + ); + +UINT64 +SwapBytes64 ( + UINT64 Value + ); + +UINT64 +InternalMathSwapBytes64 ( + UINT64 Operand + ); + +RETURN_STATUS +StrToIpv4Address ( + CONST CHAR16 *String, + CHAR16 **EndPointer, + EFI_IPv4_ADDRESS *Address, + UINT8 *PrefixLength + ); + +RETURN_STATUS +StrToIpv6Address ( + CONST CHAR16 *String, + CHAR16 **EndPointer, + EFI_IPv6_ADDRESS *Address, + UINT8 *PrefixLength + ); + +RETURN_STATUS +StrCpyS ( + CHAR16 *Destination, + UINTN DestMax, + CONST CHAR16 *Source + ); + +RETURN_STATUS +UnicodeStrToAsciiStrS ( + CONST CHAR16 *Source, + CHAR8 *Destination, + UINTN DestMax + ); +VOID * +AllocatePool ( + UINTN AllocationSize + ); + +UINT16 +WriteUnaligned16 ( + UINT16 *Buffer, + UINT16 Value + ); + +UINT16 +ReadUnaligned16 ( + CONST UINT16 *Buffer + ); + +VOID * +AllocateZeroPool ( + UINTN AllocationSize + ); + +BOOLEAN +InternalIsHexaDecimalDigitCharacter ( + CHAR16 Char + ); + +BOOLEAN +InternalSafeStringIsOverlap ( + IN VOID *Base1, + IN UINTN Size1, + IN VOID *Base2, + IN UINTN Size2 + ); + +BOOLEAN +InternalSafeStringNoStrOverlap ( + IN CHAR16 *Str1, + IN UINTN Size1, + IN CHAR16 *Str2, + IN UINTN Size2 + ); + +BOOLEAN +IsHexStr ( + CHAR16 *Str + ); + +UINTN +Strtoi ( + CHAR16 *Str + ); + +VOID +Strtoi64 ( + CHAR16 *Str, + UINT64 *Data + ); + +VOID +StrToAscii ( + CHAR16 *Str, + CHAR8 **AsciiStr + ); + +CHAR16 * +SplitStr ( + CHAR16 **List, + CHAR16 Separator + ); + +/*++ + +Routine Description: + Convert FileName to the long file path, which can support larger than 260 length. + +Arguments: + FileName - FileName. + +Returns: + LongFilePath A pointer to the converted long file path. + +--*/ + +#ifdef __cplusplus +} +#endif + +#ifdef __GNUC__ +#include <stdio.h> +#include <sys/stat.h> +#define stricmp strcasecmp +#define _stricmp strcasecmp +#define strnicmp strncasecmp +#define strcmpi strcasecmp +size_t _filelength(int fd); +#ifndef __CYGWIN__ +char *strlwr(char *s); +#endif +#endif + +// +// On windows, mkdir only has one parameter. +// On unix, it has two parameters +// +#if defined(__GNUC__) +#define mkdir(dir, perm) mkdir(dir, perm) +#else +#define mkdir(dir, perm) mkdir(dir) +#endif + +#endif diff --git a/BaseTools/Source/C/Common/Compress.h b/BaseTools/Source/C/Common/Compress.h index 499e183c2b..1777345927 100644 --- a/BaseTools/Source/C/Common/Compress.h +++ b/BaseTools/Source/C/Common/Compress.h @@ -1,67 +1,67 @@ -/** @file
-Header file for compression routine.
-Providing both EFI and Tiano Compress algorithms.
-
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _COMPRESS_H_
-#define _COMPRESS_H_
-
-#include <string.h>
-#include <stdlib.h>
-
-#include "CommonLib.h"
-#include <Common/UefiBaseTypes.h>
-
-/**
- Tiano compression routine.
-**/
-EFI_STATUS
-TianoCompress (
- IN UINT8 *SrcBuffer,
- IN UINT32 SrcSize,
- IN UINT8 *DstBuffer,
- IN OUT UINT32 *DstSize
- )
-;
-
-/**
- Efi compression routine.
-**/
-EFI_STATUS
-EfiCompress (
- IN UINT8 *SrcBuffer,
- IN UINT32 SrcSize,
- IN UINT8 *DstBuffer,
- IN OUT UINT32 *DstSize
- )
-;
-
-/**
- The compression routine.
-
- @param SrcBuffer The buffer storing the source data
- @param SrcSize The size of source data
- @param DstBuffer The buffer to store the compressed data
- @param DstSize On input, the size of DstBuffer; On output,
- the size of the actual compressed data.
-
- @retval EFI_BUFFER_TOO_SMALL The DstBuffer is too small. In this case,
- DstSize contains the size needed.
- @retval EFI_SUCCESS Compression is successful.
- @retval EFI_OUT_OF_RESOURCES No resource to complete function.
- @retval EFI_INVALID_PARAMETER Parameter supplied is wrong.
-**/
-typedef
-EFI_STATUS
-(*COMPRESS_FUNCTION) (
- IN UINT8 *SrcBuffer,
- IN UINT32 SrcSize,
- IN UINT8 *DstBuffer,
- IN OUT UINT32 *DstSize
- );
-
-#endif
+/** @file +Header file for compression routine. +Providing both EFI and Tiano Compress algorithms. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _COMPRESS_H_ +#define _COMPRESS_H_ + +#include <string.h> +#include <stdlib.h> + +#include "CommonLib.h" +#include <Common/UefiBaseTypes.h> + +/** + Tiano compression routine. +**/ +EFI_STATUS +TianoCompress ( + IN UINT8 *SrcBuffer, + IN UINT32 SrcSize, + IN UINT8 *DstBuffer, + IN OUT UINT32 *DstSize + ) +; + +/** + Efi compression routine. +**/ +EFI_STATUS +EfiCompress ( + IN UINT8 *SrcBuffer, + IN UINT32 SrcSize, + IN UINT8 *DstBuffer, + IN OUT UINT32 *DstSize + ) +; + +/** + The compression routine. + + @param SrcBuffer The buffer storing the source data + @param SrcSize The size of source data + @param DstBuffer The buffer to store the compressed data + @param DstSize On input, the size of DstBuffer; On output, + the size of the actual compressed data. + + @retval EFI_BUFFER_TOO_SMALL The DstBuffer is too small. In this case, + DstSize contains the size needed. + @retval EFI_SUCCESS Compression is successful. + @retval EFI_OUT_OF_RESOURCES No resource to complete function. + @retval EFI_INVALID_PARAMETER Parameter supplied is wrong. +**/ +typedef +EFI_STATUS +(*COMPRESS_FUNCTION) ( + IN UINT8 *SrcBuffer, + IN UINT32 SrcSize, + IN UINT8 *DstBuffer, + IN OUT UINT32 *DstSize + ); + +#endif diff --git a/BaseTools/Source/C/Common/Crc32.c b/BaseTools/Source/C/Common/Crc32.c index 00cae94898..b5a154f4f2 100644 --- a/BaseTools/Source/C/Common/Crc32.c +++ b/BaseTools/Source/C/Common/Crc32.c @@ -1,305 +1,305 @@ -/** @file
-CalculateCrc32 routine.
-
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <stdlib.h>
-#include "Crc32.h"
-
-UINT32 mCrcTable[256] = {
- 0x00000000,
- 0x77073096,
- 0xEE0E612C,
- 0x990951BA,
- 0x076DC419,
- 0x706AF48F,
- 0xE963A535,
- 0x9E6495A3,
- 0x0EDB8832,
- 0x79DCB8A4,
- 0xE0D5E91E,
- 0x97D2D988,
- 0x09B64C2B,
- 0x7EB17CBD,
- 0xE7B82D07,
- 0x90BF1D91,
- 0x1DB71064,
- 0x6AB020F2,
- 0xF3B97148,
- 0x84BE41DE,
- 0x1ADAD47D,
- 0x6DDDE4EB,
- 0xF4D4B551,
- 0x83D385C7,
- 0x136C9856,
- 0x646BA8C0,
- 0xFD62F97A,
- 0x8A65C9EC,
- 0x14015C4F,
- 0x63066CD9,
- 0xFA0F3D63,
- 0x8D080DF5,
- 0x3B6E20C8,
- 0x4C69105E,
- 0xD56041E4,
- 0xA2677172,
- 0x3C03E4D1,
- 0x4B04D447,
- 0xD20D85FD,
- 0xA50AB56B,
- 0x35B5A8FA,
- 0x42B2986C,
- 0xDBBBC9D6,
- 0xACBCF940,
- 0x32D86CE3,
- 0x45DF5C75,
- 0xDCD60DCF,
- 0xABD13D59,
- 0x26D930AC,
- 0x51DE003A,
- 0xC8D75180,
- 0xBFD06116,
- 0x21B4F4B5,
- 0x56B3C423,
- 0xCFBA9599,
- 0xB8BDA50F,
- 0x2802B89E,
- 0x5F058808,
- 0xC60CD9B2,
- 0xB10BE924,
- 0x2F6F7C87,
- 0x58684C11,
- 0xC1611DAB,
- 0xB6662D3D,
- 0x76DC4190,
- 0x01DB7106,
- 0x98D220BC,
- 0xEFD5102A,
- 0x71B18589,
- 0x06B6B51F,
- 0x9FBFE4A5,
- 0xE8B8D433,
- 0x7807C9A2,
- 0x0F00F934,
- 0x9609A88E,
- 0xE10E9818,
- 0x7F6A0DBB,
- 0x086D3D2D,
- 0x91646C97,
- 0xE6635C01,
- 0x6B6B51F4,
- 0x1C6C6162,
- 0x856530D8,
- 0xF262004E,
- 0x6C0695ED,
- 0x1B01A57B,
- 0x8208F4C1,
- 0xF50FC457,
- 0x65B0D9C6,
- 0x12B7E950,
- 0x8BBEB8EA,
- 0xFCB9887C,
- 0x62DD1DDF,
- 0x15DA2D49,
- 0x8CD37CF3,
- 0xFBD44C65,
- 0x4DB26158,
- 0x3AB551CE,
- 0xA3BC0074,
- 0xD4BB30E2,
- 0x4ADFA541,
- 0x3DD895D7,
- 0xA4D1C46D,
- 0xD3D6F4FB,
- 0x4369E96A,
- 0x346ED9FC,
- 0xAD678846,
- 0xDA60B8D0,
- 0x44042D73,
- 0x33031DE5,
- 0xAA0A4C5F,
- 0xDD0D7CC9,
- 0x5005713C,
- 0x270241AA,
- 0xBE0B1010,
- 0xC90C2086,
- 0x5768B525,
- 0x206F85B3,
- 0xB966D409,
- 0xCE61E49F,
- 0x5EDEF90E,
- 0x29D9C998,
- 0xB0D09822,
- 0xC7D7A8B4,
- 0x59B33D17,
- 0x2EB40D81,
- 0xB7BD5C3B,
- 0xC0BA6CAD,
- 0xEDB88320,
- 0x9ABFB3B6,
- 0x03B6E20C,
- 0x74B1D29A,
- 0xEAD54739,
- 0x9DD277AF,
- 0x04DB2615,
- 0x73DC1683,
- 0xE3630B12,
- 0x94643B84,
- 0x0D6D6A3E,
- 0x7A6A5AA8,
- 0xE40ECF0B,
- 0x9309FF9D,
- 0x0A00AE27,
- 0x7D079EB1,
- 0xF00F9344,
- 0x8708A3D2,
- 0x1E01F268,
- 0x6906C2FE,
- 0xF762575D,
- 0x806567CB,
- 0x196C3671,
- 0x6E6B06E7,
- 0xFED41B76,
- 0x89D32BE0,
- 0x10DA7A5A,
- 0x67DD4ACC,
- 0xF9B9DF6F,
- 0x8EBEEFF9,
- 0x17B7BE43,
- 0x60B08ED5,
- 0xD6D6A3E8,
- 0xA1D1937E,
- 0x38D8C2C4,
- 0x4FDFF252,
- 0xD1BB67F1,
- 0xA6BC5767,
- 0x3FB506DD,
- 0x48B2364B,
- 0xD80D2BDA,
- 0xAF0A1B4C,
- 0x36034AF6,
- 0x41047A60,
- 0xDF60EFC3,
- 0xA867DF55,
- 0x316E8EEF,
- 0x4669BE79,
- 0xCB61B38C,
- 0xBC66831A,
- 0x256FD2A0,
- 0x5268E236,
- 0xCC0C7795,
- 0xBB0B4703,
- 0x220216B9,
- 0x5505262F,
- 0xC5BA3BBE,
- 0xB2BD0B28,
- 0x2BB45A92,
- 0x5CB36A04,
- 0xC2D7FFA7,
- 0xB5D0CF31,
- 0x2CD99E8B,
- 0x5BDEAE1D,
- 0x9B64C2B0,
- 0xEC63F226,
- 0x756AA39C,
- 0x026D930A,
- 0x9C0906A9,
- 0xEB0E363F,
- 0x72076785,
- 0x05005713,
- 0x95BF4A82,
- 0xE2B87A14,
- 0x7BB12BAE,
- 0x0CB61B38,
- 0x92D28E9B,
- 0xE5D5BE0D,
- 0x7CDCEFB7,
- 0x0BDBDF21,
- 0x86D3D2D4,
- 0xF1D4E242,
- 0x68DDB3F8,
- 0x1FDA836E,
- 0x81BE16CD,
- 0xF6B9265B,
- 0x6FB077E1,
- 0x18B74777,
- 0x88085AE6,
- 0xFF0F6A70,
- 0x66063BCA,
- 0x11010B5C,
- 0x8F659EFF,
- 0xF862AE69,
- 0x616BFFD3,
- 0x166CCF45,
- 0xA00AE278,
- 0xD70DD2EE,
- 0x4E048354,
- 0x3903B3C2,
- 0xA7672661,
- 0xD06016F7,
- 0x4969474D,
- 0x3E6E77DB,
- 0xAED16A4A,
- 0xD9D65ADC,
- 0x40DF0B66,
- 0x37D83BF0,
- 0xA9BCAE53,
- 0xDEBB9EC5,
- 0x47B2CF7F,
- 0x30B5FFE9,
- 0xBDBDF21C,
- 0xCABAC28A,
- 0x53B39330,
- 0x24B4A3A6,
- 0xBAD03605,
- 0xCDD70693,
- 0x54DE5729,
- 0x23D967BF,
- 0xB3667A2E,
- 0xC4614AB8,
- 0x5D681B02,
- 0x2A6F2B94,
- 0xB40BBE37,
- 0xC30C8EA1,
- 0x5A05DF1B,
- 0x2D02EF8D
-};
-
-/**
- The CalculateCrc32 routine.
-
- @param Data The buffer containing the data to be processed
- @param DataSize The size of data to be processed
- @param CrcOut A pointer to the caller allocated UINT32 that on
- contains the CRC32 checksum of Data
-
- @retval EFI_SUCCESS Calculation is successful.
- @retval EFI_INVALID_PARAMETER Data / CrcOut = NULL, or DataSize = 0
-**/
-EFI_STATUS
-CalculateCrc32 (
- IN UINT8 *Data,
- IN UINTN DataSize,
- IN OUT UINT32 *CrcOut
- )
-{
- UINT32 Crc;
- UINTN Index;
- UINT8 *Ptr;
-
- if ((DataSize == 0) || (Data == NULL) || (CrcOut == NULL)) {
- return EFI_INVALID_PARAMETER;
- }
-
- Crc = 0xffffffff;
- for (Index = 0, Ptr = Data; Index < DataSize; Index++, Ptr++) {
- Crc = (Crc >> 8) ^ mCrcTable[(UINT8) Crc ^ *Ptr];
- }
-
- *CrcOut = Crc ^ 0xffffffff;
-
- return EFI_SUCCESS;
-}
+/** @file +CalculateCrc32 routine. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <stdlib.h> +#include "Crc32.h" + +UINT32 mCrcTable[256] = { + 0x00000000, + 0x77073096, + 0xEE0E612C, + 0x990951BA, + 0x076DC419, + 0x706AF48F, + 0xE963A535, + 0x9E6495A3, + 0x0EDB8832, + 0x79DCB8A4, + 0xE0D5E91E, + 0x97D2D988, + 0x09B64C2B, + 0x7EB17CBD, + 0xE7B82D07, + 0x90BF1D91, + 0x1DB71064, + 0x6AB020F2, + 0xF3B97148, + 0x84BE41DE, + 0x1ADAD47D, + 0x6DDDE4EB, + 0xF4D4B551, + 0x83D385C7, + 0x136C9856, + 0x646BA8C0, + 0xFD62F97A, + 0x8A65C9EC, + 0x14015C4F, + 0x63066CD9, + 0xFA0F3D63, + 0x8D080DF5, + 0x3B6E20C8, + 0x4C69105E, + 0xD56041E4, + 0xA2677172, + 0x3C03E4D1, + 0x4B04D447, + 0xD20D85FD, + 0xA50AB56B, + 0x35B5A8FA, + 0x42B2986C, + 0xDBBBC9D6, + 0xACBCF940, + 0x32D86CE3, + 0x45DF5C75, + 0xDCD60DCF, + 0xABD13D59, + 0x26D930AC, + 0x51DE003A, + 0xC8D75180, + 0xBFD06116, + 0x21B4F4B5, + 0x56B3C423, + 0xCFBA9599, + 0xB8BDA50F, + 0x2802B89E, + 0x5F058808, + 0xC60CD9B2, + 0xB10BE924, + 0x2F6F7C87, + 0x58684C11, + 0xC1611DAB, + 0xB6662D3D, + 0x76DC4190, + 0x01DB7106, + 0x98D220BC, + 0xEFD5102A, + 0x71B18589, + 0x06B6B51F, + 0x9FBFE4A5, + 0xE8B8D433, + 0x7807C9A2, + 0x0F00F934, + 0x9609A88E, + 0xE10E9818, + 0x7F6A0DBB, + 0x086D3D2D, + 0x91646C97, + 0xE6635C01, + 0x6B6B51F4, + 0x1C6C6162, + 0x856530D8, + 0xF262004E, + 0x6C0695ED, + 0x1B01A57B, + 0x8208F4C1, + 0xF50FC457, + 0x65B0D9C6, + 0x12B7E950, + 0x8BBEB8EA, + 0xFCB9887C, + 0x62DD1DDF, + 0x15DA2D49, + 0x8CD37CF3, + 0xFBD44C65, + 0x4DB26158, + 0x3AB551CE, + 0xA3BC0074, + 0xD4BB30E2, + 0x4ADFA541, + 0x3DD895D7, + 0xA4D1C46D, + 0xD3D6F4FB, + 0x4369E96A, + 0x346ED9FC, + 0xAD678846, + 0xDA60B8D0, + 0x44042D73, + 0x33031DE5, + 0xAA0A4C5F, + 0xDD0D7CC9, + 0x5005713C, + 0x270241AA, + 0xBE0B1010, + 0xC90C2086, + 0x5768B525, + 0x206F85B3, + 0xB966D409, + 0xCE61E49F, + 0x5EDEF90E, + 0x29D9C998, + 0xB0D09822, + 0xC7D7A8B4, + 0x59B33D17, + 0x2EB40D81, + 0xB7BD5C3B, + 0xC0BA6CAD, + 0xEDB88320, + 0x9ABFB3B6, + 0x03B6E20C, + 0x74B1D29A, + 0xEAD54739, + 0x9DD277AF, + 0x04DB2615, + 0x73DC1683, + 0xE3630B12, + 0x94643B84, + 0x0D6D6A3E, + 0x7A6A5AA8, + 0xE40ECF0B, + 0x9309FF9D, + 0x0A00AE27, + 0x7D079EB1, + 0xF00F9344, + 0x8708A3D2, + 0x1E01F268, + 0x6906C2FE, + 0xF762575D, + 0x806567CB, + 0x196C3671, + 0x6E6B06E7, + 0xFED41B76, + 0x89D32BE0, + 0x10DA7A5A, + 0x67DD4ACC, + 0xF9B9DF6F, + 0x8EBEEFF9, + 0x17B7BE43, + 0x60B08ED5, + 0xD6D6A3E8, + 0xA1D1937E, + 0x38D8C2C4, + 0x4FDFF252, + 0xD1BB67F1, + 0xA6BC5767, + 0x3FB506DD, + 0x48B2364B, + 0xD80D2BDA, + 0xAF0A1B4C, + 0x36034AF6, + 0x41047A60, + 0xDF60EFC3, + 0xA867DF55, + 0x316E8EEF, + 0x4669BE79, + 0xCB61B38C, + 0xBC66831A, + 0x256FD2A0, + 0x5268E236, + 0xCC0C7795, + 0xBB0B4703, + 0x220216B9, + 0x5505262F, + 0xC5BA3BBE, + 0xB2BD0B28, + 0x2BB45A92, + 0x5CB36A04, + 0xC2D7FFA7, + 0xB5D0CF31, + 0x2CD99E8B, + 0x5BDEAE1D, + 0x9B64C2B0, + 0xEC63F226, + 0x756AA39C, + 0x026D930A, + 0x9C0906A9, + 0xEB0E363F, + 0x72076785, + 0x05005713, + 0x95BF4A82, + 0xE2B87A14, + 0x7BB12BAE, + 0x0CB61B38, + 0x92D28E9B, + 0xE5D5BE0D, + 0x7CDCEFB7, + 0x0BDBDF21, + 0x86D3D2D4, + 0xF1D4E242, + 0x68DDB3F8, + 0x1FDA836E, + 0x81BE16CD, + 0xF6B9265B, + 0x6FB077E1, + 0x18B74777, + 0x88085AE6, + 0xFF0F6A70, + 0x66063BCA, + 0x11010B5C, + 0x8F659EFF, + 0xF862AE69, + 0x616BFFD3, + 0x166CCF45, + 0xA00AE278, + 0xD70DD2EE, + 0x4E048354, + 0x3903B3C2, + 0xA7672661, + 0xD06016F7, + 0x4969474D, + 0x3E6E77DB, + 0xAED16A4A, + 0xD9D65ADC, + 0x40DF0B66, + 0x37D83BF0, + 0xA9BCAE53, + 0xDEBB9EC5, + 0x47B2CF7F, + 0x30B5FFE9, + 0xBDBDF21C, + 0xCABAC28A, + 0x53B39330, + 0x24B4A3A6, + 0xBAD03605, + 0xCDD70693, + 0x54DE5729, + 0x23D967BF, + 0xB3667A2E, + 0xC4614AB8, + 0x5D681B02, + 0x2A6F2B94, + 0xB40BBE37, + 0xC30C8EA1, + 0x5A05DF1B, + 0x2D02EF8D +}; + +/** + The CalculateCrc32 routine. + + @param Data The buffer containing the data to be processed + @param DataSize The size of data to be processed + @param CrcOut A pointer to the caller allocated UINT32 that on + contains the CRC32 checksum of Data + + @retval EFI_SUCCESS Calculation is successful. + @retval EFI_INVALID_PARAMETER Data / CrcOut = NULL, or DataSize = 0 +**/ +EFI_STATUS +CalculateCrc32 ( + IN UINT8 *Data, + IN UINTN DataSize, + IN OUT UINT32 *CrcOut + ) +{ + UINT32 Crc; + UINTN Index; + UINT8 *Ptr; + + if ((DataSize == 0) || (Data == NULL) || (CrcOut == NULL)) { + return EFI_INVALID_PARAMETER; + } + + Crc = 0xffffffff; + for (Index = 0, Ptr = Data; Index < DataSize; Index++, Ptr++) { + Crc = (Crc >> 8) ^ mCrcTable[(UINT8) Crc ^ *Ptr]; + } + + *CrcOut = Crc ^ 0xffffffff; + + return EFI_SUCCESS; +} diff --git a/BaseTools/Source/C/Common/Crc32.h b/BaseTools/Source/C/Common/Crc32.h index 3f6b5b35fc..b8922fa8dd 100644 --- a/BaseTools/Source/C/Common/Crc32.h +++ b/BaseTools/Source/C/Common/Crc32.h @@ -1,33 +1,33 @@ -/** @file
-Header file for CalculateCrc32 routine
-
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _CRC32_H
-#define _CRC32_H
-
-#include <Common/UefiBaseTypes.h>
-
-/**
- The CalculateCrc32 routine.
-
- @param Data The buffer containing the data to be processed
- @param DataSize The size of data to be processed
- @param CrcOut A pointer to the caller allocated UINT32 that on
- contains the CRC32 checksum of Data
-
- @retval EFI_SUCCESS - Calculation is successful.
- @retval EFI_INVALID_PARAMETER - Data / CrcOut = NULL, or DataSize = 0
-**/
-EFI_STATUS
-CalculateCrc32 (
- IN UINT8 *Data,
- IN UINTN DataSize,
- IN OUT UINT32 *CrcOut
- )
-;
-
-#endif
+/** @file +Header file for CalculateCrc32 routine + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _CRC32_H +#define _CRC32_H + +#include <Common/UefiBaseTypes.h> + +/** + The CalculateCrc32 routine. + + @param Data The buffer containing the data to be processed + @param DataSize The size of data to be processed + @param CrcOut A pointer to the caller allocated UINT32 that on + contains the CRC32 checksum of Data + + @retval EFI_SUCCESS - Calculation is successful. + @retval EFI_INVALID_PARAMETER - Data / CrcOut = NULL, or DataSize = 0 +**/ +EFI_STATUS +CalculateCrc32 ( + IN UINT8 *Data, + IN UINTN DataSize, + IN OUT UINT32 *CrcOut + ) +; + +#endif diff --git a/BaseTools/Source/C/Common/Decompress.c b/BaseTools/Source/C/Common/Decompress.c index 0f2bdbffa7..27bc04ebcb 100644 --- a/BaseTools/Source/C/Common/Decompress.c +++ b/BaseTools/Source/C/Common/Decompress.c @@ -1,903 +1,903 @@ -/** @file
-Decompressor. Algorithm Ported from OPSD code (Decomp.asm) for Efi and Tiano
-compress algorithm.
-
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
---*/
-
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-#include "Decompress.h"
-
-//
-// Decompression algorithm begins here
-//
-#define UINT8_MAX 0xff
-#define BITBUFSIZ 32
-#define MAXMATCH 256
-#define THRESHOLD 3
-#define CODE_BIT 16
-#define BAD_TABLE - 1
-
-//
-// C: Char&Len Set; P: Position Set; T: exTra Set
-//
-#define NC (0xff + MAXMATCH + 2 - THRESHOLD)
-#define CBIT 9
-#define EFIPBIT 4
-#define MAXPBIT 5
-#define TBIT 5
-#define MAXNP ((1U << MAXPBIT) - 1)
-#define NT (CODE_BIT + 3)
-#if NT > MAXNP
-#define NPT NT
-#else
-#define NPT MAXNP
-#endif
-
-typedef struct {
- UINT8 *mSrcBase; // Starting address of compressed data
- UINT8 *mDstBase; // Starting address of decompressed data
- UINT32 mOutBuf;
- UINT32 mInBuf;
-
- UINT16 mBitCount;
- UINT32 mBitBuf;
- UINT32 mSubBitBuf;
- UINT16 mBlockSize;
- UINT32 mCompSize;
- UINT32 mOrigSize;
-
- UINT16 mBadTableFlag;
-
- UINT16 mLeft[2 * NC - 1];
- UINT16 mRight[2 * NC - 1];
- UINT8 mCLen[NC];
- UINT8 mPTLen[NPT];
- UINT16 mCTable[4096];
- UINT16 mPTTable[256];
-} SCRATCH_DATA;
-
-STATIC UINT16 mPbit = EFIPBIT;
-
-/**
- Shift mBitBuf NumOfBits left. Read in NumOfBits of bits from source.
-
- @param Sd The global scratch data
- @param NumOfBit The number of bits to shift and read.
-**/
-STATIC
-VOID
-FillBuf (
- IN SCRATCH_DATA *Sd,
- IN UINT16 NumOfBits
- )
-{
- Sd->mBitBuf = (UINT32) (((UINT64)Sd->mBitBuf) << NumOfBits);
-
- while (NumOfBits > Sd->mBitCount) {
-
- Sd->mBitBuf |= (UINT32) (((UINT64)Sd->mSubBitBuf) << (NumOfBits = (UINT16) (NumOfBits - Sd->mBitCount)));
-
- if (Sd->mCompSize > 0) {
- //
- // Get 1 byte into SubBitBuf
- //
- Sd->mCompSize--;
- Sd->mSubBitBuf = 0;
- Sd->mSubBitBuf = Sd->mSrcBase[Sd->mInBuf++];
- Sd->mBitCount = 8;
-
- } else {
- //
- // No more bits from the source, just pad zero bit.
- //
- Sd->mSubBitBuf = 0;
- Sd->mBitCount = 8;
-
- }
- }
-
- Sd->mBitCount = (UINT16) (Sd->mBitCount - NumOfBits);
- Sd->mBitBuf |= Sd->mSubBitBuf >> Sd->mBitCount;
-}
-
-/**
- Get NumOfBits of bits out from mBitBuf. Fill mBitBuf with subsequent
- NumOfBits of bits from source. Returns NumOfBits of bits that are
- popped out.
-
- @param Sd The global scratch data.
- @param NumOfBits The number of bits to pop and read.
-
- @return The bits that are popped out.
-**/
-STATIC
-UINT32
-GetBits (
- IN SCRATCH_DATA *Sd,
- IN UINT16 NumOfBits
- )
-{
- UINT32 OutBits;
-
- OutBits = (UINT32) (Sd->mBitBuf >> (BITBUFSIZ - NumOfBits));
-
- FillBuf (Sd, NumOfBits);
-
- return OutBits;
-}
-
-/**
- Creates Huffman Code mapping table according to code length array.
-
- @param Sd The global scratch data
- @param NumOfChar Number of symbols in the symbol set
- @param BitLen Code length array
- @param TableBits The width of the mapping table
- @param Table The table
-
- @retval 0 - OK.
- @retval BAD_TABLE - The table is corrupted.
-**/
-STATIC
-UINT16
-MakeTable (
- IN SCRATCH_DATA *Sd,
- IN UINT16 NumOfChar,
- IN UINT8 *BitLen,
- IN UINT16 TableBits,
- OUT UINT16 *Table
- )
-{
- UINT16 Count[17];
- UINT16 Weight[17];
- UINT16 Start[18];
- UINT16 *Pointer;
- UINT16 Index3;
- UINT16 Index;
- UINT16 Len;
- UINT16 Char;
- UINT16 JuBits;
- UINT16 Avail;
- UINT16 NextCode;
- UINT16 Mask;
- UINT16 MaxTableLength;
-
- for (Index = 1; Index <= 16; Index++) {
- Count[Index] = 0;
- }
-
- for (Index = 0; Index < NumOfChar; Index++) {
- if (BitLen[Index] > 16) {
- return (UINT16) BAD_TABLE;
- }
- Count[BitLen[Index]]++;
- }
-
- Start[1] = 0;
-
- for (Index = 1; Index <= 16; Index++) {
- Start[Index + 1] = (UINT16) (Start[Index] + (Count[Index] << (16 - Index)));
- }
-
- if (Start[17] != 0) {
- /*(1U << 16)*/
- return (UINT16) BAD_TABLE;
- }
-
- JuBits = (UINT16) (16 - TableBits);
-
- for (Index = 1; Index <= TableBits; Index++) {
- Start[Index] >>= JuBits;
- Weight[Index] = (UINT16) (1U << (TableBits - Index));
- }
-
- while (Index <= 16) {
- Weight[Index] = (UINT16) (1U << (16 - Index));
- Index++;
- }
-
- Index = (UINT16) (Start[TableBits + 1] >> JuBits);
-
- if (Index != 0) {
- Index3 = (UINT16) (1U << TableBits);
- while (Index != Index3) {
- Table[Index++] = 0;
- }
- }
-
- Avail = NumOfChar;
- Mask = (UINT16) (1U << (15 - TableBits));
- MaxTableLength = (UINT16) (1U << TableBits);
-
- for (Char = 0; Char < NumOfChar; Char++) {
-
- Len = BitLen[Char];
- if (Len == 0 || Len >= 17) {
- continue;
- }
-
- NextCode = (UINT16) (Start[Len] + Weight[Len]);
-
- if (Len <= TableBits) {
-
- if (Start[Len] >= NextCode || NextCode > MaxTableLength){
- return (UINT16) BAD_TABLE;
- }
-
- for (Index = Start[Len]; Index < NextCode; Index++) {
- Table[Index] = Char;
- }
-
- } else {
-
- Index3 = Start[Len];
- Pointer = &Table[Index3 >> JuBits];
- Index = (UINT16) (Len - TableBits);
-
- while (Index != 0) {
- if (*Pointer == 0) {
- Sd->mRight[Avail] = Sd->mLeft[Avail] = 0;
- *Pointer = Avail++;
- }
-
- if (Index3 & Mask) {
- Pointer = &Sd->mRight[*Pointer];
- } else {
- Pointer = &Sd->mLeft[*Pointer];
- }
-
- Index3 <<= 1;
- Index--;
- }
-
- *Pointer = Char;
-
- }
-
- Start[Len] = NextCode;
- }
- //
- // Succeeds
- //
- return 0;
-}
-
-/**
- Decodes a position value.
-
- @param Sd the global scratch data
-
- @return The position value decoded.
-**/
-STATIC
-UINT32
-DecodeP (
- IN SCRATCH_DATA *Sd
- )
-{
- UINT16 Val;
- UINT32 Mask;
- UINT32 Pos;
-
- Val = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)];
-
- if (Val >= MAXNP) {
- Mask = 1U << (BITBUFSIZ - 1 - 8);
-
- do {
-
- if (Sd->mBitBuf & Mask) {
- Val = Sd->mRight[Val];
- } else {
- Val = Sd->mLeft[Val];
- }
-
- Mask >>= 1;
- } while (Val >= MAXNP);
- }
- //
- // Advance what we have read
- //
- FillBuf (Sd, Sd->mPTLen[Val]);
-
- Pos = Val;
- if (Val > 1) {
- Pos = (UINT32) ((1U << (Val - 1)) + GetBits (Sd, (UINT16) (Val - 1)));
- }
-
- return Pos;
-}
-
-/**
- Reads code lengths for the Extra Set or the Position Set
-
- @param Sd The global scratch data
- @param nn Number of symbols
- @param nbit Number of bits needed to represent nn
- @param Special The special symbol that needs to be taken care of
-
- @retval 0 - OK.
- @retval BAD_TABLE - Table is corrupted.
-**/
-STATIC
-UINT16
-ReadPTLen (
- IN SCRATCH_DATA *Sd,
- IN UINT16 nn,
- IN UINT16 nbit,
- IN UINT16 Special
- )
-{
- UINT16 Number;
- UINT16 CharC;
- UINT16 Index;
- UINT32 Mask;
-
- assert (nn <= NPT);
-
- Number = (UINT16) GetBits (Sd, nbit);
-
- if (Number == 0) {
- CharC = (UINT16) GetBits (Sd, nbit);
-
- for (Index = 0; Index < 256; Index++) {
- Sd->mPTTable[Index] = CharC;
- }
-
- for (Index = 0; Index < nn; Index++) {
- Sd->mPTLen[Index] = 0;
- }
-
- return 0;
- }
-
- Index = 0;
-
- while (Index < Number && Index < NPT) {
-
- CharC = (UINT16) (Sd->mBitBuf >> (BITBUFSIZ - 3));
-
- if (CharC == 7) {
- Mask = 1U << (BITBUFSIZ - 1 - 3);
- while (Mask & Sd->mBitBuf) {
- Mask >>= 1;
- CharC += 1;
- }
- }
-
- FillBuf (Sd, (UINT16) ((CharC < 7) ? 3 : CharC - 3));
-
- Sd->mPTLen[Index++] = (UINT8) CharC;
-
- if (Index == Special) {
- CharC = (UINT16) GetBits (Sd, 2);
- CharC--;
- while ((INT16) (CharC) >= 0 && Index < NPT) {
- Sd->mPTLen[Index++] = 0;
- CharC--;
- }
- }
- }
-
- while (Index < nn && Index < NPT) {
- Sd->mPTLen[Index++] = 0;
- }
-
- return MakeTable (Sd, nn, Sd->mPTLen, 8, Sd->mPTTable);
-}
-
-/**
- Reads code lengths for Char&Len Set.
-
- @param Sd the global scratch data
-**/
-STATIC
-VOID
-ReadCLen (
- SCRATCH_DATA *Sd
- )
-{
- UINT16 Number;
- UINT16 CharC;
- UINT16 Index;
- UINT32 Mask;
-
- Number = (UINT16) GetBits (Sd, CBIT);
-
- if (Number == 0) {
- CharC = (UINT16) GetBits (Sd, CBIT);
-
- for (Index = 0; Index < NC; Index++) {
- Sd->mCLen[Index] = 0;
- }
-
- for (Index = 0; Index < 4096; Index++) {
- Sd->mCTable[Index] = CharC;
- }
-
- return ;
- }
-
- Index = 0;
- while (Index < Number) {
-
- CharC = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)];
- if (CharC >= NT) {
- Mask = 1U << (BITBUFSIZ - 1 - 8);
-
- do {
-
- if (Mask & Sd->mBitBuf) {
- CharC = Sd->mRight[CharC];
- } else {
- CharC = Sd->mLeft[CharC];
- }
-
- Mask >>= 1;
-
- } while (CharC >= NT);
- }
- //
- // Advance what we have read
- //
- FillBuf (Sd, Sd->mPTLen[CharC]);
-
- if (CharC <= 2) {
-
- if (CharC == 0) {
- CharC = 1;
- } else if (CharC == 1) {
- CharC = (UINT16) (GetBits (Sd, 4) + 3);
- } else if (CharC == 2) {
- CharC = (UINT16) (GetBits (Sd, CBIT) + 20);
- }
-
- CharC--;
- while ((INT16) (CharC) >= 0) {
- Sd->mCLen[Index++] = 0;
- CharC--;
- }
-
- } else {
-
- Sd->mCLen[Index++] = (UINT8) (CharC - 2);
-
- }
- }
-
- while (Index < NC) {
- Sd->mCLen[Index++] = 0;
- }
-
- MakeTable (Sd, NC, Sd->mCLen, 12, Sd->mCTable);
-
- return ;
-}
-
-/**
- Decode a character/length value.
-
- @param Sd The global scratch data.
-
- @return The value decoded.
-**/
-STATIC
-UINT16
-DecodeC (
- SCRATCH_DATA *Sd
- )
-{
- UINT16 Index2;
- UINT32 Mask;
-
- if (Sd->mBlockSize == 0) {
- //
- // Starting a new block
- //
- Sd->mBlockSize = (UINT16) GetBits (Sd, 16);
- Sd->mBadTableFlag = ReadPTLen (Sd, NT, TBIT, 3);
- if (Sd->mBadTableFlag != 0) {
- return 0;
- }
-
- ReadCLen (Sd);
-
- Sd->mBadTableFlag = ReadPTLen (Sd, MAXNP, mPbit, (UINT16) (-1));
- if (Sd->mBadTableFlag != 0) {
- return 0;
- }
- }
-
- Sd->mBlockSize--;
- Index2 = Sd->mCTable[Sd->mBitBuf >> (BITBUFSIZ - 12)];
-
- if (Index2 >= NC) {
- Mask = 1U << (BITBUFSIZ - 1 - 12);
-
- do {
- if (Sd->mBitBuf & Mask) {
- Index2 = Sd->mRight[Index2];
- } else {
- Index2 = Sd->mLeft[Index2];
- }
-
- Mask >>= 1;
- } while (Index2 >= NC);
- }
- //
- // Advance what we have read
- //
- FillBuf (Sd, Sd->mCLen[Index2]);
-
- return Index2;
-}
-
-/**
- Decode the source data and put the resulting data into the destination buffer.
-
- @param Sd The global scratch data
- **/
-STATIC
-VOID
-Decode (
- SCRATCH_DATA *Sd
- )
-{
- UINT16 BytesRemain;
- UINT32 DataIdx;
- UINT16 CharC;
-
- BytesRemain = (UINT16) (-1);
-
- DataIdx = 0;
-
- for (;;) {
- CharC = DecodeC (Sd);
- if (Sd->mBadTableFlag != 0) {
- return ;
- }
-
- if (CharC < 256) {
- //
- // Process an Original character
- //
- Sd->mDstBase[Sd->mOutBuf++] = (UINT8) CharC;
- if (Sd->mOutBuf >= Sd->mOrigSize) {
- return ;
- }
-
- } else {
- //
- // Process a Pointer
- //
- CharC = (UINT16) (CharC - (UINT8_MAX + 1 - THRESHOLD));
-
- BytesRemain = CharC;
-
- DataIdx = Sd->mOutBuf - DecodeP (Sd) - 1;
-
- BytesRemain--;
- while ((INT16) (BytesRemain) >= 0) {
- if (Sd->mOutBuf >= Sd->mOrigSize) {
- return ;
- }
- if (DataIdx >= Sd->mOrigSize) {
- Sd->mBadTableFlag = (UINT16) BAD_TABLE;
- return ;
- }
- Sd->mDstBase[Sd->mOutBuf++] = Sd->mDstBase[DataIdx++];
-
- BytesRemain--;
- }
- //
- // Once mOutBuf is fully filled, directly return
- //
- if (Sd->mOutBuf >= Sd->mOrigSize) {
- return ;
- }
- }
- }
-
- return ;
-}
-
-/**
- The implementation of EFI_DECOMPRESS_PROTOCOL.GetInfo().
-
- @param Source The source buffer containing the compressed data.
- @param SrcSize The size of source buffer
- @param DstSize The size of destination buffer.
- @param ScratchSize The size of scratch buffer.
-
- @retval EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successfully retrieved.
- @retval EFI_INVALID_PARAMETER - The source data is corrupted
-**/
-EFI_STATUS
-GetInfo (
- IN VOID *Source,
- IN UINT32 SrcSize,
- OUT UINT32 *DstSize,
- OUT UINT32 *ScratchSize
- )
-{
- UINT8 *Src;
- UINT32 CompSize;
-
- *ScratchSize = sizeof (SCRATCH_DATA);
-
- Src = Source;
- if (SrcSize < 8) {
- return EFI_INVALID_PARAMETER;
- }
-
- CompSize = Src[0] + (Src[1] << 8) + (Src[2] << 16) + (Src[3] << 24);
- *DstSize = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24);
-
- if (SrcSize < CompSize + 8 || (CompSize + 8) < 8) {
- return EFI_INVALID_PARAMETER;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- The implementation Efi and Tiano Decompress().
-
- @param Source - The source buffer containing the compressed data.
- @param SrcSize - The size of source buffer
- @param Destination - The destination buffer to store the decompressed data
- @param DstSize - The size of destination buffer.
- @param Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data.
- @param ScratchSize - The size of scratch buffer.
-
- @retval EFI_SUCCESS - Decompression is successful
- @retval EFI_INVALID_PARAMETER - The source data is corrupted
-**/
-EFI_STATUS
-Decompress (
- IN VOID *Source,
- IN UINT32 SrcSize,
- IN OUT VOID *Destination,
- IN UINT32 DstSize,
- IN OUT VOID *Scratch,
- IN UINT32 ScratchSize
- )
-{
- UINT32 Index;
- UINT32 CompSize;
- UINT32 OrigSize;
- EFI_STATUS Status;
- SCRATCH_DATA *Sd;
- UINT8 *Src;
- UINT8 *Dst;
-
- Status = EFI_SUCCESS;
- Src = Source;
- Dst = Destination;
-
- if (ScratchSize < sizeof (SCRATCH_DATA)) {
- return EFI_INVALID_PARAMETER;
- }
-
- Sd = (SCRATCH_DATA *) Scratch;
-
- if (SrcSize < 8) {
- return EFI_INVALID_PARAMETER;
- }
-
- CompSize = Src[0] + (Src[1] << 8) + (Src[2] << 16) + (Src[3] << 24);
- OrigSize = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24);
-
- if (SrcSize < CompSize + 8 || (CompSize + 8) < 8) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (DstSize != OrigSize) {
- return EFI_INVALID_PARAMETER;
- }
-
- Src = Src + 8;
-
- for (Index = 0; Index < sizeof (SCRATCH_DATA); Index++) {
- ((UINT8 *) Sd)[Index] = 0;
- }
-
- Sd->mSrcBase = Src;
- Sd->mDstBase = Dst;
- Sd->mCompSize = CompSize;
- Sd->mOrigSize = OrigSize;
-
- //
- // Fill the first BITBUFSIZ bits
- //
- FillBuf (Sd, BITBUFSIZ);
-
- //
- // Decompress it
- //
- Decode (Sd);
-
- if (Sd->mBadTableFlag != 0) {
- //
- // Something wrong with the source
- //
- Status = EFI_INVALID_PARAMETER;
- }
-
- return Status;
-}
-
-/**
- The implementation Efi Decompress GetInfo().
-
- @param Source The source buffer containing the compressed data.
- @param SrcSize The size of source buffer
- @param DstSize The size of destination buffer.
- @param ScratchSize The size of scratch buffer.
-
- @retval EFI_SUCCESS The size of destination buffer and the size of scratch buffer are successfully retrieved.
- @retval EFI_INVALID_PARAMETER The source data is corrupted
-**/
-EFI_STATUS
-EfiGetInfo (
- IN VOID *Source,
- IN UINT32 SrcSize,
- OUT UINT32 *DstSize,
- OUT UINT32 *ScratchSize
- )
-{
- return GetInfo (Source, SrcSize, DstSize, ScratchSize);
-}
-
-/**
- The implementation Tiano Decompress GetInfo().
-
- @param Source The source buffer containing the compressed data.
- @param SrcSize The size of source buffer
- @param DstSize The size of destination buffer.
- @param ScratchSize The size of scratch buffer.
-
- @retval EFI_SUCCESS The size of destination buffer and the size of scratch buffer are successfully retrieved.
- @retval EFI_INVALID_PARAMETER The source data is corrupted
-**/
-EFI_STATUS
-TianoGetInfo (
- IN VOID *Source,
- IN UINT32 SrcSize,
- OUT UINT32 *DstSize,
- OUT UINT32 *ScratchSize
- )
-{
- return GetInfo (Source, SrcSize, DstSize, ScratchSize);
-}
-
-/**
- The implementation of Efi Decompress().
-
- @param Source The source buffer containing the compressed data.
- @param SrcSize The size of source buffer
- @param Destination The destination buffer to store the decompressed data
- @param DstSize The size of destination buffer.
- @param Scratch The buffer used internally by the decompress routine. This buffer is needed to store intermediate data.
- @param ScratchSize The size of scratch buffer.
-
- @retval EFI_SUCCESS Decompression is successful
- @retval EFI_INVALID_PARAMETER The source data is corrupted
-**/
-EFI_STATUS
-EfiDecompress (
- IN VOID *Source,
- IN UINT32 SrcSize,
- IN OUT VOID *Destination,
- IN UINT32 DstSize,
- IN OUT VOID *Scratch,
- IN UINT32 ScratchSize
- )
-{
- mPbit = EFIPBIT;
- return Decompress (Source, SrcSize, Destination, DstSize, Scratch, ScratchSize);
-}
-
-/**
- The implementation of Tiano Decompress().
-
- @param Source The source buffer containing the compressed data.
- @param SrcSize The size of source buffer
- @param Destination The destination buffer to store the decompressed data
- @param DstSize The size of destination buffer.
- @param Scratch The buffer used internally by the decompress routine. This buffer is needed to store intermediate data.
- @param ScratchSize The size of scratch buffer.
-
- @retval EFI_SUCCESS Decompression is successful
- @retval EFI_INVALID_PARAMETER The source data is corrupted
-**/
-EFI_STATUS
-TianoDecompress (
- IN VOID *Source,
- IN UINT32 SrcSize,
- IN OUT VOID *Destination,
- IN UINT32 DstSize,
- IN OUT VOID *Scratch,
- IN UINT32 ScratchSize
- )
-{
- mPbit = MAXPBIT;
- return Decompress (Source, SrcSize, Destination, DstSize, Scratch, ScratchSize);
-}
-
-EFI_STATUS
-Extract (
- IN VOID *Source,
- IN UINT32 SrcSize,
- OUT VOID **Destination,
- OUT UINT32 *DstSize,
- IN UINTN Algorithm
- )
-{
- VOID *Scratch;
- UINT32 ScratchSize;
- EFI_STATUS Status;
-
- Scratch = NULL;
- Status = EFI_SUCCESS;
-
- switch (Algorithm) {
- case 0:
- *Destination = (VOID *)malloc(SrcSize);
- if (*Destination != NULL) {
- memcpy(*Destination, Source, SrcSize);
- } else {
- Status = EFI_OUT_OF_RESOURCES;
- }
- break;
- case 1:
- Status = EfiGetInfo(Source, SrcSize, DstSize, &ScratchSize);
- if (Status == EFI_SUCCESS) {
- Scratch = (VOID *)malloc(ScratchSize);
- if (Scratch == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- *Destination = (VOID *)malloc(*DstSize);
- if (*Destination == NULL) {
- free (Scratch);
- return EFI_OUT_OF_RESOURCES;
- }
-
- Status = EfiDecompress(Source, SrcSize, *Destination, *DstSize, Scratch, ScratchSize);
- }
- break;
- case 2:
- Status = TianoGetInfo(Source, SrcSize, DstSize, &ScratchSize);
- if (Status == EFI_SUCCESS) {
- Scratch = (VOID *)malloc(ScratchSize);
- if (Scratch == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- *Destination = (VOID *)malloc(*DstSize);
- if (*Destination == NULL) {
- free (Scratch);
- return EFI_OUT_OF_RESOURCES;
- }
-
- Status = TianoDecompress(Source, SrcSize, *Destination, *DstSize, Scratch, ScratchSize);
- }
- break;
- default:
- Status = EFI_INVALID_PARAMETER;
- }
-
- if (Scratch != NULL) {
- free (Scratch);
- }
-
- return Status;
-}
-
-
+/** @file +Decompressor. Algorithm Ported from OPSD code (Decomp.asm) for Efi and Tiano +compress algorithm. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +--*/ + +#include <stdlib.h> +#include <string.h> +#include <assert.h> +#include "Decompress.h" + +// +// Decompression algorithm begins here +// +#define UINT8_MAX 0xff +#define BITBUFSIZ 32 +#define MAXMATCH 256 +#define THRESHOLD 3 +#define CODE_BIT 16 +#define BAD_TABLE - 1 + +// +// C: Char&Len Set; P: Position Set; T: exTra Set +// +#define NC (0xff + MAXMATCH + 2 - THRESHOLD) +#define CBIT 9 +#define EFIPBIT 4 +#define MAXPBIT 5 +#define TBIT 5 +#define MAXNP ((1U << MAXPBIT) - 1) +#define NT (CODE_BIT + 3) +#if NT > MAXNP +#define NPT NT +#else +#define NPT MAXNP +#endif + +typedef struct { + UINT8 *mSrcBase; // Starting address of compressed data + UINT8 *mDstBase; // Starting address of decompressed data + UINT32 mOutBuf; + UINT32 mInBuf; + + UINT16 mBitCount; + UINT32 mBitBuf; + UINT32 mSubBitBuf; + UINT16 mBlockSize; + UINT32 mCompSize; + UINT32 mOrigSize; + + UINT16 mBadTableFlag; + + UINT16 mLeft[2 * NC - 1]; + UINT16 mRight[2 * NC - 1]; + UINT8 mCLen[NC]; + UINT8 mPTLen[NPT]; + UINT16 mCTable[4096]; + UINT16 mPTTable[256]; +} SCRATCH_DATA; + +STATIC UINT16 mPbit = EFIPBIT; + +/** + Shift mBitBuf NumOfBits left. Read in NumOfBits of bits from source. + + @param Sd The global scratch data + @param NumOfBit The number of bits to shift and read. +**/ +STATIC +VOID +FillBuf ( + IN SCRATCH_DATA *Sd, + IN UINT16 NumOfBits + ) +{ + Sd->mBitBuf = (UINT32) (((UINT64)Sd->mBitBuf) << NumOfBits); + + while (NumOfBits > Sd->mBitCount) { + + Sd->mBitBuf |= (UINT32) (((UINT64)Sd->mSubBitBuf) << (NumOfBits = (UINT16) (NumOfBits - Sd->mBitCount))); + + if (Sd->mCompSize > 0) { + // + // Get 1 byte into SubBitBuf + // + Sd->mCompSize--; + Sd->mSubBitBuf = 0; + Sd->mSubBitBuf = Sd->mSrcBase[Sd->mInBuf++]; + Sd->mBitCount = 8; + + } else { + // + // No more bits from the source, just pad zero bit. + // + Sd->mSubBitBuf = 0; + Sd->mBitCount = 8; + + } + } + + Sd->mBitCount = (UINT16) (Sd->mBitCount - NumOfBits); + Sd->mBitBuf |= Sd->mSubBitBuf >> Sd->mBitCount; +} + +/** + Get NumOfBits of bits out from mBitBuf. Fill mBitBuf with subsequent + NumOfBits of bits from source. Returns NumOfBits of bits that are + popped out. + + @param Sd The global scratch data. + @param NumOfBits The number of bits to pop and read. + + @return The bits that are popped out. +**/ +STATIC +UINT32 +GetBits ( + IN SCRATCH_DATA *Sd, + IN UINT16 NumOfBits + ) +{ + UINT32 OutBits; + + OutBits = (UINT32) (Sd->mBitBuf >> (BITBUFSIZ - NumOfBits)); + + FillBuf (Sd, NumOfBits); + + return OutBits; +} + +/** + Creates Huffman Code mapping table according to code length array. + + @param Sd The global scratch data + @param NumOfChar Number of symbols in the symbol set + @param BitLen Code length array + @param TableBits The width of the mapping table + @param Table The table + + @retval 0 - OK. + @retval BAD_TABLE - The table is corrupted. +**/ +STATIC +UINT16 +MakeTable ( + IN SCRATCH_DATA *Sd, + IN UINT16 NumOfChar, + IN UINT8 *BitLen, + IN UINT16 TableBits, + OUT UINT16 *Table + ) +{ + UINT16 Count[17]; + UINT16 Weight[17]; + UINT16 Start[18]; + UINT16 *Pointer; + UINT16 Index3; + UINT16 Index; + UINT16 Len; + UINT16 Char; + UINT16 JuBits; + UINT16 Avail; + UINT16 NextCode; + UINT16 Mask; + UINT16 MaxTableLength; + + for (Index = 1; Index <= 16; Index++) { + Count[Index] = 0; + } + + for (Index = 0; Index < NumOfChar; Index++) { + if (BitLen[Index] > 16) { + return (UINT16) BAD_TABLE; + } + Count[BitLen[Index]]++; + } + + Start[1] = 0; + + for (Index = 1; Index <= 16; Index++) { + Start[Index + 1] = (UINT16) (Start[Index] + (Count[Index] << (16 - Index))); + } + + if (Start[17] != 0) { + /*(1U << 16)*/ + return (UINT16) BAD_TABLE; + } + + JuBits = (UINT16) (16 - TableBits); + + for (Index = 1; Index <= TableBits; Index++) { + Start[Index] >>= JuBits; + Weight[Index] = (UINT16) (1U << (TableBits - Index)); + } + + while (Index <= 16) { + Weight[Index] = (UINT16) (1U << (16 - Index)); + Index++; + } + + Index = (UINT16) (Start[TableBits + 1] >> JuBits); + + if (Index != 0) { + Index3 = (UINT16) (1U << TableBits); + while (Index != Index3) { + Table[Index++] = 0; + } + } + + Avail = NumOfChar; + Mask = (UINT16) (1U << (15 - TableBits)); + MaxTableLength = (UINT16) (1U << TableBits); + + for (Char = 0; Char < NumOfChar; Char++) { + + Len = BitLen[Char]; + if (Len == 0 || Len >= 17) { + continue; + } + + NextCode = (UINT16) (Start[Len] + Weight[Len]); + + if (Len <= TableBits) { + + if (Start[Len] >= NextCode || NextCode > MaxTableLength){ + return (UINT16) BAD_TABLE; + } + + for (Index = Start[Len]; Index < NextCode; Index++) { + Table[Index] = Char; + } + + } else { + + Index3 = Start[Len]; + Pointer = &Table[Index3 >> JuBits]; + Index = (UINT16) (Len - TableBits); + + while (Index != 0) { + if (*Pointer == 0) { + Sd->mRight[Avail] = Sd->mLeft[Avail] = 0; + *Pointer = Avail++; + } + + if (Index3 & Mask) { + Pointer = &Sd->mRight[*Pointer]; + } else { + Pointer = &Sd->mLeft[*Pointer]; + } + + Index3 <<= 1; + Index--; + } + + *Pointer = Char; + + } + + Start[Len] = NextCode; + } + // + // Succeeds + // + return 0; +} + +/** + Decodes a position value. + + @param Sd the global scratch data + + @return The position value decoded. +**/ +STATIC +UINT32 +DecodeP ( + IN SCRATCH_DATA *Sd + ) +{ + UINT16 Val; + UINT32 Mask; + UINT32 Pos; + + Val = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)]; + + if (Val >= MAXNP) { + Mask = 1U << (BITBUFSIZ - 1 - 8); + + do { + + if (Sd->mBitBuf & Mask) { + Val = Sd->mRight[Val]; + } else { + Val = Sd->mLeft[Val]; + } + + Mask >>= 1; + } while (Val >= MAXNP); + } + // + // Advance what we have read + // + FillBuf (Sd, Sd->mPTLen[Val]); + + Pos = Val; + if (Val > 1) { + Pos = (UINT32) ((1U << (Val - 1)) + GetBits (Sd, (UINT16) (Val - 1))); + } + + return Pos; +} + +/** + Reads code lengths for the Extra Set or the Position Set + + @param Sd The global scratch data + @param nn Number of symbols + @param nbit Number of bits needed to represent nn + @param Special The special symbol that needs to be taken care of + + @retval 0 - OK. + @retval BAD_TABLE - Table is corrupted. +**/ +STATIC +UINT16 +ReadPTLen ( + IN SCRATCH_DATA *Sd, + IN UINT16 nn, + IN UINT16 nbit, + IN UINT16 Special + ) +{ + UINT16 Number; + UINT16 CharC; + UINT16 Index; + UINT32 Mask; + + assert (nn <= NPT); + + Number = (UINT16) GetBits (Sd, nbit); + + if (Number == 0) { + CharC = (UINT16) GetBits (Sd, nbit); + + for (Index = 0; Index < 256; Index++) { + Sd->mPTTable[Index] = CharC; + } + + for (Index = 0; Index < nn; Index++) { + Sd->mPTLen[Index] = 0; + } + + return 0; + } + + Index = 0; + + while (Index < Number && Index < NPT) { + + CharC = (UINT16) (Sd->mBitBuf >> (BITBUFSIZ - 3)); + + if (CharC == 7) { + Mask = 1U << (BITBUFSIZ - 1 - 3); + while (Mask & Sd->mBitBuf) { + Mask >>= 1; + CharC += 1; + } + } + + FillBuf (Sd, (UINT16) ((CharC < 7) ? 3 : CharC - 3)); + + Sd->mPTLen[Index++] = (UINT8) CharC; + + if (Index == Special) { + CharC = (UINT16) GetBits (Sd, 2); + CharC--; + while ((INT16) (CharC) >= 0 && Index < NPT) { + Sd->mPTLen[Index++] = 0; + CharC--; + } + } + } + + while (Index < nn && Index < NPT) { + Sd->mPTLen[Index++] = 0; + } + + return MakeTable (Sd, nn, Sd->mPTLen, 8, Sd->mPTTable); +} + +/** + Reads code lengths for Char&Len Set. + + @param Sd the global scratch data +**/ +STATIC +VOID +ReadCLen ( + SCRATCH_DATA *Sd + ) +{ + UINT16 Number; + UINT16 CharC; + UINT16 Index; + UINT32 Mask; + + Number = (UINT16) GetBits (Sd, CBIT); + + if (Number == 0) { + CharC = (UINT16) GetBits (Sd, CBIT); + + for (Index = 0; Index < NC; Index++) { + Sd->mCLen[Index] = 0; + } + + for (Index = 0; Index < 4096; Index++) { + Sd->mCTable[Index] = CharC; + } + + return ; + } + + Index = 0; + while (Index < Number) { + + CharC = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)]; + if (CharC >= NT) { + Mask = 1U << (BITBUFSIZ - 1 - 8); + + do { + + if (Mask & Sd->mBitBuf) { + CharC = Sd->mRight[CharC]; + } else { + CharC = Sd->mLeft[CharC]; + } + + Mask >>= 1; + + } while (CharC >= NT); + } + // + // Advance what we have read + // + FillBuf (Sd, Sd->mPTLen[CharC]); + + if (CharC <= 2) { + + if (CharC == 0) { + CharC = 1; + } else if (CharC == 1) { + CharC = (UINT16) (GetBits (Sd, 4) + 3); + } else if (CharC == 2) { + CharC = (UINT16) (GetBits (Sd, CBIT) + 20); + } + + CharC--; + while ((INT16) (CharC) >= 0) { + Sd->mCLen[Index++] = 0; + CharC--; + } + + } else { + + Sd->mCLen[Index++] = (UINT8) (CharC - 2); + + } + } + + while (Index < NC) { + Sd->mCLen[Index++] = 0; + } + + MakeTable (Sd, NC, Sd->mCLen, 12, Sd->mCTable); + + return ; +} + +/** + Decode a character/length value. + + @param Sd The global scratch data. + + @return The value decoded. +**/ +STATIC +UINT16 +DecodeC ( + SCRATCH_DATA *Sd + ) +{ + UINT16 Index2; + UINT32 Mask; + + if (Sd->mBlockSize == 0) { + // + // Starting a new block + // + Sd->mBlockSize = (UINT16) GetBits (Sd, 16); + Sd->mBadTableFlag = ReadPTLen (Sd, NT, TBIT, 3); + if (Sd->mBadTableFlag != 0) { + return 0; + } + + ReadCLen (Sd); + + Sd->mBadTableFlag = ReadPTLen (Sd, MAXNP, mPbit, (UINT16) (-1)); + if (Sd->mBadTableFlag != 0) { + return 0; + } + } + + Sd->mBlockSize--; + Index2 = Sd->mCTable[Sd->mBitBuf >> (BITBUFSIZ - 12)]; + + if (Index2 >= NC) { + Mask = 1U << (BITBUFSIZ - 1 - 12); + + do { + if (Sd->mBitBuf & Mask) { + Index2 = Sd->mRight[Index2]; + } else { + Index2 = Sd->mLeft[Index2]; + } + + Mask >>= 1; + } while (Index2 >= NC); + } + // + // Advance what we have read + // + FillBuf (Sd, Sd->mCLen[Index2]); + + return Index2; +} + +/** + Decode the source data and put the resulting data into the destination buffer. + + @param Sd The global scratch data + **/ +STATIC +VOID +Decode ( + SCRATCH_DATA *Sd + ) +{ + UINT16 BytesRemain; + UINT32 DataIdx; + UINT16 CharC; + + BytesRemain = (UINT16) (-1); + + DataIdx = 0; + + for (;;) { + CharC = DecodeC (Sd); + if (Sd->mBadTableFlag != 0) { + return ; + } + + if (CharC < 256) { + // + // Process an Original character + // + Sd->mDstBase[Sd->mOutBuf++] = (UINT8) CharC; + if (Sd->mOutBuf >= Sd->mOrigSize) { + return ; + } + + } else { + // + // Process a Pointer + // + CharC = (UINT16) (CharC - (UINT8_MAX + 1 - THRESHOLD)); + + BytesRemain = CharC; + + DataIdx = Sd->mOutBuf - DecodeP (Sd) - 1; + + BytesRemain--; + while ((INT16) (BytesRemain) >= 0) { + if (Sd->mOutBuf >= Sd->mOrigSize) { + return ; + } + if (DataIdx >= Sd->mOrigSize) { + Sd->mBadTableFlag = (UINT16) BAD_TABLE; + return ; + } + Sd->mDstBase[Sd->mOutBuf++] = Sd->mDstBase[DataIdx++]; + + BytesRemain--; + } + // + // Once mOutBuf is fully filled, directly return + // + if (Sd->mOutBuf >= Sd->mOrigSize) { + return ; + } + } + } + + return ; +} + +/** + The implementation of EFI_DECOMPRESS_PROTOCOL.GetInfo(). + + @param Source The source buffer containing the compressed data. + @param SrcSize The size of source buffer + @param DstSize The size of destination buffer. + @param ScratchSize The size of scratch buffer. + + @retval EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successfully retrieved. + @retval EFI_INVALID_PARAMETER - The source data is corrupted +**/ +EFI_STATUS +GetInfo ( + IN VOID *Source, + IN UINT32 SrcSize, + OUT UINT32 *DstSize, + OUT UINT32 *ScratchSize + ) +{ + UINT8 *Src; + UINT32 CompSize; + + *ScratchSize = sizeof (SCRATCH_DATA); + + Src = Source; + if (SrcSize < 8) { + return EFI_INVALID_PARAMETER; + } + + CompSize = Src[0] + (Src[1] << 8) + (Src[2] << 16) + (Src[3] << 24); + *DstSize = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24); + + if (SrcSize < CompSize + 8 || (CompSize + 8) < 8) { + return EFI_INVALID_PARAMETER; + } + + return EFI_SUCCESS; +} + +/** + The implementation Efi and Tiano Decompress(). + + @param Source - The source buffer containing the compressed data. + @param SrcSize - The size of source buffer + @param Destination - The destination buffer to store the decompressed data + @param DstSize - The size of destination buffer. + @param Scratch - The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. + @param ScratchSize - The size of scratch buffer. + + @retval EFI_SUCCESS - Decompression is successful + @retval EFI_INVALID_PARAMETER - The source data is corrupted +**/ +EFI_STATUS +Decompress ( + IN VOID *Source, + IN UINT32 SrcSize, + IN OUT VOID *Destination, + IN UINT32 DstSize, + IN OUT VOID *Scratch, + IN UINT32 ScratchSize + ) +{ + UINT32 Index; + UINT32 CompSize; + UINT32 OrigSize; + EFI_STATUS Status; + SCRATCH_DATA *Sd; + UINT8 *Src; + UINT8 *Dst; + + Status = EFI_SUCCESS; + Src = Source; + Dst = Destination; + + if (ScratchSize < sizeof (SCRATCH_DATA)) { + return EFI_INVALID_PARAMETER; + } + + Sd = (SCRATCH_DATA *) Scratch; + + if (SrcSize < 8) { + return EFI_INVALID_PARAMETER; + } + + CompSize = Src[0] + (Src[1] << 8) + (Src[2] << 16) + (Src[3] << 24); + OrigSize = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24); + + if (SrcSize < CompSize + 8 || (CompSize + 8) < 8) { + return EFI_INVALID_PARAMETER; + } + + if (DstSize != OrigSize) { + return EFI_INVALID_PARAMETER; + } + + Src = Src + 8; + + for (Index = 0; Index < sizeof (SCRATCH_DATA); Index++) { + ((UINT8 *) Sd)[Index] = 0; + } + + Sd->mSrcBase = Src; + Sd->mDstBase = Dst; + Sd->mCompSize = CompSize; + Sd->mOrigSize = OrigSize; + + // + // Fill the first BITBUFSIZ bits + // + FillBuf (Sd, BITBUFSIZ); + + // + // Decompress it + // + Decode (Sd); + + if (Sd->mBadTableFlag != 0) { + // + // Something wrong with the source + // + Status = EFI_INVALID_PARAMETER; + } + + return Status; +} + +/** + The implementation Efi Decompress GetInfo(). + + @param Source The source buffer containing the compressed data. + @param SrcSize The size of source buffer + @param DstSize The size of destination buffer. + @param ScratchSize The size of scratch buffer. + + @retval EFI_SUCCESS The size of destination buffer and the size of scratch buffer are successfully retrieved. + @retval EFI_INVALID_PARAMETER The source data is corrupted +**/ +EFI_STATUS +EfiGetInfo ( + IN VOID *Source, + IN UINT32 SrcSize, + OUT UINT32 *DstSize, + OUT UINT32 *ScratchSize + ) +{ + return GetInfo (Source, SrcSize, DstSize, ScratchSize); +} + +/** + The implementation Tiano Decompress GetInfo(). + + @param Source The source buffer containing the compressed data. + @param SrcSize The size of source buffer + @param DstSize The size of destination buffer. + @param ScratchSize The size of scratch buffer. + + @retval EFI_SUCCESS The size of destination buffer and the size of scratch buffer are successfully retrieved. + @retval EFI_INVALID_PARAMETER The source data is corrupted +**/ +EFI_STATUS +TianoGetInfo ( + IN VOID *Source, + IN UINT32 SrcSize, + OUT UINT32 *DstSize, + OUT UINT32 *ScratchSize + ) +{ + return GetInfo (Source, SrcSize, DstSize, ScratchSize); +} + +/** + The implementation of Efi Decompress(). + + @param Source The source buffer containing the compressed data. + @param SrcSize The size of source buffer + @param Destination The destination buffer to store the decompressed data + @param DstSize The size of destination buffer. + @param Scratch The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. + @param ScratchSize The size of scratch buffer. + + @retval EFI_SUCCESS Decompression is successful + @retval EFI_INVALID_PARAMETER The source data is corrupted +**/ +EFI_STATUS +EfiDecompress ( + IN VOID *Source, + IN UINT32 SrcSize, + IN OUT VOID *Destination, + IN UINT32 DstSize, + IN OUT VOID *Scratch, + IN UINT32 ScratchSize + ) +{ + mPbit = EFIPBIT; + return Decompress (Source, SrcSize, Destination, DstSize, Scratch, ScratchSize); +} + +/** + The implementation of Tiano Decompress(). + + @param Source The source buffer containing the compressed data. + @param SrcSize The size of source buffer + @param Destination The destination buffer to store the decompressed data + @param DstSize The size of destination buffer. + @param Scratch The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. + @param ScratchSize The size of scratch buffer. + + @retval EFI_SUCCESS Decompression is successful + @retval EFI_INVALID_PARAMETER The source data is corrupted +**/ +EFI_STATUS +TianoDecompress ( + IN VOID *Source, + IN UINT32 SrcSize, + IN OUT VOID *Destination, + IN UINT32 DstSize, + IN OUT VOID *Scratch, + IN UINT32 ScratchSize + ) +{ + mPbit = MAXPBIT; + return Decompress (Source, SrcSize, Destination, DstSize, Scratch, ScratchSize); +} + +EFI_STATUS +Extract ( + IN VOID *Source, + IN UINT32 SrcSize, + OUT VOID **Destination, + OUT UINT32 *DstSize, + IN UINTN Algorithm + ) +{ + VOID *Scratch; + UINT32 ScratchSize; + EFI_STATUS Status; + + Scratch = NULL; + Status = EFI_SUCCESS; + + switch (Algorithm) { + case 0: + *Destination = (VOID *)malloc(SrcSize); + if (*Destination != NULL) { + memcpy(*Destination, Source, SrcSize); + } else { + Status = EFI_OUT_OF_RESOURCES; + } + break; + case 1: + Status = EfiGetInfo(Source, SrcSize, DstSize, &ScratchSize); + if (Status == EFI_SUCCESS) { + Scratch = (VOID *)malloc(ScratchSize); + if (Scratch == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + *Destination = (VOID *)malloc(*DstSize); + if (*Destination == NULL) { + free (Scratch); + return EFI_OUT_OF_RESOURCES; + } + + Status = EfiDecompress(Source, SrcSize, *Destination, *DstSize, Scratch, ScratchSize); + } + break; + case 2: + Status = TianoGetInfo(Source, SrcSize, DstSize, &ScratchSize); + if (Status == EFI_SUCCESS) { + Scratch = (VOID *)malloc(ScratchSize); + if (Scratch == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + *Destination = (VOID *)malloc(*DstSize); + if (*Destination == NULL) { + free (Scratch); + return EFI_OUT_OF_RESOURCES; + } + + Status = TianoDecompress(Source, SrcSize, *Destination, *DstSize, Scratch, ScratchSize); + } + break; + default: + Status = EFI_INVALID_PARAMETER; + } + + if (Scratch != NULL) { + free (Scratch); + } + + return Status; +} + + diff --git a/BaseTools/Source/C/Common/Decompress.h b/BaseTools/Source/C/Common/Decompress.h index 00a1e31b8c..73e35966fa 100644 --- a/BaseTools/Source/C/Common/Decompress.h +++ b/BaseTools/Source/C/Common/Decompress.h @@ -1,135 +1,135 @@ -/** @file
-Header file for compression routine
-
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _EFI_DECOMPRESS_H
-#define _EFI_DECOMPRESS_H
-
-#include <Common/UefiBaseTypes.h>
-
-/**
-
-Routine Description:
-
- The implementation Efi Decompress GetInfo().
-
-Arguments:
-
- Source - The source buffer containing the compressed data.
- SrcSize - The size of source buffer
- DstSize - The size of destination buffer.
- ScratchSize - The size of scratch buffer.
-
-Returns:
-
- EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successfully retrieved.
- EFI_INVALID_PARAMETER - The source data is corrupted
-
-**/
-EFI_STATUS
-EfiGetInfo (
- IN VOID *Source,
- IN UINT32 SrcSize,
- OUT UINT32 *DstSize,
- OUT UINT32 *ScratchSize
- );
-
-/**
- The implementation of Efi Decompress().
-
- @param Source The source buffer containing the compressed data.
- @param SrcSize The size of source buffer
- @param Destination The destination buffer to store the decompressed data
- @param DstSize The size of destination buffer.
- @param Scratch The buffer used internally by the decompress routine. This buffer is needed to store intermediate data.
- @param ScratchSize The size of scratch buffer.
-
- @retval EFI_SUCCESS Decompression is successful
- @retval EFI_INVALID_PARAMETER The source data is corrupted
-**/
-EFI_STATUS
-EfiDecompress (
- IN VOID *Source,
- IN UINT32 SrcSize,
- IN OUT VOID *Destination,
- IN UINT32 DstSize,
- IN OUT VOID *Scratch,
- IN UINT32 ScratchSize
- );
-
-/**
- The implementation Tiano Decompress GetInfo().
-
- @param Source The source buffer containing the compressed data.
- @param SrcSize The size of source buffer
- @param DstSize The size of destination buffer.
- @param ScratchSize The size of scratch buffer.
-
- @retval EFI_SUCCESS The size of destination buffer and the size of scratch buffer are successfully retrieved.
- @retval EFI_INVALID_PARAMETER The source data is corrupted
-**/
-EFI_STATUS
-TianoGetInfo (
- IN VOID *Source,
- IN UINT32 SrcSize,
- OUT UINT32 *DstSize,
- OUT UINT32 *ScratchSize
- );
-
-/**
- The implementation of Tiano Decompress().
-
- @param Source The source buffer containing the compressed data.
- @param SrcSize The size of source buffer
- @param Destination The destination buffer to store the decompressed data
- @param DstSize The size of destination buffer.
- @param Scratch The buffer used internally by the decompress routine. This buffer is needed to store intermediate data.
- @param ScratchSize The size of scratch buffer.
-
- @retval EFI_SUCCESS Decompression is successful
- @retval EFI_INVALID_PARAMETER The source data is corrupted
-**/
-EFI_STATUS
-TianoDecompress (
- IN VOID *Source,
- IN UINT32 SrcSize,
- IN OUT VOID *Destination,
- IN UINT32 DstSize,
- IN OUT VOID *Scratch,
- IN UINT32 ScratchSize
- );
-
-typedef
-EFI_STATUS
-(*GETINFO_FUNCTION) (
- IN VOID *Source,
- IN UINT32 SrcSize,
- OUT UINT32 *DstSize,
- OUT UINT32 *ScratchSize
- );
-
-typedef
-EFI_STATUS
-(*DECOMPRESS_FUNCTION) (
- IN VOID *Source,
- IN UINT32 SrcSize,
- IN OUT VOID *Destination,
- IN UINT32 DstSize,
- IN OUT VOID *Scratch,
- IN UINT32 ScratchSize
- );
-
-EFI_STATUS
-Extract (
- IN VOID *Source,
- IN UINT32 SrcSize,
- OUT VOID **Destination,
- OUT UINT32 *DstSize,
- IN UINTN Algorithm
- );
-
-#endif
+/** @file +Header file for compression routine + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_DECOMPRESS_H +#define _EFI_DECOMPRESS_H + +#include <Common/UefiBaseTypes.h> + +/** + +Routine Description: + + The implementation Efi Decompress GetInfo(). + +Arguments: + + Source - The source buffer containing the compressed data. + SrcSize - The size of source buffer + DstSize - The size of destination buffer. + ScratchSize - The size of scratch buffer. + +Returns: + + EFI_SUCCESS - The size of destination buffer and the size of scratch buffer are successfully retrieved. + EFI_INVALID_PARAMETER - The source data is corrupted + +**/ +EFI_STATUS +EfiGetInfo ( + IN VOID *Source, + IN UINT32 SrcSize, + OUT UINT32 *DstSize, + OUT UINT32 *ScratchSize + ); + +/** + The implementation of Efi Decompress(). + + @param Source The source buffer containing the compressed data. + @param SrcSize The size of source buffer + @param Destination The destination buffer to store the decompressed data + @param DstSize The size of destination buffer. + @param Scratch The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. + @param ScratchSize The size of scratch buffer. + + @retval EFI_SUCCESS Decompression is successful + @retval EFI_INVALID_PARAMETER The source data is corrupted +**/ +EFI_STATUS +EfiDecompress ( + IN VOID *Source, + IN UINT32 SrcSize, + IN OUT VOID *Destination, + IN UINT32 DstSize, + IN OUT VOID *Scratch, + IN UINT32 ScratchSize + ); + +/** + The implementation Tiano Decompress GetInfo(). + + @param Source The source buffer containing the compressed data. + @param SrcSize The size of source buffer + @param DstSize The size of destination buffer. + @param ScratchSize The size of scratch buffer. + + @retval EFI_SUCCESS The size of destination buffer and the size of scratch buffer are successfully retrieved. + @retval EFI_INVALID_PARAMETER The source data is corrupted +**/ +EFI_STATUS +TianoGetInfo ( + IN VOID *Source, + IN UINT32 SrcSize, + OUT UINT32 *DstSize, + OUT UINT32 *ScratchSize + ); + +/** + The implementation of Tiano Decompress(). + + @param Source The source buffer containing the compressed data. + @param SrcSize The size of source buffer + @param Destination The destination buffer to store the decompressed data + @param DstSize The size of destination buffer. + @param Scratch The buffer used internally by the decompress routine. This buffer is needed to store intermediate data. + @param ScratchSize The size of scratch buffer. + + @retval EFI_SUCCESS Decompression is successful + @retval EFI_INVALID_PARAMETER The source data is corrupted +**/ +EFI_STATUS +TianoDecompress ( + IN VOID *Source, + IN UINT32 SrcSize, + IN OUT VOID *Destination, + IN UINT32 DstSize, + IN OUT VOID *Scratch, + IN UINT32 ScratchSize + ); + +typedef +EFI_STATUS +(*GETINFO_FUNCTION) ( + IN VOID *Source, + IN UINT32 SrcSize, + OUT UINT32 *DstSize, + OUT UINT32 *ScratchSize + ); + +typedef +EFI_STATUS +(*DECOMPRESS_FUNCTION) ( + IN VOID *Source, + IN UINT32 SrcSize, + IN OUT VOID *Destination, + IN UINT32 DstSize, + IN OUT VOID *Scratch, + IN UINT32 ScratchSize + ); + +EFI_STATUS +Extract ( + IN VOID *Source, + IN UINT32 SrcSize, + OUT VOID **Destination, + OUT UINT32 *DstSize, + IN UINTN Algorithm + ); + +#endif diff --git a/BaseTools/Source/C/Common/EfiCompress.c b/BaseTools/Source/C/Common/EfiCompress.c index 0db958b853..913bef7c8f 100644 --- a/BaseTools/Source/C/Common/EfiCompress.c +++ b/BaseTools/Source/C/Common/EfiCompress.c @@ -1,1407 +1,1407 @@ -/** @file
-Compression routine. The compression algorithm is a mixture of LZ77 and Huffman
-coding. LZ77 transforms the source data into a sequence of Original Characters
-and Pointers to repeated strings. This sequence is further divided into Blocks
-and Huffman codings are applied to each Block.
-
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "Compress.h"
-
-
-//
-// Macro Definitions
-//
-
-#undef UINT8_MAX
-typedef INT16 NODE;
-#define UINT8_MAX 0xff
-#define UINT8_BIT 8
-#define THRESHOLD 3
-#define INIT_CRC 0
-#define WNDBIT 13
-#define WNDSIZ (1U << WNDBIT)
-#define MAXMATCH 256
-#define PERC_FLAG 0x8000U
-#define CODE_BIT 16
-#define NIL 0
-#define MAX_HASH_VAL (3 * WNDSIZ + (WNDSIZ / 512 + 1) * UINT8_MAX)
-#define HASH(p, c) ((p) + ((c) << (WNDBIT - 9)) + WNDSIZ * 2)
-#define CRCPOLY 0xA001
-#define UPDATE_CRC(c) mCrc = mCrcTable[(mCrc ^ (c)) & 0xFF] ^ (mCrc >> UINT8_BIT)
-
-//
-// C: the Char&Len Set; P: the Position Set; T: the exTra Set
-//
-
-#define NC (UINT8_MAX + MAXMATCH + 2 - THRESHOLD)
-#define CBIT 9
-#define NP (WNDBIT + 1)
-#define PBIT 4
-#define NT (CODE_BIT + 3)
-#define TBIT 5
-#if NT > NP
- #define NPT NT
-#else
- #define NPT NP
-#endif
-
-//
-// Function Prototypes
-//
-
-STATIC
-VOID
-PutDword(
- IN UINT32 Data
- );
-
-STATIC
-EFI_STATUS
-AllocateMemory (
- );
-
-STATIC
-VOID
-FreeMemory (
- );
-
-STATIC
-VOID
-InitSlide (
- );
-
-STATIC
-NODE
-Child (
- IN NODE q,
- IN UINT8 c
- );
-
-STATIC
-VOID
-MakeChild (
- IN NODE q,
- IN UINT8 c,
- IN NODE r
- );
-
-STATIC
-VOID
-Split (
- IN NODE Old
- );
-
-STATIC
-VOID
-InsertNode (
- );
-
-STATIC
-VOID
-DeleteNode (
- );
-
-STATIC
-VOID
-GetNextMatch (
- );
-
-STATIC
-EFI_STATUS
-Encode (
- );
-
-STATIC
-VOID
-CountTFreq (
- );
-
-STATIC
-VOID
-WritePTLen (
- IN INT32 n,
- IN INT32 nbit,
- IN INT32 Special
- );
-
-STATIC
-VOID
-WriteCLen (
- );
-
-STATIC
-VOID
-EncodeC (
- IN INT32 c
- );
-
-STATIC
-VOID
-EncodeP (
- IN UINT32 p
- );
-
-STATIC
-VOID
-SendBlock (
- );
-
-STATIC
-VOID
-Output (
- IN UINT32 c,
- IN UINT32 p
- );
-
-STATIC
-VOID
-HufEncodeStart (
- );
-
-STATIC
-VOID
-HufEncodeEnd (
- );
-
-STATIC
-VOID
-MakeCrcTable (
- );
-
-STATIC
-VOID
-PutBits (
- IN INT32 n,
- IN UINT32 x
- );
-
-STATIC
-INT32
-FreadCrc (
- OUT UINT8 *p,
- IN INT32 n
- );
-
-STATIC
-VOID
-InitPutBits (
- );
-
-STATIC
-VOID
-CountLen (
- IN INT32 i
- );
-
-STATIC
-VOID
-MakeLen (
- IN INT32 Root
- );
-
-STATIC
-VOID
-DownHeap (
- IN INT32 i
- );
-
-STATIC
-VOID
-MakeCode (
- IN INT32 n,
- IN UINT8 Len[],
- OUT UINT16 Code[]
- );
-
-STATIC
-INT32
-MakeTree (
- IN INT32 NParm,
- IN UINT16 FreqParm[],
- OUT UINT8 LenParm[],
- OUT UINT16 CodeParm[]
- );
-
-
-//
-// Global Variables
-//
-
-STATIC UINT8 *mSrc, *mDst, *mSrcUpperLimit, *mDstUpperLimit;
-
-STATIC UINT8 *mLevel, *mText, *mChildCount, *mBuf, mCLen[NC], mPTLen[NPT], *mLen;
-STATIC INT16 mHeap[NC + 1];
-STATIC INT32 mRemainder, mMatchLen, mBitCount, mHeapSize, mN;
-STATIC UINT32 mBufSiz = 0, mOutputPos, mOutputMask, mSubBitBuf, mCrc;
-STATIC UINT32 mCompSize, mOrigSize;
-
-STATIC UINT16 *mFreq, *mSortPtr, mLenCnt[17], mLeft[2 * NC - 1], mRight[2 * NC - 1],
- mCrcTable[UINT8_MAX + 1], mCFreq[2 * NC - 1],mCCode[NC],
- mPFreq[2 * NP - 1], mPTCode[NPT], mTFreq[2 * NT - 1];
-
-STATIC NODE mPos, mMatchPos, mAvail, *mPosition, *mParent, *mPrev, *mNext = NULL;
-
-
-//
-// functions
-//
-
-/**
- The main compression routine.
-
- @param SrcBuffer The buffer storing the source data
- @param SrcSize The size of source data
- @param DstBuffer The buffer to store the compressed data
- @param DstSize On input, the size of DstBuffer; On output,
- the size of the actual compressed data.
-
- @retval EFI_BUFFER_TOO_SMALL The DstBuffer is too small. In this case,
- DstSize contains the size needed.
- @retval EFI_SUCCESS Compression is successful.
-
-**/
-EFI_STATUS
-EfiCompress (
- IN UINT8 *SrcBuffer,
- IN UINT32 SrcSize,
- IN UINT8 *DstBuffer,
- IN OUT UINT32 *DstSize
- )
-{
- EFI_STATUS Status = EFI_SUCCESS;
-
- //
- // Initializations
- //
- mBufSiz = 0;
- mBuf = NULL;
- mText = NULL;
- mLevel = NULL;
- mChildCount = NULL;
- mPosition = NULL;
- mParent = NULL;
- mPrev = NULL;
- mNext = NULL;
-
-
- mSrc = SrcBuffer;
- mSrcUpperLimit = mSrc + SrcSize;
- mDst = DstBuffer;
- mDstUpperLimit = mDst + *DstSize;
-
- PutDword(0L);
- PutDword(0L);
-
- MakeCrcTable ();
-
- mOrigSize = mCompSize = 0;
- mCrc = INIT_CRC;
-
- //
- // Compress it
- //
-
- Status = Encode();
- if (EFI_ERROR (Status)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // Null terminate the compressed data
- //
- if (mDst < mDstUpperLimit) {
- *mDst++ = 0;
- }
-
- //
- // Fill in compressed size and original size
- //
- mDst = DstBuffer;
- PutDword(mCompSize+1);
- PutDword(mOrigSize);
-
- //
- // Return
- //
-
- if (mCompSize + 1 + 8 > *DstSize) {
- *DstSize = mCompSize + 1 + 8;
- return EFI_BUFFER_TOO_SMALL;
- } else {
- *DstSize = mCompSize + 1 + 8;
- return EFI_SUCCESS;
- }
-
-}
-
-/**
- Put a dword to output stream
-
- @param Data the dword to put
-**/
-STATIC
-VOID
-PutDword(
- IN UINT32 Data
- )
-{
- if (mDst < mDstUpperLimit) {
- *mDst++ = (UINT8)(((UINT8)(Data )) & 0xff);
- }
-
- if (mDst < mDstUpperLimit) {
- *mDst++ = (UINT8)(((UINT8)(Data >> 0x08)) & 0xff);
- }
-
- if (mDst < mDstUpperLimit) {
- *mDst++ = (UINT8)(((UINT8)(Data >> 0x10)) & 0xff);
- }
-
- if (mDst < mDstUpperLimit) {
- *mDst++ = (UINT8)(((UINT8)(Data >> 0x18)) & 0xff);
- }
-}
-
-/**
- Allocate memory spaces for data structures used in compression process
-
- @retval EFI_SUCCESS Memory is allocated successfully
- @retva; EFI_OUT_OF_RESOURCES Allocation fails
-**/
-STATIC
-EFI_STATUS
-AllocateMemory ()
-{
- UINT32 i;
-
- mText = malloc (WNDSIZ * 2 + MAXMATCH);
- if (mText == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- for (i = 0 ; i < WNDSIZ * 2 + MAXMATCH; i ++) {
- mText[i] = 0;
- }
-
- mLevel = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof(*mLevel));
- mChildCount = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof(*mChildCount));
- mPosition = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof(*mPosition));
- mParent = malloc (WNDSIZ * 2 * sizeof(*mParent));
- mPrev = malloc (WNDSIZ * 2 * sizeof(*mPrev));
- mNext = malloc ((MAX_HASH_VAL + 1) * sizeof(*mNext));
- if (mLevel == NULL || mChildCount == NULL || mPosition == NULL ||
- mParent == NULL || mPrev == NULL || mNext == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- mBufSiz = 16 * 1024U;
- while ((mBuf = malloc(mBufSiz)) == NULL) {
- mBufSiz = (mBufSiz / 10U) * 9U;
- if (mBufSiz < 4 * 1024U) {
- return EFI_OUT_OF_RESOURCES;
- }
- }
- mBuf[0] = 0;
-
- return EFI_SUCCESS;
-}
-
-/**
- Called when compression is completed to free memory previously allocated.
-**/
-VOID
-FreeMemory ()
-{
- if (mText) {
- free (mText);
- }
-
- if (mLevel) {
- free (mLevel);
- }
-
- if (mChildCount) {
- free (mChildCount);
- }
-
- if (mPosition) {
- free (mPosition);
- }
-
- if (mParent) {
- free (mParent);
- }
-
- if (mPrev) {
- free (mPrev);
- }
-
- if (mNext) {
- free (mNext);
- }
-
- if (mBuf) {
- free (mBuf);
- }
-
- return;
-}
-
-/**
- Initialize String Info Log data structures
-**/
-STATIC
-VOID
-InitSlide ()
-{
- NODE i;
-
- for (i = WNDSIZ; i <= WNDSIZ + UINT8_MAX; i++) {
- mLevel[i] = 1;
- mPosition[i] = NIL; /* sentinel */
- }
- for (i = WNDSIZ; i < WNDSIZ * 2; i++) {
- mParent[i] = NIL;
- }
- mAvail = 1;
- for (i = 1; i < WNDSIZ - 1; i++) {
- mNext[i] = (NODE)(i + 1);
- }
-
- mNext[WNDSIZ - 1] = NIL;
- for (i = WNDSIZ * 2; i <= MAX_HASH_VAL; i++) {
- mNext[i] = NIL;
- }
-}
-
-/**
- Find child node given the parent node and the edge character
-
- @param q the parent node
- @param c the edge character
-
- @return The child node (NIL if not found)
-**/
-STATIC
-NODE
-Child (
- IN NODE q,
- IN UINT8 c
- )
-{
- NODE r;
-
- r = mNext[HASH(q, c)];
- mParent[NIL] = q; /* sentinel */
- while (mParent[r] != q) {
- r = mNext[r];
- }
-
- return r;
-}
-
-/**
- Create a new child for a given parent node.
-
- @param q the parent node
- @param c the edge character
- @param r the child node
-**/
-STATIC
-VOID
-MakeChild (
- IN NODE q,
- IN UINT8 c,
- IN NODE r
- )
-{
- NODE h, t;
-
- h = (NODE)HASH(q, c);
- t = mNext[h];
- mNext[h] = r;
- mNext[r] = t;
- mPrev[t] = r;
- mPrev[r] = h;
- mParent[r] = q;
- mChildCount[q]++;
-}
-
-/**
- Split a node.
-
- @param Old the node to split
-**/
-STATIC
-VOID
-Split (
- NODE Old
- )
-{
- NODE New, t;
-
- New = mAvail;
- mAvail = mNext[New];
- mChildCount[New] = 0;
- t = mPrev[Old];
- mPrev[New] = t;
- mNext[t] = New;
- t = mNext[Old];
- mNext[New] = t;
- mPrev[t] = New;
- mParent[New] = mParent[Old];
- mLevel[New] = (UINT8)mMatchLen;
- mPosition[New] = mPos;
- MakeChild(New, mText[mMatchPos + mMatchLen], Old);
- MakeChild(New, mText[mPos + mMatchLen], mPos);
-}
-
-/**
- Insert string info for current position into the String Info Log
-**/
-STATIC
-VOID
-InsertNode ()
-{
- NODE q, r, j, t;
- UINT8 c, *t1, *t2;
-
- if (mMatchLen >= 4) {
-
- //
- // We have just got a long match, the target tree
- // can be located by MatchPos + 1. Traverse the tree
- // from bottom up to get to a proper starting point.
- // The usage of PERC_FLAG ensures proper node deletion
- // in DeleteNode() later.
- //
-
- mMatchLen--;
- r = (INT16)((mMatchPos + 1) | WNDSIZ);
- while ((q = mParent[r]) == NIL) {
- r = mNext[r];
- }
- while (mLevel[q] >= mMatchLen) {
- r = q; q = mParent[q];
- }
- t = q;
- while (mPosition[t] < 0) {
- mPosition[t] = mPos;
- t = mParent[t];
- }
- if (t < WNDSIZ) {
- mPosition[t] = (NODE)(mPos | PERC_FLAG);
- }
- } else {
-
- //
- // Locate the target tree
- //
-
- q = (INT16)(mText[mPos] + WNDSIZ);
- c = mText[mPos + 1];
- if ((r = Child(q, c)) == NIL) {
- MakeChild(q, c, mPos);
- mMatchLen = 1;
- return;
- }
- mMatchLen = 2;
- }
-
- //
- // Traverse down the tree to find a match.
- // Update Position value along the route.
- // Node split or creation is involved.
- //
-
- for ( ; ; ) {
- if (r >= WNDSIZ) {
- j = MAXMATCH;
- mMatchPos = r;
- } else {
- j = mLevel[r];
- mMatchPos = (NODE)(mPosition[r] & ~PERC_FLAG);
- }
- if (mMatchPos >= mPos) {
- mMatchPos -= WNDSIZ;
- }
- t1 = &mText[mPos + mMatchLen];
- t2 = &mText[mMatchPos + mMatchLen];
- while (mMatchLen < j) {
- if (*t1 != *t2) {
- Split(r);
- return;
- }
- mMatchLen++;
- t1++;
- t2++;
- }
- if (mMatchLen >= MAXMATCH) {
- break;
- }
- mPosition[r] = mPos;
- q = r;
- if ((r = Child(q, *t1)) == NIL) {
- MakeChild(q, *t1, mPos);
- return;
- }
- mMatchLen++;
- }
- t = mPrev[r];
- mPrev[mPos] = t;
- mNext[t] = mPos;
- t = mNext[r];
- mNext[mPos] = t;
- mPrev[t] = mPos;
- mParent[mPos] = q;
- mParent[r] = NIL;
-
- //
- // Special usage of 'next'
- //
- mNext[r] = mPos;
-
-}
-
-/**
- Delete outdated string info. (The Usage of PERC_FLAG
- ensures a clean deletion)
-**/
-STATIC
-VOID
-DeleteNode ()
-{
- NODE q, r, s, t, u;
-
- if (mParent[mPos] == NIL) {
- return;
- }
-
- r = mPrev[mPos];
- s = mNext[mPos];
- mNext[r] = s;
- mPrev[s] = r;
- r = mParent[mPos];
- mParent[mPos] = NIL;
- if (r >= WNDSIZ || --mChildCount[r] > 1) {
- return;
- }
- t = (NODE)(mPosition[r] & ~PERC_FLAG);
- if (t >= mPos) {
- t -= WNDSIZ;
- }
- s = t;
- q = mParent[r];
- while ((u = mPosition[q]) & PERC_FLAG) {
- u &= ~PERC_FLAG;
- if (u >= mPos) {
- u -= WNDSIZ;
- }
- if (u > s) {
- s = u;
- }
- mPosition[q] = (INT16)(s | WNDSIZ);
- q = mParent[q];
- }
- if (q < WNDSIZ) {
- if (u >= mPos) {
- u -= WNDSIZ;
- }
- if (u > s) {
- s = u;
- }
- mPosition[q] = (INT16)(s | WNDSIZ | PERC_FLAG);
- }
- s = Child(r, mText[t + mLevel[r]]);
- t = mPrev[s];
- u = mNext[s];
- mNext[t] = u;
- mPrev[u] = t;
- t = mPrev[r];
- mNext[t] = s;
- mPrev[s] = t;
- t = mNext[r];
- mPrev[t] = s;
- mNext[s] = t;
- mParent[s] = mParent[r];
- mParent[r] = NIL;
- mNext[r] = mAvail;
- mAvail = r;
-}
-
-/**
- Advance the current position (read in new data if needed).
- Delete outdated string info. Find a match string for current position.
-**/
-STATIC
-VOID
-GetNextMatch ()
-{
- INT32 n;
-
- mRemainder--;
- if (++mPos == WNDSIZ * 2) {
- memmove(&mText[0], &mText[WNDSIZ], WNDSIZ + MAXMATCH);
- n = FreadCrc(&mText[WNDSIZ + MAXMATCH], WNDSIZ);
- mRemainder += n;
- mPos = WNDSIZ;
- }
- DeleteNode();
- InsertNode();
-}
-
-/**
- The main controlling routine for compression process.
-
- @retval EFI_SUCCESS The compression is successful
- @retval EFI_OUT_0F_RESOURCES Not enough memory for compression process
-**/
-STATIC
-EFI_STATUS
-Encode ()
-{
- EFI_STATUS Status;
- INT32 LastMatchLen;
- NODE LastMatchPos;
-
- Status = AllocateMemory();
- if (EFI_ERROR(Status)) {
- FreeMemory();
- return Status;
- }
-
- InitSlide();
-
- HufEncodeStart();
-
- mRemainder = FreadCrc(&mText[WNDSIZ], WNDSIZ + MAXMATCH);
-
- mMatchLen = 0;
- mPos = WNDSIZ;
- InsertNode();
- if (mMatchLen > mRemainder) {
- mMatchLen = mRemainder;
- }
- while (mRemainder > 0) {
- LastMatchLen = mMatchLen;
- LastMatchPos = mMatchPos;
- GetNextMatch();
- if (mMatchLen > mRemainder) {
- mMatchLen = mRemainder;
- }
-
- if (mMatchLen > LastMatchLen || LastMatchLen < THRESHOLD) {
-
- //
- // Not enough benefits are gained by outputting a pointer,
- // so just output the original character
- //
-
- Output(mText[mPos - 1], 0);
- } else {
-
- //
- // Outputting a pointer is beneficial enough, do it.
- //
-
- Output(LastMatchLen + (UINT8_MAX + 1 - THRESHOLD),
- (mPos - LastMatchPos - 2) & (WNDSIZ - 1));
- while (--LastMatchLen > 0) {
- GetNextMatch();
- }
- if (mMatchLen > mRemainder) {
- mMatchLen = mRemainder;
- }
- }
- }
-
- HufEncodeEnd();
- FreeMemory();
- return EFI_SUCCESS;
-}
-
-/**
- Count the frequencies for the Extra Set
-**/
-STATIC
-VOID
-CountTFreq ()
-{
- INT32 i, k, n, Count;
-
- for (i = 0; i < NT; i++) {
- mTFreq[i] = 0;
- }
- n = NC;
- while (n > 0 && mCLen[n - 1] == 0) {
- n--;
- }
- i = 0;
- while (i < n) {
- k = mCLen[i++];
- if (k == 0) {
- Count = 1;
- while (i < n && mCLen[i] == 0) {
- i++;
- Count++;
- }
- if (Count <= 2) {
- mTFreq[0] = (UINT16)(mTFreq[0] + Count);
- } else if (Count <= 18) {
- mTFreq[1]++;
- } else if (Count == 19) {
- mTFreq[0]++;
- mTFreq[1]++;
- } else {
- mTFreq[2]++;
- }
- } else {
- mTFreq[k + 2]++;
- }
- }
-}
-
-/**
- Outputs the code length array for the Extra Set or the Position Set.
-
- @param n the number of symbols
- @param nbit the number of bits needed to represent 'n'
- @param Special the special symbol that needs to be take care of
-**/
-STATIC
-VOID
-WritePTLen (
- IN INT32 n,
- IN INT32 nbit,
- IN INT32 Special
- )
-{
- INT32 i, k;
-
- while (n > 0 && mPTLen[n - 1] == 0) {
- n--;
- }
- PutBits(nbit, n);
- i = 0;
- while (i < n) {
- k = mPTLen[i++];
- if (k <= 6) {
- PutBits(3, k);
- } else {
- PutBits(k - 3, (1U << (k - 3)) - 2);
- }
- if (i == Special) {
- while (i < 6 && mPTLen[i] == 0) {
- i++;
- }
- PutBits(2, (i - 3) & 3);
- }
- }
-}
-
-/**
- Outputs the code length array for Char&Length Set
-**/
-STATIC
-VOID
-WriteCLen ()
-{
- INT32 i, k, n, Count;
-
- n = NC;
- while (n > 0 && mCLen[n - 1] == 0) {
- n--;
- }
- PutBits(CBIT, n);
- i = 0;
- while (i < n) {
- k = mCLen[i++];
- if (k == 0) {
- Count = 1;
- while (i < n && mCLen[i] == 0) {
- i++;
- Count++;
- }
- if (Count <= 2) {
- for (k = 0; k < Count; k++) {
- PutBits(mPTLen[0], mPTCode[0]);
- }
- } else if (Count <= 18) {
- PutBits(mPTLen[1], mPTCode[1]);
- PutBits(4, Count - 3);
- } else if (Count == 19) {
- PutBits(mPTLen[0], mPTCode[0]);
- PutBits(mPTLen[1], mPTCode[1]);
- PutBits(4, 15);
- } else {
- PutBits(mPTLen[2], mPTCode[2]);
- PutBits(CBIT, Count - 20);
- }
- } else {
- PutBits(mPTLen[k + 2], mPTCode[k + 2]);
- }
- }
-}
-
-STATIC
-VOID
-EncodeC (
- IN INT32 c
- )
-{
- PutBits(mCLen[c], mCCode[c]);
-}
-
-STATIC
-VOID
-EncodeP (
- IN UINT32 p
- )
-{
- UINT32 c, q;
-
- c = 0;
- q = p;
- while (q) {
- q >>= 1;
- c++;
- }
- PutBits(mPTLen[c], mPTCode[c]);
- if (c > 1) {
- PutBits(c - 1, p & (0xFFFFU >> (17 - c)));
- }
-}
-
-/**
- Huffman code the block and output it.
-**/
-STATIC
-VOID
-SendBlock ()
-{
- UINT32 i, k, Flags, Root, Pos, Size;
- Flags = 0;
-
- Root = MakeTree(NC, mCFreq, mCLen, mCCode);
- Size = mCFreq[Root];
- PutBits(16, Size);
- if (Root >= NC) {
- CountTFreq();
- Root = MakeTree(NT, mTFreq, mPTLen, mPTCode);
- if (Root >= NT) {
- WritePTLen(NT, TBIT, 3);
- } else {
- PutBits(TBIT, 0);
- PutBits(TBIT, Root);
- }
- WriteCLen();
- } else {
- PutBits(TBIT, 0);
- PutBits(TBIT, 0);
- PutBits(CBIT, 0);
- PutBits(CBIT, Root);
- }
- Root = MakeTree(NP, mPFreq, mPTLen, mPTCode);
- if (Root >= NP) {
- WritePTLen(NP, PBIT, -1);
- } else {
- PutBits(PBIT, 0);
- PutBits(PBIT, Root);
- }
- Pos = 0;
- for (i = 0; i < Size; i++) {
- if (i % UINT8_BIT == 0) {
- Flags = mBuf[Pos++];
- } else {
- Flags <<= 1;
- }
- if (Flags & (1U << (UINT8_BIT - 1))) {
- EncodeC(mBuf[Pos++] + (1U << UINT8_BIT));
- k = mBuf[Pos++] << UINT8_BIT;
- k += mBuf[Pos++];
- EncodeP(k);
- } else {
- EncodeC(mBuf[Pos++]);
- }
- }
- for (i = 0; i < NC; i++) {
- mCFreq[i] = 0;
- }
- for (i = 0; i < NP; i++) {
- mPFreq[i] = 0;
- }
-}
-
-/**
- Outputs an Original Character or a Pointer
-
- @param c The original character or the 'String Length' element of a Pointer
- @param p The 'Position' field of a Pointer
-**/
-STATIC
-VOID
-Output (
- IN UINT32 c,
- IN UINT32 p
- )
-{
- STATIC UINT32 CPos;
-
- if ((mOutputMask >>= 1) == 0) {
- mOutputMask = 1U << (UINT8_BIT - 1);
- if (mOutputPos >= mBufSiz - 3 * UINT8_BIT) {
- SendBlock();
- mOutputPos = 0;
- }
- CPos = mOutputPos++;
- mBuf[CPos] = 0;
- }
- mBuf[mOutputPos++] = (UINT8) c;
- mCFreq[c]++;
- if (c >= (1U << UINT8_BIT)) {
- mBuf[CPos] |= mOutputMask;
- mBuf[mOutputPos++] = (UINT8)(p >> UINT8_BIT);
- mBuf[mOutputPos++] = (UINT8) p;
- c = 0;
- while (p) {
- p >>= 1;
- c++;
- }
- mPFreq[c]++;
- }
-}
-
-STATIC
-VOID
-HufEncodeStart ()
-{
- INT32 i;
-
- for (i = 0; i < NC; i++) {
- mCFreq[i] = 0;
- }
- for (i = 0; i < NP; i++) {
- mPFreq[i] = 0;
- }
- mOutputPos = mOutputMask = 0;
- InitPutBits();
- return;
-}
-
-STATIC
-VOID
-HufEncodeEnd ()
-{
- SendBlock();
-
- //
- // Flush remaining bits
- //
- PutBits(UINT8_BIT - 1, 0);
-
- return;
-}
-
-
-STATIC
-VOID
-MakeCrcTable ()
-{
- UINT32 i, j, r;
-
- for (i = 0; i <= UINT8_MAX; i++) {
- r = i;
- for (j = 0; j < UINT8_BIT; j++) {
- if (r & 1) {
- r = (r >> 1) ^ CRCPOLY;
- } else {
- r >>= 1;
- }
- }
- mCrcTable[i] = (UINT16)r;
- }
-}
-
-/**
- Outputs rightmost n bits of x
-
- @param n the rightmost n bits of the data is used
- @param x the data
-**/
-STATIC
-VOID
-PutBits (
- IN INT32 n,
- IN UINT32 x
- )
-{
- UINT8 Temp;
-
- if (n < mBitCount) {
- mSubBitBuf |= x << (mBitCount -= n);
- } else {
-
- Temp = (UINT8)(mSubBitBuf | (x >> (n -= mBitCount)));
- if (mDst < mDstUpperLimit) {
- *mDst++ = Temp;
- }
- mCompSize++;
-
- if (n < UINT8_BIT) {
- mSubBitBuf = x << (mBitCount = UINT8_BIT - n);
- } else {
-
- Temp = (UINT8)(x >> (n - UINT8_BIT));
- if (mDst < mDstUpperLimit) {
- *mDst++ = Temp;
- }
- mCompSize++;
-
- mSubBitBuf = x << (mBitCount = 2 * UINT8_BIT - n);
- }
- }
-}
-
-/**
- Read in source data
-
- @param p the buffer to hold the data
- @param n number of bytes to read
-
- @return number of bytes actually read
-**/
-STATIC
-INT32
-FreadCrc (
- OUT UINT8 *p,
- IN INT32 n
- )
-{
- INT32 i;
-
- for (i = 0; mSrc < mSrcUpperLimit && i < n; i++) {
- *p++ = *mSrc++;
- }
- n = i;
-
- p -= n;
- mOrigSize += n;
- while (--i >= 0) {
- UPDATE_CRC(*p++);
- }
- return n;
-}
-
-
-STATIC
-VOID
-InitPutBits ()
-{
- mBitCount = UINT8_BIT;
- mSubBitBuf = 0;
-}
-
-/**
- Count the number of each code length for a Huffman tree.
-
- @param i the top node
-**/
-STATIC
-VOID
-CountLen (
- IN INT32 i
- )
-{
- STATIC INT32 Depth = 0;
-
- if (i < mN) {
- mLenCnt[(Depth < 16) ? Depth : 16]++;
- } else {
- Depth++;
- CountLen(mLeft [i]);
- CountLen(mRight[i]);
- Depth--;
- }
-}
-
-/**
- Create code length array for a Huffman tree
-
- @param Root the root of the tree
-**/
-STATIC
-VOID
-MakeLen (
- IN INT32 Root
- )
-{
- INT32 i, k;
- UINT32 Cum;
-
- for (i = 0; i <= 16; i++) {
- mLenCnt[i] = 0;
- }
- CountLen(Root);
-
- //
- // Adjust the length count array so that
- // no code will be generated longer than its designated length
- //
-
- Cum = 0;
- for (i = 16; i > 0; i--) {
- Cum += mLenCnt[i] << (16 - i);
- }
- while (Cum != (1U << 16)) {
- mLenCnt[16]--;
- for (i = 15; i > 0; i--) {
- if (mLenCnt[i] != 0) {
- mLenCnt[i]--;
- mLenCnt[i+1] += 2;
- break;
- }
- }
- Cum--;
- }
- for (i = 16; i > 0; i--) {
- k = mLenCnt[i];
- while (--k >= 0) {
- mLen[*mSortPtr++] = (UINT8)i;
- }
- }
-}
-
-STATIC
-VOID
-DownHeap (
- IN INT32 i
- )
-{
- INT32 j, k;
-
- //
- // priority queue: send i-th entry down heap
- //
-
- k = mHeap[i];
- while ((j = 2 * i) <= mHeapSize) {
- if (j < mHeapSize && mFreq[mHeap[j]] > mFreq[mHeap[j + 1]]) {
- j++;
- }
- if (mFreq[k] <= mFreq[mHeap[j]]) {
- break;
- }
- mHeap[i] = mHeap[j];
- i = j;
- }
- mHeap[i] = (INT16)k;
-}
-
-/**
- Assign code to each symbol based on the code length array
-
- @param n number of symbols
- @param Len the code length array
- @param Code stores codes for each symbol
-**/
-STATIC
-VOID
-MakeCode (
- IN INT32 n,
- IN UINT8 Len[],
- OUT UINT16 Code[]
- )
-{
- INT32 i;
- UINT16 Start[18];
-
- Start[1] = 0;
- for (i = 1; i <= 16; i++) {
- Start[i + 1] = (UINT16)((Start[i] + mLenCnt[i]) << 1);
- }
- for (i = 0; i < n; i++) {
- Code[i] = Start[Len[i]]++;
- }
-}
-
-/**
- Generates Huffman codes given a frequency distribution of symbols
-
- @param NParm number of symbols
- @param FreqParm frequency of each symbol
- @param LenParm code length for each symbol
- @param CodeParm code for each symbol
-
- @return Root of the Huffman tree.
-**/
-STATIC
-INT32
-MakeTree (
- IN INT32 NParm,
- IN UINT16 FreqParm[],
- OUT UINT8 LenParm[],
- OUT UINT16 CodeParm[]
- )
-{
- INT32 i, j, k, Avail;
-
- //
- // make tree, calculate len[], return root
- //
-
- mN = NParm;
- mFreq = FreqParm;
- mLen = LenParm;
- Avail = mN;
- mHeapSize = 0;
- mHeap[1] = 0;
- for (i = 0; i < mN; i++) {
- mLen[i] = 0;
- if (mFreq[i]) {
- mHeap[++mHeapSize] = (INT16)i;
- }
- }
- if (mHeapSize < 2) {
- CodeParm[mHeap[1]] = 0;
- return mHeap[1];
- }
- for (i = mHeapSize / 2; i >= 1; i--) {
-
- //
- // make priority queue
- //
- DownHeap(i);
- }
- mSortPtr = CodeParm;
- do {
- i = mHeap[1];
- if (i < mN) {
- *mSortPtr++ = (UINT16)i;
- }
- mHeap[1] = mHeap[mHeapSize--];
- DownHeap(1);
- j = mHeap[1];
- if (j < mN) {
- *mSortPtr++ = (UINT16)j;
- }
- k = Avail++;
- mFreq[k] = (UINT16)(mFreq[i] + mFreq[j]);
- mHeap[1] = (INT16)k;
- DownHeap(1);
- mLeft[k] = (UINT16)i;
- mRight[k] = (UINT16)j;
- } while (mHeapSize > 1);
-
- mSortPtr = CodeParm;
- MakeLen(k);
- MakeCode(NParm, LenParm, CodeParm);
-
- //
- // return root
- //
- return k;
-}
-
+/** @file +Compression routine. The compression algorithm is a mixture of LZ77 and Huffman +coding. LZ77 transforms the source data into a sequence of Original Characters +and Pointers to repeated strings. This sequence is further divided into Blocks +and Huffman codings are applied to each Block. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Compress.h" + + +// +// Macro Definitions +// + +#undef UINT8_MAX +typedef INT16 NODE; +#define UINT8_MAX 0xff +#define UINT8_BIT 8 +#define THRESHOLD 3 +#define INIT_CRC 0 +#define WNDBIT 13 +#define WNDSIZ (1U << WNDBIT) +#define MAXMATCH 256 +#define PERC_FLAG 0x8000U +#define CODE_BIT 16 +#define NIL 0 +#define MAX_HASH_VAL (3 * WNDSIZ + (WNDSIZ / 512 + 1) * UINT8_MAX) +#define HASH(p, c) ((p) + ((c) << (WNDBIT - 9)) + WNDSIZ * 2) +#define CRCPOLY 0xA001 +#define UPDATE_CRC(c) mCrc = mCrcTable[(mCrc ^ (c)) & 0xFF] ^ (mCrc >> UINT8_BIT) + +// +// C: the Char&Len Set; P: the Position Set; T: the exTra Set +// + +#define NC (UINT8_MAX + MAXMATCH + 2 - THRESHOLD) +#define CBIT 9 +#define NP (WNDBIT + 1) +#define PBIT 4 +#define NT (CODE_BIT + 3) +#define TBIT 5 +#if NT > NP + #define NPT NT +#else + #define NPT NP +#endif + +// +// Function Prototypes +// + +STATIC +VOID +PutDword( + IN UINT32 Data + ); + +STATIC +EFI_STATUS +AllocateMemory ( + ); + +STATIC +VOID +FreeMemory ( + ); + +STATIC +VOID +InitSlide ( + ); + +STATIC +NODE +Child ( + IN NODE q, + IN UINT8 c + ); + +STATIC +VOID +MakeChild ( + IN NODE q, + IN UINT8 c, + IN NODE r + ); + +STATIC +VOID +Split ( + IN NODE Old + ); + +STATIC +VOID +InsertNode ( + ); + +STATIC +VOID +DeleteNode ( + ); + +STATIC +VOID +GetNextMatch ( + ); + +STATIC +EFI_STATUS +Encode ( + ); + +STATIC +VOID +CountTFreq ( + ); + +STATIC +VOID +WritePTLen ( + IN INT32 n, + IN INT32 nbit, + IN INT32 Special + ); + +STATIC +VOID +WriteCLen ( + ); + +STATIC +VOID +EncodeC ( + IN INT32 c + ); + +STATIC +VOID +EncodeP ( + IN UINT32 p + ); + +STATIC +VOID +SendBlock ( + ); + +STATIC +VOID +Output ( + IN UINT32 c, + IN UINT32 p + ); + +STATIC +VOID +HufEncodeStart ( + ); + +STATIC +VOID +HufEncodeEnd ( + ); + +STATIC +VOID +MakeCrcTable ( + ); + +STATIC +VOID +PutBits ( + IN INT32 n, + IN UINT32 x + ); + +STATIC +INT32 +FreadCrc ( + OUT UINT8 *p, + IN INT32 n + ); + +STATIC +VOID +InitPutBits ( + ); + +STATIC +VOID +CountLen ( + IN INT32 i + ); + +STATIC +VOID +MakeLen ( + IN INT32 Root + ); + +STATIC +VOID +DownHeap ( + IN INT32 i + ); + +STATIC +VOID +MakeCode ( + IN INT32 n, + IN UINT8 Len[], + OUT UINT16 Code[] + ); + +STATIC +INT32 +MakeTree ( + IN INT32 NParm, + IN UINT16 FreqParm[], + OUT UINT8 LenParm[], + OUT UINT16 CodeParm[] + ); + + +// +// Global Variables +// + +STATIC UINT8 *mSrc, *mDst, *mSrcUpperLimit, *mDstUpperLimit; + +STATIC UINT8 *mLevel, *mText, *mChildCount, *mBuf, mCLen[NC], mPTLen[NPT], *mLen; +STATIC INT16 mHeap[NC + 1]; +STATIC INT32 mRemainder, mMatchLen, mBitCount, mHeapSize, mN; +STATIC UINT32 mBufSiz = 0, mOutputPos, mOutputMask, mSubBitBuf, mCrc; +STATIC UINT32 mCompSize, mOrigSize; + +STATIC UINT16 *mFreq, *mSortPtr, mLenCnt[17], mLeft[2 * NC - 1], mRight[2 * NC - 1], + mCrcTable[UINT8_MAX + 1], mCFreq[2 * NC - 1],mCCode[NC], + mPFreq[2 * NP - 1], mPTCode[NPT], mTFreq[2 * NT - 1]; + +STATIC NODE mPos, mMatchPos, mAvail, *mPosition, *mParent, *mPrev, *mNext = NULL; + + +// +// functions +// + +/** + The main compression routine. + + @param SrcBuffer The buffer storing the source data + @param SrcSize The size of source data + @param DstBuffer The buffer to store the compressed data + @param DstSize On input, the size of DstBuffer; On output, + the size of the actual compressed data. + + @retval EFI_BUFFER_TOO_SMALL The DstBuffer is too small. In this case, + DstSize contains the size needed. + @retval EFI_SUCCESS Compression is successful. + +**/ +EFI_STATUS +EfiCompress ( + IN UINT8 *SrcBuffer, + IN UINT32 SrcSize, + IN UINT8 *DstBuffer, + IN OUT UINT32 *DstSize + ) +{ + EFI_STATUS Status = EFI_SUCCESS; + + // + // Initializations + // + mBufSiz = 0; + mBuf = NULL; + mText = NULL; + mLevel = NULL; + mChildCount = NULL; + mPosition = NULL; + mParent = NULL; + mPrev = NULL; + mNext = NULL; + + + mSrc = SrcBuffer; + mSrcUpperLimit = mSrc + SrcSize; + mDst = DstBuffer; + mDstUpperLimit = mDst + *DstSize; + + PutDword(0L); + PutDword(0L); + + MakeCrcTable (); + + mOrigSize = mCompSize = 0; + mCrc = INIT_CRC; + + // + // Compress it + // + + Status = Encode(); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Null terminate the compressed data + // + if (mDst < mDstUpperLimit) { + *mDst++ = 0; + } + + // + // Fill in compressed size and original size + // + mDst = DstBuffer; + PutDword(mCompSize+1); + PutDword(mOrigSize); + + // + // Return + // + + if (mCompSize + 1 + 8 > *DstSize) { + *DstSize = mCompSize + 1 + 8; + return EFI_BUFFER_TOO_SMALL; + } else { + *DstSize = mCompSize + 1 + 8; + return EFI_SUCCESS; + } + +} + +/** + Put a dword to output stream + + @param Data the dword to put +**/ +STATIC +VOID +PutDword( + IN UINT32 Data + ) +{ + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8)(((UINT8)(Data )) & 0xff); + } + + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8)(((UINT8)(Data >> 0x08)) & 0xff); + } + + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8)(((UINT8)(Data >> 0x10)) & 0xff); + } + + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8)(((UINT8)(Data >> 0x18)) & 0xff); + } +} + +/** + Allocate memory spaces for data structures used in compression process + + @retval EFI_SUCCESS Memory is allocated successfully + @retva; EFI_OUT_OF_RESOURCES Allocation fails +**/ +STATIC +EFI_STATUS +AllocateMemory () +{ + UINT32 i; + + mText = malloc (WNDSIZ * 2 + MAXMATCH); + if (mText == NULL) { + return EFI_OUT_OF_RESOURCES; + } + for (i = 0 ; i < WNDSIZ * 2 + MAXMATCH; i ++) { + mText[i] = 0; + } + + mLevel = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof(*mLevel)); + mChildCount = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof(*mChildCount)); + mPosition = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof(*mPosition)); + mParent = malloc (WNDSIZ * 2 * sizeof(*mParent)); + mPrev = malloc (WNDSIZ * 2 * sizeof(*mPrev)); + mNext = malloc ((MAX_HASH_VAL + 1) * sizeof(*mNext)); + if (mLevel == NULL || mChildCount == NULL || mPosition == NULL || + mParent == NULL || mPrev == NULL || mNext == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + mBufSiz = 16 * 1024U; + while ((mBuf = malloc(mBufSiz)) == NULL) { + mBufSiz = (mBufSiz / 10U) * 9U; + if (mBufSiz < 4 * 1024U) { + return EFI_OUT_OF_RESOURCES; + } + } + mBuf[0] = 0; + + return EFI_SUCCESS; +} + +/** + Called when compression is completed to free memory previously allocated. +**/ +VOID +FreeMemory () +{ + if (mText) { + free (mText); + } + + if (mLevel) { + free (mLevel); + } + + if (mChildCount) { + free (mChildCount); + } + + if (mPosition) { + free (mPosition); + } + + if (mParent) { + free (mParent); + } + + if (mPrev) { + free (mPrev); + } + + if (mNext) { + free (mNext); + } + + if (mBuf) { + free (mBuf); + } + + return; +} + +/** + Initialize String Info Log data structures +**/ +STATIC +VOID +InitSlide () +{ + NODE i; + + for (i = WNDSIZ; i <= WNDSIZ + UINT8_MAX; i++) { + mLevel[i] = 1; + mPosition[i] = NIL; /* sentinel */ + } + for (i = WNDSIZ; i < WNDSIZ * 2; i++) { + mParent[i] = NIL; + } + mAvail = 1; + for (i = 1; i < WNDSIZ - 1; i++) { + mNext[i] = (NODE)(i + 1); + } + + mNext[WNDSIZ - 1] = NIL; + for (i = WNDSIZ * 2; i <= MAX_HASH_VAL; i++) { + mNext[i] = NIL; + } +} + +/** + Find child node given the parent node and the edge character + + @param q the parent node + @param c the edge character + + @return The child node (NIL if not found) +**/ +STATIC +NODE +Child ( + IN NODE q, + IN UINT8 c + ) +{ + NODE r; + + r = mNext[HASH(q, c)]; + mParent[NIL] = q; /* sentinel */ + while (mParent[r] != q) { + r = mNext[r]; + } + + return r; +} + +/** + Create a new child for a given parent node. + + @param q the parent node + @param c the edge character + @param r the child node +**/ +STATIC +VOID +MakeChild ( + IN NODE q, + IN UINT8 c, + IN NODE r + ) +{ + NODE h, t; + + h = (NODE)HASH(q, c); + t = mNext[h]; + mNext[h] = r; + mNext[r] = t; + mPrev[t] = r; + mPrev[r] = h; + mParent[r] = q; + mChildCount[q]++; +} + +/** + Split a node. + + @param Old the node to split +**/ +STATIC +VOID +Split ( + NODE Old + ) +{ + NODE New, t; + + New = mAvail; + mAvail = mNext[New]; + mChildCount[New] = 0; + t = mPrev[Old]; + mPrev[New] = t; + mNext[t] = New; + t = mNext[Old]; + mNext[New] = t; + mPrev[t] = New; + mParent[New] = mParent[Old]; + mLevel[New] = (UINT8)mMatchLen; + mPosition[New] = mPos; + MakeChild(New, mText[mMatchPos + mMatchLen], Old); + MakeChild(New, mText[mPos + mMatchLen], mPos); +} + +/** + Insert string info for current position into the String Info Log +**/ +STATIC +VOID +InsertNode () +{ + NODE q, r, j, t; + UINT8 c, *t1, *t2; + + if (mMatchLen >= 4) { + + // + // We have just got a long match, the target tree + // can be located by MatchPos + 1. Traverse the tree + // from bottom up to get to a proper starting point. + // The usage of PERC_FLAG ensures proper node deletion + // in DeleteNode() later. + // + + mMatchLen--; + r = (INT16)((mMatchPos + 1) | WNDSIZ); + while ((q = mParent[r]) == NIL) { + r = mNext[r]; + } + while (mLevel[q] >= mMatchLen) { + r = q; q = mParent[q]; + } + t = q; + while (mPosition[t] < 0) { + mPosition[t] = mPos; + t = mParent[t]; + } + if (t < WNDSIZ) { + mPosition[t] = (NODE)(mPos | PERC_FLAG); + } + } else { + + // + // Locate the target tree + // + + q = (INT16)(mText[mPos] + WNDSIZ); + c = mText[mPos + 1]; + if ((r = Child(q, c)) == NIL) { + MakeChild(q, c, mPos); + mMatchLen = 1; + return; + } + mMatchLen = 2; + } + + // + // Traverse down the tree to find a match. + // Update Position value along the route. + // Node split or creation is involved. + // + + for ( ; ; ) { + if (r >= WNDSIZ) { + j = MAXMATCH; + mMatchPos = r; + } else { + j = mLevel[r]; + mMatchPos = (NODE)(mPosition[r] & ~PERC_FLAG); + } + if (mMatchPos >= mPos) { + mMatchPos -= WNDSIZ; + } + t1 = &mText[mPos + mMatchLen]; + t2 = &mText[mMatchPos + mMatchLen]; + while (mMatchLen < j) { + if (*t1 != *t2) { + Split(r); + return; + } + mMatchLen++; + t1++; + t2++; + } + if (mMatchLen >= MAXMATCH) { + break; + } + mPosition[r] = mPos; + q = r; + if ((r = Child(q, *t1)) == NIL) { + MakeChild(q, *t1, mPos); + return; + } + mMatchLen++; + } + t = mPrev[r]; + mPrev[mPos] = t; + mNext[t] = mPos; + t = mNext[r]; + mNext[mPos] = t; + mPrev[t] = mPos; + mParent[mPos] = q; + mParent[r] = NIL; + + // + // Special usage of 'next' + // + mNext[r] = mPos; + +} + +/** + Delete outdated string info. (The Usage of PERC_FLAG + ensures a clean deletion) +**/ +STATIC +VOID +DeleteNode () +{ + NODE q, r, s, t, u; + + if (mParent[mPos] == NIL) { + return; + } + + r = mPrev[mPos]; + s = mNext[mPos]; + mNext[r] = s; + mPrev[s] = r; + r = mParent[mPos]; + mParent[mPos] = NIL; + if (r >= WNDSIZ || --mChildCount[r] > 1) { + return; + } + t = (NODE)(mPosition[r] & ~PERC_FLAG); + if (t >= mPos) { + t -= WNDSIZ; + } + s = t; + q = mParent[r]; + while ((u = mPosition[q]) & PERC_FLAG) { + u &= ~PERC_FLAG; + if (u >= mPos) { + u -= WNDSIZ; + } + if (u > s) { + s = u; + } + mPosition[q] = (INT16)(s | WNDSIZ); + q = mParent[q]; + } + if (q < WNDSIZ) { + if (u >= mPos) { + u -= WNDSIZ; + } + if (u > s) { + s = u; + } + mPosition[q] = (INT16)(s | WNDSIZ | PERC_FLAG); + } + s = Child(r, mText[t + mLevel[r]]); + t = mPrev[s]; + u = mNext[s]; + mNext[t] = u; + mPrev[u] = t; + t = mPrev[r]; + mNext[t] = s; + mPrev[s] = t; + t = mNext[r]; + mPrev[t] = s; + mNext[s] = t; + mParent[s] = mParent[r]; + mParent[r] = NIL; + mNext[r] = mAvail; + mAvail = r; +} + +/** + Advance the current position (read in new data if needed). + Delete outdated string info. Find a match string for current position. +**/ +STATIC +VOID +GetNextMatch () +{ + INT32 n; + + mRemainder--; + if (++mPos == WNDSIZ * 2) { + memmove(&mText[0], &mText[WNDSIZ], WNDSIZ + MAXMATCH); + n = FreadCrc(&mText[WNDSIZ + MAXMATCH], WNDSIZ); + mRemainder += n; + mPos = WNDSIZ; + } + DeleteNode(); + InsertNode(); +} + +/** + The main controlling routine for compression process. + + @retval EFI_SUCCESS The compression is successful + @retval EFI_OUT_0F_RESOURCES Not enough memory for compression process +**/ +STATIC +EFI_STATUS +Encode () +{ + EFI_STATUS Status; + INT32 LastMatchLen; + NODE LastMatchPos; + + Status = AllocateMemory(); + if (EFI_ERROR(Status)) { + FreeMemory(); + return Status; + } + + InitSlide(); + + HufEncodeStart(); + + mRemainder = FreadCrc(&mText[WNDSIZ], WNDSIZ + MAXMATCH); + + mMatchLen = 0; + mPos = WNDSIZ; + InsertNode(); + if (mMatchLen > mRemainder) { + mMatchLen = mRemainder; + } + while (mRemainder > 0) { + LastMatchLen = mMatchLen; + LastMatchPos = mMatchPos; + GetNextMatch(); + if (mMatchLen > mRemainder) { + mMatchLen = mRemainder; + } + + if (mMatchLen > LastMatchLen || LastMatchLen < THRESHOLD) { + + // + // Not enough benefits are gained by outputting a pointer, + // so just output the original character + // + + Output(mText[mPos - 1], 0); + } else { + + // + // Outputting a pointer is beneficial enough, do it. + // + + Output(LastMatchLen + (UINT8_MAX + 1 - THRESHOLD), + (mPos - LastMatchPos - 2) & (WNDSIZ - 1)); + while (--LastMatchLen > 0) { + GetNextMatch(); + } + if (mMatchLen > mRemainder) { + mMatchLen = mRemainder; + } + } + } + + HufEncodeEnd(); + FreeMemory(); + return EFI_SUCCESS; +} + +/** + Count the frequencies for the Extra Set +**/ +STATIC +VOID +CountTFreq () +{ + INT32 i, k, n, Count; + + for (i = 0; i < NT; i++) { + mTFreq[i] = 0; + } + n = NC; + while (n > 0 && mCLen[n - 1] == 0) { + n--; + } + i = 0; + while (i < n) { + k = mCLen[i++]; + if (k == 0) { + Count = 1; + while (i < n && mCLen[i] == 0) { + i++; + Count++; + } + if (Count <= 2) { + mTFreq[0] = (UINT16)(mTFreq[0] + Count); + } else if (Count <= 18) { + mTFreq[1]++; + } else if (Count == 19) { + mTFreq[0]++; + mTFreq[1]++; + } else { + mTFreq[2]++; + } + } else { + mTFreq[k + 2]++; + } + } +} + +/** + Outputs the code length array for the Extra Set or the Position Set. + + @param n the number of symbols + @param nbit the number of bits needed to represent 'n' + @param Special the special symbol that needs to be take care of +**/ +STATIC +VOID +WritePTLen ( + IN INT32 n, + IN INT32 nbit, + IN INT32 Special + ) +{ + INT32 i, k; + + while (n > 0 && mPTLen[n - 1] == 0) { + n--; + } + PutBits(nbit, n); + i = 0; + while (i < n) { + k = mPTLen[i++]; + if (k <= 6) { + PutBits(3, k); + } else { + PutBits(k - 3, (1U << (k - 3)) - 2); + } + if (i == Special) { + while (i < 6 && mPTLen[i] == 0) { + i++; + } + PutBits(2, (i - 3) & 3); + } + } +} + +/** + Outputs the code length array for Char&Length Set +**/ +STATIC +VOID +WriteCLen () +{ + INT32 i, k, n, Count; + + n = NC; + while (n > 0 && mCLen[n - 1] == 0) { + n--; + } + PutBits(CBIT, n); + i = 0; + while (i < n) { + k = mCLen[i++]; + if (k == 0) { + Count = 1; + while (i < n && mCLen[i] == 0) { + i++; + Count++; + } + if (Count <= 2) { + for (k = 0; k < Count; k++) { + PutBits(mPTLen[0], mPTCode[0]); + } + } else if (Count <= 18) { + PutBits(mPTLen[1], mPTCode[1]); + PutBits(4, Count - 3); + } else if (Count == 19) { + PutBits(mPTLen[0], mPTCode[0]); + PutBits(mPTLen[1], mPTCode[1]); + PutBits(4, 15); + } else { + PutBits(mPTLen[2], mPTCode[2]); + PutBits(CBIT, Count - 20); + } + } else { + PutBits(mPTLen[k + 2], mPTCode[k + 2]); + } + } +} + +STATIC +VOID +EncodeC ( + IN INT32 c + ) +{ + PutBits(mCLen[c], mCCode[c]); +} + +STATIC +VOID +EncodeP ( + IN UINT32 p + ) +{ + UINT32 c, q; + + c = 0; + q = p; + while (q) { + q >>= 1; + c++; + } + PutBits(mPTLen[c], mPTCode[c]); + if (c > 1) { + PutBits(c - 1, p & (0xFFFFU >> (17 - c))); + } +} + +/** + Huffman code the block and output it. +**/ +STATIC +VOID +SendBlock () +{ + UINT32 i, k, Flags, Root, Pos, Size; + Flags = 0; + + Root = MakeTree(NC, mCFreq, mCLen, mCCode); + Size = mCFreq[Root]; + PutBits(16, Size); + if (Root >= NC) { + CountTFreq(); + Root = MakeTree(NT, mTFreq, mPTLen, mPTCode); + if (Root >= NT) { + WritePTLen(NT, TBIT, 3); + } else { + PutBits(TBIT, 0); + PutBits(TBIT, Root); + } + WriteCLen(); + } else { + PutBits(TBIT, 0); + PutBits(TBIT, 0); + PutBits(CBIT, 0); + PutBits(CBIT, Root); + } + Root = MakeTree(NP, mPFreq, mPTLen, mPTCode); + if (Root >= NP) { + WritePTLen(NP, PBIT, -1); + } else { + PutBits(PBIT, 0); + PutBits(PBIT, Root); + } + Pos = 0; + for (i = 0; i < Size; i++) { + if (i % UINT8_BIT == 0) { + Flags = mBuf[Pos++]; + } else { + Flags <<= 1; + } + if (Flags & (1U << (UINT8_BIT - 1))) { + EncodeC(mBuf[Pos++] + (1U << UINT8_BIT)); + k = mBuf[Pos++] << UINT8_BIT; + k += mBuf[Pos++]; + EncodeP(k); + } else { + EncodeC(mBuf[Pos++]); + } + } + for (i = 0; i < NC; i++) { + mCFreq[i] = 0; + } + for (i = 0; i < NP; i++) { + mPFreq[i] = 0; + } +} + +/** + Outputs an Original Character or a Pointer + + @param c The original character or the 'String Length' element of a Pointer + @param p The 'Position' field of a Pointer +**/ +STATIC +VOID +Output ( + IN UINT32 c, + IN UINT32 p + ) +{ + STATIC UINT32 CPos; + + if ((mOutputMask >>= 1) == 0) { + mOutputMask = 1U << (UINT8_BIT - 1); + if (mOutputPos >= mBufSiz - 3 * UINT8_BIT) { + SendBlock(); + mOutputPos = 0; + } + CPos = mOutputPos++; + mBuf[CPos] = 0; + } + mBuf[mOutputPos++] = (UINT8) c; + mCFreq[c]++; + if (c >= (1U << UINT8_BIT)) { + mBuf[CPos] |= mOutputMask; + mBuf[mOutputPos++] = (UINT8)(p >> UINT8_BIT); + mBuf[mOutputPos++] = (UINT8) p; + c = 0; + while (p) { + p >>= 1; + c++; + } + mPFreq[c]++; + } +} + +STATIC +VOID +HufEncodeStart () +{ + INT32 i; + + for (i = 0; i < NC; i++) { + mCFreq[i] = 0; + } + for (i = 0; i < NP; i++) { + mPFreq[i] = 0; + } + mOutputPos = mOutputMask = 0; + InitPutBits(); + return; +} + +STATIC +VOID +HufEncodeEnd () +{ + SendBlock(); + + // + // Flush remaining bits + // + PutBits(UINT8_BIT - 1, 0); + + return; +} + + +STATIC +VOID +MakeCrcTable () +{ + UINT32 i, j, r; + + for (i = 0; i <= UINT8_MAX; i++) { + r = i; + for (j = 0; j < UINT8_BIT; j++) { + if (r & 1) { + r = (r >> 1) ^ CRCPOLY; + } else { + r >>= 1; + } + } + mCrcTable[i] = (UINT16)r; + } +} + +/** + Outputs rightmost n bits of x + + @param n the rightmost n bits of the data is used + @param x the data +**/ +STATIC +VOID +PutBits ( + IN INT32 n, + IN UINT32 x + ) +{ + UINT8 Temp; + + if (n < mBitCount) { + mSubBitBuf |= x << (mBitCount -= n); + } else { + + Temp = (UINT8)(mSubBitBuf | (x >> (n -= mBitCount))); + if (mDst < mDstUpperLimit) { + *mDst++ = Temp; + } + mCompSize++; + + if (n < UINT8_BIT) { + mSubBitBuf = x << (mBitCount = UINT8_BIT - n); + } else { + + Temp = (UINT8)(x >> (n - UINT8_BIT)); + if (mDst < mDstUpperLimit) { + *mDst++ = Temp; + } + mCompSize++; + + mSubBitBuf = x << (mBitCount = 2 * UINT8_BIT - n); + } + } +} + +/** + Read in source data + + @param p the buffer to hold the data + @param n number of bytes to read + + @return number of bytes actually read +**/ +STATIC +INT32 +FreadCrc ( + OUT UINT8 *p, + IN INT32 n + ) +{ + INT32 i; + + for (i = 0; mSrc < mSrcUpperLimit && i < n; i++) { + *p++ = *mSrc++; + } + n = i; + + p -= n; + mOrigSize += n; + while (--i >= 0) { + UPDATE_CRC(*p++); + } + return n; +} + + +STATIC +VOID +InitPutBits () +{ + mBitCount = UINT8_BIT; + mSubBitBuf = 0; +} + +/** + Count the number of each code length for a Huffman tree. + + @param i the top node +**/ +STATIC +VOID +CountLen ( + IN INT32 i + ) +{ + STATIC INT32 Depth = 0; + + if (i < mN) { + mLenCnt[(Depth < 16) ? Depth : 16]++; + } else { + Depth++; + CountLen(mLeft [i]); + CountLen(mRight[i]); + Depth--; + } +} + +/** + Create code length array for a Huffman tree + + @param Root the root of the tree +**/ +STATIC +VOID +MakeLen ( + IN INT32 Root + ) +{ + INT32 i, k; + UINT32 Cum; + + for (i = 0; i <= 16; i++) { + mLenCnt[i] = 0; + } + CountLen(Root); + + // + // Adjust the length count array so that + // no code will be generated longer than its designated length + // + + Cum = 0; + for (i = 16; i > 0; i--) { + Cum += mLenCnt[i] << (16 - i); + } + while (Cum != (1U << 16)) { + mLenCnt[16]--; + for (i = 15; i > 0; i--) { + if (mLenCnt[i] != 0) { + mLenCnt[i]--; + mLenCnt[i+1] += 2; + break; + } + } + Cum--; + } + for (i = 16; i > 0; i--) { + k = mLenCnt[i]; + while (--k >= 0) { + mLen[*mSortPtr++] = (UINT8)i; + } + } +} + +STATIC +VOID +DownHeap ( + IN INT32 i + ) +{ + INT32 j, k; + + // + // priority queue: send i-th entry down heap + // + + k = mHeap[i]; + while ((j = 2 * i) <= mHeapSize) { + if (j < mHeapSize && mFreq[mHeap[j]] > mFreq[mHeap[j + 1]]) { + j++; + } + if (mFreq[k] <= mFreq[mHeap[j]]) { + break; + } + mHeap[i] = mHeap[j]; + i = j; + } + mHeap[i] = (INT16)k; +} + +/** + Assign code to each symbol based on the code length array + + @param n number of symbols + @param Len the code length array + @param Code stores codes for each symbol +**/ +STATIC +VOID +MakeCode ( + IN INT32 n, + IN UINT8 Len[], + OUT UINT16 Code[] + ) +{ + INT32 i; + UINT16 Start[18]; + + Start[1] = 0; + for (i = 1; i <= 16; i++) { + Start[i + 1] = (UINT16)((Start[i] + mLenCnt[i]) << 1); + } + for (i = 0; i < n; i++) { + Code[i] = Start[Len[i]]++; + } +} + +/** + Generates Huffman codes given a frequency distribution of symbols + + @param NParm number of symbols + @param FreqParm frequency of each symbol + @param LenParm code length for each symbol + @param CodeParm code for each symbol + + @return Root of the Huffman tree. +**/ +STATIC +INT32 +MakeTree ( + IN INT32 NParm, + IN UINT16 FreqParm[], + OUT UINT8 LenParm[], + OUT UINT16 CodeParm[] + ) +{ + INT32 i, j, k, Avail; + + // + // make tree, calculate len[], return root + // + + mN = NParm; + mFreq = FreqParm; + mLen = LenParm; + Avail = mN; + mHeapSize = 0; + mHeap[1] = 0; + for (i = 0; i < mN; i++) { + mLen[i] = 0; + if (mFreq[i]) { + mHeap[++mHeapSize] = (INT16)i; + } + } + if (mHeapSize < 2) { + CodeParm[mHeap[1]] = 0; + return mHeap[1]; + } + for (i = mHeapSize / 2; i >= 1; i--) { + + // + // make priority queue + // + DownHeap(i); + } + mSortPtr = CodeParm; + do { + i = mHeap[1]; + if (i < mN) { + *mSortPtr++ = (UINT16)i; + } + mHeap[1] = mHeap[mHeapSize--]; + DownHeap(1); + j = mHeap[1]; + if (j < mN) { + *mSortPtr++ = (UINT16)j; + } + k = Avail++; + mFreq[k] = (UINT16)(mFreq[i] + mFreq[j]); + mHeap[1] = (INT16)k; + DownHeap(1); + mLeft[k] = (UINT16)i; + mRight[k] = (UINT16)j; + } while (mHeapSize > 1); + + mSortPtr = CodeParm; + MakeLen(k); + MakeCode(NParm, LenParm, CodeParm); + + // + // return root + // + return k; +} + diff --git a/BaseTools/Source/C/Common/EfiUtilityMsgs.c b/BaseTools/Source/C/Common/EfiUtilityMsgs.c index faf354064c..a40ad93c0c 100644 --- a/BaseTools/Source/C/Common/EfiUtilityMsgs.c +++ b/BaseTools/Source/C/Common/EfiUtilityMsgs.c @@ -1,788 +1,788 @@ -/** @file
-EFI tools utility functions to display warning, error, and informational messages
-
-Copyright (c) 2004 - 2017, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
---*/
-
-#include <stdio.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdarg.h>
-#include <time.h>
-
-#include "EfiUtilityMsgs.h"
-
-//
-// Declare module globals for keeping track of the utility's
-// name and other settings.
-//
-STATIC STATUS mStatus = STATUS_SUCCESS;
-STATIC CHAR8 mUtilityName[50] = { 0 };
-STATIC UINT64 mPrintLogLevel = INFO_LOG_LEVEL;
-STATIC CHAR8 *mSourceFileName = NULL;
-STATIC UINT32 mSourceFileLineNum = 0;
-STATIC UINT32 mErrorCount = 0;
-STATIC UINT32 mWarningCount = 0;
-STATIC UINT32 mMaxErrors = 0;
-STATIC UINT32 mMaxWarnings = 0;
-STATIC UINT32 mMaxWarningsPlusErrors = 0;
-STATIC INT8 mPrintLimitsSet = 0;
-
-STATIC
-VOID
-PrintLimitExceeded (
- VOID
- );
-
-/**
- Prints an error message.
-
- All arguments are optional, though the printed message may be useless if
- at least something valid is not specified.
-
- @note:
- We print the following (similar to the Warn() and Debug()
- W
- Typical error/warning message format:
-
- bin\VfrCompile.cpp(330) : error C2660: 'AddVfrDataStructField' : function does not take 2 parameters
-
- BUGBUG -- these three utility functions are almost identical, and
- should be modified to share code.
-
- Visual Studio does not find error messages with:
-
- " error :"
- " error 1:"
- " error c1:"
- " error 1000:"
- " error c100:"
-
- It does find:
- " error c1000:"
-
- @param FileName name of the file or application. If not specified, then the
- utility name (as set by the utility calling SetUtilityName()
- earlier) is used. Otherwise "Unknown utility" is used.
-
- @param LineNumber the line number of error, typically used by parsers. If the
- utility is not a parser, then 0 should be specified. Otherwise
- the FileName and LineNumber info can be used to cause
- MS Visual Studio to jump to the error.
-
- @param MessageCode an application-specific error code that can be referenced in
- other documentation.
-
- @param Text the text in question, typically used by parsers.
-
- @param MsgFmt the format string for the error message. Can contain formatting
- controls for use with the varargs.
-**/
-VOID
-Error (
- CHAR8 *FileName,
- UINT32 LineNumber,
- UINT32 MessageCode,
- CHAR8 *Text,
- CHAR8 *MsgFmt,
- ...
- )
-{
- va_list List;
- //
- // If limits have been set, then check that we have not exceeded them
- //
- if (mPrintLimitsSet) {
- //
- // See if we've exceeded our total count
- //
- if (mMaxWarningsPlusErrors != 0) {
- if (mErrorCount + mWarningCount > mMaxWarningsPlusErrors) {
- PrintLimitExceeded ();
- return ;
- }
- }
- //
- // See if we've exceeded our error count
- //
- if (mMaxErrors != 0) {
- if (mErrorCount > mMaxErrors) {
- PrintLimitExceeded ();
- return ;
- }
- }
- }
-
- mErrorCount++;
- va_start (List, MsgFmt);
- PrintMessage ("ERROR", FileName, LineNumber, MessageCode, Text, MsgFmt, List);
- va_end (List);
-}
-
-/**
- Print a parser error, using the source file name and line number
- set by a previous call to SetParserPosition().
-
- @param MessageCode application-specific error code
- @param Text text to print in the error message
- @param MsgFmt format string to print at the end of the error message
-**/
-VOID
-ParserError (
- UINT32 MessageCode,
- CHAR8 *Text,
- CHAR8 *MsgFmt,
- ...
- )
-{
- va_list List;
- //
- // If limits have been set, then check them
- //
- if (mPrintLimitsSet) {
- //
- // See if we've exceeded our total count
- //
- if (mMaxWarningsPlusErrors != 0) {
- if (mErrorCount + mWarningCount > mMaxWarningsPlusErrors) {
- PrintLimitExceeded ();
- return ;
- }
- }
- //
- // See if we've exceeded our error count
- //
- if (mMaxErrors != 0) {
- if (mErrorCount > mMaxErrors) {
- PrintLimitExceeded ();
- return ;
- }
- }
- }
-
- mErrorCount++;
- va_start (List, MsgFmt);
- PrintMessage ("ERROR", mSourceFileName, mSourceFileLineNum, MessageCode, Text, MsgFmt, List);
- va_end (List);
-}
-
-/**
- Print a parser warning, using the source file name and line number
- set by a previous call to SetParserPosition().
-
- @param ErrorCode application-specific error code
- @param OffendingText text to print in the warning message
- @param MsgFmt format string to print at the end of the warning message
-**/
-VOID
-ParserWarning (
- UINT32 ErrorCode,
- CHAR8 *OffendingText,
- CHAR8 *MsgFmt,
- ...
- )
-{
- va_list List;
- //
- // If limits have been set, then check them
- //
- if (mPrintLimitsSet) {
- //
- // See if we've exceeded our total count
- //
- if (mMaxWarningsPlusErrors != 0) {
- if (mErrorCount + mWarningCount > mMaxWarningsPlusErrors) {
- PrintLimitExceeded ();
- return ;
- }
- }
- //
- // See if we've exceeded our warning count
- //
- if (mMaxWarnings != 0) {
- if (mWarningCount > mMaxWarnings) {
- PrintLimitExceeded ();
- return ;
- }
- }
- }
-
- mWarningCount++;
- va_start (List, MsgFmt);
- PrintMessage ("WARNING", mSourceFileName, mSourceFileLineNum, ErrorCode, OffendingText, MsgFmt, List);
- va_end (List);
- //
- // Don't set warning status accordingly
- //
- // if (mStatus < STATUS_WARNING) {
- // mStatus = STATUS_WARNING;
- // }
-}
-
-/**
- Print a warning message.
-
- @param FileName name of the file where the warning was detected, or the name
- of the application that detected the warning
- @param LineNumber the line number where the warning was detected (parsers).
- 0 should be specified if the utility is not a parser.
- @param MessageCode an application-specific warning code that can be referenced in
- other documentation.
- @param Text the text in question (parsers)
- @param MsgFmt the format string for the warning message. Can contain formatting
- controls for use with varargs.
-**/
-VOID
-Warning (
- CHAR8 *FileName,
- UINT32 LineNumber,
- UINT32 MessageCode,
- CHAR8 *Text,
- CHAR8 *MsgFmt,
- ...
- )
-{
- va_list List;
-
- //
- // Current Print Level not output warning information.
- //
- if (WARNING_LOG_LEVEL < mPrintLogLevel) {
- return;
- }
- //
- // If limits have been set, then check them
- //
- if (mPrintLimitsSet) {
- //
- // See if we've exceeded our total count
- //
- if (mMaxWarningsPlusErrors != 0) {
- if (mErrorCount + mWarningCount > mMaxWarningsPlusErrors) {
- PrintLimitExceeded ();
- return ;
- }
- }
- //
- // See if we've exceeded our warning count
- //
- if (mMaxWarnings != 0) {
- if (mWarningCount > mMaxWarnings) {
- PrintLimitExceeded ();
- return ;
- }
- }
- }
-
- mWarningCount++;
- va_start (List, MsgFmt);
- PrintMessage ("WARNING", FileName, LineNumber, MessageCode, Text, MsgFmt, List);
- va_end (List);
-}
-
-/**
- Print a Debug message.
-
- @param FileName typically the name of the utility printing the debug message, but
- can be the name of a file being parsed.
- @param LineNumber the line number in FileName (parsers)
- @param MsgLevel Debug message print level (0~9)
- @param Text the text in question (parsers)
- @param MsgFmt the format string for the debug message. Can contain formatting
- controls for use with varargs.
-
-**/
-VOID
-DebugMsg (
- CHAR8 *FileName,
- UINT32 LineNumber,
- UINT64 MsgLevel,
- CHAR8 *Text,
- CHAR8 *MsgFmt,
- ...
- )
-{
- va_list List;
- //
- // If the debug level is less than current print level, then do nothing.
- //
- if (MsgLevel < mPrintLogLevel) {
- return ;
- }
-
- va_start (List, MsgFmt);
- PrintMessage ("DEBUG", FileName, LineNumber, 0, Text, MsgFmt, List);
- va_end (List);
-}
-
-/**
- Worker routine for all the utility printing services. Prints the message in
- a format that Visual Studio will find when scanning build outputs for
- errors or warnings.
-
- @note:
- If FileName == NULL then this utility will use the string passed into SetUtilityName().
-
- LineNumber is only used if the caller is a parser, in which case FileName refers to the
- file being parsed.
-
- Text and MsgFmt are both optional, though it would be of little use calling this function with
- them both NULL.
-
- Output will typically be of the form:
- <FileName>(<LineNumber>) : <Type> <Type[0]><MessageCode>: <Text> : <MsgFmt>
-
- Parser (LineNumber != 0)
- VfrCompile.cpp(330) : error E2660: AddVfrDataStructField : function does not take 2 parameters
- Generic utility (LineNumber == 0)
- UtilityName : error E1234 : Text string : MsgFmt string and args
-
- @param Type "warning" or "error" string to insert into the message to be
- printed. The first character of this string (converted to uppercase)
- is used to precede the MessageCode value in the output string.
- @param FileName name of the file where the warning was detected, or the name
- of the application that detected the warning
- @param LineNumber the line number where the warning was detected (parsers).
- 0 should be specified if the utility is not a parser.
- @param MessageCode an application-specific warning code that can be referenced in
- other documentation.
- @param Text part of the message to print
- @param MsgFmt the format string for the message. Can contain formatting
- controls for use with varargs.
- @param List the variable list.
-**/
-VOID
-PrintMessage (
- CHAR8 *Type,
- CHAR8 *FileName,
- UINT32 LineNumber,
- UINT32 MessageCode,
- CHAR8 *Text,
- CHAR8 *MsgFmt,
- va_list List
- )
-{
- CHAR8 Line[MAX_LINE_LEN];
- CHAR8 Line2[MAX_LINE_LEN];
- CHAR8 *Cptr;
- struct tm *NewTime;
- time_t CurrentTime;
-
- //
- // init local variable
- //
- Line[0] = '\0';
- Line2[0] = '\0';
-
- //
- // If given a filename, then add it (and the line number) to the string.
- // If there's no filename, then use the program name if provided.
- //
- if (FileName != NULL) {
- Cptr = FileName;
- } else {
- Cptr = NULL;
- }
-
- if (strcmp (Type, "DEBUG") == 0) {
- //
- // Debug Message requires current time.
- //
- time (&CurrentTime);
- NewTime = localtime (&CurrentTime);
- if (NewTime != NULL) {
- fprintf (stdout, "%04d-%02d-%02d %02d:%02d:%02d",
- NewTime->tm_year + 1900,
- NewTime->tm_mon + 1,
- NewTime->tm_mday,
- NewTime->tm_hour,
- NewTime->tm_min,
- NewTime->tm_sec
- );
- }
- if (Cptr != NULL) {
- strcpy (Line, ": ");
- strncat (Line, Cptr, MAX_LINE_LEN - strlen (Line) - 1);
- if (LineNumber != 0) {
- sprintf (Line2, "(%u)", (unsigned) LineNumber);
- strncat (Line, Line2, MAX_LINE_LEN - strlen (Line) - 1);
- }
- }
- } else {
- //
- // Error and Warning Information.
- //
- if (Cptr != NULL) {
- if (mUtilityName[0] != '\0') {
- fprintf (stdout, "%s...\n", mUtilityName);
- }
- strncpy (Line, Cptr, MAX_LINE_LEN - 1);
- Line[MAX_LINE_LEN - 1] = 0;
- if (LineNumber != 0) {
- sprintf (Line2, "(%u)", (unsigned) LineNumber);
- strncat (Line, Line2, MAX_LINE_LEN - strlen (Line) - 1);
- }
- } else {
- if (mUtilityName[0] != '\0') {
- strncpy (Line, mUtilityName, MAX_LINE_LEN - 1);
- Line[MAX_LINE_LEN - 1] = 0;
- }
- }
-
- if (strcmp (Type, "ERROR") == 0) {
- //
- // Set status accordingly for ERROR information.
- //
- if (mStatus < STATUS_ERROR) {
- mStatus = STATUS_ERROR;
- }
- }
- }
-
- //
- // Have to print an error code or Visual Studio won't find the
- // message for you. It has to be decimal digits too.
- //
- strncat (Line, ": ", MAX_LINE_LEN - strlen (Line) - 1);
- strncat (Line, Type, MAX_LINE_LEN - strlen (Line) - 1);
- if (MessageCode != 0) {
- sprintf (Line2, " %04u", (unsigned) MessageCode);
- strncat (Line, Line2, MAX_LINE_LEN - strlen (Line) - 1);
- }
- fprintf (stdout, "%s", Line);
- //
- // If offending text was provided, then print it
- //
- if (Text != NULL) {
- fprintf (stdout, ": %s", Text);
- }
- fprintf (stdout, "\n");
-
- //
- // Print formatted message if provided
- //
- if (MsgFmt != NULL) {
- vsprintf (Line2, MsgFmt, List);
- fprintf (stdout, " %s\n", Line2);
- }
-
-}
-
-/**
- Print message into stdout.
-
- @param MsgFmt the format string for the message. Can contain formatting
- controls for use with varargs.
- @param List the variable list.
-**/
-STATIC
-VOID
-PrintSimpleMessage (
- CHAR8 *MsgFmt,
- va_list List
- )
-{
- CHAR8 Line[MAX_LINE_LEN];
- //
- // Print formatted message if provided
- //
- if (MsgFmt != NULL) {
- vsprintf (Line, MsgFmt, List);
- fprintf (stdout, "%s\n", Line);
- }
-}
-
-/**
- Set the position in a file being parsed. This can be used to
- print error messages deeper down in a parser.
-
- @param SourceFileName name of the source file being parsed
- @param LineNum line number of the source file being parsed
-**/
-VOID
-ParserSetPosition (
- CHAR8 *SourceFileName,
- UINT32 LineNum
- )
-{
- mSourceFileName = SourceFileName;
- mSourceFileLineNum = LineNum;
-}
-
-/**
- All printed error/warning/debug messages follow the same format, and
- typically will print a filename or utility name followed by the error
- text. However if a filename is not passed to the print routines, then
- they'll print the utility name if you call this function early in your
- app to set the utility name.
-
- @param UtilityName name of the utility, which will be printed with all
- error/warning/debug messages.
-**/
-VOID
-SetUtilityName (
- CHAR8 *UtilityName
- )
-{
- //
- // Save the name of the utility in our local variable. Make sure its
- // length does not exceed our buffer.
- //
- if (UtilityName != NULL) {
- if (strlen (UtilityName) >= sizeof (mUtilityName)) {
- Error (UtilityName, 0, 0, "application error", "utility name length exceeds internal buffer size");
- }
- strncpy (mUtilityName, UtilityName, sizeof (mUtilityName) - 1);
- mUtilityName[sizeof (mUtilityName) - 1] = 0;
- } else {
- Error (NULL, 0, 0, "application error", "SetUtilityName() called with NULL utility name");
- }
-}
-
-/**
- When you call Error() or Warning(), this module keeps track of it and
- sets a local mStatus to STATUS_ERROR or STATUS_WARNING. When the utility
- exits, it can call this function to get the status and use it as a return
- value.
-
- @return Worst-case status reported, as defined by which print function was called.
-**/
-STATUS
-GetUtilityStatus (
- VOID
- )
-{
- return mStatus;
-}
-
-/**
- Set the printing message Level. This is used by the PrintMsg() function
- to determine when/if a message should be printed.
-
- @param LogLevel 0~50 to specify the different level message.
-**/
-VOID
-SetPrintLevel (
- UINT64 LogLevel
- )
-{
- mPrintLogLevel = LogLevel;
-}
-
-/**
- Print a verbose level message.
-
- @param MsgFmt the format string for the message. Can contain formatting
- controls for use with varargs.
- @param List the variable list.
-**/
-VOID
-VerboseMsg (
- CHAR8 *MsgFmt,
- ...
- )
-{
- va_list List;
- //
- // If the debug level is less than current print level, then do nothing.
- //
- if (VERBOSE_LOG_LEVEL < mPrintLogLevel) {
- return ;
- }
-
- va_start (List, MsgFmt);
- PrintSimpleMessage (MsgFmt, List);
- va_end (List);
-}
-
-/**
- Print a default level message.
-
- @param MsgFmt the format string for the message. Can contain formatting
- controls for use with varargs.
- @param List the variable list.
-**/
-VOID
-NormalMsg (
- CHAR8 *MsgFmt,
- ...
- )
-{
- va_list List;
- //
- // If the debug level is less than current print level, then do nothing.
- //
- if (INFO_LOG_LEVEL < mPrintLogLevel) {
- return ;
- }
-
- va_start (List, MsgFmt);
- PrintSimpleMessage (MsgFmt, List);
- va_end (List);
-}
-
-/**
- Print a key level message.
-
- @param MsgFmt the format string for the message. Can contain formatting
- controls for use with varargs.
- @param List the variable list.
-**/
-VOID
-KeyMsg (
- CHAR8 *MsgFmt,
- ...
- )
-{
- va_list List;
- //
- // If the debug level is less than current print level, then do nothing.
- //
- if (KEY_LOG_LEVEL < mPrintLogLevel) {
- return ;
- }
-
- va_start (List, MsgFmt);
- PrintSimpleMessage (MsgFmt, List);
- va_end (List);
-}
-
-/**
- Set the limits of how many errors, warnings, and errors+warnings
- we will print.
-
- @param MaxErrors maximum number of error messages to print
- @param MaxWarnings maximum number of warning messages to print
- @param MaxWarningsPlusErrors
- maximum number of errors+warnings to print
-**/
-VOID
-SetPrintLimits (
- UINT32 MaxErrors,
- UINT32 MaxWarnings,
- UINT32 MaxWarningsPlusErrors
- )
-{
- mMaxErrors = MaxErrors;
- mMaxWarnings = MaxWarnings;
- mMaxWarningsPlusErrors = MaxWarningsPlusErrors;
- mPrintLimitsSet = 1;
-}
-
-STATIC
-VOID
-PrintLimitExceeded (
- VOID
- )
-{
- STATIC INT8 mPrintLimitExceeded = 0;
- //
- // If we've already printed the message, do nothing. Otherwise
- // temporarily increase our print limits so we can pass one
- // more message through.
- //
- if (mPrintLimitExceeded == 0) {
- mPrintLimitExceeded++;
- mMaxErrors++;
- mMaxWarnings++;
- mMaxWarningsPlusErrors++;
- Error (NULL, 0, 0, "error/warning print limit exceeded", NULL);
- mMaxErrors--;
- mMaxWarnings--;
- mMaxWarningsPlusErrors--;
- }
-}
-
-#if 0
-VOID
-TestUtilityMessages (
- VOID
- )
-{
- CHAR8 *ArgStr = "ArgString";
- int ArgInt;
-
- ArgInt = 0x12345678;
- //
- // Test without setting utility name
- //
- fprintf (stdout, "* Testing without setting utility name\n");
- fprintf (stdout, "** Test debug message not printed\n");
- DebugMsg (NULL, 0, 0x00000001, NULL, NULL);
- fprintf (stdout, "** Test warning with two strings and two args\n");
- Warning (NULL, 0, 1234, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt);
- fprintf (stdout, "** Test error with two strings and two args\n");
- Warning (NULL, 0, 1234, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt);
- fprintf (stdout, "** Test parser warning with nothing\n");
- ParserWarning (0, NULL, NULL);
- fprintf (stdout, "** Test parser error with nothing\n");
- ParserError (0, NULL, NULL);
- //
- // Test with utility name set now
- //
- fprintf (stdout, "** Testingin with utility name set\n");
- SetUtilityName ("MyUtilityName");
- //
- // Test debug prints
- //
- SetDebugMsgMask (2);
- fprintf (stdout, "** Test debug message with one string\n");
- DebugMsg (NULL, 0, 0x00000002, "Text1", NULL);
- fprintf (stdout, "** Test debug message with one string\n");
- DebugMsg (NULL, 0, 0x00000002, NULL, "Text2");
- fprintf (stdout, "** Test debug message with two strings\n");
- DebugMsg (NULL, 0, 0x00000002, "Text1", "Text2");
- fprintf (stdout, "** Test debug message with two strings and two args\n");
- DebugMsg (NULL, 0, 0x00000002, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt);
- //
- // Test warning prints
- //
- fprintf (stdout, "** Test warning with no strings\n");
- Warning (NULL, 0, 1234, NULL, NULL);
- fprintf (stdout, "** Test warning with one string\n");
- Warning (NULL, 0, 1234, "Text1", NULL);
- fprintf (stdout, "** Test warning with one string\n");
- Warning (NULL, 0, 1234, NULL, "Text2");
- fprintf (stdout, "** Test warning with two strings and two args\n");
- Warning (NULL, 0, 1234, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt);
- //
- // Test error prints
- //
- fprintf (stdout, "** Test error with no strings\n");
- Error (NULL, 0, 1234, NULL, NULL);
- fprintf (stdout, "** Test error with one string\n");
- Error (NULL, 0, 1234, "Text1", NULL);
- fprintf (stdout, "** Test error with one string\n");
- Error (NULL, 0, 1234, NULL, "Text2");
- fprintf (stdout, "** Test error with two strings and two args\n");
- Error (NULL, 0, 1234, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt);
- //
- // Test parser prints
- //
- fprintf (stdout, "** Test parser errors\n");
- ParserSetPosition (__FILE__, __LINE__ + 1);
- ParserError (1234, NULL, NULL);
- ParserSetPosition (__FILE__, __LINE__ + 1);
- ParserError (1234, "Text1", NULL);
- ParserSetPosition (__FILE__, __LINE__ + 1);
- ParserError (1234, NULL, "Text2");
- ParserSetPosition (__FILE__, __LINE__ + 1);
- ParserError (1234, "Text1", "Text2");
- ParserSetPosition (__FILE__, __LINE__ + 1);
- ParserError (1234, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt);
-
- fprintf (stdout, "** Test parser warnings\n");
- ParserSetPosition (__FILE__, __LINE__ + 1);
- ParserWarning (4321, NULL, NULL);
- ParserSetPosition (__FILE__, __LINE__ + 1);
- ParserWarning (4321, "Text1", NULL);
- ParserSetPosition (__FILE__, __LINE__ + 1);
- ParserWarning (4321, NULL, "Text2");
- ParserSetPosition (__FILE__, __LINE__ + 1);
- ParserWarning (4321, "Text1", "Text2");
- ParserSetPosition (__FILE__, __LINE__ + 1);
- ParserWarning (4321, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt);
-}
-#endif
+/** @file +EFI tools utility functions to display warning, error, and informational messages + +Copyright (c) 2004 - 2017, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +--*/ + +#include <stdio.h> +#include <string.h> +#include <ctype.h> +#include <stdarg.h> +#include <time.h> + +#include "EfiUtilityMsgs.h" + +// +// Declare module globals for keeping track of the utility's +// name and other settings. +// +STATIC STATUS mStatus = STATUS_SUCCESS; +STATIC CHAR8 mUtilityName[50] = { 0 }; +STATIC UINT64 mPrintLogLevel = INFO_LOG_LEVEL; +STATIC CHAR8 *mSourceFileName = NULL; +STATIC UINT32 mSourceFileLineNum = 0; +STATIC UINT32 mErrorCount = 0; +STATIC UINT32 mWarningCount = 0; +STATIC UINT32 mMaxErrors = 0; +STATIC UINT32 mMaxWarnings = 0; +STATIC UINT32 mMaxWarningsPlusErrors = 0; +STATIC INT8 mPrintLimitsSet = 0; + +STATIC +VOID +PrintLimitExceeded ( + VOID + ); + +/** + Prints an error message. + + All arguments are optional, though the printed message may be useless if + at least something valid is not specified. + + @note: + We print the following (similar to the Warn() and Debug() + W + Typical error/warning message format: + + bin\VfrCompile.cpp(330) : error C2660: 'AddVfrDataStructField' : function does not take 2 parameters + + BUGBUG -- these three utility functions are almost identical, and + should be modified to share code. + + Visual Studio does not find error messages with: + + " error :" + " error 1:" + " error c1:" + " error 1000:" + " error c100:" + + It does find: + " error c1000:" + + @param FileName name of the file or application. If not specified, then the + utility name (as set by the utility calling SetUtilityName() + earlier) is used. Otherwise "Unknown utility" is used. + + @param LineNumber the line number of error, typically used by parsers. If the + utility is not a parser, then 0 should be specified. Otherwise + the FileName and LineNumber info can be used to cause + MS Visual Studio to jump to the error. + + @param MessageCode an application-specific error code that can be referenced in + other documentation. + + @param Text the text in question, typically used by parsers. + + @param MsgFmt the format string for the error message. Can contain formatting + controls for use with the varargs. +**/ +VOID +Error ( + CHAR8 *FileName, + UINT32 LineNumber, + UINT32 MessageCode, + CHAR8 *Text, + CHAR8 *MsgFmt, + ... + ) +{ + va_list List; + // + // If limits have been set, then check that we have not exceeded them + // + if (mPrintLimitsSet) { + // + // See if we've exceeded our total count + // + if (mMaxWarningsPlusErrors != 0) { + if (mErrorCount + mWarningCount > mMaxWarningsPlusErrors) { + PrintLimitExceeded (); + return ; + } + } + // + // See if we've exceeded our error count + // + if (mMaxErrors != 0) { + if (mErrorCount > mMaxErrors) { + PrintLimitExceeded (); + return ; + } + } + } + + mErrorCount++; + va_start (List, MsgFmt); + PrintMessage ("ERROR", FileName, LineNumber, MessageCode, Text, MsgFmt, List); + va_end (List); +} + +/** + Print a parser error, using the source file name and line number + set by a previous call to SetParserPosition(). + + @param MessageCode application-specific error code + @param Text text to print in the error message + @param MsgFmt format string to print at the end of the error message +**/ +VOID +ParserError ( + UINT32 MessageCode, + CHAR8 *Text, + CHAR8 *MsgFmt, + ... + ) +{ + va_list List; + // + // If limits have been set, then check them + // + if (mPrintLimitsSet) { + // + // See if we've exceeded our total count + // + if (mMaxWarningsPlusErrors != 0) { + if (mErrorCount + mWarningCount > mMaxWarningsPlusErrors) { + PrintLimitExceeded (); + return ; + } + } + // + // See if we've exceeded our error count + // + if (mMaxErrors != 0) { + if (mErrorCount > mMaxErrors) { + PrintLimitExceeded (); + return ; + } + } + } + + mErrorCount++; + va_start (List, MsgFmt); + PrintMessage ("ERROR", mSourceFileName, mSourceFileLineNum, MessageCode, Text, MsgFmt, List); + va_end (List); +} + +/** + Print a parser warning, using the source file name and line number + set by a previous call to SetParserPosition(). + + @param ErrorCode application-specific error code + @param OffendingText text to print in the warning message + @param MsgFmt format string to print at the end of the warning message +**/ +VOID +ParserWarning ( + UINT32 ErrorCode, + CHAR8 *OffendingText, + CHAR8 *MsgFmt, + ... + ) +{ + va_list List; + // + // If limits have been set, then check them + // + if (mPrintLimitsSet) { + // + // See if we've exceeded our total count + // + if (mMaxWarningsPlusErrors != 0) { + if (mErrorCount + mWarningCount > mMaxWarningsPlusErrors) { + PrintLimitExceeded (); + return ; + } + } + // + // See if we've exceeded our warning count + // + if (mMaxWarnings != 0) { + if (mWarningCount > mMaxWarnings) { + PrintLimitExceeded (); + return ; + } + } + } + + mWarningCount++; + va_start (List, MsgFmt); + PrintMessage ("WARNING", mSourceFileName, mSourceFileLineNum, ErrorCode, OffendingText, MsgFmt, List); + va_end (List); + // + // Don't set warning status accordingly + // + // if (mStatus < STATUS_WARNING) { + // mStatus = STATUS_WARNING; + // } +} + +/** + Print a warning message. + + @param FileName name of the file where the warning was detected, or the name + of the application that detected the warning + @param LineNumber the line number where the warning was detected (parsers). + 0 should be specified if the utility is not a parser. + @param MessageCode an application-specific warning code that can be referenced in + other documentation. + @param Text the text in question (parsers) + @param MsgFmt the format string for the warning message. Can contain formatting + controls for use with varargs. +**/ +VOID +Warning ( + CHAR8 *FileName, + UINT32 LineNumber, + UINT32 MessageCode, + CHAR8 *Text, + CHAR8 *MsgFmt, + ... + ) +{ + va_list List; + + // + // Current Print Level not output warning information. + // + if (WARNING_LOG_LEVEL < mPrintLogLevel) { + return; + } + // + // If limits have been set, then check them + // + if (mPrintLimitsSet) { + // + // See if we've exceeded our total count + // + if (mMaxWarningsPlusErrors != 0) { + if (mErrorCount + mWarningCount > mMaxWarningsPlusErrors) { + PrintLimitExceeded (); + return ; + } + } + // + // See if we've exceeded our warning count + // + if (mMaxWarnings != 0) { + if (mWarningCount > mMaxWarnings) { + PrintLimitExceeded (); + return ; + } + } + } + + mWarningCount++; + va_start (List, MsgFmt); + PrintMessage ("WARNING", FileName, LineNumber, MessageCode, Text, MsgFmt, List); + va_end (List); +} + +/** + Print a Debug message. + + @param FileName typically the name of the utility printing the debug message, but + can be the name of a file being parsed. + @param LineNumber the line number in FileName (parsers) + @param MsgLevel Debug message print level (0~9) + @param Text the text in question (parsers) + @param MsgFmt the format string for the debug message. Can contain formatting + controls for use with varargs. + +**/ +VOID +DebugMsg ( + CHAR8 *FileName, + UINT32 LineNumber, + UINT64 MsgLevel, + CHAR8 *Text, + CHAR8 *MsgFmt, + ... + ) +{ + va_list List; + // + // If the debug level is less than current print level, then do nothing. + // + if (MsgLevel < mPrintLogLevel) { + return ; + } + + va_start (List, MsgFmt); + PrintMessage ("DEBUG", FileName, LineNumber, 0, Text, MsgFmt, List); + va_end (List); +} + +/** + Worker routine for all the utility printing services. Prints the message in + a format that Visual Studio will find when scanning build outputs for + errors or warnings. + + @note: + If FileName == NULL then this utility will use the string passed into SetUtilityName(). + + LineNumber is only used if the caller is a parser, in which case FileName refers to the + file being parsed. + + Text and MsgFmt are both optional, though it would be of little use calling this function with + them both NULL. + + Output will typically be of the form: + <FileName>(<LineNumber>) : <Type> <Type[0]><MessageCode>: <Text> : <MsgFmt> + + Parser (LineNumber != 0) + VfrCompile.cpp(330) : error E2660: AddVfrDataStructField : function does not take 2 parameters + Generic utility (LineNumber == 0) + UtilityName : error E1234 : Text string : MsgFmt string and args + + @param Type "warning" or "error" string to insert into the message to be + printed. The first character of this string (converted to uppercase) + is used to precede the MessageCode value in the output string. + @param FileName name of the file where the warning was detected, or the name + of the application that detected the warning + @param LineNumber the line number where the warning was detected (parsers). + 0 should be specified if the utility is not a parser. + @param MessageCode an application-specific warning code that can be referenced in + other documentation. + @param Text part of the message to print + @param MsgFmt the format string for the message. Can contain formatting + controls for use with varargs. + @param List the variable list. +**/ +VOID +PrintMessage ( + CHAR8 *Type, + CHAR8 *FileName, + UINT32 LineNumber, + UINT32 MessageCode, + CHAR8 *Text, + CHAR8 *MsgFmt, + va_list List + ) +{ + CHAR8 Line[MAX_LINE_LEN]; + CHAR8 Line2[MAX_LINE_LEN]; + CHAR8 *Cptr; + struct tm *NewTime; + time_t CurrentTime; + + // + // init local variable + // + Line[0] = '\0'; + Line2[0] = '\0'; + + // + // If given a filename, then add it (and the line number) to the string. + // If there's no filename, then use the program name if provided. + // + if (FileName != NULL) { + Cptr = FileName; + } else { + Cptr = NULL; + } + + if (strcmp (Type, "DEBUG") == 0) { + // + // Debug Message requires current time. + // + time (&CurrentTime); + NewTime = localtime (&CurrentTime); + if (NewTime != NULL) { + fprintf (stdout, "%04d-%02d-%02d %02d:%02d:%02d", + NewTime->tm_year + 1900, + NewTime->tm_mon + 1, + NewTime->tm_mday, + NewTime->tm_hour, + NewTime->tm_min, + NewTime->tm_sec + ); + } + if (Cptr != NULL) { + strcpy (Line, ": "); + strncat (Line, Cptr, MAX_LINE_LEN - strlen (Line) - 1); + if (LineNumber != 0) { + sprintf (Line2, "(%u)", (unsigned) LineNumber); + strncat (Line, Line2, MAX_LINE_LEN - strlen (Line) - 1); + } + } + } else { + // + // Error and Warning Information. + // + if (Cptr != NULL) { + if (mUtilityName[0] != '\0') { + fprintf (stdout, "%s...\n", mUtilityName); + } + strncpy (Line, Cptr, MAX_LINE_LEN - 1); + Line[MAX_LINE_LEN - 1] = 0; + if (LineNumber != 0) { + sprintf (Line2, "(%u)", (unsigned) LineNumber); + strncat (Line, Line2, MAX_LINE_LEN - strlen (Line) - 1); + } + } else { + if (mUtilityName[0] != '\0') { + strncpy (Line, mUtilityName, MAX_LINE_LEN - 1); + Line[MAX_LINE_LEN - 1] = 0; + } + } + + if (strcmp (Type, "ERROR") == 0) { + // + // Set status accordingly for ERROR information. + // + if (mStatus < STATUS_ERROR) { + mStatus = STATUS_ERROR; + } + } + } + + // + // Have to print an error code or Visual Studio won't find the + // message for you. It has to be decimal digits too. + // + strncat (Line, ": ", MAX_LINE_LEN - strlen (Line) - 1); + strncat (Line, Type, MAX_LINE_LEN - strlen (Line) - 1); + if (MessageCode != 0) { + sprintf (Line2, " %04u", (unsigned) MessageCode); + strncat (Line, Line2, MAX_LINE_LEN - strlen (Line) - 1); + } + fprintf (stdout, "%s", Line); + // + // If offending text was provided, then print it + // + if (Text != NULL) { + fprintf (stdout, ": %s", Text); + } + fprintf (stdout, "\n"); + + // + // Print formatted message if provided + // + if (MsgFmt != NULL) { + vsprintf (Line2, MsgFmt, List); + fprintf (stdout, " %s\n", Line2); + } + +} + +/** + Print message into stdout. + + @param MsgFmt the format string for the message. Can contain formatting + controls for use with varargs. + @param List the variable list. +**/ +STATIC +VOID +PrintSimpleMessage ( + CHAR8 *MsgFmt, + va_list List + ) +{ + CHAR8 Line[MAX_LINE_LEN]; + // + // Print formatted message if provided + // + if (MsgFmt != NULL) { + vsprintf (Line, MsgFmt, List); + fprintf (stdout, "%s\n", Line); + } +} + +/** + Set the position in a file being parsed. This can be used to + print error messages deeper down in a parser. + + @param SourceFileName name of the source file being parsed + @param LineNum line number of the source file being parsed +**/ +VOID +ParserSetPosition ( + CHAR8 *SourceFileName, + UINT32 LineNum + ) +{ + mSourceFileName = SourceFileName; + mSourceFileLineNum = LineNum; +} + +/** + All printed error/warning/debug messages follow the same format, and + typically will print a filename or utility name followed by the error + text. However if a filename is not passed to the print routines, then + they'll print the utility name if you call this function early in your + app to set the utility name. + + @param UtilityName name of the utility, which will be printed with all + error/warning/debug messages. +**/ +VOID +SetUtilityName ( + CHAR8 *UtilityName + ) +{ + // + // Save the name of the utility in our local variable. Make sure its + // length does not exceed our buffer. + // + if (UtilityName != NULL) { + if (strlen (UtilityName) >= sizeof (mUtilityName)) { + Error (UtilityName, 0, 0, "application error", "utility name length exceeds internal buffer size"); + } + strncpy (mUtilityName, UtilityName, sizeof (mUtilityName) - 1); + mUtilityName[sizeof (mUtilityName) - 1] = 0; + } else { + Error (NULL, 0, 0, "application error", "SetUtilityName() called with NULL utility name"); + } +} + +/** + When you call Error() or Warning(), this module keeps track of it and + sets a local mStatus to STATUS_ERROR or STATUS_WARNING. When the utility + exits, it can call this function to get the status and use it as a return + value. + + @return Worst-case status reported, as defined by which print function was called. +**/ +STATUS +GetUtilityStatus ( + VOID + ) +{ + return mStatus; +} + +/** + Set the printing message Level. This is used by the PrintMsg() function + to determine when/if a message should be printed. + + @param LogLevel 0~50 to specify the different level message. +**/ +VOID +SetPrintLevel ( + UINT64 LogLevel + ) +{ + mPrintLogLevel = LogLevel; +} + +/** + Print a verbose level message. + + @param MsgFmt the format string for the message. Can contain formatting + controls for use with varargs. + @param List the variable list. +**/ +VOID +VerboseMsg ( + CHAR8 *MsgFmt, + ... + ) +{ + va_list List; + // + // If the debug level is less than current print level, then do nothing. + // + if (VERBOSE_LOG_LEVEL < mPrintLogLevel) { + return ; + } + + va_start (List, MsgFmt); + PrintSimpleMessage (MsgFmt, List); + va_end (List); +} + +/** + Print a default level message. + + @param MsgFmt the format string for the message. Can contain formatting + controls for use with varargs. + @param List the variable list. +**/ +VOID +NormalMsg ( + CHAR8 *MsgFmt, + ... + ) +{ + va_list List; + // + // If the debug level is less than current print level, then do nothing. + // + if (INFO_LOG_LEVEL < mPrintLogLevel) { + return ; + } + + va_start (List, MsgFmt); + PrintSimpleMessage (MsgFmt, List); + va_end (List); +} + +/** + Print a key level message. + + @param MsgFmt the format string for the message. Can contain formatting + controls for use with varargs. + @param List the variable list. +**/ +VOID +KeyMsg ( + CHAR8 *MsgFmt, + ... + ) +{ + va_list List; + // + // If the debug level is less than current print level, then do nothing. + // + if (KEY_LOG_LEVEL < mPrintLogLevel) { + return ; + } + + va_start (List, MsgFmt); + PrintSimpleMessage (MsgFmt, List); + va_end (List); +} + +/** + Set the limits of how many errors, warnings, and errors+warnings + we will print. + + @param MaxErrors maximum number of error messages to print + @param MaxWarnings maximum number of warning messages to print + @param MaxWarningsPlusErrors + maximum number of errors+warnings to print +**/ +VOID +SetPrintLimits ( + UINT32 MaxErrors, + UINT32 MaxWarnings, + UINT32 MaxWarningsPlusErrors + ) +{ + mMaxErrors = MaxErrors; + mMaxWarnings = MaxWarnings; + mMaxWarningsPlusErrors = MaxWarningsPlusErrors; + mPrintLimitsSet = 1; +} + +STATIC +VOID +PrintLimitExceeded ( + VOID + ) +{ + STATIC INT8 mPrintLimitExceeded = 0; + // + // If we've already printed the message, do nothing. Otherwise + // temporarily increase our print limits so we can pass one + // more message through. + // + if (mPrintLimitExceeded == 0) { + mPrintLimitExceeded++; + mMaxErrors++; + mMaxWarnings++; + mMaxWarningsPlusErrors++; + Error (NULL, 0, 0, "error/warning print limit exceeded", NULL); + mMaxErrors--; + mMaxWarnings--; + mMaxWarningsPlusErrors--; + } +} + +#if 0 +VOID +TestUtilityMessages ( + VOID + ) +{ + CHAR8 *ArgStr = "ArgString"; + int ArgInt; + + ArgInt = 0x12345678; + // + // Test without setting utility name + // + fprintf (stdout, "* Testing without setting utility name\n"); + fprintf (stdout, "** Test debug message not printed\n"); + DebugMsg (NULL, 0, 0x00000001, NULL, NULL); + fprintf (stdout, "** Test warning with two strings and two args\n"); + Warning (NULL, 0, 1234, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt); + fprintf (stdout, "** Test error with two strings and two args\n"); + Warning (NULL, 0, 1234, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt); + fprintf (stdout, "** Test parser warning with nothing\n"); + ParserWarning (0, NULL, NULL); + fprintf (stdout, "** Test parser error with nothing\n"); + ParserError (0, NULL, NULL); + // + // Test with utility name set now + // + fprintf (stdout, "** Testingin with utility name set\n"); + SetUtilityName ("MyUtilityName"); + // + // Test debug prints + // + SetDebugMsgMask (2); + fprintf (stdout, "** Test debug message with one string\n"); + DebugMsg (NULL, 0, 0x00000002, "Text1", NULL); + fprintf (stdout, "** Test debug message with one string\n"); + DebugMsg (NULL, 0, 0x00000002, NULL, "Text2"); + fprintf (stdout, "** Test debug message with two strings\n"); + DebugMsg (NULL, 0, 0x00000002, "Text1", "Text2"); + fprintf (stdout, "** Test debug message with two strings and two args\n"); + DebugMsg (NULL, 0, 0x00000002, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt); + // + // Test warning prints + // + fprintf (stdout, "** Test warning with no strings\n"); + Warning (NULL, 0, 1234, NULL, NULL); + fprintf (stdout, "** Test warning with one string\n"); + Warning (NULL, 0, 1234, "Text1", NULL); + fprintf (stdout, "** Test warning with one string\n"); + Warning (NULL, 0, 1234, NULL, "Text2"); + fprintf (stdout, "** Test warning with two strings and two args\n"); + Warning (NULL, 0, 1234, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt); + // + // Test error prints + // + fprintf (stdout, "** Test error with no strings\n"); + Error (NULL, 0, 1234, NULL, NULL); + fprintf (stdout, "** Test error with one string\n"); + Error (NULL, 0, 1234, "Text1", NULL); + fprintf (stdout, "** Test error with one string\n"); + Error (NULL, 0, 1234, NULL, "Text2"); + fprintf (stdout, "** Test error with two strings and two args\n"); + Error (NULL, 0, 1234, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt); + // + // Test parser prints + // + fprintf (stdout, "** Test parser errors\n"); + ParserSetPosition (__FILE__, __LINE__ + 1); + ParserError (1234, NULL, NULL); + ParserSetPosition (__FILE__, __LINE__ + 1); + ParserError (1234, "Text1", NULL); + ParserSetPosition (__FILE__, __LINE__ + 1); + ParserError (1234, NULL, "Text2"); + ParserSetPosition (__FILE__, __LINE__ + 1); + ParserError (1234, "Text1", "Text2"); + ParserSetPosition (__FILE__, __LINE__ + 1); + ParserError (1234, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt); + + fprintf (stdout, "** Test parser warnings\n"); + ParserSetPosition (__FILE__, __LINE__ + 1); + ParserWarning (4321, NULL, NULL); + ParserSetPosition (__FILE__, __LINE__ + 1); + ParserWarning (4321, "Text1", NULL); + ParserSetPosition (__FILE__, __LINE__ + 1); + ParserWarning (4321, NULL, "Text2"); + ParserSetPosition (__FILE__, __LINE__ + 1); + ParserWarning (4321, "Text1", "Text2"); + ParserSetPosition (__FILE__, __LINE__ + 1); + ParserWarning (4321, "Text1", "Text2 %s 0x%X", ArgStr, ArgInt); +} +#endif diff --git a/BaseTools/Source/C/Common/EfiUtilityMsgs.h b/BaseTools/Source/C/Common/EfiUtilityMsgs.h index 85f018cbad..406cc70e33 100644 --- a/BaseTools/Source/C/Common/EfiUtilityMsgs.h +++ b/BaseTools/Source/C/Common/EfiUtilityMsgs.h @@ -1,164 +1,164 @@ -/** @file
-Defines and prototypes for common EFI utility error and debug messages.
-
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _EFI_UTILITY_MSGS_H_
-#define _EFI_UTILITY_MSGS_H_
-
-#include <Common/UefiBaseTypes.h>
-
-//
-// Log message print Level
-//
-#define VERBOSE_LOG_LEVEL 15
-#define WARNING_LOG_LEVEL 15
-#define INFO_LOG_LEVEL 20
-#define KEY_LOG_LEVEL 40
-#define ERROR_LOG_LEVLE 50
-
-//
-// Status codes returned by EFI utility programs and functions
-//
-#define STATUS_SUCCESS 0
-#define STATUS_WARNING 1
-#define STATUS_ERROR 2
-#define VOID void
-
-typedef int STATUS;
-
-#define MAX_LINE_LEN 0x200
-#define MAXIMUM_INPUT_FILE_NUM 10
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-//
-// When we call Error() or Warning(), the module keeps track of the worst
-// case reported. GetUtilityStatus() will get the worst-case results, which
-// can be used as the return value from the app.
-//
-STATUS
-GetUtilityStatus (
- VOID
- );
-
-//
-// If someone prints an error message and didn't specify a source file name,
-// then we print the utility name instead. However they must tell us the
-// utility name early on via this function.
-//
-VOID
-SetUtilityName (
- CHAR8 *ProgramName
- )
-;
-
-VOID
-PrintMessage (
- CHAR8 *Type,
- CHAR8 *FileName,
- UINT32 LineNumber,
- UINT32 MessageCode,
- CHAR8 *Text,
- CHAR8 *MsgFmt,
- va_list List
- );
-
-VOID
-Error (
- CHAR8 *FileName,
- UINT32 LineNumber,
- UINT32 ErrorCode,
- CHAR8 *OffendingText,
- CHAR8 *MsgFmt,
- ...
- )
-;
-
-VOID
-Warning (
- CHAR8 *FileName,
- UINT32 LineNumber,
- UINT32 WarningCode,
- CHAR8 *OffendingText,
- CHAR8 *MsgFmt,
- ...
- )
-;
-
-VOID
-DebugMsg (
- CHAR8 *FileName,
- UINT32 LineNumber,
- UINT64 MsgLevel,
- CHAR8 *OffendingText,
- CHAR8 *MsgFmt,
- ...
- )
-;
-
-VOID
-VerboseMsg (
- CHAR8 *MsgFmt,
- ...
- );
-
-VOID
-NormalMsg (
- CHAR8 *MsgFmt,
- ...
- );
-
-VOID
-KeyMsg (
- CHAR8 *MsgFmt,
- ...
- );
-
-VOID
-SetPrintLevel (
- UINT64 LogLevel
- );
-
-VOID
-ParserSetPosition (
- CHAR8 *SourceFileName,
- UINT32 LineNum
- )
-;
-
-VOID
-ParserError (
- UINT32 ErrorCode,
- CHAR8 *OffendingText,
- CHAR8 *MsgFmt,
- ...
- )
-;
-
-VOID
-ParserWarning (
- UINT32 ErrorCode,
- CHAR8 *OffendingText,
- CHAR8 *MsgFmt,
- ...
- )
-;
-
-VOID
-SetPrintLimits (
- UINT32 NumErrors,
- UINT32 NumWarnings,
- UINT32 NumWarningsPlusErrors
- )
-;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif // #ifndef _EFI_UTILITY_MSGS_H_
+/** @file +Defines and prototypes for common EFI utility error and debug messages. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_UTILITY_MSGS_H_ +#define _EFI_UTILITY_MSGS_H_ + +#include <Common/UefiBaseTypes.h> + +// +// Log message print Level +// +#define VERBOSE_LOG_LEVEL 15 +#define WARNING_LOG_LEVEL 15 +#define INFO_LOG_LEVEL 20 +#define KEY_LOG_LEVEL 40 +#define ERROR_LOG_LEVLE 50 + +// +// Status codes returned by EFI utility programs and functions +// +#define STATUS_SUCCESS 0 +#define STATUS_WARNING 1 +#define STATUS_ERROR 2 +#define VOID void + +typedef int STATUS; + +#define MAX_LINE_LEN 0x200 +#define MAXIMUM_INPUT_FILE_NUM 10 + +#ifdef __cplusplus +extern "C" { +#endif +// +// When we call Error() or Warning(), the module keeps track of the worst +// case reported. GetUtilityStatus() will get the worst-case results, which +// can be used as the return value from the app. +// +STATUS +GetUtilityStatus ( + VOID + ); + +// +// If someone prints an error message and didn't specify a source file name, +// then we print the utility name instead. However they must tell us the +// utility name early on via this function. +// +VOID +SetUtilityName ( + CHAR8 *ProgramName + ) +; + +VOID +PrintMessage ( + CHAR8 *Type, + CHAR8 *FileName, + UINT32 LineNumber, + UINT32 MessageCode, + CHAR8 *Text, + CHAR8 *MsgFmt, + va_list List + ); + +VOID +Error ( + CHAR8 *FileName, + UINT32 LineNumber, + UINT32 ErrorCode, + CHAR8 *OffendingText, + CHAR8 *MsgFmt, + ... + ) +; + +VOID +Warning ( + CHAR8 *FileName, + UINT32 LineNumber, + UINT32 WarningCode, + CHAR8 *OffendingText, + CHAR8 *MsgFmt, + ... + ) +; + +VOID +DebugMsg ( + CHAR8 *FileName, + UINT32 LineNumber, + UINT64 MsgLevel, + CHAR8 *OffendingText, + CHAR8 *MsgFmt, + ... + ) +; + +VOID +VerboseMsg ( + CHAR8 *MsgFmt, + ... + ); + +VOID +NormalMsg ( + CHAR8 *MsgFmt, + ... + ); + +VOID +KeyMsg ( + CHAR8 *MsgFmt, + ... + ); + +VOID +SetPrintLevel ( + UINT64 LogLevel + ); + +VOID +ParserSetPosition ( + CHAR8 *SourceFileName, + UINT32 LineNum + ) +; + +VOID +ParserError ( + UINT32 ErrorCode, + CHAR8 *OffendingText, + CHAR8 *MsgFmt, + ... + ) +; + +VOID +ParserWarning ( + UINT32 ErrorCode, + CHAR8 *OffendingText, + CHAR8 *MsgFmt, + ... + ) +; + +VOID +SetPrintLimits ( + UINT32 NumErrors, + UINT32 NumWarnings, + UINT32 NumWarningsPlusErrors + ) +; + +#ifdef __cplusplus +} +#endif + +#endif // #ifndef _EFI_UTILITY_MSGS_H_ diff --git a/BaseTools/Source/C/Common/FirmwareVolumeBuffer.c b/BaseTools/Source/C/Common/FirmwareVolumeBuffer.c index 40e068c303..f8f117bcb2 100644 --- a/BaseTools/Source/C/Common/FirmwareVolumeBuffer.c +++ b/BaseTools/Source/C/Common/FirmwareVolumeBuffer.c @@ -1,1518 +1,1518 @@ -/** @file
-EFI Firmware Volume routines which work on a Fv image in buffers.
-
-Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "FirmwareVolumeBufferLib.h"
-#include "BinderFuncs.h"
-
-//
-// Local macros
-//
-#define EFI_TEST_FFS_ATTRIBUTES_BIT(FvbAttributes, TestAttributes, Bit) \
- ( \
- (BOOLEAN) ( \
- (FvbAttributes & EFI_FVB2_ERASE_POLARITY) ? (((~TestAttributes) & Bit) == Bit) : ((TestAttributes & Bit) == Bit) \
- ) \
- )
-
-
-//
-// Local prototypes
-//
-
-STATIC
-UINT32
-FvBufGetSecHdrLen(
- IN EFI_COMMON_SECTION_HEADER *SectionHeader
- )
-{
- if (SectionHeader == NULL) {
- return 0;
- }
- if (FvBufExpand3ByteSize(SectionHeader->Size) == 0xffffff) {
- return sizeof(EFI_COMMON_SECTION_HEADER2);
- }
- return sizeof(EFI_COMMON_SECTION_HEADER);
-}
-
-STATIC
-UINT32
-FvBufGetSecFileLen (
- IN EFI_COMMON_SECTION_HEADER *SectionHeader
- )
-{
- UINT32 Length;
- if (SectionHeader == NULL) {
- return 0;
- }
- Length = FvBufExpand3ByteSize(SectionHeader->Size);
- if (Length == 0xffffff) {
- Length = ((EFI_COMMON_SECTION_HEADER2 *)SectionHeader)->ExtendedSize;
- }
- return Length;
-}
-
-//
-// Local prototypes
-//
-
-STATIC
-UINT16
-FvBufCalculateChecksum16 (
- IN UINT16 *Buffer,
- IN UINTN Size
- );
-
-STATIC
-UINT8
-FvBufCalculateChecksum8 (
- IN UINT8 *Buffer,
- IN UINTN Size
- );
-
-//
-// Procedures start
-//
-
-/**
- Clears out all files from the Fv buffer in memory
-
- @param SourceFv Address of the Fv in memory, this firmware volume will
- be modified, if SourceFfsFile exists
- @param SourceFfsFile Input FFS file to replace
-
- @retval EFI_SUCCESS
- @retval EFI_NOT_FOUND
-**/
-EFI_STATUS
-FvBufRemoveFileNew (
- IN OUT VOID *Fv,
- IN EFI_GUID *Name
- )
-{
- EFI_STATUS Status;
- EFI_FFS_FILE_HEADER* FileToRm;
- UINTN FileToRmLength;
-
- Status = FvBufFindFileByName(
- Fv,
- Name,
- (VOID **)&FileToRm
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- FileToRmLength = FvBufGetFfsFileSize (FileToRm);
-
- CommonLibBinderSetMem (
- FileToRm,
- FileToRmLength,
- (((EFI_FIRMWARE_VOLUME_HEADER*)Fv)->Attributes & EFI_FVB2_ERASE_POLARITY)
- ? 0xFF : 0
- );
-
- return EFI_SUCCESS;
-}
-
-/**
- Clears out all files from the Fv buffer in memory
-
- @param SourceFv Address of the Fv in memory, this firmware volume will
- be modified, if SourceFfsFile exists
- @param SourceFfsFile Input FFS file to replace
-
- @retval EFI_SUCCESS
- @retval EFI_NOT_FOUND
-**/
-EFI_STATUS
-FvBufRemoveFile (
- IN OUT VOID *Fv,
- IN EFI_GUID *Name
- )
-{
- EFI_STATUS Status;
- EFI_FFS_FILE_HEADER *NextFile;
- EFI_FIRMWARE_VOLUME_HEADER *TempFv;
- UINTN FileKey;
- UINTN FvLength;
-
- Status = FvBufFindFileByName(
- Fv,
- Name,
- NULL
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = FvBufGetSize (Fv, &FvLength);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- TempFv = NULL;
- Status = FvBufDuplicate (Fv, (VOID **)&TempFv);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = FvBufClearAllFiles (TempFv);
- if (EFI_ERROR (Status)) {
- CommonLibBinderFree (TempFv);
- return Status;
- }
-
- // TempFv has been allocated. It must now be freed
- // before returning.
-
- FileKey = 0;
- while (TRUE) {
-
- Status = FvBufFindNextFile (Fv, &FileKey, (VOID **)&NextFile);
- if (Status == EFI_NOT_FOUND) {
- break;
- } else if (EFI_ERROR (Status)) {
- CommonLibBinderFree (TempFv);
- return Status;
- }
-
- if (CommonLibBinderCompareGuid (Name, &NextFile->Name)) {
- continue;
- }
- else {
- Status = FvBufAddFile (TempFv, NextFile);
- if (EFI_ERROR (Status)) {
- CommonLibBinderFree (TempFv);
- return Status;
- }
- }
- }
-
- CommonLibBinderCopyMem (Fv, TempFv, FvLength);
- CommonLibBinderFree (TempFv);
-
- return EFI_SUCCESS;
-}
-
-/**
- Clears out all files from the Fv buffer in memory
-
- @param SourceFfsFile Input FFS file to update the checksum for
-
- @retval EFI_SUCCESS
- @retval EFI_NOT_FOUND
-**/
-EFI_STATUS
-FvBufChecksumFile (
- IN OUT VOID *FfsFile
- )
-{
- EFI_FFS_FILE_HEADER* File = (EFI_FFS_FILE_HEADER*)FfsFile;
- EFI_FFS_FILE_STATE StateBackup;
- UINT32 FileSize;
-
- FileSize = FvBufGetFfsFileSize (File);
-
- //
- // Fill in checksums and state, they must be 0 for checksumming.
- //
- File->IntegrityCheck.Checksum.Header = 0;
- File->IntegrityCheck.Checksum.File = 0;
- StateBackup = File->State;
- File->State = 0;
-
- File->IntegrityCheck.Checksum.Header =
- FvBufCalculateChecksum8 (
- (UINT8 *) File,
- FvBufGetFfsHeaderSize (File)
- );
-
- if (File->Attributes & FFS_ATTRIB_CHECKSUM) {
- File->IntegrityCheck.Checksum.File = FvBufCalculateChecksum8 (
- (VOID*)((UINT8 *)File + FvBufGetFfsHeaderSize (File)),
- FileSize - FvBufGetFfsHeaderSize (File)
- );
- } else {
- File->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
- }
-
- File->State = StateBackup;
-
- return EFI_SUCCESS;
-}
-
-/**
- Clears out all files from the Fv buffer in memory
-
- @param SourceFv Address of the Fv in memory, this firmware volume will
- be modified, if SourceFfsFile exists
- @param SourceFfsFile Input FFS file to replace
-
- @retval EFI_SUCCESS
- @retval EFI_NOT_FOUND
-**/
-EFI_STATUS
-FvBufChecksumHeader (
- IN OUT VOID *Fv
- )
-{
- EFI_FIRMWARE_VOLUME_HEADER* FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
-
- FvHeader->Checksum = 0;
- FvHeader->Checksum =
- FvBufCalculateChecksum16 (
- (UINT16*) FvHeader,
- FvHeader->HeaderLength / sizeof (UINT16)
- );
-
- return EFI_SUCCESS;
-}
-
-/**
- Clears out all files from the Fv buffer in memory
-
- @param SourceFv - Address of the Fv in memory
- @param DestinationFv - Output for destination Fv
- DestinationFv == NULL - invalid parameter
- *DestinationFv == NULL - memory will be allocated
- *DestinationFv != NULL - this address will be the destination
-
- @retval EFI_SUCCESS
-**/
-EFI_STATUS
-FvBufDuplicate (
- IN VOID *SourceFv,
- IN OUT VOID **DestinationFv
- )
-{
- EFI_STATUS Status;
- UINTN size;
-
- if (DestinationFv == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- Status = FvBufGetSize (SourceFv, &size);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (*DestinationFv == NULL) {
- *DestinationFv = CommonLibBinderAllocate (size);
- if (*DestinationFv == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- }
-
- CommonLibBinderCopyMem (*DestinationFv, SourceFv, size);
-
- return EFI_SUCCESS;
-}
-
-/**
- Extends a firmware volume by the given number of bytes.
-
- BUGBUG: Does not handle the case where the firmware volume has a
- VTF (Volume Top File). The VTF will not be moved to the
- end of the extended FV.
-
- @param Fv Source and destination firmware volume.
- Note: The original firmware volume buffer is freed!
-
- @param Size The minimum size that the firmware volume is to be extended by.
- The FV may be extended more than this size.
-
- @retval EFI_SUCCESS
-**/
-EFI_STATUS
-FvBufExtend (
- IN VOID **Fv,
- IN UINTN Size
- )
-{
- EFI_STATUS Status;
- UINTN OldSize;
- UINTN NewSize;
- UINTN BlockCount;
- VOID* NewFv;
-
- EFI_FIRMWARE_VOLUME_HEADER* hdr;
- EFI_FV_BLOCK_MAP_ENTRY* blk;
-
- Status = FvBufGetSize (*Fv, &OldSize);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Locate the block map in the fv header
- //
- hdr = (EFI_FIRMWARE_VOLUME_HEADER*)*Fv;
- blk = hdr->BlockMap;
-
- //
- // Calculate the number of blocks needed to achieve the requested
- // size extension
- //
- BlockCount = ((Size + (blk->Length - 1)) / blk->Length);
-
- //
- // Calculate the new size from the number of blocks that will be added
- //
- NewSize = OldSize + (BlockCount * blk->Length);
-
- NewFv = CommonLibBinderAllocate (NewSize);
- if (NewFv == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // Copy the old data
- //
- CommonLibBinderCopyMem (NewFv, *Fv, OldSize);
-
- //
- // Free the old fv buffer
- //
- CommonLibBinderFree (*Fv);
-
- //
- // Locate the block map in the new fv header
- //
- hdr = (EFI_FIRMWARE_VOLUME_HEADER*)NewFv;
- hdr->FvLength = NewSize;
- blk = hdr->BlockMap;
-
- //
- // Update the block map for the new fv
- //
- blk->NumBlocks += (UINT32)BlockCount;
-
- //
- // Update the FV header checksum
- //
- FvBufChecksumHeader (NewFv);
-
- //
- // Clear out the new area of the FV
- //
- CommonLibBinderSetMem (
- (UINT8*)NewFv + OldSize,
- (NewSize - OldSize),
- (hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0
- );
-
- //
- // Set output with new fv that was created
- //
- *Fv = NewFv;
-
- return EFI_SUCCESS;
-
-}
-
-/**
- Clears out all files from the Fv buffer in memory
-
- @param Fv Address of the Fv in memory
-
- @retval EFI_SUCCESS
-**/
-EFI_STATUS
-FvBufClearAllFiles (
- IN OUT VOID *Fv
- )
-{
- EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
- EFI_STATUS Status;
- UINTN size = 0;
-
- Status = FvBufGetSize (Fv, &size);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- CommonLibBinderSetMem(
- (UINT8*)hdr + hdr->HeaderLength,
- size - hdr->HeaderLength,
- (hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0
- );
-
- return EFI_SUCCESS;
-}
-
-/**
- Clears out all files from the Fv buffer in memory
-
- @param Fv Address of the Fv in memory
-
- @retval EFI_SUCCESS
-**/
-EFI_STATUS
-FvBufGetSize (
- IN VOID *Fv,
- OUT UINTN *Size
- )
-{
- EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
- EFI_FV_BLOCK_MAP_ENTRY *blk = hdr->BlockMap;
-
- *Size = 0;
-
- while (blk->Length != 0 || blk->NumBlocks != 0) {
- *Size = *Size + (blk->Length * blk->NumBlocks);
- if (*Size >= 0x40000000) {
- // If size is greater than 1GB, then assume it is corrupted
- return EFI_VOLUME_CORRUPTED;
- }
- blk++;
- }
-
- if (*Size == 0) {
- // If size is 0, then assume the volume is corrupted
- return EFI_VOLUME_CORRUPTED;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Adds a new FFS file
-
- @param Fv Address of the Fv in memory
- @param File FFS file to add to Fv
-
- @retval EFI_SUCCESS
-**/
-EFI_STATUS
-FvBufAddFile (
- IN OUT VOID *Fv,
- IN VOID *File
- )
-{
- EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
-
- EFI_FFS_FILE_HEADER *fhdr = NULL;
- EFI_FVB_ATTRIBUTES_2 FvbAttributes;
- UINTN offset;
- UINTN fsize;
- UINTN newSize;
- UINTN clearLoop;
-
- EFI_STATUS Status;
- UINTN fvSize;
-
- Status = FvBufGetSize (Fv, &fvSize);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- FvbAttributes = hdr->Attributes;
- newSize = FvBufGetFfsFileSize ((EFI_FFS_FILE_HEADER*)File);
-
- for(
- offset = (UINTN)ALIGN_POINTER (hdr->HeaderLength, 8);
- offset + newSize <= fvSize;
- offset = (UINTN)ALIGN_POINTER (offset, 8)
- ) {
-
- fhdr = (EFI_FFS_FILE_HEADER*) ((UINT8*)hdr + offset);
-
- if (EFI_TEST_FFS_ATTRIBUTES_BIT(
- FvbAttributes,
- fhdr->State,
- EFI_FILE_HEADER_VALID
- )
- ) {
- // BUGBUG: Need to make sure that the new file does not already
- // exist.
-
- fsize = FvBufGetFfsFileSize (fhdr);
- if (fsize == 0 || (offset + fsize > fvSize)) {
- return EFI_VOLUME_CORRUPTED;
- }
-
- offset = offset + fsize;
- continue;
- }
-
- clearLoop = 0;
- while ((clearLoop < newSize) &&
- (((UINT8*)fhdr)[clearLoop] ==
- (UINT8)((hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0)
- )
- ) {
- clearLoop++;
- }
-
- //
- // We found a place in the FV which is empty and big enough for
- // the new file
- //
- if (clearLoop >= newSize) {
- break;
- }
-
- offset = offset + 1; // Make some forward progress
- }
-
- if (offset + newSize > fvSize) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- CommonLibBinderCopyMem (fhdr, File, newSize);
-
- return EFI_SUCCESS;
-}
-
-/**
- Adds a new FFS file. Extends the firmware volume if needed.
-
- @param Fv Source and destination firmware volume.
- Note: If the FV is extended, then the original firmware volume
- buffer is freed!
-
- @param Size The minimum size that the firmware volume is to be extended by.
- The FV may be extended more than this size.
-
- @retval EFI_SUCCESS
-**/
-EFI_STATUS
-FvBufAddFileWithExtend (
- IN OUT VOID **Fv,
- IN VOID *File
- )
-{
- EFI_STATUS Status;
- EFI_FFS_FILE_HEADER* NewFile;
-
- NewFile = (EFI_FFS_FILE_HEADER*)File;
-
- //
- // Try to add to the capsule volume
- //
- Status = FvBufAddFile (*Fv, NewFile);
- if (Status == EFI_OUT_OF_RESOURCES) {
- //
- // Try to extend the capsule volume by the size of the file
- //
- Status = FvBufExtend (Fv, FvBufExpand3ByteSize (NewFile->Size));
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Now, try to add the file again
- //
- Status = FvBufAddFile (*Fv, NewFile);
- }
-
- return Status;
-}
-
-/**
- Adds a new FFS VFT (Volume Top File) file. In other words, adds the
- file to the end of the firmware volume.
-
- @param Fv Address of the Fv in memory
- @param File FFS file to add to Fv
-
- @retval EFI_SUCCESS
-**/
-EFI_STATUS
-FvBufAddVtfFile (
- IN OUT VOID *Fv,
- IN VOID *File
- )
-{
- EFI_STATUS Status;
-
- EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
-
- EFI_FFS_FILE_HEADER* NewFile;
- UINTN NewFileSize;
-
- UINT8 erasedUint8;
- UINTN clearLoop;
-
- EFI_FFS_FILE_HEADER *LastFile;
- UINTN LastFileSize;
-
- UINTN fvSize;
- UINTN Key;
-
- Status = FvBufGetSize (Fv, &fvSize);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- erasedUint8 = (UINT8)((hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0);
- NewFileSize = FvBufGetFfsFileSize ((EFI_FFS_FILE_HEADER*)File);
-
- if (NewFileSize != (UINTN)ALIGN_POINTER (NewFileSize, 8)) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Find the last file in the FV
- //
- Key = 0;
- LastFile = NULL;
- LastFileSize = 0;
- do {
- Status = FvBufFindNextFile (Fv, &Key, (VOID **)&LastFile);
- LastFileSize = FvBufGetFfsFileSize ((EFI_FFS_FILE_HEADER*)File);
- } while (!EFI_ERROR (Status));
-
- //
- // If no files were found, then we start at the beginning of the FV
- //
- if (LastFile == NULL) {
- LastFile = (EFI_FFS_FILE_HEADER*)((UINT8*)hdr + hdr->HeaderLength);
- }
-
- //
- // We want to put the new file (VTF) at the end of the FV
- //
- NewFile = (EFI_FFS_FILE_HEADER*)((UINT8*)hdr + (fvSize - NewFileSize));
-
- //
- // Check to see if there is enough room for the VTF after the last file
- // found in the FV
- //
- if ((UINT8*)NewFile < ((UINT8*)LastFile + LastFileSize)) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- //
- // Loop to determine if the end of the FV is empty
- //
- clearLoop = 0;
- while ((clearLoop < NewFileSize) &&
- (((UINT8*)NewFile)[clearLoop] == erasedUint8)
- ) {
- clearLoop++;
- }
-
- //
- // Check to see if there was not enough room for the file
- //
- if (clearLoop < NewFileSize) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- CommonLibBinderCopyMem (NewFile, File, NewFileSize);
-
- return EFI_SUCCESS;
-}
-
-/**
- Expands the 3 byte size commonly used in Firmware Volume data structures
-
- @param Size Address of the 3 byte array representing the size
-
- @return UINT32
-**/
-VOID
-FvBufCompact3ByteSize (
- OUT VOID* SizeDest,
- IN UINT32 Size
- )
-{
- ((UINT8*)SizeDest)[0] = (UINT8)Size;
- ((UINT8*)SizeDest)[1] = (UINT8)(Size >> 8);
- ((UINT8*)SizeDest)[2] = (UINT8)(Size >> 16);
-}
-
-/**
- Get the FFS file size.
-
- @param Ffs Pointer to FFS header
-
- @return UINT32
-**/
-UINT32
-FvBufGetFfsFileSize (
- IN EFI_FFS_FILE_HEADER *Ffs
- )
-{
- if (Ffs == NULL) {
- return 0;
- }
- if (Ffs->Attributes & FFS_ATTRIB_LARGE_FILE) {
- return (UINT32) ((EFI_FFS_FILE_HEADER2 *)Ffs)->ExtendedSize;
- }
- return FvBufExpand3ByteSize(Ffs->Size);
-}
-
-/**
- Get the FFS header size.
-
- @param Ffs Pointer to FFS header
-
- @return UINT32
-**/
-UINT32
-FvBufGetFfsHeaderSize (
- IN EFI_FFS_FILE_HEADER *Ffs
- )
-{
- if (Ffs == NULL) {
- return 0;
- }
- if (Ffs->Attributes & FFS_ATTRIB_LARGE_FILE) {
- return sizeof(EFI_FFS_FILE_HEADER2);
- }
- return sizeof(EFI_FFS_FILE_HEADER);
-}
-
-/**
- Expands the 3 byte size commonly used in Firmware Volume data structures
-
- @param Size Address of the 3 byte array representing the size
-
- @return UINT32
-**/
-UINT32
-FvBufExpand3ByteSize (
- IN VOID* Size
- )
-{
- return (((UINT8*)Size)[2] << 16) +
- (((UINT8*)Size)[1] << 8) +
- ((UINT8*)Size)[0];
-}
-
-/**
- Iterates through the files contained within the firmware volume
-
- @param Fv Address of the Fv in memory
- @param Key Should be 0 to get the first file. After that, it should be
- passed back in without modifying its contents to retrieve
- subsequent files.
- @param File Output file pointer
- File == NULL - invalid parameter
- otherwise - *File will be update to the location of the file
-
- @retval EFI_SUCCESS
- @retval EFI_NOT_FOUND
- @retval EFI_VOLUME_CORRUPTED
-**/
-EFI_STATUS
-FvBufFindNextFile (
- IN VOID *Fv,
- IN OUT UINTN *Key,
- OUT VOID **File
- )
-{
- EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
-
- EFI_FFS_FILE_HEADER *fhdr = NULL;
- EFI_FVB_ATTRIBUTES_2 FvbAttributes;
- UINTN fsize;
-
- EFI_STATUS Status;
- UINTN fvSize;
-
- if (Fv == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- Status = FvBufGetSize (Fv, &fvSize);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (*Key == 0) {
- *Key = hdr->HeaderLength;
- }
-
- FvbAttributes = hdr->Attributes;
-
- for(
- *Key = (UINTN)ALIGN_POINTER (*Key, 8);
- (*Key + sizeof (*fhdr)) < fvSize;
- *Key = (UINTN)ALIGN_POINTER (*Key, 8)
- ) {
-
- fhdr = (EFI_FFS_FILE_HEADER*) ((UINT8*)hdr + *Key);
- fsize = FvBufGetFfsFileSize (fhdr);
-
- if (!EFI_TEST_FFS_ATTRIBUTES_BIT(
- FvbAttributes,
- fhdr->State,
- EFI_FILE_HEADER_VALID
- ) ||
- EFI_TEST_FFS_ATTRIBUTES_BIT(
- FvbAttributes,
- fhdr->State,
- EFI_FILE_HEADER_INVALID
- )
- ) {
- *Key = *Key + 1; // Make some forward progress
- continue;
- } else if(
- EFI_TEST_FFS_ATTRIBUTES_BIT(
- FvbAttributes,
- fhdr->State,
- EFI_FILE_MARKED_FOR_UPDATE
- ) ||
- EFI_TEST_FFS_ATTRIBUTES_BIT(
- FvbAttributes,
- fhdr->State,
- EFI_FILE_DELETED
- )
- ) {
- *Key = *Key + fsize;
- continue;
- } else if (EFI_TEST_FFS_ATTRIBUTES_BIT(
- FvbAttributes,
- fhdr->State,
- EFI_FILE_DATA_VALID
- )
- ) {
- *File = (UINT8*)hdr + *Key;
- *Key = *Key + fsize;
- return EFI_SUCCESS;
- }
-
- *Key = *Key + 1; // Make some forward progress
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- Searches the Fv for a file by its name
-
- @param Fv Address of the Fv in memory
- @param Name Guid filename to search for in the firmware volume
- @param File Output file pointer
- File == NULL - Only determine if the file exists, based on return
- value from the function call.
- otherwise - *File will be update to the location of the file
-
- @retval EFI_SUCCESS
- @retval EFI_NOT_FOUND
- @retval EFI_VOLUME_CORRUPTED
-**/
-EFI_STATUS
-FvBufFindFileByName (
- IN VOID *Fv,
- IN EFI_GUID *Name,
- OUT VOID **File
- )
-{
- EFI_STATUS Status;
- UINTN Key;
- EFI_FFS_FILE_HEADER *NextFile;
-
- Key = 0;
- while (TRUE) {
- Status = FvBufFindNextFile (Fv, &Key, (VOID **)&NextFile);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (CommonLibBinderCompareGuid (Name, &NextFile->Name)) {
- if (File != NULL) {
- *File = NextFile;
- }
- return EFI_SUCCESS;
- }
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- Searches the Fv for a file by its type
-
- @param Fv Address of the Fv in memory
- @param Type FFS FILE type to search for
- @param File Output file pointer
- (File == NULL) -> Only determine if the file exists, based on return
- value from the function call.
- otherwise -> *File will be update to the location of the file
-
- @retval EFI_SUCCESS
- @retval EFI_NOT_FOUND
- @retval EFI_VOLUME_CORRUPTED
-**/
-EFI_STATUS
-FvBufFindFileByType (
- IN VOID *Fv,
- IN EFI_FV_FILETYPE Type,
- OUT VOID **File
- )
-{
- EFI_STATUS Status;
- UINTN Key;
- EFI_FFS_FILE_HEADER *NextFile;
-
- Key = 0;
- while (TRUE) {
- Status = FvBufFindNextFile (Fv, &Key, (VOID **)&NextFile);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (Type == NextFile->Type) {
- if (File != NULL) {
- *File = NextFile;
- }
- return EFI_SUCCESS;
- }
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- Searches the requested file for raw data.
-
- This routine either returns all the payload of a EFI_FV_FILETYPE_RAW file,
- or finds the EFI_SECTION_RAW section within the file and returns its data.
-
- @param FfsFile Address of the FFS file in memory
- @param RawData Pointer to the raw data within the file
- (This is NOT allocated. It is within the file.)
- @param RawDataSize Size of the raw data within the file
-
- @return EFI_STATUS
-**/
-EFI_STATUS
-FvBufGetFileRawData (
- IN VOID* FfsFile,
- OUT VOID** RawData,
- OUT UINTN* RawDataSize
- )
-{
- EFI_STATUS Status;
- EFI_FFS_FILE_HEADER* File;
- EFI_RAW_SECTION* Section;
-
- File = (EFI_FFS_FILE_HEADER*)FfsFile;
-
- //
- // Is the file type == EFI_FV_FILETYPE_RAW?
- //
- if (File->Type == EFI_FV_FILETYPE_RAW) {
- //
- // Raw filetypes don't have sections, so we just return the raw data
- //
- *RawData = (VOID*)((UINT8 *)File + FvBufGetFfsHeaderSize (File));
- *RawDataSize = FvBufGetFfsFileSize (File) - FvBufGetFfsHeaderSize (File);
- return EFI_SUCCESS;
- }
-
- //
- // Within the file, we now need to find the EFI_SECTION_RAW section.
- //
- Status = FvBufFindSectionByType (File, EFI_SECTION_RAW, (VOID **)&Section);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- *RawData = (VOID*)((UINT8 *)Section + FvBufGetSecHdrLen(Section));
- *RawDataSize =
- FvBufGetSecFileLen (Section) - FvBufGetSecHdrLen(Section);
-
- return EFI_SUCCESS;
-
-}
-
-/**
- Packages up a FFS file containing the input raw data.
-
- The file created will have a type of EFI_FV_FILETYPE_FREEFORM, and will
- contain one EFI_FV_FILETYPE_RAW section.
-
- @param RawData Pointer to the raw data to be packed
- @param RawDataSize Size of the raw data to be packed
- @param FfsFile Address of the packaged FFS file.
- Note: The called must deallocate this memory!
-
- @return EFI_STATUS
-**/
-EFI_STATUS
-FvBufPackageFreeformRawFile (
- IN EFI_GUID* Filename,
- IN VOID* RawData,
- IN UINTN RawDataSize,
- OUT VOID** FfsFile
- )
-{
- EFI_FFS_FILE_HEADER* NewFile;
- UINT32 NewFileSize;
- EFI_RAW_SECTION* NewSection;
- UINT32 NewSectionSize;
- UINT32 FfsHdrLen;
- UINT32 SecHdrLen;
-
- //
- // The section size is the DataSize + the size of the section header
- //
- NewSectionSize = (UINT32)sizeof (EFI_RAW_SECTION) + (UINT32)RawDataSize;
- SecHdrLen = sizeof (EFI_RAW_SECTION);
- if (NewSectionSize >= MAX_SECTION_SIZE) {
- NewSectionSize = (UINT32)sizeof (EFI_RAW_SECTION2) + (UINT32)RawDataSize;
- SecHdrLen = sizeof (EFI_RAW_SECTION2);
- }
-
- //
- // The file size is the size of the file header + the section size
- //
- NewFileSize = sizeof (EFI_FFS_FILE_HEADER) + NewSectionSize;
- FfsHdrLen = sizeof (EFI_FFS_FILE_HEADER);
- if (NewFileSize >= MAX_FFS_SIZE) {
- NewFileSize = sizeof (EFI_FFS_FILE_HEADER2) + NewSectionSize;
- FfsHdrLen = sizeof (EFI_FFS_FILE_HEADER2);
- }
-
- //
- // Try to allocate a buffer to build the new FFS file in
- //
- NewFile = CommonLibBinderAllocate (NewFileSize);
- if (NewFile == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- CommonLibBinderSetMem (NewFile, NewFileSize, 0);
-
- //
- // The NewSection follow right after the FFS file header
- //
- NewSection = (EFI_RAW_SECTION*)((UINT8*)NewFile + FfsHdrLen);
- if (NewSectionSize >= MAX_SECTION_SIZE) {
- FvBufCompact3ByteSize (NewSection->Size, 0xffffff);
- ((EFI_RAW_SECTION2 *)NewSection)->ExtendedSize = NewSectionSize;
- } else {
- FvBufCompact3ByteSize (NewSection->Size, NewSectionSize);
- }
- NewSection->Type = EFI_SECTION_RAW;
-
- //
- // Copy the actual file data into the buffer
- //
- CommonLibBinderCopyMem ((UINT8 *)NewSection + SecHdrLen, RawData, RawDataSize);
-
- //
- // Initialize the FFS file header
- //
- CommonLibBinderCopyMem (&NewFile->Name, Filename, sizeof (EFI_GUID));
- NewFile->Attributes = 0;
- if (NewFileSize >= MAX_FFS_SIZE) {
- FvBufCompact3ByteSize (NewFile->Size, 0x0);
- ((EFI_FFS_FILE_HEADER2 *)NewFile)->ExtendedSize = NewFileSize;
- NewFile->Attributes |= FFS_ATTRIB_LARGE_FILE;
- } else {
- FvBufCompact3ByteSize (NewFile->Size, NewFileSize);
- }
- NewFile->Type = EFI_FV_FILETYPE_FREEFORM;
- NewFile->IntegrityCheck.Checksum.Header =
- FvBufCalculateChecksum8 ((UINT8*)NewFile, FfsHdrLen);
- NewFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
- NewFile->State = (UINT8)~( EFI_FILE_HEADER_CONSTRUCTION |
- EFI_FILE_HEADER_VALID |
- EFI_FILE_DATA_VALID
- );
-
- *FfsFile = NewFile;
-
- return EFI_SUCCESS;
-}
-
-/**
- Iterates through the sections contained within a given array of sections
-
- @param SectionsStart Address of the start of the FFS sections array
- @param TotalSectionsSize Total size of all the sections
- @param Key Should be 0 to get the first section. After that, it should be
- passed back in without modifying its contents to retrieve
- subsequent files.
- @param Section Output section pointer
- (Section == NULL) -> invalid parameter
- otherwise -> *Section will be update to the location of the file
-
- @retval EFI_SUCCESS
- @retval EFI_NOT_FOUND
- @retval EFI_VOLUME_CORRUPTED
-**/
-EFI_STATUS
-FvBufFindNextSection (
- IN VOID *SectionsStart,
- IN UINTN TotalSectionsSize,
- IN OUT UINTN *Key,
- OUT VOID **Section
- )
-{
- EFI_COMMON_SECTION_HEADER *sectionHdr;
- UINTN sectionSize;
-
- *Key = (UINTN)ALIGN_POINTER (*Key, 4); // Sections are DWORD aligned
-
- if ((*Key + sizeof (*sectionHdr)) > TotalSectionsSize) {
- return EFI_NOT_FOUND;
- }
-
- sectionHdr = (EFI_COMMON_SECTION_HEADER*)((UINT8*)SectionsStart + *Key);
- sectionSize = FvBufGetSecFileLen (sectionHdr);
-
- if (sectionSize < sizeof (EFI_COMMON_SECTION_HEADER)) {
- return EFI_NOT_FOUND;
- }
-
- if ((*Key + sectionSize) > TotalSectionsSize) {
- return EFI_NOT_FOUND;
- }
-
- *Section = (UINT8*)sectionHdr;
- *Key = *Key + sectionSize;
- return EFI_SUCCESS;
-
-}
-
-/**
- Searches the FFS file and counts the number of sections found.
- The sections are NOT recursed.
-
- @param FfsFile Address of the FFS file in memory
- @param Count The location to store the section count in
-
- @retval EFI_SUCCESS
- @retval EFI_NOT_FOUND
- @retval EFI_VOLUME_CORRUPTED
-**/
-EFI_STATUS
-FvBufCountSections (
- IN VOID* FfsFile,
- IN UINTN* Count
- )
-{
- EFI_STATUS Status;
- UINTN Key;
- VOID* SectionStart;
- UINTN TotalSectionsSize;
- EFI_COMMON_SECTION_HEADER* NextSection;
-
- SectionStart = (VOID*)((UINTN)FfsFile + FvBufGetFfsHeaderSize(FfsFile));
- TotalSectionsSize =
- FvBufGetFfsFileSize ((EFI_FFS_FILE_HEADER*)FfsFile) -
- FvBufGetFfsHeaderSize(FfsFile);
- Key = 0;
- *Count = 0;
- while (TRUE) {
- Status = FvBufFindNextSection (
- SectionStart,
- TotalSectionsSize,
- &Key,
- (VOID **)&NextSection
- );
- if (Status == EFI_NOT_FOUND) {
- return EFI_SUCCESS;
- } else if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Increment the section counter
- //
- *Count += 1;
-
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- Searches the FFS file for a section by its type
-
- @param FfsFile Address of the FFS file in memory
- @param Type FFS FILE section type to search for
- @param Section Output section pointer
- (Section == NULL) -> Only determine if the section exists, based on return
- value from the function call.
- otherwise -> *Section will be update to the location of the file
-
- @retval EFI_SUCCESS
- @retval EFI_NOT_FOUND
- @retval EFI_VOLUME_CORRUPTED
-**/
-EFI_STATUS
-FvBufFindSectionByType (
- IN VOID *FfsFile,
- IN UINT8 Type,
- OUT VOID **Section
- )
-{
- EFI_STATUS Status;
- UINTN Key;
- VOID* SectionStart;
- UINTN TotalSectionsSize;
- EFI_COMMON_SECTION_HEADER* NextSection;
-
- SectionStart = (VOID*)((UINTN)FfsFile + FvBufGetFfsHeaderSize(FfsFile));
- TotalSectionsSize =
- FvBufGetFfsFileSize ((EFI_FFS_FILE_HEADER*)FfsFile) -
- FvBufGetFfsHeaderSize(FfsFile);
- Key = 0;
- while (TRUE) {
- Status = FvBufFindNextSection (
- SectionStart,
- TotalSectionsSize,
- &Key,
- (VOID **)&NextSection
- );
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- if (Type == NextSection->Type) {
- if (Section != NULL) {
- *Section = NextSection;
- }
- return EFI_SUCCESS;
- }
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- Shrinks a firmware volume (in place) to provide a minimal FV.
-
- BUGBUG: Does not handle the case where the firmware volume has a
- VTF (Volume Top File). The VTF will not be moved to the
- end of the extended FV.
-
- @param Fv Firmware volume.
-
- @retval EFI_SUCCESS
-**/
-EFI_STATUS
-FvBufShrinkWrap (
- IN VOID *Fv
- )
-{
- EFI_STATUS Status;
- UINTN OldSize;
- UINT32 BlockCount;
- UINT32 NewBlockSize = 128;
- UINTN Key;
- EFI_FFS_FILE_HEADER* FileIt;
- VOID* EndOfLastFile;
-
- EFI_FIRMWARE_VOLUME_HEADER* FvHdr;
-
- Status = FvBufGetSize (Fv, &OldSize);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- Status = FvBufUnifyBlockSizes (Fv, NewBlockSize);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- //
- // Locate the block map in the fv header
- //
- FvHdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
-
- //
- // Find the end of the last file
- //
- Key = 0;
- EndOfLastFile = (UINT8*)FvHdr + FvHdr->FvLength;
- while (!EFI_ERROR (FvBufFindNextFile (Fv, &Key, (VOID **)&FileIt))) {
- EndOfLastFile =
- (VOID*)((UINT8*)FileIt + FvBufGetFfsFileSize (FileIt));
- }
-
- //
- // Set the BlockCount to have the minimal number of blocks for the Fv.
- //
- BlockCount = (UINT32)((UINTN)EndOfLastFile - (UINTN)Fv);
- BlockCount = BlockCount + NewBlockSize - 1;
- BlockCount = BlockCount / NewBlockSize;
-
- //
- // Adjust the block count to shrink the Fv in place.
- //
- FvHdr->BlockMap[0].NumBlocks = BlockCount;
- FvHdr->FvLength = BlockCount * NewBlockSize;
-
- //
- // Update the FV header checksum
- //
- FvBufChecksumHeader (Fv);
-
- return EFI_SUCCESS;
-
-}
-
-/**
- Searches the FFS file for a section by its type
-
- @param Fv Address of the Fv in memory
- @param BlockSize The size of the blocks to convert the Fv to. If the total size
- of the Fv is not evenly divisible by this size, then
- EFI_INVALID_PARAMETER will be returned.
-
- @retval EFI_SUCCESS
- @retval EFI_NOT_FOUND
- @retval EFI_VOLUME_CORRUPTED
-**/
-EFI_STATUS
-FvBufUnifyBlockSizes (
- IN OUT VOID *Fv,
- IN UINTN BlockSize
- )
-{
- EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv;
- EFI_FV_BLOCK_MAP_ENTRY *blk = hdr->BlockMap;
- UINT32 Size;
-
- Size = 0;
-
- //
- // Scan through the block map list, performing error checking, and adding
- // up the total Fv size.
- //
- while( blk->Length != 0 ||
- blk->NumBlocks != 0
- ) {
- Size = Size + (blk->Length * blk->NumBlocks);
- blk++;
- if ((UINT8*)blk > ((UINT8*)hdr + hdr->HeaderLength)) {
- return EFI_VOLUME_CORRUPTED;
- }
- }
-
- //
- // Make sure that the Fv size is a multiple of the new block size.
- //
- if ((Size % BlockSize) != 0) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Zero out the entire block map.
- //
- CommonLibBinderSetMem (
- &hdr->BlockMap,
- (UINTN)blk - (UINTN)&hdr->BlockMap,
- 0
- );
-
- //
- // Write out the single block map entry.
- //
- hdr->BlockMap[0].Length = (UINT32)BlockSize;
- hdr->BlockMap[0].NumBlocks = Size / (UINT32)BlockSize;
-
- return EFI_SUCCESS;
-}
-
-/**
- This function calculates the UINT16 sum for the requested region.
-
- @param Buffer Pointer to buffer containing byte data of component.
- @param Size Size of the buffer
-
- @return The 16 bit checksum
-**/
-STATIC
-UINT16
-FvBufCalculateSum16 (
- IN UINT16 *Buffer,
- IN UINTN Size
- )
-{
- UINTN Index;
- UINT16 Sum;
-
- Sum = 0;
-
- //
- // Perform the word sum for buffer
- //
- for (Index = 0; Index < Size; Index++) {
- Sum = (UINT16) (Sum + Buffer[Index]);
- }
-
- return (UINT16) Sum;
-}
-
-/**
- This function calculates the value needed for a valid UINT16 checksum
-
- @param Buffer Pointer to buffer containing byte data of component.
- @param Size Size of the buffer
-
- @return The 16 bit checksum value needed.
-**/
-STATIC
-UINT16
-FvBufCalculateChecksum16 (
- IN UINT16 *Buffer,
- IN UINTN Size
- )
-{
- return (UINT16)(0x10000 - FvBufCalculateSum16 (Buffer, Size));
-}
-
-/**
- This function calculates the UINT8 sum for the requested region.
-
- @param Buffer Pointer to buffer containing byte data of component.
- @param Size Size of the buffer
-
- @return The 8 bit checksum value needed.
-**/
-STATIC
-UINT8
-FvBufCalculateSum8 (
- IN UINT8 *Buffer,
- IN UINTN Size
- )
-{
- UINTN Index;
- UINT8 Sum;
-
- Sum = 0;
-
- //
- // Perform the byte sum for buffer
- //
- for (Index = 0; Index < Size; Index++) {
- Sum = (UINT8) (Sum + Buffer[Index]);
- }
-
- return Sum;
-}
-
-/**
- This function calculates the value needed for a valid UINT8 checksum
-
- @param Buffer Pointer to buffer containing byte data of component.
- @param Size Size of the buffer
-
- @return The 8 bit checksum value needed.
-**/
-STATIC
-UINT8
-FvBufCalculateChecksum8 (
- IN UINT8 *Buffer,
- IN UINTN Size
- )
-{
- return (UINT8)(0x100 - FvBufCalculateSum8 (Buffer, Size));
-}
-
-
+/** @file +EFI Firmware Volume routines which work on a Fv image in buffers. + +Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "FirmwareVolumeBufferLib.h" +#include "BinderFuncs.h" + +// +// Local macros +// +#define EFI_TEST_FFS_ATTRIBUTES_BIT(FvbAttributes, TestAttributes, Bit) \ + ( \ + (BOOLEAN) ( \ + (FvbAttributes & EFI_FVB2_ERASE_POLARITY) ? (((~TestAttributes) & Bit) == Bit) : ((TestAttributes & Bit) == Bit) \ + ) \ + ) + + +// +// Local prototypes +// + +STATIC +UINT32 +FvBufGetSecHdrLen( + IN EFI_COMMON_SECTION_HEADER *SectionHeader + ) +{ + if (SectionHeader == NULL) { + return 0; + } + if (FvBufExpand3ByteSize(SectionHeader->Size) == 0xffffff) { + return sizeof(EFI_COMMON_SECTION_HEADER2); + } + return sizeof(EFI_COMMON_SECTION_HEADER); +} + +STATIC +UINT32 +FvBufGetSecFileLen ( + IN EFI_COMMON_SECTION_HEADER *SectionHeader + ) +{ + UINT32 Length; + if (SectionHeader == NULL) { + return 0; + } + Length = FvBufExpand3ByteSize(SectionHeader->Size); + if (Length == 0xffffff) { + Length = ((EFI_COMMON_SECTION_HEADER2 *)SectionHeader)->ExtendedSize; + } + return Length; +} + +// +// Local prototypes +// + +STATIC +UINT16 +FvBufCalculateChecksum16 ( + IN UINT16 *Buffer, + IN UINTN Size + ); + +STATIC +UINT8 +FvBufCalculateChecksum8 ( + IN UINT8 *Buffer, + IN UINTN Size + ); + +// +// Procedures start +// + +/** + Clears out all files from the Fv buffer in memory + + @param SourceFv Address of the Fv in memory, this firmware volume will + be modified, if SourceFfsFile exists + @param SourceFfsFile Input FFS file to replace + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND +**/ +EFI_STATUS +FvBufRemoveFileNew ( + IN OUT VOID *Fv, + IN EFI_GUID *Name + ) +{ + EFI_STATUS Status; + EFI_FFS_FILE_HEADER* FileToRm; + UINTN FileToRmLength; + + Status = FvBufFindFileByName( + Fv, + Name, + (VOID **)&FileToRm + ); + if (EFI_ERROR (Status)) { + return Status; + } + + FileToRmLength = FvBufGetFfsFileSize (FileToRm); + + CommonLibBinderSetMem ( + FileToRm, + FileToRmLength, + (((EFI_FIRMWARE_VOLUME_HEADER*)Fv)->Attributes & EFI_FVB2_ERASE_POLARITY) + ? 0xFF : 0 + ); + + return EFI_SUCCESS; +} + +/** + Clears out all files from the Fv buffer in memory + + @param SourceFv Address of the Fv in memory, this firmware volume will + be modified, if SourceFfsFile exists + @param SourceFfsFile Input FFS file to replace + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND +**/ +EFI_STATUS +FvBufRemoveFile ( + IN OUT VOID *Fv, + IN EFI_GUID *Name + ) +{ + EFI_STATUS Status; + EFI_FFS_FILE_HEADER *NextFile; + EFI_FIRMWARE_VOLUME_HEADER *TempFv; + UINTN FileKey; + UINTN FvLength; + + Status = FvBufFindFileByName( + Fv, + Name, + NULL + ); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = FvBufGetSize (Fv, &FvLength); + if (EFI_ERROR (Status)) { + return Status; + } + + TempFv = NULL; + Status = FvBufDuplicate (Fv, (VOID **)&TempFv); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = FvBufClearAllFiles (TempFv); + if (EFI_ERROR (Status)) { + CommonLibBinderFree (TempFv); + return Status; + } + + // TempFv has been allocated. It must now be freed + // before returning. + + FileKey = 0; + while (TRUE) { + + Status = FvBufFindNextFile (Fv, &FileKey, (VOID **)&NextFile); + if (Status == EFI_NOT_FOUND) { + break; + } else if (EFI_ERROR (Status)) { + CommonLibBinderFree (TempFv); + return Status; + } + + if (CommonLibBinderCompareGuid (Name, &NextFile->Name)) { + continue; + } + else { + Status = FvBufAddFile (TempFv, NextFile); + if (EFI_ERROR (Status)) { + CommonLibBinderFree (TempFv); + return Status; + } + } + } + + CommonLibBinderCopyMem (Fv, TempFv, FvLength); + CommonLibBinderFree (TempFv); + + return EFI_SUCCESS; +} + +/** + Clears out all files from the Fv buffer in memory + + @param SourceFfsFile Input FFS file to update the checksum for + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND +**/ +EFI_STATUS +FvBufChecksumFile ( + IN OUT VOID *FfsFile + ) +{ + EFI_FFS_FILE_HEADER* File = (EFI_FFS_FILE_HEADER*)FfsFile; + EFI_FFS_FILE_STATE StateBackup; + UINT32 FileSize; + + FileSize = FvBufGetFfsFileSize (File); + + // + // Fill in checksums and state, they must be 0 for checksumming. + // + File->IntegrityCheck.Checksum.Header = 0; + File->IntegrityCheck.Checksum.File = 0; + StateBackup = File->State; + File->State = 0; + + File->IntegrityCheck.Checksum.Header = + FvBufCalculateChecksum8 ( + (UINT8 *) File, + FvBufGetFfsHeaderSize (File) + ); + + if (File->Attributes & FFS_ATTRIB_CHECKSUM) { + File->IntegrityCheck.Checksum.File = FvBufCalculateChecksum8 ( + (VOID*)((UINT8 *)File + FvBufGetFfsHeaderSize (File)), + FileSize - FvBufGetFfsHeaderSize (File) + ); + } else { + File->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; + } + + File->State = StateBackup; + + return EFI_SUCCESS; +} + +/** + Clears out all files from the Fv buffer in memory + + @param SourceFv Address of the Fv in memory, this firmware volume will + be modified, if SourceFfsFile exists + @param SourceFfsFile Input FFS file to replace + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND +**/ +EFI_STATUS +FvBufChecksumHeader ( + IN OUT VOID *Fv + ) +{ + EFI_FIRMWARE_VOLUME_HEADER* FvHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + + FvHeader->Checksum = 0; + FvHeader->Checksum = + FvBufCalculateChecksum16 ( + (UINT16*) FvHeader, + FvHeader->HeaderLength / sizeof (UINT16) + ); + + return EFI_SUCCESS; +} + +/** + Clears out all files from the Fv buffer in memory + + @param SourceFv - Address of the Fv in memory + @param DestinationFv - Output for destination Fv + DestinationFv == NULL - invalid parameter + *DestinationFv == NULL - memory will be allocated + *DestinationFv != NULL - this address will be the destination + + @retval EFI_SUCCESS +**/ +EFI_STATUS +FvBufDuplicate ( + IN VOID *SourceFv, + IN OUT VOID **DestinationFv + ) +{ + EFI_STATUS Status; + UINTN size; + + if (DestinationFv == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = FvBufGetSize (SourceFv, &size); + if (EFI_ERROR (Status)) { + return Status; + } + + if (*DestinationFv == NULL) { + *DestinationFv = CommonLibBinderAllocate (size); + if (*DestinationFv == NULL) { + return EFI_OUT_OF_RESOURCES; + } + } + + CommonLibBinderCopyMem (*DestinationFv, SourceFv, size); + + return EFI_SUCCESS; +} + +/** + Extends a firmware volume by the given number of bytes. + + BUGBUG: Does not handle the case where the firmware volume has a + VTF (Volume Top File). The VTF will not be moved to the + end of the extended FV. + + @param Fv Source and destination firmware volume. + Note: The original firmware volume buffer is freed! + + @param Size The minimum size that the firmware volume is to be extended by. + The FV may be extended more than this size. + + @retval EFI_SUCCESS +**/ +EFI_STATUS +FvBufExtend ( + IN VOID **Fv, + IN UINTN Size + ) +{ + EFI_STATUS Status; + UINTN OldSize; + UINTN NewSize; + UINTN BlockCount; + VOID* NewFv; + + EFI_FIRMWARE_VOLUME_HEADER* hdr; + EFI_FV_BLOCK_MAP_ENTRY* blk; + + Status = FvBufGetSize (*Fv, &OldSize); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Locate the block map in the fv header + // + hdr = (EFI_FIRMWARE_VOLUME_HEADER*)*Fv; + blk = hdr->BlockMap; + + // + // Calculate the number of blocks needed to achieve the requested + // size extension + // + BlockCount = ((Size + (blk->Length - 1)) / blk->Length); + + // + // Calculate the new size from the number of blocks that will be added + // + NewSize = OldSize + (BlockCount * blk->Length); + + NewFv = CommonLibBinderAllocate (NewSize); + if (NewFv == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Copy the old data + // + CommonLibBinderCopyMem (NewFv, *Fv, OldSize); + + // + // Free the old fv buffer + // + CommonLibBinderFree (*Fv); + + // + // Locate the block map in the new fv header + // + hdr = (EFI_FIRMWARE_VOLUME_HEADER*)NewFv; + hdr->FvLength = NewSize; + blk = hdr->BlockMap; + + // + // Update the block map for the new fv + // + blk->NumBlocks += (UINT32)BlockCount; + + // + // Update the FV header checksum + // + FvBufChecksumHeader (NewFv); + + // + // Clear out the new area of the FV + // + CommonLibBinderSetMem ( + (UINT8*)NewFv + OldSize, + (NewSize - OldSize), + (hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0 + ); + + // + // Set output with new fv that was created + // + *Fv = NewFv; + + return EFI_SUCCESS; + +} + +/** + Clears out all files from the Fv buffer in memory + + @param Fv Address of the Fv in memory + + @retval EFI_SUCCESS +**/ +EFI_STATUS +FvBufClearAllFiles ( + IN OUT VOID *Fv + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + EFI_STATUS Status; + UINTN size = 0; + + Status = FvBufGetSize (Fv, &size); + if (EFI_ERROR (Status)) { + return Status; + } + + CommonLibBinderSetMem( + (UINT8*)hdr + hdr->HeaderLength, + size - hdr->HeaderLength, + (hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0 + ); + + return EFI_SUCCESS; +} + +/** + Clears out all files from the Fv buffer in memory + + @param Fv Address of the Fv in memory + + @retval EFI_SUCCESS +**/ +EFI_STATUS +FvBufGetSize ( + IN VOID *Fv, + OUT UINTN *Size + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + EFI_FV_BLOCK_MAP_ENTRY *blk = hdr->BlockMap; + + *Size = 0; + + while (blk->Length != 0 || blk->NumBlocks != 0) { + *Size = *Size + (blk->Length * blk->NumBlocks); + if (*Size >= 0x40000000) { + // If size is greater than 1GB, then assume it is corrupted + return EFI_VOLUME_CORRUPTED; + } + blk++; + } + + if (*Size == 0) { + // If size is 0, then assume the volume is corrupted + return EFI_VOLUME_CORRUPTED; + } + + return EFI_SUCCESS; +} + +/** + Adds a new FFS file + + @param Fv Address of the Fv in memory + @param File FFS file to add to Fv + + @retval EFI_SUCCESS +**/ +EFI_STATUS +FvBufAddFile ( + IN OUT VOID *Fv, + IN VOID *File + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + + EFI_FFS_FILE_HEADER *fhdr = NULL; + EFI_FVB_ATTRIBUTES_2 FvbAttributes; + UINTN offset; + UINTN fsize; + UINTN newSize; + UINTN clearLoop; + + EFI_STATUS Status; + UINTN fvSize; + + Status = FvBufGetSize (Fv, &fvSize); + if (EFI_ERROR (Status)) { + return Status; + } + + FvbAttributes = hdr->Attributes; + newSize = FvBufGetFfsFileSize ((EFI_FFS_FILE_HEADER*)File); + + for( + offset = (UINTN)ALIGN_POINTER (hdr->HeaderLength, 8); + offset + newSize <= fvSize; + offset = (UINTN)ALIGN_POINTER (offset, 8) + ) { + + fhdr = (EFI_FFS_FILE_HEADER*) ((UINT8*)hdr + offset); + + if (EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_HEADER_VALID + ) + ) { + // BUGBUG: Need to make sure that the new file does not already + // exist. + + fsize = FvBufGetFfsFileSize (fhdr); + if (fsize == 0 || (offset + fsize > fvSize)) { + return EFI_VOLUME_CORRUPTED; + } + + offset = offset + fsize; + continue; + } + + clearLoop = 0; + while ((clearLoop < newSize) && + (((UINT8*)fhdr)[clearLoop] == + (UINT8)((hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0) + ) + ) { + clearLoop++; + } + + // + // We found a place in the FV which is empty and big enough for + // the new file + // + if (clearLoop >= newSize) { + break; + } + + offset = offset + 1; // Make some forward progress + } + + if (offset + newSize > fvSize) { + return EFI_OUT_OF_RESOURCES; + } + + CommonLibBinderCopyMem (fhdr, File, newSize); + + return EFI_SUCCESS; +} + +/** + Adds a new FFS file. Extends the firmware volume if needed. + + @param Fv Source and destination firmware volume. + Note: If the FV is extended, then the original firmware volume + buffer is freed! + + @param Size The minimum size that the firmware volume is to be extended by. + The FV may be extended more than this size. + + @retval EFI_SUCCESS +**/ +EFI_STATUS +FvBufAddFileWithExtend ( + IN OUT VOID **Fv, + IN VOID *File + ) +{ + EFI_STATUS Status; + EFI_FFS_FILE_HEADER* NewFile; + + NewFile = (EFI_FFS_FILE_HEADER*)File; + + // + // Try to add to the capsule volume + // + Status = FvBufAddFile (*Fv, NewFile); + if (Status == EFI_OUT_OF_RESOURCES) { + // + // Try to extend the capsule volume by the size of the file + // + Status = FvBufExtend (Fv, FvBufExpand3ByteSize (NewFile->Size)); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Now, try to add the file again + // + Status = FvBufAddFile (*Fv, NewFile); + } + + return Status; +} + +/** + Adds a new FFS VFT (Volume Top File) file. In other words, adds the + file to the end of the firmware volume. + + @param Fv Address of the Fv in memory + @param File FFS file to add to Fv + + @retval EFI_SUCCESS +**/ +EFI_STATUS +FvBufAddVtfFile ( + IN OUT VOID *Fv, + IN VOID *File + ) +{ + EFI_STATUS Status; + + EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + + EFI_FFS_FILE_HEADER* NewFile; + UINTN NewFileSize; + + UINT8 erasedUint8; + UINTN clearLoop; + + EFI_FFS_FILE_HEADER *LastFile; + UINTN LastFileSize; + + UINTN fvSize; + UINTN Key; + + Status = FvBufGetSize (Fv, &fvSize); + if (EFI_ERROR (Status)) { + return Status; + } + + erasedUint8 = (UINT8)((hdr->Attributes & EFI_FVB2_ERASE_POLARITY) ? 0xFF : 0); + NewFileSize = FvBufGetFfsFileSize ((EFI_FFS_FILE_HEADER*)File); + + if (NewFileSize != (UINTN)ALIGN_POINTER (NewFileSize, 8)) { + return EFI_INVALID_PARAMETER; + } + + // + // Find the last file in the FV + // + Key = 0; + LastFile = NULL; + LastFileSize = 0; + do { + Status = FvBufFindNextFile (Fv, &Key, (VOID **)&LastFile); + LastFileSize = FvBufGetFfsFileSize ((EFI_FFS_FILE_HEADER*)File); + } while (!EFI_ERROR (Status)); + + // + // If no files were found, then we start at the beginning of the FV + // + if (LastFile == NULL) { + LastFile = (EFI_FFS_FILE_HEADER*)((UINT8*)hdr + hdr->HeaderLength); + } + + // + // We want to put the new file (VTF) at the end of the FV + // + NewFile = (EFI_FFS_FILE_HEADER*)((UINT8*)hdr + (fvSize - NewFileSize)); + + // + // Check to see if there is enough room for the VTF after the last file + // found in the FV + // + if ((UINT8*)NewFile < ((UINT8*)LastFile + LastFileSize)) { + return EFI_OUT_OF_RESOURCES; + } + + // + // Loop to determine if the end of the FV is empty + // + clearLoop = 0; + while ((clearLoop < NewFileSize) && + (((UINT8*)NewFile)[clearLoop] == erasedUint8) + ) { + clearLoop++; + } + + // + // Check to see if there was not enough room for the file + // + if (clearLoop < NewFileSize) { + return EFI_OUT_OF_RESOURCES; + } + + CommonLibBinderCopyMem (NewFile, File, NewFileSize); + + return EFI_SUCCESS; +} + +/** + Expands the 3 byte size commonly used in Firmware Volume data structures + + @param Size Address of the 3 byte array representing the size + + @return UINT32 +**/ +VOID +FvBufCompact3ByteSize ( + OUT VOID* SizeDest, + IN UINT32 Size + ) +{ + ((UINT8*)SizeDest)[0] = (UINT8)Size; + ((UINT8*)SizeDest)[1] = (UINT8)(Size >> 8); + ((UINT8*)SizeDest)[2] = (UINT8)(Size >> 16); +} + +/** + Get the FFS file size. + + @param Ffs Pointer to FFS header + + @return UINT32 +**/ +UINT32 +FvBufGetFfsFileSize ( + IN EFI_FFS_FILE_HEADER *Ffs + ) +{ + if (Ffs == NULL) { + return 0; + } + if (Ffs->Attributes & FFS_ATTRIB_LARGE_FILE) { + return (UINT32) ((EFI_FFS_FILE_HEADER2 *)Ffs)->ExtendedSize; + } + return FvBufExpand3ByteSize(Ffs->Size); +} + +/** + Get the FFS header size. + + @param Ffs Pointer to FFS header + + @return UINT32 +**/ +UINT32 +FvBufGetFfsHeaderSize ( + IN EFI_FFS_FILE_HEADER *Ffs + ) +{ + if (Ffs == NULL) { + return 0; + } + if (Ffs->Attributes & FFS_ATTRIB_LARGE_FILE) { + return sizeof(EFI_FFS_FILE_HEADER2); + } + return sizeof(EFI_FFS_FILE_HEADER); +} + +/** + Expands the 3 byte size commonly used in Firmware Volume data structures + + @param Size Address of the 3 byte array representing the size + + @return UINT32 +**/ +UINT32 +FvBufExpand3ByteSize ( + IN VOID* Size + ) +{ + return (((UINT8*)Size)[2] << 16) + + (((UINT8*)Size)[1] << 8) + + ((UINT8*)Size)[0]; +} + +/** + Iterates through the files contained within the firmware volume + + @param Fv Address of the Fv in memory + @param Key Should be 0 to get the first file. After that, it should be + passed back in without modifying its contents to retrieve + subsequent files. + @param File Output file pointer + File == NULL - invalid parameter + otherwise - *File will be update to the location of the file + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND + @retval EFI_VOLUME_CORRUPTED +**/ +EFI_STATUS +FvBufFindNextFile ( + IN VOID *Fv, + IN OUT UINTN *Key, + OUT VOID **File + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + + EFI_FFS_FILE_HEADER *fhdr = NULL; + EFI_FVB_ATTRIBUTES_2 FvbAttributes; + UINTN fsize; + + EFI_STATUS Status; + UINTN fvSize; + + if (Fv == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = FvBufGetSize (Fv, &fvSize); + if (EFI_ERROR (Status)) { + return Status; + } + + if (*Key == 0) { + *Key = hdr->HeaderLength; + } + + FvbAttributes = hdr->Attributes; + + for( + *Key = (UINTN)ALIGN_POINTER (*Key, 8); + (*Key + sizeof (*fhdr)) < fvSize; + *Key = (UINTN)ALIGN_POINTER (*Key, 8) + ) { + + fhdr = (EFI_FFS_FILE_HEADER*) ((UINT8*)hdr + *Key); + fsize = FvBufGetFfsFileSize (fhdr); + + if (!EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_HEADER_VALID + ) || + EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_HEADER_INVALID + ) + ) { + *Key = *Key + 1; // Make some forward progress + continue; + } else if( + EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_MARKED_FOR_UPDATE + ) || + EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_DELETED + ) + ) { + *Key = *Key + fsize; + continue; + } else if (EFI_TEST_FFS_ATTRIBUTES_BIT( + FvbAttributes, + fhdr->State, + EFI_FILE_DATA_VALID + ) + ) { + *File = (UINT8*)hdr + *Key; + *Key = *Key + fsize; + return EFI_SUCCESS; + } + + *Key = *Key + 1; // Make some forward progress + } + + return EFI_NOT_FOUND; +} + +/** + Searches the Fv for a file by its name + + @param Fv Address of the Fv in memory + @param Name Guid filename to search for in the firmware volume + @param File Output file pointer + File == NULL - Only determine if the file exists, based on return + value from the function call. + otherwise - *File will be update to the location of the file + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND + @retval EFI_VOLUME_CORRUPTED +**/ +EFI_STATUS +FvBufFindFileByName ( + IN VOID *Fv, + IN EFI_GUID *Name, + OUT VOID **File + ) +{ + EFI_STATUS Status; + UINTN Key; + EFI_FFS_FILE_HEADER *NextFile; + + Key = 0; + while (TRUE) { + Status = FvBufFindNextFile (Fv, &Key, (VOID **)&NextFile); + if (EFI_ERROR (Status)) { + return Status; + } + + if (CommonLibBinderCompareGuid (Name, &NextFile->Name)) { + if (File != NULL) { + *File = NextFile; + } + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + Searches the Fv for a file by its type + + @param Fv Address of the Fv in memory + @param Type FFS FILE type to search for + @param File Output file pointer + (File == NULL) -> Only determine if the file exists, based on return + value from the function call. + otherwise -> *File will be update to the location of the file + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND + @retval EFI_VOLUME_CORRUPTED +**/ +EFI_STATUS +FvBufFindFileByType ( + IN VOID *Fv, + IN EFI_FV_FILETYPE Type, + OUT VOID **File + ) +{ + EFI_STATUS Status; + UINTN Key; + EFI_FFS_FILE_HEADER *NextFile; + + Key = 0; + while (TRUE) { + Status = FvBufFindNextFile (Fv, &Key, (VOID **)&NextFile); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Type == NextFile->Type) { + if (File != NULL) { + *File = NextFile; + } + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + Searches the requested file for raw data. + + This routine either returns all the payload of a EFI_FV_FILETYPE_RAW file, + or finds the EFI_SECTION_RAW section within the file and returns its data. + + @param FfsFile Address of the FFS file in memory + @param RawData Pointer to the raw data within the file + (This is NOT allocated. It is within the file.) + @param RawDataSize Size of the raw data within the file + + @return EFI_STATUS +**/ +EFI_STATUS +FvBufGetFileRawData ( + IN VOID* FfsFile, + OUT VOID** RawData, + OUT UINTN* RawDataSize + ) +{ + EFI_STATUS Status; + EFI_FFS_FILE_HEADER* File; + EFI_RAW_SECTION* Section; + + File = (EFI_FFS_FILE_HEADER*)FfsFile; + + // + // Is the file type == EFI_FV_FILETYPE_RAW? + // + if (File->Type == EFI_FV_FILETYPE_RAW) { + // + // Raw filetypes don't have sections, so we just return the raw data + // + *RawData = (VOID*)((UINT8 *)File + FvBufGetFfsHeaderSize (File)); + *RawDataSize = FvBufGetFfsFileSize (File) - FvBufGetFfsHeaderSize (File); + return EFI_SUCCESS; + } + + // + // Within the file, we now need to find the EFI_SECTION_RAW section. + // + Status = FvBufFindSectionByType (File, EFI_SECTION_RAW, (VOID **)&Section); + if (EFI_ERROR (Status)) { + return Status; + } + + *RawData = (VOID*)((UINT8 *)Section + FvBufGetSecHdrLen(Section)); + *RawDataSize = + FvBufGetSecFileLen (Section) - FvBufGetSecHdrLen(Section); + + return EFI_SUCCESS; + +} + +/** + Packages up a FFS file containing the input raw data. + + The file created will have a type of EFI_FV_FILETYPE_FREEFORM, and will + contain one EFI_FV_FILETYPE_RAW section. + + @param RawData Pointer to the raw data to be packed + @param RawDataSize Size of the raw data to be packed + @param FfsFile Address of the packaged FFS file. + Note: The called must deallocate this memory! + + @return EFI_STATUS +**/ +EFI_STATUS +FvBufPackageFreeformRawFile ( + IN EFI_GUID* Filename, + IN VOID* RawData, + IN UINTN RawDataSize, + OUT VOID** FfsFile + ) +{ + EFI_FFS_FILE_HEADER* NewFile; + UINT32 NewFileSize; + EFI_RAW_SECTION* NewSection; + UINT32 NewSectionSize; + UINT32 FfsHdrLen; + UINT32 SecHdrLen; + + // + // The section size is the DataSize + the size of the section header + // + NewSectionSize = (UINT32)sizeof (EFI_RAW_SECTION) + (UINT32)RawDataSize; + SecHdrLen = sizeof (EFI_RAW_SECTION); + if (NewSectionSize >= MAX_SECTION_SIZE) { + NewSectionSize = (UINT32)sizeof (EFI_RAW_SECTION2) + (UINT32)RawDataSize; + SecHdrLen = sizeof (EFI_RAW_SECTION2); + } + + // + // The file size is the size of the file header + the section size + // + NewFileSize = sizeof (EFI_FFS_FILE_HEADER) + NewSectionSize; + FfsHdrLen = sizeof (EFI_FFS_FILE_HEADER); + if (NewFileSize >= MAX_FFS_SIZE) { + NewFileSize = sizeof (EFI_FFS_FILE_HEADER2) + NewSectionSize; + FfsHdrLen = sizeof (EFI_FFS_FILE_HEADER2); + } + + // + // Try to allocate a buffer to build the new FFS file in + // + NewFile = CommonLibBinderAllocate (NewFileSize); + if (NewFile == NULL) { + return EFI_OUT_OF_RESOURCES; + } + CommonLibBinderSetMem (NewFile, NewFileSize, 0); + + // + // The NewSection follow right after the FFS file header + // + NewSection = (EFI_RAW_SECTION*)((UINT8*)NewFile + FfsHdrLen); + if (NewSectionSize >= MAX_SECTION_SIZE) { + FvBufCompact3ByteSize (NewSection->Size, 0xffffff); + ((EFI_RAW_SECTION2 *)NewSection)->ExtendedSize = NewSectionSize; + } else { + FvBufCompact3ByteSize (NewSection->Size, NewSectionSize); + } + NewSection->Type = EFI_SECTION_RAW; + + // + // Copy the actual file data into the buffer + // + CommonLibBinderCopyMem ((UINT8 *)NewSection + SecHdrLen, RawData, RawDataSize); + + // + // Initialize the FFS file header + // + CommonLibBinderCopyMem (&NewFile->Name, Filename, sizeof (EFI_GUID)); + NewFile->Attributes = 0; + if (NewFileSize >= MAX_FFS_SIZE) { + FvBufCompact3ByteSize (NewFile->Size, 0x0); + ((EFI_FFS_FILE_HEADER2 *)NewFile)->ExtendedSize = NewFileSize; + NewFile->Attributes |= FFS_ATTRIB_LARGE_FILE; + } else { + FvBufCompact3ByteSize (NewFile->Size, NewFileSize); + } + NewFile->Type = EFI_FV_FILETYPE_FREEFORM; + NewFile->IntegrityCheck.Checksum.Header = + FvBufCalculateChecksum8 ((UINT8*)NewFile, FfsHdrLen); + NewFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; + NewFile->State = (UINT8)~( EFI_FILE_HEADER_CONSTRUCTION | + EFI_FILE_HEADER_VALID | + EFI_FILE_DATA_VALID + ); + + *FfsFile = NewFile; + + return EFI_SUCCESS; +} + +/** + Iterates through the sections contained within a given array of sections + + @param SectionsStart Address of the start of the FFS sections array + @param TotalSectionsSize Total size of all the sections + @param Key Should be 0 to get the first section. After that, it should be + passed back in without modifying its contents to retrieve + subsequent files. + @param Section Output section pointer + (Section == NULL) -> invalid parameter + otherwise -> *Section will be update to the location of the file + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND + @retval EFI_VOLUME_CORRUPTED +**/ +EFI_STATUS +FvBufFindNextSection ( + IN VOID *SectionsStart, + IN UINTN TotalSectionsSize, + IN OUT UINTN *Key, + OUT VOID **Section + ) +{ + EFI_COMMON_SECTION_HEADER *sectionHdr; + UINTN sectionSize; + + *Key = (UINTN)ALIGN_POINTER (*Key, 4); // Sections are DWORD aligned + + if ((*Key + sizeof (*sectionHdr)) > TotalSectionsSize) { + return EFI_NOT_FOUND; + } + + sectionHdr = (EFI_COMMON_SECTION_HEADER*)((UINT8*)SectionsStart + *Key); + sectionSize = FvBufGetSecFileLen (sectionHdr); + + if (sectionSize < sizeof (EFI_COMMON_SECTION_HEADER)) { + return EFI_NOT_FOUND; + } + + if ((*Key + sectionSize) > TotalSectionsSize) { + return EFI_NOT_FOUND; + } + + *Section = (UINT8*)sectionHdr; + *Key = *Key + sectionSize; + return EFI_SUCCESS; + +} + +/** + Searches the FFS file and counts the number of sections found. + The sections are NOT recursed. + + @param FfsFile Address of the FFS file in memory + @param Count The location to store the section count in + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND + @retval EFI_VOLUME_CORRUPTED +**/ +EFI_STATUS +FvBufCountSections ( + IN VOID* FfsFile, + IN UINTN* Count + ) +{ + EFI_STATUS Status; + UINTN Key; + VOID* SectionStart; + UINTN TotalSectionsSize; + EFI_COMMON_SECTION_HEADER* NextSection; + + SectionStart = (VOID*)((UINTN)FfsFile + FvBufGetFfsHeaderSize(FfsFile)); + TotalSectionsSize = + FvBufGetFfsFileSize ((EFI_FFS_FILE_HEADER*)FfsFile) - + FvBufGetFfsHeaderSize(FfsFile); + Key = 0; + *Count = 0; + while (TRUE) { + Status = FvBufFindNextSection ( + SectionStart, + TotalSectionsSize, + &Key, + (VOID **)&NextSection + ); + if (Status == EFI_NOT_FOUND) { + return EFI_SUCCESS; + } else if (EFI_ERROR (Status)) { + return Status; + } + + // + // Increment the section counter + // + *Count += 1; + + } + + return EFI_NOT_FOUND; +} + +/** + Searches the FFS file for a section by its type + + @param FfsFile Address of the FFS file in memory + @param Type FFS FILE section type to search for + @param Section Output section pointer + (Section == NULL) -> Only determine if the section exists, based on return + value from the function call. + otherwise -> *Section will be update to the location of the file + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND + @retval EFI_VOLUME_CORRUPTED +**/ +EFI_STATUS +FvBufFindSectionByType ( + IN VOID *FfsFile, + IN UINT8 Type, + OUT VOID **Section + ) +{ + EFI_STATUS Status; + UINTN Key; + VOID* SectionStart; + UINTN TotalSectionsSize; + EFI_COMMON_SECTION_HEADER* NextSection; + + SectionStart = (VOID*)((UINTN)FfsFile + FvBufGetFfsHeaderSize(FfsFile)); + TotalSectionsSize = + FvBufGetFfsFileSize ((EFI_FFS_FILE_HEADER*)FfsFile) - + FvBufGetFfsHeaderSize(FfsFile); + Key = 0; + while (TRUE) { + Status = FvBufFindNextSection ( + SectionStart, + TotalSectionsSize, + &Key, + (VOID **)&NextSection + ); + if (EFI_ERROR (Status)) { + return Status; + } + + if (Type == NextSection->Type) { + if (Section != NULL) { + *Section = NextSection; + } + return EFI_SUCCESS; + } + } + + return EFI_NOT_FOUND; +} + +/** + Shrinks a firmware volume (in place) to provide a minimal FV. + + BUGBUG: Does not handle the case where the firmware volume has a + VTF (Volume Top File). The VTF will not be moved to the + end of the extended FV. + + @param Fv Firmware volume. + + @retval EFI_SUCCESS +**/ +EFI_STATUS +FvBufShrinkWrap ( + IN VOID *Fv + ) +{ + EFI_STATUS Status; + UINTN OldSize; + UINT32 BlockCount; + UINT32 NewBlockSize = 128; + UINTN Key; + EFI_FFS_FILE_HEADER* FileIt; + VOID* EndOfLastFile; + + EFI_FIRMWARE_VOLUME_HEADER* FvHdr; + + Status = FvBufGetSize (Fv, &OldSize); + if (EFI_ERROR (Status)) { + return Status; + } + + Status = FvBufUnifyBlockSizes (Fv, NewBlockSize); + if (EFI_ERROR (Status)) { + return Status; + } + + // + // Locate the block map in the fv header + // + FvHdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + + // + // Find the end of the last file + // + Key = 0; + EndOfLastFile = (UINT8*)FvHdr + FvHdr->FvLength; + while (!EFI_ERROR (FvBufFindNextFile (Fv, &Key, (VOID **)&FileIt))) { + EndOfLastFile = + (VOID*)((UINT8*)FileIt + FvBufGetFfsFileSize (FileIt)); + } + + // + // Set the BlockCount to have the minimal number of blocks for the Fv. + // + BlockCount = (UINT32)((UINTN)EndOfLastFile - (UINTN)Fv); + BlockCount = BlockCount + NewBlockSize - 1; + BlockCount = BlockCount / NewBlockSize; + + // + // Adjust the block count to shrink the Fv in place. + // + FvHdr->BlockMap[0].NumBlocks = BlockCount; + FvHdr->FvLength = BlockCount * NewBlockSize; + + // + // Update the FV header checksum + // + FvBufChecksumHeader (Fv); + + return EFI_SUCCESS; + +} + +/** + Searches the FFS file for a section by its type + + @param Fv Address of the Fv in memory + @param BlockSize The size of the blocks to convert the Fv to. If the total size + of the Fv is not evenly divisible by this size, then + EFI_INVALID_PARAMETER will be returned. + + @retval EFI_SUCCESS + @retval EFI_NOT_FOUND + @retval EFI_VOLUME_CORRUPTED +**/ +EFI_STATUS +FvBufUnifyBlockSizes ( + IN OUT VOID *Fv, + IN UINTN BlockSize + ) +{ + EFI_FIRMWARE_VOLUME_HEADER *hdr = (EFI_FIRMWARE_VOLUME_HEADER*)Fv; + EFI_FV_BLOCK_MAP_ENTRY *blk = hdr->BlockMap; + UINT32 Size; + + Size = 0; + + // + // Scan through the block map list, performing error checking, and adding + // up the total Fv size. + // + while( blk->Length != 0 || + blk->NumBlocks != 0 + ) { + Size = Size + (blk->Length * blk->NumBlocks); + blk++; + if ((UINT8*)blk > ((UINT8*)hdr + hdr->HeaderLength)) { + return EFI_VOLUME_CORRUPTED; + } + } + + // + // Make sure that the Fv size is a multiple of the new block size. + // + if ((Size % BlockSize) != 0) { + return EFI_INVALID_PARAMETER; + } + + // + // Zero out the entire block map. + // + CommonLibBinderSetMem ( + &hdr->BlockMap, + (UINTN)blk - (UINTN)&hdr->BlockMap, + 0 + ); + + // + // Write out the single block map entry. + // + hdr->BlockMap[0].Length = (UINT32)BlockSize; + hdr->BlockMap[0].NumBlocks = Size / (UINT32)BlockSize; + + return EFI_SUCCESS; +} + +/** + This function calculates the UINT16 sum for the requested region. + + @param Buffer Pointer to buffer containing byte data of component. + @param Size Size of the buffer + + @return The 16 bit checksum +**/ +STATIC +UINT16 +FvBufCalculateSum16 ( + IN UINT16 *Buffer, + IN UINTN Size + ) +{ + UINTN Index; + UINT16 Sum; + + Sum = 0; + + // + // Perform the word sum for buffer + // + for (Index = 0; Index < Size; Index++) { + Sum = (UINT16) (Sum + Buffer[Index]); + } + + return (UINT16) Sum; +} + +/** + This function calculates the value needed for a valid UINT16 checksum + + @param Buffer Pointer to buffer containing byte data of component. + @param Size Size of the buffer + + @return The 16 bit checksum value needed. +**/ +STATIC +UINT16 +FvBufCalculateChecksum16 ( + IN UINT16 *Buffer, + IN UINTN Size + ) +{ + return (UINT16)(0x10000 - FvBufCalculateSum16 (Buffer, Size)); +} + +/** + This function calculates the UINT8 sum for the requested region. + + @param Buffer Pointer to buffer containing byte data of component. + @param Size Size of the buffer + + @return The 8 bit checksum value needed. +**/ +STATIC +UINT8 +FvBufCalculateSum8 ( + IN UINT8 *Buffer, + IN UINTN Size + ) +{ + UINTN Index; + UINT8 Sum; + + Sum = 0; + + // + // Perform the byte sum for buffer + // + for (Index = 0; Index < Size; Index++) { + Sum = (UINT8) (Sum + Buffer[Index]); + } + + return Sum; +} + +/** + This function calculates the value needed for a valid UINT8 checksum + + @param Buffer Pointer to buffer containing byte data of component. + @param Size Size of the buffer + + @return The 8 bit checksum value needed. +**/ +STATIC +UINT8 +FvBufCalculateChecksum8 ( + IN UINT8 *Buffer, + IN UINTN Size + ) +{ + return (UINT8)(0x100 - FvBufCalculateSum8 (Buffer, Size)); +} + + diff --git a/BaseTools/Source/C/Common/FirmwareVolumeBufferLib.h b/BaseTools/Source/C/Common/FirmwareVolumeBufferLib.h index 6b1caba993..6ba9e80e0c 100644 --- a/BaseTools/Source/C/Common/FirmwareVolumeBufferLib.h +++ b/BaseTools/Source/C/Common/FirmwareVolumeBufferLib.h @@ -1,163 +1,163 @@ -/** @file
-EFI Firmware Volume routines which work on a Fv image in buffers.
-
-Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef FirmwareVolumeBuffer_h_INCLUDED
-#define FirmwareVolumeBuffer_h_INCLUDED
-
-#include "Common/UefiBaseTypes.h"
-#include "Common/PiFirmwareFile.h"
-#include "Common/PiFirmwareVolume.h"
-
-EFI_STATUS
-FvBufAddFile (
- IN OUT VOID *Fv,
- IN VOID *File
- );
-
-EFI_STATUS
-FvBufAddFileWithExtend (
- IN OUT VOID **Fv,
- IN VOID *File
- );
-
-EFI_STATUS
-FvBufAddVtfFile (
- IN OUT VOID *Fv,
- IN VOID *File
- );
-
-EFI_STATUS
-FvBufChecksumFile (
- IN OUT VOID *FfsFile
- );
-
-EFI_STATUS
-FvBufChecksumHeader (
- IN OUT VOID *Fv
- );
-
-EFI_STATUS
-FvBufClearAllFiles (
- IN OUT VOID *Fv
- );
-
-VOID
-FvBufCompact3ByteSize (
- OUT VOID* SizeDest,
- IN UINT32 Size
- );
-
-EFI_STATUS
-FvBufCountSections (
- IN VOID* FfsFile,
- IN UINTN* Count
- );
-
-EFI_STATUS
-FvBufDuplicate (
- IN VOID *SourceFv,
- IN OUT VOID **DestinationFv
- );
-
-UINT32
-FvBufExpand3ByteSize (
- IN VOID* Size
- );
-
-UINT32
-FvBufGetFfsFileSize (
- IN EFI_FFS_FILE_HEADER *Ffs
- );
-
-UINT32
-FvBufGetFfsHeaderSize (
- IN EFI_FFS_FILE_HEADER *Ffs
- );
-
-EFI_STATUS
-FvBufExtend (
- IN VOID **Fv,
- IN UINTN Size
- );
-
-EFI_STATUS
-FvBufFindFileByName (
- IN VOID *Fv,
- IN EFI_GUID *Name,
- OUT VOID **File
- );
-
-EFI_STATUS
-FvBufFindFileByType (
- IN VOID *Fv,
- IN EFI_FV_FILETYPE Type,
- OUT VOID **File
- );
-
-EFI_STATUS
-FvBufFindNextFile (
- IN VOID *Fv,
- IN OUT UINTN *Key,
- OUT VOID **File
- );
-
-EFI_STATUS
-FvBufFindNextSection (
- IN VOID *SectionsStart,
- IN UINTN TotalSectionsSize,
- IN OUT UINTN *Key,
- OUT VOID **Section
- );
-
-EFI_STATUS
-FvBufFindSectionByType (
- IN VOID *FfsFile,
- IN UINT8 Type,
- OUT VOID **Section
- );
-
-EFI_STATUS
-FvBufGetFileRawData (
- IN VOID* FfsFile,
- OUT VOID** RawData,
- OUT UINTN* RawDataSize
- );
-
-EFI_STATUS
-FvBufGetSize (
- IN VOID *Fv,
- OUT UINTN *Size
- );
-
-EFI_STATUS
-FvBufPackageFreeformRawFile (
- IN EFI_GUID* Filename,
- IN VOID* RawData,
- IN UINTN RawDataSize,
- OUT VOID** FfsFile
- );
-
-EFI_STATUS
-FvBufRemoveFile (
- IN OUT VOID *Fv,
- IN EFI_GUID *Name
- );
-
-EFI_STATUS
-FvBufUnifyBlockSizes (
- IN OUT VOID *Fv,
- IN UINTN BlockSize
- );
-
-EFI_STATUS
-FvBufShrinkWrap (
- IN VOID *Fv
- );
-
-#endif // #ifndef FirmwareVolumeBuffer_h_INCLUDED
-
+/** @file +EFI Firmware Volume routines which work on a Fv image in buffers. + +Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef FirmwareVolumeBuffer_h_INCLUDED +#define FirmwareVolumeBuffer_h_INCLUDED + +#include "Common/UefiBaseTypes.h" +#include "Common/PiFirmwareFile.h" +#include "Common/PiFirmwareVolume.h" + +EFI_STATUS +FvBufAddFile ( + IN OUT VOID *Fv, + IN VOID *File + ); + +EFI_STATUS +FvBufAddFileWithExtend ( + IN OUT VOID **Fv, + IN VOID *File + ); + +EFI_STATUS +FvBufAddVtfFile ( + IN OUT VOID *Fv, + IN VOID *File + ); + +EFI_STATUS +FvBufChecksumFile ( + IN OUT VOID *FfsFile + ); + +EFI_STATUS +FvBufChecksumHeader ( + IN OUT VOID *Fv + ); + +EFI_STATUS +FvBufClearAllFiles ( + IN OUT VOID *Fv + ); + +VOID +FvBufCompact3ByteSize ( + OUT VOID* SizeDest, + IN UINT32 Size + ); + +EFI_STATUS +FvBufCountSections ( + IN VOID* FfsFile, + IN UINTN* Count + ); + +EFI_STATUS +FvBufDuplicate ( + IN VOID *SourceFv, + IN OUT VOID **DestinationFv + ); + +UINT32 +FvBufExpand3ByteSize ( + IN VOID* Size + ); + +UINT32 +FvBufGetFfsFileSize ( + IN EFI_FFS_FILE_HEADER *Ffs + ); + +UINT32 +FvBufGetFfsHeaderSize ( + IN EFI_FFS_FILE_HEADER *Ffs + ); + +EFI_STATUS +FvBufExtend ( + IN VOID **Fv, + IN UINTN Size + ); + +EFI_STATUS +FvBufFindFileByName ( + IN VOID *Fv, + IN EFI_GUID *Name, + OUT VOID **File + ); + +EFI_STATUS +FvBufFindFileByType ( + IN VOID *Fv, + IN EFI_FV_FILETYPE Type, + OUT VOID **File + ); + +EFI_STATUS +FvBufFindNextFile ( + IN VOID *Fv, + IN OUT UINTN *Key, + OUT VOID **File + ); + +EFI_STATUS +FvBufFindNextSection ( + IN VOID *SectionsStart, + IN UINTN TotalSectionsSize, + IN OUT UINTN *Key, + OUT VOID **Section + ); + +EFI_STATUS +FvBufFindSectionByType ( + IN VOID *FfsFile, + IN UINT8 Type, + OUT VOID **Section + ); + +EFI_STATUS +FvBufGetFileRawData ( + IN VOID* FfsFile, + OUT VOID** RawData, + OUT UINTN* RawDataSize + ); + +EFI_STATUS +FvBufGetSize ( + IN VOID *Fv, + OUT UINTN *Size + ); + +EFI_STATUS +FvBufPackageFreeformRawFile ( + IN EFI_GUID* Filename, + IN VOID* RawData, + IN UINTN RawDataSize, + OUT VOID** FfsFile + ); + +EFI_STATUS +FvBufRemoveFile ( + IN OUT VOID *Fv, + IN EFI_GUID *Name + ); + +EFI_STATUS +FvBufUnifyBlockSizes ( + IN OUT VOID *Fv, + IN UINTN BlockSize + ); + +EFI_STATUS +FvBufShrinkWrap ( + IN VOID *Fv + ); + +#endif // #ifndef FirmwareVolumeBuffer_h_INCLUDED + diff --git a/BaseTools/Source/C/Common/FvLib.c b/BaseTools/Source/C/Common/FvLib.c index 37631f470f..2b1b77469c 100644 --- a/BaseTools/Source/C/Common/FvLib.c +++ b/BaseTools/Source/C/Common/FvLib.c @@ -1,828 +1,828 @@ -/** @file
-These functions assist in parsing and manipulating a Firmware Volume.
-
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-//
-// Include files
-//
-#include "FvLib.h"
-#include "CommonLib.h"
-#include "EfiUtilityMsgs.h"
-
-//
-// Module global variables
-//
-EFI_FIRMWARE_VOLUME_HEADER *mFvHeader = NULL;
-UINT32 mFvLength = 0;
-
-//
-// External function implementations
-//
-
-/**
- This initializes the FV lib with a pointer to the FV and length. It does not
- verify the FV in any way.
-
- @param Fv Buffer containing the FV.
- @param FvLength Length of the FV
-
- @retval EFI_SUCCESS Function Completed successfully.
- @retval EFI_INVALID_PARAMETER A required parameter was NULL.
-**/
-EFI_STATUS
-InitializeFvLib (
- IN VOID *Fv,
- IN UINT32 FvLength
- )
-{
- //
- // Verify input arguments
- //
- if (Fv == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- mFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) Fv;
- mFvLength = FvLength;
-
- return EFI_SUCCESS;
-}
-
-/**
- This function returns a pointer to the current FV and the size.
-
- @param FvHeader Pointer to the FV buffer.
- @param FvLength Length of the FV
-
- @retval EFI_SUCCESS Function Completed successfully.
- @retval EFI_INVALID_PARAMETER A required parameter was NULL.
- @retvalEFI_ABORTED The library needs to be initialized.
-**/
-EFI_STATUS
-GetFvHeader (
- OUT EFI_FIRMWARE_VOLUME_HEADER **FvHeader,
- OUT UINT32 *FvLength
- )
-{
- //
- // Verify library has been initialized.
- //
- if (mFvHeader == NULL || mFvLength == 0) {
- return EFI_ABORTED;
- }
- //
- // Verify input arguments
- //
- if (FvHeader == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- *FvHeader = mFvHeader;
- *FvLength = mFvLength;
- return EFI_SUCCESS;
-}
-
-/**
- This function returns the next file. If the current file is NULL, it returns
- the first file in the FV. If the function returns EFI_SUCCESS and the file
- pointer is NULL, then there are no more files in the FV.
-
- @param CurrentFile Pointer to the current file, must be within the current FV.
- @param NextFile Pointer to the next file in the FV.
-
- @retval EFI_SUCCESS Function completed successfully.
- @retval EFI_INVALID_PARAMETER A required parameter was NULL or is out of range.
- @retval EFI_ABORTED The library needs to be initialized.
-**/
-EFI_STATUS
-GetNextFile (
- IN EFI_FFS_FILE_HEADER *CurrentFile,
- OUT EFI_FFS_FILE_HEADER **NextFile
- )
-{
- EFI_STATUS Status;
-
- //
- // Verify library has been initialized.
- //
- if (mFvHeader == NULL || mFvLength == 0) {
- return EFI_ABORTED;
- }
- //
- // Verify input arguments
- //
- if (NextFile == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Verify FV header
- //
- Status = VerifyFv (mFvHeader);
- if (EFI_ERROR (Status)) {
- return EFI_ABORTED;
- }
- //
- // Get first file
- //
- if (CurrentFile == NULL) {
- CurrentFile = (EFI_FFS_FILE_HEADER *) ((UINTN) mFvHeader + mFvHeader->HeaderLength);
-
- //
- // Verify file is valid
- //
- Status = VerifyFfsFile (CurrentFile);
- if (EFI_ERROR (Status)) {
- //
- // no files in this FV
- //
- *NextFile = NULL;
- return EFI_SUCCESS;
- } else {
- //
- // Verify file is in this FV.
- //
- if ((UINTN) CurrentFile + GetFfsFileLength(CurrentFile) > (UINTN) mFvHeader + mFvLength) {
- *NextFile = NULL;
- return EFI_SUCCESS;
- }
-
- *NextFile = CurrentFile;
- return EFI_SUCCESS;
- }
- }
- //
- // Verify current file is in range
- //
- if (((UINTN) CurrentFile < (UINTN) mFvHeader + mFvHeader->HeaderLength) ||
- ((UINTN) CurrentFile + GetFfsFileLength(CurrentFile) > (UINTN) mFvHeader + mFvLength)
- ) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Get next file, compensate for 8 byte alignment if necessary.
- //
- *NextFile = (EFI_FFS_FILE_HEADER *) ((((UINTN) CurrentFile - (UINTN) mFvHeader + GetFfsFileLength(CurrentFile) + 0x07) & (~(UINTN) 7)) + (UINT8 *) mFvHeader);
-
- //
- // Verify file is in this FV.
- //
- if (((UINTN) *NextFile + GetFfsHeaderLength(*NextFile) >= (UINTN) mFvHeader + mFvLength) ||
- ((UINTN) *NextFile + GetFfsFileLength (*NextFile) > (UINTN) mFvHeader + mFvLength)
- ) {
- *NextFile = NULL;
- return EFI_SUCCESS;
- }
- //
- // Verify file is valid
- //
- Status = VerifyFfsFile (*NextFile);
- if (EFI_ERROR (Status)) {
- //
- // no more files in this FV
- //
- *NextFile = NULL;
- return EFI_SUCCESS;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Find a file by name. The function will return NULL if the file is not found.
-
- @param FileName The GUID file name of the file to search for.
- @param File Return pointer. In the case of an error, contents are undefined.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_ABORTED An error was encountered.
- @retval EFI_INVALID_PARAMETER One of the parameters was NULL.
-**/
-EFI_STATUS
-GetFileByName (
- IN EFI_GUID *FileName,
- OUT EFI_FFS_FILE_HEADER **File
- )
-{
- EFI_FFS_FILE_HEADER *CurrentFile;
- EFI_STATUS Status;
- CHAR8 FileGuidString[80];
-
- //
- // Verify library has been initialized.
- //
- if (mFvHeader == NULL || mFvLength == 0) {
- return EFI_ABORTED;
- }
- //
- // Verify input parameters
- //
- if (FileName == NULL || File == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // File Guid String Name
- //
- PrintGuidToBuffer (FileName, (UINT8 *)FileGuidString, sizeof (FileGuidString), TRUE);
- //
- // Verify FV header
- //
- Status = VerifyFv (mFvHeader);
- if (EFI_ERROR (Status)) {
- return EFI_ABORTED;
- }
- //
- // Get the first file
- //
- Status = GetNextFile (NULL, &CurrentFile);
- if (EFI_ERROR (Status)) {
- Error (NULL, 0, 0003, "error parsing FV image", "FFS file with Guid %s can't be found", FileGuidString);
- return EFI_ABORTED;
- }
- //
- // Loop as long as we have a valid file
- //
- while (CurrentFile) {
- if (!CompareGuid (&CurrentFile->Name, FileName)) {
- *File = CurrentFile;
- return EFI_SUCCESS;
- }
-
- Status = GetNextFile (CurrentFile, &CurrentFile);
- if (EFI_ERROR (Status)) {
- Error (NULL, 0, 0003, "error parsing FV image", "FFS file with Guid %s can't be found", FileGuidString);
- return EFI_ABORTED;
- }
- }
- //
- // File not found in this FV.
- //
- *File = NULL;
- return EFI_SUCCESS;
-}
-
-/**
- Find a file by type and instance. An instance of 1 is the first instance.
- The function will return NULL if a matching file cannot be found.
- File type EFI_FV_FILETYPE_ALL means any file type is valid.
-
- @param FileType Type of file to search for.
- @param Instance Instance of the file type to return.
- @param File Return pointer. In the case of an error, contents are undefined.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_ABORTED An error was encountered.
- @retval EFI_INVALID_PARAMETER One of the parameters was NULL.
-**/
-EFI_STATUS
-GetFileByType (
- IN EFI_FV_FILETYPE FileType,
- IN UINTN Instance,
- OUT EFI_FFS_FILE_HEADER **File
- )
-{
- EFI_FFS_FILE_HEADER *CurrentFile;
- EFI_STATUS Status;
- UINTN FileCount;
-
- //
- // Verify library has been initialized.
- //
- if (mFvHeader == NULL || mFvLength == 0) {
- return EFI_ABORTED;
- }
- //
- // Verify input parameters
- //
- if (File == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Verify FV header
- //
- Status = VerifyFv (mFvHeader);
- if (EFI_ERROR (Status)) {
- return EFI_ABORTED;
- }
- //
- // Initialize the number of matching files found.
- //
- FileCount = 0;
-
- //
- // Get the first file
- //
- Status = GetNextFile (NULL, &CurrentFile);
- if (EFI_ERROR (Status)) {
- Error (NULL, 0, 0003, "error parsing FV image", "FFS file with FileType 0x%x can't be found", FileType);
- return EFI_ABORTED;
- }
- //
- // Loop as long as we have a valid file
- //
- while (CurrentFile) {
- if (FileType == EFI_FV_FILETYPE_ALL || CurrentFile->Type == FileType) {
- FileCount++;
- }
-
- if (FileCount == Instance) {
- *File = CurrentFile;
- return EFI_SUCCESS;
- }
-
- Status = GetNextFile (CurrentFile, &CurrentFile);
- if (EFI_ERROR (Status)) {
- Error (NULL, 0, 0003, "error parsing FV image", "FFS file with FileType 0x%x can't be found", FileType);
- return EFI_ABORTED;
- }
- }
-
- *File = NULL;
- return EFI_SUCCESS;
-}
-
-/**
- Helper function to search a sequence of sections from the section pointed
- by FirstSection to SearchEnd for the Instance-th section of type SectionType.
- The current counter is saved in StartIndex and when the section is found, it's
- saved in Section. GUID-defined sections, if special processing is not required,
- are searched recursively in a depth-first manner.
-
- @param FirstSection The first section to start searching from.
- @param SearchEnd The end address to stop search.
- @param SectionType The type of section to search.
- @param StartIndex The current counter is saved.
- @param Instance The requested n-th section number.
- @param Section The found section returned.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_NOT_FOUND The section is not found.
-**/
-EFI_STATUS
-SearchSectionByType (
- IN EFI_FILE_SECTION_POINTER FirstSection,
- IN UINT8 *SearchEnd,
- IN EFI_SECTION_TYPE SectionType,
- IN OUT UINTN *StartIndex,
- IN UINTN Instance,
- OUT EFI_FILE_SECTION_POINTER *Section
- )
-{
- EFI_FILE_SECTION_POINTER CurrentSection;
- EFI_FILE_SECTION_POINTER InnerSection;
- EFI_STATUS Status;
- UINTN SectionSize;
- UINT16 GuidSecAttr;
- UINT16 GuidDataOffset;
-
- GuidSecAttr = 0;
- GuidDataOffset = 0;
- CurrentSection = FirstSection;
-
- while ((UINTN) CurrentSection.CommonHeader < (UINTN) SearchEnd) {
- if (CurrentSection.CommonHeader->Type == SectionType) {
- (*StartIndex)++;
- }
-
- if (*StartIndex == Instance) {
- *Section = CurrentSection;
- return EFI_SUCCESS;
- }
- //
- // If the requesting section is not GUID-defined and
- // we find a GUID-defined section that doesn't need
- // special processing, go ahead to search the requesting
- // section inside the GUID-defined section.
- //
- if (CurrentSection.CommonHeader->Type == EFI_SECTION_GUID_DEFINED) {
- if (GetLength(CurrentSection.CommonHeader->Size) == 0xffffff) {
- GuidSecAttr = CurrentSection.GuidDefinedSection2->Attributes;
- GuidDataOffset = CurrentSection.GuidDefinedSection2->DataOffset;
- } else {
- GuidSecAttr = CurrentSection.GuidDefinedSection->Attributes;
- GuidDataOffset = CurrentSection.GuidDefinedSection->DataOffset;
- }
- }
- if (SectionType != EFI_SECTION_GUID_DEFINED &&
- CurrentSection.CommonHeader->Type == EFI_SECTION_GUID_DEFINED &&
- !(GuidSecAttr & EFI_GUIDED_SECTION_PROCESSING_REQUIRED)) {
- InnerSection.CommonHeader = (EFI_COMMON_SECTION_HEADER *)
- ((UINTN) CurrentSection.CommonHeader + GuidDataOffset);
- SectionSize = GetSectionFileLength(CurrentSection.CommonHeader);
- Status = SearchSectionByType (
- InnerSection,
- (UINT8 *) ((UINTN) CurrentSection.CommonHeader + SectionSize),
- SectionType,
- StartIndex,
- Instance,
- Section
- );
- if (!EFI_ERROR (Status)) {
- return EFI_SUCCESS;
- }
- }
- //
- // Find next section (including compensating for alignment issues.
- //
- CurrentSection.CommonHeader = (EFI_COMMON_SECTION_HEADER *) ((((UINTN) CurrentSection.CommonHeader) + GetSectionFileLength(CurrentSection.CommonHeader) + 0x03) & (~(UINTN) 3));
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- Find a section in a file by type and instance. An instance of 1 is the first
- instance. The function will return NULL if a matching section cannot be found.
- GUID-defined sections, if special processing is not needed, are handled in a
- depth-first manner.
-
- @param File The file to search.
- @param SectionType Type of file to search for.
- @param Instance Instance of the section to return.
- @param Section Return pointer. In the case of an error, contents are undefined.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_ABORTED An error was encountered.
- @retval EFI_INVALID_PARAMETER One of the parameters was NULL.
- @retval EFI_NOT_FOUND No found.
-**/
-EFI_STATUS
-GetSectionByType (
- IN EFI_FFS_FILE_HEADER *File,
- IN EFI_SECTION_TYPE SectionType,
- IN UINTN Instance,
- OUT EFI_FILE_SECTION_POINTER *Section
- )
-{
- EFI_FILE_SECTION_POINTER CurrentSection;
- EFI_STATUS Status;
- UINTN SectionCount;
-
- //
- // Verify input parameters
- //
- if (File == NULL || Instance == 0) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Verify FFS header
- //
- Status = VerifyFfsFile (File);
- if (EFI_ERROR (Status)) {
- Error (NULL, 0, 0006, "invalid FFS file", NULL);
- return EFI_ABORTED;
- }
- //
- // Initialize the number of matching sections found.
- //
- SectionCount = 0;
-
- //
- // Get the first section
- //
- CurrentSection.CommonHeader = (EFI_COMMON_SECTION_HEADER *) ((UINTN) File + GetFfsHeaderLength(File));
-
- //
- // Depth-first manner to find section file.
- //
- Status = SearchSectionByType (
- CurrentSection,
- (UINT8 *) ((UINTN) File + GetFfsFileLength (File)),
- SectionType,
- &SectionCount,
- Instance,
- Section
- );
-
- if (!EFI_ERROR (Status)) {
- return EFI_SUCCESS;
- } else {
- //
- // Section not found
- //
- (*Section).Code16Section = NULL;
- return EFI_NOT_FOUND;
- }
-}
-
-//
-// will not parse compressed sections
-//
-
-/**
- Verify the current pointer points to a valid FV header.
-
- @param FvHeader Pointer to an alleged FV file.
-
- @retval EFI_SUCCESS The FV header is valid.
- @retval EFI_VOLUME_CORRUPTED The FV header is not valid.
- @retval EFI_INVALID_PARAMETER A required parameter was NULL.
- @retval EFI_ABORTED Operation aborted.
-**/
-EFI_STATUS
-VerifyFv (
- IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader
- )
-{
- UINT16 Checksum;
-
- //
- // Verify input parameters
- //
- if (FvHeader == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (FvHeader->Signature != EFI_FVH_SIGNATURE) {
- Error (NULL, 0, 0006, "invalid FV header signature", NULL);
- return EFI_VOLUME_CORRUPTED;
- }
- //
- // Verify header checksum
- //
- Checksum = CalculateSum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
-
- if (Checksum != 0) {
- Error (NULL, 0, 0006, "invalid FV header checksum", NULL);
- return EFI_ABORTED;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- Verify the current pointer points to a FFS file header.
-
- @param FfsHeader Pointer to an alleged FFS file.
-
- @retval EFI_SUCCESS The Ffs header is valid.
- @retval EFI_NOT_FOUND This "file" is the beginning of free space.
- @retval EFI_VOLUME_CORRUPTED The Ffs header is not valid.
- @retval EFI_ABORTED The erase polarity is not known.
-**/
-EFI_STATUS
-VerifyFfsFile (
- IN EFI_FFS_FILE_HEADER *FfsHeader
- )
-{
- BOOLEAN ErasePolarity;
- EFI_STATUS Status;
- EFI_FFS_FILE_HEADER2 BlankHeader;
- UINT8 Checksum;
- UINT32 FileLength;
- UINT8 SavedChecksum;
- UINT8 SavedState;
- UINT8 FileGuidString[80];
- UINT32 FfsHeaderSize;
-
- //
- // Verify library has been initialized.
- //
- if (mFvHeader == NULL || mFvLength == 0) {
- return EFI_ABORTED;
- }
- //
- // Verify FV header
- //
- Status = VerifyFv (mFvHeader);
- if (EFI_ERROR (Status)) {
- return EFI_ABORTED;
- }
- //
- // Get the erase polarity.
- //
- Status = GetErasePolarity (&ErasePolarity);
- if (EFI_ERROR (Status)) {
- return EFI_ABORTED;
- }
-
- FfsHeaderSize = GetFfsHeaderLength(FfsHeader);
- //
- // Check if we have free space
- //
- if (ErasePolarity) {
- memset (&BlankHeader, -1, FfsHeaderSize);
- } else {
- memset (&BlankHeader, 0, FfsHeaderSize);
- }
-
- if (memcmp (&BlankHeader, FfsHeader, FfsHeaderSize) == 0) {
- return EFI_NOT_FOUND;
- }
- //
- // Convert the GUID to a string so we can at least report which file
- // if we find an error.
- //
- PrintGuidToBuffer (&FfsHeader->Name, FileGuidString, sizeof (FileGuidString), TRUE);
- //
- // Verify file header checksum
- //
- SavedState = FfsHeader->State;
- FfsHeader->State = 0;
- SavedChecksum = FfsHeader->IntegrityCheck.Checksum.File;
- FfsHeader->IntegrityCheck.Checksum.File = 0;
- Checksum = CalculateSum8 ((UINT8 *) FfsHeader, FfsHeaderSize);
- FfsHeader->State = SavedState;
- FfsHeader->IntegrityCheck.Checksum.File = SavedChecksum;
- if (Checksum != 0) {
- Error (NULL, 0, 0006, "invalid FFS file header checksum", "Ffs file with Guid %s", FileGuidString);
- return EFI_ABORTED;
- }
- //
- // Verify file checksum
- //
- if (FfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) {
- //
- // Verify file data checksum
- //
- FileLength = GetFfsFileLength (FfsHeader);
- Checksum = CalculateSum8 ((UINT8 *) ((UINT8 *)FfsHeader + FfsHeaderSize), FileLength - FfsHeaderSize);
- Checksum = Checksum + FfsHeader->IntegrityCheck.Checksum.File;
- if (Checksum != 0) {
- Error (NULL, 0, 0006, "invalid FFS file checksum", "Ffs file with Guid %s", FileGuidString);
- return EFI_ABORTED;
- }
- } else {
- //
- // File does not have a checksum
- // Verify contents are 0xAA as spec'd
- //
- if (FfsHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) {
- Error (NULL, 0, 0006, "invalid fixed FFS file header checksum", "Ffs file with Guid %s", FileGuidString);
- return EFI_ABORTED;
- }
- }
-
- return EFI_SUCCESS;
-}
-
-UINT32
-GetFfsHeaderLength(
- IN EFI_FFS_FILE_HEADER *FfsHeader
- )
-{
- if (FfsHeader == NULL) {
- return 0;
- }
- if (FfsHeader->Attributes & FFS_ATTRIB_LARGE_FILE) {
- return sizeof(EFI_FFS_FILE_HEADER2);
- }
- return sizeof(EFI_FFS_FILE_HEADER);
-}
-
-UINT32
-GetSectionHeaderLength(
- IN EFI_COMMON_SECTION_HEADER *SectionHeader
- )
-{
- if (SectionHeader == NULL) {
- return 0;
- }
- if (GetLength(SectionHeader->Size) == 0xffffff) {
- return sizeof(EFI_COMMON_SECTION_HEADER2);
- }
- return sizeof(EFI_COMMON_SECTION_HEADER);
-}
-
-/**
- Get FFS file length including FFS header.
-
- @param FfsHeader Pointer to EFI_FFS_FILE_HEADER.
-
- @return UINT32 Length of FFS file header.
-**/
-UINT32
-GetFfsFileLength (
- EFI_FFS_FILE_HEADER *FfsHeader
- )
-{
- if (FfsHeader == NULL) {
- return 0;
- }
- if (FfsHeader->Attributes & FFS_ATTRIB_LARGE_FILE) {
- return (UINT32) ((EFI_FFS_FILE_HEADER2 *)FfsHeader)->ExtendedSize;
- } else {
- return GetLength(FfsHeader->Size);
- }
-}
-
-UINT32
-GetSectionFileLength (
- EFI_COMMON_SECTION_HEADER *SectionHeader
- )
-{
- UINT32 Length;
- if (SectionHeader == NULL) {
- return 0;
- }
- Length = GetLength(SectionHeader->Size);
- if (Length == 0xffffff) {
- Length = ((EFI_COMMON_SECTION_HEADER2 *)SectionHeader)->ExtendedSize;
- }
- return Length;
-}
-
-/**
- Converts a three byte length value into a UINT32.
-
- @param ThreeByteLength Pointer to the first of the 3 byte length.
-
- @return UINT32 Size of the section
-**/
-UINT32
-GetLength (
- UINT8 *ThreeByteLength
- )
-{
- UINT32 Length;
-
- if (ThreeByteLength == NULL) {
- return 0;
- }
-
- Length = *((UINT32 *) ThreeByteLength);
- Length = Length & 0x00FFFFFF;
-
- return Length;
-}
-
-/**
- This function returns with the FV erase polarity. If the erase polarity
- for a bit is 1, the function return TRUE.
-
- @param ErasePolarity A pointer to the erase polarity.
-
- @retval EFI_SUCCESS The function completed successfully.
- @retval EFI_INVALID_PARAMETER One of the input parameters was invalid.
- @retval EFI_ABORTED Operation aborted.
-**/
-EFI_STATUS
-GetErasePolarity (
- OUT BOOLEAN *ErasePolarity
- )
-{
- EFI_STATUS Status;
-
- //
- // Verify library has been initialized.
- //
- if (mFvHeader == NULL || mFvLength == 0) {
- return EFI_ABORTED;
- }
- //
- // Verify FV header
- //
- Status = VerifyFv (mFvHeader);
- if (EFI_ERROR (Status)) {
- return EFI_ABORTED;
- }
- //
- // Verify input parameters.
- //
- if (ErasePolarity == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- if (mFvHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {
- *ErasePolarity = TRUE;
- } else {
- *ErasePolarity = FALSE;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- This function returns a the highest state bit in the FFS that is set.
- It in no way validate the FFS file.
-
- @param ErasePolarity The erase polarity for the file state bits.
- @param FfsHeader Pointer to a FFS file.
-
- @retval UINT8 The hightest set state of the file.
-**/
-UINT8
-GetFileState (
- IN BOOLEAN ErasePolarity,
- IN EFI_FFS_FILE_HEADER *FfsHeader
- )
-{
- UINT8 FileState;
- UINT8 HighestBit;
-
- FileState = FfsHeader->State;
-
- if (ErasePolarity) {
- FileState = (UINT8)~FileState;
- }
-
- HighestBit = 0x80;
- while (HighestBit != 0 && (HighestBit & FileState) == 0) {
- HighestBit >>= 1;
- }
-
- return HighestBit;
-}
+/** @file +These functions assist in parsing and manipulating a Firmware Volume. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +// +// Include files +// +#include "FvLib.h" +#include "CommonLib.h" +#include "EfiUtilityMsgs.h" + +// +// Module global variables +// +EFI_FIRMWARE_VOLUME_HEADER *mFvHeader = NULL; +UINT32 mFvLength = 0; + +// +// External function implementations +// + +/** + This initializes the FV lib with a pointer to the FV and length. It does not + verify the FV in any way. + + @param Fv Buffer containing the FV. + @param FvLength Length of the FV + + @retval EFI_SUCCESS Function Completed successfully. + @retval EFI_INVALID_PARAMETER A required parameter was NULL. +**/ +EFI_STATUS +InitializeFvLib ( + IN VOID *Fv, + IN UINT32 FvLength + ) +{ + // + // Verify input arguments + // + if (Fv == NULL) { + return EFI_INVALID_PARAMETER; + } + + mFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) Fv; + mFvLength = FvLength; + + return EFI_SUCCESS; +} + +/** + This function returns a pointer to the current FV and the size. + + @param FvHeader Pointer to the FV buffer. + @param FvLength Length of the FV + + @retval EFI_SUCCESS Function Completed successfully. + @retval EFI_INVALID_PARAMETER A required parameter was NULL. + @retvalEFI_ABORTED The library needs to be initialized. +**/ +EFI_STATUS +GetFvHeader ( + OUT EFI_FIRMWARE_VOLUME_HEADER **FvHeader, + OUT UINT32 *FvLength + ) +{ + // + // Verify library has been initialized. + // + if (mFvHeader == NULL || mFvLength == 0) { + return EFI_ABORTED; + } + // + // Verify input arguments + // + if (FvHeader == NULL) { + return EFI_INVALID_PARAMETER; + } + + *FvHeader = mFvHeader; + *FvLength = mFvLength; + return EFI_SUCCESS; +} + +/** + This function returns the next file. If the current file is NULL, it returns + the first file in the FV. If the function returns EFI_SUCCESS and the file + pointer is NULL, then there are no more files in the FV. + + @param CurrentFile Pointer to the current file, must be within the current FV. + @param NextFile Pointer to the next file in the FV. + + @retval EFI_SUCCESS Function completed successfully. + @retval EFI_INVALID_PARAMETER A required parameter was NULL or is out of range. + @retval EFI_ABORTED The library needs to be initialized. +**/ +EFI_STATUS +GetNextFile ( + IN EFI_FFS_FILE_HEADER *CurrentFile, + OUT EFI_FFS_FILE_HEADER **NextFile + ) +{ + EFI_STATUS Status; + + // + // Verify library has been initialized. + // + if (mFvHeader == NULL || mFvLength == 0) { + return EFI_ABORTED; + } + // + // Verify input arguments + // + if (NextFile == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Verify FV header + // + Status = VerifyFv (mFvHeader); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + // + // Get first file + // + if (CurrentFile == NULL) { + CurrentFile = (EFI_FFS_FILE_HEADER *) ((UINTN) mFvHeader + mFvHeader->HeaderLength); + + // + // Verify file is valid + // + Status = VerifyFfsFile (CurrentFile); + if (EFI_ERROR (Status)) { + // + // no files in this FV + // + *NextFile = NULL; + return EFI_SUCCESS; + } else { + // + // Verify file is in this FV. + // + if ((UINTN) CurrentFile + GetFfsFileLength(CurrentFile) > (UINTN) mFvHeader + mFvLength) { + *NextFile = NULL; + return EFI_SUCCESS; + } + + *NextFile = CurrentFile; + return EFI_SUCCESS; + } + } + // + // Verify current file is in range + // + if (((UINTN) CurrentFile < (UINTN) mFvHeader + mFvHeader->HeaderLength) || + ((UINTN) CurrentFile + GetFfsFileLength(CurrentFile) > (UINTN) mFvHeader + mFvLength) + ) { + return EFI_INVALID_PARAMETER; + } + // + // Get next file, compensate for 8 byte alignment if necessary. + // + *NextFile = (EFI_FFS_FILE_HEADER *) ((((UINTN) CurrentFile - (UINTN) mFvHeader + GetFfsFileLength(CurrentFile) + 0x07) & (~(UINTN) 7)) + (UINT8 *) mFvHeader); + + // + // Verify file is in this FV. + // + if (((UINTN) *NextFile + GetFfsHeaderLength(*NextFile) >= (UINTN) mFvHeader + mFvLength) || + ((UINTN) *NextFile + GetFfsFileLength (*NextFile) > (UINTN) mFvHeader + mFvLength) + ) { + *NextFile = NULL; + return EFI_SUCCESS; + } + // + // Verify file is valid + // + Status = VerifyFfsFile (*NextFile); + if (EFI_ERROR (Status)) { + // + // no more files in this FV + // + *NextFile = NULL; + return EFI_SUCCESS; + } + + return EFI_SUCCESS; +} + +/** + Find a file by name. The function will return NULL if the file is not found. + + @param FileName The GUID file name of the file to search for. + @param File Return pointer. In the case of an error, contents are undefined. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_ABORTED An error was encountered. + @retval EFI_INVALID_PARAMETER One of the parameters was NULL. +**/ +EFI_STATUS +GetFileByName ( + IN EFI_GUID *FileName, + OUT EFI_FFS_FILE_HEADER **File + ) +{ + EFI_FFS_FILE_HEADER *CurrentFile; + EFI_STATUS Status; + CHAR8 FileGuidString[80]; + + // + // Verify library has been initialized. + // + if (mFvHeader == NULL || mFvLength == 0) { + return EFI_ABORTED; + } + // + // Verify input parameters + // + if (FileName == NULL || File == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // File Guid String Name + // + PrintGuidToBuffer (FileName, (UINT8 *)FileGuidString, sizeof (FileGuidString), TRUE); + // + // Verify FV header + // + Status = VerifyFv (mFvHeader); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + // + // Get the first file + // + Status = GetNextFile (NULL, &CurrentFile); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0003, "error parsing FV image", "FFS file with Guid %s can't be found", FileGuidString); + return EFI_ABORTED; + } + // + // Loop as long as we have a valid file + // + while (CurrentFile) { + if (!CompareGuid (&CurrentFile->Name, FileName)) { + *File = CurrentFile; + return EFI_SUCCESS; + } + + Status = GetNextFile (CurrentFile, &CurrentFile); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0003, "error parsing FV image", "FFS file with Guid %s can't be found", FileGuidString); + return EFI_ABORTED; + } + } + // + // File not found in this FV. + // + *File = NULL; + return EFI_SUCCESS; +} + +/** + Find a file by type and instance. An instance of 1 is the first instance. + The function will return NULL if a matching file cannot be found. + File type EFI_FV_FILETYPE_ALL means any file type is valid. + + @param FileType Type of file to search for. + @param Instance Instance of the file type to return. + @param File Return pointer. In the case of an error, contents are undefined. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_ABORTED An error was encountered. + @retval EFI_INVALID_PARAMETER One of the parameters was NULL. +**/ +EFI_STATUS +GetFileByType ( + IN EFI_FV_FILETYPE FileType, + IN UINTN Instance, + OUT EFI_FFS_FILE_HEADER **File + ) +{ + EFI_FFS_FILE_HEADER *CurrentFile; + EFI_STATUS Status; + UINTN FileCount; + + // + // Verify library has been initialized. + // + if (mFvHeader == NULL || mFvLength == 0) { + return EFI_ABORTED; + } + // + // Verify input parameters + // + if (File == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Verify FV header + // + Status = VerifyFv (mFvHeader); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + // + // Initialize the number of matching files found. + // + FileCount = 0; + + // + // Get the first file + // + Status = GetNextFile (NULL, &CurrentFile); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0003, "error parsing FV image", "FFS file with FileType 0x%x can't be found", FileType); + return EFI_ABORTED; + } + // + // Loop as long as we have a valid file + // + while (CurrentFile) { + if (FileType == EFI_FV_FILETYPE_ALL || CurrentFile->Type == FileType) { + FileCount++; + } + + if (FileCount == Instance) { + *File = CurrentFile; + return EFI_SUCCESS; + } + + Status = GetNextFile (CurrentFile, &CurrentFile); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0003, "error parsing FV image", "FFS file with FileType 0x%x can't be found", FileType); + return EFI_ABORTED; + } + } + + *File = NULL; + return EFI_SUCCESS; +} + +/** + Helper function to search a sequence of sections from the section pointed + by FirstSection to SearchEnd for the Instance-th section of type SectionType. + The current counter is saved in StartIndex and when the section is found, it's + saved in Section. GUID-defined sections, if special processing is not required, + are searched recursively in a depth-first manner. + + @param FirstSection The first section to start searching from. + @param SearchEnd The end address to stop search. + @param SectionType The type of section to search. + @param StartIndex The current counter is saved. + @param Instance The requested n-th section number. + @param Section The found section returned. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_NOT_FOUND The section is not found. +**/ +EFI_STATUS +SearchSectionByType ( + IN EFI_FILE_SECTION_POINTER FirstSection, + IN UINT8 *SearchEnd, + IN EFI_SECTION_TYPE SectionType, + IN OUT UINTN *StartIndex, + IN UINTN Instance, + OUT EFI_FILE_SECTION_POINTER *Section + ) +{ + EFI_FILE_SECTION_POINTER CurrentSection; + EFI_FILE_SECTION_POINTER InnerSection; + EFI_STATUS Status; + UINTN SectionSize; + UINT16 GuidSecAttr; + UINT16 GuidDataOffset; + + GuidSecAttr = 0; + GuidDataOffset = 0; + CurrentSection = FirstSection; + + while ((UINTN) CurrentSection.CommonHeader < (UINTN) SearchEnd) { + if (CurrentSection.CommonHeader->Type == SectionType) { + (*StartIndex)++; + } + + if (*StartIndex == Instance) { + *Section = CurrentSection; + return EFI_SUCCESS; + } + // + // If the requesting section is not GUID-defined and + // we find a GUID-defined section that doesn't need + // special processing, go ahead to search the requesting + // section inside the GUID-defined section. + // + if (CurrentSection.CommonHeader->Type == EFI_SECTION_GUID_DEFINED) { + if (GetLength(CurrentSection.CommonHeader->Size) == 0xffffff) { + GuidSecAttr = CurrentSection.GuidDefinedSection2->Attributes; + GuidDataOffset = CurrentSection.GuidDefinedSection2->DataOffset; + } else { + GuidSecAttr = CurrentSection.GuidDefinedSection->Attributes; + GuidDataOffset = CurrentSection.GuidDefinedSection->DataOffset; + } + } + if (SectionType != EFI_SECTION_GUID_DEFINED && + CurrentSection.CommonHeader->Type == EFI_SECTION_GUID_DEFINED && + !(GuidSecAttr & EFI_GUIDED_SECTION_PROCESSING_REQUIRED)) { + InnerSection.CommonHeader = (EFI_COMMON_SECTION_HEADER *) + ((UINTN) CurrentSection.CommonHeader + GuidDataOffset); + SectionSize = GetSectionFileLength(CurrentSection.CommonHeader); + Status = SearchSectionByType ( + InnerSection, + (UINT8 *) ((UINTN) CurrentSection.CommonHeader + SectionSize), + SectionType, + StartIndex, + Instance, + Section + ); + if (!EFI_ERROR (Status)) { + return EFI_SUCCESS; + } + } + // + // Find next section (including compensating for alignment issues. + // + CurrentSection.CommonHeader = (EFI_COMMON_SECTION_HEADER *) ((((UINTN) CurrentSection.CommonHeader) + GetSectionFileLength(CurrentSection.CommonHeader) + 0x03) & (~(UINTN) 3)); + } + + return EFI_NOT_FOUND; +} + +/** + Find a section in a file by type and instance. An instance of 1 is the first + instance. The function will return NULL if a matching section cannot be found. + GUID-defined sections, if special processing is not needed, are handled in a + depth-first manner. + + @param File The file to search. + @param SectionType Type of file to search for. + @param Instance Instance of the section to return. + @param Section Return pointer. In the case of an error, contents are undefined. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_ABORTED An error was encountered. + @retval EFI_INVALID_PARAMETER One of the parameters was NULL. + @retval EFI_NOT_FOUND No found. +**/ +EFI_STATUS +GetSectionByType ( + IN EFI_FFS_FILE_HEADER *File, + IN EFI_SECTION_TYPE SectionType, + IN UINTN Instance, + OUT EFI_FILE_SECTION_POINTER *Section + ) +{ + EFI_FILE_SECTION_POINTER CurrentSection; + EFI_STATUS Status; + UINTN SectionCount; + + // + // Verify input parameters + // + if (File == NULL || Instance == 0) { + return EFI_INVALID_PARAMETER; + } + // + // Verify FFS header + // + Status = VerifyFfsFile (File); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0006, "invalid FFS file", NULL); + return EFI_ABORTED; + } + // + // Initialize the number of matching sections found. + // + SectionCount = 0; + + // + // Get the first section + // + CurrentSection.CommonHeader = (EFI_COMMON_SECTION_HEADER *) ((UINTN) File + GetFfsHeaderLength(File)); + + // + // Depth-first manner to find section file. + // + Status = SearchSectionByType ( + CurrentSection, + (UINT8 *) ((UINTN) File + GetFfsFileLength (File)), + SectionType, + &SectionCount, + Instance, + Section + ); + + if (!EFI_ERROR (Status)) { + return EFI_SUCCESS; + } else { + // + // Section not found + // + (*Section).Code16Section = NULL; + return EFI_NOT_FOUND; + } +} + +// +// will not parse compressed sections +// + +/** + Verify the current pointer points to a valid FV header. + + @param FvHeader Pointer to an alleged FV file. + + @retval EFI_SUCCESS The FV header is valid. + @retval EFI_VOLUME_CORRUPTED The FV header is not valid. + @retval EFI_INVALID_PARAMETER A required parameter was NULL. + @retval EFI_ABORTED Operation aborted. +**/ +EFI_STATUS +VerifyFv ( + IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader + ) +{ + UINT16 Checksum; + + // + // Verify input parameters + // + if (FvHeader == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (FvHeader->Signature != EFI_FVH_SIGNATURE) { + Error (NULL, 0, 0006, "invalid FV header signature", NULL); + return EFI_VOLUME_CORRUPTED; + } + // + // Verify header checksum + // + Checksum = CalculateSum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16)); + + if (Checksum != 0) { + Error (NULL, 0, 0006, "invalid FV header checksum", NULL); + return EFI_ABORTED; + } + + return EFI_SUCCESS; +} + +/** + Verify the current pointer points to a FFS file header. + + @param FfsHeader Pointer to an alleged FFS file. + + @retval EFI_SUCCESS The Ffs header is valid. + @retval EFI_NOT_FOUND This "file" is the beginning of free space. + @retval EFI_VOLUME_CORRUPTED The Ffs header is not valid. + @retval EFI_ABORTED The erase polarity is not known. +**/ +EFI_STATUS +VerifyFfsFile ( + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +{ + BOOLEAN ErasePolarity; + EFI_STATUS Status; + EFI_FFS_FILE_HEADER2 BlankHeader; + UINT8 Checksum; + UINT32 FileLength; + UINT8 SavedChecksum; + UINT8 SavedState; + UINT8 FileGuidString[80]; + UINT32 FfsHeaderSize; + + // + // Verify library has been initialized. + // + if (mFvHeader == NULL || mFvLength == 0) { + return EFI_ABORTED; + } + // + // Verify FV header + // + Status = VerifyFv (mFvHeader); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + // + // Get the erase polarity. + // + Status = GetErasePolarity (&ErasePolarity); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + + FfsHeaderSize = GetFfsHeaderLength(FfsHeader); + // + // Check if we have free space + // + if (ErasePolarity) { + memset (&BlankHeader, -1, FfsHeaderSize); + } else { + memset (&BlankHeader, 0, FfsHeaderSize); + } + + if (memcmp (&BlankHeader, FfsHeader, FfsHeaderSize) == 0) { + return EFI_NOT_FOUND; + } + // + // Convert the GUID to a string so we can at least report which file + // if we find an error. + // + PrintGuidToBuffer (&FfsHeader->Name, FileGuidString, sizeof (FileGuidString), TRUE); + // + // Verify file header checksum + // + SavedState = FfsHeader->State; + FfsHeader->State = 0; + SavedChecksum = FfsHeader->IntegrityCheck.Checksum.File; + FfsHeader->IntegrityCheck.Checksum.File = 0; + Checksum = CalculateSum8 ((UINT8 *) FfsHeader, FfsHeaderSize); + FfsHeader->State = SavedState; + FfsHeader->IntegrityCheck.Checksum.File = SavedChecksum; + if (Checksum != 0) { + Error (NULL, 0, 0006, "invalid FFS file header checksum", "Ffs file with Guid %s", FileGuidString); + return EFI_ABORTED; + } + // + // Verify file checksum + // + if (FfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) { + // + // Verify file data checksum + // + FileLength = GetFfsFileLength (FfsHeader); + Checksum = CalculateSum8 ((UINT8 *) ((UINT8 *)FfsHeader + FfsHeaderSize), FileLength - FfsHeaderSize); + Checksum = Checksum + FfsHeader->IntegrityCheck.Checksum.File; + if (Checksum != 0) { + Error (NULL, 0, 0006, "invalid FFS file checksum", "Ffs file with Guid %s", FileGuidString); + return EFI_ABORTED; + } + } else { + // + // File does not have a checksum + // Verify contents are 0xAA as spec'd + // + if (FfsHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) { + Error (NULL, 0, 0006, "invalid fixed FFS file header checksum", "Ffs file with Guid %s", FileGuidString); + return EFI_ABORTED; + } + } + + return EFI_SUCCESS; +} + +UINT32 +GetFfsHeaderLength( + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +{ + if (FfsHeader == NULL) { + return 0; + } + if (FfsHeader->Attributes & FFS_ATTRIB_LARGE_FILE) { + return sizeof(EFI_FFS_FILE_HEADER2); + } + return sizeof(EFI_FFS_FILE_HEADER); +} + +UINT32 +GetSectionHeaderLength( + IN EFI_COMMON_SECTION_HEADER *SectionHeader + ) +{ + if (SectionHeader == NULL) { + return 0; + } + if (GetLength(SectionHeader->Size) == 0xffffff) { + return sizeof(EFI_COMMON_SECTION_HEADER2); + } + return sizeof(EFI_COMMON_SECTION_HEADER); +} + +/** + Get FFS file length including FFS header. + + @param FfsHeader Pointer to EFI_FFS_FILE_HEADER. + + @return UINT32 Length of FFS file header. +**/ +UINT32 +GetFfsFileLength ( + EFI_FFS_FILE_HEADER *FfsHeader + ) +{ + if (FfsHeader == NULL) { + return 0; + } + if (FfsHeader->Attributes & FFS_ATTRIB_LARGE_FILE) { + return (UINT32) ((EFI_FFS_FILE_HEADER2 *)FfsHeader)->ExtendedSize; + } else { + return GetLength(FfsHeader->Size); + } +} + +UINT32 +GetSectionFileLength ( + EFI_COMMON_SECTION_HEADER *SectionHeader + ) +{ + UINT32 Length; + if (SectionHeader == NULL) { + return 0; + } + Length = GetLength(SectionHeader->Size); + if (Length == 0xffffff) { + Length = ((EFI_COMMON_SECTION_HEADER2 *)SectionHeader)->ExtendedSize; + } + return Length; +} + +/** + Converts a three byte length value into a UINT32. + + @param ThreeByteLength Pointer to the first of the 3 byte length. + + @return UINT32 Size of the section +**/ +UINT32 +GetLength ( + UINT8 *ThreeByteLength + ) +{ + UINT32 Length; + + if (ThreeByteLength == NULL) { + return 0; + } + + Length = *((UINT32 *) ThreeByteLength); + Length = Length & 0x00FFFFFF; + + return Length; +} + +/** + This function returns with the FV erase polarity. If the erase polarity + for a bit is 1, the function return TRUE. + + @param ErasePolarity A pointer to the erase polarity. + + @retval EFI_SUCCESS The function completed successfully. + @retval EFI_INVALID_PARAMETER One of the input parameters was invalid. + @retval EFI_ABORTED Operation aborted. +**/ +EFI_STATUS +GetErasePolarity ( + OUT BOOLEAN *ErasePolarity + ) +{ + EFI_STATUS Status; + + // + // Verify library has been initialized. + // + if (mFvHeader == NULL || mFvLength == 0) { + return EFI_ABORTED; + } + // + // Verify FV header + // + Status = VerifyFv (mFvHeader); + if (EFI_ERROR (Status)) { + return EFI_ABORTED; + } + // + // Verify input parameters. + // + if (ErasePolarity == NULL) { + return EFI_INVALID_PARAMETER; + } + + if (mFvHeader->Attributes & EFI_FVB2_ERASE_POLARITY) { + *ErasePolarity = TRUE; + } else { + *ErasePolarity = FALSE; + } + + return EFI_SUCCESS; +} + +/** + This function returns a the highest state bit in the FFS that is set. + It in no way validate the FFS file. + + @param ErasePolarity The erase polarity for the file state bits. + @param FfsHeader Pointer to a FFS file. + + @retval UINT8 The hightest set state of the file. +**/ +UINT8 +GetFileState ( + IN BOOLEAN ErasePolarity, + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +{ + UINT8 FileState; + UINT8 HighestBit; + + FileState = FfsHeader->State; + + if (ErasePolarity) { + FileState = (UINT8)~FileState; + } + + HighestBit = 0x80; + while (HighestBit != 0 && (HighestBit & FileState) == 0) { + HighestBit >>= 1; + } + + return HighestBit; +} diff --git a/BaseTools/Source/C/Common/FvLib.h b/BaseTools/Source/C/Common/FvLib.h index 815df6f802..0128779e81 100644 --- a/BaseTools/Source/C/Common/FvLib.h +++ b/BaseTools/Source/C/Common/FvLib.h @@ -1,189 +1,189 @@ -/** @file
-These functions assist in parsing and manipulating a Firmware Volume.
-
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _EFI_FV_LIB_H
-#define _EFI_FV_LIB_H
-
-//
-// Include files
-//
-#include <string.h>
-
-#include <Common/UefiBaseTypes.h>
-#include <Common/PiFirmwareFile.h>
-#include <Common/PiFirmwareVolume.h>
-
-EFI_STATUS
-InitializeFvLib (
- IN VOID *Fv,
- IN UINT32 FvLength
- )
-;
-
-EFI_STATUS
-GetFvHeader (
- OUT EFI_FIRMWARE_VOLUME_HEADER **FvHeader,
- OUT UINT32 *FvLength
- )
-;
-
-EFI_STATUS
-GetNextFile (
- IN EFI_FFS_FILE_HEADER *CurrentFile,
- OUT EFI_FFS_FILE_HEADER **NextFile
- )
-;
-
-EFI_STATUS
-GetFileByName (
- IN EFI_GUID *FileName,
- OUT EFI_FFS_FILE_HEADER **File
- )
-;
-
-EFI_STATUS
-GetFileByType (
- IN EFI_FV_FILETYPE FileType,
- IN UINTN Instance,
- OUT EFI_FFS_FILE_HEADER **File
- )
-;
-
-EFI_STATUS
-GetSectionByType (
- IN EFI_FFS_FILE_HEADER *File,
- IN EFI_SECTION_TYPE SectionType,
- IN UINTN Instance,
- OUT EFI_FILE_SECTION_POINTER *Section
- )
-;
-//
-// will not parse compressed sections
-//
-EFI_STATUS
-VerifyFv (
- IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader
- )
-;
-
-EFI_STATUS
-VerifyFfsFile (
- IN EFI_FFS_FILE_HEADER *FfsHeader
- )
-;
-
-UINT32
-GetFfsFileLength (
- EFI_FFS_FILE_HEADER *FfsHeader
- )
-;
-
-UINT32
-GetSectionFileLength (
- EFI_COMMON_SECTION_HEADER *SectionHeader
- )
-;
-
-UINT32
-GetFfsHeaderLength(
- IN EFI_FFS_FILE_HEADER *FfsHeader
- )
-;
-
-UINT32
-GetSectionHeaderLength(
- IN EFI_COMMON_SECTION_HEADER *SectionHeader
- )
-;
-
-/*++
-
-Routine Description:
-
- Verify the current pointer points to a FFS file header.
-
-Arguments:
-
- FfsHeader Pointer to an alleged FFS file.
-
-Returns:
-
- EFI_SUCCESS The Ffs header is valid.
- EFI_NOT_FOUND This "file" is the beginning of free space.
- EFI_VOLUME_CORRUPTED The Ffs header is not valid.
-
---*/
-UINT32
-GetLength (
- UINT8 *ThreeByteLength
- )
-;
-
-/*++
-
-Routine Description:
-
- Converts a three byte length value into a UINT32.
-
-Arguments:
-
- ThreeByteLength Pointer to the first of the 3 byte length.
-
-Returns:
-
- UINT32 Size of the section
-
---*/
-EFI_STATUS
-GetErasePolarity (
- OUT BOOLEAN *ErasePolarity
- )
-;
-
-/*++
-
-Routine Description:
-
- This function returns with the FV erase polarity. If the erase polarity
- for a bit is 1, the function return TRUE.
-
-Arguments:
-
- ErasePolarity A pointer to the erase polarity.
-
-Returns:
-
- EFI_SUCCESS The function completed successfully.
- EFI_INVALID_PARAMETER One of the input parameters was invalid.
-
---*/
-UINT8
-GetFileState (
- IN BOOLEAN ErasePolarity,
- IN EFI_FFS_FILE_HEADER *FfsHeader
- )
-;
-
-/*++
-
-Routine Description:
-
- This function returns a the highest state bit in the FFS that is set.
- It in no way validate the FFS file.
-
-Arguments:
-
- ErasePolarity The erase polarity for the file state bits.
- FfsHeader Pointer to a FFS file.
-
-Returns:
-
- UINT8 The hightest set state of the file.
-
---*/
-#endif
+/** @file +These functions assist in parsing and manipulating a Firmware Volume. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_FV_LIB_H +#define _EFI_FV_LIB_H + +// +// Include files +// +#include <string.h> + +#include <Common/UefiBaseTypes.h> +#include <Common/PiFirmwareFile.h> +#include <Common/PiFirmwareVolume.h> + +EFI_STATUS +InitializeFvLib ( + IN VOID *Fv, + IN UINT32 FvLength + ) +; + +EFI_STATUS +GetFvHeader ( + OUT EFI_FIRMWARE_VOLUME_HEADER **FvHeader, + OUT UINT32 *FvLength + ) +; + +EFI_STATUS +GetNextFile ( + IN EFI_FFS_FILE_HEADER *CurrentFile, + OUT EFI_FFS_FILE_HEADER **NextFile + ) +; + +EFI_STATUS +GetFileByName ( + IN EFI_GUID *FileName, + OUT EFI_FFS_FILE_HEADER **File + ) +; + +EFI_STATUS +GetFileByType ( + IN EFI_FV_FILETYPE FileType, + IN UINTN Instance, + OUT EFI_FFS_FILE_HEADER **File + ) +; + +EFI_STATUS +GetSectionByType ( + IN EFI_FFS_FILE_HEADER *File, + IN EFI_SECTION_TYPE SectionType, + IN UINTN Instance, + OUT EFI_FILE_SECTION_POINTER *Section + ) +; +// +// will not parse compressed sections +// +EFI_STATUS +VerifyFv ( + IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader + ) +; + +EFI_STATUS +VerifyFfsFile ( + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +; + +UINT32 +GetFfsFileLength ( + EFI_FFS_FILE_HEADER *FfsHeader + ) +; + +UINT32 +GetSectionFileLength ( + EFI_COMMON_SECTION_HEADER *SectionHeader + ) +; + +UINT32 +GetFfsHeaderLength( + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +; + +UINT32 +GetSectionHeaderLength( + IN EFI_COMMON_SECTION_HEADER *SectionHeader + ) +; + +/*++ + +Routine Description: + + Verify the current pointer points to a FFS file header. + +Arguments: + + FfsHeader Pointer to an alleged FFS file. + +Returns: + + EFI_SUCCESS The Ffs header is valid. + EFI_NOT_FOUND This "file" is the beginning of free space. + EFI_VOLUME_CORRUPTED The Ffs header is not valid. + +--*/ +UINT32 +GetLength ( + UINT8 *ThreeByteLength + ) +; + +/*++ + +Routine Description: + + Converts a three byte length value into a UINT32. + +Arguments: + + ThreeByteLength Pointer to the first of the 3 byte length. + +Returns: + + UINT32 Size of the section + +--*/ +EFI_STATUS +GetErasePolarity ( + OUT BOOLEAN *ErasePolarity + ) +; + +/*++ + +Routine Description: + + This function returns with the FV erase polarity. If the erase polarity + for a bit is 1, the function return TRUE. + +Arguments: + + ErasePolarity A pointer to the erase polarity. + +Returns: + + EFI_SUCCESS The function completed successfully. + EFI_INVALID_PARAMETER One of the input parameters was invalid. + +--*/ +UINT8 +GetFileState ( + IN BOOLEAN ErasePolarity, + IN EFI_FFS_FILE_HEADER *FfsHeader + ) +; + +/*++ + +Routine Description: + + This function returns a the highest state bit in the FFS that is set. + It in no way validate the FFS file. + +Arguments: + + ErasePolarity The erase polarity for the file state bits. + FfsHeader Pointer to a FFS file. + +Returns: + + UINT8 The hightest set state of the file. + +--*/ +#endif diff --git a/BaseTools/Source/C/Common/GNUmakefile b/BaseTools/Source/C/Common/GNUmakefile index b3eef7460f..a2ff48f3ee 100644 --- a/BaseTools/Source/C/Common/GNUmakefile +++ b/BaseTools/Source/C/Common/GNUmakefile @@ -1,33 +1,33 @@ -## @file
-# GNU/Linux makefile for 'Common' module build.
-#
-# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-MAKEROOT ?= ..
-
-# VPATH = ..
-
-LIBNAME = Common
-
-OBJECTS = \
- BasePeCoff.o \
- BinderFuncs.o \
- CommonLib.o \
- Crc32.o \
- Decompress.o \
- EfiCompress.o \
- EfiUtilityMsgs.o \
- FirmwareVolumeBuffer.o \
- FvLib.o \
- MemoryFile.o \
- MyAlloc.o \
- OsPath.o \
- ParseGuidedSectionTools.o \
- ParseInf.o \
- PeCoffLoaderEx.o \
- SimpleFileParsing.o \
- StringFuncs.o \
- TianoCompress.o
-
-include $(MAKEROOT)/Makefiles/lib.makefile
+## @file +# GNU/Linux makefile for 'Common' module build. +# +# Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +MAKEROOT ?= .. + +# VPATH = .. + +LIBNAME = Common + +OBJECTS = \ + BasePeCoff.o \ + BinderFuncs.o \ + CommonLib.o \ + Crc32.o \ + Decompress.o \ + EfiCompress.o \ + EfiUtilityMsgs.o \ + FirmwareVolumeBuffer.o \ + FvLib.o \ + MemoryFile.o \ + MyAlloc.o \ + OsPath.o \ + ParseGuidedSectionTools.o \ + ParseInf.o \ + PeCoffLoaderEx.o \ + SimpleFileParsing.o \ + StringFuncs.o \ + TianoCompress.o + +include $(MAKEROOT)/Makefiles/lib.makefile diff --git a/BaseTools/Source/C/Common/Makefile b/BaseTools/Source/C/Common/Makefile index ec61e45c81..971025f667 100644 --- a/BaseTools/Source/C/Common/Makefile +++ b/BaseTools/Source/C/Common/Makefile @@ -1,36 +1,36 @@ -## @file
-# Windows makefile for 'Common' module build.
-#
-# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-!INCLUDE ..\Makefiles\ms.common
-
-# VPATH = ..
-
-LIBNAME = Common
-
-OBJECTS = \
- BasePeCoff.obj \
- BinderFuncs.obj \
- CommonLib.obj \
- Crc32.obj \
- Decompress.obj \
- EfiCompress.obj \
- EfiUtilityMsgs.obj \
- FirmwareVolumeBuffer.obj \
- FvLib.obj \
- MemoryFile.obj \
- MyAlloc.obj \
- OsPath.obj \
- ParseGuidedSectionTools.obj \
- ParseInf.obj \
- PeCoffLoaderEx.obj \
- SimpleFileParsing.obj \
- StringFuncs.obj \
- TianoCompress.obj
-
-!INCLUDE ..\Makefiles\ms.lib
-
-
-
+## @file +# Windows makefile for 'Common' module build. +# +# Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +!INCLUDE ..\Makefiles\ms.common + +# VPATH = .. + +LIBNAME = Common + +OBJECTS = \ + BasePeCoff.obj \ + BinderFuncs.obj \ + CommonLib.obj \ + Crc32.obj \ + Decompress.obj \ + EfiCompress.obj \ + EfiUtilityMsgs.obj \ + FirmwareVolumeBuffer.obj \ + FvLib.obj \ + MemoryFile.obj \ + MyAlloc.obj \ + OsPath.obj \ + ParseGuidedSectionTools.obj \ + ParseInf.obj \ + PeCoffLoaderEx.obj \ + SimpleFileParsing.obj \ + StringFuncs.obj \ + TianoCompress.obj + +!INCLUDE ..\Makefiles\ms.lib + + + diff --git a/BaseTools/Source/C/Common/MemoryFile.c b/BaseTools/Source/C/Common/MemoryFile.c index 4748132683..556d1a3506 100644 --- a/BaseTools/Source/C/Common/MemoryFile.c +++ b/BaseTools/Source/C/Common/MemoryFile.c @@ -1,225 +1,225 @@ -/** @file
-This contains some useful functions for accessing files.
-
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <assert.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include "CommonLib.h"
-#include "MemoryFile.h"
-
-
-//
-// Local (static) function prototypes
-//
-STATIC
-VOID
-CheckMemoryFileState (
- IN EFI_HANDLE InputMemoryFile
- );
-
-//
-// Function implementations
-//
-
-/**
- This opens a file, reads it into memory and returns a memory file
- object.
-
- @param InputFile Memory file image.
- @param OutputMemoryFile Handle to memory file
-
- @return EFI_STATUS
- OutputMemoryFile is valid if !EFI_ERROR
-**/
-EFI_STATUS
-GetMemoryFile (
- IN CHAR8 *InputFileName,
- OUT EFI_HANDLE *OutputMemoryFile
- )
-{
- EFI_STATUS Status;
- CHAR8 *InputFileImage;
- UINT32 BytesRead;
- MEMORY_FILE *NewMemoryFile;
-
- Status = GetFileImage (InputFileName, &InputFileImage, &BytesRead);
- if (EFI_ERROR (Status)) {
- return Status;
- }
-
- NewMemoryFile = malloc (sizeof (*NewMemoryFile));
- if (NewMemoryFile == NULL) {
- free (InputFileImage);
- return EFI_OUT_OF_RESOURCES;
- }
-
- NewMemoryFile->FileImage = InputFileImage;
- NewMemoryFile->CurrentFilePointer = InputFileImage;
- NewMemoryFile->Eof = InputFileImage + BytesRead;
-
- *OutputMemoryFile = (EFI_HANDLE)NewMemoryFile;
-
- CheckMemoryFileState (*OutputMemoryFile);
-
- return EFI_SUCCESS;
-}
-
-/**
- Frees all memory associated with the input memory file.
-
- @param InputMemoryFile Handle to memory file
-
- @return EFI_STATUS
-**/
-EFI_STATUS
-FreeMemoryFile (
- IN EFI_HANDLE InputMemoryFile
- )
-{
- MEMORY_FILE *MemoryFile;
-
- CheckMemoryFileState (InputMemoryFile);
-
- MemoryFile = (MEMORY_FILE*)InputMemoryFile;
-
- free (MemoryFile->FileImage);
-
- //
- // Invalidate state of MEMORY_FILE structure to catch invalid usage.
- //
- memset (MemoryFile, 0xcc, sizeof (*MemoryFile));
- MemoryFile->Eof -= 1;
-
- free (MemoryFile);
-
- return EFI_SUCCESS;
-}
-
-/**
- This function reads a line from the memory file. The newline characters
- are stripped and a null terminated string is returned.
-
- If the string pointer returned is non-NULL, then the caller must free the
- memory associated with this string.
-
- @param InputMemoryFile Handle to memory file
-
- @retval NULL if error or EOF
- @retval NULL character termincated string otherwise (MUST BE FREED BY CALLER)
-**/
-CHAR8 *
-ReadMemoryFileLine (
- IN EFI_HANDLE InputMemoryFile
- )
-{
- CHAR8 *EndOfLine;
- UINTN CharsToCopy;
- MEMORY_FILE *InputFile;
- UINTN BytesToEof;
- CHAR8 *OutputString;
-
- //
- // Verify input parameters are not null
- //
- CheckMemoryFileState (InputMemoryFile);
-
- InputFile = (MEMORY_FILE*)InputMemoryFile;
-
- //
- // Check for end of file condition
- //
- if (InputFile->CurrentFilePointer >= InputFile->Eof) {
- return NULL;
- }
-
- //
- // Determine the number of bytes remaining until the EOF
- //
- BytesToEof = InputFile->Eof - InputFile->CurrentFilePointer;
-
- //
- // Find the next newline char
- //
- EndOfLine = memchr (InputFile->CurrentFilePointer, '\n', BytesToEof);
-
- //
- // Determine the number of characters to copy.
- //
- if (EndOfLine == 0) {
- //
- // If no newline found, copy to the end of the file.
- //
- CharsToCopy = InputFile->Eof - InputFile->CurrentFilePointer;
- } else {
- //
- // Newline found in the file.
- //
- CharsToCopy = EndOfLine - InputFile->CurrentFilePointer;
- }
-
- OutputString = malloc (CharsToCopy + 1);
- if (OutputString == NULL) {
- return NULL;
- }
-
- //
- // Copy the line.
- //
- memcpy (OutputString, InputFile->CurrentFilePointer, CharsToCopy);
-
- //
- // Add the null termination over the 0x0D
- //
- if (OutputString[CharsToCopy - 1] == '\r') {
-
- OutputString[CharsToCopy - 1] = '\0';
-
- } else {
-
- OutputString[CharsToCopy] = '\0';
-
- }
-
- //
- // Increment the current file pointer (include the 0x0A)
- //
- InputFile->CurrentFilePointer += CharsToCopy + 1;
- if (InputFile->CurrentFilePointer > InputFile->Eof) {
- InputFile->CurrentFilePointer = InputFile->Eof;
- }
- CheckMemoryFileState (InputMemoryFile);
-
- //
- // Return the string
- //
- return OutputString;
-}
-
-
-STATIC
-VOID
-CheckMemoryFileState (
- IN EFI_HANDLE InputMemoryFile
- )
-{
- MEMORY_FILE *MemoryFile;
-
- assert (InputMemoryFile != NULL);
-
- MemoryFile = (MEMORY_FILE*)InputMemoryFile;
-
- assert (MemoryFile->FileImage != NULL);
- assert (MemoryFile->CurrentFilePointer != NULL);
- assert (MemoryFile->Eof != NULL);
- assert (MemoryFile->Eof >= MemoryFile->FileImage);
- assert (MemoryFile->CurrentFilePointer >= MemoryFile->FileImage);
- assert (MemoryFile->CurrentFilePointer <= MemoryFile->Eof);
-}
-
-
+/** @file +This contains some useful functions for accessing files. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <assert.h> +#include <string.h> +#include <ctype.h> +#include <stdlib.h> +#include "CommonLib.h" +#include "MemoryFile.h" + + +// +// Local (static) function prototypes +// +STATIC +VOID +CheckMemoryFileState ( + IN EFI_HANDLE InputMemoryFile + ); + +// +// Function implementations +// + +/** + This opens a file, reads it into memory and returns a memory file + object. + + @param InputFile Memory file image. + @param OutputMemoryFile Handle to memory file + + @return EFI_STATUS + OutputMemoryFile is valid if !EFI_ERROR +**/ +EFI_STATUS +GetMemoryFile ( + IN CHAR8 *InputFileName, + OUT EFI_HANDLE *OutputMemoryFile + ) +{ + EFI_STATUS Status; + CHAR8 *InputFileImage; + UINT32 BytesRead; + MEMORY_FILE *NewMemoryFile; + + Status = GetFileImage (InputFileName, &InputFileImage, &BytesRead); + if (EFI_ERROR (Status)) { + return Status; + } + + NewMemoryFile = malloc (sizeof (*NewMemoryFile)); + if (NewMemoryFile == NULL) { + free (InputFileImage); + return EFI_OUT_OF_RESOURCES; + } + + NewMemoryFile->FileImage = InputFileImage; + NewMemoryFile->CurrentFilePointer = InputFileImage; + NewMemoryFile->Eof = InputFileImage + BytesRead; + + *OutputMemoryFile = (EFI_HANDLE)NewMemoryFile; + + CheckMemoryFileState (*OutputMemoryFile); + + return EFI_SUCCESS; +} + +/** + Frees all memory associated with the input memory file. + + @param InputMemoryFile Handle to memory file + + @return EFI_STATUS +**/ +EFI_STATUS +FreeMemoryFile ( + IN EFI_HANDLE InputMemoryFile + ) +{ + MEMORY_FILE *MemoryFile; + + CheckMemoryFileState (InputMemoryFile); + + MemoryFile = (MEMORY_FILE*)InputMemoryFile; + + free (MemoryFile->FileImage); + + // + // Invalidate state of MEMORY_FILE structure to catch invalid usage. + // + memset (MemoryFile, 0xcc, sizeof (*MemoryFile)); + MemoryFile->Eof -= 1; + + free (MemoryFile); + + return EFI_SUCCESS; +} + +/** + This function reads a line from the memory file. The newline characters + are stripped and a null terminated string is returned. + + If the string pointer returned is non-NULL, then the caller must free the + memory associated with this string. + + @param InputMemoryFile Handle to memory file + + @retval NULL if error or EOF + @retval NULL character termincated string otherwise (MUST BE FREED BY CALLER) +**/ +CHAR8 * +ReadMemoryFileLine ( + IN EFI_HANDLE InputMemoryFile + ) +{ + CHAR8 *EndOfLine; + UINTN CharsToCopy; + MEMORY_FILE *InputFile; + UINTN BytesToEof; + CHAR8 *OutputString; + + // + // Verify input parameters are not null + // + CheckMemoryFileState (InputMemoryFile); + + InputFile = (MEMORY_FILE*)InputMemoryFile; + + // + // Check for end of file condition + // + if (InputFile->CurrentFilePointer >= InputFile->Eof) { + return NULL; + } + + // + // Determine the number of bytes remaining until the EOF + // + BytesToEof = InputFile->Eof - InputFile->CurrentFilePointer; + + // + // Find the next newline char + // + EndOfLine = memchr (InputFile->CurrentFilePointer, '\n', BytesToEof); + + // + // Determine the number of characters to copy. + // + if (EndOfLine == 0) { + // + // If no newline found, copy to the end of the file. + // + CharsToCopy = InputFile->Eof - InputFile->CurrentFilePointer; + } else { + // + // Newline found in the file. + // + CharsToCopy = EndOfLine - InputFile->CurrentFilePointer; + } + + OutputString = malloc (CharsToCopy + 1); + if (OutputString == NULL) { + return NULL; + } + + // + // Copy the line. + // + memcpy (OutputString, InputFile->CurrentFilePointer, CharsToCopy); + + // + // Add the null termination over the 0x0D + // + if (OutputString[CharsToCopy - 1] == '\r') { + + OutputString[CharsToCopy - 1] = '\0'; + + } else { + + OutputString[CharsToCopy] = '\0'; + + } + + // + // Increment the current file pointer (include the 0x0A) + // + InputFile->CurrentFilePointer += CharsToCopy + 1; + if (InputFile->CurrentFilePointer > InputFile->Eof) { + InputFile->CurrentFilePointer = InputFile->Eof; + } + CheckMemoryFileState (InputMemoryFile); + + // + // Return the string + // + return OutputString; +} + + +STATIC +VOID +CheckMemoryFileState ( + IN EFI_HANDLE InputMemoryFile + ) +{ + MEMORY_FILE *MemoryFile; + + assert (InputMemoryFile != NULL); + + MemoryFile = (MEMORY_FILE*)InputMemoryFile; + + assert (MemoryFile->FileImage != NULL); + assert (MemoryFile->CurrentFilePointer != NULL); + assert (MemoryFile->Eof != NULL); + assert (MemoryFile->Eof >= MemoryFile->FileImage); + assert (MemoryFile->CurrentFilePointer >= MemoryFile->FileImage); + assert (MemoryFile->CurrentFilePointer <= MemoryFile->Eof); +} + + diff --git a/BaseTools/Source/C/Common/MemoryFile.h b/BaseTools/Source/C/Common/MemoryFile.h index c84848cf15..a466bbf823 100644 --- a/BaseTools/Source/C/Common/MemoryFile.h +++ b/BaseTools/Source/C/Common/MemoryFile.h @@ -1,79 +1,79 @@ -/** @file
-Header file for helper functions useful for accessing files.
-
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _EFI_MEMORY_FILE_H
-#define _EFI_MEMORY_FILE_H
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <Common/UefiBaseTypes.h>
-
-//
-// Common data structures
-//
-typedef struct {
- CHAR8 *FileImage;
- CHAR8 *Eof;
- CHAR8 *CurrentFilePointer;
-} MEMORY_FILE;
-
-
-//
-// Functions declarations
-//
-
-/**
- This opens a file, reads it into memory and returns a memory file
- object.
-
- @param InputFile Memory file image.
- @param OutputMemoryFile Handle to memory file
-
- @return EFI_STATUS
- OutputMemoryFile is valid if !EFI_ERROR
-**/
-EFI_STATUS
-GetMemoryFile (
- IN CHAR8 *InputFileName,
- OUT EFI_HANDLE *OutputMemoryFile
- )
-;
-
-/**
- Frees all memory associated with the input memory file.
-
- @param InputMemoryFile Handle to memory file
-
- @return EFI_STATUS
-**/
-EFI_STATUS
-FreeMemoryFile (
- IN EFI_HANDLE InputMemoryFile
- )
-;
-
-/**
- This function reads a line from the memory file. The newline characters
- are stripped and a null terminated string is returned.
-
- If the string pointer returned is non-NULL, then the caller must free the
- memory associated with this string.
-
- @param InputMemoryFile Handle to memory file
-
- @retval NULL if error or EOF
- @retval NULL character termincated string otherwise (MUST BE FREED BY CALLER)
-**/
-CHAR8 *
-ReadMemoryFileLine (
- IN EFI_HANDLE InputMemoryFile
- )
-;
-
-
-#endif
+/** @file +Header file for helper functions useful for accessing files. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_MEMORY_FILE_H +#define _EFI_MEMORY_FILE_H + +#include <stdio.h> +#include <stdlib.h> +#include <Common/UefiBaseTypes.h> + +// +// Common data structures +// +typedef struct { + CHAR8 *FileImage; + CHAR8 *Eof; + CHAR8 *CurrentFilePointer; +} MEMORY_FILE; + + +// +// Functions declarations +// + +/** + This opens a file, reads it into memory and returns a memory file + object. + + @param InputFile Memory file image. + @param OutputMemoryFile Handle to memory file + + @return EFI_STATUS + OutputMemoryFile is valid if !EFI_ERROR +**/ +EFI_STATUS +GetMemoryFile ( + IN CHAR8 *InputFileName, + OUT EFI_HANDLE *OutputMemoryFile + ) +; + +/** + Frees all memory associated with the input memory file. + + @param InputMemoryFile Handle to memory file + + @return EFI_STATUS +**/ +EFI_STATUS +FreeMemoryFile ( + IN EFI_HANDLE InputMemoryFile + ) +; + +/** + This function reads a line from the memory file. The newline characters + are stripped and a null terminated string is returned. + + If the string pointer returned is non-NULL, then the caller must free the + memory associated with this string. + + @param InputMemoryFile Handle to memory file + + @retval NULL if error or EOF + @retval NULL character termincated string otherwise (MUST BE FREED BY CALLER) +**/ +CHAR8 * +ReadMemoryFileLine ( + IN EFI_HANDLE InputMemoryFile + ) +; + + +#endif diff --git a/BaseTools/Source/C/Common/MyAlloc.c b/BaseTools/Source/C/Common/MyAlloc.c index 17ff5cfbbd..d2ebcb24f3 100644 --- a/BaseTools/Source/C/Common/MyAlloc.c +++ b/BaseTools/Source/C/Common/MyAlloc.c @@ -1,489 +1,489 @@ -/** @file
-File for memory allocation tracking functions.
-
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "MyAlloc.h"
-
-#if USE_MYALLOC
-//
-// Get back to original alloc/free calls.
-//
-#undef malloc
-#undef calloc
-#undef realloc
-#undef free
-//
-// Start of allocation list.
-//
-STATIC MY_ALLOC_STRUCT *MyAllocData = NULL;
-
-//
-//
-//
-STATIC UINT32 MyAllocHeadMagik = MYALLOC_HEAD_MAGIK;
-STATIC UINT32 MyAllocTailMagik = MYALLOC_TAIL_MAGIK;
-
-/**
- Check for corruptions in the allocated memory chain. If a corruption
- is detection program operation stops w/ an exit(1) call.
-
- @param Final When FALSE, MyCheck() returns if the allocated memory chain
- has not been corrupted. When TRUE, MyCheck() returns if there
- are no un-freed allocations. If there are un-freed allocations,
- they are displayed and exit(1) is called.
- @param File Set to __FILE__ by macro expansion.
- @param Line Set to __LINE__ by macro expansion.
-**/
-VOID
-MyCheck (
- BOOLEAN Final,
- UINT8 File[],
- UINTN Line
- )
-{
- MY_ALLOC_STRUCT *Tmp;
-
- //
- // Check parameters.
- //
- if (File == NULL) {
- printf (
- "\nMyCheck(Final=%u, File=NULL, Line=%u)"
- "Invalid parameter(s).\n",
- Final,
- (unsigned)Line
- );
-
- exit (1);
- }
-
- if (Line == 0) {
- printf (
- "\nMyCheck(Final=%u, File=%s, Line=%u)"
- "Invalid parameter(s).\n",
- Final,
- File,
- (unsigned)Line
- );
-
- exit (1);
- }
-
- if (strlen ((CHAR8 *)File) == 0) {
- printf (
- "\nMyCheck(Final=%u, File=%s, Line=%u)"
- "Invalid parameter.\n",
- Final,
- File,
- (unsigned)Line
- );
-
- exit (1);
- }
- //
- // Check structure contents.
- //
- for (Tmp = MyAllocData; Tmp != NULL; Tmp = Tmp->Next) {
- if (memcmp(Tmp->Buffer, &MyAllocHeadMagik, sizeof MyAllocHeadMagik) ||
- memcmp(&Tmp->Buffer[Tmp->Size + sizeof(UINT32)], &MyAllocTailMagik, sizeof MyAllocTailMagik)) {
- break;
- }
- }
- //
- // If Tmp is not NULL, the structure is corrupt.
- //
- if (Tmp != NULL) {
- printf (
- "\nMyCheck(Final=%u, File=%s, Line=%u)""\nStructure corrupted!"
- "\nFile=%s, Line=%u, nSize=%u, Head=%xh, Tail=%xh\n",
- Final,
- File,
- (unsigned)Line,
- Tmp->File,
- (unsigned) Tmp->Line,
- (unsigned) Tmp->Size,
- (unsigned) *(UINT32 *) (Tmp->Buffer),
- (unsigned) *(UINT32 *) (&Tmp->Buffer[Tmp->Size + sizeof (UINT32)])
- );
-
- exit (1);
- }
- //
- // If Final is TRUE, display the state of the structure chain.
- //
- if (Final) {
- if (MyAllocData != NULL) {
- printf (
- "\nMyCheck(Final=%u, File=%s, Line=%u)"
- "\nSome allocated items have not been freed.\n",
- Final,
- File,
- (unsigned)Line
- );
-
- for (Tmp = MyAllocData; Tmp != NULL; Tmp = Tmp->Next) {
- printf (
- "File=%s, Line=%u, nSize=%u, Head=%xh, Tail=%xh\n",
- Tmp->File,
- (unsigned) Tmp->Line,
- (unsigned) Tmp->Size,
- (unsigned) *(UINT32 *) (Tmp->Buffer),
- (unsigned) *(UINT32 *) (&Tmp->Buffer[Tmp->Size + sizeof (UINT32)])
- );
- }
- }
- }
-}
-
-/**
- Allocate a new link in the allocation chain along with enough storage
- for the File[] string, requested Size and alignment overhead. If
- memory cannot be allocated or the allocation chain has been corrupted,
- exit(1) will be called.
-
- @param Size Number of bytes (UINT8) requested by the called.
- Size cannot be zero.
- @param File Set to __FILE__ by macro expansion.
- @param Line Set to __LINE__ by macro expansion.
-
- @return Pointer to the caller's buffer.
-**/
-VOID *
-MyAlloc (
- UINTN Size,
- UINT8 File[],
- UINTN Line
- )
-{
- MY_ALLOC_STRUCT *Tmp;
- UINTN Len;
-
- //
- // Check for invalid parameters.
- //
- if (File == NULL) {
- printf (
- "\nMyAlloc(Size=%u, File=NULL, Line=%u)"
- "\nInvalid parameter(s).\n",
- (unsigned)Size,
- (unsigned)Line
- );
-
- exit (1);
- }
-
- if (Size == 0 || Line == 0) {
- printf (
- "\nMyAlloc(Size=%u, File=%s, Line=%u)"
- "\nInvalid parameter(s).\n",
- (unsigned)Size,
- File,
- (unsigned)Line
- );
-
- exit (1);
- }
-
- Len = strlen ((CHAR8 *)File);
- if (Len == 0) {
- printf (
- "\nMyAlloc(Size=%u, File=%s, Line=%u)"
- "\nInvalid parameter.\n",
- (unsigned)Size,
- File,
- (unsigned)Line
- );
-
- exit (1);
- }
- //
- // Check the allocation list for corruption.
- //
- MyCheck (0, (UINT8 *)__FILE__, __LINE__);
-
- //
- // Allocate a new entry.
- //
- Tmp = calloc (
- 1,
- sizeof (MY_ALLOC_STRUCT) + Len + 1 + sizeof (UINT64) + Size + (sizeof MyAllocHeadMagik) + (sizeof MyAllocTailMagik)
- );
-
- if (Tmp == NULL) {
- printf (
- "\nMyAlloc(Size=%u, File=%s, Line=%u)"
- "\nOut of memory.\n",
- (unsigned)Size,
- File,
- (unsigned)Line
- );
-
- exit (1);
- }
- //
- // Fill in the new entry.
- //
- Tmp->File = ((UINT8 *) Tmp) + sizeof (MY_ALLOC_STRUCT);
- strcpy ((CHAR8 *)Tmp->File, (CHAR8 *)File);
- Tmp->Line = Line;
- Tmp->Size = Size;
- Tmp->Buffer = (UINT8 *) (((UINTN) Tmp + Len + 9) &~7);
-
- memcpy (Tmp->Buffer, &MyAllocHeadMagik, sizeof MyAllocHeadMagik);
-
- memcpy (
- &Tmp->Buffer[Size + sizeof (UINT32)],
- &MyAllocTailMagik,
- sizeof MyAllocTailMagik
- );
-
- Tmp->Next = MyAllocData;
- Tmp->Cksum = (UINTN) Tmp + (UINTN) (Tmp->Next) + Tmp->Line + Tmp->Size + (UINTN) (Tmp->File) + (UINTN) (Tmp->Buffer);
-
- MyAllocData = Tmp;
-
- return Tmp->Buffer + sizeof (UINT32);
-}
-
-/**
- This does a MyAlloc(), memcpy() and MyFree(). There is no optimization
- for shrinking or expanding buffers. An invalid parameter will cause
- MyRealloc() to fail with a call to exit(1).
-
- @param Ptr Pointer to the caller's buffer to be re-allocated.
- @param Size Size of new buffer. Size cannot be zero.
- @param File Set to __FILE__ by macro expansion.
- @param Line Set to __LINE__ by macro expansion.
-
- @return Pointer to new caller's buffer.
-**/
-VOID *
-MyRealloc (
- VOID *Ptr,
- UINTN Size,
- UINT8 File[],
- UINTN Line
- )
-{
- MY_ALLOC_STRUCT *Tmp;
- VOID *Buffer;
-
- //
- // Check for invalid parameter(s).
- //
- if (File == NULL) {
- printf (
- "\nMyRealloc(Ptr=%p, Size=%u, File=NULL, Line=%u)"
- "\nInvalid parameter(s).\n",
- Ptr,
- (unsigned)Size,
- (unsigned)Line
- );
-
- exit (1);
- }
-
- if (Size == 0 || Line == 0) {
- printf (
- "\nMyRealloc(Ptr=%p, Size=%u, File=%s, Line=%u)"
- "\nInvalid parameter(s).\n",
- Ptr,
- (unsigned)Size,
- File,
- (unsigned)Line
- );
-
- exit (1);
- }
-
- if (strlen ((CHAR8 *)File) == 0) {
- printf (
- "\nMyRealloc(Ptr=%p, Size=%u, File=%s, Line=%u)"
- "\nInvalid parameter.\n",
- Ptr,
- (unsigned)Size,
- File,
- (unsigned)Line
- );
-
- exit (1);
- }
- //
- // Find existing buffer in allocation list.
- //
- if (Ptr == NULL) {
- Tmp = NULL;
- } else if (&MyAllocData->Buffer[sizeof (UINT32)] == Ptr) {
- Tmp = MyAllocData;
- } else {
- for (Tmp = MyAllocData;; Tmp = Tmp->Next) {
- if (Tmp->Next == NULL) {
- printf (
- "\nMyRealloc(Ptr=%p, Size=%u, File=%s, Line=%u)"
- "\nCould not find buffer.\n",
- Ptr,
- (unsigned)Size,
- File,
- (unsigned)Line
- );
-
- exit (1);
- }
-
- Tmp = Tmp->Next;
- }
- }
- //
- // Allocate new buffer, copy old data, free old buffer.
- //
- Buffer = MyAlloc (Size, File, Line);
-
- if (Buffer != NULL && Tmp != NULL) {
- memcpy (
- Buffer,
- &Tmp->Buffer[sizeof (UINT32)],
- ((Size <= Tmp->Size) ? Size : Tmp->Size)
- );
-
- MyFree (Ptr, (UINT8 *)__FILE__, __LINE__);
- }
-
- return Buffer;
-}
-
-/**
- Release a previously allocated buffer. Invalid parameters will cause
- MyFree() to fail with an exit(1) call.
-
- @param Ptr Pointer to the caller's buffer to be freed.
- A NULL pointer will be ignored.
- @param File Set to __FILE__ by macro expansion.
- @param Line Set to __LINE__ by macro expansion.
-**/
-VOID
-MyFree (
- VOID *Ptr,
- UINT8 File[],
- UINTN Line
- )
-{
- MY_ALLOC_STRUCT *Tmp;
- MY_ALLOC_STRUCT *Tmp2;
-
- //
- // Check for invalid parameter(s).
- //
- if (File == NULL) {
- printf (
- "\nMyFree(Ptr=%p, File=NULL, Line=%u)"
- "\nInvalid parameter(s).\n",
- Ptr,
- (unsigned)Line
- );
-
- exit (1);
- }
-
- if (Line == 0) {
- printf (
- "\nMyFree(Ptr=%p, File=%s, Line=%u)"
- "\nInvalid parameter(s).\n",
- Ptr,
- File,
- (unsigned)Line
- );
-
- exit (1);
- }
-
- if (strlen ((CHAR8 *)File) == 0) {
- printf (
- "\nMyFree(Ptr=%p, File=%s, Line=%u)"
- "\nInvalid parameter.\n",
- Ptr,
- File,
- (unsigned)Line
- );
-
- exit (1);
- }
- //
- // Freeing NULL is always valid.
- //
- if (Ptr == NULL) {
- return ;
- }
- //
- // Fail if nothing is allocated.
- //
- if (MyAllocData == NULL) {
- printf (
- "\nMyFree(Ptr=%p, File=%s, Line=%u)"
- "\nCalled before memory allocated.\n",
- Ptr,
- File,
- (unsigned)Line
- );
-
- exit (1);
- }
- //
- // Check for corrupted allocation list.
- //
- MyCheck (0, (UINT8 *)__FILE__, __LINE__);
-
- //
- // Need special check for first item in list.
- //
- if (&MyAllocData->Buffer[sizeof (UINT32)] == Ptr) {
- //
- // Unlink first item in list.
- //
- Tmp = MyAllocData;
- MyAllocData = MyAllocData->Next;
- } else {
- //
- // Walk list looking for matching item.
- //
- for (Tmp = MyAllocData;; Tmp = Tmp->Next) {
- //
- // Fail if end of list is reached.
- //
- if (Tmp->Next == NULL) {
- printf (
- "\nMyFree(Ptr=%p, File=%s, Line=%u)\n"
- "\nNot found.\n",
- Ptr,
- File,
- (unsigned)Line
- );
-
- exit (1);
- }
- //
- // Leave loop when match is found.
- //
- if (&Tmp->Next->Buffer[sizeof (UINT32)] == Ptr) {
- break;
- }
- }
- //
- // Unlink item from list.
- //
- Tmp2 = Tmp->Next;
- Tmp->Next = Tmp->Next->Next;
- Tmp = Tmp2;
- }
- //
- // Release item.
- //
- free (Tmp);
-}
-
-#endif /* USE_MYALLOC */
-
-/* eof - MyAlloc.c */
+/** @file +File for memory allocation tracking functions. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "MyAlloc.h" + +#if USE_MYALLOC +// +// Get back to original alloc/free calls. +// +#undef malloc +#undef calloc +#undef realloc +#undef free +// +// Start of allocation list. +// +STATIC MY_ALLOC_STRUCT *MyAllocData = NULL; + +// +// +// +STATIC UINT32 MyAllocHeadMagik = MYALLOC_HEAD_MAGIK; +STATIC UINT32 MyAllocTailMagik = MYALLOC_TAIL_MAGIK; + +/** + Check for corruptions in the allocated memory chain. If a corruption + is detection program operation stops w/ an exit(1) call. + + @param Final When FALSE, MyCheck() returns if the allocated memory chain + has not been corrupted. When TRUE, MyCheck() returns if there + are no un-freed allocations. If there are un-freed allocations, + they are displayed and exit(1) is called. + @param File Set to __FILE__ by macro expansion. + @param Line Set to __LINE__ by macro expansion. +**/ +VOID +MyCheck ( + BOOLEAN Final, + UINT8 File[], + UINTN Line + ) +{ + MY_ALLOC_STRUCT *Tmp; + + // + // Check parameters. + // + if (File == NULL) { + printf ( + "\nMyCheck(Final=%u, File=NULL, Line=%u)" + "Invalid parameter(s).\n", + Final, + (unsigned)Line + ); + + exit (1); + } + + if (Line == 0) { + printf ( + "\nMyCheck(Final=%u, File=%s, Line=%u)" + "Invalid parameter(s).\n", + Final, + File, + (unsigned)Line + ); + + exit (1); + } + + if (strlen ((CHAR8 *)File) == 0) { + printf ( + "\nMyCheck(Final=%u, File=%s, Line=%u)" + "Invalid parameter.\n", + Final, + File, + (unsigned)Line + ); + + exit (1); + } + // + // Check structure contents. + // + for (Tmp = MyAllocData; Tmp != NULL; Tmp = Tmp->Next) { + if (memcmp(Tmp->Buffer, &MyAllocHeadMagik, sizeof MyAllocHeadMagik) || + memcmp(&Tmp->Buffer[Tmp->Size + sizeof(UINT32)], &MyAllocTailMagik, sizeof MyAllocTailMagik)) { + break; + } + } + // + // If Tmp is not NULL, the structure is corrupt. + // + if (Tmp != NULL) { + printf ( + "\nMyCheck(Final=%u, File=%s, Line=%u)""\nStructure corrupted!" + "\nFile=%s, Line=%u, nSize=%u, Head=%xh, Tail=%xh\n", + Final, + File, + (unsigned)Line, + Tmp->File, + (unsigned) Tmp->Line, + (unsigned) Tmp->Size, + (unsigned) *(UINT32 *) (Tmp->Buffer), + (unsigned) *(UINT32 *) (&Tmp->Buffer[Tmp->Size + sizeof (UINT32)]) + ); + + exit (1); + } + // + // If Final is TRUE, display the state of the structure chain. + // + if (Final) { + if (MyAllocData != NULL) { + printf ( + "\nMyCheck(Final=%u, File=%s, Line=%u)" + "\nSome allocated items have not been freed.\n", + Final, + File, + (unsigned)Line + ); + + for (Tmp = MyAllocData; Tmp != NULL; Tmp = Tmp->Next) { + printf ( + "File=%s, Line=%u, nSize=%u, Head=%xh, Tail=%xh\n", + Tmp->File, + (unsigned) Tmp->Line, + (unsigned) Tmp->Size, + (unsigned) *(UINT32 *) (Tmp->Buffer), + (unsigned) *(UINT32 *) (&Tmp->Buffer[Tmp->Size + sizeof (UINT32)]) + ); + } + } + } +} + +/** + Allocate a new link in the allocation chain along with enough storage + for the File[] string, requested Size and alignment overhead. If + memory cannot be allocated or the allocation chain has been corrupted, + exit(1) will be called. + + @param Size Number of bytes (UINT8) requested by the called. + Size cannot be zero. + @param File Set to __FILE__ by macro expansion. + @param Line Set to __LINE__ by macro expansion. + + @return Pointer to the caller's buffer. +**/ +VOID * +MyAlloc ( + UINTN Size, + UINT8 File[], + UINTN Line + ) +{ + MY_ALLOC_STRUCT *Tmp; + UINTN Len; + + // + // Check for invalid parameters. + // + if (File == NULL) { + printf ( + "\nMyAlloc(Size=%u, File=NULL, Line=%u)" + "\nInvalid parameter(s).\n", + (unsigned)Size, + (unsigned)Line + ); + + exit (1); + } + + if (Size == 0 || Line == 0) { + printf ( + "\nMyAlloc(Size=%u, File=%s, Line=%u)" + "\nInvalid parameter(s).\n", + (unsigned)Size, + File, + (unsigned)Line + ); + + exit (1); + } + + Len = strlen ((CHAR8 *)File); + if (Len == 0) { + printf ( + "\nMyAlloc(Size=%u, File=%s, Line=%u)" + "\nInvalid parameter.\n", + (unsigned)Size, + File, + (unsigned)Line + ); + + exit (1); + } + // + // Check the allocation list for corruption. + // + MyCheck (0, (UINT8 *)__FILE__, __LINE__); + + // + // Allocate a new entry. + // + Tmp = calloc ( + 1, + sizeof (MY_ALLOC_STRUCT) + Len + 1 + sizeof (UINT64) + Size + (sizeof MyAllocHeadMagik) + (sizeof MyAllocTailMagik) + ); + + if (Tmp == NULL) { + printf ( + "\nMyAlloc(Size=%u, File=%s, Line=%u)" + "\nOut of memory.\n", + (unsigned)Size, + File, + (unsigned)Line + ); + + exit (1); + } + // + // Fill in the new entry. + // + Tmp->File = ((UINT8 *) Tmp) + sizeof (MY_ALLOC_STRUCT); + strcpy ((CHAR8 *)Tmp->File, (CHAR8 *)File); + Tmp->Line = Line; + Tmp->Size = Size; + Tmp->Buffer = (UINT8 *) (((UINTN) Tmp + Len + 9) &~7); + + memcpy (Tmp->Buffer, &MyAllocHeadMagik, sizeof MyAllocHeadMagik); + + memcpy ( + &Tmp->Buffer[Size + sizeof (UINT32)], + &MyAllocTailMagik, + sizeof MyAllocTailMagik + ); + + Tmp->Next = MyAllocData; + Tmp->Cksum = (UINTN) Tmp + (UINTN) (Tmp->Next) + Tmp->Line + Tmp->Size + (UINTN) (Tmp->File) + (UINTN) (Tmp->Buffer); + + MyAllocData = Tmp; + + return Tmp->Buffer + sizeof (UINT32); +} + +/** + This does a MyAlloc(), memcpy() and MyFree(). There is no optimization + for shrinking or expanding buffers. An invalid parameter will cause + MyRealloc() to fail with a call to exit(1). + + @param Ptr Pointer to the caller's buffer to be re-allocated. + @param Size Size of new buffer. Size cannot be zero. + @param File Set to __FILE__ by macro expansion. + @param Line Set to __LINE__ by macro expansion. + + @return Pointer to new caller's buffer. +**/ +VOID * +MyRealloc ( + VOID *Ptr, + UINTN Size, + UINT8 File[], + UINTN Line + ) +{ + MY_ALLOC_STRUCT *Tmp; + VOID *Buffer; + + // + // Check for invalid parameter(s). + // + if (File == NULL) { + printf ( + "\nMyRealloc(Ptr=%p, Size=%u, File=NULL, Line=%u)" + "\nInvalid parameter(s).\n", + Ptr, + (unsigned)Size, + (unsigned)Line + ); + + exit (1); + } + + if (Size == 0 || Line == 0) { + printf ( + "\nMyRealloc(Ptr=%p, Size=%u, File=%s, Line=%u)" + "\nInvalid parameter(s).\n", + Ptr, + (unsigned)Size, + File, + (unsigned)Line + ); + + exit (1); + } + + if (strlen ((CHAR8 *)File) == 0) { + printf ( + "\nMyRealloc(Ptr=%p, Size=%u, File=%s, Line=%u)" + "\nInvalid parameter.\n", + Ptr, + (unsigned)Size, + File, + (unsigned)Line + ); + + exit (1); + } + // + // Find existing buffer in allocation list. + // + if (Ptr == NULL) { + Tmp = NULL; + } else if (&MyAllocData->Buffer[sizeof (UINT32)] == Ptr) { + Tmp = MyAllocData; + } else { + for (Tmp = MyAllocData;; Tmp = Tmp->Next) { + if (Tmp->Next == NULL) { + printf ( + "\nMyRealloc(Ptr=%p, Size=%u, File=%s, Line=%u)" + "\nCould not find buffer.\n", + Ptr, + (unsigned)Size, + File, + (unsigned)Line + ); + + exit (1); + } + + Tmp = Tmp->Next; + } + } + // + // Allocate new buffer, copy old data, free old buffer. + // + Buffer = MyAlloc (Size, File, Line); + + if (Buffer != NULL && Tmp != NULL) { + memcpy ( + Buffer, + &Tmp->Buffer[sizeof (UINT32)], + ((Size <= Tmp->Size) ? Size : Tmp->Size) + ); + + MyFree (Ptr, (UINT8 *)__FILE__, __LINE__); + } + + return Buffer; +} + +/** + Release a previously allocated buffer. Invalid parameters will cause + MyFree() to fail with an exit(1) call. + + @param Ptr Pointer to the caller's buffer to be freed. + A NULL pointer will be ignored. + @param File Set to __FILE__ by macro expansion. + @param Line Set to __LINE__ by macro expansion. +**/ +VOID +MyFree ( + VOID *Ptr, + UINT8 File[], + UINTN Line + ) +{ + MY_ALLOC_STRUCT *Tmp; + MY_ALLOC_STRUCT *Tmp2; + + // + // Check for invalid parameter(s). + // + if (File == NULL) { + printf ( + "\nMyFree(Ptr=%p, File=NULL, Line=%u)" + "\nInvalid parameter(s).\n", + Ptr, + (unsigned)Line + ); + + exit (1); + } + + if (Line == 0) { + printf ( + "\nMyFree(Ptr=%p, File=%s, Line=%u)" + "\nInvalid parameter(s).\n", + Ptr, + File, + (unsigned)Line + ); + + exit (1); + } + + if (strlen ((CHAR8 *)File) == 0) { + printf ( + "\nMyFree(Ptr=%p, File=%s, Line=%u)" + "\nInvalid parameter.\n", + Ptr, + File, + (unsigned)Line + ); + + exit (1); + } + // + // Freeing NULL is always valid. + // + if (Ptr == NULL) { + return ; + } + // + // Fail if nothing is allocated. + // + if (MyAllocData == NULL) { + printf ( + "\nMyFree(Ptr=%p, File=%s, Line=%u)" + "\nCalled before memory allocated.\n", + Ptr, + File, + (unsigned)Line + ); + + exit (1); + } + // + // Check for corrupted allocation list. + // + MyCheck (0, (UINT8 *)__FILE__, __LINE__); + + // + // Need special check for first item in list. + // + if (&MyAllocData->Buffer[sizeof (UINT32)] == Ptr) { + // + // Unlink first item in list. + // + Tmp = MyAllocData; + MyAllocData = MyAllocData->Next; + } else { + // + // Walk list looking for matching item. + // + for (Tmp = MyAllocData;; Tmp = Tmp->Next) { + // + // Fail if end of list is reached. + // + if (Tmp->Next == NULL) { + printf ( + "\nMyFree(Ptr=%p, File=%s, Line=%u)\n" + "\nNot found.\n", + Ptr, + File, + (unsigned)Line + ); + + exit (1); + } + // + // Leave loop when match is found. + // + if (&Tmp->Next->Buffer[sizeof (UINT32)] == Ptr) { + break; + } + } + // + // Unlink item from list. + // + Tmp2 = Tmp->Next; + Tmp->Next = Tmp->Next->Next; + Tmp = Tmp2; + } + // + // Release item. + // + free (Tmp); +} + +#endif /* USE_MYALLOC */ + +/* eof - MyAlloc.c */ diff --git a/BaseTools/Source/C/Common/MyAlloc.h b/BaseTools/Source/C/Common/MyAlloc.h index de3323d30d..4ef6995daf 100644 --- a/BaseTools/Source/C/Common/MyAlloc.h +++ b/BaseTools/Source/C/Common/MyAlloc.h @@ -1,163 +1,163 @@ -/** @file
-Header file for memory allocation tracking functions.
-
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _MYALLOC_H_
-#define _MYALLOC_H_
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <Common/BaseTypes.h>
-
-//
-// Default operation is to use the memory allocation tracking functions.
-// To over-ride add "#define USE_MYALLOC 0" to your program header and/or
-// source files as needed. Or, just do not include this header file in
-// your project.
-//
-#ifndef USE_MYALLOC
-#define USE_MYALLOC 1
-#endif
-
-#if USE_MYALLOC
-//
-// Replace C library allocation routines with MyAlloc routines.
-//
-#define malloc(size) MyAlloc ((size), __FILE__, __LINE__)
-#define calloc(count, size) MyAlloc ((count) * (size), __FILE__, __LINE__)
-#define realloc(ptr, size) MyRealloc ((ptr), (size), __FILE__, __LINE__)
-#define free(ptr) MyFree ((ptr), __FILE__, __LINE__)
-#define alloc_check(final) MyCheck ((final), __FILE__, __LINE__)
-
-//
-// Structure for checking/tracking memory allocations.
-//
-typedef struct MyAllocStruct {
- UINTN Cksum;
- struct MyAllocStruct *Next;
- UINTN Line;
- UINTN Size;
- UINT8 *File;
- UINT8 *Buffer;
-} MY_ALLOC_STRUCT;
-//
-// Cksum := (UINTN)This + (UINTN)Next + Line + Size + (UINTN)File +
-// (UINTN)Buffer;
-//
-// Next := Pointer to next allocation structure in the list.
-//
-// Line := __LINE__
-//
-// Size := Size of allocation request.
-//
-// File := Pointer to __FILE__ string stored immediately following
-// MY_ALLOC_STRUCT in memory.
-//
-// Buffer := Pointer to UINT32 aligned storage immediately following
-// the NULL terminated __FILE__ string. This is UINT32
-// aligned because the underflow signature is 32-bits and
-// this will place the first caller address on a 64-bit
-// boundary.
-//
-//
-// Signatures used to check for buffer overflow/underflow conditions.
-//
-#define MYALLOC_HEAD_MAGIK 0xBADFACED
-#define MYALLOC_TAIL_MAGIK 0xDEADBEEF
-
-/**
- Check for corruptions in the allocated memory chain. If a corruption
- is detection program operation stops w/ an exit(1) call.
-
- @param Final When FALSE, MyCheck() returns if the allocated memory chain
- has not been corrupted. When TRUE, MyCheck() returns if there
- are no un-freed allocations. If there are un-freed allocations,
- they are displayed and exit(1) is called.
- @param File Set to __FILE__ by macro expansion.
- @param Line Set to __LINE__ by macro expansion.
-**/
-VOID
-MyCheck (
- BOOLEAN Final,
- UINT8 File[],
- UINTN Line
- )
-;
-
-/**
- Allocate a new link in the allocation chain along with enough storage
- for the File[] string, requested Size and alignment overhead. If
- memory cannot be allocated or the allocation chain has been corrupted,
- exit(1) will be called.
-
- @param Size Number of bytes (UINT8) requested by the called.
- Size cannot be zero.
- @param File Set to __FILE__ by macro expansion.
- @param Line Set to __LINE__ by macro expansion.
-
- @return Pointer to the caller's buffer.
-**/
-VOID *
-MyAlloc (
- UINTN Size,
- UINT8 File[],
- UINTN Line
- )
-;
-
-/**
- This does a MyAlloc(), memcpy() and MyFree(). There is no optimization
- for shrinking or expanding buffers. An invalid parameter will cause
- MyRealloc() to fail with a call to exit(1).
-
- @param Ptr Pointer to the caller's buffer to be re-allocated.
- Ptr cannot be NULL.
- @param Size Size of new buffer. Size cannot be zero.
- @param File Set to __FILE__ by macro expansion.
- @param Line Set to __LINE__ by macro expansion.
-
- @return Pointer to new caller's buffer.
-**/
-VOID *
-MyRealloc (
- VOID *Ptr,
- UINTN Size,
- UINT8 File[],
- UINTN Line
- )
-;
-
-/**
- Release a previously allocated buffer. Invalid parameters will cause
- MyFree() to fail with an exit(1) call.
-
- @param Ptr Pointer to the caller's buffer to be freed.
- A NULL pointer will be ignored.
- @param File Set to __FILE__ by macro expansion.
- @param Line Set to __LINE__ by macro expansion.
-**/
-VOID
-MyFree (
- VOID *Ptr,
- UINT8 File[],
- UINTN Line
- )
-;
-
-#else /* USE_MYALLOC */
-
-//
-// Nothing to do when USE_MYALLOC is zero.
-//
-#define alloc_check(final)
-
-#endif /* USE_MYALLOC */
-#endif /* _MYALLOC_H_ */
-
-/* eof - MyAlloc.h */
+/** @file +Header file for memory allocation tracking functions. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _MYALLOC_H_ +#define _MYALLOC_H_ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <Common/BaseTypes.h> + +// +// Default operation is to use the memory allocation tracking functions. +// To over-ride add "#define USE_MYALLOC 0" to your program header and/or +// source files as needed. Or, just do not include this header file in +// your project. +// +#ifndef USE_MYALLOC +#define USE_MYALLOC 1 +#endif + +#if USE_MYALLOC +// +// Replace C library allocation routines with MyAlloc routines. +// +#define malloc(size) MyAlloc ((size), __FILE__, __LINE__) +#define calloc(count, size) MyAlloc ((count) * (size), __FILE__, __LINE__) +#define realloc(ptr, size) MyRealloc ((ptr), (size), __FILE__, __LINE__) +#define free(ptr) MyFree ((ptr), __FILE__, __LINE__) +#define alloc_check(final) MyCheck ((final), __FILE__, __LINE__) + +// +// Structure for checking/tracking memory allocations. +// +typedef struct MyAllocStruct { + UINTN Cksum; + struct MyAllocStruct *Next; + UINTN Line; + UINTN Size; + UINT8 *File; + UINT8 *Buffer; +} MY_ALLOC_STRUCT; +// +// Cksum := (UINTN)This + (UINTN)Next + Line + Size + (UINTN)File + +// (UINTN)Buffer; +// +// Next := Pointer to next allocation structure in the list. +// +// Line := __LINE__ +// +// Size := Size of allocation request. +// +// File := Pointer to __FILE__ string stored immediately following +// MY_ALLOC_STRUCT in memory. +// +// Buffer := Pointer to UINT32 aligned storage immediately following +// the NULL terminated __FILE__ string. This is UINT32 +// aligned because the underflow signature is 32-bits and +// this will place the first caller address on a 64-bit +// boundary. +// +// +// Signatures used to check for buffer overflow/underflow conditions. +// +#define MYALLOC_HEAD_MAGIK 0xBADFACED +#define MYALLOC_TAIL_MAGIK 0xDEADBEEF + +/** + Check for corruptions in the allocated memory chain. If a corruption + is detection program operation stops w/ an exit(1) call. + + @param Final When FALSE, MyCheck() returns if the allocated memory chain + has not been corrupted. When TRUE, MyCheck() returns if there + are no un-freed allocations. If there are un-freed allocations, + they are displayed and exit(1) is called. + @param File Set to __FILE__ by macro expansion. + @param Line Set to __LINE__ by macro expansion. +**/ +VOID +MyCheck ( + BOOLEAN Final, + UINT8 File[], + UINTN Line + ) +; + +/** + Allocate a new link in the allocation chain along with enough storage + for the File[] string, requested Size and alignment overhead. If + memory cannot be allocated or the allocation chain has been corrupted, + exit(1) will be called. + + @param Size Number of bytes (UINT8) requested by the called. + Size cannot be zero. + @param File Set to __FILE__ by macro expansion. + @param Line Set to __LINE__ by macro expansion. + + @return Pointer to the caller's buffer. +**/ +VOID * +MyAlloc ( + UINTN Size, + UINT8 File[], + UINTN Line + ) +; + +/** + This does a MyAlloc(), memcpy() and MyFree(). There is no optimization + for shrinking or expanding buffers. An invalid parameter will cause + MyRealloc() to fail with a call to exit(1). + + @param Ptr Pointer to the caller's buffer to be re-allocated. + Ptr cannot be NULL. + @param Size Size of new buffer. Size cannot be zero. + @param File Set to __FILE__ by macro expansion. + @param Line Set to __LINE__ by macro expansion. + + @return Pointer to new caller's buffer. +**/ +VOID * +MyRealloc ( + VOID *Ptr, + UINTN Size, + UINT8 File[], + UINTN Line + ) +; + +/** + Release a previously allocated buffer. Invalid parameters will cause + MyFree() to fail with an exit(1) call. + + @param Ptr Pointer to the caller's buffer to be freed. + A NULL pointer will be ignored. + @param File Set to __FILE__ by macro expansion. + @param Line Set to __LINE__ by macro expansion. +**/ +VOID +MyFree ( + VOID *Ptr, + UINT8 File[], + UINTN Line + ) +; + +#else /* USE_MYALLOC */ + +// +// Nothing to do when USE_MYALLOC is zero. +// +#define alloc_check(final) + +#endif /* USE_MYALLOC */ +#endif /* _MYALLOC_H_ */ + +/* eof - MyAlloc.h */ diff --git a/BaseTools/Source/C/Common/OsPath.c b/BaseTools/Source/C/Common/OsPath.c index 9901f686c9..5dcb0dc8f3 100644 --- a/BaseTools/Source/C/Common/OsPath.c +++ b/BaseTools/Source/C/Common/OsPath.c @@ -1,264 +1,264 @@ -/** @file
-Functions useful to operate file directories by parsing file path.
-
-Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include "CommonLib.h"
-#include "OsPath.h"
-
-//
-// Functions implementations
-//
-
-#if 0
- //
- // BUGBUG: Not fully implemented yet.
- //
-
-/**
- This function returns the directory path which contains the particular path.
- Some examples:
- "a/b/c" -> "a/b"
- "a/b/c/" -> "a/b"
- "a" -> "."
- "." -> ".."
- "/" -> NULL
-
- This function does not check for the existence of the file.
-
- The caller must free the string returned.
-
- @param FilePath Path name of file to get the parent directory for.
-
- @return NULL if error
-**/
-CHAR8*
-OsPathDirName (
- IN CHAR8 *FilePath
- )
-
-{
- CHAR8 *Return;
- CHAR8 *Pos;
- CHAR8 Char;
- UINTN Length;
- INTN Offset;
-
- Length = strlen (FilePath);
-
- if (Length == 0) {
- return NULL;
- }
-
- //
- // Check for the root directory case
- //
- if (
- (Length == 3 && isalpha (FilePath[0]) && (strcmp(FilePath + 1, ":\\") == 0)) ||
- (strcmp(FilePath, "/") == 0)
- ) {
- return NULL;
- }
-
- //
- // If the path ends with a path separator, then just append ".."
- //
- Char = FilePath[Length - 1];
- if (Char == '/' || Char == '\\') {
- return OsPathJoin (FilePath, "..");
- }
-
- //
- //
- //
- for (Offset = Length; Offset > 0; Offset--) {
- if ((Return[Offset] == '/') || (Return[Offset] == '\\')) {
- Return[Offset] = '\0';
- return Return;
- }
- }
-}
-#endif
-
-
-#if 0
- //
- // BUGBUG: Not fully implemented yet.
- //
-
-/**
- This function returns the directory path which contains the particular path.
- Some examples:
- "a/b/../c" -> "a/c"
- "a/b//c" -> "a/b/c"
- "a/./b" -> "a/b"
-
- This function does not check for the existence of the file.
-
- @param Path Path name of file to normalize
-
- @return The string is altered in place.
-**/
-VOID
-OsPathNormPathInPlace (
- IN CHAR8 *Path
- )
-{
- CHAR8 *Pos;
- INTN Offset;
- BOOLEAN TryAgain;
- UINTN Length;
- UINTN Remaining;
- UINTN SubLength;
-
- do {
- TryAgain = FALSE;
- Length = strlen (Path);
-
- for (Offset = 0; Offset < Length; Offset++) {
- Remaining = Length - Offset;
-
- //
- // Collapse '//' -> '/'
- //
- if (
- (Remaining >= 2) &&
- ((Offset > 0) || (Path[0] != '\\')) &&
- IsDirSep (Path[Offset]) && IsDirSep (Path[Offset + 1])
- ) {
- memmove (&Path[Offset], &Path[Offset + 1], Remaining);
- TryAgain = TRUE;
- break;
- }
-
- //
- // Collapse '/./' -> '/'
- //
- if ((Remaining >= 3) && IsDirSep (Path[Offset]) &&
- (Path[Offset + 1] == '.') && IsDirSep (Path[Offset + 2])
- ) {
- memmove (&Path[Offset], &Path[Offset + 1], Remaining);
- TryAgain = TRUE;
- break;
- }
-
- //
- // Collapse 'a/../b' -> 'b'
- //
- // BUGBUG: Not implemented yet
-
- }
-
- } while (TryAgain);
-
- Return = CloneString (FilePath);
- if (Return == NULL) {
- return NULL;
- }
-
- Length = strlen (Return);
-
- //
- // Check for the root directory case
- //
- if (
- (Length == 3 && isalpha (Return[0]) && (strcmp(Return + 1, ":\\") == 0)) ||
- (strcmp(Return, "/") == 0)
- ) {
- free (Return);
- return NULL;
- }
-
- //
- //
- //
- for (Offset = Length; Offset > 0; Offset--) {
- if ((Return[Offset] == '/') || (Return[Offset] == '\\')) {
- Return[Offset] = '\0';
- return Return;
- }
- }
-}
-#endif
-
-/**
- This function replaces the final portion of a path with an alternative
- 'peer' filename. For example:
- "a/b/../c", "peer" -> "a/b/../peer"
- "a/b/", "peer" -> "a/b/peer"
- "/a", "peer" -> "/peer"
- "a", "peer" -> "peer"
-
- This function does not check for the existence of the file.
-
- @param OldPath Path name of replace the final segment
- @param Peer The new path name to concatenate to become the peer path
-
- @return A CHAR8* string, which must be freed by the caller
-**/
-CHAR8*
-OsPathPeerFilePath (
- IN CHAR8 *OldPath,
- IN CHAR8 *Peer
- )
-{
- CHAR8 *Result;
- INTN Offset;
-
- Result = (CHAR8 *) malloc (strlen (OldPath) + strlen (Peer) + 1);
- if (Result == NULL) {
- return NULL;
- }
-
- strcpy (Result, OldPath);
-
- //
- // Search for the last '/' or '\' in the string. If found, replace
- // everything following it with Peer
- //
- for (Offset = strlen (Result); Offset >= 0; Offset--) {
- if ((Result[Offset] == '/') || (Result[Offset] == '\\')) {
- Result[Offset + 1] = '\0';
- strcat (Result, Peer);
- return Result;
- }
- }
-
- //
- // Neither a '/' nor a '\' was found. Therefore, we simply return Peer.
- //
- strcpy (Result, Peer);
- return Result;
-}
-
-/**
- Checks if a file exists
-
- @param InputFileName The name of the file to check for existence
-
- @retval TRUE The file exists
- @retval FALSE The file does not exist
-**/
-BOOLEAN
-OsPathExists (
- IN CHAR8 *InputFileName
- )
-{
- FILE *InputFile;
- InputFile = fopen (LongFilePath (InputFileName), "rb");
- if (InputFile == NULL) {
- return FALSE;
- } else {
- fclose (InputFile);
- return TRUE;
- }
-}
-
-
-
+/** @file +Functions useful to operate file directories by parsing file path. + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include "CommonLib.h" +#include "OsPath.h" + +// +// Functions implementations +// + +#if 0 + // + // BUGBUG: Not fully implemented yet. + // + +/** + This function returns the directory path which contains the particular path. + Some examples: + "a/b/c" -> "a/b" + "a/b/c/" -> "a/b" + "a" -> "." + "." -> ".." + "/" -> NULL + + This function does not check for the existence of the file. + + The caller must free the string returned. + + @param FilePath Path name of file to get the parent directory for. + + @return NULL if error +**/ +CHAR8* +OsPathDirName ( + IN CHAR8 *FilePath + ) + +{ + CHAR8 *Return; + CHAR8 *Pos; + CHAR8 Char; + UINTN Length; + INTN Offset; + + Length = strlen (FilePath); + + if (Length == 0) { + return NULL; + } + + // + // Check for the root directory case + // + if ( + (Length == 3 && isalpha (FilePath[0]) && (strcmp(FilePath + 1, ":\\") == 0)) || + (strcmp(FilePath, "/") == 0) + ) { + return NULL; + } + + // + // If the path ends with a path separator, then just append ".." + // + Char = FilePath[Length - 1]; + if (Char == '/' || Char == '\\') { + return OsPathJoin (FilePath, ".."); + } + + // + // + // + for (Offset = Length; Offset > 0; Offset--) { + if ((Return[Offset] == '/') || (Return[Offset] == '\\')) { + Return[Offset] = '\0'; + return Return; + } + } +} +#endif + + +#if 0 + // + // BUGBUG: Not fully implemented yet. + // + +/** + This function returns the directory path which contains the particular path. + Some examples: + "a/b/../c" -> "a/c" + "a/b//c" -> "a/b/c" + "a/./b" -> "a/b" + + This function does not check for the existence of the file. + + @param Path Path name of file to normalize + + @return The string is altered in place. +**/ +VOID +OsPathNormPathInPlace ( + IN CHAR8 *Path + ) +{ + CHAR8 *Pos; + INTN Offset; + BOOLEAN TryAgain; + UINTN Length; + UINTN Remaining; + UINTN SubLength; + + do { + TryAgain = FALSE; + Length = strlen (Path); + + for (Offset = 0; Offset < Length; Offset++) { + Remaining = Length - Offset; + + // + // Collapse '//' -> '/' + // + if ( + (Remaining >= 2) && + ((Offset > 0) || (Path[0] != '\\')) && + IsDirSep (Path[Offset]) && IsDirSep (Path[Offset + 1]) + ) { + memmove (&Path[Offset], &Path[Offset + 1], Remaining); + TryAgain = TRUE; + break; + } + + // + // Collapse '/./' -> '/' + // + if ((Remaining >= 3) && IsDirSep (Path[Offset]) && + (Path[Offset + 1] == '.') && IsDirSep (Path[Offset + 2]) + ) { + memmove (&Path[Offset], &Path[Offset + 1], Remaining); + TryAgain = TRUE; + break; + } + + // + // Collapse 'a/../b' -> 'b' + // + // BUGBUG: Not implemented yet + + } + + } while (TryAgain); + + Return = CloneString (FilePath); + if (Return == NULL) { + return NULL; + } + + Length = strlen (Return); + + // + // Check for the root directory case + // + if ( + (Length == 3 && isalpha (Return[0]) && (strcmp(Return + 1, ":\\") == 0)) || + (strcmp(Return, "/") == 0) + ) { + free (Return); + return NULL; + } + + // + // + // + for (Offset = Length; Offset > 0; Offset--) { + if ((Return[Offset] == '/') || (Return[Offset] == '\\')) { + Return[Offset] = '\0'; + return Return; + } + } +} +#endif + +/** + This function replaces the final portion of a path with an alternative + 'peer' filename. For example: + "a/b/../c", "peer" -> "a/b/../peer" + "a/b/", "peer" -> "a/b/peer" + "/a", "peer" -> "/peer" + "a", "peer" -> "peer" + + This function does not check for the existence of the file. + + @param OldPath Path name of replace the final segment + @param Peer The new path name to concatenate to become the peer path + + @return A CHAR8* string, which must be freed by the caller +**/ +CHAR8* +OsPathPeerFilePath ( + IN CHAR8 *OldPath, + IN CHAR8 *Peer + ) +{ + CHAR8 *Result; + INTN Offset; + + Result = (CHAR8 *) malloc (strlen (OldPath) + strlen (Peer) + 1); + if (Result == NULL) { + return NULL; + } + + strcpy (Result, OldPath); + + // + // Search for the last '/' or '\' in the string. If found, replace + // everything following it with Peer + // + for (Offset = strlen (Result); Offset >= 0; Offset--) { + if ((Result[Offset] == '/') || (Result[Offset] == '\\')) { + Result[Offset + 1] = '\0'; + strcat (Result, Peer); + return Result; + } + } + + // + // Neither a '/' nor a '\' was found. Therefore, we simply return Peer. + // + strcpy (Result, Peer); + return Result; +} + +/** + Checks if a file exists + + @param InputFileName The name of the file to check for existence + + @retval TRUE The file exists + @retval FALSE The file does not exist +**/ +BOOLEAN +OsPathExists ( + IN CHAR8 *InputFileName + ) +{ + FILE *InputFile; + InputFile = fopen (LongFilePath (InputFileName), "rb"); + if (InputFile == NULL) { + return FALSE; + } else { + fclose (InputFile); + return TRUE; + } +} + + + diff --git a/BaseTools/Source/C/Common/OsPath.h b/BaseTools/Source/C/Common/OsPath.h index b1881c4a1e..7b17b6fbf2 100644 --- a/BaseTools/Source/C/Common/OsPath.h +++ b/BaseTools/Source/C/Common/OsPath.h @@ -1,97 +1,97 @@ -/** @file
-Header file for helper functions useful to operate file directories by parsing
-file path.
-
-Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _EFI_OS_PATH_H
-#define _EFI_OS_PATH_H
-
-#include <Common/UefiBaseTypes.h>
-
-//
-// Functions declarations
-//
-
-/**
- This function returns the directory path which contains the particular path.
- Some examples:
- "a/b/c" -> "a/b"
- "a/b/c/" -> "a/b"
- "a" -> "."
- "." -> ".."
- "/" -> NULL
-
- This function does not check for the existence of the file.
-
- The caller must free the string returned.
-
- @param FilePath Path name of file to get the parent directory for.
-
- @return NULL if error
-**/
-CHAR8*
-OsPathDirName (
- IN CHAR8 *FilePath
- )
-;
-
-/**
- This function returns the directory path which contains the particular path.
- Some examples:
- "a/b/../c" -> "a/c"
- "a/b//c" -> "a/b/c"
- "a/./b" -> "a/b"
-
- This function does not check for the existence of the file.
-
- @param Path Path name of file to normalize
-
- @return The string is altered in place.
-**/
-VOID
-OsPathNormPathInPlace (
- IN CHAR8 *Path
- )
-;
-
-/**
- This function replaces the final portion of a path with an alternative
- 'peer' filename. For example:
- "a/b/../c", "peer" -> "a/b/../peer"
- "a/b/", "peer" -> "a/b/peer"
- "/a", "peer" -> "/peer"
- "a", "peer" -> "peer"
-
- This function does not check for the existence of the file.
-
- @param OldPath Path name of replace the final segment
- @param Peer The new path name to concatenate to become the peer path
-
- @return A CHAR8* string, which must be freed by the caller
-**/
-CHAR8*
-OsPathPeerFilePath (
- IN CHAR8 *OldPath,
- IN CHAR8 *Peer
- )
-;
-
-/**
- Checks if a file exists
-
- @param InputFileName The name of the file to check for existence
-
- @retval TRUE The file exists
- @retval FALSE The file does not exist
-**/
-BOOLEAN
-OsPathExists (
- IN CHAR8 *InputFileName
- )
-;
-
-#endif
+/** @file +Header file for helper functions useful to operate file directories by parsing +file path. + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_OS_PATH_H +#define _EFI_OS_PATH_H + +#include <Common/UefiBaseTypes.h> + +// +// Functions declarations +// + +/** + This function returns the directory path which contains the particular path. + Some examples: + "a/b/c" -> "a/b" + "a/b/c/" -> "a/b" + "a" -> "." + "." -> ".." + "/" -> NULL + + This function does not check for the existence of the file. + + The caller must free the string returned. + + @param FilePath Path name of file to get the parent directory for. + + @return NULL if error +**/ +CHAR8* +OsPathDirName ( + IN CHAR8 *FilePath + ) +; + +/** + This function returns the directory path which contains the particular path. + Some examples: + "a/b/../c" -> "a/c" + "a/b//c" -> "a/b/c" + "a/./b" -> "a/b" + + This function does not check for the existence of the file. + + @param Path Path name of file to normalize + + @return The string is altered in place. +**/ +VOID +OsPathNormPathInPlace ( + IN CHAR8 *Path + ) +; + +/** + This function replaces the final portion of a path with an alternative + 'peer' filename. For example: + "a/b/../c", "peer" -> "a/b/../peer" + "a/b/", "peer" -> "a/b/peer" + "/a", "peer" -> "/peer" + "a", "peer" -> "peer" + + This function does not check for the existence of the file. + + @param OldPath Path name of replace the final segment + @param Peer The new path name to concatenate to become the peer path + + @return A CHAR8* string, which must be freed by the caller +**/ +CHAR8* +OsPathPeerFilePath ( + IN CHAR8 *OldPath, + IN CHAR8 *Peer + ) +; + +/** + Checks if a file exists + + @param InputFileName The name of the file to check for existence + + @retval TRUE The file exists + @retval FALSE The file does not exist +**/ +BOOLEAN +OsPathExists ( + IN CHAR8 *InputFileName + ) +; + +#endif diff --git a/BaseTools/Source/C/Common/ParseGuidedSectionTools.c b/BaseTools/Source/C/Common/ParseGuidedSectionTools.c index e1e9a97e7b..f274bc49d8 100644 --- a/BaseTools/Source/C/Common/ParseGuidedSectionTools.c +++ b/BaseTools/Source/C/Common/ParseGuidedSectionTools.c @@ -1,179 +1,179 @@ -/** @file
-Helper functions for parsing GuidedSectionTools.txt
-
-Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <assert.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include "MemoryFile.h"
-#include "CommonLib.h"
-#include "EfiUtilityMsgs.h"
-#include "ParseInf.h"
-#include "ParseGuidedSectionTools.h"
-#include "StringFuncs.h"
-
-
-//
-// Local types / structures
-//
-
-typedef struct _GUID_SEC_TOOL_ENTRY {
- EFI_GUID Guid;
- CHAR8* Name;
- CHAR8* Path;
- struct _GUID_SEC_TOOL_ENTRY *Next;
-} GUID_SEC_TOOL_ENTRY;
-
-//
-// Function Implementation
-//
-
-/**
- This function parses the tools_def.txt file. It returns a
- EFI_HANDLE object which can be used for the other library
- functions and should be passed to FreeParsedGuidedSectionToolsHandle
- to free resources when the tools_def.txt information is no
- longer needed.
-
- @param InputFile Path name of file to read
-
- @retval NULL if error parsing
- @retval A non-NULL EFI_HANDLE otherwise
-**/
-EFI_HANDLE
-ParseGuidedSectionToolsFile (
- IN CHAR8 *InputFile
- )
-{
- EFI_STATUS Status;
- EFI_HANDLE MemoryFile;
- EFI_HANDLE ParsedGuidedSectionTools;
-
- Status = GetMemoryFile (InputFile, &MemoryFile);
- if (EFI_ERROR (Status)) {
- return NULL;
- }
-
- ParsedGuidedSectionTools = ParseGuidedSectionToolsMemoryFile (MemoryFile);
-
- FreeMemoryFile (MemoryFile);
-
- return ParsedGuidedSectionTools;
-}
-
-/**
- This function parses the tools_def.txt file. It returns a
- EFI_HANDLE object which can be used for the other library
- functions and should be passed to FreeParsedGuidedSectionToolsHandle
- to free resources when the tools_def.txt information is no
- longer needed.
-
- @param InputFile Memory file image.
-
- @retval NULL if error or EOF
- @retval InputBuffer otherwise
-**/
-EFI_HANDLE
-ParseGuidedSectionToolsMemoryFile (
- IN EFI_HANDLE InputFile
- )
-{
- EFI_STATUS Status;
- CHAR8 *NextLine;
- STRING_LIST *Tool;
- EFI_GUID Guid;
- GUID_SEC_TOOL_ENTRY *FirstGuidTool;
- GUID_SEC_TOOL_ENTRY *LastGuidTool;
- GUID_SEC_TOOL_ENTRY *NewGuidTool;
-
- FirstGuidTool = NULL;
- LastGuidTool = NULL;
-
- while (TRUE) {
- NextLine = ReadMemoryFileLine (InputFile);
- if (NextLine == NULL) {
- break;
- }
-
- Status = StripInfDscStringInPlace (NextLine);
- if (EFI_ERROR (Status)) {
- free (NextLine);
- break;
- }
-
- if (NextLine[0] == '\0') {
- free (NextLine);
- continue;
- }
-
- Tool = SplitStringByWhitespace (NextLine);
- if ((Tool != NULL) &&
- (Tool->Count == 3)
- ) {
- Status = StringToGuid (Tool->Strings[0], &Guid);
- if (!EFI_ERROR (Status)) {
- NewGuidTool = malloc (sizeof (GUID_SEC_TOOL_ENTRY));
- if (NewGuidTool != NULL) {
- memcpy (&(NewGuidTool->Guid), &Guid, sizeof (Guid));
- NewGuidTool->Name = CloneString(Tool->Strings[1]);
- NewGuidTool->Path = CloneString(Tool->Strings[2]);
- NewGuidTool->Next = NULL;
-
- if (FirstGuidTool == NULL) {
- FirstGuidTool = NewGuidTool;
- } else {
- LastGuidTool->Next = NewGuidTool;
- }
- LastGuidTool = NewGuidTool;
- }
- }
- }
-
- if (Tool != NULL) {
- FreeStringList (Tool);
- }
- free (NextLine);
- }
-
- return FirstGuidTool;
-}
-
-/**
- This function looks up the appropriate tool to use for extracting
- a GUID defined FV section.
-
- @param ParsedGuidedSectionToolsHandle A parsed GUID section tools handle.
- @param SectionGuid The GUID for the section.
-
- @retval NULL if no tool is found or there is another error
- @retval Non-NULL The tool to use to access the section contents. (The caller
- must free the memory associated with this string.)
-**/
-CHAR8*
-LookupGuidedSectionToolPath (
- IN EFI_HANDLE ParsedGuidedSectionToolsHandle,
- IN EFI_GUID *SectionGuid
- )
-{
- GUID_SEC_TOOL_ENTRY *GuidTool;
-
- GuidTool = (GUID_SEC_TOOL_ENTRY*)ParsedGuidedSectionToolsHandle;
- if (GuidTool == NULL) {
- return NULL;
- }
-
- for ( ; GuidTool != NULL; GuidTool = GuidTool->Next) {
- if (CompareGuid (&(GuidTool->Guid), SectionGuid) == 0) {
- return CloneString (GuidTool->Path);
- }
- }
-
- return NULL;
-}
-
-
+/** @file +Helper functions for parsing GuidedSectionTools.txt + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <assert.h> +#include <string.h> +#include <ctype.h> +#include <stdlib.h> +#include "MemoryFile.h" +#include "CommonLib.h" +#include "EfiUtilityMsgs.h" +#include "ParseInf.h" +#include "ParseGuidedSectionTools.h" +#include "StringFuncs.h" + + +// +// Local types / structures +// + +typedef struct _GUID_SEC_TOOL_ENTRY { + EFI_GUID Guid; + CHAR8* Name; + CHAR8* Path; + struct _GUID_SEC_TOOL_ENTRY *Next; +} GUID_SEC_TOOL_ENTRY; + +// +// Function Implementation +// + +/** + This function parses the tools_def.txt file. It returns a + EFI_HANDLE object which can be used for the other library + functions and should be passed to FreeParsedGuidedSectionToolsHandle + to free resources when the tools_def.txt information is no + longer needed. + + @param InputFile Path name of file to read + + @retval NULL if error parsing + @retval A non-NULL EFI_HANDLE otherwise +**/ +EFI_HANDLE +ParseGuidedSectionToolsFile ( + IN CHAR8 *InputFile + ) +{ + EFI_STATUS Status; + EFI_HANDLE MemoryFile; + EFI_HANDLE ParsedGuidedSectionTools; + + Status = GetMemoryFile (InputFile, &MemoryFile); + if (EFI_ERROR (Status)) { + return NULL; + } + + ParsedGuidedSectionTools = ParseGuidedSectionToolsMemoryFile (MemoryFile); + + FreeMemoryFile (MemoryFile); + + return ParsedGuidedSectionTools; +} + +/** + This function parses the tools_def.txt file. It returns a + EFI_HANDLE object which can be used for the other library + functions and should be passed to FreeParsedGuidedSectionToolsHandle + to free resources when the tools_def.txt information is no + longer needed. + + @param InputFile Memory file image. + + @retval NULL if error or EOF + @retval InputBuffer otherwise +**/ +EFI_HANDLE +ParseGuidedSectionToolsMemoryFile ( + IN EFI_HANDLE InputFile + ) +{ + EFI_STATUS Status; + CHAR8 *NextLine; + STRING_LIST *Tool; + EFI_GUID Guid; + GUID_SEC_TOOL_ENTRY *FirstGuidTool; + GUID_SEC_TOOL_ENTRY *LastGuidTool; + GUID_SEC_TOOL_ENTRY *NewGuidTool; + + FirstGuidTool = NULL; + LastGuidTool = NULL; + + while (TRUE) { + NextLine = ReadMemoryFileLine (InputFile); + if (NextLine == NULL) { + break; + } + + Status = StripInfDscStringInPlace (NextLine); + if (EFI_ERROR (Status)) { + free (NextLine); + break; + } + + if (NextLine[0] == '\0') { + free (NextLine); + continue; + } + + Tool = SplitStringByWhitespace (NextLine); + if ((Tool != NULL) && + (Tool->Count == 3) + ) { + Status = StringToGuid (Tool->Strings[0], &Guid); + if (!EFI_ERROR (Status)) { + NewGuidTool = malloc (sizeof (GUID_SEC_TOOL_ENTRY)); + if (NewGuidTool != NULL) { + memcpy (&(NewGuidTool->Guid), &Guid, sizeof (Guid)); + NewGuidTool->Name = CloneString(Tool->Strings[1]); + NewGuidTool->Path = CloneString(Tool->Strings[2]); + NewGuidTool->Next = NULL; + + if (FirstGuidTool == NULL) { + FirstGuidTool = NewGuidTool; + } else { + LastGuidTool->Next = NewGuidTool; + } + LastGuidTool = NewGuidTool; + } + } + } + + if (Tool != NULL) { + FreeStringList (Tool); + } + free (NextLine); + } + + return FirstGuidTool; +} + +/** + This function looks up the appropriate tool to use for extracting + a GUID defined FV section. + + @param ParsedGuidedSectionToolsHandle A parsed GUID section tools handle. + @param SectionGuid The GUID for the section. + + @retval NULL if no tool is found or there is another error + @retval Non-NULL The tool to use to access the section contents. (The caller + must free the memory associated with this string.) +**/ +CHAR8* +LookupGuidedSectionToolPath ( + IN EFI_HANDLE ParsedGuidedSectionToolsHandle, + IN EFI_GUID *SectionGuid + ) +{ + GUID_SEC_TOOL_ENTRY *GuidTool; + + GuidTool = (GUID_SEC_TOOL_ENTRY*)ParsedGuidedSectionToolsHandle; + if (GuidTool == NULL) { + return NULL; + } + + for ( ; GuidTool != NULL; GuidTool = GuidTool->Next) { + if (CompareGuid (&(GuidTool->Guid), SectionGuid) == 0) { + return CloneString (GuidTool->Path); + } + } + + return NULL; +} + + diff --git a/BaseTools/Source/C/Common/ParseGuidedSectionTools.h b/BaseTools/Source/C/Common/ParseGuidedSectionTools.h index 2180bbd074..5c96ea6572 100644 --- a/BaseTools/Source/C/Common/ParseGuidedSectionTools.h +++ b/BaseTools/Source/C/Common/ParseGuidedSectionTools.h @@ -1,87 +1,87 @@ -/** @file
-Header file for helper functions for parsing GuidedSectionTools.txt
-
-Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _EFI_PARSE_GUIDED_SECTION_TOOLS_H
-#define _EFI_PARSE_GUIDED_SECTION_TOOLS_H
-
-#include <Common/UefiBaseTypes.h>
-
-//
-// Functions declarations
-//
-
-/**
- This function parses the tools_def.txt file. It returns a
- EFI_HANDLE object which can be used for the other library
- functions and should be passed to FreeParsedToolsDefHandle
- to free resources when the tools_def.txt information is no
- longer needed.
-
- @param InputFile Path name of file to read
-
- @retval NULL if error parsing
- @retval A non-NULL EFI_HANDLE otherwise
-**/
-EFI_HANDLE
-ParseGuidedSectionToolsFile (
- IN CHAR8 *InputFile
- )
-;
-
-/**
- This function parses the tools_def.txt file. It returns a
- EFI_HANDLE object which can be used for the other library
- functions and should be passed to FreeParsedToolsDefHandle
- to free resources when the tools_def.txt information is no
- longer needed.
-
- @param InputFile Memory file image.
-
- @retval NULL if error parsing
- @retval A non-NULL EFI_HANDLE otherwise
-**/
-EFI_HANDLE
-ParseGuidedSectionToolsMemoryFile (
- IN EFI_HANDLE InputFile
- )
-;
-
-/**
- This function looks up the appropriate tool to use for extracting
- a GUID defined FV section.
-
- @param ParsedGuidedSectionToolsHandle A parsed GUID section tools handle.
- @param SectionGuid The GUID for the section.
-
- @retval NULL if no tool is found or there is another error
- @retval Non-NULL The tool to use to access the section contents. (The caller
- must free the memory associated with this string.)
-**/
-CHAR8*
-LookupGuidedSectionToolPath (
- IN EFI_HANDLE ParsedGuidedSectionToolsHandle,
- IN EFI_GUID *SectionGuid
- )
-;
-
-/**
- Frees resources that were allocated by ParseGuidedSectionToolsFile.
- After freeing these resources, the information that was parsed
- is no longer accessible.
-
- @param ParsedToolDefHandle Handle returned from ParseGuidedSectionToolsFile
-
- @return EFI_STATUS
-**/
-EFI_STATUS
-FreeParsedGuidedSectionToolsHandle (
- IN EFI_HANDLE ParsedGuidedSectionToolsHandle
- )
-;
-
-#endif
+/** @file +Header file for helper functions for parsing GuidedSectionTools.txt + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_PARSE_GUIDED_SECTION_TOOLS_H +#define _EFI_PARSE_GUIDED_SECTION_TOOLS_H + +#include <Common/UefiBaseTypes.h> + +// +// Functions declarations +// + +/** + This function parses the tools_def.txt file. It returns a + EFI_HANDLE object which can be used for the other library + functions and should be passed to FreeParsedToolsDefHandle + to free resources when the tools_def.txt information is no + longer needed. + + @param InputFile Path name of file to read + + @retval NULL if error parsing + @retval A non-NULL EFI_HANDLE otherwise +**/ +EFI_HANDLE +ParseGuidedSectionToolsFile ( + IN CHAR8 *InputFile + ) +; + +/** + This function parses the tools_def.txt file. It returns a + EFI_HANDLE object which can be used for the other library + functions and should be passed to FreeParsedToolsDefHandle + to free resources when the tools_def.txt information is no + longer needed. + + @param InputFile Memory file image. + + @retval NULL if error parsing + @retval A non-NULL EFI_HANDLE otherwise +**/ +EFI_HANDLE +ParseGuidedSectionToolsMemoryFile ( + IN EFI_HANDLE InputFile + ) +; + +/** + This function looks up the appropriate tool to use for extracting + a GUID defined FV section. + + @param ParsedGuidedSectionToolsHandle A parsed GUID section tools handle. + @param SectionGuid The GUID for the section. + + @retval NULL if no tool is found or there is another error + @retval Non-NULL The tool to use to access the section contents. (The caller + must free the memory associated with this string.) +**/ +CHAR8* +LookupGuidedSectionToolPath ( + IN EFI_HANDLE ParsedGuidedSectionToolsHandle, + IN EFI_GUID *SectionGuid + ) +; + +/** + Frees resources that were allocated by ParseGuidedSectionToolsFile. + After freeing these resources, the information that was parsed + is no longer accessible. + + @param ParsedToolDefHandle Handle returned from ParseGuidedSectionToolsFile + + @return EFI_STATUS +**/ +EFI_STATUS +FreeParsedGuidedSectionToolsHandle ( + IN EFI_HANDLE ParsedGuidedSectionToolsHandle + ) +; + +#endif diff --git a/BaseTools/Source/C/Common/ParseInf.c b/BaseTools/Source/C/Common/ParseInf.c index 63da3d647c..ca3c4142b9 100644 --- a/BaseTools/Source/C/Common/ParseInf.c +++ b/BaseTools/Source/C/Common/ParseInf.c @@ -1,640 +1,640 @@ -/** @file
-This contains some useful functions for parsing INF files.
-
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <assert.h>
-#include <string.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include "EfiUtilityMsgs.h"
-#include "ParseInf.h"
-#include "CommonLib.h"
-
-/**
- This function reads a line, stripping any comments.
- The function reads a string from the input stream argument and stores it in
- the input string. ReadLine reads characters from the current file position
- to and including the first newline character, to the end of the stream, or
- until the number of characters read is equal to MaxLength - 1, whichever
- comes first. The newline character, if read, is replaced with a \0.
-
- @param InputFile Memory file image.
- @param InputBuffer Buffer to read into, must be MaxLength size.
- @param MaxLength The maximum size of the input buffer.
-
- @retval NULL if error or EOF
- @retval InputBuffer otherwise
-**/
-CHAR8 *
-ReadLine (
- IN MEMORY_FILE *InputFile,
- IN OUT CHAR8 *InputBuffer,
- IN UINTN MaxLength
- )
-
-{
- CHAR8 *CharPtr;
- CHAR8 *EndOfLine;
- UINTN CharsToCopy;
-
- //
- // Verify input parameters are not null
- //
- assert (InputBuffer);
- assert (InputFile->FileImage);
- assert (InputFile->Eof);
- assert (InputFile->CurrentFilePointer);
-
- //
- // Check for end of file condition
- //
- if (InputFile->CurrentFilePointer >= InputFile->Eof) {
- return NULL;
- }
- //
- // Find the next newline char
- //
- EndOfLine = strchr (InputFile->CurrentFilePointer, '\n');
-
- //
- // Determine the number of characters to copy.
- //
- if (EndOfLine == 0) {
- //
- // If no newline found, copy to the end of the file.
- //
- CharsToCopy = InputFile->Eof - InputFile->CurrentFilePointer;
- } else if (EndOfLine >= InputFile->Eof) {
- //
- // If the newline found was beyond the end of file, copy to the eof.
- //
- CharsToCopy = InputFile->Eof - InputFile->CurrentFilePointer;
- } else {
- //
- // Newline found in the file.
- //
- CharsToCopy = EndOfLine - InputFile->CurrentFilePointer;
- }
- //
- // If the end of line is too big for the current buffer, set it to the max
- // size of the buffer (leaving room for the \0.
- //
- if (CharsToCopy > MaxLength - 1) {
- CharsToCopy = MaxLength - 1;
- }
- //
- // Copy the line.
- //
- memcpy (InputBuffer, InputFile->CurrentFilePointer, CharsToCopy);
-
- //
- // Add the null termination over the 0x0D
- //
- if (InputBuffer[CharsToCopy - 1] == '\r') {
-
- InputBuffer[CharsToCopy - 1] = '\0';
-
- } else {
-
- InputBuffer[CharsToCopy] = '\0';
-
- }
-
- //
- // Increment the current file pointer (include the 0x0A)
- //
- InputFile->CurrentFilePointer += CharsToCopy + 1;
-
- //
- // Strip any comments
- //
- CharPtr = strstr (InputBuffer, "//");
- if (CharPtr != 0) {
- CharPtr[0] = 0;
- }
- //
- // Return the string
- //
- return InputBuffer;
-}
-
-/**
- This function parses a file from the beginning to find a section.
- The section string may be anywhere within a line.
-
- @param InputFile Memory file image.
- @param Section Section to search for
-
- @retval FALSE if error or EOF
- @retval TRUE if section found
-**/
-BOOLEAN
-FindSection (
- IN MEMORY_FILE *InputFile,
- IN CHAR8 *Section
- )
-{
- CHAR8 InputBuffer[MAX_LONG_FILE_PATH];
- CHAR8 *CurrentToken;
-
- //
- // Verify input is not NULL
- //
- assert (InputFile->FileImage);
- assert (InputFile->Eof);
- assert (InputFile->CurrentFilePointer);
- assert (Section);
-
- //
- // Rewind to beginning of file
- //
- InputFile->CurrentFilePointer = InputFile->FileImage;
-
- //
- // Read lines until the section is found
- //
- while (InputFile->CurrentFilePointer < InputFile->Eof) {
- //
- // Read a line
- //
- ReadLine (InputFile, InputBuffer, MAX_LONG_FILE_PATH);
-
- //
- // Check if the section is found
- //
- CurrentToken = strstr (InputBuffer, Section);
- if (CurrentToken != NULL) {
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-/**
- Finds a token value given the section and token to search for.
-
- @param InputFile Memory file image.
- @param Section The section to search for, a string within [].
- @param Token The token to search for, e.g. EFI_PEIM_RECOVERY, followed by an = in the INF file.
- @param Instance The instance of the token to search for. Zero is the first instance.
- @param Value The string that holds the value following the =. Must be MAX_LONG_FILE_PATH in size.
-
- @retval EFI_SUCCESS Value found.
- @retval EFI_ABORTED Format error detected in INF file.
- @retval EFI_INVALID_PARAMETER Input argument was null.
- @retval EFI_LOAD_ERROR Error reading from the file.
- @retval EFI_NOT_FOUND Section/Token/Value not found.
-**/
-EFI_STATUS
-FindToken (
- IN MEMORY_FILE *InputFile,
- IN CHAR8 *Section,
- IN CHAR8 *Token,
- IN UINTN Instance,
- OUT CHAR8 *Value
- )
-{
- CHAR8 InputBuffer[MAX_LONG_FILE_PATH];
- CHAR8 *CurrentToken;
- CHAR8 *Delimiter;
- BOOLEAN ParseError;
- BOOLEAN ReadError;
- UINTN Occurrence;
-
- //
- // Check input parameters
- //
- if (InputFile->FileImage == NULL ||
- InputFile->Eof == NULL ||
- InputFile->CurrentFilePointer == NULL ||
- Section == NULL ||
- strlen (Section) == 0 ||
- Token == NULL ||
- strlen (Token) == 0 ||
- Value == NULL
- ) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Initialize error codes
- //
- ParseError = FALSE;
- ReadError = FALSE;
-
- //
- // Initialize our instance counter for the search token
- //
- Occurrence = 0;
-
- if (FindSection (InputFile, Section)) {
- //
- // Found the desired section, find and read the desired token
- //
- do {
- //
- // Read a line from the file
- //
- if (ReadLine (InputFile, InputBuffer, MAX_LONG_FILE_PATH) == NULL) {
- //
- // Error reading from input file
- //
- ReadError = TRUE;
- break;
- }
- //
- // Get the first non-whitespace string
- //
- Delimiter = strchr (InputBuffer, '=');
- if (Delimiter != NULL) {
- *Delimiter = 0;
- }
-
- CurrentToken = strtok (InputBuffer, " \t\n");
- if (CurrentToken == NULL || Delimiter == NULL) {
- //
- // Whitespace line found (or comment) so continue
- //
- CurrentToken = InputBuffer;
- continue;
- }
- //
- // Make sure we have not reached the end of the current section
- //
- if (CurrentToken[0] == '[') {
- break;
- }
- //
- // Compare the current token with the desired token
- //
- if (strcmp (CurrentToken, Token) == 0) {
- //
- // Found it
- //
- //
- // Check if it is the correct instance
- //
- if (Instance == Occurrence) {
- //
- // Copy the contents following the =
- //
- CurrentToken = Delimiter + 1;
- if (*CurrentToken == 0) {
- //
- // Nothing found, parsing error
- //
- ParseError = TRUE;
- } else {
- //
- // Strip leading white space
- //
- while (*CurrentToken == ' ' || *CurrentToken == '\t') {
- CurrentToken++;
- }
- //
- // Copy the current token to the output value
- //
- strcpy (Value, CurrentToken);
- //
- // Strip trailing white space
- //
- while (strlen(Value) > 0 && (*(Value + strlen(Value) - 1) == ' ' || *(Value + strlen(Value) - 1) == '\t')) {
- *(Value + strlen(Value) - 1) = 0;
- }
- return EFI_SUCCESS;
- }
- } else {
- //
- // Increment the occurrence found
- //
- Occurrence++;
- }
- }
- } while (
- !ParseError &&
- !ReadError &&
- InputFile->CurrentFilePointer < InputFile->Eof &&
- CurrentToken[0] != '[' &&
- Occurrence <= Instance
- );
- }
- //
- // Distinguish between read errors and INF file format errors.
- //
- if (ReadError) {
- return EFI_LOAD_ERROR;
- }
-
- if (ParseError) {
- return EFI_ABORTED;
- }
-
- return EFI_NOT_FOUND;
-}
-
-/**
- Converts a string to an EFI_GUID. The string must be in the
- xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format.
-
- @param AsciiGuidBuffer pointer to ascii string
- @param GuidBuffer pointer to destination Guid
-
- @retval EFI_ABORTED Could not convert the string
- @retval EFI_SUCCESS The string was successfully converted
- @retval EFI_INVALID_PARAMETER Input parameter is invalid.
-**/
-EFI_STATUS
-StringToGuid (
- IN CHAR8 *AsciiGuidBuffer,
- OUT EFI_GUID *GuidBuffer
- )
-{
- INT32 Index;
- int Data1;
- int Data2;
- int Data3;
- int Data4[8];
-
- if (AsciiGuidBuffer == NULL || GuidBuffer == NULL) {
- return EFI_INVALID_PARAMETER;
- }
- //
- // Check Guid Format strictly xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
- //
- for (Index = 0; AsciiGuidBuffer[Index] != '\0' && Index < 37; Index ++) {
- if (Index == 8 || Index == 13 || Index == 18 || Index == 23) {
- if (AsciiGuidBuffer[Index] != '-') {
- break;
- }
- } else {
- if (((AsciiGuidBuffer[Index] >= '0') && (AsciiGuidBuffer[Index] <= '9')) ||
- ((AsciiGuidBuffer[Index] >= 'a') && (AsciiGuidBuffer[Index] <= 'f')) ||
- ((AsciiGuidBuffer[Index] >= 'A') && (AsciiGuidBuffer[Index] <= 'F'))) {
- continue;
- } else {
- break;
- }
- }
- }
-
- if (Index < 36 || AsciiGuidBuffer[36] != '\0') {
- Error (NULL, 0, 1003, "Invalid option value", "Incorrect GUID \"%s\"\n Correct Format \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"", AsciiGuidBuffer);
- return EFI_ABORTED;
- }
-
- //
- // Scan the guid string into the buffer
- //
- Index = sscanf (
- AsciiGuidBuffer,
- "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
- &Data1,
- &Data2,
- &Data3,
- &Data4[0],
- &Data4[1],
- &Data4[2],
- &Data4[3],
- &Data4[4],
- &Data4[5],
- &Data4[6],
- &Data4[7]
- );
-
- //
- // Verify the correct number of items were scanned.
- //
- if (Index != 11) {
- Error (NULL, 0, 1003, "Invalid option value", "Incorrect GUID \"%s\"\n Correct Format \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"", AsciiGuidBuffer);
- return EFI_ABORTED;
- }
- //
- // Copy the data into our GUID.
- //
- GuidBuffer->Data1 = (UINT32) Data1;
- GuidBuffer->Data2 = (UINT16) Data2;
- GuidBuffer->Data3 = (UINT16) Data3;
- GuidBuffer->Data4[0] = (UINT8) Data4[0];
- GuidBuffer->Data4[1] = (UINT8) Data4[1];
- GuidBuffer->Data4[2] = (UINT8) Data4[2];
- GuidBuffer->Data4[3] = (UINT8) Data4[3];
- GuidBuffer->Data4[4] = (UINT8) Data4[4];
- GuidBuffer->Data4[5] = (UINT8) Data4[5];
- GuidBuffer->Data4[6] = (UINT8) Data4[6];
- GuidBuffer->Data4[7] = (UINT8) Data4[7];
-
- return EFI_SUCCESS;
-}
-
-/**
- Converts a null terminated ascii string that represents a number into a
- UINT64 value. A hex number may be preceded by a 0x, but may not be
- succeeded by an h. A number without 0x or 0X is considered to be base 10
- unless the IsHex input is true.
-
- @param AsciiString The string to convert.
- @param IsHex Force the string to be treated as a hex number.
- @param ReturnValue The return value.
-
- @retval EFI_SUCCESS Number successfully converted.
- @retval EFI_ABORTED Invalid character encountered.
-**/
-EFI_STATUS
-AsciiStringToUint64 (
- IN CONST CHAR8 *AsciiString,
- IN BOOLEAN IsHex,
- OUT UINT64 *ReturnValue
- )
-{
- UINT8 Index;
- UINT64 Value;
- CHAR8 CurrentChar;
-
- //
- // Initialize the result
- //
- Value = 0;
- Index = 0;
-
- //
- // Check input parameter
- //
- if (AsciiString == NULL || ReturnValue == NULL || strlen(AsciiString) > 0xFF) {
- return EFI_INVALID_PARAMETER;
- }
- while (AsciiString[Index] == ' ') {
- Index ++;
- }
-
- //
- // Add each character to the result
- //
-
- //
- // Skip first two chars only if the string starts with '0x' or '0X'
- //
- if (AsciiString[Index] == '0' && (AsciiString[Index + 1] == 'x' || AsciiString[Index + 1] == 'X')) {
- IsHex = TRUE;
- Index += 2;
- }
- if (IsHex) {
- //
- // Convert the hex string.
- //
- for (; AsciiString[Index] != '\0'; Index++) {
- CurrentChar = AsciiString[Index];
- if (CurrentChar == ' ') {
- break;
- }
- //
- // Verify Hex string
- //
- if (isxdigit ((int)CurrentChar) == 0) {
- return EFI_ABORTED;
- }
- //
- // Add hex value
- //
- Value *= 16;
- if (CurrentChar >= '0' && CurrentChar <= '9') {
- Value += CurrentChar - '0';
- } else if (CurrentChar >= 'a' && CurrentChar <= 'f') {
- Value += CurrentChar - 'a' + 10;
- } else if (CurrentChar >= 'A' && CurrentChar <= 'F') {
- Value += CurrentChar - 'A' + 10;
- }
- }
-
- *ReturnValue = Value;
- } else {
- //
- // Convert dec string is a number
- //
- for (; Index < strlen (AsciiString); Index++) {
- CurrentChar = AsciiString[Index];
- if (CurrentChar == ' ') {
- break;
- }
- //
- // Verify Dec string
- //
- if (isdigit ((int)CurrentChar) == 0) {
- return EFI_ABORTED;
- }
- //
- // Add dec value
- //
- Value = Value * 10;
- Value += CurrentChar - '0';
- }
-
- *ReturnValue = Value;
- }
-
- return EFI_SUCCESS;
-}
-
-/**
- This function reads a line, stripping any comments.
- // BUGBUG: This is obsolete once genmake goes away...
-
- @param InputFile Stream pointer.
- @param InputBuffer Buffer to read into, must be MAX_LONG_FILE_PATH size.
-
- @retval NULL if error or EOF
- @retval InputBuffer otherwise
-**/
-CHAR8 *
-ReadLineInStream (
- IN FILE *InputFile,
- IN OUT CHAR8 *InputBuffer
- )
-{
- CHAR8 *CharPtr;
-
- //
- // Verify input parameters are not null
- //
- assert (InputFile);
- assert (InputBuffer);
-
- //
- // Read a line
- //
- if (fgets (InputBuffer, MAX_LONG_FILE_PATH, InputFile) == NULL) {
- return NULL;
- }
- //
- // Strip any comments
- //
- CharPtr = strstr (InputBuffer, "//");
- if (CharPtr != 0) {
- CharPtr[0] = 0;
- }
-
- CharPtr = strstr (InputBuffer, "#");
- if (CharPtr != 0) {
- CharPtr[0] = 0;
- }
- //
- // Return the string
- //
- return InputBuffer;
-}
-
-/**
- This function parses a stream file from the beginning to find a section.
- The section string may be anywhere within a line.
- // BUGBUG: This is obsolete once genmake goes away...
-
- @param InputFile Stream pointer.
- @param Section Section to search for
-
- @retval FALSE if error or EOF
- @retval TRUE if section found
-**/
-BOOLEAN
-FindSectionInStream (
- IN FILE *InputFile,
- IN CHAR8 *Section
- )
-{
- CHAR8 InputBuffer[MAX_LONG_FILE_PATH];
- CHAR8 *CurrentToken;
-
- //
- // Verify input is not NULL
- //
- assert (InputFile);
- assert (Section);
-
- //
- // Rewind to beginning of file
- //
- if (fseek (InputFile, 0, SEEK_SET) != 0) {
- return FALSE;
- }
- //
- // Read lines until the section is found
- //
- while (feof (InputFile) == 0) {
- //
- // Read a line
- //
- ReadLineInStream (InputFile, InputBuffer);
-
- //
- // Check if the section is found
- //
- CurrentToken = strstr (InputBuffer, Section);
- if (CurrentToken != NULL) {
- return TRUE;
- }
- }
-
- return FALSE;
-}
+/** @file +This contains some useful functions for parsing INF files. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <assert.h> +#include <string.h> +#include <ctype.h> +#include <stdlib.h> +#include "EfiUtilityMsgs.h" +#include "ParseInf.h" +#include "CommonLib.h" + +/** + This function reads a line, stripping any comments. + The function reads a string from the input stream argument and stores it in + the input string. ReadLine reads characters from the current file position + to and including the first newline character, to the end of the stream, or + until the number of characters read is equal to MaxLength - 1, whichever + comes first. The newline character, if read, is replaced with a \0. + + @param InputFile Memory file image. + @param InputBuffer Buffer to read into, must be MaxLength size. + @param MaxLength The maximum size of the input buffer. + + @retval NULL if error or EOF + @retval InputBuffer otherwise +**/ +CHAR8 * +ReadLine ( + IN MEMORY_FILE *InputFile, + IN OUT CHAR8 *InputBuffer, + IN UINTN MaxLength + ) + +{ + CHAR8 *CharPtr; + CHAR8 *EndOfLine; + UINTN CharsToCopy; + + // + // Verify input parameters are not null + // + assert (InputBuffer); + assert (InputFile->FileImage); + assert (InputFile->Eof); + assert (InputFile->CurrentFilePointer); + + // + // Check for end of file condition + // + if (InputFile->CurrentFilePointer >= InputFile->Eof) { + return NULL; + } + // + // Find the next newline char + // + EndOfLine = strchr (InputFile->CurrentFilePointer, '\n'); + + // + // Determine the number of characters to copy. + // + if (EndOfLine == 0) { + // + // If no newline found, copy to the end of the file. + // + CharsToCopy = InputFile->Eof - InputFile->CurrentFilePointer; + } else if (EndOfLine >= InputFile->Eof) { + // + // If the newline found was beyond the end of file, copy to the eof. + // + CharsToCopy = InputFile->Eof - InputFile->CurrentFilePointer; + } else { + // + // Newline found in the file. + // + CharsToCopy = EndOfLine - InputFile->CurrentFilePointer; + } + // + // If the end of line is too big for the current buffer, set it to the max + // size of the buffer (leaving room for the \0. + // + if (CharsToCopy > MaxLength - 1) { + CharsToCopy = MaxLength - 1; + } + // + // Copy the line. + // + memcpy (InputBuffer, InputFile->CurrentFilePointer, CharsToCopy); + + // + // Add the null termination over the 0x0D + // + if (InputBuffer[CharsToCopy - 1] == '\r') { + + InputBuffer[CharsToCopy - 1] = '\0'; + + } else { + + InputBuffer[CharsToCopy] = '\0'; + + } + + // + // Increment the current file pointer (include the 0x0A) + // + InputFile->CurrentFilePointer += CharsToCopy + 1; + + // + // Strip any comments + // + CharPtr = strstr (InputBuffer, "//"); + if (CharPtr != 0) { + CharPtr[0] = 0; + } + // + // Return the string + // + return InputBuffer; +} + +/** + This function parses a file from the beginning to find a section. + The section string may be anywhere within a line. + + @param InputFile Memory file image. + @param Section Section to search for + + @retval FALSE if error or EOF + @retval TRUE if section found +**/ +BOOLEAN +FindSection ( + IN MEMORY_FILE *InputFile, + IN CHAR8 *Section + ) +{ + CHAR8 InputBuffer[MAX_LONG_FILE_PATH]; + CHAR8 *CurrentToken; + + // + // Verify input is not NULL + // + assert (InputFile->FileImage); + assert (InputFile->Eof); + assert (InputFile->CurrentFilePointer); + assert (Section); + + // + // Rewind to beginning of file + // + InputFile->CurrentFilePointer = InputFile->FileImage; + + // + // Read lines until the section is found + // + while (InputFile->CurrentFilePointer < InputFile->Eof) { + // + // Read a line + // + ReadLine (InputFile, InputBuffer, MAX_LONG_FILE_PATH); + + // + // Check if the section is found + // + CurrentToken = strstr (InputBuffer, Section); + if (CurrentToken != NULL) { + return TRUE; + } + } + + return FALSE; +} + +/** + Finds a token value given the section and token to search for. + + @param InputFile Memory file image. + @param Section The section to search for, a string within []. + @param Token The token to search for, e.g. EFI_PEIM_RECOVERY, followed by an = in the INF file. + @param Instance The instance of the token to search for. Zero is the first instance. + @param Value The string that holds the value following the =. Must be MAX_LONG_FILE_PATH in size. + + @retval EFI_SUCCESS Value found. + @retval EFI_ABORTED Format error detected in INF file. + @retval EFI_INVALID_PARAMETER Input argument was null. + @retval EFI_LOAD_ERROR Error reading from the file. + @retval EFI_NOT_FOUND Section/Token/Value not found. +**/ +EFI_STATUS +FindToken ( + IN MEMORY_FILE *InputFile, + IN CHAR8 *Section, + IN CHAR8 *Token, + IN UINTN Instance, + OUT CHAR8 *Value + ) +{ + CHAR8 InputBuffer[MAX_LONG_FILE_PATH]; + CHAR8 *CurrentToken; + CHAR8 *Delimiter; + BOOLEAN ParseError; + BOOLEAN ReadError; + UINTN Occurrence; + + // + // Check input parameters + // + if (InputFile->FileImage == NULL || + InputFile->Eof == NULL || + InputFile->CurrentFilePointer == NULL || + Section == NULL || + strlen (Section) == 0 || + Token == NULL || + strlen (Token) == 0 || + Value == NULL + ) { + return EFI_INVALID_PARAMETER; + } + // + // Initialize error codes + // + ParseError = FALSE; + ReadError = FALSE; + + // + // Initialize our instance counter for the search token + // + Occurrence = 0; + + if (FindSection (InputFile, Section)) { + // + // Found the desired section, find and read the desired token + // + do { + // + // Read a line from the file + // + if (ReadLine (InputFile, InputBuffer, MAX_LONG_FILE_PATH) == NULL) { + // + // Error reading from input file + // + ReadError = TRUE; + break; + } + // + // Get the first non-whitespace string + // + Delimiter = strchr (InputBuffer, '='); + if (Delimiter != NULL) { + *Delimiter = 0; + } + + CurrentToken = strtok (InputBuffer, " \t\n"); + if (CurrentToken == NULL || Delimiter == NULL) { + // + // Whitespace line found (or comment) so continue + // + CurrentToken = InputBuffer; + continue; + } + // + // Make sure we have not reached the end of the current section + // + if (CurrentToken[0] == '[') { + break; + } + // + // Compare the current token with the desired token + // + if (strcmp (CurrentToken, Token) == 0) { + // + // Found it + // + // + // Check if it is the correct instance + // + if (Instance == Occurrence) { + // + // Copy the contents following the = + // + CurrentToken = Delimiter + 1; + if (*CurrentToken == 0) { + // + // Nothing found, parsing error + // + ParseError = TRUE; + } else { + // + // Strip leading white space + // + while (*CurrentToken == ' ' || *CurrentToken == '\t') { + CurrentToken++; + } + // + // Copy the current token to the output value + // + strcpy (Value, CurrentToken); + // + // Strip trailing white space + // + while (strlen(Value) > 0 && (*(Value + strlen(Value) - 1) == ' ' || *(Value + strlen(Value) - 1) == '\t')) { + *(Value + strlen(Value) - 1) = 0; + } + return EFI_SUCCESS; + } + } else { + // + // Increment the occurrence found + // + Occurrence++; + } + } + } while ( + !ParseError && + !ReadError && + InputFile->CurrentFilePointer < InputFile->Eof && + CurrentToken[0] != '[' && + Occurrence <= Instance + ); + } + // + // Distinguish between read errors and INF file format errors. + // + if (ReadError) { + return EFI_LOAD_ERROR; + } + + if (ParseError) { + return EFI_ABORTED; + } + + return EFI_NOT_FOUND; +} + +/** + Converts a string to an EFI_GUID. The string must be in the + xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format. + + @param AsciiGuidBuffer pointer to ascii string + @param GuidBuffer pointer to destination Guid + + @retval EFI_ABORTED Could not convert the string + @retval EFI_SUCCESS The string was successfully converted + @retval EFI_INVALID_PARAMETER Input parameter is invalid. +**/ +EFI_STATUS +StringToGuid ( + IN CHAR8 *AsciiGuidBuffer, + OUT EFI_GUID *GuidBuffer + ) +{ + INT32 Index; + int Data1; + int Data2; + int Data3; + int Data4[8]; + + if (AsciiGuidBuffer == NULL || GuidBuffer == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Check Guid Format strictly xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx + // + for (Index = 0; AsciiGuidBuffer[Index] != '\0' && Index < 37; Index ++) { + if (Index == 8 || Index == 13 || Index == 18 || Index == 23) { + if (AsciiGuidBuffer[Index] != '-') { + break; + } + } else { + if (((AsciiGuidBuffer[Index] >= '0') && (AsciiGuidBuffer[Index] <= '9')) || + ((AsciiGuidBuffer[Index] >= 'a') && (AsciiGuidBuffer[Index] <= 'f')) || + ((AsciiGuidBuffer[Index] >= 'A') && (AsciiGuidBuffer[Index] <= 'F'))) { + continue; + } else { + break; + } + } + } + + if (Index < 36 || AsciiGuidBuffer[36] != '\0') { + Error (NULL, 0, 1003, "Invalid option value", "Incorrect GUID \"%s\"\n Correct Format \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"", AsciiGuidBuffer); + return EFI_ABORTED; + } + + // + // Scan the guid string into the buffer + // + Index = sscanf ( + AsciiGuidBuffer, + "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", + &Data1, + &Data2, + &Data3, + &Data4[0], + &Data4[1], + &Data4[2], + &Data4[3], + &Data4[4], + &Data4[5], + &Data4[6], + &Data4[7] + ); + + // + // Verify the correct number of items were scanned. + // + if (Index != 11) { + Error (NULL, 0, 1003, "Invalid option value", "Incorrect GUID \"%s\"\n Correct Format \"xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\"", AsciiGuidBuffer); + return EFI_ABORTED; + } + // + // Copy the data into our GUID. + // + GuidBuffer->Data1 = (UINT32) Data1; + GuidBuffer->Data2 = (UINT16) Data2; + GuidBuffer->Data3 = (UINT16) Data3; + GuidBuffer->Data4[0] = (UINT8) Data4[0]; + GuidBuffer->Data4[1] = (UINT8) Data4[1]; + GuidBuffer->Data4[2] = (UINT8) Data4[2]; + GuidBuffer->Data4[3] = (UINT8) Data4[3]; + GuidBuffer->Data4[4] = (UINT8) Data4[4]; + GuidBuffer->Data4[5] = (UINT8) Data4[5]; + GuidBuffer->Data4[6] = (UINT8) Data4[6]; + GuidBuffer->Data4[7] = (UINT8) Data4[7]; + + return EFI_SUCCESS; +} + +/** + Converts a null terminated ascii string that represents a number into a + UINT64 value. A hex number may be preceded by a 0x, but may not be + succeeded by an h. A number without 0x or 0X is considered to be base 10 + unless the IsHex input is true. + + @param AsciiString The string to convert. + @param IsHex Force the string to be treated as a hex number. + @param ReturnValue The return value. + + @retval EFI_SUCCESS Number successfully converted. + @retval EFI_ABORTED Invalid character encountered. +**/ +EFI_STATUS +AsciiStringToUint64 ( + IN CONST CHAR8 *AsciiString, + IN BOOLEAN IsHex, + OUT UINT64 *ReturnValue + ) +{ + UINT8 Index; + UINT64 Value; + CHAR8 CurrentChar; + + // + // Initialize the result + // + Value = 0; + Index = 0; + + // + // Check input parameter + // + if (AsciiString == NULL || ReturnValue == NULL || strlen(AsciiString) > 0xFF) { + return EFI_INVALID_PARAMETER; + } + while (AsciiString[Index] == ' ') { + Index ++; + } + + // + // Add each character to the result + // + + // + // Skip first two chars only if the string starts with '0x' or '0X' + // + if (AsciiString[Index] == '0' && (AsciiString[Index + 1] == 'x' || AsciiString[Index + 1] == 'X')) { + IsHex = TRUE; + Index += 2; + } + if (IsHex) { + // + // Convert the hex string. + // + for (; AsciiString[Index] != '\0'; Index++) { + CurrentChar = AsciiString[Index]; + if (CurrentChar == ' ') { + break; + } + // + // Verify Hex string + // + if (isxdigit ((int)CurrentChar) == 0) { + return EFI_ABORTED; + } + // + // Add hex value + // + Value *= 16; + if (CurrentChar >= '0' && CurrentChar <= '9') { + Value += CurrentChar - '0'; + } else if (CurrentChar >= 'a' && CurrentChar <= 'f') { + Value += CurrentChar - 'a' + 10; + } else if (CurrentChar >= 'A' && CurrentChar <= 'F') { + Value += CurrentChar - 'A' + 10; + } + } + + *ReturnValue = Value; + } else { + // + // Convert dec string is a number + // + for (; Index < strlen (AsciiString); Index++) { + CurrentChar = AsciiString[Index]; + if (CurrentChar == ' ') { + break; + } + // + // Verify Dec string + // + if (isdigit ((int)CurrentChar) == 0) { + return EFI_ABORTED; + } + // + // Add dec value + // + Value = Value * 10; + Value += CurrentChar - '0'; + } + + *ReturnValue = Value; + } + + return EFI_SUCCESS; +} + +/** + This function reads a line, stripping any comments. + // BUGBUG: This is obsolete once genmake goes away... + + @param InputFile Stream pointer. + @param InputBuffer Buffer to read into, must be MAX_LONG_FILE_PATH size. + + @retval NULL if error or EOF + @retval InputBuffer otherwise +**/ +CHAR8 * +ReadLineInStream ( + IN FILE *InputFile, + IN OUT CHAR8 *InputBuffer + ) +{ + CHAR8 *CharPtr; + + // + // Verify input parameters are not null + // + assert (InputFile); + assert (InputBuffer); + + // + // Read a line + // + if (fgets (InputBuffer, MAX_LONG_FILE_PATH, InputFile) == NULL) { + return NULL; + } + // + // Strip any comments + // + CharPtr = strstr (InputBuffer, "//"); + if (CharPtr != 0) { + CharPtr[0] = 0; + } + + CharPtr = strstr (InputBuffer, "#"); + if (CharPtr != 0) { + CharPtr[0] = 0; + } + // + // Return the string + // + return InputBuffer; +} + +/** + This function parses a stream file from the beginning to find a section. + The section string may be anywhere within a line. + // BUGBUG: This is obsolete once genmake goes away... + + @param InputFile Stream pointer. + @param Section Section to search for + + @retval FALSE if error or EOF + @retval TRUE if section found +**/ +BOOLEAN +FindSectionInStream ( + IN FILE *InputFile, + IN CHAR8 *Section + ) +{ + CHAR8 InputBuffer[MAX_LONG_FILE_PATH]; + CHAR8 *CurrentToken; + + // + // Verify input is not NULL + // + assert (InputFile); + assert (Section); + + // + // Rewind to beginning of file + // + if (fseek (InputFile, 0, SEEK_SET) != 0) { + return FALSE; + } + // + // Read lines until the section is found + // + while (feof (InputFile) == 0) { + // + // Read a line + // + ReadLineInStream (InputFile, InputBuffer); + + // + // Check if the section is found + // + CurrentToken = strstr (InputBuffer, Section); + if (CurrentToken != NULL) { + return TRUE; + } + } + + return FALSE; +} diff --git a/BaseTools/Source/C/Common/ParseInf.h b/BaseTools/Source/C/Common/ParseInf.h index a0881a5c9e..3778fe9e02 100644 --- a/BaseTools/Source/C/Common/ParseInf.h +++ b/BaseTools/Source/C/Common/ParseInf.h @@ -1,164 +1,164 @@ -/** @file
-Header file for helper functions useful for parsing INF files.
-
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _EFI_PARSE_INF_H
-#define _EFI_PARSE_INF_H
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <Common/UefiBaseTypes.h>
-#include <MemoryFile.h>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-//
-// Functions declarations
-//
-
-/**
- This function reads a line, stripping any comments.
- The function reads a string from the input stream argument and stores it in
- the input string. ReadLine reads characters from the current file position
- to and including the first newline character, to the end of the stream, or
- until the number of characters read is equal to MaxLength - 1, whichever
- comes first. The newline character, if read, is replaced with a \0.
-
- @param InputFile Memory file image.
- @param InputBuffer Buffer to read into, must be MaxLength size.
- @param MaxLength The maximum size of the input buffer.
-
- @retval NULL if error or EOF
- @retval InputBuffer otherwise
-**/
-CHAR8 *
-ReadLine (
- IN MEMORY_FILE *InputFile,
- IN OUT CHAR8 *InputBuffer,
- IN UINTN MaxLength
- )
-;
-
-/**
- This function parses a file from the beginning to find a section.
- The section string may be anywhere within a line.
-
- @param InputFile Memory file image.
- @param Section Section to search for
-
- @retval FALSE if error or EOF
- @retval TRUE if section found
-**/
-BOOLEAN
-FindSection (
- IN MEMORY_FILE *InputFile,
- IN CHAR8 *Section
- )
-;
-
-/**
- Finds a token value given the section and token to search for.
-
- @param InputFile Memory file image.
- @param Section The section to search for, a string within [].
- @param Token The token to search for, e.g. EFI_PEIM_RECOVERY, followed by an = in the INF file.
- @param Instance The instance of the token to search for. Zero is the first instance.
- @param Value The string that holds the value following the =. Must be MAX_LONG_FILE_PATH in size.
-
- @retval EFI_SUCCESS Value found.
- @retval EFI_ABORTED Format error detected in INF file.
- @retval EFI_INVALID_PARAMETER Input argument was null.
- @retval EFI_LOAD_ERROR Error reading from the file.
- @retval EFI_NOT_FOUND Section/Token/Value not found.
-**/
-EFI_STATUS
-FindToken (
- IN MEMORY_FILE *InputFile,
- IN CHAR8 *Section,
- IN CHAR8 *Token,
- IN UINTN Instance,
- OUT CHAR8 *Value
- )
-;
-
-/**
- Converts a string to an EFI_GUID. The string must be in the
- xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format.
-
- @param GuidBuffer pointer to destination Guid
- @param AsciiGuidBuffer pointer to ascii string
-
- @retval EFI_ABORTED Could not convert the string
- @retval EFI_SUCCESS The string was successfully converted
-**/
-EFI_STATUS
-StringToGuid (
- IN CHAR8 *AsciiGuidBuffer,
- OUT EFI_GUID *GuidBuffer
- )
-;
-
-/**
- Converts a null terminated ascii string that represents a number into a
- UINT64 value. A hex number may be preceded by a 0x, but may not be
- succeeded by an h. A number without 0x or 0X is considered to be base 10
- unless the IsHex input is true.
-
- @param AsciiString The string to convert.
- @param IsHex Force the string to be treated as a hex number.
- @param ReturnValue The return value.
-
- @retval EFI_SUCCESS Number successfully converted.
- @retval EFI_ABORTED Invalid character encountered.
-**/
-EFI_STATUS
-AsciiStringToUint64 (
- IN CONST CHAR8 *AsciiString,
- IN BOOLEAN IsHex,
- OUT UINT64 *ReturnValue
- )
-;
-
-/**
- This function reads a line, stripping any comments.
-
- @param InputFile Stream pointer.
- @param InputBuffer Buffer to read into, must be MAX_LONG_FILE_PATH size.
-
- @retval NULL if error or EOF
- @retval InputBuffer otherwise
-**/
-CHAR8 *
-ReadLineInStream (
- IN FILE *InputFile,
- IN OUT CHAR8 *InputBuffer
- )
-;
-
-/**
- This function parses a stream file from the beginning to find a section.
- The section string may be anywhere within a line.
-
- @param InputFile Stream pointer.
- @param Section Section to search for
-
- @retval FALSE if error or EOF
- @retval TRUE if section found
-**/
-BOOLEAN
-FindSectionInStream (
- IN FILE *InputFile,
- IN CHAR8 *Section
- )
-;
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
+/** @file +Header file for helper functions useful for parsing INF files. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_PARSE_INF_H +#define _EFI_PARSE_INF_H + +#include <stdio.h> +#include <stdlib.h> +#include <Common/UefiBaseTypes.h> +#include <MemoryFile.h> + +#ifdef __cplusplus +extern "C" { +#endif +// +// Functions declarations +// + +/** + This function reads a line, stripping any comments. + The function reads a string from the input stream argument and stores it in + the input string. ReadLine reads characters from the current file position + to and including the first newline character, to the end of the stream, or + until the number of characters read is equal to MaxLength - 1, whichever + comes first. The newline character, if read, is replaced with a \0. + + @param InputFile Memory file image. + @param InputBuffer Buffer to read into, must be MaxLength size. + @param MaxLength The maximum size of the input buffer. + + @retval NULL if error or EOF + @retval InputBuffer otherwise +**/ +CHAR8 * +ReadLine ( + IN MEMORY_FILE *InputFile, + IN OUT CHAR8 *InputBuffer, + IN UINTN MaxLength + ) +; + +/** + This function parses a file from the beginning to find a section. + The section string may be anywhere within a line. + + @param InputFile Memory file image. + @param Section Section to search for + + @retval FALSE if error or EOF + @retval TRUE if section found +**/ +BOOLEAN +FindSection ( + IN MEMORY_FILE *InputFile, + IN CHAR8 *Section + ) +; + +/** + Finds a token value given the section and token to search for. + + @param InputFile Memory file image. + @param Section The section to search for, a string within []. + @param Token The token to search for, e.g. EFI_PEIM_RECOVERY, followed by an = in the INF file. + @param Instance The instance of the token to search for. Zero is the first instance. + @param Value The string that holds the value following the =. Must be MAX_LONG_FILE_PATH in size. + + @retval EFI_SUCCESS Value found. + @retval EFI_ABORTED Format error detected in INF file. + @retval EFI_INVALID_PARAMETER Input argument was null. + @retval EFI_LOAD_ERROR Error reading from the file. + @retval EFI_NOT_FOUND Section/Token/Value not found. +**/ +EFI_STATUS +FindToken ( + IN MEMORY_FILE *InputFile, + IN CHAR8 *Section, + IN CHAR8 *Token, + IN UINTN Instance, + OUT CHAR8 *Value + ) +; + +/** + Converts a string to an EFI_GUID. The string must be in the + xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx format. + + @param GuidBuffer pointer to destination Guid + @param AsciiGuidBuffer pointer to ascii string + + @retval EFI_ABORTED Could not convert the string + @retval EFI_SUCCESS The string was successfully converted +**/ +EFI_STATUS +StringToGuid ( + IN CHAR8 *AsciiGuidBuffer, + OUT EFI_GUID *GuidBuffer + ) +; + +/** + Converts a null terminated ascii string that represents a number into a + UINT64 value. A hex number may be preceded by a 0x, but may not be + succeeded by an h. A number without 0x or 0X is considered to be base 10 + unless the IsHex input is true. + + @param AsciiString The string to convert. + @param IsHex Force the string to be treated as a hex number. + @param ReturnValue The return value. + + @retval EFI_SUCCESS Number successfully converted. + @retval EFI_ABORTED Invalid character encountered. +**/ +EFI_STATUS +AsciiStringToUint64 ( + IN CONST CHAR8 *AsciiString, + IN BOOLEAN IsHex, + OUT UINT64 *ReturnValue + ) +; + +/** + This function reads a line, stripping any comments. + + @param InputFile Stream pointer. + @param InputBuffer Buffer to read into, must be MAX_LONG_FILE_PATH size. + + @retval NULL if error or EOF + @retval InputBuffer otherwise +**/ +CHAR8 * +ReadLineInStream ( + IN FILE *InputFile, + IN OUT CHAR8 *InputBuffer + ) +; + +/** + This function parses a stream file from the beginning to find a section. + The section string may be anywhere within a line. + + @param InputFile Stream pointer. + @param Section Section to search for + + @retval FALSE if error or EOF + @retval TRUE if section found +**/ +BOOLEAN +FindSectionInStream ( + IN FILE *InputFile, + IN CHAR8 *Section + ) +; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/BaseTools/Source/C/Common/PcdValueCommon.c b/BaseTools/Source/C/Common/PcdValueCommon.c index f17a357b7c..8f4bcee1fc 100644 --- a/BaseTools/Source/C/Common/PcdValueCommon.c +++ b/BaseTools/Source/C/Common/PcdValueCommon.c @@ -1,678 +1,678 @@ -/** @file
-This file contains the PcdValue structure definition.
-
-Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
-
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include "CommonLib.h"
-#include "PcdValueCommon.h"
-
-typedef enum {
- PcdDataTypeBoolean,
- PcdDataTypeUint8,
- PcdDataTypeUint16,
- PcdDataTypeUint32,
- PcdDataTypeUint64,
- PcdDataTypePointer
-} PCD_DATA_TYPE;
-
-typedef struct {
- CHAR8 *SkuName;
- CHAR8 *DefaultValueName;
- CHAR8 *TokenSpaceGuidName;
- CHAR8 *TokenName;
- CHAR8 *DataType;
- CHAR8 *Value;
- PCD_DATA_TYPE PcdDataType;
-} PCD_ENTRY;
-
-PCD_ENTRY *PcdList;
-UINT32 PcdListLength;
-
-/**
- Record new token information
-
- @param FileBuffer File Buffer to be record
- @param PcdIndex Index of PCD in database
- @param TokenIndex Index of Token
- @param TokenStart Start of Token
- @param TokenEnd End of Token
-**/
-VOID
-STATIC
-RecordToken (
- UINT8 *FileBuffer,
- UINT32 PcdIndex,
- UINT32 TokenIndex,
- UINT32 TokenStart,
- UINT32 TokenEnd
- )
-
-{
- CHAR8 *Token;
-
- Token = malloc (TokenEnd - TokenStart + 1);
- if (Token == NULL) {
- return;
- }
- memcpy (Token, &FileBuffer[TokenStart], TokenEnd - TokenStart);
- Token[TokenEnd - TokenStart] = 0;
- switch (TokenIndex) {
- case 0:
- PcdList[PcdIndex].SkuName = Token;
- break;
- case 1:
- PcdList[PcdIndex].DefaultValueName = Token;
- break;
- case 2:
- PcdList[PcdIndex].TokenSpaceGuidName = Token;
- break;
- case 3:
- PcdList[PcdIndex].TokenName = Token;
- break;
- case 4:
- PcdList[PcdIndex].DataType = Token;
- if (strcmp (Token, "BOOLEAN") == 0) {
- PcdList[PcdIndex].PcdDataType = PcdDataTypeBoolean;
- } else if (strcmp (Token, "UINT8") == 0) {
- PcdList[PcdIndex].PcdDataType = PcdDataTypeUint8;
- } else if (strcmp (Token, "UINT16") == 0) {
- PcdList[PcdIndex].PcdDataType = PcdDataTypeUint16;
- } else if (strcmp (Token, "UINT32") == 0) {
- PcdList[PcdIndex].PcdDataType = PcdDataTypeUint32;
- } else if (strcmp (Token, "UINT64") == 0) {
- PcdList[PcdIndex].PcdDataType = PcdDataTypeUint64;
- } else {
- PcdList[PcdIndex].PcdDataType = PcdDataTypePointer;
- }
- break;
- case 5:
- PcdList[PcdIndex].Value = Token;
- break;
- default:
- free (Token);
- break;
- }
-}
-
-/**
- Get PCD index in Pcd database
-
- @param SkuName SkuName String
- @param DefaultValueName DefaultValueName String
- @param TokenSpaceGuidName TokenSpaceGuidName String
- @param TokenName TokenName String
-
- @return Index of PCD in Pcd database
-**/
-int
-STATIC
-LookupPcdIndex (
- CHAR8 *SkuName OPTIONAL,
- CHAR8 *DefaultValueName OPTIONAL,
- CHAR8 *TokenSpaceGuidName,
- CHAR8 *TokenName
- )
-{
- UINT32 Index;
-
- if (SkuName == NULL) {
- SkuName = "DEFAULT";
- }
- if (DefaultValueName == NULL) {
- DefaultValueName = "DEFAULT";
- }
- for (Index = 0; Index < PcdListLength; Index++) {
- if (strcmp(PcdList[Index].TokenSpaceGuidName, TokenSpaceGuidName) != 0) {
- continue;
- }
- if (strcmp(PcdList[Index].TokenName, TokenName) != 0) {
- continue;
- }
- if (strcmp(PcdList[Index].SkuName, SkuName) != 0) {
- continue;
- }
- if (strcmp(PcdList[Index].DefaultValueName, DefaultValueName) != 0) {
- continue;
- }
- return Index;
- }
- return -1;
-}
-
-/**
- Get PCD value
-
- @param SkuName SkuName String
- @param DefaultValueName DefaultValueName String
- @param TokenSpaceGuidName TokenSpaceGuidName String
- @param TokenName TokenName String
-
- @return PCD value
-**/
-UINT64
-__PcdGet (
- CHAR8 *SkuName OPTIONAL,
- CHAR8 *DefaultValueName OPTIONAL,
- CHAR8 *TokenSpaceGuidName,
- CHAR8 *TokenName
- )
-{
- int Index;
- CHAR8 *End;
-
- Index = LookupPcdIndex (SkuName, DefaultValueName, TokenSpaceGuidName, TokenName);
- if (Index < 0) {
- fprintf (stderr, "PCD %s.%s.%s.%s is not in database\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName);
- exit (EXIT_FAILURE);
- }
- switch (PcdList[Index].PcdDataType) {
- case PcdDataTypeBoolean:
- case PcdDataTypeUint8:
- case PcdDataTypeUint16:
- case PcdDataTypeUint32:
- return (UINT64)strtoul(PcdList[Index].Value, &End, 16);
- break;
- case PcdDataTypeUint64:
- return (UINT64)strtoul(PcdList[Index].Value, &End, 16);
- break;
- case PcdDataTypePointer:
- fprintf (stderr, "PCD %s.%s.%s.%s is structure. Use PcdGetPtr()\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName);
- exit (EXIT_FAILURE);
- break;
- }
- return 0;
-}
-
-/**
- Set PCD value
-
- @param SkuName SkuName String
- @param DefaultValueName DefaultValueName String
- @param TokenSpaceGuidName TokenSpaceGuidName String
- @param TokenName TokenName String
- @param Value PCD value to be set
-**/
-VOID
-__PcdSet (
- CHAR8 *SkuName OPTIONAL,
- CHAR8 *DefaultValueName OPTIONAL,
- CHAR8 *TokenSpaceGuidName,
- CHAR8 *TokenName,
- UINT64 Value
- )
-{
- int Index;
-
- Index = LookupPcdIndex (SkuName, DefaultValueName, TokenSpaceGuidName, TokenName);
- if (Index < 0) {
- fprintf (stderr, "PCD %s.%s.%s.%s is not in database\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName);
- exit (EXIT_FAILURE);
- }
- free(PcdList[Index].Value);
- PcdList[Index].Value = malloc(20);
- switch (PcdList[Index].PcdDataType) {
- case PcdDataTypeBoolean:
- if (Value == 0) {
- strcpy (PcdList[Index].Value, "0x00");
- } else {
- strcpy (PcdList[Index].Value, "0x01");
- }
- break;
- case PcdDataTypeUint8:
- sprintf(PcdList[Index].Value, "0x%02x", (UINT8)(Value & 0xff));
- break;
- case PcdDataTypeUint16:
- sprintf(PcdList[Index].Value, "0x%04x", (UINT16)(Value & 0xffff));
- break;
- case PcdDataTypeUint32:
- sprintf(PcdList[Index].Value, "0x%08x", (UINT32)(Value & 0xffffffff));
- break;
- case PcdDataTypeUint64:
- sprintf(PcdList[Index].Value, "0x%016llx", (unsigned long long)Value);
- break;
- case PcdDataTypePointer:
- fprintf (stderr, "PCD %s.%s.%s.%s is structure. Use PcdSetPtr()\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName);
- exit (EXIT_FAILURE);
- break;
- }
-}
-
-/**
- Get PCD value buffer
-
- @param SkuName SkuName String
- @param DefaultValueName DefaultValueName String
- @param TokenSpaceGuidName TokenSpaceGuidName String
- @param TokenName TokenName String
- @param Size Size of PCD value buffer
-
- @return PCD value buffer
-**/
-VOID *
-__PcdGetPtr (
- CHAR8 *SkuName OPTIONAL,
- CHAR8 *DefaultValueName OPTIONAL,
- CHAR8 *TokenSpaceGuidName,
- CHAR8 *TokenName,
- UINT32 *Size
- )
-{
- int Index;
- CHAR8 *Value;
- UINT8 *Buffer;
- CHAR8 *End;
-
- Index = LookupPcdIndex (SkuName, DefaultValueName, TokenSpaceGuidName, TokenName);
- if (Index < 0) {
- fprintf (stderr, "PCD %s.%s.%s.%s is not in database\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName);
- exit (EXIT_FAILURE);
- }
- switch (PcdList[Index].PcdDataType) {
- case PcdDataTypeBoolean:
- case PcdDataTypeUint8:
- case PcdDataTypeUint16:
- case PcdDataTypeUint32:
- case PcdDataTypeUint64:
- fprintf (stderr, "PCD %s.%s.%s.%s is a value. Use PcdGet()\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName);
- exit (EXIT_FAILURE);
- break;
- case PcdDataTypePointer:
- Value = &PcdList[Index].Value[1];
- for (*Size = 0, strtoul(Value, &End, 16); Value != End; strtoul(Value, &End, 16), *Size = *Size + 1) {
- Value = End + 1;
- }
- Buffer = malloc(*Size + 1);
- if (Buffer == NULL) {
- *Size = 0;
- return NULL;
- }
- Value = &PcdList[Index].Value[1];
- for (*Size = 0, Buffer[*Size] = (UINT8) strtoul(Value, &End, 16); Value != End; *Size = *Size + 1, Buffer[*Size] = (UINT8) strtoul(Value, &End, 16)) {
- Value = End + 1;
- }
- return Buffer;
- }
- *Size = 0;
- return 0;
-}
-
-/**
- Set PCD value buffer
-
- @param SkuName SkuName String
- @param DefaultValueName DefaultValueName String
- @param TokenSpaceGuidName TokenSpaceGuidName String
- @param TokenName TokenName String
- @param Size Size of PCD value
- @param Value Pointer to the updated PCD value buffer
-**/
-VOID
-__PcdSetPtr (
- CHAR8 *SkuName OPTIONAL,
- CHAR8 *DefaultValueName OPTIONAL,
- CHAR8 *TokenSpaceGuidName,
- CHAR8 *TokenName,
- UINT32 Size,
- UINT8 *Value
- )
-{
- int Index;
- UINT32 ValueIndex;
-
- Index = LookupPcdIndex (SkuName, DefaultValueName, TokenSpaceGuidName, TokenName);
- if (Index < 0) {
- fprintf (stderr, "PCD %s.%s.%s.%s is not in database\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName);
- exit (EXIT_FAILURE);
- }
- switch (PcdList[Index].PcdDataType) {
- case PcdDataTypeBoolean:
- case PcdDataTypeUint8:
- case PcdDataTypeUint16:
- case PcdDataTypeUint32:
- case PcdDataTypeUint64:
- fprintf (stderr, "PCD %s.%s.%s.%s is a value. Use PcdGet()\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName);
- exit (EXIT_FAILURE);
- break;
- case PcdDataTypePointer:
- free(PcdList[Index].Value);
- PcdList[Index].Value = malloc(Size * 5 + 3);
- PcdList[Index].Value[0] = '{';
- for (ValueIndex = 0; ValueIndex < Size; ValueIndex++) {
- sprintf(&PcdList[Index].Value[1 + ValueIndex * 5], "0x%02x,", Value[ValueIndex]);
- }
- PcdList[Index].Value[1 + Size * 5 - 1] = '}';
- PcdList[Index].Value[1 + Size * 5 ] = 0;
- break;
- }
-}
-
-/**
- Read the file buffer from the input file.
-
- @param InputFileName Point to the input file name.
- @param FileBuffer Point to the input file buffer.
- @param FileSize Size of the file buffer.
-**/
-VOID
-STATIC
-ReadInputFile (
- CHAR8 *InputFileName,
- UINT8 **FileBuffer,
- UINT32 *FileSize
- )
-{
- FILE *InputFile;
- UINT32 BytesRead;
-
- //
- // Open Input file and read file data.
- //
- InputFile = fopen (InputFileName, "rb");
- if (InputFile == NULL) {
- fprintf (stderr, "Error opening file %s\n", InputFileName);
- exit (EXIT_FAILURE);
- }
-
- //
- // Go to the end so that we can determine the file size
- //
- if (fseek (InputFile, 0, SEEK_END)) {
- fprintf (stderr, "Error reading input file %s\n", InputFileName);
- fclose (InputFile);
- exit (EXIT_FAILURE);
- }
-
- //
- // Get the file size
- //
- *FileSize = ftell (InputFile);
- if (*FileSize == -1) {
- fprintf (stderr, "Error parsing the input file %s\n", InputFileName);
- fclose (InputFile);
- exit (EXIT_FAILURE);
- }
-
- //
- // Allocate a buffer
- //
- *FileBuffer = malloc (*FileSize);
- if (*FileBuffer == NULL) {
- fprintf (stderr, "Can not allocate buffer for input input file %s\n", InputFileName);
- fclose (InputFile);
- exit (EXIT_FAILURE);
- }
-
- //
- // Reset to the beginning of the file
- //
- if (fseek (InputFile, 0, SEEK_SET)) {
- fprintf (stderr, "Error reading the input file %s\n", InputFileName);
- fclose (InputFile);
- free (*FileBuffer);
- exit (EXIT_FAILURE);
- }
-
- //
- // Read all of the file contents.
- //
- BytesRead = (UINT32)fread (*FileBuffer, sizeof (UINT8), *FileSize, InputFile);
- if (BytesRead != *FileSize * sizeof (UINT8)) {
- fprintf (stderr, "Error reading the input file %s\n", InputFileName);
- fclose (InputFile);
- free (*FileBuffer);
- exit (EXIT_FAILURE);
- }
-
- //
- // Close the file
- //
- fclose (InputFile);
-}
-
-/**
- Read the initial PCD value from the input file buffer.
-
- @param FileBuffer Point to the input file buffer.
- @param FileSize Size of the file buffer.
-**/
-VOID
-STATIC
-ParseFile (
- UINT8 *FileBuffer,
- UINT32 FileSize
- )
-{
- UINT32 Index;
- UINT32 NumLines;
- UINT32 TokenIndex;
- UINT32 TokenStart;
-
- for (Index = 0, NumLines = 0; Index < FileSize; Index++) {
- if (FileBuffer[Index] == '\n') {
- NumLines++;
- }
- }
- PcdList = malloc((NumLines + 1) * sizeof(PcdList[0]));
-
- for (Index = 0, TokenIndex = 0, PcdListLength = 0, TokenStart = 0; Index < FileSize; Index++) {
- if (FileBuffer[Index] == ' ') {
- continue;
- }
- if (FileBuffer[Index] == '|' || FileBuffer[Index] == '.' || FileBuffer[Index] == '\n' || FileBuffer[Index] == '\r') {
- RecordToken (FileBuffer, PcdListLength, TokenIndex, TokenStart, Index);
- if (FileBuffer[Index] == '\n' || FileBuffer[Index] == '\r') {
- if (TokenIndex != 0) {
- PcdListLength++;
- TokenIndex = 0;
- }
- } else {
- TokenIndex++;
- }
- TokenStart = Index + 1;
- continue;
- }
- }
- if (Index > TokenStart) {
- RecordToken (FileBuffer, PcdListLength, TokenIndex, TokenStart, Index);
- if (TokenIndex != 0) {
- PcdListLength++;
- }
- }
-}
-
-/**
- Write the updated PCD value into the output file name.
-
- @param OutputFileName Point to the output file name.
-**/
-VOID
-STATIC
-WriteOutputFile (
- CHAR8 *OutputFileName
- )
-{
- FILE *OutputFile;
- UINT32 Index;
-
- //
- // Open output file
- //
- OutputFile = fopen (OutputFileName, "wb");
- if (OutputFile == NULL) {
- fprintf (stderr, "Error opening file %s\n", OutputFileName);
- exit (EXIT_FAILURE);
- }
-
- for (Index = 0; Index < PcdListLength; Index++) {
- fprintf (
- OutputFile,
- "%s.%s.%s.%s|%s|%s\n",
- PcdList[Index].SkuName,
- PcdList[Index].DefaultValueName,
- PcdList[Index].TokenSpaceGuidName,
- PcdList[Index].TokenName,
- PcdList[Index].DataType,
- PcdList[Index].Value
- );
- }
-
- //
- // Done, write output file.
- //
- if (OutputFile != NULL) {
- fclose (OutputFile);
- }
-}
-
-/**
- Displays the utility usage syntax to STDOUT
-**/
-VOID
-STATIC
-Usage (
- VOID
- )
-{
- fprintf (stdout, "Usage: -i <input_file> -o <output_file>\n\n");
- fprintf (stdout, "optional arguments:\n");
- fprintf (stdout, " -h, --help Show this help message and exit\n");
- fprintf (stdout, " -i INPUT_FILENAME, --input INPUT_FILENAME\n\
- PCD Database Input file name\n");
- fprintf (stdout, " -o OUTPUT_FILENAME, --output OUTPUT_FILENAME\n\
- PCD Database Output file name\n");
-}
-
-/**
- Parse the input parameters to get the input/output file name.
-
- @param argc Number of command line parameters.
- @param argv Array of pointers to parameter strings.
- @param InputFileName Point to the input file name.
- @param OutputFileName Point to the output file name.
-**/
-VOID
-STATIC
-ParseArguments (
- int argc,
- char *argv[],
- CHAR8 **InputFileName,
- CHAR8 **OutputFileName
- )
-{
- if (argc == 1) {
- fprintf (stderr, "Missing options\n");
- exit (EXIT_FAILURE);
- }
-
- //
- // Parse command line
- //
- argc--;
- argv++;
-
- if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {
- Usage ();
- exit (EXIT_SUCCESS);
- }
-
- while (argc > 0) {
- if ((stricmp (argv[0], "-i") == 0) || (stricmp (argv[0], "--input") == 0)) {
- if (argv[1] == NULL || argv[1][0] == '-') {
- fprintf (stderr, "Invalid option value. Input File name is missing for -i option\n");
- exit (EXIT_FAILURE);
- }
- *InputFileName = argv[1];
- argc -= 2;
- argv += 2;
- continue;
- }
-
- if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--output") == 0)) {
- if (argv[1] == NULL || argv[1][0] == '-') {
- fprintf (stderr, "Invalid option value. Output File name is missing for -i option\n");
- exit (EXIT_FAILURE);
- }
- *OutputFileName = argv[1];
- argc -= 2;
- argv += 2;
- continue;
- }
-
- if (argv[0][0] == '-') {
- fprintf (stderr, "Unknown option %s\n", argv[0]);
- exit (EXIT_FAILURE);
- }
- argc --;
- argv ++;
- }
-
- //
- // Check Input parameters
- //
- if (*InputFileName == NULL) {
- fprintf (stderr, "Missing option. Input files is not specified\n");
- exit (EXIT_FAILURE);
- }
-
- if (*OutputFileName == NULL) {
- fprintf (stderr, "Missing option. Output file is not specified\n");
- exit (EXIT_FAILURE);
- }
-}
-
-/**
- Main function updates PCD values.
-
- @param argc Number of command line parameters.
- @param argv Array of pointers to parameter strings.
-
- @retval EXIT_SUCCESS
-**/
-int
-PcdValueMain (
- int argc,
- char *argv[]
- )
-{
- CHAR8 *InputFileName;
- CHAR8 *OutputFileName;
- UINT8 *FileBuffer;
- UINT32 FileSize;
-
- InputFileName = NULL;
- OutputFileName = NULL;
-
- //
- // Parse the input arguments
- //
- ParseArguments (argc, argv, &InputFileName, &OutputFileName);
-
- //
- // Open Input file and read file data.
- //
- ReadInputFile (InputFileName, &FileBuffer, &FileSize);
-
- //
- // Read the initial Pcd value
- //
- ParseFile (FileBuffer, FileSize);
-
- //
- // Customize PCD values in the PCD Database
- //
- PcdEntryPoint ();
-
- //
- // Save the updated PCD value
- //
- WriteOutputFile (OutputFileName);
-
- exit (EXIT_SUCCESS);
-}
+/** @file +This file contains the PcdValue structure definition. + +Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR> + +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include "CommonLib.h" +#include "PcdValueCommon.h" + +typedef enum { + PcdDataTypeBoolean, + PcdDataTypeUint8, + PcdDataTypeUint16, + PcdDataTypeUint32, + PcdDataTypeUint64, + PcdDataTypePointer +} PCD_DATA_TYPE; + +typedef struct { + CHAR8 *SkuName; + CHAR8 *DefaultValueName; + CHAR8 *TokenSpaceGuidName; + CHAR8 *TokenName; + CHAR8 *DataType; + CHAR8 *Value; + PCD_DATA_TYPE PcdDataType; +} PCD_ENTRY; + +PCD_ENTRY *PcdList; +UINT32 PcdListLength; + +/** + Record new token information + + @param FileBuffer File Buffer to be record + @param PcdIndex Index of PCD in database + @param TokenIndex Index of Token + @param TokenStart Start of Token + @param TokenEnd End of Token +**/ +VOID +STATIC +RecordToken ( + UINT8 *FileBuffer, + UINT32 PcdIndex, + UINT32 TokenIndex, + UINT32 TokenStart, + UINT32 TokenEnd + ) + +{ + CHAR8 *Token; + + Token = malloc (TokenEnd - TokenStart + 1); + if (Token == NULL) { + return; + } + memcpy (Token, &FileBuffer[TokenStart], TokenEnd - TokenStart); + Token[TokenEnd - TokenStart] = 0; + switch (TokenIndex) { + case 0: + PcdList[PcdIndex].SkuName = Token; + break; + case 1: + PcdList[PcdIndex].DefaultValueName = Token; + break; + case 2: + PcdList[PcdIndex].TokenSpaceGuidName = Token; + break; + case 3: + PcdList[PcdIndex].TokenName = Token; + break; + case 4: + PcdList[PcdIndex].DataType = Token; + if (strcmp (Token, "BOOLEAN") == 0) { + PcdList[PcdIndex].PcdDataType = PcdDataTypeBoolean; + } else if (strcmp (Token, "UINT8") == 0) { + PcdList[PcdIndex].PcdDataType = PcdDataTypeUint8; + } else if (strcmp (Token, "UINT16") == 0) { + PcdList[PcdIndex].PcdDataType = PcdDataTypeUint16; + } else if (strcmp (Token, "UINT32") == 0) { + PcdList[PcdIndex].PcdDataType = PcdDataTypeUint32; + } else if (strcmp (Token, "UINT64") == 0) { + PcdList[PcdIndex].PcdDataType = PcdDataTypeUint64; + } else { + PcdList[PcdIndex].PcdDataType = PcdDataTypePointer; + } + break; + case 5: + PcdList[PcdIndex].Value = Token; + break; + default: + free (Token); + break; + } +} + +/** + Get PCD index in Pcd database + + @param SkuName SkuName String + @param DefaultValueName DefaultValueName String + @param TokenSpaceGuidName TokenSpaceGuidName String + @param TokenName TokenName String + + @return Index of PCD in Pcd database +**/ +int +STATIC +LookupPcdIndex ( + CHAR8 *SkuName OPTIONAL, + CHAR8 *DefaultValueName OPTIONAL, + CHAR8 *TokenSpaceGuidName, + CHAR8 *TokenName + ) +{ + UINT32 Index; + + if (SkuName == NULL) { + SkuName = "DEFAULT"; + } + if (DefaultValueName == NULL) { + DefaultValueName = "DEFAULT"; + } + for (Index = 0; Index < PcdListLength; Index++) { + if (strcmp(PcdList[Index].TokenSpaceGuidName, TokenSpaceGuidName) != 0) { + continue; + } + if (strcmp(PcdList[Index].TokenName, TokenName) != 0) { + continue; + } + if (strcmp(PcdList[Index].SkuName, SkuName) != 0) { + continue; + } + if (strcmp(PcdList[Index].DefaultValueName, DefaultValueName) != 0) { + continue; + } + return Index; + } + return -1; +} + +/** + Get PCD value + + @param SkuName SkuName String + @param DefaultValueName DefaultValueName String + @param TokenSpaceGuidName TokenSpaceGuidName String + @param TokenName TokenName String + + @return PCD value +**/ +UINT64 +__PcdGet ( + CHAR8 *SkuName OPTIONAL, + CHAR8 *DefaultValueName OPTIONAL, + CHAR8 *TokenSpaceGuidName, + CHAR8 *TokenName + ) +{ + int Index; + CHAR8 *End; + + Index = LookupPcdIndex (SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + if (Index < 0) { + fprintf (stderr, "PCD %s.%s.%s.%s is not in database\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + exit (EXIT_FAILURE); + } + switch (PcdList[Index].PcdDataType) { + case PcdDataTypeBoolean: + case PcdDataTypeUint8: + case PcdDataTypeUint16: + case PcdDataTypeUint32: + return (UINT64)strtoul(PcdList[Index].Value, &End, 16); + break; + case PcdDataTypeUint64: + return (UINT64)strtoul(PcdList[Index].Value, &End, 16); + break; + case PcdDataTypePointer: + fprintf (stderr, "PCD %s.%s.%s.%s is structure. Use PcdGetPtr()\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + exit (EXIT_FAILURE); + break; + } + return 0; +} + +/** + Set PCD value + + @param SkuName SkuName String + @param DefaultValueName DefaultValueName String + @param TokenSpaceGuidName TokenSpaceGuidName String + @param TokenName TokenName String + @param Value PCD value to be set +**/ +VOID +__PcdSet ( + CHAR8 *SkuName OPTIONAL, + CHAR8 *DefaultValueName OPTIONAL, + CHAR8 *TokenSpaceGuidName, + CHAR8 *TokenName, + UINT64 Value + ) +{ + int Index; + + Index = LookupPcdIndex (SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + if (Index < 0) { + fprintf (stderr, "PCD %s.%s.%s.%s is not in database\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + exit (EXIT_FAILURE); + } + free(PcdList[Index].Value); + PcdList[Index].Value = malloc(20); + switch (PcdList[Index].PcdDataType) { + case PcdDataTypeBoolean: + if (Value == 0) { + strcpy (PcdList[Index].Value, "0x00"); + } else { + strcpy (PcdList[Index].Value, "0x01"); + } + break; + case PcdDataTypeUint8: + sprintf(PcdList[Index].Value, "0x%02x", (UINT8)(Value & 0xff)); + break; + case PcdDataTypeUint16: + sprintf(PcdList[Index].Value, "0x%04x", (UINT16)(Value & 0xffff)); + break; + case PcdDataTypeUint32: + sprintf(PcdList[Index].Value, "0x%08x", (UINT32)(Value & 0xffffffff)); + break; + case PcdDataTypeUint64: + sprintf(PcdList[Index].Value, "0x%016llx", (unsigned long long)Value); + break; + case PcdDataTypePointer: + fprintf (stderr, "PCD %s.%s.%s.%s is structure. Use PcdSetPtr()\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + exit (EXIT_FAILURE); + break; + } +} + +/** + Get PCD value buffer + + @param SkuName SkuName String + @param DefaultValueName DefaultValueName String + @param TokenSpaceGuidName TokenSpaceGuidName String + @param TokenName TokenName String + @param Size Size of PCD value buffer + + @return PCD value buffer +**/ +VOID * +__PcdGetPtr ( + CHAR8 *SkuName OPTIONAL, + CHAR8 *DefaultValueName OPTIONAL, + CHAR8 *TokenSpaceGuidName, + CHAR8 *TokenName, + UINT32 *Size + ) +{ + int Index; + CHAR8 *Value; + UINT8 *Buffer; + CHAR8 *End; + + Index = LookupPcdIndex (SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + if (Index < 0) { + fprintf (stderr, "PCD %s.%s.%s.%s is not in database\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + exit (EXIT_FAILURE); + } + switch (PcdList[Index].PcdDataType) { + case PcdDataTypeBoolean: + case PcdDataTypeUint8: + case PcdDataTypeUint16: + case PcdDataTypeUint32: + case PcdDataTypeUint64: + fprintf (stderr, "PCD %s.%s.%s.%s is a value. Use PcdGet()\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + exit (EXIT_FAILURE); + break; + case PcdDataTypePointer: + Value = &PcdList[Index].Value[1]; + for (*Size = 0, strtoul(Value, &End, 16); Value != End; strtoul(Value, &End, 16), *Size = *Size + 1) { + Value = End + 1; + } + Buffer = malloc(*Size + 1); + if (Buffer == NULL) { + *Size = 0; + return NULL; + } + Value = &PcdList[Index].Value[1]; + for (*Size = 0, Buffer[*Size] = (UINT8) strtoul(Value, &End, 16); Value != End; *Size = *Size + 1, Buffer[*Size] = (UINT8) strtoul(Value, &End, 16)) { + Value = End + 1; + } + return Buffer; + } + *Size = 0; + return 0; +} + +/** + Set PCD value buffer + + @param SkuName SkuName String + @param DefaultValueName DefaultValueName String + @param TokenSpaceGuidName TokenSpaceGuidName String + @param TokenName TokenName String + @param Size Size of PCD value + @param Value Pointer to the updated PCD value buffer +**/ +VOID +__PcdSetPtr ( + CHAR8 *SkuName OPTIONAL, + CHAR8 *DefaultValueName OPTIONAL, + CHAR8 *TokenSpaceGuidName, + CHAR8 *TokenName, + UINT32 Size, + UINT8 *Value + ) +{ + int Index; + UINT32 ValueIndex; + + Index = LookupPcdIndex (SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + if (Index < 0) { + fprintf (stderr, "PCD %s.%s.%s.%s is not in database\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + exit (EXIT_FAILURE); + } + switch (PcdList[Index].PcdDataType) { + case PcdDataTypeBoolean: + case PcdDataTypeUint8: + case PcdDataTypeUint16: + case PcdDataTypeUint32: + case PcdDataTypeUint64: + fprintf (stderr, "PCD %s.%s.%s.%s is a value. Use PcdGet()\n", SkuName, DefaultValueName, TokenSpaceGuidName, TokenName); + exit (EXIT_FAILURE); + break; + case PcdDataTypePointer: + free(PcdList[Index].Value); + PcdList[Index].Value = malloc(Size * 5 + 3); + PcdList[Index].Value[0] = '{'; + for (ValueIndex = 0; ValueIndex < Size; ValueIndex++) { + sprintf(&PcdList[Index].Value[1 + ValueIndex * 5], "0x%02x,", Value[ValueIndex]); + } + PcdList[Index].Value[1 + Size * 5 - 1] = '}'; + PcdList[Index].Value[1 + Size * 5 ] = 0; + break; + } +} + +/** + Read the file buffer from the input file. + + @param InputFileName Point to the input file name. + @param FileBuffer Point to the input file buffer. + @param FileSize Size of the file buffer. +**/ +VOID +STATIC +ReadInputFile ( + CHAR8 *InputFileName, + UINT8 **FileBuffer, + UINT32 *FileSize + ) +{ + FILE *InputFile; + UINT32 BytesRead; + + // + // Open Input file and read file data. + // + InputFile = fopen (InputFileName, "rb"); + if (InputFile == NULL) { + fprintf (stderr, "Error opening file %s\n", InputFileName); + exit (EXIT_FAILURE); + } + + // + // Go to the end so that we can determine the file size + // + if (fseek (InputFile, 0, SEEK_END)) { + fprintf (stderr, "Error reading input file %s\n", InputFileName); + fclose (InputFile); + exit (EXIT_FAILURE); + } + + // + // Get the file size + // + *FileSize = ftell (InputFile); + if (*FileSize == -1) { + fprintf (stderr, "Error parsing the input file %s\n", InputFileName); + fclose (InputFile); + exit (EXIT_FAILURE); + } + + // + // Allocate a buffer + // + *FileBuffer = malloc (*FileSize); + if (*FileBuffer == NULL) { + fprintf (stderr, "Can not allocate buffer for input input file %s\n", InputFileName); + fclose (InputFile); + exit (EXIT_FAILURE); + } + + // + // Reset to the beginning of the file + // + if (fseek (InputFile, 0, SEEK_SET)) { + fprintf (stderr, "Error reading the input file %s\n", InputFileName); + fclose (InputFile); + free (*FileBuffer); + exit (EXIT_FAILURE); + } + + // + // Read all of the file contents. + // + BytesRead = (UINT32)fread (*FileBuffer, sizeof (UINT8), *FileSize, InputFile); + if (BytesRead != *FileSize * sizeof (UINT8)) { + fprintf (stderr, "Error reading the input file %s\n", InputFileName); + fclose (InputFile); + free (*FileBuffer); + exit (EXIT_FAILURE); + } + + // + // Close the file + // + fclose (InputFile); +} + +/** + Read the initial PCD value from the input file buffer. + + @param FileBuffer Point to the input file buffer. + @param FileSize Size of the file buffer. +**/ +VOID +STATIC +ParseFile ( + UINT8 *FileBuffer, + UINT32 FileSize + ) +{ + UINT32 Index; + UINT32 NumLines; + UINT32 TokenIndex; + UINT32 TokenStart; + + for (Index = 0, NumLines = 0; Index < FileSize; Index++) { + if (FileBuffer[Index] == '\n') { + NumLines++; + } + } + PcdList = malloc((NumLines + 1) * sizeof(PcdList[0])); + + for (Index = 0, TokenIndex = 0, PcdListLength = 0, TokenStart = 0; Index < FileSize; Index++) { + if (FileBuffer[Index] == ' ') { + continue; + } + if (FileBuffer[Index] == '|' || FileBuffer[Index] == '.' || FileBuffer[Index] == '\n' || FileBuffer[Index] == '\r') { + RecordToken (FileBuffer, PcdListLength, TokenIndex, TokenStart, Index); + if (FileBuffer[Index] == '\n' || FileBuffer[Index] == '\r') { + if (TokenIndex != 0) { + PcdListLength++; + TokenIndex = 0; + } + } else { + TokenIndex++; + } + TokenStart = Index + 1; + continue; + } + } + if (Index > TokenStart) { + RecordToken (FileBuffer, PcdListLength, TokenIndex, TokenStart, Index); + if (TokenIndex != 0) { + PcdListLength++; + } + } +} + +/** + Write the updated PCD value into the output file name. + + @param OutputFileName Point to the output file name. +**/ +VOID +STATIC +WriteOutputFile ( + CHAR8 *OutputFileName + ) +{ + FILE *OutputFile; + UINT32 Index; + + // + // Open output file + // + OutputFile = fopen (OutputFileName, "wb"); + if (OutputFile == NULL) { + fprintf (stderr, "Error opening file %s\n", OutputFileName); + exit (EXIT_FAILURE); + } + + for (Index = 0; Index < PcdListLength; Index++) { + fprintf ( + OutputFile, + "%s.%s.%s.%s|%s|%s\n", + PcdList[Index].SkuName, + PcdList[Index].DefaultValueName, + PcdList[Index].TokenSpaceGuidName, + PcdList[Index].TokenName, + PcdList[Index].DataType, + PcdList[Index].Value + ); + } + + // + // Done, write output file. + // + if (OutputFile != NULL) { + fclose (OutputFile); + } +} + +/** + Displays the utility usage syntax to STDOUT +**/ +VOID +STATIC +Usage ( + VOID + ) +{ + fprintf (stdout, "Usage: -i <input_file> -o <output_file>\n\n"); + fprintf (stdout, "optional arguments:\n"); + fprintf (stdout, " -h, --help Show this help message and exit\n"); + fprintf (stdout, " -i INPUT_FILENAME, --input INPUT_FILENAME\n\ + PCD Database Input file name\n"); + fprintf (stdout, " -o OUTPUT_FILENAME, --output OUTPUT_FILENAME\n\ + PCD Database Output file name\n"); +} + +/** + Parse the input parameters to get the input/output file name. + + @param argc Number of command line parameters. + @param argv Array of pointers to parameter strings. + @param InputFileName Point to the input file name. + @param OutputFileName Point to the output file name. +**/ +VOID +STATIC +ParseArguments ( + int argc, + char *argv[], + CHAR8 **InputFileName, + CHAR8 **OutputFileName + ) +{ + if (argc == 1) { + fprintf (stderr, "Missing options\n"); + exit (EXIT_FAILURE); + } + + // + // Parse command line + // + argc--; + argv++; + + if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) { + Usage (); + exit (EXIT_SUCCESS); + } + + while (argc > 0) { + if ((stricmp (argv[0], "-i") == 0) || (stricmp (argv[0], "--input") == 0)) { + if (argv[1] == NULL || argv[1][0] == '-') { + fprintf (stderr, "Invalid option value. Input File name is missing for -i option\n"); + exit (EXIT_FAILURE); + } + *InputFileName = argv[1]; + argc -= 2; + argv += 2; + continue; + } + + if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--output") == 0)) { + if (argv[1] == NULL || argv[1][0] == '-') { + fprintf (stderr, "Invalid option value. Output File name is missing for -i option\n"); + exit (EXIT_FAILURE); + } + *OutputFileName = argv[1]; + argc -= 2; + argv += 2; + continue; + } + + if (argv[0][0] == '-') { + fprintf (stderr, "Unknown option %s\n", argv[0]); + exit (EXIT_FAILURE); + } + argc --; + argv ++; + } + + // + // Check Input parameters + // + if (*InputFileName == NULL) { + fprintf (stderr, "Missing option. Input files is not specified\n"); + exit (EXIT_FAILURE); + } + + if (*OutputFileName == NULL) { + fprintf (stderr, "Missing option. Output file is not specified\n"); + exit (EXIT_FAILURE); + } +} + +/** + Main function updates PCD values. + + @param argc Number of command line parameters. + @param argv Array of pointers to parameter strings. + + @retval EXIT_SUCCESS +**/ +int +PcdValueMain ( + int argc, + char *argv[] + ) +{ + CHAR8 *InputFileName; + CHAR8 *OutputFileName; + UINT8 *FileBuffer; + UINT32 FileSize; + + InputFileName = NULL; + OutputFileName = NULL; + + // + // Parse the input arguments + // + ParseArguments (argc, argv, &InputFileName, &OutputFileName); + + // + // Open Input file and read file data. + // + ReadInputFile (InputFileName, &FileBuffer, &FileSize); + + // + // Read the initial Pcd value + // + ParseFile (FileBuffer, FileSize); + + // + // Customize PCD values in the PCD Database + // + PcdEntryPoint (); + + // + // Save the updated PCD value + // + WriteOutputFile (OutputFileName); + + exit (EXIT_SUCCESS); +} diff --git a/BaseTools/Source/C/Common/PcdValueCommon.h b/BaseTools/Source/C/Common/PcdValueCommon.h index 7dac5bd92d..2ec8a5a629 100644 --- a/BaseTools/Source/C/Common/PcdValueCommon.h +++ b/BaseTools/Source/C/Common/PcdValueCommon.h @@ -1,137 +1,137 @@ -/** @file
-Header file for PcdValue structure definition.
-
-Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _PCD_VALUE_COMMON_H
-#define _PCD_VALUE_COMMON_H
-
-#include <Common/UefiBaseTypes.h>
-#include <Common/UefiInternalFormRepresentation.h>
-
-#define __FIELD_SIZE(TYPE, Field) (sizeof((TYPE *)0)->Field)
-#define __ARRAY_ELEMENT_SIZE(TYPE, Field) (sizeof((TYPE *)0)->Field[0])
-#define __OFFSET_OF(TYPE, Field) ((UINT32)(size_t) &(((TYPE *)0)->Field))
-#define __FLEXIBLE_SIZE(Size, TYPE, Field, MaxIndex) if (__FIELD_SIZE(TYPE, Field) == 0) Size = MAX((__OFFSET_OF(TYPE, Field) + __ARRAY_ELEMENT_SIZE(TYPE, Field) * (MaxIndex)), Size)
-#define __ARRAY_SIZE(Array) (sizeof(Array)/sizeof(Array[0]))
-
-#if defined(_MSC_EXTENSIONS)
-#define __STATIC_ASSERT static_assert
-#else
-#define __STATIC_ASSERT _Static_assert
-#endif
-
-/**
- Main function updates PCD values. It is auto generated by Build
-**/
-VOID
-PcdEntryPoint (
- VOID
- )
-
-;
-
-/**
- Main function updates PCD values.
-
- @param argc Number of command line parameters.
- @param argv Array of pointers to parameter strings.
-
- @retval EXIT_SUCCESS
-**/
-int
-PcdValueMain (
- int argc,
- char *argv[]
- )
-;
-
-/**
- Set PCD value
-
- @param SkuName SkuName String
- @param DefaultValueName DefaultValueName String
- @param TokenSpaceGuidName TokenSpaceGuidName String
- @param TokenName TokenName String
- @param Value PCD value to be set
-**/
-VOID
-__PcdSet (
- CHAR8 *SkuName OPTIONAL,
- CHAR8 *DefaultValueName OPTIONAL,
- CHAR8 *TokenSpaceGuidName,
- CHAR8 *TokenName,
- UINT64 Value
- )
-;
-
-/**
- Get PCD value
-
- @param SkuName SkuName String
- @param DefaultValueName DefaultValueName String
- @param TokenSpaceGuidName TokenSpaceGuidName String
- @param TokenName TokenName String
-
- @return PCD value
-**/
-UINT64
-__PcdGet (
- CHAR8 *SkuName OPTIONAL,
- CHAR8 *DefaultValueName OPTIONAL,
- CHAR8 *TokenSpaceGuidName,
- CHAR8 *TokenName
- )
-;
-
-/**
- Get PCD value buffer
-
- @param SkuName SkuName String
- @param DefaultValueName DefaultValueName String
- @param TokenSpaceGuidName TokenSpaceGuidName String
- @param TokenName TokenName String
- @param Size Size of PCD value buffer
-
- @return PCD value buffer
-**/
-VOID *
-__PcdGetPtr (
- CHAR8 *SkuName OPTIONAL,
- CHAR8 *DefaultValueName OPTIONAL,
- CHAR8 *TokenSpaceGuidName,
- CHAR8 *TokenName,
- UINT32 *Size
- )
-;
-
-/**
- Set PCD value buffer
-
- @param SkuName SkuName String
- @param DefaultValueName DefaultValueName String
- @param TokenSpaceGuidName TokenSpaceGuidName String
- @param TokenName TokenName String
- @param Size Size of PCD value
- @param Value Pointer to the updated PCD value buffer
-**/
-VOID
-__PcdSetPtr (
- CHAR8 *SkuName OPTIONAL,
- CHAR8 *DefaultValueName OPTIONAL,
- CHAR8 *TokenSpaceGuidName,
- CHAR8 *TokenName,
- UINT32 Size,
- UINT8 *Value
- )
-;
-
-#define PcdGet(A, B, C, D) __PcdGet(#A, #B, #C, #D)
-#define PcdSet(A, B, C, D, Value) __PcdSet(#A, #B, #C, #D, Value)
-#define PcdGetPtr(A, B, C, D, Size) __PcdGetPtr(#A, #B, #C, #D, Size)
-#define PcdSetPtr(A, B, C, D, Size, Value) __PcdSetPtr(#A, #B, #C, #D, Size, Value)
-
-#endif
+/** @file +Header file for PcdValue structure definition. + +Copyright (c) 2017, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _PCD_VALUE_COMMON_H +#define _PCD_VALUE_COMMON_H + +#include <Common/UefiBaseTypes.h> +#include <Common/UefiInternalFormRepresentation.h> + +#define __FIELD_SIZE(TYPE, Field) (sizeof((TYPE *)0)->Field) +#define __ARRAY_ELEMENT_SIZE(TYPE, Field) (sizeof((TYPE *)0)->Field[0]) +#define __OFFSET_OF(TYPE, Field) ((UINT32)(size_t) &(((TYPE *)0)->Field)) +#define __FLEXIBLE_SIZE(Size, TYPE, Field, MaxIndex) if (__FIELD_SIZE(TYPE, Field) == 0) Size = MAX((__OFFSET_OF(TYPE, Field) + __ARRAY_ELEMENT_SIZE(TYPE, Field) * (MaxIndex)), Size) +#define __ARRAY_SIZE(Array) (sizeof(Array)/sizeof(Array[0])) + +#if defined(_MSC_EXTENSIONS) +#define __STATIC_ASSERT static_assert +#else +#define __STATIC_ASSERT _Static_assert +#endif + +/** + Main function updates PCD values. It is auto generated by Build +**/ +VOID +PcdEntryPoint ( + VOID + ) + +; + +/** + Main function updates PCD values. + + @param argc Number of command line parameters. + @param argv Array of pointers to parameter strings. + + @retval EXIT_SUCCESS +**/ +int +PcdValueMain ( + int argc, + char *argv[] + ) +; + +/** + Set PCD value + + @param SkuName SkuName String + @param DefaultValueName DefaultValueName String + @param TokenSpaceGuidName TokenSpaceGuidName String + @param TokenName TokenName String + @param Value PCD value to be set +**/ +VOID +__PcdSet ( + CHAR8 *SkuName OPTIONAL, + CHAR8 *DefaultValueName OPTIONAL, + CHAR8 *TokenSpaceGuidName, + CHAR8 *TokenName, + UINT64 Value + ) +; + +/** + Get PCD value + + @param SkuName SkuName String + @param DefaultValueName DefaultValueName String + @param TokenSpaceGuidName TokenSpaceGuidName String + @param TokenName TokenName String + + @return PCD value +**/ +UINT64 +__PcdGet ( + CHAR8 *SkuName OPTIONAL, + CHAR8 *DefaultValueName OPTIONAL, + CHAR8 *TokenSpaceGuidName, + CHAR8 *TokenName + ) +; + +/** + Get PCD value buffer + + @param SkuName SkuName String + @param DefaultValueName DefaultValueName String + @param TokenSpaceGuidName TokenSpaceGuidName String + @param TokenName TokenName String + @param Size Size of PCD value buffer + + @return PCD value buffer +**/ +VOID * +__PcdGetPtr ( + CHAR8 *SkuName OPTIONAL, + CHAR8 *DefaultValueName OPTIONAL, + CHAR8 *TokenSpaceGuidName, + CHAR8 *TokenName, + UINT32 *Size + ) +; + +/** + Set PCD value buffer + + @param SkuName SkuName String + @param DefaultValueName DefaultValueName String + @param TokenSpaceGuidName TokenSpaceGuidName String + @param TokenName TokenName String + @param Size Size of PCD value + @param Value Pointer to the updated PCD value buffer +**/ +VOID +__PcdSetPtr ( + CHAR8 *SkuName OPTIONAL, + CHAR8 *DefaultValueName OPTIONAL, + CHAR8 *TokenSpaceGuidName, + CHAR8 *TokenName, + UINT32 Size, + UINT8 *Value + ) +; + +#define PcdGet(A, B, C, D) __PcdGet(#A, #B, #C, #D) +#define PcdSet(A, B, C, D, Value) __PcdSet(#A, #B, #C, #D, Value) +#define PcdGetPtr(A, B, C, D, Size) __PcdGetPtr(#A, #B, #C, #D, Size) +#define PcdSetPtr(A, B, C, D, Size, Value) __PcdSetPtr(#A, #B, #C, #D, Size, Value) + +#endif diff --git a/BaseTools/Source/C/Common/PeCoffLib.h b/BaseTools/Source/C/Common/PeCoffLib.h index dd38f442f9..b625f6ac01 100644 --- a/BaseTools/Source/C/Common/PeCoffLib.h +++ b/BaseTools/Source/C/Common/PeCoffLib.h @@ -1,213 +1,213 @@ -/** @file
- Function prototypes and defines on Memory Only PE COFF loader
-
- Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
- Portion Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
- SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef __BASE_PE_COFF_LIB_H__
-#define __BASE_PE_COFF_LIB_H__
-
-//
-// Return status codes from the PE/COFF Loader services
-// BUGBUG: Find where used and see if can be replaced by RETURN_STATUS codes
-//
-#define IMAGE_ERROR_SUCCESS 0
-#define IMAGE_ERROR_IMAGE_READ 1
-#define IMAGE_ERROR_INVALID_PE_HEADER_SIGNATURE 2
-#define IMAGE_ERROR_INVALID_MACHINE_TYPE 3
-#define IMAGE_ERROR_INVALID_SUBSYSTEM 4
-#define IMAGE_ERROR_INVALID_IMAGE_ADDRESS 5
-#define IMAGE_ERROR_INVALID_IMAGE_SIZE 6
-#define IMAGE_ERROR_INVALID_SECTION_ALIGNMENT 7
-#define IMAGE_ERROR_SECTION_NOT_LOADED 8
-#define IMAGE_ERROR_FAILED_RELOCATION 9
-#define IMAGE_ERROR_FAILED_ICACHE_FLUSH 10
-
-//
-// Macro definitions for RISC-V architecture.
-//
-#define RV_X(x, s, n) (((x) >> (s)) & ((1<<(n))-1))
-#define RISCV_IMM_BITS 12
-#define RISCV_IMM_REACH (1LL<<RISCV_IMM_BITS)
-#define RISCV_CONST_HIGH_PART(VALUE) \
- (((VALUE) + (RISCV_IMM_REACH/2)) & ~(RISCV_IMM_REACH-1))
-
-//
-// PE/COFF Loader Read Function passed in by caller
-//
-typedef
-RETURN_STATUS
-(EFIAPI *PE_COFF_LOADER_READ_FILE) (
- IN VOID *FileHandle,
- IN UINTN FileOffset,
- IN OUT UINTN *ReadSize,
- OUT VOID *Buffer
- );
-
-//
-// Context structure used while PE/COFF image is being loaded and relocated
-//
-typedef struct {
- PHYSICAL_ADDRESS ImageAddress;
- UINT64 ImageSize;
- PHYSICAL_ADDRESS DestinationAddress;
- PHYSICAL_ADDRESS EntryPoint;
- PE_COFF_LOADER_READ_FILE ImageRead;
- VOID *Handle;
- VOID *FixupData;
- UINT32 SectionAlignment;
- UINT32 PeCoffHeaderOffset;
- UINT32 DebugDirectoryEntryRva;
- VOID *CodeView;
- CHAR8 *PdbPointer;
- UINTN SizeOfHeaders;
- UINT32 ImageCodeMemoryType;
- UINT32 ImageDataMemoryType;
- UINT32 ImageError;
- UINTN FixupDataSize;
- UINT16 Machine;
- UINT16 ImageType;
- BOOLEAN RelocationsStripped;
- BOOLEAN IsTeImage;
-} PE_COFF_LOADER_IMAGE_CONTEXT;
-
-
-/**
- Retrieves information on a PE/COFF image
-
- @param ImageContext The context of the image being loaded
-
- @retval EFI_SUCCESS The information on the PE/COFF image was collected.
- @retval EFI_INVALID_PARAMETER ImageContext is NULL.
- @retval EFI_UNSUPPORTED The PE/COFF image is not supported.
- @retval Otherwise The error status from reading the PE/COFF image using the
- ImageContext->ImageRead() function
-
-**/
-RETURN_STATUS
-EFIAPI
-PeCoffLoaderGetImageInfo (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
- )
-;
-
-/**
- Relocates a PE/COFF image in memory
-
- @param ImageContext Contains information on the loaded image to relocate
-
- @retval EFI_SUCCESS if the PE/COFF image was relocated
- @retval EFI_LOAD_ERROR if the image is not a valid PE/COFF image
- @retval EFI_UNSUPPORTED not support
-
-**/
-RETURN_STATUS
-EFIAPI
-PeCoffLoaderRelocateImage (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
- )
-;
-
-/**
- Loads a PE/COFF image into memory
-
- @param ImageContext Contains information on image to load into memory
-
- @retval EFI_SUCCESS if the PE/COFF image was loaded
- @retval EFI_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer
- @retval EFI_LOAD_ERROR if the image is a runtime driver with no relocations
- @retval EFI_INVALID_PARAMETER if the image address is invalid
-
-**/
-RETURN_STATUS
-EFIAPI
-PeCoffLoaderLoadImage (
- IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
- )
-;
-
-VOID *
-EFIAPI
-PeCoffLoaderGetPdbPointer (
- IN VOID *Pe32Data
- )
-;
-
-RETURN_STATUS
-EFIAPI
-PeCoffLoaderGetEntryPoint (
- IN VOID *Pe32Data,
- OUT VOID **EntryPoint,
- OUT VOID **BaseOfImage
- )
-;
-
-//
-// These functions are used by the ARM PE/COFF relocation code and by
-// the ELF to PE/COFF converter so that is why they are public
-//
-
-/**
- Pass in a pointer to an ARM MOVT or MOVW immediate instruction and
- return the immediate data encoded in the instruction
-
- @param Instruction Pointer to ARM MOVT or MOVW immediate instruction
-
- @return Immediate address encoded in the instruction
-
-**/
-UINT16
-EFIAPI
-ThumbMovtImmediateAddress (
- IN UINT16 *Instruction
- );
-
-/**
- Update an ARM MOVT or MOVW immediate instruction immediate data.
-
- @param Instruction Pointer to ARM MOVT or MOVW immediate instruction
- @param Address New address to patch into the instruction
-
-**/
-VOID
-EFIAPI
-ThumbMovtImmediatePatch (
- IN OUT UINT16 *Instruction,
- IN UINT16 Address
- );
-
-
-/**
- Pass in a pointer to an ARM MOVW/MOVT instruction pair and
- return the immediate data encoded in the two` instruction
-
- @param Instructions Pointer to ARM MOVW/MOVT instruction pair
-
- @return Immediate address encoded in the instructions
-
-**/
-UINT32
-EFIAPI
-ThumbMovwMovtImmediateAddress (
- IN UINT16 *Instructions
- );
-
-/**
- Update an ARM MOVW/MOVT immediate instruction instruction pair.
-
- @param Instructions Pointer to ARM MOVW/MOVT instruction pair
- @param Address New address to patch into the instructions
-**/
-VOID
-EFIAPI
-ThumbMovwMovtImmediatePatch (
- IN OUT UINT16 *Instructions,
- IN UINT32 Address
- );
-
-
-
-#endif
+/** @file + Function prototypes and defines on Memory Only PE COFF loader + + Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> + Portion Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR> + SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef __BASE_PE_COFF_LIB_H__ +#define __BASE_PE_COFF_LIB_H__ + +// +// Return status codes from the PE/COFF Loader services +// BUGBUG: Find where used and see if can be replaced by RETURN_STATUS codes +// +#define IMAGE_ERROR_SUCCESS 0 +#define IMAGE_ERROR_IMAGE_READ 1 +#define IMAGE_ERROR_INVALID_PE_HEADER_SIGNATURE 2 +#define IMAGE_ERROR_INVALID_MACHINE_TYPE 3 +#define IMAGE_ERROR_INVALID_SUBSYSTEM 4 +#define IMAGE_ERROR_INVALID_IMAGE_ADDRESS 5 +#define IMAGE_ERROR_INVALID_IMAGE_SIZE 6 +#define IMAGE_ERROR_INVALID_SECTION_ALIGNMENT 7 +#define IMAGE_ERROR_SECTION_NOT_LOADED 8 +#define IMAGE_ERROR_FAILED_RELOCATION 9 +#define IMAGE_ERROR_FAILED_ICACHE_FLUSH 10 + +// +// Macro definitions for RISC-V architecture. +// +#define RV_X(x, s, n) (((x) >> (s)) & ((1<<(n))-1)) +#define RISCV_IMM_BITS 12 +#define RISCV_IMM_REACH (1LL<<RISCV_IMM_BITS) +#define RISCV_CONST_HIGH_PART(VALUE) \ + (((VALUE) + (RISCV_IMM_REACH/2)) & ~(RISCV_IMM_REACH-1)) + +// +// PE/COFF Loader Read Function passed in by caller +// +typedef +RETURN_STATUS +(EFIAPI *PE_COFF_LOADER_READ_FILE) ( + IN VOID *FileHandle, + IN UINTN FileOffset, + IN OUT UINTN *ReadSize, + OUT VOID *Buffer + ); + +// +// Context structure used while PE/COFF image is being loaded and relocated +// +typedef struct { + PHYSICAL_ADDRESS ImageAddress; + UINT64 ImageSize; + PHYSICAL_ADDRESS DestinationAddress; + PHYSICAL_ADDRESS EntryPoint; + PE_COFF_LOADER_READ_FILE ImageRead; + VOID *Handle; + VOID *FixupData; + UINT32 SectionAlignment; + UINT32 PeCoffHeaderOffset; + UINT32 DebugDirectoryEntryRva; + VOID *CodeView; + CHAR8 *PdbPointer; + UINTN SizeOfHeaders; + UINT32 ImageCodeMemoryType; + UINT32 ImageDataMemoryType; + UINT32 ImageError; + UINTN FixupDataSize; + UINT16 Machine; + UINT16 ImageType; + BOOLEAN RelocationsStripped; + BOOLEAN IsTeImage; +} PE_COFF_LOADER_IMAGE_CONTEXT; + + +/** + Retrieves information on a PE/COFF image + + @param ImageContext The context of the image being loaded + + @retval EFI_SUCCESS The information on the PE/COFF image was collected. + @retval EFI_INVALID_PARAMETER ImageContext is NULL. + @retval EFI_UNSUPPORTED The PE/COFF image is not supported. + @retval Otherwise The error status from reading the PE/COFF image using the + ImageContext->ImageRead() function + +**/ +RETURN_STATUS +EFIAPI +PeCoffLoaderGetImageInfo ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +; + +/** + Relocates a PE/COFF image in memory + + @param ImageContext Contains information on the loaded image to relocate + + @retval EFI_SUCCESS if the PE/COFF image was relocated + @retval EFI_LOAD_ERROR if the image is not a valid PE/COFF image + @retval EFI_UNSUPPORTED not support + +**/ +RETURN_STATUS +EFIAPI +PeCoffLoaderRelocateImage ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +; + +/** + Loads a PE/COFF image into memory + + @param ImageContext Contains information on image to load into memory + + @retval EFI_SUCCESS if the PE/COFF image was loaded + @retval EFI_BUFFER_TOO_SMALL if the caller did not provide a large enough buffer + @retval EFI_LOAD_ERROR if the image is a runtime driver with no relocations + @retval EFI_INVALID_PARAMETER if the image address is invalid + +**/ +RETURN_STATUS +EFIAPI +PeCoffLoaderLoadImage ( + IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext + ) +; + +VOID * +EFIAPI +PeCoffLoaderGetPdbPointer ( + IN VOID *Pe32Data + ) +; + +RETURN_STATUS +EFIAPI +PeCoffLoaderGetEntryPoint ( + IN VOID *Pe32Data, + OUT VOID **EntryPoint, + OUT VOID **BaseOfImage + ) +; + +// +// These functions are used by the ARM PE/COFF relocation code and by +// the ELF to PE/COFF converter so that is why they are public +// + +/** + Pass in a pointer to an ARM MOVT or MOVW immediate instruction and + return the immediate data encoded in the instruction + + @param Instruction Pointer to ARM MOVT or MOVW immediate instruction + + @return Immediate address encoded in the instruction + +**/ +UINT16 +EFIAPI +ThumbMovtImmediateAddress ( + IN UINT16 *Instruction + ); + +/** + Update an ARM MOVT or MOVW immediate instruction immediate data. + + @param Instruction Pointer to ARM MOVT or MOVW immediate instruction + @param Address New address to patch into the instruction + +**/ +VOID +EFIAPI +ThumbMovtImmediatePatch ( + IN OUT UINT16 *Instruction, + IN UINT16 Address + ); + + +/** + Pass in a pointer to an ARM MOVW/MOVT instruction pair and + return the immediate data encoded in the two` instruction + + @param Instructions Pointer to ARM MOVW/MOVT instruction pair + + @return Immediate address encoded in the instructions + +**/ +UINT32 +EFIAPI +ThumbMovwMovtImmediateAddress ( + IN UINT16 *Instructions + ); + +/** + Update an ARM MOVW/MOVT immediate instruction instruction pair. + + @param Instructions Pointer to ARM MOVW/MOVT instruction pair + @param Address New address to patch into the instructions +**/ +VOID +EFIAPI +ThumbMovwMovtImmediatePatch ( + IN OUT UINT16 *Instructions, + IN UINT32 Address + ); + + + +#endif diff --git a/BaseTools/Source/C/Common/PeCoffLoaderEx.c b/BaseTools/Source/C/Common/PeCoffLoaderEx.c index 181192035e..c7fa7f49bd 100644 --- a/BaseTools/Source/C/Common/PeCoffLoaderEx.c +++ b/BaseTools/Source/C/Common/PeCoffLoaderEx.c @@ -1,391 +1,391 @@ -/** @file
-IA32 and X64 Specific relocation fixups
-
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
-Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
-Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
-Copyright (c) 2022, Loongson Technology Corporation Limited. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
---*/
-
-#include <Common/UefiBaseTypes.h>
-#include <IndustryStandard/PeImage.h>
-#include "PeCoffLib.h"
-#include "CommonLib.h"
-#include "EfiUtilityMsgs.h"
-
-
-#define EXT_IMM64(Value, Address, Size, InstPos, ValPos) \
- Value |= (((UINT64)((*(Address) >> InstPos) & (((UINT64)1 << Size) - 1))) << ValPos)
-
-#define INS_IMM64(Value, Address, Size, InstPos, ValPos) \
- *(UINT32*)Address = (*(UINT32*)Address & ~(((1 << Size) - 1) << InstPos)) | \
- ((UINT32)((((UINT64)Value >> ValPos) & (((UINT64)1 << Size) - 1))) << InstPos)
-
-#define IMM64_IMM7B_INST_WORD_X 3
-#define IMM64_IMM7B_SIZE_X 7
-#define IMM64_IMM7B_INST_WORD_POS_X 4
-#define IMM64_IMM7B_VAL_POS_X 0
-
-#define IMM64_IMM9D_INST_WORD_X 3
-#define IMM64_IMM9D_SIZE_X 9
-#define IMM64_IMM9D_INST_WORD_POS_X 18
-#define IMM64_IMM9D_VAL_POS_X 7
-
-#define IMM64_IMM5C_INST_WORD_X 3
-#define IMM64_IMM5C_SIZE_X 5
-#define IMM64_IMM5C_INST_WORD_POS_X 13
-#define IMM64_IMM5C_VAL_POS_X 16
-
-#define IMM64_IC_INST_WORD_X 3
-#define IMM64_IC_SIZE_X 1
-#define IMM64_IC_INST_WORD_POS_X 12
-#define IMM64_IC_VAL_POS_X 21
-
-#define IMM64_IMM41a_INST_WORD_X 1
-#define IMM64_IMM41a_SIZE_X 10
-#define IMM64_IMM41a_INST_WORD_POS_X 14
-#define IMM64_IMM41a_VAL_POS_X 22
-
-#define IMM64_IMM41b_INST_WORD_X 1
-#define IMM64_IMM41b_SIZE_X 8
-#define IMM64_IMM41b_INST_WORD_POS_X 24
-#define IMM64_IMM41b_VAL_POS_X 32
-
-#define IMM64_IMM41c_INST_WORD_X 2
-#define IMM64_IMM41c_SIZE_X 23
-#define IMM64_IMM41c_INST_WORD_POS_X 0
-#define IMM64_IMM41c_VAL_POS_X 40
-
-#define IMM64_SIGN_INST_WORD_X 3
-#define IMM64_SIGN_SIZE_X 1
-#define IMM64_SIGN_INST_WORD_POS_X 27
-#define IMM64_SIGN_VAL_POS_X 63
-
-UINT32 *RiscVHi20Fixup = NULL;
-
-/**
- Performs an IA-32 specific relocation fixup
-
- @param Reloc Pointer to the relocation record
- @param Fixup Pointer to the address to fix up
- @param FixupData Pointer to a buffer to log the fixups
- @param Adjust The offset to adjust the fixup
-
- @retval EFI_UNSUPPORTED - Unsupported now
-**/
-RETURN_STATUS
-PeCoffLoaderRelocateIa32Image (
- IN UINT16 *Reloc,
- IN OUT CHAR8 *Fixup,
- IN OUT CHAR8 **FixupData,
- IN UINT64 Adjust
- )
-{
- return RETURN_UNSUPPORTED;
-}
-
-/**
- Performs an RISC-V specific relocation fixup
-
- @param Reloc Pointer to the relocation record
- @param Fixup Pointer to the address to fix up
- @param FixupData Pointer to a buffer to log the fixups
- @param Adjust The offset to adjust the fixup
-
- @return Status code
-**/
-RETURN_STATUS
-PeCoffLoaderRelocateRiscVImage (
- IN UINT16 *Reloc,
- IN OUT CHAR8 *Fixup,
- IN OUT CHAR8 **FixupData,
- IN UINT64 Adjust
- )
-{
- UINT32 Value;
- UINT32 Value2;
-
- switch ((*Reloc) >> 12) {
- case EFI_IMAGE_REL_BASED_RISCV_HI20:
- RiscVHi20Fixup = (UINT32 *) Fixup;
- break;
-
- case EFI_IMAGE_REL_BASED_RISCV_LOW12I:
- if (RiscVHi20Fixup != NULL) {
- Value = (UINT32)(RV_X(*RiscVHi20Fixup, 12, 20) << 12);
- Value2 = (UINT32)(RV_X(*(UINT32 *)Fixup, 20, 12));
- if (Value2 & (RISCV_IMM_REACH/2)) {
- Value2 |= ~(RISCV_IMM_REACH-1);
- }
- Value += Value2;
- Value += (UINT32)Adjust;
- Value2 = RISCV_CONST_HIGH_PART (Value);
- *(UINT32 *)RiscVHi20Fixup = (RV_X (Value2, 12, 20) << 12) | \
- (RV_X (*(UINT32 *)RiscVHi20Fixup, 0, 12));
- *(UINT32 *)Fixup = (RV_X (Value, 0, 12) << 20) | \
- (RV_X (*(UINT32 *)Fixup, 0, 20));
- }
- RiscVHi20Fixup = NULL;
- break;
-
- case EFI_IMAGE_REL_BASED_RISCV_LOW12S:
- if (RiscVHi20Fixup != NULL) {
- Value = (UINT32)(RV_X(*RiscVHi20Fixup, 12, 20) << 12);
- Value2 = (UINT32)(RV_X(*(UINT32 *)Fixup, 7, 5) | (RV_X(*(UINT32 *)Fixup, 25, 7) << 5));
- if (Value2 & (RISCV_IMM_REACH/2)) {
- Value2 |= ~(RISCV_IMM_REACH-1);
- }
- Value += Value2;
- Value += (UINT32)Adjust;
- Value2 = RISCV_CONST_HIGH_PART (Value);
- *(UINT32 *)RiscVHi20Fixup = (RV_X (Value2, 12, 20) << 12) | \
- (RV_X (*(UINT32 *)RiscVHi20Fixup, 0, 12));
- Value2 = *(UINT32 *)Fixup & 0x01fff07f;
- Value &= RISCV_IMM_REACH - 1;
- *(UINT32 *)Fixup = Value2 | (UINT32)(((RV_X(Value, 0, 5) << 7) | (RV_X(Value, 5, 7) << 25)));
- }
- RiscVHi20Fixup = NULL;
- break;
-
- default:
- return EFI_UNSUPPORTED;
-
- }
- return RETURN_SUCCESS;
-}
-
-/**
- Pass in a pointer to an ARM MOVT or MOVW immediate instruction and
- return the immediate data encoded in the instruction
-
- @param Instruction Pointer to ARM MOVT or MOVW immediate instruction
-
- @return Immediate address encoded in the instruction
-
-**/
-UINT16
-ThumbMovtImmediateAddress (
- IN UINT16 *Instruction
- )
-{
- UINT32 Movt;
- UINT16 Address;
-
- // Thumb2 is two 16-bit instructions working together. Not a single 32-bit instruction
- // Example MOVT R0, #0 is 0x0000f2c0 or 0xf2c0 0x0000
- Movt = (*Instruction << 16) | (*(Instruction + 1));
-
- // imm16 = imm4:i:imm3:imm8
- // imm4 -> Bit19:Bit16
- // i -> Bit26
- // imm3 -> Bit14:Bit12
- // imm8 -> Bit7:Bit0
- Address = (UINT16)(Movt & 0x000000ff); // imm8
- Address |= (UINT16)((Movt >> 4) & 0x0000f700); // imm4 imm3
- Address |= (((Movt & BIT26) != 0) ? BIT11 : 0); // i
- return Address;
-}
-
-
-/**
- Update an ARM MOVT or MOVW immediate instruction immediate data.
-
- @param Instruction Pointer to ARM MOVT or MOVW immediate instruction
- @param Address New address to patch into the instruction
-**/
-VOID
-ThumbMovtImmediatePatch (
- IN OUT UINT16 *Instruction,
- IN UINT16 Address
- )
-{
- UINT16 Patch;
-
- // First 16-bit chunk of instruction
- Patch = ((Address >> 12) & 0x000f); // imm4
- Patch |= (((Address & BIT11) != 0) ? BIT10 : 0); // i
- *Instruction = (*Instruction & ~0x040f) | Patch;
-
- // Second 16-bit chunk of instruction
- Patch = Address & 0x000000ff; // imm8
- Patch |= ((Address << 4) & 0x00007000); // imm3
- Instruction++;
- *Instruction = (*Instruction & ~0x70ff) | Patch;
-}
-
-/**
- Pass in a pointer to an ARM MOVW/MOVT instruction pair and
- return the immediate data encoded in the two` instruction
-
- @param Instructions Pointer to ARM MOVW/MOVT instruction pair
-
- @return Immediate address encoded in the instructions
-
-**/
-UINT32
-EFIAPI
-ThumbMovwMovtImmediateAddress (
- IN UINT16 *Instructions
- )
-{
- UINT16 *Word;
- UINT16 *Top;
-
- Word = Instructions; // MOVW
- Top = Word + 2; // MOVT
-
- return (ThumbMovtImmediateAddress (Top) << 16) + ThumbMovtImmediateAddress (Word);
-}
-
-
-/**
- Update an ARM MOVW/MOVT immediate instruction instruction pair.
-
- @param Instructions Pointer to ARM MOVW/MOVT instruction pair
- @param Address New address to patch into the instructions
-**/
-VOID
-EFIAPI
-ThumbMovwMovtImmediatePatch (
- IN OUT UINT16 *Instructions,
- IN UINT32 Address
- )
-{
- UINT16 *Word;
- UINT16 *Top;
-
- Word = (UINT16 *)Instructions; // MOVW
- Top = Word + 2; // MOVT
-
- ThumbMovtImmediatePatch (Word, (UINT16)(Address & 0xffff));
- ThumbMovtImmediatePatch (Top, (UINT16)(Address >> 16));
-}
-
-
-/**
- Performs an ARM-based specific relocation fixup and is a no-op on other
- instruction sets.
-
- @param Reloc Pointer to the relocation record.
- @param Fixup Pointer to the address to fix up.
- @param FixupData Pointer to a buffer to log the fixups.
- @param Adjust The offset to adjust the fixup.
-
- @return Status code.
-
-**/
-RETURN_STATUS
-PeCoffLoaderRelocateArmImage (
- IN UINT16 **Reloc,
- IN OUT CHAR8 *Fixup,
- IN OUT CHAR8 **FixupData,
- IN UINT64 Adjust
- )
-{
- UINT16 *Fixup16;
- UINT32 FixupVal;
-
- Fixup16 = (UINT16 *) Fixup;
-
- switch ((**Reloc) >> 12) {
-
- case EFI_IMAGE_REL_BASED_ARM_MOV32T:
- FixupVal = ThumbMovwMovtImmediateAddress (Fixup16) + (UINT32)Adjust;
- ThumbMovwMovtImmediatePatch (Fixup16, FixupVal);
-
-
- if (*FixupData != NULL) {
- *FixupData = ALIGN_POINTER(*FixupData, sizeof(UINT64));
- CopyMem (*FixupData, Fixup16, sizeof (UINT64));
- *FixupData = *FixupData + sizeof(UINT64);
- }
- break;
-
- case EFI_IMAGE_REL_BASED_ARM_MOV32A:
- // break omitted - ARM instruction encoding not implemented
- default:
- return RETURN_UNSUPPORTED;
- }
-
- return RETURN_SUCCESS;
-}
-
-/**
- Performs a LoongArch specific relocation fixup.
-
- @param[in] Reloc Pointer to the relocation record.
- @param[in, out] Fixup Pointer to the address to fix up.
- @param[in, out] FixupData Pointer to a buffer to log the fixups.
- @param[in] Adjust The offset to adjust the fixup.
-
- @return Status code.
-**/
-RETURN_STATUS
-PeCoffLoaderRelocateLoongArch64Image (
- IN UINT16 *Reloc,
- IN OUT CHAR8 *Fixup,
- IN OUT CHAR8 **FixupData,
- IN UINT64 Adjust
- )
-{
- UINT8 RelocType;
- UINT64 Value;
- UINT64 Tmp1;
- UINT64 Tmp2;
-
- RelocType = ((*Reloc) >> 12);
- Value = 0;
- Tmp1 = 0;
- Tmp2 = 0;
-
- switch (RelocType) {
- case EFI_IMAGE_REL_BASED_LOONGARCH64_MARK_LA:
- // The next four instructions are used to load a 64 bit address, relocate all of them
- Value = (*(UINT32 *)Fixup & 0x1ffffe0) << 7 | // lu12i.w 20bits from bit5
- (*((UINT32 *)Fixup + 1) & 0x3ffc00) >> 10; // ori 12bits from bit10
- Tmp1 = *((UINT32 *)Fixup + 2) & 0x1ffffe0; // lu32i.d 20bits from bit5
- Tmp2 = *((UINT32 *)Fixup + 3) & 0x3ffc00; // lu52i.d 12bits from bit10
- Value = Value | (Tmp1 << 27) | (Tmp2 << 42);
- Value += Adjust;
-
- *(UINT32 *)Fixup = (*(UINT32 *)Fixup & ~0x1ffffe0) | (((Value >> 12) & 0xfffff) << 5);
- if (*FixupData != NULL) {
- *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT32));
- *(UINT32 *)(*FixupData) = *(UINT32 *)Fixup;
- *FixupData = *FixupData + sizeof (UINT32);
- }
-
- Fixup += sizeof (UINT32);
- *(UINT32 *)Fixup = (*(UINT32 *)Fixup & ~0x3ffc00) | ((Value & 0xfff) << 10);
- if (*FixupData != NULL) {
- *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT32));
- *(UINT32 *)(*FixupData) = *(UINT32 *)Fixup;
- *FixupData = *FixupData + sizeof (UINT32);
- }
-
- Fixup += sizeof (UINT32);
- *(UINT32 *)Fixup = (*(UINT32 *)Fixup & ~0x1ffffe0) | (((Value >> 32) & 0xfffff) << 5);
- if (*FixupData != NULL) {
- *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT32));
- *(UINT32 *)(*FixupData) = *(UINT32 *)Fixup;
- *FixupData = *FixupData + sizeof (UINT32);
- }
-
- Fixup += sizeof (UINT32);
- *(UINT32 *)Fixup = (*(UINT32 *)Fixup & ~0x3ffc00) | (((Value >> 52) & 0xfff) << 10);
- if (*FixupData != NULL) {
- *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT32));
- *(UINT32 *)(*FixupData) = *(UINT32 *)Fixup;
- *FixupData = *FixupData + sizeof (UINT32);
- }
-
- break;
- default:
- Error (NULL, 0, 3000, "", "PeCoffLoaderRelocateLoongArch64Image: Fixup[0x%x] Adjust[0x%llx] *Reloc[0x%x], type[0x%x].", *(UINT32 *)Fixup, Adjust, *Reloc, RelocType);
- return RETURN_UNSUPPORTED;
- }
-
- return RETURN_SUCCESS;
-}
+/** @file +IA32 and X64 Specific relocation fixups + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR> +Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR> +Copyright (c) 2022, Loongson Technology Corporation Limited. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +--*/ + +#include <Common/UefiBaseTypes.h> +#include <IndustryStandard/PeImage.h> +#include "PeCoffLib.h" +#include "CommonLib.h" +#include "EfiUtilityMsgs.h" + + +#define EXT_IMM64(Value, Address, Size, InstPos, ValPos) \ + Value |= (((UINT64)((*(Address) >> InstPos) & (((UINT64)1 << Size) - 1))) << ValPos) + +#define INS_IMM64(Value, Address, Size, InstPos, ValPos) \ + *(UINT32*)Address = (*(UINT32*)Address & ~(((1 << Size) - 1) << InstPos)) | \ + ((UINT32)((((UINT64)Value >> ValPos) & (((UINT64)1 << Size) - 1))) << InstPos) + +#define IMM64_IMM7B_INST_WORD_X 3 +#define IMM64_IMM7B_SIZE_X 7 +#define IMM64_IMM7B_INST_WORD_POS_X 4 +#define IMM64_IMM7B_VAL_POS_X 0 + +#define IMM64_IMM9D_INST_WORD_X 3 +#define IMM64_IMM9D_SIZE_X 9 +#define IMM64_IMM9D_INST_WORD_POS_X 18 +#define IMM64_IMM9D_VAL_POS_X 7 + +#define IMM64_IMM5C_INST_WORD_X 3 +#define IMM64_IMM5C_SIZE_X 5 +#define IMM64_IMM5C_INST_WORD_POS_X 13 +#define IMM64_IMM5C_VAL_POS_X 16 + +#define IMM64_IC_INST_WORD_X 3 +#define IMM64_IC_SIZE_X 1 +#define IMM64_IC_INST_WORD_POS_X 12 +#define IMM64_IC_VAL_POS_X 21 + +#define IMM64_IMM41a_INST_WORD_X 1 +#define IMM64_IMM41a_SIZE_X 10 +#define IMM64_IMM41a_INST_WORD_POS_X 14 +#define IMM64_IMM41a_VAL_POS_X 22 + +#define IMM64_IMM41b_INST_WORD_X 1 +#define IMM64_IMM41b_SIZE_X 8 +#define IMM64_IMM41b_INST_WORD_POS_X 24 +#define IMM64_IMM41b_VAL_POS_X 32 + +#define IMM64_IMM41c_INST_WORD_X 2 +#define IMM64_IMM41c_SIZE_X 23 +#define IMM64_IMM41c_INST_WORD_POS_X 0 +#define IMM64_IMM41c_VAL_POS_X 40 + +#define IMM64_SIGN_INST_WORD_X 3 +#define IMM64_SIGN_SIZE_X 1 +#define IMM64_SIGN_INST_WORD_POS_X 27 +#define IMM64_SIGN_VAL_POS_X 63 + +UINT32 *RiscVHi20Fixup = NULL; + +/** + Performs an IA-32 specific relocation fixup + + @param Reloc Pointer to the relocation record + @param Fixup Pointer to the address to fix up + @param FixupData Pointer to a buffer to log the fixups + @param Adjust The offset to adjust the fixup + + @retval EFI_UNSUPPORTED - Unsupported now +**/ +RETURN_STATUS +PeCoffLoaderRelocateIa32Image ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ) +{ + return RETURN_UNSUPPORTED; +} + +/** + Performs an RISC-V specific relocation fixup + + @param Reloc Pointer to the relocation record + @param Fixup Pointer to the address to fix up + @param FixupData Pointer to a buffer to log the fixups + @param Adjust The offset to adjust the fixup + + @return Status code +**/ +RETURN_STATUS +PeCoffLoaderRelocateRiscVImage ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ) +{ + UINT32 Value; + UINT32 Value2; + + switch ((*Reloc) >> 12) { + case EFI_IMAGE_REL_BASED_RISCV_HI20: + RiscVHi20Fixup = (UINT32 *) Fixup; + break; + + case EFI_IMAGE_REL_BASED_RISCV_LOW12I: + if (RiscVHi20Fixup != NULL) { + Value = (UINT32)(RV_X(*RiscVHi20Fixup, 12, 20) << 12); + Value2 = (UINT32)(RV_X(*(UINT32 *)Fixup, 20, 12)); + if (Value2 & (RISCV_IMM_REACH/2)) { + Value2 |= ~(RISCV_IMM_REACH-1); + } + Value += Value2; + Value += (UINT32)Adjust; + Value2 = RISCV_CONST_HIGH_PART (Value); + *(UINT32 *)RiscVHi20Fixup = (RV_X (Value2, 12, 20) << 12) | \ + (RV_X (*(UINT32 *)RiscVHi20Fixup, 0, 12)); + *(UINT32 *)Fixup = (RV_X (Value, 0, 12) << 20) | \ + (RV_X (*(UINT32 *)Fixup, 0, 20)); + } + RiscVHi20Fixup = NULL; + break; + + case EFI_IMAGE_REL_BASED_RISCV_LOW12S: + if (RiscVHi20Fixup != NULL) { + Value = (UINT32)(RV_X(*RiscVHi20Fixup, 12, 20) << 12); + Value2 = (UINT32)(RV_X(*(UINT32 *)Fixup, 7, 5) | (RV_X(*(UINT32 *)Fixup, 25, 7) << 5)); + if (Value2 & (RISCV_IMM_REACH/2)) { + Value2 |= ~(RISCV_IMM_REACH-1); + } + Value += Value2; + Value += (UINT32)Adjust; + Value2 = RISCV_CONST_HIGH_PART (Value); + *(UINT32 *)RiscVHi20Fixup = (RV_X (Value2, 12, 20) << 12) | \ + (RV_X (*(UINT32 *)RiscVHi20Fixup, 0, 12)); + Value2 = *(UINT32 *)Fixup & 0x01fff07f; + Value &= RISCV_IMM_REACH - 1; + *(UINT32 *)Fixup = Value2 | (UINT32)(((RV_X(Value, 0, 5) << 7) | (RV_X(Value, 5, 7) << 25))); + } + RiscVHi20Fixup = NULL; + break; + + default: + return EFI_UNSUPPORTED; + + } + return RETURN_SUCCESS; +} + +/** + Pass in a pointer to an ARM MOVT or MOVW immediate instruction and + return the immediate data encoded in the instruction + + @param Instruction Pointer to ARM MOVT or MOVW immediate instruction + + @return Immediate address encoded in the instruction + +**/ +UINT16 +ThumbMovtImmediateAddress ( + IN UINT16 *Instruction + ) +{ + UINT32 Movt; + UINT16 Address; + + // Thumb2 is two 16-bit instructions working together. Not a single 32-bit instruction + // Example MOVT R0, #0 is 0x0000f2c0 or 0xf2c0 0x0000 + Movt = (*Instruction << 16) | (*(Instruction + 1)); + + // imm16 = imm4:i:imm3:imm8 + // imm4 -> Bit19:Bit16 + // i -> Bit26 + // imm3 -> Bit14:Bit12 + // imm8 -> Bit7:Bit0 + Address = (UINT16)(Movt & 0x000000ff); // imm8 + Address |= (UINT16)((Movt >> 4) & 0x0000f700); // imm4 imm3 + Address |= (((Movt & BIT26) != 0) ? BIT11 : 0); // i + return Address; +} + + +/** + Update an ARM MOVT or MOVW immediate instruction immediate data. + + @param Instruction Pointer to ARM MOVT or MOVW immediate instruction + @param Address New address to patch into the instruction +**/ +VOID +ThumbMovtImmediatePatch ( + IN OUT UINT16 *Instruction, + IN UINT16 Address + ) +{ + UINT16 Patch; + + // First 16-bit chunk of instruction + Patch = ((Address >> 12) & 0x000f); // imm4 + Patch |= (((Address & BIT11) != 0) ? BIT10 : 0); // i + *Instruction = (*Instruction & ~0x040f) | Patch; + + // Second 16-bit chunk of instruction + Patch = Address & 0x000000ff; // imm8 + Patch |= ((Address << 4) & 0x00007000); // imm3 + Instruction++; + *Instruction = (*Instruction & ~0x70ff) | Patch; +} + +/** + Pass in a pointer to an ARM MOVW/MOVT instruction pair and + return the immediate data encoded in the two` instruction + + @param Instructions Pointer to ARM MOVW/MOVT instruction pair + + @return Immediate address encoded in the instructions + +**/ +UINT32 +EFIAPI +ThumbMovwMovtImmediateAddress ( + IN UINT16 *Instructions + ) +{ + UINT16 *Word; + UINT16 *Top; + + Word = Instructions; // MOVW + Top = Word + 2; // MOVT + + return (ThumbMovtImmediateAddress (Top) << 16) + ThumbMovtImmediateAddress (Word); +} + + +/** + Update an ARM MOVW/MOVT immediate instruction instruction pair. + + @param Instructions Pointer to ARM MOVW/MOVT instruction pair + @param Address New address to patch into the instructions +**/ +VOID +EFIAPI +ThumbMovwMovtImmediatePatch ( + IN OUT UINT16 *Instructions, + IN UINT32 Address + ) +{ + UINT16 *Word; + UINT16 *Top; + + Word = (UINT16 *)Instructions; // MOVW + Top = Word + 2; // MOVT + + ThumbMovtImmediatePatch (Word, (UINT16)(Address & 0xffff)); + ThumbMovtImmediatePatch (Top, (UINT16)(Address >> 16)); +} + + +/** + Performs an ARM-based specific relocation fixup and is a no-op on other + instruction sets. + + @param Reloc Pointer to the relocation record. + @param Fixup Pointer to the address to fix up. + @param FixupData Pointer to a buffer to log the fixups. + @param Adjust The offset to adjust the fixup. + + @return Status code. + +**/ +RETURN_STATUS +PeCoffLoaderRelocateArmImage ( + IN UINT16 **Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ) +{ + UINT16 *Fixup16; + UINT32 FixupVal; + + Fixup16 = (UINT16 *) Fixup; + + switch ((**Reloc) >> 12) { + + case EFI_IMAGE_REL_BASED_ARM_MOV32T: + FixupVal = ThumbMovwMovtImmediateAddress (Fixup16) + (UINT32)Adjust; + ThumbMovwMovtImmediatePatch (Fixup16, FixupVal); + + + if (*FixupData != NULL) { + *FixupData = ALIGN_POINTER(*FixupData, sizeof(UINT64)); + CopyMem (*FixupData, Fixup16, sizeof (UINT64)); + *FixupData = *FixupData + sizeof(UINT64); + } + break; + + case EFI_IMAGE_REL_BASED_ARM_MOV32A: + // break omitted - ARM instruction encoding not implemented + default: + return RETURN_UNSUPPORTED; + } + + return RETURN_SUCCESS; +} + +/** + Performs a LoongArch specific relocation fixup. + + @param[in] Reloc Pointer to the relocation record. + @param[in, out] Fixup Pointer to the address to fix up. + @param[in, out] FixupData Pointer to a buffer to log the fixups. + @param[in] Adjust The offset to adjust the fixup. + + @return Status code. +**/ +RETURN_STATUS +PeCoffLoaderRelocateLoongArch64Image ( + IN UINT16 *Reloc, + IN OUT CHAR8 *Fixup, + IN OUT CHAR8 **FixupData, + IN UINT64 Adjust + ) +{ + UINT8 RelocType; + UINT64 Value; + UINT64 Tmp1; + UINT64 Tmp2; + + RelocType = ((*Reloc) >> 12); + Value = 0; + Tmp1 = 0; + Tmp2 = 0; + + switch (RelocType) { + case EFI_IMAGE_REL_BASED_LOONGARCH64_MARK_LA: + // The next four instructions are used to load a 64 bit address, relocate all of them + Value = (*(UINT32 *)Fixup & 0x1ffffe0) << 7 | // lu12i.w 20bits from bit5 + (*((UINT32 *)Fixup + 1) & 0x3ffc00) >> 10; // ori 12bits from bit10 + Tmp1 = *((UINT32 *)Fixup + 2) & 0x1ffffe0; // lu32i.d 20bits from bit5 + Tmp2 = *((UINT32 *)Fixup + 3) & 0x3ffc00; // lu52i.d 12bits from bit10 + Value = Value | (Tmp1 << 27) | (Tmp2 << 42); + Value += Adjust; + + *(UINT32 *)Fixup = (*(UINT32 *)Fixup & ~0x1ffffe0) | (((Value >> 12) & 0xfffff) << 5); + if (*FixupData != NULL) { + *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT32)); + *(UINT32 *)(*FixupData) = *(UINT32 *)Fixup; + *FixupData = *FixupData + sizeof (UINT32); + } + + Fixup += sizeof (UINT32); + *(UINT32 *)Fixup = (*(UINT32 *)Fixup & ~0x3ffc00) | ((Value & 0xfff) << 10); + if (*FixupData != NULL) { + *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT32)); + *(UINT32 *)(*FixupData) = *(UINT32 *)Fixup; + *FixupData = *FixupData + sizeof (UINT32); + } + + Fixup += sizeof (UINT32); + *(UINT32 *)Fixup = (*(UINT32 *)Fixup & ~0x1ffffe0) | (((Value >> 32) & 0xfffff) << 5); + if (*FixupData != NULL) { + *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT32)); + *(UINT32 *)(*FixupData) = *(UINT32 *)Fixup; + *FixupData = *FixupData + sizeof (UINT32); + } + + Fixup += sizeof (UINT32); + *(UINT32 *)Fixup = (*(UINT32 *)Fixup & ~0x3ffc00) | (((Value >> 52) & 0xfff) << 10); + if (*FixupData != NULL) { + *FixupData = ALIGN_POINTER (*FixupData, sizeof (UINT32)); + *(UINT32 *)(*FixupData) = *(UINT32 *)Fixup; + *FixupData = *FixupData + sizeof (UINT32); + } + + break; + default: + Error (NULL, 0, 3000, "", "PeCoffLoaderRelocateLoongArch64Image: Fixup[0x%x] Adjust[0x%llx] *Reloc[0x%x], type[0x%x].", *(UINT32 *)Fixup, Adjust, *Reloc, RelocType); + return RETURN_UNSUPPORTED; + } + + return RETURN_SUCCESS; +} diff --git a/BaseTools/Source/C/Common/SimpleFileParsing.c b/BaseTools/Source/C/Common/SimpleFileParsing.c index 382cd406cb..2dcc865931 100644 --- a/BaseTools/Source/C/Common/SimpleFileParsing.c +++ b/BaseTools/Source/C/Common/SimpleFileParsing.c @@ -1,1323 +1,1323 @@ -/** @file
-Generic but simple file parsing routines.
-
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
---*/
-
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-
-#include "CommonLib.h"
-#include "EfiUtilityMsgs.h"
-#include "SimpleFileParsing.h"
-
-#ifndef MAX_PATH
-#define MAX_PATH 255
-#endif
-//
-// just in case we get in an endless loop.
-//
-#define MAX_NEST_DEPTH 20
-//
-// number of wchars
-//
-#define MAX_STRING_IDENTIFIER_NAME 100
-
-#define T_CHAR_SPACE ' '
-#define T_CHAR_NULL 0
-#define T_CHAR_CR '\r'
-#define T_CHAR_TAB '\t'
-#define T_CHAR_LF '\n'
-#define T_CHAR_SLASH '/'
-#define T_CHAR_BACKSLASH '\\'
-#define T_CHAR_DOUBLE_QUOTE '"'
-#define T_CHAR_LC_X 'x'
-#define T_CHAR_0 '0'
-#define T_CHAR_STAR '*'
-
-//
-// We keep a linked list of these for the source files we process
-//
-typedef struct _SOURCE_FILE {
- FILE *Fptr;
- CHAR8 *FileBuffer;
- CHAR8 *FileBufferPtr;
- UINTN FileSize;
- CHAR8 FileName[MAX_PATH];
- UINTN LineNum;
- BOOLEAN EndOfFile;
- BOOLEAN SkipToHash;
- struct _SOURCE_FILE *Previous;
- struct _SOURCE_FILE *Next;
- CHAR8 ControlCharacter;
-} SOURCE_FILE;
-
-typedef struct {
- CHAR8 *FileBufferPtr;
-} FILE_POSITION;
-
-//
-// Keep all our module globals in this structure
-//
-STATIC struct {
- SOURCE_FILE SourceFile;
- BOOLEAN VerboseFile;
- BOOLEAN VerboseToken;
-} mGlobals;
-
-STATIC
-UINTN
-t_strcmp (
- CHAR8 *Buffer,
- CHAR8 *Str
- );
-
-STATIC
-UINTN
-t_strncmp (
- CHAR8 *Str1,
- CHAR8 *Str2,
- INTN Len
- );
-
-STATIC
-UINTN
-t_strlen (
- CHAR8 *Str
- );
-
-STATIC
-VOID
-RewindFile (
- SOURCE_FILE *SourceFile
- );
-
-STATIC
-BOOLEAN
-IsWhiteSpace (
- SOURCE_FILE *SourceFile
- );
-
-STATIC
-UINTN
-SkipWhiteSpace (
- SOURCE_FILE *SourceFile
- );
-
-STATIC
-BOOLEAN
-EndOfFile (
- SOURCE_FILE *SourceFile
- );
-
-STATIC
-VOID
-PreprocessFile (
- SOURCE_FILE *SourceFile
- );
-
-STATIC
-CHAR8 *
-t_strcpy (
- CHAR8 *Dest,
- CHAR8 *Src
- );
-
-STATIC
-STATUS
-ProcessIncludeFile (
- SOURCE_FILE *SourceFile,
- SOURCE_FILE *ParentSourceFile
- );
-
-STATIC
-STATUS
-ProcessFile (
- SOURCE_FILE *SourceFile
- );
-
-STATIC
-STATUS
-GetFilePosition (
- FILE_POSITION *Fpos
- );
-
-STATIC
-STATUS
-SetFilePosition (
- FILE_POSITION *Fpos
- );
-
-/**
- @retval STATUS_SUCCESS always
-**/
-STATUS
-SFPInit (
- VOID
- )
-{
- memset ((VOID *) &mGlobals, 0, sizeof (mGlobals));
- return STATUS_SUCCESS;
-}
-
-/**
- Return the line number of the file we're parsing. Used
- for error reporting purposes.
-
- @return The line number, or 0 if no file is being processed
-**/
-UINTN
-SFPGetLineNumber (
- VOID
- )
-{
- return mGlobals.SourceFile.LineNum;
-}
-
-/**
- Return the name of the file we're parsing. Used
- for error reporting purposes.
-
- @return A pointer to the file name. Null if no file is being
- processed.
-**/
-CHAR8 *
-SFPGetFileName (
- VOID
- )
-{
- if (mGlobals.SourceFile.FileName[0]) {
- return mGlobals.SourceFile.FileName;
- }
-
- return NULL;
-}
-
-/**
- Open a file for parsing.
-
- @param FileName name of the file to parse
-**/
-STATUS
-SFPOpenFile (
- CHAR8 *FileName
- )
-{
- STATUS Status;
- t_strcpy (mGlobals.SourceFile.FileName, FileName);
- Status = ProcessIncludeFile (&mGlobals.SourceFile, NULL);
- return Status;
-}
-
-/**
- Check to see if the specified token is found at
- the current position in the input file.
-
- @note:
- We do a simple string comparison on this function. It is
- the responsibility of the caller to ensure that the token
- is not a subset of some other token.
-
- The file pointer is advanced past the token in the input file.
-
- @param Str the token to look for
-
- @retval TRUE the token is next
- @retval FALSE the token is not next
-**/
-BOOLEAN
-SFPIsToken (
- CHAR8 *Str
- )
-{
- UINTN Len;
- SkipWhiteSpace (&mGlobals.SourceFile);
- if (EndOfFile (&mGlobals.SourceFile)) {
- return FALSE;
- }
-
- if ((Len = t_strcmp (mGlobals.SourceFile.FileBufferPtr, Str)) > 0) {
- mGlobals.SourceFile.FileBufferPtr += Len;
- if (mGlobals.VerboseToken) {
- printf ("Token: '%s'\n", Str);
- }
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- Check to see if the specified keyword is found at
- the current position in the input file.
-
- @note:
- A keyword is defined as a "special" string that has a non-alphanumeric
- character following it.
-
- @param Str keyword to look for
-
- @retval TRUE the keyword is next
- @retval FALSE the keyword is not next
-**/
-BOOLEAN
-SFPIsKeyword (
- CHAR8 *Str
- )
-{
- UINTN Len;
- SkipWhiteSpace (&mGlobals.SourceFile);
- if (EndOfFile (&mGlobals.SourceFile)) {
- return FALSE;
- }
-
- if ((Len = t_strcmp (mGlobals.SourceFile.FileBufferPtr, Str)) > 0) {
- if (isalnum ((int)mGlobals.SourceFile.FileBufferPtr[Len])) {
- return FALSE;
- }
-
- mGlobals.SourceFile.FileBufferPtr += Len;
- if (mGlobals.VerboseToken) {
- printf ("Token: '%s'\n", Str);
- }
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- Get the next token from the input stream.
-
- @note:
- Preceding white space is ignored.
- The parser's buffer pointer is advanced past the end of the
- token.
-
- @param Str pointer to a copy of the next token
- @param Len size of buffer pointed to by Str
-
- @retval TRUE next token successfully returned
- @retval FALSE otherwise
-**/
-BOOLEAN
-SFPGetNextToken (
- CHAR8 *Str,
- UINTN Len
- )
-{
- UINTN Index;
- CHAR8 TempChar;
-
- SkipWhiteSpace (&mGlobals.SourceFile);
- if (EndOfFile (&mGlobals.SourceFile)) {
- return FALSE;
- }
- //
- // Have to have enough string for at least one char and a null-terminator
- //
- if (Len < 2) {
- return FALSE;
- }
- //
- // Look at the first character. If it's an identifier, then treat it
- // as such
- //
- TempChar = mGlobals.SourceFile.FileBufferPtr[0];
- if (((TempChar >= 'a') && (TempChar <= 'z')) || ((TempChar >= 'A') && (TempChar <= 'Z')) || (TempChar == '_')) {
- Str[0] = TempChar;
- mGlobals.SourceFile.FileBufferPtr++;
- Index = 1;
- while (!EndOfFile (&mGlobals.SourceFile) && (Index < Len)) {
- TempChar = mGlobals.SourceFile.FileBufferPtr[0];
- if (((TempChar >= 'a') && (TempChar <= 'z')) ||
- ((TempChar >= 'A') && (TempChar <= 'Z')) ||
- ((TempChar >= '0') && (TempChar <= '9')) ||
- (TempChar == '_')
- ) {
- Str[Index] = mGlobals.SourceFile.FileBufferPtr[0];
- mGlobals.SourceFile.FileBufferPtr++;
- Index++;
- } else {
- //
- // Invalid character for symbol name, so break out
- //
- break;
- }
- }
- //
- // Null terminate and return success
- //
- Str[Index] = 0;
- return TRUE;
- } else if ((TempChar == ')') || (TempChar == '(') || (TempChar == '*')) {
- Str[0] = mGlobals.SourceFile.FileBufferPtr[0];
- mGlobals.SourceFile.FileBufferPtr++;
- Str[1] = 0;
- return TRUE;
- } else {
- //
- // Everything else is white-space (or EOF) separated
- //
- Index = 0;
- while (!EndOfFile (&mGlobals.SourceFile) && (Index < Len)) {
- if (IsWhiteSpace (&mGlobals.SourceFile)) {
- if (Index > 0) {
- Str[Index] = 0;
- return TRUE;
- }
-
- return FALSE;
- } else {
- Str[Index] = mGlobals.SourceFile.FileBufferPtr[0];
- mGlobals.SourceFile.FileBufferPtr++;
- Index++;
- }
- }
- //
- // See if we just ran out of file contents, but did find a token
- //
- if ((Index > 0) && EndOfFile (&mGlobals.SourceFile)) {
- Str[Index] = 0;
- return TRUE;
- }
- }
-
- return FALSE;
-}
-
-/**
- Parse a GUID from the input stream. Stop when you discover white space.
-
- @param Str pointer to a copy of the next token
- @param Len size of buffer pointed to by Str
-
- @retval TRUE GUID string returned successfully
- @retval FALSE otherwise
-**/
-BOOLEAN
-SFPGetGuidToken (
- CHAR8 *Str,
- UINT32 Len
- )
-{
- UINT32 Index;
- SkipWhiteSpace (&mGlobals.SourceFile);
- if (EndOfFile (&mGlobals.SourceFile)) {
- return FALSE;
- }
-
- Index = 0;
- while (!EndOfFile (&mGlobals.SourceFile) && (Index < Len)) {
- if (IsWhiteSpace (&mGlobals.SourceFile)) {
- if (Index > 0) {
- Str[Index] = 0;
- return TRUE;
- }
-
- return FALSE;
- } else {
- Str[Index] = mGlobals.SourceFile.FileBufferPtr[0];
- mGlobals.SourceFile.FileBufferPtr++;
- Index++;
- }
- }
-
- return FALSE;
-}
-
-BOOLEAN
-SFPSkipToToken (
- CHAR8 *Str
- )
-{
- UINTN Len;
- CHAR8 *SavePos;
- Len = t_strlen (Str);
- SavePos = mGlobals.SourceFile.FileBufferPtr;
- SkipWhiteSpace (&mGlobals.SourceFile);
- while (!EndOfFile (&mGlobals.SourceFile)) {
- if (t_strncmp (Str, mGlobals.SourceFile.FileBufferPtr, Len) == 0) {
- mGlobals.SourceFile.FileBufferPtr += Len;
- return TRUE;
- }
-
- mGlobals.SourceFile.FileBufferPtr++;
- SkipWhiteSpace (&mGlobals.SourceFile);
- }
-
- mGlobals.SourceFile.FileBufferPtr = SavePos;
- return FALSE;
-}
-
-/**
- Check the token at the current file position for a numeric value.
- May be either decimal or hex.
-
- @param Value pointer where to store the value
-
- @retval FALSE current token is not a number
- @retval TRUE current token is a number
-**/
-BOOLEAN
-SFPGetNumber (
- UINTN *Value
- )
-{
- int Val;
-
- SkipWhiteSpace (&mGlobals.SourceFile);
- if (EndOfFile (&mGlobals.SourceFile)) {
- return FALSE;
- }
-
- if (isdigit ((int)mGlobals.SourceFile.FileBufferPtr[0])) {
- //
- // Check for hex value
- //
- if ((mGlobals.SourceFile.FileBufferPtr[0] == T_CHAR_0) && (mGlobals.SourceFile.FileBufferPtr[1] == T_CHAR_LC_X)) {
- if (!isxdigit ((int)mGlobals.SourceFile.FileBufferPtr[2])) {
- return FALSE;
- }
-
- mGlobals.SourceFile.FileBufferPtr += 2;
- sscanf (mGlobals.SourceFile.FileBufferPtr, "%x", &Val);
- *Value = (UINT32) Val;
- while (isxdigit ((int)mGlobals.SourceFile.FileBufferPtr[0])) {
- mGlobals.SourceFile.FileBufferPtr++;
- }
-
- return TRUE;
- } else {
- *Value = atoi (mGlobals.SourceFile.FileBufferPtr);
- while (isdigit ((int)mGlobals.SourceFile.FileBufferPtr[0])) {
- mGlobals.SourceFile.FileBufferPtr++;
- }
-
- return TRUE;
- }
- } else {
- return FALSE;
- }
-}
-
-/**
- Close the file being parsed.
-
- @retval STATUS_SUCCESS the file was closed
- @retval STATUS_ERROR no file is currently open
-**/
-STATUS
-SFPCloseFile (
- VOID
- )
-{
- if (mGlobals.SourceFile.FileBuffer != NULL) {
- free (mGlobals.SourceFile.FileBuffer);
- memset (&mGlobals.SourceFile, 0, sizeof (mGlobals.SourceFile));
- return STATUS_SUCCESS;
- }
-
- return STATUS_ERROR;
-}
-
-/**
- Given a source file, open the file and parse it
-
- @param SourceFile name of file to parse
- @param ParentSourceFile for error reporting purposes, the file that #included SourceFile.
-
- @return Standard status.
-**/
-STATIC
-STATUS
-ProcessIncludeFile (
- SOURCE_FILE *SourceFile,
- SOURCE_FILE *ParentSourceFile
- )
-{
- STATIC UINTN NestDepth = 0;
- CHAR8 FoundFileName[MAX_PATH];
- STATUS Status;
-
- Status = STATUS_SUCCESS;
- NestDepth++;
- //
- // Print the file being processed. Indent so you can tell the include nesting
- // depth.
- //
- if (mGlobals.VerboseFile) {
- fprintf (stdout, "%*cProcessing file '%s'\n", (int)NestDepth * 2, ' ', SourceFile->FileName);
- fprintf (stdout, "Parent source file = '%s'\n", ParentSourceFile->FileName);
- }
-
- //
- // Make sure we didn't exceed our maximum nesting depth
- //
- if (NestDepth > MAX_NEST_DEPTH) {
- Error (NULL, 0, 3001, "Not Supported", "%s exceeds max nesting depth (%u)", SourceFile->FileName, (unsigned) NestDepth);
- Status = STATUS_ERROR;
- goto Finish;
- }
- //
- // Try to open the file locally, and if that fails try along our include paths.
- //
- strcpy (FoundFileName, SourceFile->FileName);
- if ((SourceFile->Fptr = fopen (LongFilePath (FoundFileName), "rb")) == NULL) {
- return STATUS_ERROR;
- }
- //
- // Process the file found
- //
- ProcessFile (SourceFile);
-Finish:
- //
- // Close open files and return status
- //
- if (SourceFile->Fptr != NULL) {
- fclose (SourceFile->Fptr);
- SourceFile->Fptr = NULL;
- }
-
- return Status;
-}
-
-/**
- Given a source file that's been opened, read the contents into an internal
- buffer and pre-process it to remove comments.
-
- @param SourceFile structure containing info on the file to process
-
- @return Standard status.
-**/
-STATIC
-STATUS
-ProcessFile (
- SOURCE_FILE *SourceFile
- )
-{
- //
- // Get the file size, and then read the entire thing into memory.
- // Allocate extra space for a terminator character.
- //
- fseek (SourceFile->Fptr, 0, SEEK_END);
- SourceFile->FileSize = ftell (SourceFile->Fptr);
- if (mGlobals.VerboseFile) {
- printf ("FileSize = %u (0x%X)\n", (unsigned) SourceFile->FileSize, (unsigned) SourceFile->FileSize);
- }
-
- fseek (SourceFile->Fptr, 0, SEEK_SET);
- SourceFile->FileBuffer = (CHAR8 *) malloc (SourceFile->FileSize + sizeof (CHAR8 ));
- if (SourceFile->FileBuffer == NULL) {
- Error (NULL, 0, 4001, "Resource: memory cannot be allocated", NULL);
- return STATUS_ERROR;
- }
-
- fread ((VOID *) SourceFile->FileBuffer, SourceFile->FileSize, 1, SourceFile->Fptr);
- SourceFile->FileBuffer[(SourceFile->FileSize / sizeof (CHAR8 ))] = T_CHAR_NULL;
- //
- // Pre-process the file to replace comments with spaces
- //
- PreprocessFile (SourceFile);
- SourceFile->LineNum = 1;
- return STATUS_SUCCESS;
-}
-
-/**
- Preprocess a file to replace all carriage returns with NULLs so
- we can print lines (as part of error messages) from the file to the screen.
-
- @param SourceFile structure that we use to keep track of an input file.
-**/
-STATIC
-VOID
-PreprocessFile (
- SOURCE_FILE *SourceFile
- )
-{
- BOOLEAN InComment;
- BOOLEAN SlashSlashComment;
- int LineNum;
-
- RewindFile (SourceFile);
- InComment = FALSE;
- SlashSlashComment = FALSE;
- while (!EndOfFile (SourceFile)) {
- //
- // If a line-feed, then no longer in a comment if we're in a // comment
- //
- if (SourceFile->FileBufferPtr[0] == T_CHAR_LF) {
- SourceFile->FileBufferPtr++;
- SourceFile->LineNum++;
- if (InComment && SlashSlashComment) {
- InComment = FALSE;
- SlashSlashComment = FALSE;
- }
- } else if (SourceFile->FileBufferPtr[0] == T_CHAR_CR) {
- //
- // Replace all carriage returns with a NULL so we can print stuff
- //
- SourceFile->FileBufferPtr[0] = 0;
- SourceFile->FileBufferPtr++;
- //
- // Check for */ comment end
- //
- } else if (InComment &&
- !SlashSlashComment &&
- (SourceFile->FileBufferPtr[0] == T_CHAR_STAR) &&
- (SourceFile->FileBufferPtr[1] == T_CHAR_SLASH)
- ) {
- SourceFile->FileBufferPtr[0] = T_CHAR_SPACE;
- SourceFile->FileBufferPtr++;
- SourceFile->FileBufferPtr[0] = T_CHAR_SPACE;
- SourceFile->FileBufferPtr++;
- InComment = FALSE;
- } else if (InComment) {
- SourceFile->FileBufferPtr[0] = T_CHAR_SPACE;
- SourceFile->FileBufferPtr++;
- //
- // Check for // comments
- //
- } else if ((SourceFile->FileBufferPtr[0] == T_CHAR_SLASH) && (SourceFile->FileBufferPtr[1] == T_CHAR_SLASH)) {
- InComment = TRUE;
- SlashSlashComment = TRUE;
- //
- // Check for /* comment start
- //
- } else if ((SourceFile->FileBufferPtr[0] == T_CHAR_SLASH) && (SourceFile->FileBufferPtr[1] == T_CHAR_STAR)) {
- SourceFile->FileBufferPtr[0] = T_CHAR_SPACE;
- SourceFile->FileBufferPtr++;
- SourceFile->FileBufferPtr[0] = T_CHAR_SPACE;
- SourceFile->FileBufferPtr++;
- SlashSlashComment = FALSE;
- InComment = TRUE;
- } else {
- SourceFile->FileBufferPtr++;
- }
- }
- //
- // Could check for end-of-file and still in a comment, but
- // should not be necessary. So just restore the file pointers.
- //
- RewindFile (SourceFile);
- //
- // Dump the reformatted file if verbose mode
- //
- if (mGlobals.VerboseFile) {
- LineNum = 1;
- printf ("%04d: ", LineNum);
- while (!EndOfFile (SourceFile)) {
- if (SourceFile->FileBufferPtr[0] == T_CHAR_LF) {
- printf ("'\n%04d: '", ++LineNum);
- } else {
- printf ("%c", SourceFile->FileBufferPtr[0]);
- }
-
- SourceFile->FileBufferPtr++;
- }
-
- printf ("'\n");
- printf ("FileSize = %u (0x%X)\n", (unsigned)SourceFile->FileSize, (unsigned)SourceFile->FileSize);
- RewindFile (SourceFile);
- }
-}
-
-/**
- Retrieve a quoted-string from the input file.
-
- @param Str pointer to a copy of the quoted string parsed
- @param Length size of buffer pointed to by Str
-
- @retval TRUE next token in input stream was a quoted string, and
- the string value was returned in Str
- @retval FALSE otherwise
-**/
-BOOLEAN
-SFPGetQuotedString (
- CHAR8 *Str,
- INTN Length
- )
-{
- SkipWhiteSpace (&mGlobals.SourceFile);
- if (EndOfFile (&mGlobals.SourceFile)) {
- return FALSE;
- }
-
- if (mGlobals.SourceFile.FileBufferPtr[0] == T_CHAR_DOUBLE_QUOTE) {
- mGlobals.SourceFile.FileBufferPtr++;
- while (Length > 0) {
- if (EndOfFile (&mGlobals.SourceFile)) {
- return FALSE;
- }
- //
- // Check for closing quote
- //
- if (mGlobals.SourceFile.FileBufferPtr[0] == T_CHAR_DOUBLE_QUOTE) {
- mGlobals.SourceFile.FileBufferPtr++;
- *Str = 0;
- return TRUE;
- }
-
- *Str = mGlobals.SourceFile.FileBufferPtr[0];
- Str++;
- Length--;
- mGlobals.SourceFile.FileBufferPtr++;
- }
- }
- //
- // First character was not a quote, or the input string length was
- // insufficient to contain the quoted string, so return failure code.
- //
- return FALSE;
-}
-
-/**
- Return TRUE of FALSE to indicate whether or not we've reached the end of the
- file we're parsing.
-
- @retval TRUE EOF reached
- @retval FALSE otherwise
-**/
-BOOLEAN
-SFPIsEOF (
- VOID
- )
-{
- SkipWhiteSpace (&mGlobals.SourceFile);
- return EndOfFile (&mGlobals.SourceFile);
-}
-
-#if 0
-STATIC
-CHAR8 *
-GetQuotedString (
- SOURCE_FILE *SourceFile,
- BOOLEAN Optional
- )
-{
- CHAR8 *String;
- CHAR8 *Start;
- CHAR8 *Ptr;
- UINTN Len;
- BOOLEAN PreviousBackslash;
-
- if (SourceFile->FileBufferPtr[0] != T_CHAR_DOUBLE_QUOTE) {
- if (Optional == FALSE) {
- Error (SourceFile->FileName, SourceFile->LineNum, 0, "expected quoted string", "%S", SourceFile->FileBufferPtr);
- }
-
- return NULL;
- }
-
- Len = 0;
- SourceFile->FileBufferPtr++;
- Start = Ptr = SourceFile->FileBufferPtr;
- PreviousBackslash = FALSE;
- while (!EndOfFile (SourceFile)) {
- if ((SourceFile->FileBufferPtr[0] == T_CHAR_DOUBLE_QUOTE) && (PreviousBackslash == FALSE)) {
- break;
- } else if (SourceFile->FileBufferPtr[0] == T_CHAR_CR) {
- Warning (SourceFile->FileName, SourceFile->LineNum, 0, "carriage return found in quoted string", "%S", Start);
- PreviousBackslash = FALSE;
- } else if (SourceFile->FileBufferPtr[0] == T_CHAR_BACKSLASH) {
- PreviousBackslash = TRUE;
- } else {
- PreviousBackslash = FALSE;
- }
-
- SourceFile->FileBufferPtr++;
- Len++;
- }
-
- if (SourceFile->FileBufferPtr[0] != T_CHAR_DOUBLE_QUOTE) {
- Warning (SourceFile->FileName, SourceFile->LineNum, 0, "missing closing quote on string", "%S", Start);
- } else {
- SourceFile->FileBufferPtr++;
- }
- //
- // Now allocate memory for the string and save it off
- //
- String = (CHAR8 *) malloc ((Len + 1) * sizeof (CHAR8 ));
- if (String == NULL) {
- Error (NULL, 0, 4001, "Resource: memory cannot be allocated", NULL);
- return NULL;
- }
- //
- // Copy the string from the file buffer to the local copy.
- // We do no reformatting of it whatsoever at this point.
- //
- Ptr = String;
- while (Len > 0) {
- *Ptr = *Start;
- Start++;
- Ptr++;
- Len--;
- }
-
- *Ptr = 0;
- return String;
-}
-#endif
-STATIC
-BOOLEAN
-EndOfFile (
- SOURCE_FILE *SourceFile
- )
-{
- //
- // The file buffer pointer will typically get updated before the End-of-file flag in the
- // source file structure, so check it first.
- //
- if (SourceFile->FileBufferPtr >= SourceFile->FileBuffer + SourceFile->FileSize / sizeof (CHAR8 )) {
- SourceFile->EndOfFile = TRUE;
- return TRUE;
- }
-
- if (SourceFile->EndOfFile) {
- return TRUE;
- }
-
- return FALSE;
-}
-
-#if 0
-STATIC
-VOID
-ProcessTokenInclude (
- SOURCE_FILE *SourceFile
- )
-{
- CHAR8 IncludeFileName[MAX_PATH];
- CHAR8 *To;
- UINTN Len;
- BOOLEAN ReportedError;
- SOURCE_FILE IncludedSourceFile;
-
- ReportedError = FALSE;
- if (SkipWhiteSpace (SourceFile) == 0) {
- Warning (SourceFile->FileName, SourceFile->LineNum, 0, "expected whitespace following #include keyword", NULL);
- }
- //
- // Should be quoted file name
- //
- if (SourceFile->FileBufferPtr[0] != T_CHAR_DOUBLE_QUOTE) {
- Error (SourceFile->FileName, SourceFile->LineNum, 0, "expected quoted include file name", NULL);
- goto FailDone;
- }
-
- SourceFile->FileBufferPtr++;
- //
- // Copy the filename as ascii to our local string
- //
- To = IncludeFileName;
- Len = 0;
- while (!EndOfFile (SourceFile)) {
- if ((SourceFile->FileBufferPtr[0] == T_CHAR_CR) || (SourceFile->FileBufferPtr[0] == T_CHAR_LF)) {
- Error (SourceFile->FileName, SourceFile->LineNum, 0, "end-of-line found in quoted include file name", NULL);
- goto FailDone;
- }
-
- if (SourceFile->FileBufferPtr[0] == T_CHAR_DOUBLE_QUOTE) {
- SourceFile->FileBufferPtr++;
- break;
- }
- //
- // If too long, then report the error once and process until the closing quote
- //
- Len++;
- if (!ReportedError && (Len >= sizeof (IncludeFileName))) {
- Error (SourceFile->FileName, SourceFile->LineNum, 0, "length of include file name exceeds limit", NULL);
- ReportedError = TRUE;
- }
-
- if (!ReportedError) {
- *To = (CHAR8 ) SourceFile->FileBufferPtr[0];
- To++;
- }
-
- SourceFile->FileBufferPtr++;
- }
-
- if (!ReportedError) {
- *To = 0;
- memset ((CHAR8 *) &IncludedSourceFile, 0, sizeof (SOURCE_FILE));
- strcpy (IncludedSourceFile.FileName, IncludeFileName);
- ProcessIncludeFile (&IncludedSourceFile, SourceFile);
- }
-
- return ;
-FailDone:
- //
- // Error recovery -- skip to next #
- //
- SourceFile->SkipToHash = TRUE;
-}
-#endif
-STATIC
-BOOLEAN
-IsWhiteSpace (
- SOURCE_FILE *SourceFile
- )
-{
- switch (*SourceFile->FileBufferPtr) {
- case T_CHAR_NULL:
- case T_CHAR_CR:
- case T_CHAR_SPACE:
- case T_CHAR_TAB:
- case T_CHAR_LF:
- return TRUE;
-
- default:
- return FALSE;
- }
-}
-
-UINTN
-SkipWhiteSpace (
- SOURCE_FILE *SourceFile
- )
-{
- UINTN Count;
-
- Count = 0;
- while (!EndOfFile (SourceFile)) {
- Count++;
- switch (*SourceFile->FileBufferPtr) {
- case T_CHAR_NULL:
- case T_CHAR_CR:
- case T_CHAR_SPACE:
- case T_CHAR_TAB:
- SourceFile->FileBufferPtr++;
- break;
-
- case T_CHAR_LF:
- SourceFile->FileBufferPtr++;
- SourceFile->LineNum++;
- break;
-
- default:
- return Count - 1;
- }
- }
- //
- // Some tokens require trailing whitespace. If we're at the end of the
- // file, then we count that as well.
- //
- if ((Count == 0) && (EndOfFile (SourceFile))) {
- Count++;
- }
-
- return Count;
-}
-
-/**
- Compare two strings for equality. The string pointed to by 'Buffer' may or may not be null-terminated,
- so only compare up to the length of Str.
-
- @param Buffer pointer to first (possibly not null-terminated) string
- @param Str pointer to null-terminated string to compare to Buffer
-
- @retval Number of bytes matched if exact match
- @retval 0 if Buffer does not start with Str
-**/
-STATIC
-UINTN
-t_strcmp (
- CHAR8 *Buffer,
- CHAR8 *Str
- )
-{
- UINTN Len;
-
- Len = 0;
- while (*Str && (*Str == *Buffer)) {
- Buffer++;
- Str++;
- Len++;
- }
-
- if (*Str) {
- return 0;
- }
-
- return Len;
-}
-
-STATIC
-UINTN
-t_strlen (
- CHAR8 *Str
- )
-{
- UINTN Len;
- Len = 0;
- while (*Str) {
- Len++;
- Str++;
- }
-
- return Len;
-}
-
-STATIC
-UINTN
-t_strncmp (
- CHAR8 *Str1,
- CHAR8 *Str2,
- INTN Len
- )
-{
- while (Len > 0) {
- if (*Str1 != *Str2) {
- return Len;
- }
-
- Len--;
- Str1++;
- Str2++;
- }
-
- return 0;
-}
-
-STATIC
-CHAR8 *
-t_strcpy (
- CHAR8 *Dest,
- CHAR8 *Src
- )
-{
- CHAR8 *SaveDest;
- SaveDest = Dest;
- while (*Src) {
- *Dest = *Src;
- Dest++;
- Src++;
- }
-
- *Dest = 0;
- return SaveDest;
-}
-
-STATIC
-VOID
-RewindFile (
- SOURCE_FILE *SourceFile
- )
-{
- SourceFile->LineNum = 1;
- SourceFile->FileBufferPtr = SourceFile->FileBuffer;
- SourceFile->EndOfFile = 0;
-}
-
-STATIC
-UINT32
-GetHexChars (
- CHAR8 *Buffer,
- UINT32 BufferLen
- )
-{
- UINT32 Len;
- Len = 0;
- while (!EndOfFile (&mGlobals.SourceFile) && (Len < BufferLen)) {
- if (isxdigit ((int)mGlobals.SourceFile.FileBufferPtr[0])) {
- Buffer[Len] = mGlobals.SourceFile.FileBufferPtr[0];
- Len++;
- mGlobals.SourceFile.FileBufferPtr++;
- } else {
- break;
- }
- }
- //
- // Null terminate if we can
- //
- if ((Len > 0) && (Len < BufferLen)) {
- Buffer[Len] = 0;
- }
-
- return Len;
-}
-
-/**
- Parse a GUID from the input stream. Stop when you discover white space.
-
- GUID styles
- Style[0] 12345678-1234-5678-AAAA-BBBBCCCCDDDD
-
- @param GuidStyle Style of the following GUID token
- @param Value pointer to EFI_GUID struct for output
-
- @retval TRUE GUID string parsed successfully
- @retval FALSE otherwise
-**/
-BOOLEAN
-SFPGetGuid (
- INTN GuidStyle,
- EFI_GUID *Value
- )
-{
- INT32 Value32;
- UINT32 Index;
- FILE_POSITION FPos;
- CHAR8 TempString[20];
- CHAR8 TempString2[3];
- CHAR8 *From;
- CHAR8 *To;
- UINT32 Len;
- BOOLEAN Status;
-
- Status = FALSE;
- //
- // Skip white space, then start parsing
- //
- SkipWhiteSpace (&mGlobals.SourceFile);
- GetFilePosition (&FPos);
- if (EndOfFile (&mGlobals.SourceFile)) {
- return FALSE;
- }
-
- if (GuidStyle == PARSE_GUID_STYLE_5_FIELDS) {
- //
- // Style[0] 12345678-1234-5678-AAAA-BBBBCCCCDDDD
- //
- Len = GetHexChars (TempString, sizeof (TempString));
- if ((Len == 0) || (Len > 8)) {
- goto Done;
- }
-
- sscanf (TempString, "%x", &Value32);
- Value->Data1 = Value32;
- //
- // Next two UINT16 fields
- //
- if (mGlobals.SourceFile.FileBufferPtr[0] != '-') {
- goto Done;
- }
-
- mGlobals.SourceFile.FileBufferPtr++;
- Len = GetHexChars (TempString, sizeof (TempString));
- if ((Len == 0) || (Len > 4)) {
- goto Done;
- }
-
- sscanf (TempString, "%x", &Value32);
- Value->Data2 = (UINT16) Value32;
-
- if (mGlobals.SourceFile.FileBufferPtr[0] != '-') {
- goto Done;
- }
-
- mGlobals.SourceFile.FileBufferPtr++;
- Len = GetHexChars (TempString, sizeof (TempString));
- if ((Len == 0) || (Len > 4)) {
- goto Done;
- }
-
- sscanf (TempString, "%x", &Value32);
- Value->Data3 = (UINT16) Value32;
- //
- // Parse the "AAAA" as two bytes
- //
- if (mGlobals.SourceFile.FileBufferPtr[0] != '-') {
- goto Done;
- }
-
- mGlobals.SourceFile.FileBufferPtr++;
- Len = GetHexChars (TempString, sizeof (TempString));
- if ((Len == 0) || (Len > 4)) {
- goto Done;
- }
-
- sscanf (TempString, "%x", &Value32);
- Value->Data4[0] = (UINT8) (Value32 >> 8);
- Value->Data4[1] = (UINT8) Value32;
- if (mGlobals.SourceFile.FileBufferPtr[0] != '-') {
- goto Done;
- }
-
- mGlobals.SourceFile.FileBufferPtr++;
- //
- // Read the last 6 bytes of the GUID
- //
- //
- Len = GetHexChars (TempString, sizeof (TempString));
- if ((Len == 0) || (Len > 12)) {
- goto Done;
- }
- //
- // Insert leading 0's to make life easier
- //
- if (Len != 12) {
- From = TempString + Len - 1;
- To = TempString + 11;
- TempString[12] = 0;
- while (From >= TempString) {
- *To = *From;
- To--;
- From--;
- }
-
- while (To >= TempString) {
- *To = '0';
- To--;
- }
- }
- //
- // Now parse each byte
- //
- TempString2[2] = 0;
- for (Index = 0; Index < 6; Index++) {
- //
- // Copy the two characters from the input string to something
- // we can parse.
- //
- TempString2[0] = TempString[Index * 2];
- TempString2[1] = TempString[Index * 2 + 1];
- sscanf (TempString2, "%x", &Value32);
- Value->Data4[Index + 2] = (UINT8) Value32;
- }
-
- Status = TRUE;
- } else {
- //
- // Unsupported GUID style
- //
- return FALSE;
- }
-
-Done:
- if (Status == FALSE) {
- SetFilePosition (&FPos);
- }
-
- return Status;
-}
-
-STATIC
-STATUS
-GetFilePosition (
- FILE_POSITION *Fpos
- )
-{
- Fpos->FileBufferPtr = mGlobals.SourceFile.FileBufferPtr;
- return STATUS_SUCCESS;
-}
-
-STATIC
-STATUS
-SetFilePosition (
- FILE_POSITION *Fpos
- )
-{
- //
- // Should check range of pointer
- //
- mGlobals.SourceFile.FileBufferPtr = Fpos->FileBufferPtr;
- return STATUS_SUCCESS;
-}
+/** @file +Generic but simple file parsing routines. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +--*/ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <ctype.h> + +#include "CommonLib.h" +#include "EfiUtilityMsgs.h" +#include "SimpleFileParsing.h" + +#ifndef MAX_PATH +#define MAX_PATH 255 +#endif +// +// just in case we get in an endless loop. +// +#define MAX_NEST_DEPTH 20 +// +// number of wchars +// +#define MAX_STRING_IDENTIFIER_NAME 100 + +#define T_CHAR_SPACE ' ' +#define T_CHAR_NULL 0 +#define T_CHAR_CR '\r' +#define T_CHAR_TAB '\t' +#define T_CHAR_LF '\n' +#define T_CHAR_SLASH '/' +#define T_CHAR_BACKSLASH '\\' +#define T_CHAR_DOUBLE_QUOTE '"' +#define T_CHAR_LC_X 'x' +#define T_CHAR_0 '0' +#define T_CHAR_STAR '*' + +// +// We keep a linked list of these for the source files we process +// +typedef struct _SOURCE_FILE { + FILE *Fptr; + CHAR8 *FileBuffer; + CHAR8 *FileBufferPtr; + UINTN FileSize; + CHAR8 FileName[MAX_PATH]; + UINTN LineNum; + BOOLEAN EndOfFile; + BOOLEAN SkipToHash; + struct _SOURCE_FILE *Previous; + struct _SOURCE_FILE *Next; + CHAR8 ControlCharacter; +} SOURCE_FILE; + +typedef struct { + CHAR8 *FileBufferPtr; +} FILE_POSITION; + +// +// Keep all our module globals in this structure +// +STATIC struct { + SOURCE_FILE SourceFile; + BOOLEAN VerboseFile; + BOOLEAN VerboseToken; +} mGlobals; + +STATIC +UINTN +t_strcmp ( + CHAR8 *Buffer, + CHAR8 *Str + ); + +STATIC +UINTN +t_strncmp ( + CHAR8 *Str1, + CHAR8 *Str2, + INTN Len + ); + +STATIC +UINTN +t_strlen ( + CHAR8 *Str + ); + +STATIC +VOID +RewindFile ( + SOURCE_FILE *SourceFile + ); + +STATIC +BOOLEAN +IsWhiteSpace ( + SOURCE_FILE *SourceFile + ); + +STATIC +UINTN +SkipWhiteSpace ( + SOURCE_FILE *SourceFile + ); + +STATIC +BOOLEAN +EndOfFile ( + SOURCE_FILE *SourceFile + ); + +STATIC +VOID +PreprocessFile ( + SOURCE_FILE *SourceFile + ); + +STATIC +CHAR8 * +t_strcpy ( + CHAR8 *Dest, + CHAR8 *Src + ); + +STATIC +STATUS +ProcessIncludeFile ( + SOURCE_FILE *SourceFile, + SOURCE_FILE *ParentSourceFile + ); + +STATIC +STATUS +ProcessFile ( + SOURCE_FILE *SourceFile + ); + +STATIC +STATUS +GetFilePosition ( + FILE_POSITION *Fpos + ); + +STATIC +STATUS +SetFilePosition ( + FILE_POSITION *Fpos + ); + +/** + @retval STATUS_SUCCESS always +**/ +STATUS +SFPInit ( + VOID + ) +{ + memset ((VOID *) &mGlobals, 0, sizeof (mGlobals)); + return STATUS_SUCCESS; +} + +/** + Return the line number of the file we're parsing. Used + for error reporting purposes. + + @return The line number, or 0 if no file is being processed +**/ +UINTN +SFPGetLineNumber ( + VOID + ) +{ + return mGlobals.SourceFile.LineNum; +} + +/** + Return the name of the file we're parsing. Used + for error reporting purposes. + + @return A pointer to the file name. Null if no file is being + processed. +**/ +CHAR8 * +SFPGetFileName ( + VOID + ) +{ + if (mGlobals.SourceFile.FileName[0]) { + return mGlobals.SourceFile.FileName; + } + + return NULL; +} + +/** + Open a file for parsing. + + @param FileName name of the file to parse +**/ +STATUS +SFPOpenFile ( + CHAR8 *FileName + ) +{ + STATUS Status; + t_strcpy (mGlobals.SourceFile.FileName, FileName); + Status = ProcessIncludeFile (&mGlobals.SourceFile, NULL); + return Status; +} + +/** + Check to see if the specified token is found at + the current position in the input file. + + @note: + We do a simple string comparison on this function. It is + the responsibility of the caller to ensure that the token + is not a subset of some other token. + + The file pointer is advanced past the token in the input file. + + @param Str the token to look for + + @retval TRUE the token is next + @retval FALSE the token is not next +**/ +BOOLEAN +SFPIsToken ( + CHAR8 *Str + ) +{ + UINTN Len; + SkipWhiteSpace (&mGlobals.SourceFile); + if (EndOfFile (&mGlobals.SourceFile)) { + return FALSE; + } + + if ((Len = t_strcmp (mGlobals.SourceFile.FileBufferPtr, Str)) > 0) { + mGlobals.SourceFile.FileBufferPtr += Len; + if (mGlobals.VerboseToken) { + printf ("Token: '%s'\n", Str); + } + + return TRUE; + } + + return FALSE; +} + +/** + Check to see if the specified keyword is found at + the current position in the input file. + + @note: + A keyword is defined as a "special" string that has a non-alphanumeric + character following it. + + @param Str keyword to look for + + @retval TRUE the keyword is next + @retval FALSE the keyword is not next +**/ +BOOLEAN +SFPIsKeyword ( + CHAR8 *Str + ) +{ + UINTN Len; + SkipWhiteSpace (&mGlobals.SourceFile); + if (EndOfFile (&mGlobals.SourceFile)) { + return FALSE; + } + + if ((Len = t_strcmp (mGlobals.SourceFile.FileBufferPtr, Str)) > 0) { + if (isalnum ((int)mGlobals.SourceFile.FileBufferPtr[Len])) { + return FALSE; + } + + mGlobals.SourceFile.FileBufferPtr += Len; + if (mGlobals.VerboseToken) { + printf ("Token: '%s'\n", Str); + } + + return TRUE; + } + + return FALSE; +} + +/** + Get the next token from the input stream. + + @note: + Preceding white space is ignored. + The parser's buffer pointer is advanced past the end of the + token. + + @param Str pointer to a copy of the next token + @param Len size of buffer pointed to by Str + + @retval TRUE next token successfully returned + @retval FALSE otherwise +**/ +BOOLEAN +SFPGetNextToken ( + CHAR8 *Str, + UINTN Len + ) +{ + UINTN Index; + CHAR8 TempChar; + + SkipWhiteSpace (&mGlobals.SourceFile); + if (EndOfFile (&mGlobals.SourceFile)) { + return FALSE; + } + // + // Have to have enough string for at least one char and a null-terminator + // + if (Len < 2) { + return FALSE; + } + // + // Look at the first character. If it's an identifier, then treat it + // as such + // + TempChar = mGlobals.SourceFile.FileBufferPtr[0]; + if (((TempChar >= 'a') && (TempChar <= 'z')) || ((TempChar >= 'A') && (TempChar <= 'Z')) || (TempChar == '_')) { + Str[0] = TempChar; + mGlobals.SourceFile.FileBufferPtr++; + Index = 1; + while (!EndOfFile (&mGlobals.SourceFile) && (Index < Len)) { + TempChar = mGlobals.SourceFile.FileBufferPtr[0]; + if (((TempChar >= 'a') && (TempChar <= 'z')) || + ((TempChar >= 'A') && (TempChar <= 'Z')) || + ((TempChar >= '0') && (TempChar <= '9')) || + (TempChar == '_') + ) { + Str[Index] = mGlobals.SourceFile.FileBufferPtr[0]; + mGlobals.SourceFile.FileBufferPtr++; + Index++; + } else { + // + // Invalid character for symbol name, so break out + // + break; + } + } + // + // Null terminate and return success + // + Str[Index] = 0; + return TRUE; + } else if ((TempChar == ')') || (TempChar == '(') || (TempChar == '*')) { + Str[0] = mGlobals.SourceFile.FileBufferPtr[0]; + mGlobals.SourceFile.FileBufferPtr++; + Str[1] = 0; + return TRUE; + } else { + // + // Everything else is white-space (or EOF) separated + // + Index = 0; + while (!EndOfFile (&mGlobals.SourceFile) && (Index < Len)) { + if (IsWhiteSpace (&mGlobals.SourceFile)) { + if (Index > 0) { + Str[Index] = 0; + return TRUE; + } + + return FALSE; + } else { + Str[Index] = mGlobals.SourceFile.FileBufferPtr[0]; + mGlobals.SourceFile.FileBufferPtr++; + Index++; + } + } + // + // See if we just ran out of file contents, but did find a token + // + if ((Index > 0) && EndOfFile (&mGlobals.SourceFile)) { + Str[Index] = 0; + return TRUE; + } + } + + return FALSE; +} + +/** + Parse a GUID from the input stream. Stop when you discover white space. + + @param Str pointer to a copy of the next token + @param Len size of buffer pointed to by Str + + @retval TRUE GUID string returned successfully + @retval FALSE otherwise +**/ +BOOLEAN +SFPGetGuidToken ( + CHAR8 *Str, + UINT32 Len + ) +{ + UINT32 Index; + SkipWhiteSpace (&mGlobals.SourceFile); + if (EndOfFile (&mGlobals.SourceFile)) { + return FALSE; + } + + Index = 0; + while (!EndOfFile (&mGlobals.SourceFile) && (Index < Len)) { + if (IsWhiteSpace (&mGlobals.SourceFile)) { + if (Index > 0) { + Str[Index] = 0; + return TRUE; + } + + return FALSE; + } else { + Str[Index] = mGlobals.SourceFile.FileBufferPtr[0]; + mGlobals.SourceFile.FileBufferPtr++; + Index++; + } + } + + return FALSE; +} + +BOOLEAN +SFPSkipToToken ( + CHAR8 *Str + ) +{ + UINTN Len; + CHAR8 *SavePos; + Len = t_strlen (Str); + SavePos = mGlobals.SourceFile.FileBufferPtr; + SkipWhiteSpace (&mGlobals.SourceFile); + while (!EndOfFile (&mGlobals.SourceFile)) { + if (t_strncmp (Str, mGlobals.SourceFile.FileBufferPtr, Len) == 0) { + mGlobals.SourceFile.FileBufferPtr += Len; + return TRUE; + } + + mGlobals.SourceFile.FileBufferPtr++; + SkipWhiteSpace (&mGlobals.SourceFile); + } + + mGlobals.SourceFile.FileBufferPtr = SavePos; + return FALSE; +} + +/** + Check the token at the current file position for a numeric value. + May be either decimal or hex. + + @param Value pointer where to store the value + + @retval FALSE current token is not a number + @retval TRUE current token is a number +**/ +BOOLEAN +SFPGetNumber ( + UINTN *Value + ) +{ + int Val; + + SkipWhiteSpace (&mGlobals.SourceFile); + if (EndOfFile (&mGlobals.SourceFile)) { + return FALSE; + } + + if (isdigit ((int)mGlobals.SourceFile.FileBufferPtr[0])) { + // + // Check for hex value + // + if ((mGlobals.SourceFile.FileBufferPtr[0] == T_CHAR_0) && (mGlobals.SourceFile.FileBufferPtr[1] == T_CHAR_LC_X)) { + if (!isxdigit ((int)mGlobals.SourceFile.FileBufferPtr[2])) { + return FALSE; + } + + mGlobals.SourceFile.FileBufferPtr += 2; + sscanf (mGlobals.SourceFile.FileBufferPtr, "%x", &Val); + *Value = (UINT32) Val; + while (isxdigit ((int)mGlobals.SourceFile.FileBufferPtr[0])) { + mGlobals.SourceFile.FileBufferPtr++; + } + + return TRUE; + } else { + *Value = atoi (mGlobals.SourceFile.FileBufferPtr); + while (isdigit ((int)mGlobals.SourceFile.FileBufferPtr[0])) { + mGlobals.SourceFile.FileBufferPtr++; + } + + return TRUE; + } + } else { + return FALSE; + } +} + +/** + Close the file being parsed. + + @retval STATUS_SUCCESS the file was closed + @retval STATUS_ERROR no file is currently open +**/ +STATUS +SFPCloseFile ( + VOID + ) +{ + if (mGlobals.SourceFile.FileBuffer != NULL) { + free (mGlobals.SourceFile.FileBuffer); + memset (&mGlobals.SourceFile, 0, sizeof (mGlobals.SourceFile)); + return STATUS_SUCCESS; + } + + return STATUS_ERROR; +} + +/** + Given a source file, open the file and parse it + + @param SourceFile name of file to parse + @param ParentSourceFile for error reporting purposes, the file that #included SourceFile. + + @return Standard status. +**/ +STATIC +STATUS +ProcessIncludeFile ( + SOURCE_FILE *SourceFile, + SOURCE_FILE *ParentSourceFile + ) +{ + STATIC UINTN NestDepth = 0; + CHAR8 FoundFileName[MAX_PATH]; + STATUS Status; + + Status = STATUS_SUCCESS; + NestDepth++; + // + // Print the file being processed. Indent so you can tell the include nesting + // depth. + // + if (mGlobals.VerboseFile) { + fprintf (stdout, "%*cProcessing file '%s'\n", (int)NestDepth * 2, ' ', SourceFile->FileName); + fprintf (stdout, "Parent source file = '%s'\n", ParentSourceFile->FileName); + } + + // + // Make sure we didn't exceed our maximum nesting depth + // + if (NestDepth > MAX_NEST_DEPTH) { + Error (NULL, 0, 3001, "Not Supported", "%s exceeds max nesting depth (%u)", SourceFile->FileName, (unsigned) NestDepth); + Status = STATUS_ERROR; + goto Finish; + } + // + // Try to open the file locally, and if that fails try along our include paths. + // + strcpy (FoundFileName, SourceFile->FileName); + if ((SourceFile->Fptr = fopen (LongFilePath (FoundFileName), "rb")) == NULL) { + return STATUS_ERROR; + } + // + // Process the file found + // + ProcessFile (SourceFile); +Finish: + // + // Close open files and return status + // + if (SourceFile->Fptr != NULL) { + fclose (SourceFile->Fptr); + SourceFile->Fptr = NULL; + } + + return Status; +} + +/** + Given a source file that's been opened, read the contents into an internal + buffer and pre-process it to remove comments. + + @param SourceFile structure containing info on the file to process + + @return Standard status. +**/ +STATIC +STATUS +ProcessFile ( + SOURCE_FILE *SourceFile + ) +{ + // + // Get the file size, and then read the entire thing into memory. + // Allocate extra space for a terminator character. + // + fseek (SourceFile->Fptr, 0, SEEK_END); + SourceFile->FileSize = ftell (SourceFile->Fptr); + if (mGlobals.VerboseFile) { + printf ("FileSize = %u (0x%X)\n", (unsigned) SourceFile->FileSize, (unsigned) SourceFile->FileSize); + } + + fseek (SourceFile->Fptr, 0, SEEK_SET); + SourceFile->FileBuffer = (CHAR8 *) malloc (SourceFile->FileSize + sizeof (CHAR8 )); + if (SourceFile->FileBuffer == NULL) { + Error (NULL, 0, 4001, "Resource: memory cannot be allocated", NULL); + return STATUS_ERROR; + } + + fread ((VOID *) SourceFile->FileBuffer, SourceFile->FileSize, 1, SourceFile->Fptr); + SourceFile->FileBuffer[(SourceFile->FileSize / sizeof (CHAR8 ))] = T_CHAR_NULL; + // + // Pre-process the file to replace comments with spaces + // + PreprocessFile (SourceFile); + SourceFile->LineNum = 1; + return STATUS_SUCCESS; +} + +/** + Preprocess a file to replace all carriage returns with NULLs so + we can print lines (as part of error messages) from the file to the screen. + + @param SourceFile structure that we use to keep track of an input file. +**/ +STATIC +VOID +PreprocessFile ( + SOURCE_FILE *SourceFile + ) +{ + BOOLEAN InComment; + BOOLEAN SlashSlashComment; + int LineNum; + + RewindFile (SourceFile); + InComment = FALSE; + SlashSlashComment = FALSE; + while (!EndOfFile (SourceFile)) { + // + // If a line-feed, then no longer in a comment if we're in a // comment + // + if (SourceFile->FileBufferPtr[0] == T_CHAR_LF) { + SourceFile->FileBufferPtr++; + SourceFile->LineNum++; + if (InComment && SlashSlashComment) { + InComment = FALSE; + SlashSlashComment = FALSE; + } + } else if (SourceFile->FileBufferPtr[0] == T_CHAR_CR) { + // + // Replace all carriage returns with a NULL so we can print stuff + // + SourceFile->FileBufferPtr[0] = 0; + SourceFile->FileBufferPtr++; + // + // Check for */ comment end + // + } else if (InComment && + !SlashSlashComment && + (SourceFile->FileBufferPtr[0] == T_CHAR_STAR) && + (SourceFile->FileBufferPtr[1] == T_CHAR_SLASH) + ) { + SourceFile->FileBufferPtr[0] = T_CHAR_SPACE; + SourceFile->FileBufferPtr++; + SourceFile->FileBufferPtr[0] = T_CHAR_SPACE; + SourceFile->FileBufferPtr++; + InComment = FALSE; + } else if (InComment) { + SourceFile->FileBufferPtr[0] = T_CHAR_SPACE; + SourceFile->FileBufferPtr++; + // + // Check for // comments + // + } else if ((SourceFile->FileBufferPtr[0] == T_CHAR_SLASH) && (SourceFile->FileBufferPtr[1] == T_CHAR_SLASH)) { + InComment = TRUE; + SlashSlashComment = TRUE; + // + // Check for /* comment start + // + } else if ((SourceFile->FileBufferPtr[0] == T_CHAR_SLASH) && (SourceFile->FileBufferPtr[1] == T_CHAR_STAR)) { + SourceFile->FileBufferPtr[0] = T_CHAR_SPACE; + SourceFile->FileBufferPtr++; + SourceFile->FileBufferPtr[0] = T_CHAR_SPACE; + SourceFile->FileBufferPtr++; + SlashSlashComment = FALSE; + InComment = TRUE; + } else { + SourceFile->FileBufferPtr++; + } + } + // + // Could check for end-of-file and still in a comment, but + // should not be necessary. So just restore the file pointers. + // + RewindFile (SourceFile); + // + // Dump the reformatted file if verbose mode + // + if (mGlobals.VerboseFile) { + LineNum = 1; + printf ("%04d: ", LineNum); + while (!EndOfFile (SourceFile)) { + if (SourceFile->FileBufferPtr[0] == T_CHAR_LF) { + printf ("'\n%04d: '", ++LineNum); + } else { + printf ("%c", SourceFile->FileBufferPtr[0]); + } + + SourceFile->FileBufferPtr++; + } + + printf ("'\n"); + printf ("FileSize = %u (0x%X)\n", (unsigned)SourceFile->FileSize, (unsigned)SourceFile->FileSize); + RewindFile (SourceFile); + } +} + +/** + Retrieve a quoted-string from the input file. + + @param Str pointer to a copy of the quoted string parsed + @param Length size of buffer pointed to by Str + + @retval TRUE next token in input stream was a quoted string, and + the string value was returned in Str + @retval FALSE otherwise +**/ +BOOLEAN +SFPGetQuotedString ( + CHAR8 *Str, + INTN Length + ) +{ + SkipWhiteSpace (&mGlobals.SourceFile); + if (EndOfFile (&mGlobals.SourceFile)) { + return FALSE; + } + + if (mGlobals.SourceFile.FileBufferPtr[0] == T_CHAR_DOUBLE_QUOTE) { + mGlobals.SourceFile.FileBufferPtr++; + while (Length > 0) { + if (EndOfFile (&mGlobals.SourceFile)) { + return FALSE; + } + // + // Check for closing quote + // + if (mGlobals.SourceFile.FileBufferPtr[0] == T_CHAR_DOUBLE_QUOTE) { + mGlobals.SourceFile.FileBufferPtr++; + *Str = 0; + return TRUE; + } + + *Str = mGlobals.SourceFile.FileBufferPtr[0]; + Str++; + Length--; + mGlobals.SourceFile.FileBufferPtr++; + } + } + // + // First character was not a quote, or the input string length was + // insufficient to contain the quoted string, so return failure code. + // + return FALSE; +} + +/** + Return TRUE of FALSE to indicate whether or not we've reached the end of the + file we're parsing. + + @retval TRUE EOF reached + @retval FALSE otherwise +**/ +BOOLEAN +SFPIsEOF ( + VOID + ) +{ + SkipWhiteSpace (&mGlobals.SourceFile); + return EndOfFile (&mGlobals.SourceFile); +} + +#if 0 +STATIC +CHAR8 * +GetQuotedString ( + SOURCE_FILE *SourceFile, + BOOLEAN Optional + ) +{ + CHAR8 *String; + CHAR8 *Start; + CHAR8 *Ptr; + UINTN Len; + BOOLEAN PreviousBackslash; + + if (SourceFile->FileBufferPtr[0] != T_CHAR_DOUBLE_QUOTE) { + if (Optional == FALSE) { + Error (SourceFile->FileName, SourceFile->LineNum, 0, "expected quoted string", "%S", SourceFile->FileBufferPtr); + } + + return NULL; + } + + Len = 0; + SourceFile->FileBufferPtr++; + Start = Ptr = SourceFile->FileBufferPtr; + PreviousBackslash = FALSE; + while (!EndOfFile (SourceFile)) { + if ((SourceFile->FileBufferPtr[0] == T_CHAR_DOUBLE_QUOTE) && (PreviousBackslash == FALSE)) { + break; + } else if (SourceFile->FileBufferPtr[0] == T_CHAR_CR) { + Warning (SourceFile->FileName, SourceFile->LineNum, 0, "carriage return found in quoted string", "%S", Start); + PreviousBackslash = FALSE; + } else if (SourceFile->FileBufferPtr[0] == T_CHAR_BACKSLASH) { + PreviousBackslash = TRUE; + } else { + PreviousBackslash = FALSE; + } + + SourceFile->FileBufferPtr++; + Len++; + } + + if (SourceFile->FileBufferPtr[0] != T_CHAR_DOUBLE_QUOTE) { + Warning (SourceFile->FileName, SourceFile->LineNum, 0, "missing closing quote on string", "%S", Start); + } else { + SourceFile->FileBufferPtr++; + } + // + // Now allocate memory for the string and save it off + // + String = (CHAR8 *) malloc ((Len + 1) * sizeof (CHAR8 )); + if (String == NULL) { + Error (NULL, 0, 4001, "Resource: memory cannot be allocated", NULL); + return NULL; + } + // + // Copy the string from the file buffer to the local copy. + // We do no reformatting of it whatsoever at this point. + // + Ptr = String; + while (Len > 0) { + *Ptr = *Start; + Start++; + Ptr++; + Len--; + } + + *Ptr = 0; + return String; +} +#endif +STATIC +BOOLEAN +EndOfFile ( + SOURCE_FILE *SourceFile + ) +{ + // + // The file buffer pointer will typically get updated before the End-of-file flag in the + // source file structure, so check it first. + // + if (SourceFile->FileBufferPtr >= SourceFile->FileBuffer + SourceFile->FileSize / sizeof (CHAR8 )) { + SourceFile->EndOfFile = TRUE; + return TRUE; + } + + if (SourceFile->EndOfFile) { + return TRUE; + } + + return FALSE; +} + +#if 0 +STATIC +VOID +ProcessTokenInclude ( + SOURCE_FILE *SourceFile + ) +{ + CHAR8 IncludeFileName[MAX_PATH]; + CHAR8 *To; + UINTN Len; + BOOLEAN ReportedError; + SOURCE_FILE IncludedSourceFile; + + ReportedError = FALSE; + if (SkipWhiteSpace (SourceFile) == 0) { + Warning (SourceFile->FileName, SourceFile->LineNum, 0, "expected whitespace following #include keyword", NULL); + } + // + // Should be quoted file name + // + if (SourceFile->FileBufferPtr[0] != T_CHAR_DOUBLE_QUOTE) { + Error (SourceFile->FileName, SourceFile->LineNum, 0, "expected quoted include file name", NULL); + goto FailDone; + } + + SourceFile->FileBufferPtr++; + // + // Copy the filename as ascii to our local string + // + To = IncludeFileName; + Len = 0; + while (!EndOfFile (SourceFile)) { + if ((SourceFile->FileBufferPtr[0] == T_CHAR_CR) || (SourceFile->FileBufferPtr[0] == T_CHAR_LF)) { + Error (SourceFile->FileName, SourceFile->LineNum, 0, "end-of-line found in quoted include file name", NULL); + goto FailDone; + } + + if (SourceFile->FileBufferPtr[0] == T_CHAR_DOUBLE_QUOTE) { + SourceFile->FileBufferPtr++; + break; + } + // + // If too long, then report the error once and process until the closing quote + // + Len++; + if (!ReportedError && (Len >= sizeof (IncludeFileName))) { + Error (SourceFile->FileName, SourceFile->LineNum, 0, "length of include file name exceeds limit", NULL); + ReportedError = TRUE; + } + + if (!ReportedError) { + *To = (CHAR8 ) SourceFile->FileBufferPtr[0]; + To++; + } + + SourceFile->FileBufferPtr++; + } + + if (!ReportedError) { + *To = 0; + memset ((CHAR8 *) &IncludedSourceFile, 0, sizeof (SOURCE_FILE)); + strcpy (IncludedSourceFile.FileName, IncludeFileName); + ProcessIncludeFile (&IncludedSourceFile, SourceFile); + } + + return ; +FailDone: + // + // Error recovery -- skip to next # + // + SourceFile->SkipToHash = TRUE; +} +#endif +STATIC +BOOLEAN +IsWhiteSpace ( + SOURCE_FILE *SourceFile + ) +{ + switch (*SourceFile->FileBufferPtr) { + case T_CHAR_NULL: + case T_CHAR_CR: + case T_CHAR_SPACE: + case T_CHAR_TAB: + case T_CHAR_LF: + return TRUE; + + default: + return FALSE; + } +} + +UINTN +SkipWhiteSpace ( + SOURCE_FILE *SourceFile + ) +{ + UINTN Count; + + Count = 0; + while (!EndOfFile (SourceFile)) { + Count++; + switch (*SourceFile->FileBufferPtr) { + case T_CHAR_NULL: + case T_CHAR_CR: + case T_CHAR_SPACE: + case T_CHAR_TAB: + SourceFile->FileBufferPtr++; + break; + + case T_CHAR_LF: + SourceFile->FileBufferPtr++; + SourceFile->LineNum++; + break; + + default: + return Count - 1; + } + } + // + // Some tokens require trailing whitespace. If we're at the end of the + // file, then we count that as well. + // + if ((Count == 0) && (EndOfFile (SourceFile))) { + Count++; + } + + return Count; +} + +/** + Compare two strings for equality. The string pointed to by 'Buffer' may or may not be null-terminated, + so only compare up to the length of Str. + + @param Buffer pointer to first (possibly not null-terminated) string + @param Str pointer to null-terminated string to compare to Buffer + + @retval Number of bytes matched if exact match + @retval 0 if Buffer does not start with Str +**/ +STATIC +UINTN +t_strcmp ( + CHAR8 *Buffer, + CHAR8 *Str + ) +{ + UINTN Len; + + Len = 0; + while (*Str && (*Str == *Buffer)) { + Buffer++; + Str++; + Len++; + } + + if (*Str) { + return 0; + } + + return Len; +} + +STATIC +UINTN +t_strlen ( + CHAR8 *Str + ) +{ + UINTN Len; + Len = 0; + while (*Str) { + Len++; + Str++; + } + + return Len; +} + +STATIC +UINTN +t_strncmp ( + CHAR8 *Str1, + CHAR8 *Str2, + INTN Len + ) +{ + while (Len > 0) { + if (*Str1 != *Str2) { + return Len; + } + + Len--; + Str1++; + Str2++; + } + + return 0; +} + +STATIC +CHAR8 * +t_strcpy ( + CHAR8 *Dest, + CHAR8 *Src + ) +{ + CHAR8 *SaveDest; + SaveDest = Dest; + while (*Src) { + *Dest = *Src; + Dest++; + Src++; + } + + *Dest = 0; + return SaveDest; +} + +STATIC +VOID +RewindFile ( + SOURCE_FILE *SourceFile + ) +{ + SourceFile->LineNum = 1; + SourceFile->FileBufferPtr = SourceFile->FileBuffer; + SourceFile->EndOfFile = 0; +} + +STATIC +UINT32 +GetHexChars ( + CHAR8 *Buffer, + UINT32 BufferLen + ) +{ + UINT32 Len; + Len = 0; + while (!EndOfFile (&mGlobals.SourceFile) && (Len < BufferLen)) { + if (isxdigit ((int)mGlobals.SourceFile.FileBufferPtr[0])) { + Buffer[Len] = mGlobals.SourceFile.FileBufferPtr[0]; + Len++; + mGlobals.SourceFile.FileBufferPtr++; + } else { + break; + } + } + // + // Null terminate if we can + // + if ((Len > 0) && (Len < BufferLen)) { + Buffer[Len] = 0; + } + + return Len; +} + +/** + Parse a GUID from the input stream. Stop when you discover white space. + + GUID styles + Style[0] 12345678-1234-5678-AAAA-BBBBCCCCDDDD + + @param GuidStyle Style of the following GUID token + @param Value pointer to EFI_GUID struct for output + + @retval TRUE GUID string parsed successfully + @retval FALSE otherwise +**/ +BOOLEAN +SFPGetGuid ( + INTN GuidStyle, + EFI_GUID *Value + ) +{ + INT32 Value32; + UINT32 Index; + FILE_POSITION FPos; + CHAR8 TempString[20]; + CHAR8 TempString2[3]; + CHAR8 *From; + CHAR8 *To; + UINT32 Len; + BOOLEAN Status; + + Status = FALSE; + // + // Skip white space, then start parsing + // + SkipWhiteSpace (&mGlobals.SourceFile); + GetFilePosition (&FPos); + if (EndOfFile (&mGlobals.SourceFile)) { + return FALSE; + } + + if (GuidStyle == PARSE_GUID_STYLE_5_FIELDS) { + // + // Style[0] 12345678-1234-5678-AAAA-BBBBCCCCDDDD + // + Len = GetHexChars (TempString, sizeof (TempString)); + if ((Len == 0) || (Len > 8)) { + goto Done; + } + + sscanf (TempString, "%x", &Value32); + Value->Data1 = Value32; + // + // Next two UINT16 fields + // + if (mGlobals.SourceFile.FileBufferPtr[0] != '-') { + goto Done; + } + + mGlobals.SourceFile.FileBufferPtr++; + Len = GetHexChars (TempString, sizeof (TempString)); + if ((Len == 0) || (Len > 4)) { + goto Done; + } + + sscanf (TempString, "%x", &Value32); + Value->Data2 = (UINT16) Value32; + + if (mGlobals.SourceFile.FileBufferPtr[0] != '-') { + goto Done; + } + + mGlobals.SourceFile.FileBufferPtr++; + Len = GetHexChars (TempString, sizeof (TempString)); + if ((Len == 0) || (Len > 4)) { + goto Done; + } + + sscanf (TempString, "%x", &Value32); + Value->Data3 = (UINT16) Value32; + // + // Parse the "AAAA" as two bytes + // + if (mGlobals.SourceFile.FileBufferPtr[0] != '-') { + goto Done; + } + + mGlobals.SourceFile.FileBufferPtr++; + Len = GetHexChars (TempString, sizeof (TempString)); + if ((Len == 0) || (Len > 4)) { + goto Done; + } + + sscanf (TempString, "%x", &Value32); + Value->Data4[0] = (UINT8) (Value32 >> 8); + Value->Data4[1] = (UINT8) Value32; + if (mGlobals.SourceFile.FileBufferPtr[0] != '-') { + goto Done; + } + + mGlobals.SourceFile.FileBufferPtr++; + // + // Read the last 6 bytes of the GUID + // + // + Len = GetHexChars (TempString, sizeof (TempString)); + if ((Len == 0) || (Len > 12)) { + goto Done; + } + // + // Insert leading 0's to make life easier + // + if (Len != 12) { + From = TempString + Len - 1; + To = TempString + 11; + TempString[12] = 0; + while (From >= TempString) { + *To = *From; + To--; + From--; + } + + while (To >= TempString) { + *To = '0'; + To--; + } + } + // + // Now parse each byte + // + TempString2[2] = 0; + for (Index = 0; Index < 6; Index++) { + // + // Copy the two characters from the input string to something + // we can parse. + // + TempString2[0] = TempString[Index * 2]; + TempString2[1] = TempString[Index * 2 + 1]; + sscanf (TempString2, "%x", &Value32); + Value->Data4[Index + 2] = (UINT8) Value32; + } + + Status = TRUE; + } else { + // + // Unsupported GUID style + // + return FALSE; + } + +Done: + if (Status == FALSE) { + SetFilePosition (&FPos); + } + + return Status; +} + +STATIC +STATUS +GetFilePosition ( + FILE_POSITION *Fpos + ) +{ + Fpos->FileBufferPtr = mGlobals.SourceFile.FileBufferPtr; + return STATUS_SUCCESS; +} + +STATIC +STATUS +SetFilePosition ( + FILE_POSITION *Fpos + ) +{ + // + // Should check range of pointer + // + mGlobals.SourceFile.FileBufferPtr = Fpos->FileBufferPtr; + return STATUS_SUCCESS; +} diff --git a/BaseTools/Source/C/Common/SimpleFileParsing.h b/BaseTools/Source/C/Common/SimpleFileParsing.h index 2fc52a6c01..e699f050cb 100644 --- a/BaseTools/Source/C/Common/SimpleFileParsing.h +++ b/BaseTools/Source/C/Common/SimpleFileParsing.h @@ -1,104 +1,104 @@ -/** @file
-Function prototypes and defines for the simple file parsing routines.
-
-Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _SIMPLE_FILE_PARSING_H_
-#define _SIMPLE_FILE_PARSING_H_
-
-#include <Common/UefiBaseTypes.h>
-
-STATUS
-SFPInit (
- VOID
- )
-;
-
-STATUS
-SFPOpenFile (
- CHAR8 *FileName
- )
-;
-
-BOOLEAN
-SFPIsKeyword (
- CHAR8 *Str
- )
-;
-
-BOOLEAN
-SFPIsToken (
- CHAR8 *Str
- )
-;
-
-BOOLEAN
-SFPGetNextToken (
- CHAR8 *Str,
- UINTN Len
- )
-;
-
-BOOLEAN
-SFPGetGuidToken (
- CHAR8 *Str,
- UINT32 Len
- )
-;
-
-#define PARSE_GUID_STYLE_5_FIELDS 0
-
-BOOLEAN
-SFPGetGuid (
- INTN GuidStyle,
- EFI_GUID *Value
- )
-;
-
-BOOLEAN
-SFPSkipToToken (
- CHAR8 *Str
- )
-;
-
-BOOLEAN
-SFPGetNumber (
- UINTN *Value
- )
-;
-
-BOOLEAN
-SFPGetQuotedString (
- CHAR8 *Str,
- INTN Length
- )
-;
-
-BOOLEAN
-SFPIsEOF (
- VOID
- )
-;
-
-STATUS
-SFPCloseFile (
- VOID
- )
-;
-
-UINTN
-SFPGetLineNumber (
- VOID
- )
-;
-
-CHAR8 *
-SFPGetFileName (
- VOID
- )
-;
-
-#endif // #ifndef _SIMPLE_FILE_PARSING_H_
+/** @file +Function prototypes and defines for the simple file parsing routines. + +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _SIMPLE_FILE_PARSING_H_ +#define _SIMPLE_FILE_PARSING_H_ + +#include <Common/UefiBaseTypes.h> + +STATUS +SFPInit ( + VOID + ) +; + +STATUS +SFPOpenFile ( + CHAR8 *FileName + ) +; + +BOOLEAN +SFPIsKeyword ( + CHAR8 *Str + ) +; + +BOOLEAN +SFPIsToken ( + CHAR8 *Str + ) +; + +BOOLEAN +SFPGetNextToken ( + CHAR8 *Str, + UINTN Len + ) +; + +BOOLEAN +SFPGetGuidToken ( + CHAR8 *Str, + UINT32 Len + ) +; + +#define PARSE_GUID_STYLE_5_FIELDS 0 + +BOOLEAN +SFPGetGuid ( + INTN GuidStyle, + EFI_GUID *Value + ) +; + +BOOLEAN +SFPSkipToToken ( + CHAR8 *Str + ) +; + +BOOLEAN +SFPGetNumber ( + UINTN *Value + ) +; + +BOOLEAN +SFPGetQuotedString ( + CHAR8 *Str, + INTN Length + ) +; + +BOOLEAN +SFPIsEOF ( + VOID + ) +; + +STATUS +SFPCloseFile ( + VOID + ) +; + +UINTN +SFPGetLineNumber ( + VOID + ) +; + +CHAR8 * +SFPGetFileName ( + VOID + ) +; + +#endif // #ifndef _SIMPLE_FILE_PARSING_H_ diff --git a/BaseTools/Source/C/Common/StringFuncs.c b/BaseTools/Source/C/Common/StringFuncs.c index 53e44365e9..90c5354119 100644 --- a/BaseTools/Source/C/Common/StringFuncs.c +++ b/BaseTools/Source/C/Common/StringFuncs.c @@ -1,327 +1,327 @@ -/** @file
-Function prototypes and defines for string routines.
-
-Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include <string.h>
-#include <ctype.h>
-#include "StringFuncs.h"
-
-//
-// Functions implementations
-//
-
-/**
- Allocates a new string and copies 'String' to clone it
-
- @param String The string to clone
-
- @return CHAR8* - NULL if there are not enough resources
-**/
-CHAR8*
-CloneString (
- IN CHAR8 *String
- )
-{
- CHAR8* NewString;
-
- NewString = malloc (strlen (String) + 1);
- if (NewString != NULL) {
- strcpy (NewString, String);
- }
-
- return NewString;
-}
-
-/**
- Remove all comments, leading and trailing whitespace from the string.
-
- @param String The string to 'strip'
-
- @return EFI_STATUS
-**/
-EFI_STATUS
-StripInfDscStringInPlace (
- IN CHAR8 *String
- )
-{
- CHAR8 *Pos;
-
- if (String == NULL) {
- return EFI_INVALID_PARAMETER;
- }
-
- //
- // Remove leading whitespace
- //
- for (Pos = String; isspace ((int)*Pos); Pos++) {
- }
- if (Pos != String) {
- memmove (String, Pos, strlen (Pos) + 1);
- }
-
- //
- // Comment BUGBUGs!
- //
- // What about strings? Comment characters are okay in strings.
- // What about multiline comments?
- //
-
- Pos = (CHAR8 *) strstr (String, "//");
- if (Pos != NULL) {
- *Pos = '\0';
- }
-
- Pos = (CHAR8 *) strchr (String, '#');
- if (Pos != NULL) {
- *Pos = '\0';
- }
-
- //
- // Remove trailing whitespace
- //
- for (Pos = String + strlen (String);
- ((Pos - 1) >= String) && (isspace ((int)*(Pos - 1)));
- Pos--
- ) {
- }
- *Pos = '\0';
-
- return EFI_SUCCESS;
-}
-
-/**
- Creates and returns a 'split' STRING_LIST by splitting the string
- on whitespace boundaries.
-
- @param String The string to 'split'
-
- @return EFI_STATUS
-**/
-STRING_LIST*
-SplitStringByWhitespace (
- IN CHAR8 *String
- )
-{
- CHAR8 *Pos;
- CHAR8 *EndOfSubString;
- CHAR8 *EndOfString;
- STRING_LIST *Output;
- UINTN Item;
-
- String = CloneString (String);
- if (String == NULL) {
- return NULL;
- }
- EndOfString = String + strlen (String);
-
- Output = NewStringList ();
-
- for (Pos = String, Item = 0; Pos < EndOfString; Item++) {
- while (isspace ((int)*Pos)) {
- Pos++;
- }
-
- for (EndOfSubString=Pos;
- (*EndOfSubString != '\0') && !isspace ((int)*EndOfSubString);
- EndOfSubString++
- ) {
- }
-
- if (EndOfSubString == Pos) {
- break;
- }
-
- *EndOfSubString = '\0';
-
- AppendCopyOfStringToList (&Output, Pos);
-
- Pos = EndOfSubString + 1;
- }
-
- free (String);
- return Output;
-}
-
-/**
- Creates a new STRING_LIST with 0 strings.
-
- @return STRING_LIST* - Null if there is not enough resources to create the object.
-**/
-STRING_LIST*
-NewStringList (
- )
-{
- STRING_LIST *NewList;
- NewList = AllocateStringListStruct (0);
- if (NewList != NULL) {
- NewList->Count = 0;
- }
- return NewList;
-}
-
-/**
- Adds String to StringList. A new copy of String is made before it is
- added to StringList.
-
- @return EFI_STATUS
-**/
-EFI_STATUS
-AppendCopyOfStringToList (
- IN OUT STRING_LIST **StringList,
- IN CHAR8 *String
- )
-{
- STRING_LIST *OldList;
- STRING_LIST *NewList;
- CHAR8 *NewString;
-
- OldList = *StringList;
- NewList = AllocateStringListStruct (OldList->Count + 1);
- if (NewList == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- NewString = CloneString (String);
- if (NewString == NULL) {
- free (NewList);
- return EFI_OUT_OF_RESOURCES;
- }
-
- memcpy (
- NewList->Strings,
- OldList->Strings,
- sizeof (OldList->Strings[0]) * OldList->Count
- );
- NewList->Count = OldList->Count + 1;
- NewList->Strings[OldList->Count] = NewString;
-
- *StringList = NewList;
- free (OldList);
-
- return EFI_SUCCESS;
-}
-
-/**
- Removes the last string from StringList and frees the memory associated
- with it.
-
- @param StringList The string list to remove the string from
-
- @return EFI_STATUS
-**/
-EFI_STATUS
-RemoveLastStringFromList (
- IN STRING_LIST *StringList
- )
-{
- if (StringList->Count == 0) {
- return EFI_INVALID_PARAMETER;
- }
-
- free (StringList->Strings[StringList->Count - 1]);
- StringList->Count--;
- return EFI_SUCCESS;
-}
-
-/**
- Allocates a STRING_LIST structure that can store StringCount strings.
-
- @param StringCount The number of strings that need to be stored
-
- @return EFI_STATUS
-**/
-STRING_LIST*
-AllocateStringListStruct (
- IN UINTN StringCount
- )
-{
- return malloc (OFFSET_OF(STRING_LIST, Strings[StringCount + 1]));
-}
-
-/**
- Frees all memory associated with StringList.
-
- @param StringList The string list to free
-**/
-VOID
-FreeStringList (
- IN STRING_LIST *StringList
- )
-{
- while (StringList->Count > 0) {
- RemoveLastStringFromList (StringList);
- }
-
- free (StringList);
-}
-
-/**
- Generates a string that represents the STRING_LIST
-
- @param StringList The string list to convert to a string
-
- @return CHAR8* - The string list represented with a single string. The returned
- string must be freed by the caller.
-**/
-CHAR8*
-StringListToString (
- IN STRING_LIST *StringList
- )
-{
- UINTN Count;
- UINTN Length;
- CHAR8 *NewString;
-
- Length = 2;
- for (Count = 0; Count < StringList->Count; Count++) {
- if (Count > 0) {
- Length += 2;
- }
- Length += strlen (StringList->Strings[Count]) + 2;
- }
-
- NewString = malloc (Length + 1);
- if (NewString == NULL) {
- return NewString;
- }
- NewString[0] = '\0';
-
- strcat (NewString, "[");
- for (Count = 0; Count < StringList->Count; Count++) {
- if (Count > 0) {
- strcat (NewString, ", ");
- }
- strcat (NewString, "\"");
- strcat (NewString, StringList->Strings[Count]);
- strcat (NewString, "\"");
- }
- strcat (NewString, "]");
-
- return NewString;
-}
-
-/**
- Prints out the string list
-
- @param StringList The string list to print
-
- @return EFI_STATUS
-**/
-VOID
-PrintStringList (
- IN STRING_LIST *StringList
- )
-{
- CHAR8* String;
- String = StringListToString (StringList);
- if (String != NULL) {
- printf ("%s", String);
- free (String);
- }
-}
-
-
+/** @file +Function prototypes and defines for string routines. + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include <string.h> +#include <ctype.h> +#include "StringFuncs.h" + +// +// Functions implementations +// + +/** + Allocates a new string and copies 'String' to clone it + + @param String The string to clone + + @return CHAR8* - NULL if there are not enough resources +**/ +CHAR8* +CloneString ( + IN CHAR8 *String + ) +{ + CHAR8* NewString; + + NewString = malloc (strlen (String) + 1); + if (NewString != NULL) { + strcpy (NewString, String); + } + + return NewString; +} + +/** + Remove all comments, leading and trailing whitespace from the string. + + @param String The string to 'strip' + + @return EFI_STATUS +**/ +EFI_STATUS +StripInfDscStringInPlace ( + IN CHAR8 *String + ) +{ + CHAR8 *Pos; + + if (String == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Remove leading whitespace + // + for (Pos = String; isspace ((int)*Pos); Pos++) { + } + if (Pos != String) { + memmove (String, Pos, strlen (Pos) + 1); + } + + // + // Comment BUGBUGs! + // + // What about strings? Comment characters are okay in strings. + // What about multiline comments? + // + + Pos = (CHAR8 *) strstr (String, "//"); + if (Pos != NULL) { + *Pos = '\0'; + } + + Pos = (CHAR8 *) strchr (String, '#'); + if (Pos != NULL) { + *Pos = '\0'; + } + + // + // Remove trailing whitespace + // + for (Pos = String + strlen (String); + ((Pos - 1) >= String) && (isspace ((int)*(Pos - 1))); + Pos-- + ) { + } + *Pos = '\0'; + + return EFI_SUCCESS; +} + +/** + Creates and returns a 'split' STRING_LIST by splitting the string + on whitespace boundaries. + + @param String The string to 'split' + + @return EFI_STATUS +**/ +STRING_LIST* +SplitStringByWhitespace ( + IN CHAR8 *String + ) +{ + CHAR8 *Pos; + CHAR8 *EndOfSubString; + CHAR8 *EndOfString; + STRING_LIST *Output; + UINTN Item; + + String = CloneString (String); + if (String == NULL) { + return NULL; + } + EndOfString = String + strlen (String); + + Output = NewStringList (); + + for (Pos = String, Item = 0; Pos < EndOfString; Item++) { + while (isspace ((int)*Pos)) { + Pos++; + } + + for (EndOfSubString=Pos; + (*EndOfSubString != '\0') && !isspace ((int)*EndOfSubString); + EndOfSubString++ + ) { + } + + if (EndOfSubString == Pos) { + break; + } + + *EndOfSubString = '\0'; + + AppendCopyOfStringToList (&Output, Pos); + + Pos = EndOfSubString + 1; + } + + free (String); + return Output; +} + +/** + Creates a new STRING_LIST with 0 strings. + + @return STRING_LIST* - Null if there is not enough resources to create the object. +**/ +STRING_LIST* +NewStringList ( + ) +{ + STRING_LIST *NewList; + NewList = AllocateStringListStruct (0); + if (NewList != NULL) { + NewList->Count = 0; + } + return NewList; +} + +/** + Adds String to StringList. A new copy of String is made before it is + added to StringList. + + @return EFI_STATUS +**/ +EFI_STATUS +AppendCopyOfStringToList ( + IN OUT STRING_LIST **StringList, + IN CHAR8 *String + ) +{ + STRING_LIST *OldList; + STRING_LIST *NewList; + CHAR8 *NewString; + + OldList = *StringList; + NewList = AllocateStringListStruct (OldList->Count + 1); + if (NewList == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + NewString = CloneString (String); + if (NewString == NULL) { + free (NewList); + return EFI_OUT_OF_RESOURCES; + } + + memcpy ( + NewList->Strings, + OldList->Strings, + sizeof (OldList->Strings[0]) * OldList->Count + ); + NewList->Count = OldList->Count + 1; + NewList->Strings[OldList->Count] = NewString; + + *StringList = NewList; + free (OldList); + + return EFI_SUCCESS; +} + +/** + Removes the last string from StringList and frees the memory associated + with it. + + @param StringList The string list to remove the string from + + @return EFI_STATUS +**/ +EFI_STATUS +RemoveLastStringFromList ( + IN STRING_LIST *StringList + ) +{ + if (StringList->Count == 0) { + return EFI_INVALID_PARAMETER; + } + + free (StringList->Strings[StringList->Count - 1]); + StringList->Count--; + return EFI_SUCCESS; +} + +/** + Allocates a STRING_LIST structure that can store StringCount strings. + + @param StringCount The number of strings that need to be stored + + @return EFI_STATUS +**/ +STRING_LIST* +AllocateStringListStruct ( + IN UINTN StringCount + ) +{ + return malloc (OFFSET_OF(STRING_LIST, Strings[StringCount + 1])); +} + +/** + Frees all memory associated with StringList. + + @param StringList The string list to free +**/ +VOID +FreeStringList ( + IN STRING_LIST *StringList + ) +{ + while (StringList->Count > 0) { + RemoveLastStringFromList (StringList); + } + + free (StringList); +} + +/** + Generates a string that represents the STRING_LIST + + @param StringList The string list to convert to a string + + @return CHAR8* - The string list represented with a single string. The returned + string must be freed by the caller. +**/ +CHAR8* +StringListToString ( + IN STRING_LIST *StringList + ) +{ + UINTN Count; + UINTN Length; + CHAR8 *NewString; + + Length = 2; + for (Count = 0; Count < StringList->Count; Count++) { + if (Count > 0) { + Length += 2; + } + Length += strlen (StringList->Strings[Count]) + 2; + } + + NewString = malloc (Length + 1); + if (NewString == NULL) { + return NewString; + } + NewString[0] = '\0'; + + strcat (NewString, "["); + for (Count = 0; Count < StringList->Count; Count++) { + if (Count > 0) { + strcat (NewString, ", "); + } + strcat (NewString, "\""); + strcat (NewString, StringList->Strings[Count]); + strcat (NewString, "\""); + } + strcat (NewString, "]"); + + return NewString; +} + +/** + Prints out the string list + + @param StringList The string list to print + + @return EFI_STATUS +**/ +VOID +PrintStringList ( + IN STRING_LIST *StringList + ) +{ + CHAR8* String; + String = StringListToString (StringList); + if (String != NULL) { + printf ("%s", String); + free (String); + } +} + + diff --git a/BaseTools/Source/C/Common/StringFuncs.h b/BaseTools/Source/C/Common/StringFuncs.h index 23dce27244..e29d9be41a 100644 --- a/BaseTools/Source/C/Common/StringFuncs.h +++ b/BaseTools/Source/C/Common/StringFuncs.h @@ -1,167 +1,167 @@ -/** @file
-String routines implementation
-
-Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#ifndef _EFI_STRING_FUNCS_H
-#define _EFI_STRING_FUNCS_H
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <Common/UefiBaseTypes.h>
-
-//
-// Common data structures
-//
-typedef struct {
- UINTN Count;
- //
- // Actually this array can be 0 or more items (based on Count)
- //
- CHAR8* Strings[1];
-} STRING_LIST;
-
-
-//
-// Functions declarations
-//
-
-/**
- Allocates a new string and copies 'String' to clone it
-
- @param String The string to clone
-
- @return CHAR8* - NULL if there are not enough resources
-**/
-CHAR8*
-CloneString (
- IN CHAR8 *String
- )
-;
-
-/**
- Remove all comments, leading and trailing whitespace from the string.
-
- @param String The string to 'strip'
-
- @return EFI_STATUS
-**/
-EFI_STATUS
-StripInfDscStringInPlace (
- IN CHAR8 *String
- )
-;
-
-/**
- Creates and returns a 'split' STRING_LIST by splitting the string
- on whitespace boundaries.
-
- @param String The string to 'split'
-
- @return EFI_STATUS
-**/
-STRING_LIST*
-SplitStringByWhitespace (
- IN CHAR8 *String
- )
-;
-
-/**
- Creates a new STRING_LIST with 0 strings.
-
- @return STRING_LIST* - Null if there is not enough resources to create the object.
-**/
-STRING_LIST*
-NewStringList (
- )
-;
-
-
-/**
- Adds String to StringList. A new copy of String is made before it is
- added to StringList.
-
- @return EFI_STATUS
-**/
-EFI_STATUS
-AppendCopyOfStringToList (
- IN OUT STRING_LIST **StringList,
- IN CHAR8 *String
- )
-;
-
-/**
- Removes the last string from StringList and frees the memory associated
- with it.
-
- @param StringList The string list to remove the string from
-
- @return EFI_STATUS
-**/
-EFI_STATUS
-RemoveLastStringFromList (
- IN STRING_LIST *StringList
- )
-;
-
-
-/**
- Allocates a STRING_LIST structure that can store StringCount strings.
-
- @param StringCount The number of strings that need to be stored
-
- @return EFI_STATUS
-**/
-STRING_LIST*
-AllocateStringListStruct (
- IN UINTN StringCount
- )
-;
-
-
-/**
- Frees all memory associated with StringList.
-
- @param StringList The string list to free
-
- @return EFI_STATUS
-**/
-VOID
-FreeStringList (
- IN STRING_LIST *StringList
- )
-;
-
-
-/**
- Generates a string that represents the STRING_LIST
-
- @param StringList The string list to convert to a string
-
- @return CHAR8* The string list represented with a single string. The returned
- string must be freed by the caller.
-**/
-CHAR8*
-StringListToString (
- IN STRING_LIST *StringList
- )
-;
-
-
-/**
- Prints out the string list
-
- @param StringList The string list to print
-**/
-VOID
-PrintStringList (
- IN STRING_LIST *StringList
- )
-;
-
-
-
-#endif
+/** @file +String routines implementation + +Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#ifndef _EFI_STRING_FUNCS_H +#define _EFI_STRING_FUNCS_H + +#include <stdio.h> +#include <stdlib.h> +#include <Common/UefiBaseTypes.h> + +// +// Common data structures +// +typedef struct { + UINTN Count; + // + // Actually this array can be 0 or more items (based on Count) + // + CHAR8* Strings[1]; +} STRING_LIST; + + +// +// Functions declarations +// + +/** + Allocates a new string and copies 'String' to clone it + + @param String The string to clone + + @return CHAR8* - NULL if there are not enough resources +**/ +CHAR8* +CloneString ( + IN CHAR8 *String + ) +; + +/** + Remove all comments, leading and trailing whitespace from the string. + + @param String The string to 'strip' + + @return EFI_STATUS +**/ +EFI_STATUS +StripInfDscStringInPlace ( + IN CHAR8 *String + ) +; + +/** + Creates and returns a 'split' STRING_LIST by splitting the string + on whitespace boundaries. + + @param String The string to 'split' + + @return EFI_STATUS +**/ +STRING_LIST* +SplitStringByWhitespace ( + IN CHAR8 *String + ) +; + +/** + Creates a new STRING_LIST with 0 strings. + + @return STRING_LIST* - Null if there is not enough resources to create the object. +**/ +STRING_LIST* +NewStringList ( + ) +; + + +/** + Adds String to StringList. A new copy of String is made before it is + added to StringList. + + @return EFI_STATUS +**/ +EFI_STATUS +AppendCopyOfStringToList ( + IN OUT STRING_LIST **StringList, + IN CHAR8 *String + ) +; + +/** + Removes the last string from StringList and frees the memory associated + with it. + + @param StringList The string list to remove the string from + + @return EFI_STATUS +**/ +EFI_STATUS +RemoveLastStringFromList ( + IN STRING_LIST *StringList + ) +; + + +/** + Allocates a STRING_LIST structure that can store StringCount strings. + + @param StringCount The number of strings that need to be stored + + @return EFI_STATUS +**/ +STRING_LIST* +AllocateStringListStruct ( + IN UINTN StringCount + ) +; + + +/** + Frees all memory associated with StringList. + + @param StringList The string list to free + + @return EFI_STATUS +**/ +VOID +FreeStringList ( + IN STRING_LIST *StringList + ) +; + + +/** + Generates a string that represents the STRING_LIST + + @param StringList The string list to convert to a string + + @return CHAR8* The string list represented with a single string. The returned + string must be freed by the caller. +**/ +CHAR8* +StringListToString ( + IN STRING_LIST *StringList + ) +; + + +/** + Prints out the string list + + @param StringList The string list to print +**/ +VOID +PrintStringList ( + IN STRING_LIST *StringList + ) +; + + + +#endif diff --git a/BaseTools/Source/C/Common/TianoCompress.c b/BaseTools/Source/C/Common/TianoCompress.c index 6d23259720..d53ee59aab 100644 --- a/BaseTools/Source/C/Common/TianoCompress.c +++ b/BaseTools/Source/C/Common/TianoCompress.c @@ -1,1558 +1,1558 @@ -/** @file
-Compression routine. The compression algorithm is a mixture of LZ77 and Huffman
-coding. LZ77 transforms the source data into a sequence of Original Characters
-and Pointers to repeated strings. This sequence is further divided into Blocks
-and Huffman codings are applied to each Block.
-
-Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
-SPDX-License-Identifier: BSD-2-Clause-Patent
-
-**/
-
-#include "Compress.h"
-
-//
-// Macro Definitions
-//
-#undef UINT8_MAX
-typedef INT32 NODE;
-#define UINT8_MAX 0xff
-#define UINT8_BIT 8
-#define THRESHOLD 3
-#define INIT_CRC 0
-#define WNDBIT 19
-#define WNDSIZ (1U << WNDBIT)
-#define MAXMATCH 256
-#define BLKSIZ (1U << 14) // 16 * 1024U
-#define PERC_FLAG 0x80000000U
-#define CODE_BIT 16
-#define NIL 0
-#define MAX_HASH_VAL (3 * WNDSIZ + (WNDSIZ / 512 + 1) * UINT8_MAX)
-#define HASH(p, c) ((p) + ((c) << (WNDBIT - 9)) + WNDSIZ * 2)
-#define CRCPOLY 0xA001
-#define UPDATE_CRC(c) mCrc = mCrcTable[(mCrc ^ (c)) & 0xFF] ^ (mCrc >> UINT8_BIT)
-
-//
-// C: the Char&Len Set; P: the Position Set; T: the exTra Set
-//
-#define NC (UINT8_MAX + MAXMATCH + 2 - THRESHOLD)
-#define CBIT 9
-#define NP (WNDBIT + 1)
-#define PBIT 5
-#define NT (CODE_BIT + 3)
-#define TBIT 5
-#if NT > NP
-#define NPT NT
-#else
-#define NPT NP
-#endif
-//
-// Function Prototypes
-//
-
-STATIC
-VOID
-PutDword(
- IN UINT32 Data
- );
-
-STATIC
-EFI_STATUS
-AllocateMemory (
- VOID
- );
-
-STATIC
-VOID
-FreeMemory (
- VOID
- );
-
-STATIC
-VOID
-InitSlide (
- VOID
- );
-
-STATIC
-NODE
-Child (
- IN NODE NodeQ,
- IN UINT8 CharC
- );
-
-STATIC
-VOID
-MakeChild (
- IN NODE NodeQ,
- IN UINT8 CharC,
- IN NODE NodeR
- );
-
-STATIC
-VOID
-Split (
- IN NODE Old
- );
-
-STATIC
-VOID
-InsertNode (
- VOID
- );
-
-STATIC
-VOID
-DeleteNode (
- VOID
- );
-
-STATIC
-VOID
-GetNextMatch (
- VOID
- );
-
-STATIC
-EFI_STATUS
-Encode (
- VOID
- );
-
-STATIC
-VOID
-CountTFreq (
- VOID
- );
-
-STATIC
-VOID
-WritePTLen (
- IN INT32 Number,
- IN INT32 nbit,
- IN INT32 Special
- );
-
-STATIC
-VOID
-WriteCLen (
- VOID
- );
-
-STATIC
-VOID
-EncodeC (
- IN INT32 Value
- );
-
-STATIC
-VOID
-EncodeP (
- IN UINT32 Value
- );
-
-STATIC
-VOID
-SendBlock (
- VOID
- );
-
-STATIC
-VOID
-Output (
- IN UINT32 c,
- IN UINT32 p
- );
-
-STATIC
-VOID
-HufEncodeStart (
- VOID
- );
-
-STATIC
-VOID
-HufEncodeEnd (
- VOID
- );
-
-STATIC
-VOID
-MakeCrcTable (
- VOID
- );
-
-STATIC
-VOID
-PutBits (
- IN INT32 Number,
- IN UINT32 Value
- );
-
-STATIC
-INT32
-FreadCrc (
- OUT UINT8 *Pointer,
- IN INT32 Number
- );
-
-STATIC
-VOID
-InitPutBits (
- VOID
- );
-
-STATIC
-VOID
-CountLen (
- IN INT32 Index
- );
-
-STATIC
-VOID
-MakeLen (
- IN INT32 Root
- );
-
-STATIC
-VOID
-DownHeap (
- IN INT32 Index
- );
-
-STATIC
-VOID
-MakeCode (
- IN INT32 Number,
- IN UINT8 Len[ ],
- OUT UINT16 Code[]
- );
-
-STATIC
-INT32
-MakeTree (
- IN INT32 NParm,
- IN UINT16 FreqParm[],
- OUT UINT8 LenParm[ ],
- OUT UINT16 CodeParm[]
- );
-
-//
-// Global Variables
-//
-STATIC UINT8 *mSrc, *mDst, *mSrcUpperLimit, *mDstUpperLimit;
-
-STATIC UINT8 *mLevel, *mText, *mChildCount, *mBuf, mCLen[NC], mPTLen[NPT], *mLen;
-STATIC INT16 mHeap[NC + 1];
-STATIC INT32 mRemainder, mMatchLen, mBitCount, mHeapSize, mN;
-STATIC UINT32 mBufSiz = 0, mOutputPos, mOutputMask, mSubBitBuf, mCrc;
-STATIC UINT32 mCompSize, mOrigSize;
-
-STATIC UINT16 *mFreq, *mSortPtr, mLenCnt[17], mLeft[2 * NC - 1], mRight[2 * NC - 1], mCrcTable[UINT8_MAX + 1],
- mCFreq[2 * NC - 1], mCCode[NC], mPFreq[2 * NP - 1], mPTCode[NPT], mTFreq[2 * NT - 1];
-
-STATIC NODE mPos, mMatchPos, mAvail, *mPosition, *mParent, *mPrev, *mNext = NULL;
-
-//
-// functions
-//
-
-/**
- The internal implementation of [Efi/Tiano]Compress().
-
- @param SrcBuffer The buffer storing the source data
- @param SrcSize The size of source data
- @param DstBuffer The buffer to store the compressed data
- @param DstSize On input, the size of DstBuffer; On output,
- the size of the actual compressed data.
- @param Version The version of de/compression algorithm.
- Version 1 for UEFI 2.0 de/compression algorithm.
- Version 2 for Tiano de/compression algorithm.
-
- @retval EFI_BUFFER_TOO_SMALL The DstBuffer is too small. In this case,
- DstSize contains the size needed.
- @retval EFI_SUCCESS Compression is successful.
- @retval EFI_OUT_OF_RESOURCES No resource to complete function.
- @retval EFI_INVALID_PARAMETER Parameter supplied is wrong.
-**/
-EFI_STATUS
-TianoCompress (
- IN UINT8 *SrcBuffer,
- IN UINT32 SrcSize,
- IN UINT8 *DstBuffer,
- IN OUT UINT32 *DstSize
- )
-{
- EFI_STATUS Status;
-
- //
- // Initializations
- //
- mBufSiz = 0;
- mBuf = NULL;
- mText = NULL;
- mLevel = NULL;
- mChildCount = NULL;
- mPosition = NULL;
- mParent = NULL;
- mPrev = NULL;
- mNext = NULL;
-
- mSrc = SrcBuffer;
- mSrcUpperLimit = mSrc + SrcSize;
- mDst = DstBuffer;
- mDstUpperLimit = mDst +*DstSize;
-
- PutDword (0L);
- PutDword (0L);
-
- MakeCrcTable ();
-
- mOrigSize = mCompSize = 0;
- mCrc = INIT_CRC;
-
- //
- // Compress it
- //
- Status = Encode ();
- if (EFI_ERROR (Status)) {
- return EFI_OUT_OF_RESOURCES;
- }
- //
- // Null terminate the compressed data
- //
- if (mDst < mDstUpperLimit) {
- *mDst++ = 0;
- }
- //
- // Fill in compressed size and original size
- //
- mDst = DstBuffer;
- PutDword (mCompSize + 1);
- PutDword (mOrigSize);
-
- //
- // Return
- //
- if (mCompSize + 1 + 8 > *DstSize) {
- *DstSize = mCompSize + 1 + 8;
- return EFI_BUFFER_TOO_SMALL;
- } else {
- *DstSize = mCompSize + 1 + 8;
- return EFI_SUCCESS;
- }
-
-}
-
-/**
- Put a dword to output stream
-
- @param Data the dword to put
-**/
-STATIC
-VOID
-PutDword (
- IN UINT32 Data
- )
-{
- if (mDst < mDstUpperLimit) {
- *mDst++ = (UINT8) (((UINT8) (Data)) & 0xff);
- }
-
- if (mDst < mDstUpperLimit) {
- *mDst++ = (UINT8) (((UINT8) (Data >> 0x08)) & 0xff);
- }
-
- if (mDst < mDstUpperLimit) {
- *mDst++ = (UINT8) (((UINT8) (Data >> 0x10)) & 0xff);
- }
-
- if (mDst < mDstUpperLimit) {
- *mDst++ = (UINT8) (((UINT8) (Data >> 0x18)) & 0xff);
- }
-}
-
-/**
- Allocate memory spaces for data structures used in compression process
-
- @retval EFI_SUCCESS Memory is allocated successfully
- @retval EFI_OUT_OF_RESOURCES Allocation fails
-**/
-STATIC
-EFI_STATUS
-AllocateMemory (
- VOID
- )
-{
- UINT32 Index;
-
- mText = malloc (WNDSIZ * 2 + MAXMATCH);
- if (mText == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
- for (Index = 0; Index < WNDSIZ * 2 + MAXMATCH; Index++) {
- mText[Index] = 0;
- }
-
- mLevel = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof (*mLevel));
- mChildCount = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof (*mChildCount));
- mPosition = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof (*mPosition));
- mParent = malloc (WNDSIZ * 2 * sizeof (*mParent));
- mPrev = malloc (WNDSIZ * 2 * sizeof (*mPrev));
- mNext = malloc ((MAX_HASH_VAL + 1) * sizeof (*mNext));
- if (mLevel == NULL || mChildCount == NULL || mPosition == NULL ||
- mParent == NULL || mPrev == NULL || mNext == NULL) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- mBufSiz = BLKSIZ;
- mBuf = malloc (mBufSiz);
- while (mBuf == NULL) {
- mBufSiz = (mBufSiz / 10U) * 9U;
- if (mBufSiz < 4 * 1024U) {
- return EFI_OUT_OF_RESOURCES;
- }
-
- mBuf = malloc (mBufSiz);
- }
-
- mBuf[0] = 0;
-
- return EFI_SUCCESS;
-}
-
-/**
- Called when compression is completed to free memory previously allocated.
-**/
-VOID
-FreeMemory (
- VOID
- )
-{
- if (mText != NULL) {
- free (mText);
- }
-
- if (mLevel != NULL) {
- free (mLevel);
- }
-
- if (mChildCount != NULL) {
- free (mChildCount);
- }
-
- if (mPosition != NULL) {
- free (mPosition);
- }
-
- if (mParent != NULL) {
- free (mParent);
- }
-
- if (mPrev != NULL) {
- free (mPrev);
- }
-
- if (mNext != NULL) {
- free (mNext);
- }
-
- if (mBuf != NULL) {
- free (mBuf);
- }
-
- return ;
-}
-
-/**
- Initialize String Info Log data structures
-**/
-STATIC
-VOID
-InitSlide (
- VOID
- )
-{
- NODE Index;
-
- for (Index = WNDSIZ; Index <= WNDSIZ + UINT8_MAX; Index++) {
- mLevel[Index] = 1;
- mPosition[Index] = NIL; /* sentinel */
- }
-
- for (Index = WNDSIZ; Index < WNDSIZ * 2; Index++) {
- mParent[Index] = NIL;
- }
-
- mAvail = 1;
- for (Index = 1; Index < WNDSIZ - 1; Index++) {
- mNext[Index] = (NODE) (Index + 1);
- }
-
- mNext[WNDSIZ - 1] = NIL;
- for (Index = WNDSIZ * 2; Index <= MAX_HASH_VAL; Index++) {
- mNext[Index] = NIL;
- }
-}
-
-/**
- Find child node given the parent node and the edge character
-
- @param NodeQ the parent node
- @param CharC the edge character
-
- @return The child node (NIL if not found)
-**/
-STATIC
-NODE
-Child (
- IN NODE NodeQ,
- IN UINT8 CharC
- )
-{
- NODE NodeR;
-
- NodeR = mNext[HASH (NodeQ, CharC)];
- //
- // sentinel
- //
- mParent[NIL] = NodeQ;
- while (mParent[NodeR] != NodeQ) {
- NodeR = mNext[NodeR];
- }
-
- return NodeR;
-}
-
-/**
- Create a new child for a given parent node.
-
- @param Parent the parent node
- @param CharC the edge character
- @param Child the child node
-**/
-STATIC
-VOID
-MakeChild (
- IN NODE Parent,
- IN UINT8 CharC,
- IN NODE Child
- )
-{
- NODE Node1;
- NODE Node2;
-
- Node1 = (NODE) HASH (Parent, CharC);
- Node2 = mNext[Node1];
- mNext[Node1] = Child;
- mNext[Child] = Node2;
- mPrev[Node2] = Child;
- mPrev[Child] = Node1;
- mParent[Child] = Parent;
- mChildCount[Parent]++;
-}
-
-/**
- Split a node.
-
- @param Old the node to split
-**/
-STATIC
-VOID
-Split (
- NODE Old
- )
-{
- NODE New;
- NODE TempNode;
-
- New = mAvail;
- mAvail = mNext[New];
- mChildCount[New] = 0;
- TempNode = mPrev[Old];
- mPrev[New] = TempNode;
- mNext[TempNode] = New;
- TempNode = mNext[Old];
- mNext[New] = TempNode;
- mPrev[TempNode] = New;
- mParent[New] = mParent[Old];
- mLevel[New] = (UINT8) mMatchLen;
- mPosition[New] = mPos;
- MakeChild (New, mText[mMatchPos + mMatchLen], Old);
- MakeChild (New, mText[mPos + mMatchLen], mPos);
-}
-
-/**
- Insert string info for current position into the String Info Log
-**/
-STATIC
-VOID
-InsertNode (
- VOID
- )
-{
- NODE NodeQ;
- NODE NodeR;
- NODE Index2;
- NODE NodeT;
- UINT8 CharC;
- UINT8 *t1;
- UINT8 *t2;
-
- if (mMatchLen >= 4) {
- //
- // We have just got a long match, the target tree
- // can be located by MatchPos + 1. Traverse the tree
- // from bottom up to get to a proper starting point.
- // The usage of PERC_FLAG ensures proper node deletion
- // in DeleteNode() later.
- //
- mMatchLen--;
- NodeR = (NODE) ((mMatchPos + 1) | WNDSIZ);
- NodeQ = mParent[NodeR];
- while (NodeQ == NIL) {
- NodeR = mNext[NodeR];
- NodeQ = mParent[NodeR];
- }
-
- while (mLevel[NodeQ] >= mMatchLen) {
- NodeR = NodeQ;
- NodeQ = mParent[NodeQ];
- }
-
- NodeT = NodeQ;
- while (mPosition[NodeT] < 0) {
- mPosition[NodeT] = mPos;
- NodeT = mParent[NodeT];
- }
-
- if (NodeT < WNDSIZ) {
- mPosition[NodeT] = (NODE) (mPos | (UINT32) PERC_FLAG);
- }
- } else {
- //
- // Locate the target tree
- //
- NodeQ = (NODE) (mText[mPos] + WNDSIZ);
- CharC = mText[mPos + 1];
- NodeR = Child (NodeQ, CharC);
- if (NodeR == NIL) {
- MakeChild (NodeQ, CharC, mPos);
- mMatchLen = 1;
- return ;
- }
-
- mMatchLen = 2;
- }
- //
- // Traverse down the tree to find a match.
- // Update Position value along the route.
- // Node split or creation is involved.
- //
- for (;;) {
- if (NodeR >= WNDSIZ) {
- Index2 = MAXMATCH;
- mMatchPos = NodeR;
- } else {
- Index2 = mLevel[NodeR];
- mMatchPos = (NODE) (mPosition[NodeR] & (UINT32)~PERC_FLAG);
- }
-
- if (mMatchPos >= mPos) {
- mMatchPos -= WNDSIZ;
- }
-
- t1 = &mText[mPos + mMatchLen];
- t2 = &mText[mMatchPos + mMatchLen];
- while (mMatchLen < Index2) {
- if (*t1 != *t2) {
- Split (NodeR);
- return ;
- }
-
- mMatchLen++;
- t1++;
- t2++;
- }
-
- if (mMatchLen >= MAXMATCH) {
- break;
- }
-
- mPosition[NodeR] = mPos;
- NodeQ = NodeR;
- NodeR = Child (NodeQ, *t1);
- if (NodeR == NIL) {
- MakeChild (NodeQ, *t1, mPos);
- return ;
- }
-
- mMatchLen++;
- }
-
- NodeT = mPrev[NodeR];
- mPrev[mPos] = NodeT;
- mNext[NodeT] = mPos;
- NodeT = mNext[NodeR];
- mNext[mPos] = NodeT;
- mPrev[NodeT] = mPos;
- mParent[mPos] = NodeQ;
- mParent[NodeR] = NIL;
-
- //
- // Special usage of 'next'
- //
- mNext[NodeR] = mPos;
-
-}
-
-/**
- Delete outdated string info. (The Usage of PERC_FLAG
- ensures a clean deletion)
-**/
-STATIC
-VOID
-DeleteNode (
- VOID
- )
-{
- NODE NodeQ;
- NODE NodeR;
- NODE NodeS;
- NODE NodeT;
- NODE NodeU;
-
- if (mParent[mPos] == NIL) {
- return ;
- }
-
- NodeR = mPrev[mPos];
- NodeS = mNext[mPos];
- mNext[NodeR] = NodeS;
- mPrev[NodeS] = NodeR;
- NodeR = mParent[mPos];
- mParent[mPos] = NIL;
- if (NodeR >= WNDSIZ) {
- return ;
- }
-
- mChildCount[NodeR]--;
- if (mChildCount[NodeR] > 1) {
- return ;
- }
-
- NodeT = (NODE) (mPosition[NodeR] & (UINT32)~PERC_FLAG);
- if (NodeT >= mPos) {
- NodeT -= WNDSIZ;
- }
-
- NodeS = NodeT;
- NodeQ = mParent[NodeR];
- NodeU = mPosition[NodeQ];
- while (NodeU & (UINT32) PERC_FLAG) {
- NodeU &= (UINT32)~PERC_FLAG;
- if (NodeU >= mPos) {
- NodeU -= WNDSIZ;
- }
-
- if (NodeU > NodeS) {
- NodeS = NodeU;
- }
-
- mPosition[NodeQ] = (NODE) (NodeS | WNDSIZ);
- NodeQ = mParent[NodeQ];
- NodeU = mPosition[NodeQ];
- }
-
- if (NodeQ < WNDSIZ) {
- if (NodeU >= mPos) {
- NodeU -= WNDSIZ;
- }
-
- if (NodeU > NodeS) {
- NodeS = NodeU;
- }
-
- mPosition[NodeQ] = (NODE) (NodeS | WNDSIZ | (UINT32) PERC_FLAG);
- }
-
- NodeS = Child (NodeR, mText[NodeT + mLevel[NodeR]]);
- NodeT = mPrev[NodeS];
- NodeU = mNext[NodeS];
- mNext[NodeT] = NodeU;
- mPrev[NodeU] = NodeT;
- NodeT = mPrev[NodeR];
- mNext[NodeT] = NodeS;
- mPrev[NodeS] = NodeT;
- NodeT = mNext[NodeR];
- mPrev[NodeT] = NodeS;
- mNext[NodeS] = NodeT;
- mParent[NodeS] = mParent[NodeR];
- mParent[NodeR] = NIL;
- mNext[NodeR] = mAvail;
- mAvail = NodeR;
-}
-
-/**
- Advance the current position (read in new data if needed).
- Delete outdated string info. Find a match string for current position.
-**/
-STATIC
-VOID
-GetNextMatch (
- VOID
- )
-{
- INT32 Number;
-
- mRemainder--;
- mPos++;
- if (mPos == WNDSIZ * 2) {
- memmove (&mText[0], &mText[WNDSIZ], WNDSIZ + MAXMATCH);
- Number = FreadCrc (&mText[WNDSIZ + MAXMATCH], WNDSIZ);
- mRemainder += Number;
- mPos = WNDSIZ;
- }
-
- DeleteNode ();
- InsertNode ();
-}
-
-/**
- The main controlling routine for compression process.
-
- @retval EFI_SUCCESS The compression is successful
- @retval EFI_OUT_0F_RESOURCES Not enough memory for compression process
-**/
-STATIC
-EFI_STATUS
-Encode (
- VOID
- )
-{
- EFI_STATUS Status;
- INT32 LastMatchLen;
- NODE LastMatchPos;
-
- Status = AllocateMemory ();
- if (EFI_ERROR (Status)) {
- FreeMemory ();
- return Status;
- }
-
- InitSlide ();
-
- HufEncodeStart ();
-
- mRemainder = FreadCrc (&mText[WNDSIZ], WNDSIZ + MAXMATCH);
-
- mMatchLen = 0;
- mPos = WNDSIZ;
- InsertNode ();
- if (mMatchLen > mRemainder) {
- mMatchLen = mRemainder;
- }
-
- while (mRemainder > 0) {
- LastMatchLen = mMatchLen;
- LastMatchPos = mMatchPos;
- GetNextMatch ();
- if (mMatchLen > mRemainder) {
- mMatchLen = mRemainder;
- }
-
- if (mMatchLen > LastMatchLen || LastMatchLen < THRESHOLD) {
- //
- // Not enough benefits are gained by outputting a pointer,
- // so just output the original character
- //
- Output (mText[mPos - 1], 0);
-
- } else {
-
- if (LastMatchLen == THRESHOLD) {
- if (((mPos - LastMatchPos - 2) & (WNDSIZ - 1)) > (1U << 11)) {
- Output (mText[mPos - 1], 0);
- continue;
- }
- }
- //
- // Outputting a pointer is beneficial enough, do it.
- //
- Output (
- LastMatchLen + (UINT8_MAX + 1 - THRESHOLD),
- (mPos - LastMatchPos - 2) & (WNDSIZ - 1)
- );
- LastMatchLen--;
- while (LastMatchLen > 0) {
- GetNextMatch ();
- LastMatchLen--;
- }
-
- if (mMatchLen > mRemainder) {
- mMatchLen = mRemainder;
- }
- }
- }
-
- HufEncodeEnd ();
- FreeMemory ();
- return EFI_SUCCESS;
-}
-
-/**
- Count the frequencies for the Extra Set
-**/
-STATIC
-VOID
-CountTFreq (
- VOID
- )
-{
- INT32 Index;
- INT32 Index3;
- INT32 Number;
- INT32 Count;
-
- for (Index = 0; Index < NT; Index++) {
- mTFreq[Index] = 0;
- }
-
- Number = NC;
- while (Number > 0 && mCLen[Number - 1] == 0) {
- Number--;
- }
-
- Index = 0;
- while (Index < Number) {
- Index3 = mCLen[Index++];
- if (Index3 == 0) {
- Count = 1;
- while (Index < Number && mCLen[Index] == 0) {
- Index++;
- Count++;
- }
-
- if (Count <= 2) {
- mTFreq[0] = (UINT16) (mTFreq[0] + Count);
- } else if (Count <= 18) {
- mTFreq[1]++;
- } else if (Count == 19) {
- mTFreq[0]++;
- mTFreq[1]++;
- } else {
- mTFreq[2]++;
- }
- } else {
- mTFreq[Index3 + 2]++;
- }
- }
-}
-
-/**
- Outputs the code length array for the Extra Set or the Position Set.
-
- @param Number the number of symbols
- @param nbit the number of bits needed to represent 'n'
- @param Special the special symbol that needs to be take care of
-**/
-STATIC
-VOID
-WritePTLen (
- IN INT32 Number,
- IN INT32 nbit,
- IN INT32 Special
- )
-{
- INT32 Index;
- INT32 Index3;
-
- while (Number > 0 && mPTLen[Number - 1] == 0) {
- Number--;
- }
-
- PutBits (nbit, Number);
- Index = 0;
- while (Index < Number) {
- Index3 = mPTLen[Index++];
- if (Index3 <= 6) {
- PutBits (3, Index3);
- } else {
- PutBits (Index3 - 3, (1U << (Index3 - 3)) - 2);
- }
-
- if (Index == Special) {
- while (Index < 6 && mPTLen[Index] == 0) {
- Index++;
- }
-
- PutBits (2, (Index - 3) & 3);
- }
- }
-}
-
-/**
- Outputs the code length array for Char&Length Set
-**/
-STATIC
-VOID
-WriteCLen (
- VOID
- )
-{
- INT32 Index;
- INT32 Index3;
- INT32 Number;
- INT32 Count;
-
- Number = NC;
- while (Number > 0 && mCLen[Number - 1] == 0) {
- Number--;
- }
-
- PutBits (CBIT, Number);
- Index = 0;
- while (Index < Number) {
- Index3 = mCLen[Index++];
- if (Index3 == 0) {
- Count = 1;
- while (Index < Number && mCLen[Index] == 0) {
- Index++;
- Count++;
- }
-
- if (Count <= 2) {
- for (Index3 = 0; Index3 < Count; Index3++) {
- PutBits (mPTLen[0], mPTCode[0]);
- }
- } else if (Count <= 18) {
- PutBits (mPTLen[1], mPTCode[1]);
- PutBits (4, Count - 3);
- } else if (Count == 19) {
- PutBits (mPTLen[0], mPTCode[0]);
- PutBits (mPTLen[1], mPTCode[1]);
- PutBits (4, 15);
- } else {
- PutBits (mPTLen[2], mPTCode[2]);
- PutBits (CBIT, Count - 20);
- }
- } else {
- PutBits (mPTLen[Index3 + 2], mPTCode[Index3 + 2]);
- }
- }
-}
-
-STATIC
-VOID
-EncodeC (
- IN INT32 Value
- )
-{
- PutBits (mCLen[Value], mCCode[Value]);
-}
-
-STATIC
-VOID
-EncodeP (
- IN UINT32 Value
- )
-{
- UINT32 Index;
- UINT32 NodeQ;
-
- Index = 0;
- NodeQ = Value;
- while (NodeQ) {
- NodeQ >>= 1;
- Index++;
- }
-
- PutBits (mPTLen[Index], mPTCode[Index]);
- if (Index > 1) {
- PutBits (Index - 1, Value & (0xFFFFFFFFU >> (32 - Index + 1)));
- }
-}
-
-/**
- Huffman code the block and output it.
-**/
-STATIC
-VOID
-SendBlock (
- VOID
- )
-{
- UINT32 Index;
- UINT32 Index2;
- UINT32 Index3;
- UINT32 Flags;
- UINT32 Root;
- UINT32 Pos;
- UINT32 Size;
- Flags = 0;
-
- Root = MakeTree (NC, mCFreq, mCLen, mCCode);
- Size = mCFreq[Root];
- PutBits (16, Size);
- if (Root >= NC) {
- CountTFreq ();
- Root = MakeTree (NT, mTFreq, mPTLen, mPTCode);
- if (Root >= NT) {
- WritePTLen (NT, TBIT, 3);
- } else {
- PutBits (TBIT, 0);
- PutBits (TBIT, Root);
- }
-
- WriteCLen ();
- } else {
- PutBits (TBIT, 0);
- PutBits (TBIT, 0);
- PutBits (CBIT, 0);
- PutBits (CBIT, Root);
- }
-
- Root = MakeTree (NP, mPFreq, mPTLen, mPTCode);
- if (Root >= NP) {
- WritePTLen (NP, PBIT, -1);
- } else {
- PutBits (PBIT, 0);
- PutBits (PBIT, Root);
- }
-
- Pos = 0;
- for (Index = 0; Index < Size; Index++) {
- if (Index % UINT8_BIT == 0) {
- Flags = mBuf[Pos++];
- } else {
- Flags <<= 1;
- }
-
- if (Flags & (1U << (UINT8_BIT - 1))) {
- EncodeC (mBuf[Pos++] + (1U << UINT8_BIT));
- Index3 = mBuf[Pos++];
- for (Index2 = 0; Index2 < 3; Index2++) {
- Index3 <<= UINT8_BIT;
- Index3 += mBuf[Pos++];
- }
-
- EncodeP (Index3);
- } else {
- EncodeC (mBuf[Pos++]);
- }
- }
-
- for (Index = 0; Index < NC; Index++) {
- mCFreq[Index] = 0;
- }
-
- for (Index = 0; Index < NP; Index++) {
- mPFreq[Index] = 0;
- }
-}
-
-/**
- Outputs an Original Character or a Pointer
-
- @param CharC The original character or the 'String Length' element of a Pointer
- @param Pos The 'Position' field of a Pointer
-**/
-STATIC
-VOID
-Output (
- IN UINT32 CharC,
- IN UINT32 Pos
- )
-{
- STATIC UINT32 CPos;
-
- if ((mOutputMask >>= 1) == 0) {
- mOutputMask = 1U << (UINT8_BIT - 1);
- //
- // Check the buffer overflow per outputing UINT8_BIT symbols
- // which is an Original Character or a Pointer. The biggest
- // symbol is a Pointer which occupies 5 bytes.
- //
- if (mOutputPos >= mBufSiz - 5 * UINT8_BIT) {
- SendBlock ();
- mOutputPos = 0;
- }
-
- CPos = mOutputPos++;
- mBuf[CPos] = 0;
- }
-
- mBuf[mOutputPos++] = (UINT8) CharC;
- mCFreq[CharC]++;
- if (CharC >= (1U << UINT8_BIT)) {
- mBuf[CPos] |= mOutputMask;
- mBuf[mOutputPos++] = (UINT8) (Pos >> 24);
- mBuf[mOutputPos++] = (UINT8) (Pos >> 16);
- mBuf[mOutputPos++] = (UINT8) (Pos >> (UINT8_BIT));
- mBuf[mOutputPos++] = (UINT8) Pos;
- CharC = 0;
- while (Pos) {
- Pos >>= 1;
- CharC++;
- }
-
- mPFreq[CharC]++;
- }
-}
-
-STATIC
-VOID
-HufEncodeStart (
- VOID
- )
-{
- INT32 Index;
-
- for (Index = 0; Index < NC; Index++) {
- mCFreq[Index] = 0;
- }
-
- for (Index = 0; Index < NP; Index++) {
- mPFreq[Index] = 0;
- }
-
- mOutputPos = mOutputMask = 0;
- InitPutBits ();
- return ;
-}
-
-STATIC
-VOID
-HufEncodeEnd (
- VOID
- )
-{
- SendBlock ();
-
- //
- // Flush remaining bits
- //
- PutBits (UINT8_BIT - 1, 0);
-
- return ;
-}
-
-STATIC
-VOID
-MakeCrcTable (
- VOID
- )
-{
- UINT32 Index;
- UINT32 Index2;
- UINT32 Temp;
-
- for (Index = 0; Index <= UINT8_MAX; Index++) {
- Temp = Index;
- for (Index2 = 0; Index2 < UINT8_BIT; Index2++) {
- if (Temp & 1) {
- Temp = (Temp >> 1) ^ CRCPOLY;
- } else {
- Temp >>= 1;
- }
- }
-
- mCrcTable[Index] = (UINT16) Temp;
- }
-}
-
-/**
- Outputs rightmost n bits of x
-
- @param Number the rightmost n bits of the data is used
- @param x the data
-**/
-STATIC
-VOID
-PutBits (
- IN INT32 Number,
- IN UINT32 Value
- )
-{
- UINT8 Temp;
-
- while (Number >= mBitCount) {
- //
- // Number -= mBitCount should never equal to 32
- //
- Temp = (UINT8) (mSubBitBuf | (Value >> (Number -= mBitCount)));
- if (mDst < mDstUpperLimit) {
- *mDst++ = Temp;
- }
-
- mCompSize++;
- mSubBitBuf = 0;
- mBitCount = UINT8_BIT;
- }
-
- mSubBitBuf |= Value << (mBitCount -= Number);
-}
-
-/**
- Read in source data
-
- @param Pointer - the buffer to hold the data
- @param Number - number of bytes to read
-
- @return number of bytes actually read
-**/
-STATIC
-INT32
-FreadCrc (
- OUT UINT8 *Pointer,
- IN INT32 Number
- )
-{
- INT32 Index;
-
- for (Index = 0; mSrc < mSrcUpperLimit && Index < Number; Index++) {
- *Pointer++ = *mSrc++;
- }
-
- Number = Index;
-
- Pointer -= Number;
- mOrigSize += Number;
- Index--;
- while (Index >= 0) {
- UPDATE_CRC (*Pointer++);
- Index--;
- }
-
- return Number;
-}
-
-STATIC
-VOID
-InitPutBits (
- VOID
- )
-{
- mBitCount = UINT8_BIT;
- mSubBitBuf = 0;
-}
-
-/**
- Count the number of each code length for a Huffman tree.
-
- @param Index the top node
-**/
-STATIC
-VOID
-CountLen (
- IN INT32 Index
- )
-{
- STATIC INT32 Depth = 0;
-
- if (Index < mN) {
- mLenCnt[(Depth < 16) ? Depth : 16]++;
- } else {
- Depth++;
- CountLen (mLeft[Index]);
- CountLen (mRight[Index]);
- Depth--;
- }
-}
-
-/**
- Create code length array for a Huffman tree
-
- @param Root the root of the tree
-**/
-STATIC
-VOID
-MakeLen (
- IN INT32 Root
- )
-{
- INT32 Index;
- INT32 Index3;
- UINT32 Cum;
-
- for (Index = 0; Index <= 16; Index++) {
- mLenCnt[Index] = 0;
- }
-
- CountLen (Root);
-
- //
- // Adjust the length count array so that
- // no code will be generated longer than its designated length
- //
- Cum = 0;
- for (Index = 16; Index > 0; Index--) {
- Cum += mLenCnt[Index] << (16 - Index);
- }
-
- while (Cum != (1U << 16)) {
- mLenCnt[16]--;
- for (Index = 15; Index > 0; Index--) {
- if (mLenCnt[Index] != 0) {
- mLenCnt[Index]--;
- mLenCnt[Index + 1] += 2;
- break;
- }
- }
-
- Cum--;
- }
-
- for (Index = 16; Index > 0; Index--) {
- Index3 = mLenCnt[Index];
- Index3--;
- while (Index3 >= 0) {
- mLen[*mSortPtr++] = (UINT8) Index;
- Index3--;
- }
- }
-}
-
-STATIC
-VOID
-DownHeap (
- IN INT32 Index
- )
-{
- INT32 Index2;
- INT32 Index3;
-
- //
- // priority queue: send Index-th entry down heap
- //
- Index3 = mHeap[Index];
- Index2 = 2 * Index;
- while (Index2 <= mHeapSize) {
- if (Index2 < mHeapSize && mFreq[mHeap[Index2]] > mFreq[mHeap[Index2 + 1]]) {
- Index2++;
- }
-
- if (mFreq[Index3] <= mFreq[mHeap[Index2]]) {
- break;
- }
-
- mHeap[Index] = mHeap[Index2];
- Index = Index2;
- Index2 = 2 * Index;
- }
-
- mHeap[Index] = (INT16) Index3;
-}
-
-/**
- Assign code to each symbol based on the code length array
-
- @param Number number of symbols
- @param Len the code length array
- @param Code stores codes for each symbol
-**/
-STATIC
-VOID
-MakeCode (
- IN INT32 Number,
- IN UINT8 Len[ ],
- OUT UINT16 Code[]
- )
-{
- INT32 Index;
- UINT16 Start[18];
-
- Start[1] = 0;
- for (Index = 1; Index <= 16; Index++) {
- Start[Index + 1] = (UINT16) ((Start[Index] + mLenCnt[Index]) << 1);
- }
-
- for (Index = 0; Index < Number; Index++) {
- Code[Index] = Start[Len[Index]]++;
- }
-}
-
-/**
- Generates Huffman codes given a frequency distribution of symbols
-
- @param NParm number of symbols
- @param FreqParm frequency of each symbol
- @param LenParm code length for each symbol
- @param CodeParm code for each symbol
-
- @return Root of the Huffman tree.
-**/
-STATIC
-INT32
-MakeTree (
- IN INT32 NParm,
- IN UINT16 FreqParm[],
- OUT UINT8 LenParm[ ],
- OUT UINT16 CodeParm[]
- )
-{
- INT32 Index;
- INT32 Index2;
- INT32 Index3;
- INT32 Avail;
-
- //
- // make tree, calculate len[], return root
- //
- mN = NParm;
- mFreq = FreqParm;
- mLen = LenParm;
- Avail = mN;
- mHeapSize = 0;
- mHeap[1] = 0;
- for (Index = 0; Index < mN; Index++) {
- mLen[Index] = 0;
- if (mFreq[Index]) {
- mHeapSize++;
- mHeap[mHeapSize] = (INT16) Index;
- }
- }
-
- if (mHeapSize < 2) {
- CodeParm[mHeap[1]] = 0;
- return mHeap[1];
- }
-
- for (Index = mHeapSize / 2; Index >= 1; Index--) {
- //
- // make priority queue
- //
- DownHeap (Index);
- }
-
- mSortPtr = CodeParm;
- do {
- Index = mHeap[1];
- if (Index < mN) {
- *mSortPtr++ = (UINT16) Index;
- }
-
- mHeap[1] = mHeap[mHeapSize--];
- DownHeap (1);
- Index2 = mHeap[1];
- if (Index2 < mN) {
- *mSortPtr++ = (UINT16) Index2;
- }
-
- Index3 = Avail++;
- mFreq[Index3] = (UINT16) (mFreq[Index] + mFreq[Index2]);
- mHeap[1] = (INT16) Index3;
- DownHeap (1);
- mLeft[Index3] = (UINT16) Index;
- mRight[Index3] = (UINT16) Index2;
- } while (mHeapSize > 1);
-
- mSortPtr = CodeParm;
- MakeLen (Index3);
- MakeCode (NParm, LenParm, CodeParm);
-
- //
- // return root
- //
- return Index3;
-}
+/** @file +Compression routine. The compression algorithm is a mixture of LZ77 and Huffman +coding. LZ77 transforms the source data into a sequence of Original Characters +and Pointers to repeated strings. This sequence is further divided into Blocks +and Huffman codings are applied to each Block. + +Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR> +SPDX-License-Identifier: BSD-2-Clause-Patent + +**/ + +#include "Compress.h" + +// +// Macro Definitions +// +#undef UINT8_MAX +typedef INT32 NODE; +#define UINT8_MAX 0xff +#define UINT8_BIT 8 +#define THRESHOLD 3 +#define INIT_CRC 0 +#define WNDBIT 19 +#define WNDSIZ (1U << WNDBIT) +#define MAXMATCH 256 +#define BLKSIZ (1U << 14) // 16 * 1024U +#define PERC_FLAG 0x80000000U +#define CODE_BIT 16 +#define NIL 0 +#define MAX_HASH_VAL (3 * WNDSIZ + (WNDSIZ / 512 + 1) * UINT8_MAX) +#define HASH(p, c) ((p) + ((c) << (WNDBIT - 9)) + WNDSIZ * 2) +#define CRCPOLY 0xA001 +#define UPDATE_CRC(c) mCrc = mCrcTable[(mCrc ^ (c)) & 0xFF] ^ (mCrc >> UINT8_BIT) + +// +// C: the Char&Len Set; P: the Position Set; T: the exTra Set +// +#define NC (UINT8_MAX + MAXMATCH + 2 - THRESHOLD) +#define CBIT 9 +#define NP (WNDBIT + 1) +#define PBIT 5 +#define NT (CODE_BIT + 3) +#define TBIT 5 +#if NT > NP +#define NPT NT +#else +#define NPT NP +#endif +// +// Function Prototypes +// + +STATIC +VOID +PutDword( + IN UINT32 Data + ); + +STATIC +EFI_STATUS +AllocateMemory ( + VOID + ); + +STATIC +VOID +FreeMemory ( + VOID + ); + +STATIC +VOID +InitSlide ( + VOID + ); + +STATIC +NODE +Child ( + IN NODE NodeQ, + IN UINT8 CharC + ); + +STATIC +VOID +MakeChild ( + IN NODE NodeQ, + IN UINT8 CharC, + IN NODE NodeR + ); + +STATIC +VOID +Split ( + IN NODE Old + ); + +STATIC +VOID +InsertNode ( + VOID + ); + +STATIC +VOID +DeleteNode ( + VOID + ); + +STATIC +VOID +GetNextMatch ( + VOID + ); + +STATIC +EFI_STATUS +Encode ( + VOID + ); + +STATIC +VOID +CountTFreq ( + VOID + ); + +STATIC +VOID +WritePTLen ( + IN INT32 Number, + IN INT32 nbit, + IN INT32 Special + ); + +STATIC +VOID +WriteCLen ( + VOID + ); + +STATIC +VOID +EncodeC ( + IN INT32 Value + ); + +STATIC +VOID +EncodeP ( + IN UINT32 Value + ); + +STATIC +VOID +SendBlock ( + VOID + ); + +STATIC +VOID +Output ( + IN UINT32 c, + IN UINT32 p + ); + +STATIC +VOID +HufEncodeStart ( + VOID + ); + +STATIC +VOID +HufEncodeEnd ( + VOID + ); + +STATIC +VOID +MakeCrcTable ( + VOID + ); + +STATIC +VOID +PutBits ( + IN INT32 Number, + IN UINT32 Value + ); + +STATIC +INT32 +FreadCrc ( + OUT UINT8 *Pointer, + IN INT32 Number + ); + +STATIC +VOID +InitPutBits ( + VOID + ); + +STATIC +VOID +CountLen ( + IN INT32 Index + ); + +STATIC +VOID +MakeLen ( + IN INT32 Root + ); + +STATIC +VOID +DownHeap ( + IN INT32 Index + ); + +STATIC +VOID +MakeCode ( + IN INT32 Number, + IN UINT8 Len[ ], + OUT UINT16 Code[] + ); + +STATIC +INT32 +MakeTree ( + IN INT32 NParm, + IN UINT16 FreqParm[], + OUT UINT8 LenParm[ ], + OUT UINT16 CodeParm[] + ); + +// +// Global Variables +// +STATIC UINT8 *mSrc, *mDst, *mSrcUpperLimit, *mDstUpperLimit; + +STATIC UINT8 *mLevel, *mText, *mChildCount, *mBuf, mCLen[NC], mPTLen[NPT], *mLen; +STATIC INT16 mHeap[NC + 1]; +STATIC INT32 mRemainder, mMatchLen, mBitCount, mHeapSize, mN; +STATIC UINT32 mBufSiz = 0, mOutputPos, mOutputMask, mSubBitBuf, mCrc; +STATIC UINT32 mCompSize, mOrigSize; + +STATIC UINT16 *mFreq, *mSortPtr, mLenCnt[17], mLeft[2 * NC - 1], mRight[2 * NC - 1], mCrcTable[UINT8_MAX + 1], + mCFreq[2 * NC - 1], mCCode[NC], mPFreq[2 * NP - 1], mPTCode[NPT], mTFreq[2 * NT - 1]; + +STATIC NODE mPos, mMatchPos, mAvail, *mPosition, *mParent, *mPrev, *mNext = NULL; + +// +// functions +// + +/** + The internal implementation of [Efi/Tiano]Compress(). + + @param SrcBuffer The buffer storing the source data + @param SrcSize The size of source data + @param DstBuffer The buffer to store the compressed data + @param DstSize On input, the size of DstBuffer; On output, + the size of the actual compressed data. + @param Version The version of de/compression algorithm. + Version 1 for UEFI 2.0 de/compression algorithm. + Version 2 for Tiano de/compression algorithm. + + @retval EFI_BUFFER_TOO_SMALL The DstBuffer is too small. In this case, + DstSize contains the size needed. + @retval EFI_SUCCESS Compression is successful. + @retval EFI_OUT_OF_RESOURCES No resource to complete function. + @retval EFI_INVALID_PARAMETER Parameter supplied is wrong. +**/ +EFI_STATUS +TianoCompress ( + IN UINT8 *SrcBuffer, + IN UINT32 SrcSize, + IN UINT8 *DstBuffer, + IN OUT UINT32 *DstSize + ) +{ + EFI_STATUS Status; + + // + // Initializations + // + mBufSiz = 0; + mBuf = NULL; + mText = NULL; + mLevel = NULL; + mChildCount = NULL; + mPosition = NULL; + mParent = NULL; + mPrev = NULL; + mNext = NULL; + + mSrc = SrcBuffer; + mSrcUpperLimit = mSrc + SrcSize; + mDst = DstBuffer; + mDstUpperLimit = mDst +*DstSize; + + PutDword (0L); + PutDword (0L); + + MakeCrcTable (); + + mOrigSize = mCompSize = 0; + mCrc = INIT_CRC; + + // + // Compress it + // + Status = Encode (); + if (EFI_ERROR (Status)) { + return EFI_OUT_OF_RESOURCES; + } + // + // Null terminate the compressed data + // + if (mDst < mDstUpperLimit) { + *mDst++ = 0; + } + // + // Fill in compressed size and original size + // + mDst = DstBuffer; + PutDword (mCompSize + 1); + PutDword (mOrigSize); + + // + // Return + // + if (mCompSize + 1 + 8 > *DstSize) { + *DstSize = mCompSize + 1 + 8; + return EFI_BUFFER_TOO_SMALL; + } else { + *DstSize = mCompSize + 1 + 8; + return EFI_SUCCESS; + } + +} + +/** + Put a dword to output stream + + @param Data the dword to put +**/ +STATIC +VOID +PutDword ( + IN UINT32 Data + ) +{ + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8) (((UINT8) (Data)) & 0xff); + } + + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8) (((UINT8) (Data >> 0x08)) & 0xff); + } + + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8) (((UINT8) (Data >> 0x10)) & 0xff); + } + + if (mDst < mDstUpperLimit) { + *mDst++ = (UINT8) (((UINT8) (Data >> 0x18)) & 0xff); + } +} + +/** + Allocate memory spaces for data structures used in compression process + + @retval EFI_SUCCESS Memory is allocated successfully + @retval EFI_OUT_OF_RESOURCES Allocation fails +**/ +STATIC +EFI_STATUS +AllocateMemory ( + VOID + ) +{ + UINT32 Index; + + mText = malloc (WNDSIZ * 2 + MAXMATCH); + if (mText == NULL) { + return EFI_OUT_OF_RESOURCES; + } + for (Index = 0; Index < WNDSIZ * 2 + MAXMATCH; Index++) { + mText[Index] = 0; + } + + mLevel = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof (*mLevel)); + mChildCount = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof (*mChildCount)); + mPosition = malloc ((WNDSIZ + UINT8_MAX + 1) * sizeof (*mPosition)); + mParent = malloc (WNDSIZ * 2 * sizeof (*mParent)); + mPrev = malloc (WNDSIZ * 2 * sizeof (*mPrev)); + mNext = malloc ((MAX_HASH_VAL + 1) * sizeof (*mNext)); + if (mLevel == NULL || mChildCount == NULL || mPosition == NULL || + mParent == NULL || mPrev == NULL || mNext == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + mBufSiz = BLKSIZ; + mBuf = malloc (mBufSiz); + while (mBuf == NULL) { + mBufSiz = (mBufSiz / 10U) * 9U; + if (mBufSiz < 4 * 1024U) { + return EFI_OUT_OF_RESOURCES; + } + + mBuf = malloc (mBufSiz); + } + + mBuf[0] = 0; + + return EFI_SUCCESS; +} + +/** + Called when compression is completed to free memory previously allocated. +**/ +VOID +FreeMemory ( + VOID + ) +{ + if (mText != NULL) { + free (mText); + } + + if (mLevel != NULL) { + free (mLevel); + } + + if (mChildCount != NULL) { + free (mChildCount); + } + + if (mPosition != NULL) { + free (mPosition); + } + + if (mParent != NULL) { + free (mParent); + } + + if (mPrev != NULL) { + free (mPrev); + } + + if (mNext != NULL) { + free (mNext); + } + + if (mBuf != NULL) { + free (mBuf); + } + + return ; +} + +/** + Initialize String Info Log data structures +**/ +STATIC +VOID +InitSlide ( + VOID + ) +{ + NODE Index; + + for (Index = WNDSIZ; Index <= WNDSIZ + UINT8_MAX; Index++) { + mLevel[Index] = 1; + mPosition[Index] = NIL; /* sentinel */ + } + + for (Index = WNDSIZ; Index < WNDSIZ * 2; Index++) { + mParent[Index] = NIL; + } + + mAvail = 1; + for (Index = 1; Index < WNDSIZ - 1; Index++) { + mNext[Index] = (NODE) (Index + 1); + } + + mNext[WNDSIZ - 1] = NIL; + for (Index = WNDSIZ * 2; Index <= MAX_HASH_VAL; Index++) { + mNext[Index] = NIL; + } +} + +/** + Find child node given the parent node and the edge character + + @param NodeQ the parent node + @param CharC the edge character + + @return The child node (NIL if not found) +**/ +STATIC +NODE +Child ( + IN NODE NodeQ, + IN UINT8 CharC + ) +{ + NODE NodeR; + + NodeR = mNext[HASH (NodeQ, CharC)]; + // + // sentinel + // + mParent[NIL] = NodeQ; + while (mParent[NodeR] != NodeQ) { + NodeR = mNext[NodeR]; + } + + return NodeR; +} + +/** + Create a new child for a given parent node. + + @param Parent the parent node + @param CharC the edge character + @param Child the child node +**/ +STATIC +VOID +MakeChild ( + IN NODE Parent, + IN UINT8 CharC, + IN NODE Child + ) +{ + NODE Node1; + NODE Node2; + + Node1 = (NODE) HASH (Parent, CharC); + Node2 = mNext[Node1]; + mNext[Node1] = Child; + mNext[Child] = Node2; + mPrev[Node2] = Child; + mPrev[Child] = Node1; + mParent[Child] = Parent; + mChildCount[Parent]++; +} + +/** + Split a node. + + @param Old the node to split +**/ +STATIC +VOID +Split ( + NODE Old + ) +{ + NODE New; + NODE TempNode; + + New = mAvail; + mAvail = mNext[New]; + mChildCount[New] = 0; + TempNode = mPrev[Old]; + mPrev[New] = TempNode; + mNext[TempNode] = New; + TempNode = mNext[Old]; + mNext[New] = TempNode; + mPrev[TempNode] = New; + mParent[New] = mParent[Old]; + mLevel[New] = (UINT8) mMatchLen; + mPosition[New] = mPos; + MakeChild (New, mText[mMatchPos + mMatchLen], Old); + MakeChild (New, mText[mPos + mMatchLen], mPos); +} + +/** + Insert string info for current position into the String Info Log +**/ +STATIC +VOID +InsertNode ( + VOID + ) +{ + NODE NodeQ; + NODE NodeR; + NODE Index2; + NODE NodeT; + UINT8 CharC; + UINT8 *t1; + UINT8 *t2; + + if (mMatchLen >= 4) { + // + // We have just got a long match, the target tree + // can be located by MatchPos + 1. Traverse the tree + // from bottom up to get to a proper starting point. + // The usage of PERC_FLAG ensures proper node deletion + // in DeleteNode() later. + // + mMatchLen--; + NodeR = (NODE) ((mMatchPos + 1) | WNDSIZ); + NodeQ = mParent[NodeR]; + while (NodeQ == NIL) { + NodeR = mNext[NodeR]; + NodeQ = mParent[NodeR]; + } + + while (mLevel[NodeQ] >= mMatchLen) { + NodeR = NodeQ; + NodeQ = mParent[NodeQ]; + } + + NodeT = NodeQ; + while (mPosition[NodeT] < 0) { + mPosition[NodeT] = mPos; + NodeT = mParent[NodeT]; + } + + if (NodeT < WNDSIZ) { + mPosition[NodeT] = (NODE) (mPos | (UINT32) PERC_FLAG); + } + } else { + // + // Locate the target tree + // + NodeQ = (NODE) (mText[mPos] + WNDSIZ); + CharC = mText[mPos + 1]; + NodeR = Child (NodeQ, CharC); + if (NodeR == NIL) { + MakeChild (NodeQ, CharC, mPos); + mMatchLen = 1; + return ; + } + + mMatchLen = 2; + } + // + // Traverse down the tree to find a match. + // Update Position value along the route. + // Node split or creation is involved. + // + for (;;) { + if (NodeR >= WNDSIZ) { + Index2 = MAXMATCH; + mMatchPos = NodeR; + } else { + Index2 = mLevel[NodeR]; + mMatchPos = (NODE) (mPosition[NodeR] & (UINT32)~PERC_FLAG); + } + + if (mMatchPos >= mPos) { + mMatchPos -= WNDSIZ; + } + + t1 = &mText[mPos + mMatchLen]; + t2 = &mText[mMatchPos + mMatchLen]; + while (mMatchLen < Index2) { + if (*t1 != *t2) { + Split (NodeR); + return ; + } + + mMatchLen++; + t1++; + t2++; + } + + if (mMatchLen >= MAXMATCH) { + break; + } + + mPosition[NodeR] = mPos; + NodeQ = NodeR; + NodeR = Child (NodeQ, *t1); + if (NodeR == NIL) { + MakeChild (NodeQ, *t1, mPos); + return ; + } + + mMatchLen++; + } + + NodeT = mPrev[NodeR]; + mPrev[mPos] = NodeT; + mNext[NodeT] = mPos; + NodeT = mNext[NodeR]; + mNext[mPos] = NodeT; + mPrev[NodeT] = mPos; + mParent[mPos] = NodeQ; + mParent[NodeR] = NIL; + + // + // Special usage of 'next' + // + mNext[NodeR] = mPos; + +} + +/** + Delete outdated string info. (The Usage of PERC_FLAG + ensures a clean deletion) +**/ +STATIC +VOID +DeleteNode ( + VOID + ) +{ + NODE NodeQ; + NODE NodeR; + NODE NodeS; + NODE NodeT; + NODE NodeU; + + if (mParent[mPos] == NIL) { + return ; + } + + NodeR = mPrev[mPos]; + NodeS = mNext[mPos]; + mNext[NodeR] = NodeS; + mPrev[NodeS] = NodeR; + NodeR = mParent[mPos]; + mParent[mPos] = NIL; + if (NodeR >= WNDSIZ) { + return ; + } + + mChildCount[NodeR]--; + if (mChildCount[NodeR] > 1) { + return ; + } + + NodeT = (NODE) (mPosition[NodeR] & (UINT32)~PERC_FLAG); + if (NodeT >= mPos) { + NodeT -= WNDSIZ; + } + + NodeS = NodeT; + NodeQ = mParent[NodeR]; + NodeU = mPosition[NodeQ]; + while (NodeU & (UINT32) PERC_FLAG) { + NodeU &= (UINT32)~PERC_FLAG; + if (NodeU >= mPos) { + NodeU -= WNDSIZ; + } + + if (NodeU > NodeS) { + NodeS = NodeU; + } + + mPosition[NodeQ] = (NODE) (NodeS | WNDSIZ); + NodeQ = mParent[NodeQ]; + NodeU = mPosition[NodeQ]; + } + + if (NodeQ < WNDSIZ) { + if (NodeU >= mPos) { + NodeU -= WNDSIZ; + } + + if (NodeU > NodeS) { + NodeS = NodeU; + } + + mPosition[NodeQ] = (NODE) (NodeS | WNDSIZ | (UINT32) PERC_FLAG); + } + + NodeS = Child (NodeR, mText[NodeT + mLevel[NodeR]]); + NodeT = mPrev[NodeS]; + NodeU = mNext[NodeS]; + mNext[NodeT] = NodeU; + mPrev[NodeU] = NodeT; + NodeT = mPrev[NodeR]; + mNext[NodeT] = NodeS; + mPrev[NodeS] = NodeT; + NodeT = mNext[NodeR]; + mPrev[NodeT] = NodeS; + mNext[NodeS] = NodeT; + mParent[NodeS] = mParent[NodeR]; + mParent[NodeR] = NIL; + mNext[NodeR] = mAvail; + mAvail = NodeR; +} + +/** + Advance the current position (read in new data if needed). + Delete outdated string info. Find a match string for current position. +**/ +STATIC +VOID +GetNextMatch ( + VOID + ) +{ + INT32 Number; + + mRemainder--; + mPos++; + if (mPos == WNDSIZ * 2) { + memmove (&mText[0], &mText[WNDSIZ], WNDSIZ + MAXMATCH); + Number = FreadCrc (&mText[WNDSIZ + MAXMATCH], WNDSIZ); + mRemainder += Number; + mPos = WNDSIZ; + } + + DeleteNode (); + InsertNode (); +} + +/** + The main controlling routine for compression process. + + @retval EFI_SUCCESS The compression is successful + @retval EFI_OUT_0F_RESOURCES Not enough memory for compression process +**/ +STATIC +EFI_STATUS +Encode ( + VOID + ) +{ + EFI_STATUS Status; + INT32 LastMatchLen; + NODE LastMatchPos; + + Status = AllocateMemory (); + if (EFI_ERROR (Status)) { + FreeMemory (); + return Status; + } + + InitSlide (); + + HufEncodeStart (); + + mRemainder = FreadCrc (&mText[WNDSIZ], WNDSIZ + MAXMATCH); + + mMatchLen = 0; + mPos = WNDSIZ; + InsertNode (); + if (mMatchLen > mRemainder) { + mMatchLen = mRemainder; + } + + while (mRemainder > 0) { + LastMatchLen = mMatchLen; + LastMatchPos = mMatchPos; + GetNextMatch (); + if (mMatchLen > mRemainder) { + mMatchLen = mRemainder; + } + + if (mMatchLen > LastMatchLen || LastMatchLen < THRESHOLD) { + // + // Not enough benefits are gained by outputting a pointer, + // so just output the original character + // + Output (mText[mPos - 1], 0); + + } else { + + if (LastMatchLen == THRESHOLD) { + if (((mPos - LastMatchPos - 2) & (WNDSIZ - 1)) > (1U << 11)) { + Output (mText[mPos - 1], 0); + continue; + } + } + // + // Outputting a pointer is beneficial enough, do it. + // + Output ( + LastMatchLen + (UINT8_MAX + 1 - THRESHOLD), + (mPos - LastMatchPos - 2) & (WNDSIZ - 1) + ); + LastMatchLen--; + while (LastMatchLen > 0) { + GetNextMatch (); + LastMatchLen--; + } + + if (mMatchLen > mRemainder) { + mMatchLen = mRemainder; + } + } + } + + HufEncodeEnd (); + FreeMemory (); + return EFI_SUCCESS; +} + +/** + Count the frequencies for the Extra Set +**/ +STATIC +VOID +CountTFreq ( + VOID + ) +{ + INT32 Index; + INT32 Index3; + INT32 Number; + INT32 Count; + + for (Index = 0; Index < NT; Index++) { + mTFreq[Index] = 0; + } + + Number = NC; + while (Number > 0 && mCLen[Number - 1] == 0) { + Number--; + } + + Index = 0; + while (Index < Number) { + Index3 = mCLen[Index++]; + if (Index3 == 0) { + Count = 1; + while (Index < Number && mCLen[Index] == 0) { + Index++; + Count++; + } + + if (Count <= 2) { + mTFreq[0] = (UINT16) (mTFreq[0] + Count); + } else if (Count <= 18) { + mTFreq[1]++; + } else if (Count == 19) { + mTFreq[0]++; + mTFreq[1]++; + } else { + mTFreq[2]++; + } + } else { + mTFreq[Index3 + 2]++; + } + } +} + +/** + Outputs the code length array for the Extra Set or the Position Set. + + @param Number the number of symbols + @param nbit the number of bits needed to represent 'n' + @param Special the special symbol that needs to be take care of +**/ +STATIC +VOID +WritePTLen ( + IN INT32 Number, + IN INT32 nbit, + IN INT32 Special + ) +{ + INT32 Index; + INT32 Index3; + + while (Number > 0 && mPTLen[Number - 1] == 0) { + Number--; + } + + PutBits (nbit, Number); + Index = 0; + while (Index < Number) { + Index3 = mPTLen[Index++]; + if (Index3 <= 6) { + PutBits (3, Index3); + } else { + PutBits (Index3 - 3, (1U << (Index3 - 3)) - 2); + } + + if (Index == Special) { + while (Index < 6 && mPTLen[Index] == 0) { + Index++; + } + + PutBits (2, (Index - 3) & 3); + } + } +} + +/** + Outputs the code length array for Char&Length Set +**/ +STATIC +VOID +WriteCLen ( + VOID + ) +{ + INT32 Index; + INT32 Index3; + INT32 Number; + INT32 Count; + + Number = NC; + while (Number > 0 && mCLen[Number - 1] == 0) { + Number--; + } + + PutBits (CBIT, Number); + Index = 0; + while (Index < Number) { + Index3 = mCLen[Index++]; + if (Index3 == 0) { + Count = 1; + while (Index < Number && mCLen[Index] == 0) { + Index++; + Count++; + } + + if (Count <= 2) { + for (Index3 = 0; Index3 < Count; Index3++) { + PutBits (mPTLen[0], mPTCode[0]); + } + } else if (Count <= 18) { + PutBits (mPTLen[1], mPTCode[1]); + PutBits (4, Count - 3); + } else if (Count == 19) { + PutBits (mPTLen[0], mPTCode[0]); + PutBits (mPTLen[1], mPTCode[1]); + PutBits (4, 15); + } else { + PutBits (mPTLen[2], mPTCode[2]); + PutBits (CBIT, Count - 20); + } + } else { + PutBits (mPTLen[Index3 + 2], mPTCode[Index3 + 2]); + } + } +} + +STATIC +VOID +EncodeC ( + IN INT32 Value + ) +{ + PutBits (mCLen[Value], mCCode[Value]); +} + +STATIC +VOID +EncodeP ( + IN UINT32 Value + ) +{ + UINT32 Index; + UINT32 NodeQ; + + Index = 0; + NodeQ = Value; + while (NodeQ) { + NodeQ >>= 1; + Index++; + } + + PutBits (mPTLen[Index], mPTCode[Index]); + if (Index > 1) { + PutBits (Index - 1, Value & (0xFFFFFFFFU >> (32 - Index + 1))); + } +} + +/** + Huffman code the block and output it. +**/ +STATIC +VOID +SendBlock ( + VOID + ) +{ + UINT32 Index; + UINT32 Index2; + UINT32 Index3; + UINT32 Flags; + UINT32 Root; + UINT32 Pos; + UINT32 Size; + Flags = 0; + + Root = MakeTree (NC, mCFreq, mCLen, mCCode); + Size = mCFreq[Root]; + PutBits (16, Size); + if (Root >= NC) { + CountTFreq (); + Root = MakeTree (NT, mTFreq, mPTLen, mPTCode); + if (Root >= NT) { + WritePTLen (NT, TBIT, 3); + } else { + PutBits (TBIT, 0); + PutBits (TBIT, Root); + } + + WriteCLen (); + } else { + PutBits (TBIT, 0); + PutBits (TBIT, 0); + PutBits (CBIT, 0); + PutBits (CBIT, Root); + } + + Root = MakeTree (NP, mPFreq, mPTLen, mPTCode); + if (Root >= NP) { + WritePTLen (NP, PBIT, -1); + } else { + PutBits (PBIT, 0); + PutBits (PBIT, Root); + } + + Pos = 0; + for (Index = 0; Index < Size; Index++) { + if (Index % UINT8_BIT == 0) { + Flags = mBuf[Pos++]; + } else { + Flags <<= 1; + } + + if (Flags & (1U << (UINT8_BIT - 1))) { + EncodeC (mBuf[Pos++] + (1U << UINT8_BIT)); + Index3 = mBuf[Pos++]; + for (Index2 = 0; Index2 < 3; Index2++) { + Index3 <<= UINT8_BIT; + Index3 += mBuf[Pos++]; + } + + EncodeP (Index3); + } else { + EncodeC (mBuf[Pos++]); + } + } + + for (Index = 0; Index < NC; Index++) { + mCFreq[Index] = 0; + } + + for (Index = 0; Index < NP; Index++) { + mPFreq[Index] = 0; + } +} + +/** + Outputs an Original Character or a Pointer + + @param CharC The original character or the 'String Length' element of a Pointer + @param Pos The 'Position' field of a Pointer +**/ +STATIC +VOID +Output ( + IN UINT32 CharC, + IN UINT32 Pos + ) +{ + STATIC UINT32 CPos; + + if ((mOutputMask >>= 1) == 0) { + mOutputMask = 1U << (UINT8_BIT - 1); + // + // Check the buffer overflow per outputing UINT8_BIT symbols + // which is an Original Character or a Pointer. The biggest + // symbol is a Pointer which occupies 5 bytes. + // + if (mOutputPos >= mBufSiz - 5 * UINT8_BIT) { + SendBlock (); + mOutputPos = 0; + } + + CPos = mOutputPos++; + mBuf[CPos] = 0; + } + + mBuf[mOutputPos++] = (UINT8) CharC; + mCFreq[CharC]++; + if (CharC >= (1U << UINT8_BIT)) { + mBuf[CPos] |= mOutputMask; + mBuf[mOutputPos++] = (UINT8) (Pos >> 24); + mBuf[mOutputPos++] = (UINT8) (Pos >> 16); + mBuf[mOutputPos++] = (UINT8) (Pos >> (UINT8_BIT)); + mBuf[mOutputPos++] = (UINT8) Pos; + CharC = 0; + while (Pos) { + Pos >>= 1; + CharC++; + } + + mPFreq[CharC]++; + } +} + +STATIC +VOID +HufEncodeStart ( + VOID + ) +{ + INT32 Index; + + for (Index = 0; Index < NC; Index++) { + mCFreq[Index] = 0; + } + + for (Index = 0; Index < NP; Index++) { + mPFreq[Index] = 0; + } + + mOutputPos = mOutputMask = 0; + InitPutBits (); + return ; +} + +STATIC +VOID +HufEncodeEnd ( + VOID + ) +{ + SendBlock (); + + // + // Flush remaining bits + // + PutBits (UINT8_BIT - 1, 0); + + return ; +} + +STATIC +VOID +MakeCrcTable ( + VOID + ) +{ + UINT32 Index; + UINT32 Index2; + UINT32 Temp; + + for (Index = 0; Index <= UINT8_MAX; Index++) { + Temp = Index; + for (Index2 = 0; Index2 < UINT8_BIT; Index2++) { + if (Temp & 1) { + Temp = (Temp >> 1) ^ CRCPOLY; + } else { + Temp >>= 1; + } + } + + mCrcTable[Index] = (UINT16) Temp; + } +} + +/** + Outputs rightmost n bits of x + + @param Number the rightmost n bits of the data is used + @param x the data +**/ +STATIC +VOID +PutBits ( + IN INT32 Number, + IN UINT32 Value + ) +{ + UINT8 Temp; + + while (Number >= mBitCount) { + // + // Number -= mBitCount should never equal to 32 + // + Temp = (UINT8) (mSubBitBuf | (Value >> (Number -= mBitCount))); + if (mDst < mDstUpperLimit) { + *mDst++ = Temp; + } + + mCompSize++; + mSubBitBuf = 0; + mBitCount = UINT8_BIT; + } + + mSubBitBuf |= Value << (mBitCount -= Number); +} + +/** + Read in source data + + @param Pointer - the buffer to hold the data + @param Number - number of bytes to read + + @return number of bytes actually read +**/ +STATIC +INT32 +FreadCrc ( + OUT UINT8 *Pointer, + IN INT32 Number + ) +{ + INT32 Index; + + for (Index = 0; mSrc < mSrcUpperLimit && Index < Number; Index++) { + *Pointer++ = *mSrc++; + } + + Number = Index; + + Pointer -= Number; + mOrigSize += Number; + Index--; + while (Index >= 0) { + UPDATE_CRC (*Pointer++); + Index--; + } + + return Number; +} + +STATIC +VOID +InitPutBits ( + VOID + ) +{ + mBitCount = UINT8_BIT; + mSubBitBuf = 0; +} + +/** + Count the number of each code length for a Huffman tree. + + @param Index the top node +**/ +STATIC +VOID +CountLen ( + IN INT32 Index + ) +{ + STATIC INT32 Depth = 0; + + if (Index < mN) { + mLenCnt[(Depth < 16) ? Depth : 16]++; + } else { + Depth++; + CountLen (mLeft[Index]); + CountLen (mRight[Index]); + Depth--; + } +} + +/** + Create code length array for a Huffman tree + + @param Root the root of the tree +**/ +STATIC +VOID +MakeLen ( + IN INT32 Root + ) +{ + INT32 Index; + INT32 Index3; + UINT32 Cum; + + for (Index = 0; Index <= 16; Index++) { + mLenCnt[Index] = 0; + } + + CountLen (Root); + + // + // Adjust the length count array so that + // no code will be generated longer than its designated length + // + Cum = 0; + for (Index = 16; Index > 0; Index--) { + Cum += mLenCnt[Index] << (16 - Index); + } + + while (Cum != (1U << 16)) { + mLenCnt[16]--; + for (Index = 15; Index > 0; Index--) { + if (mLenCnt[Index] != 0) { + mLenCnt[Index]--; + mLenCnt[Index + 1] += 2; + break; + } + } + + Cum--; + } + + for (Index = 16; Index > 0; Index--) { + Index3 = mLenCnt[Index]; + Index3--; + while (Index3 >= 0) { + mLen[*mSortPtr++] = (UINT8) Index; + Index3--; + } + } +} + +STATIC +VOID +DownHeap ( + IN INT32 Index + ) +{ + INT32 Index2; + INT32 Index3; + + // + // priority queue: send Index-th entry down heap + // + Index3 = mHeap[Index]; + Index2 = 2 * Index; + while (Index2 <= mHeapSize) { + if (Index2 < mHeapSize && mFreq[mHeap[Index2]] > mFreq[mHeap[Index2 + 1]]) { + Index2++; + } + + if (mFreq[Index3] <= mFreq[mHeap[Index2]]) { + break; + } + + mHeap[Index] = mHeap[Index2]; + Index = Index2; + Index2 = 2 * Index; + } + + mHeap[Index] = (INT16) Index3; +} + +/** + Assign code to each symbol based on the code length array + + @param Number number of symbols + @param Len the code length array + @param Code stores codes for each symbol +**/ +STATIC +VOID +MakeCode ( + IN INT32 Number, + IN UINT8 Len[ ], + OUT UINT16 Code[] + ) +{ + INT32 Index; + UINT16 Start[18]; + + Start[1] = 0; + for (Index = 1; Index <= 16; Index++) { + Start[Index + 1] = (UINT16) ((Start[Index] + mLenCnt[Index]) << 1); + } + + for (Index = 0; Index < Number; Index++) { + Code[Index] = Start[Len[Index]]++; + } +} + +/** + Generates Huffman codes given a frequency distribution of symbols + + @param NParm number of symbols + @param FreqParm frequency of each symbol + @param LenParm code length for each symbol + @param CodeParm code for each symbol + + @return Root of the Huffman tree. +**/ +STATIC +INT32 +MakeTree ( + IN INT32 NParm, + IN UINT16 FreqParm[], + OUT UINT8 LenParm[ ], + OUT UINT16 CodeParm[] + ) +{ + INT32 Index; + INT32 Index2; + INT32 Index3; + INT32 Avail; + + // + // make tree, calculate len[], return root + // + mN = NParm; + mFreq = FreqParm; + mLen = LenParm; + Avail = mN; + mHeapSize = 0; + mHeap[1] = 0; + for (Index = 0; Index < mN; Index++) { + mLen[Index] = 0; + if (mFreq[Index]) { + mHeapSize++; + mHeap[mHeapSize] = (INT16) Index; + } + } + + if (mHeapSize < 2) { + CodeParm[mHeap[1]] = 0; + return mHeap[1]; + } + + for (Index = mHeapSize / 2; Index >= 1; Index--) { + // + // make priority queue + // + DownHeap (Index); + } + + mSortPtr = CodeParm; + do { + Index = mHeap[1]; + if (Index < mN) { + *mSortPtr++ = (UINT16) Index; + } + + mHeap[1] = mHeap[mHeapSize--]; + DownHeap (1); + Index2 = mHeap[1]; + if (Index2 < mN) { + *mSortPtr++ = (UINT16) Index2; + } + + Index3 = Avail++; + mFreq[Index3] = (UINT16) (mFreq[Index] + mFreq[Index2]); + mHeap[1] = (INT16) Index3; + DownHeap (1); + mLeft[Index3] = (UINT16) Index; + mRight[Index3] = (UINT16) Index2; + } while (mHeapSize > 1); + + mSortPtr = CodeParm; + MakeLen (Index3); + MakeCode (NParm, LenParm, CodeParm); + + // + // return root + // + return Index3; +} |
