/** @file The API to parse the binary. Copyright (c) 2011-2019, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #ifndef __GNUC__ #include "windows.h" #else #include #include #include #endif #include "BinaryParse.h" #include "BinaryCreate.h" #include "VariableCommon.h" #include "FirmwareVolumeBufferLib.h" extern G_EFI_FD_INFO gEfiFdInfo; extern EFI_HANDLE mParsedGuidedSectionTools; extern CHAR8 mInputFdName[MAX_FILENAME_LEN]; // // The Guid to sign the position of Vfr and Uni array in FV // EFI_GUID gVfrArrayAttractGuid = EFI_VFR_ATTRACT_GUID; EFI_GUID gUniStrArrayAttractGuid = EFI_UNI_STR_ATTRACT_GUID; EFI_GUID gEfiSystemNvDataFvGuid = EFI_SYSTEM_NVDATA_FV_GUID; EFI_GUID gEfiCrc32GuidedSectionExtractionProtocolGuid = EFI_CRC32_GUIDED_SECTION_EXTRACTION_PROTOCOL_GUID; /** Converts a three byte length value into a UINT32. @param ThreeByteLength Pointer to the first of the 3 byte length. @retval Length Size of the section **/ static UINT32 Get3ByteLength ( IN UINT8 *ThreeByteLength ) { UINT32 Length; Length = 0; if (ThreeByteLength == NULL) { return 0; } Length = *((UINT32 *) ThreeByteLength); Length = Length & 0x00FFFFFF; return Length; } /** Generate the unique template filename. **/ CHAR8 * GenTempFile ( VOID ) { CHAR8 *TemString; TemString = NULL; #ifndef __GNUC__ TemString = CloneString (tmpnam (NULL)); #else CHAR8 tmp[] = "/tmp/fileXXXXXX"; UINTN Fdtmp; Fdtmp = mkstemp(tmp); TemString = CloneString(tmp); close(Fdtmp); #endif return TemString; } /** Check whether exist the same Ifr FFS. If not existed, return TRUE. @param[in] FfsImage The pointer to the binary. @param[in] FileSize The size of binary. @return The string after convert. **/ static BOOLEAN NotExistSameFfsIfr ( IN VOID *FfsImage ) { UINT32 Index; Index = 0; while (gEfiFdInfo.FfsArray[Index] != NULL) { if (memcmp (gEfiFdInfo.FfsArray[Index], FfsImage, sizeof (EFI_GUID)) == 0) { return FALSE; } Index++; } return TRUE; } /** This function returns the next larger size that meets the alignment requirement specified. @param ActualSize The size. @param Alignment The desired alignment. @retval The Occupied length **/ static UINT32 GetOccupiedSize ( IN UINT32 ActualSize, IN UINT32 Alignment ) { UINT32 OccupiedSize; OccupiedSize = ActualSize; while ((OccupiedSize & (Alignment - 1)) != 0) { OccupiedSize++; } return OccupiedSize; } /** Parses FFS Sections, and remove the FFS headers. Tis function olny handle one efi in this FFS. @param SectionBuffer The section base address @param BufferLength The length of FFS. @param EfiBufferHeader The structure dual pointer to the efi informations @retval EFI_SUCCESS The application exited normally. @retval EFI_ABORTED An error occurred. **/ EFI_STATUS ParseSection ( IN BOOLEAN IsFfsOrEfi, IN OUT UINT8 *SectionBuffer, IN UINT32 BufferLength, IN OUT EFI_SECTION_STRUCT **EfiBufferHeader ) { UINT32 ParsedLength; EFI_SECTION_TYPE Type; UINT8 *Ptr; UINT32 SectionLength; UINT8 *CompressedBuffer; UINT32 CompressedLength; UINT8 *UncompressedBuffer; UINT32 UncompressedLength; UINT8 CompressionType; DECOMPRESS_FUNCTION DecompressFunction; GETINFO_FUNCTION GetInfoFunction; UINT32 ScratchSize; UINT8 *ScratchBuffer; EFI_STATUS Status; UINT32 DstSize; CHAR8 *ExtractionTool; CHAR8 *ToolInputFile; CHAR8 *ToolOutputFile; CHAR8 *SystemCommandFormatString; CHAR8 *SystemCommand; UINT8 *ToolOutputBuffer; UINT32 ToolOutputLength; BOOLEAN HasDepexSection; Ptr = NULL; SectionLength = 0; CompressedBuffer = NULL; CompressedLength = 0; UncompressedBuffer = NULL; UncompressedLength = 0; CompressionType = 0; ScratchSize = 0; ScratchBuffer = NULL; Status = EFI_SUCCESS; DstSize = 0; ExtractionTool = NULL; ToolInputFile = NULL; ToolOutputFile = NULL; SystemCommandFormatString = NULL; SystemCommand = NULL; // // Jump the FFS header // if (IsFfsOrEfi) { SectionBuffer = SectionBuffer + sizeof (EFI_FFS_FILE_HEADER); BufferLength = BufferLength - sizeof (EFI_FFS_FILE_HEADER); } ParsedLength = 0; HasDepexSection = FALSE; ExtractionTool = NULL; ToolOutputLength = 0; ToolOutputBuffer = NULL; (*EfiBufferHeader)->Length = BufferLength; while (ParsedLength < BufferLength) { Ptr = SectionBuffer + ParsedLength; SectionLength = Get3ByteLength (((EFI_COMMON_SECTION_HEADER *) Ptr)->Size); Type = ((EFI_COMMON_SECTION_HEADER *) Ptr)->Type; // // This is sort of an odd check, but is necessary because FFS files are // padded to a QWORD boundary, meaning there is potentially a whole section // header worth of 0xFF bytes. // if ((SectionLength == 0xffffff) && (Type == 0xff)) { ParsedLength += 4; continue; } switch (Type) { case EFI_SECTION_PE32: case EFI_SECTION_TE: // //Got the correct address // (*EfiBufferHeader)->BufferBase = (UINTN)(Ptr + sizeof (EFI_COMMON_SECTION_HEADER)); return EFI_SUCCESS; case EFI_SECTION_RAW: case EFI_SECTION_PIC: break; case EFI_SECTION_USER_INTERFACE: HasDepexSection = FALSE; break; case EFI_SECTION_FIRMWARE_VOLUME_IMAGE: case EFI_SECTION_COMPATIBILITY16: case EFI_SECTION_FREEFORM_SUBTYPE_GUID: break; case EFI_SECTION_PEI_DEPEX: case EFI_SECTION_DXE_DEPEX: case EFI_SECTION_SMM_DEPEX: HasDepexSection = TRUE; break; case EFI_SECTION_VERSION: break; case EFI_SECTION_COMPRESSION: UncompressedBuffer = NULL; CompressedLength = SectionLength - sizeof (EFI_COMPRESSION_SECTION); UncompressedLength = ((EFI_COMPRESSION_SECTION *) Ptr)->UncompressedLength; CompressionType = ((EFI_COMPRESSION_SECTION *) Ptr)->CompressionType; if (CompressionType == EFI_NOT_COMPRESSED) { if (CompressedLength != UncompressedLength) { Error ( NULL, 0, 0, "file is not compressed, but the compressed length does not match the uncompressed length", NULL ); return EFI_ABORTED; } UncompressedBuffer = Ptr + sizeof (EFI_COMPRESSION_SECTION); } else if (CompressionType == EFI_STANDARD_COMPRESSION) { GetInfoFunction = EfiGetInfo; DecompressFunction = EfiDecompress; CompressedBuffer = Ptr + sizeof (EFI_COMPRESSION_SECTION); Status = GetInfoFunction ( CompressedBuffer, CompressedLength, &DstSize, &ScratchSize ); if (EFI_ERROR (Status)) { Error (NULL, 0, 0003, "error getting compression info from compression section", NULL); return EFI_ABORTED; } if (DstSize != UncompressedLength) { Error (NULL, 0, 0003, "compression error in the compression section", NULL); return EFI_ABORTED; } ScratchBuffer = malloc (ScratchSize); if (ScratchBuffer == NULL) { return EFI_ABORTED; } UncompressedBuffer = malloc (UncompressedLength); if (UncompressedBuffer == NULL) { free (ScratchBuffer); return EFI_ABORTED; } memset (UncompressedBuffer, 0, UncompressedLength); Status = DecompressFunction ( CompressedBuffer, CompressedLength, UncompressedBuffer, UncompressedLength, ScratchBuffer, ScratchSize ); free (ScratchBuffer); if (Status != EFI_SUCCESS) { Error (NULL, 0, 0003, "decompress failed", NULL); free (UncompressedBuffer); return EFI_ABORTED; } } else { Error (NULL, 0, 0003, "unrecognized compression type", "type 0x%X", CompressionType); return EFI_ABORTED; } Status = ParseSection (FALSE, UncompressedBuffer, UncompressedLength, EfiBufferHeader); if (Status != EFI_SUCCESS) { Error (NULL, 0, 0003, "failed to parse section", NULL); free (UncompressedBuffer); UncompressedBuffer = NULL; } else { return EFI_SUCCESS; } // // Store the allocate memory address for UncompressedBuffer // if (UncompressedBuffer != NULL) { (*EfiBufferHeader)->UncompressedBuffer[(*EfiBufferHeader)->UnCompressIndex] = (UINTN) UncompressedBuffer; (*EfiBufferHeader)->UnCompressIndex = (*EfiBufferHeader)->UnCompressIndex + 1; } break; case EFI_SECTION_GUID_DEFINED: // // Decompress failed, and then check for CRC32 sections which we can handle internally if needed. // Maybe this section is no-compressed. // if (!CompareGuid ( &((EFI_GUID_DEFINED_SECTION *) Ptr)->SectionDefinitionGuid, &gEfiCrc32GuidedSectionExtractionProtocolGuid )) { // // CRC32 guided section // Status = ParseSection ( FALSE, SectionBuffer + ((EFI_GUID_DEFINED_SECTION *) Ptr)->DataOffset, BufferLength - ((EFI_GUID_DEFINED_SECTION *) Ptr)->DataOffset, EfiBufferHeader ); if (EFI_ERROR (Status)) { Error (NULL, 0, 0003, "parse of CRC32 GUIDED section failed", NULL); return EFI_ABORTED; } else { return EFI_SUCCESS; } } else { ExtractionTool = LookupGuidedSectionToolPath ( mParsedGuidedSectionTools, &((EFI_GUID_DEFINED_SECTION *) Ptr)->SectionDefinitionGuid ); if (ExtractionTool != NULL) { ToolInputFile = GenTempFile (); ToolOutputFile = GenTempFile (); // // Construction 'system' command string // SystemCommandFormatString = "%s -d -o \"%s\" \"%s\""; SystemCommand = malloc ( strlen (SystemCommandFormatString) \ + strlen (ExtractionTool) \ + strlen (ToolInputFile) \ + strlen (ToolOutputFile) \ + 1 ); if (SystemCommand == NULL) { free (ExtractionTool); free (ToolInputFile); free (ToolOutputFile); return EFI_ABORTED; } sprintf ( SystemCommand, "%s -d -o \"%s\" \"%s\"", ExtractionTool, ToolOutputFile, ToolInputFile ); free (ExtractionTool); Status = PutFileImage ( ToolInputFile, (CHAR8*) Ptr + ((EFI_GUID_DEFINED_SECTION *) Ptr)->DataOffset, SectionLength - ((EFI_GUID_DEFINED_SECTION *) Ptr)->DataOffset ); if (HasDepexSection) { HasDepexSection = FALSE; } system (SystemCommand); remove (ToolInputFile); free (ToolInputFile); ToolInputFile = NULL; free (SystemCommand); SystemCommand = NULL; if (EFI_ERROR (Status)) { Error ("FCE", 0, 0004, "unable to decoded GUIDED section", NULL); free (ToolOutputFile); return EFI_ABORTED; } Status = GetFileImage ( ToolOutputFile, (CHAR8 **)&ToolOutputBuffer, &ToolOutputLength ); remove (ToolOutputFile); free (ToolOutputFile); ToolOutputFile = NULL; if (EFI_ERROR (Status)) { return EFI_ABORTED; } } Status = ParseSection ( FALSE, ToolOutputBuffer, ToolOutputLength, EfiBufferHeader ); if (EFI_ERROR (Status)) { Error (NULL, 0, 0003, "parse of decoded GUIDED section failed", NULL); return EFI_ABORTED; } } break; default: ; } ParsedLength += SectionLength; // // We make then next section begin on a 4-byte boundary // ParsedLength = GetOccupiedSize (ParsedLength, 4); } return EFI_ABORTED; } static BOOLEAN GetNextOffset ( IN UINT8 *Data, IN EFI_GUID *Guid, IN UINTN Len, IN OUT UINTN *Offset ) { UINTN NextOffset; if (*Offset >= Len || Len - *Offset <= sizeof (EFI_GUID)) { return FALSE; } for (NextOffset = *Offset; NextOffset < Len - sizeof (EFI_GUID); NextOffset++) { if (CompareGuid(Guid, (EFI_GUID*)(Data + NextOffset)) == 0) { *Offset = NextOffset + sizeof(EFI_GUID); return TRUE; } } return FALSE; } /** Get the address by Guid. Parse the FFS image, and find the GUID address.There may be some Guids matching the searched Guid. @param Fv the Pointer to the image. @param Guid The Guid need to find. @param Offset The dual Pointer to the offset. @param NumOfMatchGuid The number of matching Guid offset. @retval EFI_SUCCESS The Search was complete successfully @return EFI_ABORTED An error occurred **/ EFI_STATUS GetAddressByGuid ( IN VOID *Fv, IN EFI_GUID *Guid, IN UINTN Len, OUT UINTN **Offset, OUT UINT8 *NumOfMatchGuid ) { VOID *LocalFv; UINT8 Flag; EFI_RAW_SECTION* Section; UINT8 *RawData; VOID* SectionStart; UINTN NextOffset; UINTN Key; UINTN TotalSectionsSize; UINTN SecLen; UINTN SecHdr; EFI_STATUS Status; if( (Fv == NULL) || (Fv == NULL) || (Guid == NULL) || Len == 0 ){ return EFI_ABORTED; } LocalFv = Fv; Flag = 0; Section = NULL; Key = 0; if (NumOfMatchGuid != NULL) { *NumOfMatchGuid = 0; } SectionStart = (VOID*)((UINTN)LocalFv + FvBufGetFfsHeaderSize(LocalFv)); TotalSectionsSize = Len - FvBufGetFfsHeaderSize(LocalFv); while (TRUE) { Status = FvBufFindNextSection ( SectionStart, TotalSectionsSize, &Key, (VOID **)&Section ); if (Section == NULL || EFI_ERROR (Status)) { break; } if (EFI_SECTION_RAW == Section->Type) { if ((*(UINT32 *)Section->Size & 0xffffff) == 0xffffff) { SecLen = ((EFI_RAW_SECTION2 *)Section)->ExtendedSize; SecHdr = sizeof(EFI_RAW_SECTION2); } else { SecLen = *(UINT32 *)Section->Size & 0xffffff; SecHdr = sizeof(EFI_RAW_SECTION); } if (SecLen <= SecHdr || SecLen - SecHdr < sizeof(EFI_GUID)) { continue; } RawData = (UINT8 *)Section + SecHdr; NextOffset = 0; while (GetNextOffset(RawData, Guid, SecLen - SecHdr, &NextOffset)) { Flag = 1; if ((NumOfMatchGuid != NULL) && (Offset != NULL)) { if (*NumOfMatchGuid == 0) { *Offset = malloc (sizeof (UINTN) * MAX_MATCH_GUID_NUM); if (*Offset == NULL) { return EFI_ABORTED; } memset (*Offset, 0, sizeof (UINTN) * MAX_MATCH_GUID_NUM); } *(*Offset + *NumOfMatchGuid) = NextOffset + (RawData - (UINT8 *)Fv); (*NumOfMatchGuid)++; } else { return EFI_SUCCESS; } } } } if( Flag == 0 ) { return EFI_ABORTED; } return EFI_SUCCESS; } /** Search the VfrBin Base address. According the known GUID gVfrArrayAttractGuid to get the base address from FFS. @param Fv the Pointer to the FFS @param EfiAddr the Pointer to the EFI in FFS @param Length the length of Fv @param Offset the Pointer to the Addr (Offset) @param NumOfMachingOffset the number of Addr (Offset) @retval EFI_SUCCESS Get the address successfully. **/ EFI_STATUS SearchVfrBinInFFS ( IN VOID *Fv, IN VOID *EfiAddr, IN UINTN Length, OUT UINTN **Offset, OUT UINT8 *NumOfMachingOffset ) { UINTN Index; EFI_STATUS Status; UINTN VirOffValue; Index = 0; Status = EFI_SUCCESS; VirOffValue = 0; if ((Fv == NULL) || (Offset == NULL)) { return EFI_ABORTED; } Status = GetAddressByGuid ( Fv, &gVfrArrayAttractGuid, Length, Offset, NumOfMachingOffset ); if (Status != EFI_SUCCESS) { return EFI_ABORTED; } while (Index < *NumOfMachingOffset) { // // Got the virOffset after the GUID // VirOffValue = *(UINTN *)((UINTN)Fv + *(*Offset + Index)); // //Transfer the offset to the VA address. One modules may own more VfrBin address. // *(*Offset + Index) = (UINTN) EfiAddr + VirOffValue; Index++; } return EFI_SUCCESS; } /** Search the UniBin Base address. According the known GUID gUniStrArrayAttractGuid to get the base address from FFS. @param Fv the Pointer to the FFS @param EfiAddr the Pointer to the EFI in FFS @param Length the length of Fv @param Offset the Pointer to the Addr (Offset) @retval Base address Get the address successfully. **/ EFI_STATUS SearchUniBinInFFS ( IN VOID *Fv, IN VOID *EfiAddr, IN UINTN Length, OUT UINTN **Offset ) { UINT8 NumOfMachingOffset; EFI_STATUS Status; UINTN VirOffValue; NumOfMachingOffset = 0; Status = EFI_SUCCESS; VirOffValue = 0; if ((Fv == NULL) || (Offset == NULL)) { return EFI_ABORTED; } Status = GetAddressByGuid ( Fv, &gUniStrArrayAttractGuid, Length, Offset, &NumOfMachingOffset ); if (Status != EFI_SUCCESS) { return EFI_ABORTED; } // //Transfer the offset to the VA address. There is only one UniArray in one modules. // if (NumOfMachingOffset == 1) { VirOffValue = *(UINTN *)((UINTN)Fv + **Offset); **Offset = (UINTN) EfiAddr + VirOffValue; } else { printf ("Error. Find more than 1 UniBin in FFS.\n"); return EFI_ABORTED; } return EFI_SUCCESS; } EFI_STATUS SearchNvStoreDatabaseInFd( IN VOID *Fv, IN UINTN length ) { EFI_STATUS Status; UINTN Offset; PCD_NV_STORE_DEFAULT_BUFFER_HEADER *NvStoreHeader; Status = EFI_SUCCESS; Offset = 0; if (Fv == NULL) { printf ("The FV is NULL."); return EFI_ABORTED; } while (Offset < (length - sizeof(PCD_NV_STORE_DEFAULT_BUFFER_HEADER))){ NvStoreHeader = (PCD_NV_STORE_DEFAULT_BUFFER_HEADER *)((UINT8*)Fv + Offset); if (NvStoreHeader->Signature == PCD_NV_STORE_DEFAULT_BUFFER_SIGNATURE) { gEfiFdInfo.ExistNvStoreDatabase = TRUE; gEfiFdInfo.NvStoreDatabase = (UINT8 *) NvStoreHeader; break; } Offset++; } if (Offset == (length - sizeof(PCD_NV_STORE_DEFAULT_BUFFER_HEADER)) || gEfiFdInfo.ExistNvStoreDatabase != TRUE) { //printf ("Not found the PcdNvStoreDefaultValueBuffer\n"); return Status; } return Status; } /** Get the address by Guid. Parse the FD image, and find the GUID address.There may be some Guids matching the searched Guid. @param Fv the Pointer to the image. @param Guid The Guid need to find. @param Offset The dual Pointer to the offset. @param NumOfMatchGuid The number of matching Guid offset. @retval EFI_SUCCESS The Search was complete successfully @return EFI_ABORTED An error occurred **/ EFI_STATUS GetVariableAddressByGuid ( IN VOID *Fv, IN EFI_GUID *Guid, IN UINTN Len, OUT UINTN **Offset, OUT UINT8 *NumOfMatchGuid ) { UINTN NextOffset; UINT8 Flag; if( (Fv == NULL) || (Fv == NULL) || (Guid == NULL) ){ return EFI_ABORTED; } Flag = 0; NextOffset = 0; if (NumOfMatchGuid != NULL) { *NumOfMatchGuid = 0; } while (GetNextOffset(Fv, Guid, Len, &NextOffset)) { Flag = 1; if (NumOfMatchGuid != NULL && Offset != NULL) { if (*NumOfMatchGuid == 0) { *Offset = malloc (sizeof (UINTN) * MAX_MATCH_GUID_NUM); if (*Offset == NULL) { return EFI_ABORTED; } memset (*Offset, 0, sizeof (UINTN) * MAX_MATCH_GUID_NUM); } *(*Offset + *NumOfMatchGuid) = NextOffset; (*NumOfMatchGuid)++; } else { return EFI_SUCCESS; } } if( Flag == 0 ) { return EFI_ABORTED; } return EFI_SUCCESS; } /** Search the EFI Variable Base address. According the known GUID gEfiSystemNvDataFvGuid to get the base address from FFS. @param Fv the Pointer to the FFS @param Length the length of Fv @param Offset the Pointer to the Addr (Offset) @param NumOfMachingOffset the number of IFR array in one FFS @retval EFI_SUCCESS Get the address successfully. @retval EFI_ABORTED An error occured. **/ EFI_STATUS SearchEfiVarInFFS ( IN VOID *Fv, IN UINTN Length, OUT UINTN **Offset, OUT UINT8 *NumOfMachingOffset ) { EFI_STATUS Status; UINT8 Index; Status = EFI_SUCCESS; Index = 0; if ((Fv == NULL) || (Offset == NULL)) { printf ("The FV or offset is NULL."); return EFI_ABORTED; } Status = GetVariableAddressByGuid ( Fv, &gEfiSystemNvDataFvGuid, Length, Offset, NumOfMachingOffset ); if (Status != EFI_SUCCESS) { return EFI_ABORTED; } // //Transfer the offset to the VA address. // while (Index < *NumOfMachingOffset) { *(*Offset + Index) = (UINTN) Fv + *(*Offset + Index); Index++; } return EFI_SUCCESS; } /** Parse the Ffs header to get the size. @param InputFile The pointer to the input file @param FvSize The pointer to the file size @return EFI_SUCCESS Get the file size successfully **/ EFI_STATUS ReadFfsHeader ( IN FILE *InputFile, OUT UINT32 *FvSize ) { EFI_FFS_FILE_HEADER FfsHeader; EFI_FV_FILETYPE Type; // // Check input parameters // if ((InputFile == NULL) || (FvSize == NULL)) { return EFI_ABORTED; } // // Read the header // fread ( &FfsHeader, sizeof (EFI_FFS_FILE_HEADER), 1, InputFile ); Type = FfsHeader.Type; if (Type == EFI_FV_FILETYPE_DRIVER) { *FvSize = *(UINT32 *)FfsHeader.Size & 0xffffff; } else if (Type == EFI_FV_FILETYPE_APPLICATION) { *FvSize = *(UINT32 *)FfsHeader.Size & 0xffffff; } else if (Type == EFI_FV_FILETYPE_FREEFORM) { *FvSize = *(UINT32 *)FfsHeader.Size & 0xffffff; } else { return EFI_ABORTED; } return EFI_SUCCESS; } /* Read the length of the whole FD This function determines the size of the FV. @param InputFile The file that contains the FV image. @param FvSize The size of the FV. @retval EFI_SUCCESS The application exited normally. @retval EFI_ABORTED An error occurred. **/ static EFI_STATUS ReadFdHeader ( IN FILE *InputFile, OUT UINT32 *FvSize ) { // // Check input parameters // if ((InputFile == NULL) || (FvSize == NULL)) { return EFI_ABORTED; } *FvSize = 0; // // Get the total size of FD file (Fixed the length) // fseek(InputFile,0,SEEK_END); *FvSize = ftell(InputFile); fseek(InputFile,0,SEEK_SET); if (*FvSize == 0) { return EFI_ABORTED; } return EFI_SUCCESS; } /** Read the file to memory. @param InputFile The file that contains the FV image. @param Size The size of the file. @retval The pointer to the begining position of memory. **/ VOID * ReadFileToMemory ( IN CHAR8 *FileName, OUT UINT32 *Size ) { FILE *InFile; VOID *Address; UINT32 BytesRead; EFI_STATUS Status; InFile = NULL; Address = NULL; BytesRead = 0; Status = EFI_SUCCESS; InFile = fopen (FileName,"rb"); if (InFile == NULL) { return NULL; } // // Determine the size of FV // Status = ReadFdHeader (InFile, Size); if (Status != EFI_SUCCESS) { fclose (InFile); return NULL; } // // Allocate a buffer for the FV image // Address = malloc (*Size); if (Address == NULL) { fclose (InFile); return NULL; } memset (Address, 0, *Size); // // Seek to the start of the image, then read the entire FV to the buffer // fseek (InFile, 0, SEEK_SET); BytesRead = fread (Address, 1, *Size, InFile); fclose (InFile); if ((UINTN) BytesRead != *Size) { free (Address); return NULL; } return Address; } /** Search the EFI variables address in Fd. Open and read the *.fd to the memory, initialize the global structure. Update the EFI variables addr and the begining position of memory. @retval EFI_SUCCESS Get the address successfully. **/ EFI_STATUS GetEfiVariablesAddr ( BOOLEAN UqiIsSet ) { VOID *FdImage; UINT32 FdSize; EFI_STATUS Status; UINTN *EfiVarAddr; UINT8 NumOfMachingVar; UINT32 Index; BOOLEAN GotFlag; EFI_FIRMWARE_VOLUME_HEADER *Variable; BOOLEAN AuthencitatedMonotonicOrNot; BOOLEAN AuthencitatedBasedTimeOrNot; BOOLEAN NormalOrNot; FdImage = NULL; FdSize = 0; Status = EFI_SUCCESS; EfiVarAddr = NULL; NumOfMachingVar = 0; Index = 0; GotFlag = TRUE; Variable = NULL; FdImage = ReadFileToMemory (mInputFdName, &FdSize); if (FdImage == NULL) { return EFI_ABORTED; } if (!UqiIsSet) { Status = SearchNvStoreDatabaseInFd(FdImage, FdSize); if (EFI_ERROR (Status)) { return EFI_ABORTED; } } Status = SearchEfiVarInFFS ( FdImage, FdSize, &EfiVarAddr, &NumOfMachingVar ); if (EFI_ERROR (Status)) { return EFI_ABORTED; } // // Check the signature "_FVH" // Index = 0; GotFlag = FALSE; while (Index < NumOfMachingVar) { Variable = (EFI_FIRMWARE_VOLUME_HEADER *)(*(EfiVarAddr + Index) - 0x20); if (Variable->Signature == 0x4856465F) { AuthencitatedMonotonicOrNot = CheckMonotonicBasedVarStore ((UINT8 *)Variable + Variable->HeaderLength); AuthencitatedBasedTimeOrNot = CheckTimeBasedVarStoreOrNot ((UINT8 *)Variable + Variable->HeaderLength); NormalOrNot = CheckNormalVarStoreOrNot ((UINT8 *)Variable + Variable->HeaderLength); if (AuthencitatedMonotonicOrNot || AuthencitatedBasedTimeOrNot || NormalOrNot) { GotFlag = TRUE; gEfiFdInfo.EfiVariableAddr = (UINTN)Variable; break; } } Index++; } free (EfiVarAddr); if (!GotFlag) { return EFI_ABORTED; } gEfiFdInfo.Fd = FdImage; gEfiFdInfo.FdSize = FdSize; return EFI_SUCCESS; } /** Pick up the FFS which includes IFR section. Parse all FFS extracted by BfmLib, and save all which includes IFR Binary to gEfiFdInfo structure. @retval EFI_SUCCESS Get the address successfully. @retval EFI_BUFFER_TOO_SMALL Memory can't be allocated. @retval EFI_ABORTED Read FFS Failed. **/ EFI_STATUS FindFileInFolder ( IN CHAR8 *FolderName, OUT BOOLEAN *ExistStorageInBfv, OUT BOOLEAN *SizeOptimized ) { CHAR8 *FileName; CHAR8 *CurFolderName; EFI_STATUS Status; UINTN MaxFileNameLen; UINTN Index; CHAR8 FileNameArry[MAX_FILENAME_LEN]; FILE *FfsFile; UINTN FileSize; VOID *FfsImage; UINTN BytesRead; #ifndef __GNUC__ HANDLE FindHandle; WIN32_FIND_DATA FindFileData; #else struct dirent *pDirent; DIR *pDir; #endif FileName = NULL; CurFolderName = NULL; Status = EFI_SUCCESS; MaxFileNameLen = 0; Index = 0; FileSize = 0; BytesRead = 0; FfsImage = NULL; FfsFile = NULL; MaxFileNameLen = strlen (FolderName) + MAX_FILENAME_LEN; CurFolderName = (CHAR8 *)calloc( strlen (FolderName) + strlen (OS_SEP_STR) + strlen ("*.*")+ 1, sizeof(CHAR8) ); if (CurFolderName == NULL) { return EFI_BUFFER_TOO_SMALL; } strcpy (CurFolderName, FolderName); strcat (CurFolderName, OS_SEP_STR); strcat (CurFolderName, "*.*"); FileName = (CHAR8 *)calloc( MaxFileNameLen, sizeof(CHAR8) ); if (FileName == NULL) { free (CurFolderName); return EFI_BUFFER_TOO_SMALL; } #ifndef __GNUC__ if((FindHandle = FindFirstFile(CurFolderName, &FindFileData)) != INVALID_HANDLE_VALUE){ do { memset (FileName, 0, MaxFileNameLen); if ((strcmp (FindFileData.cFileName, ".") == 0) || (strcmp (FindFileData.cFileName, "..") == 0) ) { continue; } if (strlen(FolderName) + strlen ("\\") + strlen (FindFileData.cFileName) > MAX_FILENAME_LEN - 1) { Status = EFI_ABORTED; goto Done; } snprintf (FileNameArry, MAX_FILENAME_LEN, "%s%c%s", FolderName, OS_SEP, FindFileData.cFileName); FfsFile = fopen (FileNameArry, "rb"); if (FfsFile == NULL) { Status = EFI_ABORTED; goto Done; } Status = ReadFfsHeader (FfsFile, (UINT32 *)&FileSize); if (EFI_ERROR (Status)) { fclose (FfsFile); Status = EFI_SUCCESS; continue; } // // Allocate a buffer for the FFS file // FfsImage = malloc (FileSize); if (FfsImage == NULL) { fclose (FfsFile); Status = EFI_BUFFER_TOO_SMALL; goto Done; } // // Seek to the start of the image, then read the entire FV to the buffer // fseek (FfsFile, 0, SEEK_SET); BytesRead = fread (FfsImage, 1, FileSize, FfsFile); fclose (FfsFile); if ((UINTN) BytesRead != FileSize) { free (FfsImage); Status = EFI_ABORTED; goto Done; } // // Check whether exists the storage ffs in BFV for multi-platform mode // if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid,(EFI_GUID *) FfsImage) == 0) { *ExistStorageInBfv = TRUE; *SizeOptimized = FALSE; gEfiFdInfo.StorageFfsInBfv = FfsImage; continue; } // // Check whether exists the optimized storage ffs in BFV for multi-platform mode // if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid2,(EFI_GUID *) FfsImage) == 0) { *ExistStorageInBfv = TRUE; *SizeOptimized = TRUE; gEfiFdInfo.StorageFfsInBfv = FfsImage; continue; } // // Check whether current FFS includes IFR // Status = GetAddressByGuid ( FfsImage, &gVfrArrayAttractGuid, FileSize, NULL, NULL ); if (EFI_ERROR (Status)) { free (FfsImage); Status = EFI_SUCCESS; } else { // // Check whether existed same IFR binary. If existed, not insert the new one. // if (NotExistSameFfsIfr (FfsImage)) { gEfiFdInfo.FfsArray[Index] = FfsImage; gEfiFdInfo.Length[Index++] = FileSize; } } } while (FindNextFile (FindHandle, &FindFileData)); FindClose(FindHandle); } else { Status = EFI_ABORTED; goto Done; } Done: free (CurFolderName); free (FileName); #else if((pDir = opendir(FolderName)) != NULL){ while ((pDirent = readdir(pDir)) != NULL){ memset (FileName, 0, MaxFileNameLen); if ((strcmp (pDirent->d_name, ".") == 0) || (strcmp (pDirent->d_name, "..") == 0) ) { continue; } sprintf (FileNameArry, "%s%c%s", FolderName, OS_SEP, pDirent->d_name); FfsFile = fopen (FileNameArry, "rb"); Status = ReadFfsHeader (FfsFile, (UINT32 *)&FileSize); if (EFI_ERROR (Status)) { fclose (FfsFile); Status = EFI_SUCCESS; continue; } // // Allocate a buffer for the FFS file // FfsImage = malloc (FileSize); if (FfsImage == NULL) { fclose (FfsFile); Status = EFI_BUFFER_TOO_SMALL; goto Done; } // // Seek to the start of the image, then read the entire FV to the buffer // fseek (FfsFile, 0, SEEK_SET); BytesRead = fread (FfsImage, 1, FileSize, FfsFile); fclose (FfsFile); if ((UINTN) BytesRead != FileSize) { free (FfsImage); Status = EFI_ABORTED; goto Done; } // // Check whether exists the storage ffs in BFV for multi-platform mode // if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid,(EFI_GUID *) FfsImage) == 0) { *ExistStorageInBfv = TRUE; *SizeOptimized = FALSE; gEfiFdInfo.StorageFfsInBfv = FfsImage; continue; } // // Check whether exists the optimized storage ffs in BFV for multi-platform mode // if (CompareGuid(&gEfiFfsBfvForMultiPlatformGuid2,(EFI_GUID *) FfsImage) == 0) { *ExistStorageInBfv = TRUE; *SizeOptimized = TRUE; gEfiFdInfo.StorageFfsInBfv = FfsImage; continue; } // // Check whether current FFS includes IFR // Status = GetAddressByGuid ( FfsImage, &gVfrArrayAttractGuid, FileSize, NULL, NULL ); if (EFI_ERROR (Status)) { free (FfsImage); Status = EFI_SUCCESS; } else { // // Check whether existed same IFR binary. If existed, not insert the new one. // if (NotExistSameFfsIfr (FfsImage)) { gEfiFdInfo.FfsArray[Index] = FfsImage; gEfiFdInfo.Length[Index++] = FileSize; } } } closedir(pDir); } else { Status = EFI_ABORTED; goto Done; } Done: free (CurFolderName); free (FileName); #endif return Status; }