/** @file The tool dumps the contents of a firmware volume Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.
Copyright (c) 2022, Konstantin Aladyshev
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #ifdef __GNUC__ #include #else #include #endif #include #include #include #include #include #include #include #include #include "Compress.h" #include "Decompress.h" #include "VolInfo.h" #include "CommonLib.h" #include "EfiUtilityMsgs.h" #include "FirmwareVolumeBufferLib.h" #include "OsPath.h" #include "ParseGuidedSectionTools.h" #include "StringFuncs.h" #include "ParseInf.h" #include "PeCoffLib.h" // // Utility global variables // EFI_GUID gEfiCrc32GuidedSectionExtractionProtocolGuid = EFI_CRC32_GUIDED_SECTION_EXTRACTION_PROTOCOL_GUID; EFI_GUID gPeiAprioriFileNameGuid = { 0x1b45cc0a, 0x156a, 0x428a, { 0XAF, 0x62, 0x49, 0x86, 0x4d, 0xa0, 0xe6, 0xe6 }}; EFI_GUID gAprioriGuid = { 0xFC510EE7, 0xFFDC, 0x11D4, { 0xBD, 0x41, 0x00, 0x80, 0xC7, 0x3C, 0x88, 0x81 }}; #define UTILITY_MAJOR_VERSION 1 #define UTILITY_MINOR_VERSION 0 #define UTILITY_NAME "VolInfo" #define EFI_SECTION_ERROR EFIERR (100) // // Structure to keep a list of guid-to-basenames // typedef struct _GUID_TO_BASENAME { struct _GUID_TO_BASENAME *Next; INT8 Guid[PRINTED_GUID_BUFFER_SIZE]; INT8 BaseName[MAX_LINE_LEN]; } GUID_TO_BASENAME; static GUID_TO_BASENAME *mGuidBaseNameList = NULL; // // Store GUIDed Section guid->tool mapping // EFI_HANDLE mParsedGuidedSectionTools = NULL; CHAR8* mUtilityFilename = NULL; BOOLEAN EnableHash = FALSE; CHAR8 *OpenSslPath = NULL; EFI_STATUS ParseGuidBaseNameFile ( CHAR8 *FileName ); EFI_STATUS FreeGuidBaseNameList ( VOID ); EFI_STATUS PrintGuidName ( IN UINT8 *GuidStr ); EFI_STATUS ParseSection ( IN UINT8 *SectionBuffer, IN UINT32 BufferLength ); EFI_STATUS DumpDepexSection ( IN UINT8 *Ptr, IN UINT32 SectionLength ); STATIC EFI_STATUS ReadHeader ( IN FILE *InputFile, OUT UINT32 *FvSize, OUT BOOLEAN *ErasePolarity ); STATIC EFI_STATUS PrintAprioriFile ( EFI_FFS_FILE_HEADER *FileHeader ); STATIC EFI_STATUS PrintFileInfo ( EFI_FIRMWARE_VOLUME_HEADER *FvImage, EFI_FFS_FILE_HEADER *FileHeader, BOOLEAN ErasePolarity ); static EFI_STATUS PrintFvInfo ( IN VOID *Fv, IN BOOLEAN IsChildFv ); static VOID LoadGuidedSectionToolsTxt ( IN CHAR8* FirmwareVolumeFilename ); EFI_STATUS CombinePath ( IN CHAR8* DefaultPath, IN CHAR8* AppendPath, OUT CHAR8* NewPath ); void Usage ( VOID ); UINT32 UnicodeStrLen ( IN CHAR16 *String ) /*++ Routine Description: Returns the length of a null-terminated unicode string. Arguments: String - The pointer to a null-terminated unicode string. Returns: N/A --*/ { UINT32 Length; for (Length = 0; *String != L'\0'; String++, Length++) { ; } return Length; } VOID Unicode2AsciiString ( IN CHAR16 *Source, OUT CHAR8 *Destination ) /*++ Routine Description: Convert a null-terminated unicode string to a null-terminated ascii string. Arguments: Source - The pointer to the null-terminated input unicode string. Destination - The pointer to the null-terminated output ascii string. Returns: N/A --*/ { while (*Source != '\0') { *(Destination++) = (CHAR8) *(Source++); } // // End the ascii with a NULL. // *Destination = '\0'; } int main ( int argc, char *argv[] ) /*++ Routine Description: GC_TODO: Add function description Arguments: argc - GC_TODO: add argument description ] - GC_TODO: add argument description Returns: GC_TODO: add return values --*/ { FILE *InputFile; int BytesRead; EFI_FIRMWARE_VOLUME_HEADER *FvImage; UINT32 FvSize; EFI_STATUS Status; int Offset; BOOLEAN ErasePolarity; UINT64 LogLevel; CHAR8 *OpenSslEnv; CHAR8 *OpenSslCommand; SetUtilityName (UTILITY_NAME); // // Print utility header // printf ("%s Version %d.%d Build %s\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION ); if (argc == 1) { Usage (); return -1; } argc--; argv++; LogLevel = 0; Offset = 0; // // Look for help options // if ((strcmp(argv[0], "-h") == 0) || (strcmp(argv[0], "--help") == 0) || (strcmp(argv[0], "-?") == 0) || (strcmp(argv[0], "/?") == 0)) { Usage(); return STATUS_SUCCESS; } // // Version has already be printed, so just return success // if (strcmp(argv[0], "--version") == 0) { return STATUS_SUCCESS; } // // If they specified -x xref guid/basename cross-reference files, process it. // This will print the basename beside each file guid. To use it, specify // -x xref_filename to processdsc, then use xref_filename as a parameter // here. // while (argc > 0) { if ((strcmp(argv[0], "-x") == 0) || (strcmp(argv[0], "--xref") == 0)) { ParseGuidBaseNameFile (argv[1]); printf("ParseGuidBaseNameFile: %s\n", argv[1]); argc -= 2; argv += 2; continue; } if (strcmp(argv[0], "--offset") == 0) { // // Hex or decimal? // if ((argv[1][0] == '0') && (tolower ((int)argv[1][1]) == 'x')) { if (sscanf (argv[1], "%x", &Offset) != 1) { Error (NULL, 0, 1003, "Invalid option value", "Offset = %s", argv[1]); return GetUtilityStatus (); } } else { if (sscanf (argv[1], "%d", &Offset) != 1) { Error (NULL, 0, 1003, "Invalid option value", "Offset = %s", argv[1]); return GetUtilityStatus (); } // // See if they said something like "64K" // if (tolower ((int)argv[1][strlen (argv[1]) - 1]) == 'k') { Offset *= 1024; } } argc -= 2; argv += 2; continue; } if ((stricmp (argv[0], "--hash") == 0)) { if (EnableHash == TRUE) { // // --hash already given in the option, ignore this one // argc --; argv ++; continue; } EnableHash = TRUE; OpenSslCommand = "openssl"; OpenSslEnv = getenv("OPENSSL_PATH"); if (OpenSslEnv == NULL) { OpenSslPath = OpenSslCommand; } else { // // We add quotes to the Openssl Path in case it has space characters // OpenSslPath = malloc(2+strlen(OpenSslEnv)+strlen(OpenSslCommand)+1); if (OpenSslPath == NULL) { Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); return GetUtilityStatus (); } CombinePath(OpenSslEnv, OpenSslCommand, OpenSslPath); } if (OpenSslPath == NULL){ Error (NULL, 0, 3000, "Open SSL command not available. Please verify PATH or set OPENSSL_PATH.", NULL); return GetUtilityStatus (); } argc --; argv ++; continue; } if ((stricmp (argv[0], "-v") == 0) || (stricmp (argv[0], "--verbose") == 0)) { SetPrintLevel (VERBOSE_LOG_LEVEL); argc --; argv ++; continue; } if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) { SetPrintLevel (KEY_LOG_LEVEL); argc --; argv ++; continue; } if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) { Status = AsciiStringToUint64 (argv[1], FALSE, &LogLevel); if (EFI_ERROR (Status)) { Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]); return -1; } if (LogLevel > 9) { Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, current input level is %d", (int) LogLevel); return -1; } SetPrintLevel (LogLevel); DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[1]); argc -= 2; argv += 2; continue; } mUtilityFilename = argv[0]; argc --; argv ++; } // // Open the file containing the FV // if (mUtilityFilename == NULL) { Error (NULL, 0, 1001, "Missing option", "Input files are not specified"); return GetUtilityStatus (); } InputFile = fopen (LongFilePath (mUtilityFilename), "rb"); if (InputFile == NULL) { Error (NULL, 0, 0001, "Error opening the input file", mUtilityFilename); return GetUtilityStatus (); } // // Skip over pad bytes if specified. This is used if they prepend 0xff // data to the FV image binary. // if (Offset != 0) { fseek (InputFile, Offset, SEEK_SET); } // // Determine size of FV // Status = ReadHeader (InputFile, &FvSize, &ErasePolarity); if (EFI_ERROR (Status)) { Error (NULL, 0, 0003, "error parsing FV image", "%s Header is invalid", mUtilityFilename); fclose (InputFile); return GetUtilityStatus (); } // // Allocate a buffer for the FV image // FvImage = malloc (FvSize); if (FvImage == NULL) { Error (NULL, 0, 4001, "Resource: Memory can't be allocated", NULL); fclose (InputFile); return GetUtilityStatus (); } // // Seek to the start of the image, then read the entire FV to the buffer // fseek (InputFile, Offset, SEEK_SET); BytesRead = fread (FvImage, 1, FvSize, InputFile); fclose (InputFile); if ((unsigned int) BytesRead != FvSize) { Error (NULL, 0, 0004, "error reading FvImage from", mUtilityFilename); free (FvImage); return GetUtilityStatus (); } LoadGuidedSectionToolsTxt (mUtilityFilename); PrintFvInfo (FvImage, FALSE); // // Clean up // free (FvImage); FreeGuidBaseNameList (); return GetUtilityStatus (); } static EFI_STATUS PrintFvInfo ( IN VOID *Fv, IN BOOLEAN IsChildFv ) /*++ Routine Description: GC_TODO: Add function description Arguments: Fv - Firmware Volume to print information about IsChildFv - Flag specifies whether the input FV is a child FV. Returns: EFI_STATUS --*/ { EFI_STATUS Status; UINTN NumberOfFiles; BOOLEAN ErasePolarity; UINTN FvSize; EFI_FFS_FILE_HEADER *CurrentFile; UINTN Key; Status = FvBufGetSize (Fv, &FvSize); NumberOfFiles = 0; ErasePolarity = (((EFI_FIRMWARE_VOLUME_HEADER*)Fv)->Attributes & EFI_FVB2_ERASE_POLARITY) ? TRUE : FALSE; // // Get the first file // Key = 0; Status = FvBufFindNextFile (Fv, &Key, (VOID **) &CurrentFile); if (EFI_ERROR (Status)) { Error (NULL, 0, 0003, "error parsing FV image", "cannot find the first file in the FV image"); return GetUtilityStatus (); } // // Display information about files found // while (CurrentFile != NULL) { // // Increment the number of files counter // NumberOfFiles++; // // Display info about this file // Status = PrintFileInfo (Fv, CurrentFile, ErasePolarity); if (EFI_ERROR (Status)) { Error (NULL, 0, 0003, "error parsing FV image", "failed to parse a file in the FV"); return GetUtilityStatus (); } // // Get the next file // Status = FvBufFindNextFile (Fv, &Key, (VOID **) &CurrentFile); if (Status == EFI_NOT_FOUND) { CurrentFile = NULL; } else if (EFI_ERROR (Status)) { Error (NULL, 0, 0003, "error parsing FV image", "cannot find the next file in the FV image"); return GetUtilityStatus (); } } if (IsChildFv) { printf ("There are a total of %d files in the child FV\n", (int) NumberOfFiles); } else { printf ("There are a total of %d files in this FV\n", (int) NumberOfFiles); } return EFI_SUCCESS; } UINT32 GetOccupiedSize ( IN UINT32 ActualSize, IN UINT32 Alignment ) /*++ Routine Description: This function returns the next larger size that meets the alignment requirement specified. Arguments: ActualSize The size. Alignment The desired alignment. Returns: EFI_SUCCESS Function completed successfully. EFI_ABORTED The function encountered an error. --*/ { UINT32 OccupiedSize; OccupiedSize = ActualSize; while ((OccupiedSize & (Alignment - 1)) != 0) { OccupiedSize++; } return OccupiedSize; } static CHAR8 * SectionNameToStr ( IN EFI_SECTION_TYPE Type ) /*++ Routine Description: Converts EFI Section names to Strings Arguments: Type - The EFI Section type Returns: CHAR8* - Pointer to the String containing the section name. --*/ { CHAR8 *SectionStr; CHAR8 *SectionTypeStringTable[] = { // // 0X00 // "EFI_SECTION_ALL", // // 0x01 // "EFI_SECTION_COMPRESSION", // // 0x02 // "EFI_SECTION_GUID_DEFINED", // // 0x03 // "Unknown section type - Reserved 0x03", // // 0x04 // "Unknown section type - Reserved 0x04", // // 0x05 // "Unknown section type - Reserved 0x05", // // 0x06 // "Unknown section type - Reserved 0x06", // // 0x07 // "Unknown section type - Reserved 0x07", // // 0x08 // "Unknown section type - Reserved 0x08", // // 0x09 // "Unknown section type - Reserved 0x09", // // 0x0A // "Unknown section type - Reserved 0x0A", // // 0x0B // "Unknown section type - Reserved 0x0B", // // 0x0C // "Unknown section type - Reserved 0x0C", // // 0x0D // "Unknown section type - Reserved 0x0D", // // 0x0E // "Unknown section type - Reserved 0x0E", // // 0x0F // "Unknown section type - Reserved 0x0E", // // 0x10 // "EFI_SECTION_PE32", // // 0x11 // "EFI_SECTION_PIC", // // 0x12 // "EFI_SECTION_TE", // // 0x13 // "EFI_SECTION_DXE_DEPEX", // // 0x14 // "EFI_SECTION_VERSION", // // 0x15 // "EFI_SECTION_USER_INTERFACE", // // 0x16 // "EFI_SECTION_COMPATIBILITY16", // // 0x17 // "EFI_SECTION_FIRMWARE_VOLUME_IMAGE", // // 0x18 // "EFI_SECTION_FREEFORM_SUBTYPE_GUID", // // 0x19 // "EFI_SECTION_RAW", // // 0x1A // "Unknown section type - 0x1A", // // 0x1B // "EFI_SECTION_PEI_DEPEX", // // 0x1C // "EFI_SECTION_MM_DEPEX", // // 0x1C+ // "Unknown section type - Reserved - beyond last defined section" }; if (Type > EFI_SECTION_LAST_SECTION_TYPE) { Type = EFI_SECTION_LAST_SECTION_TYPE + 1; } SectionStr = malloc (100); if (SectionStr == NULL) { printf ("Error: Out of memory resources.\n"); return SectionStr; } strcpy (SectionStr, SectionTypeStringTable[Type]); return SectionStr; } STATIC EFI_STATUS ReadHeader ( IN FILE *InputFile, OUT UINT32 *FvSize, OUT BOOLEAN *ErasePolarity ) /*++ Routine Description: This function determines the size of the FV and the erase polarity. The erase polarity is the FALSE value for file state. Arguments: InputFile The file that contains the FV image. FvSize The size of the FV. ErasePolarity The FV erase polarity. Returns: EFI_SUCCESS Function completed successfully. EFI_INVALID_PARAMETER A required parameter was NULL or is out of range. EFI_ABORTED The function encountered an error. --*/ { EFI_FIRMWARE_VOLUME_HEADER VolumeHeader; EFI_FV_BLOCK_MAP_ENTRY BlockMap; UINTN Signature[2]; UINTN BytesRead; UINT32 Size; size_t ReadSize; BytesRead = 0; Size = 0; // // Check input parameters // if (InputFile == NULL || FvSize == NULL || ErasePolarity == NULL) { Error (__FILE__, __LINE__, 0, "application error", "invalid parameter to function"); return EFI_INVALID_PARAMETER; } // // Read the header // ReadSize = fread (&VolumeHeader, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile); if (ReadSize != 1) { return EFI_ABORTED; } BytesRead = sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY); Signature[0] = VolumeHeader.Signature; Signature[1] = 0; // // Print FV header information // printf ("Signature: %s (%X)\n", (char *) Signature, (unsigned) VolumeHeader.Signature); printf ("Attributes: %X\n", (unsigned) VolumeHeader.Attributes); if (VolumeHeader.Attributes & EFI_FVB2_READ_DISABLED_CAP) { printf (" EFI_FVB2_READ_DISABLED_CAP\n"); } if (VolumeHeader.Attributes & EFI_FVB2_READ_ENABLED_CAP) { printf (" EFI_FVB2_READ_ENABLED_CAP\n"); } if (VolumeHeader.Attributes & EFI_FVB2_READ_STATUS) { printf (" EFI_FVB2_READ_STATUS\n"); } if (VolumeHeader.Attributes & EFI_FVB2_WRITE_DISABLED_CAP) { printf (" EFI_FVB2_WRITE_DISABLED_CAP\n"); } if (VolumeHeader.Attributes & EFI_FVB2_WRITE_ENABLED_CAP) { printf (" EFI_FVB2_WRITE_ENABLED_CAP\n"); } if (VolumeHeader.Attributes & EFI_FVB2_WRITE_STATUS) { printf (" EFI_FVB2_WRITE_STATUS\n"); } if (VolumeHeader.Attributes & EFI_FVB2_LOCK_CAP) { printf (" EFI_FVB2_LOCK_CAP\n"); } if (VolumeHeader.Attributes & EFI_FVB2_LOCK_STATUS) { printf (" EFI_FVB2_LOCK_STATUS\n"); } if (VolumeHeader.Attributes & EFI_FVB2_STICKY_WRITE) { printf (" EFI_FVB2_STICKY_WRITE\n"); } if (VolumeHeader.Attributes & EFI_FVB2_MEMORY_MAPPED) { printf (" EFI_FVB2_MEMORY_MAPPED\n"); } if (VolumeHeader.Attributes & EFI_FVB2_ERASE_POLARITY) { printf (" EFI_FVB2_ERASE_POLARITY\n"); *ErasePolarity = TRUE; } #if (PI_SPECIFICATION_VERSION < 0x00010000) if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT) { printf (" EFI_FVB2_ALIGNMENT\n"); } if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_2) { printf (" EFI_FVB2_ALIGNMENT_2\n"); } if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_4) { printf (" EFI_FVB2_ALIGNMENT_4\n"); } if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_8) { printf (" EFI_FVB2_ALIGNMENT_8\n"); } if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_16) { printf (" EFI_FVB2_ALIGNMENT_16\n"); } if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_32) { printf (" EFI_FVB2_ALIGNMENT_32\n"); } if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_64) { printf (" EFI_FVB2_ALIGNMENT_64\n"); } if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_128) { printf (" EFI_FVB2_ALIGNMENT_128\n"); } if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_256) { printf (" EFI_FVB2_ALIGNMENT_256\n"); } if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_512) { printf (" EFI_FVB2_ALIGNMENT_512\n"); } if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_1K) { printf (" EFI_FVB2_ALIGNMENT_1K\n"); } if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_2K) { printf (" EFI_FVB2_ALIGNMENT_2K\n"); } if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_4K) { printf (" EFI_FVB2_ALIGNMENT_4K\n"); } if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_8K) { printf (" EFI_FVB2_ALIGNMENT_8K\n"); } if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_16K) { printf (" EFI_FVB2_ALIGNMENT_16K\n"); } if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_32K) { printf (" EFI_FVB2_ALIGNMENT_32K\n"); } if (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT_64K) { printf (" EFI_FVB2_ALIGNMENT_64K\n"); } #else if (VolumeHeader.Attributes & EFI_FVB2_READ_LOCK_CAP) { printf (" EFI_FVB2_READ_LOCK_CAP\n"); } if (VolumeHeader.Attributes & EFI_FVB2_READ_LOCK_STATUS) { printf (" EFI_FVB2_READ_LOCK_STATUS\n"); } if (VolumeHeader.Attributes & EFI_FVB2_WRITE_LOCK_CAP) { printf (" EFI_FVB2_WRITE_LOCK_CAP\n"); } if (VolumeHeader.Attributes & EFI_FVB2_WRITE_LOCK_STATUS) { printf (" EFI_FVB2_WRITE_LOCK_STATUS\n"); } switch (VolumeHeader.Attributes & EFI_FVB2_ALIGNMENT) { case EFI_FVB2_ALIGNMENT_1: printf (" EFI_FVB2_ALIGNMENT_1\n"); break; case EFI_FVB2_ALIGNMENT_2: printf (" EFI_FVB2_ALIGNMENT_2\n"); break; case EFI_FVB2_ALIGNMENT_4: printf (" EFI_FVB2_ALIGNMENT_4\n"); break; case EFI_FVB2_ALIGNMENT_8: printf (" EFI_FVB2_ALIGNMENT_8\n"); break; case EFI_FVB2_ALIGNMENT_16: printf (" EFI_FVB2_ALIGNMENT_16\n"); break; case EFI_FVB2_ALIGNMENT_32: printf (" EFI_FVB2_ALIGNMENT_32\n"); break; case EFI_FVB2_ALIGNMENT_64: printf (" EFI_FVB2_ALIGNMENT_64\n"); break; case EFI_FVB2_ALIGNMENT_128: printf (" EFI_FVB2_ALIGNMENT_128\n"); break; case EFI_FVB2_ALIGNMENT_256: printf (" EFI_FVB2_ALIGNMENT_256\n"); break; case EFI_FVB2_ALIGNMENT_512: printf (" EFI_FVB2_ALIGNMENT_512\n"); break; case EFI_FVB2_ALIGNMENT_1K: printf (" EFI_FVB2_ALIGNMENT_1K\n"); break; case EFI_FVB2_ALIGNMENT_2K: printf (" EFI_FVB2_ALIGNMENT_2K\n"); break; case EFI_FVB2_ALIGNMENT_4K: printf (" EFI_FVB2_ALIGNMENT_4K\n"); break; case EFI_FVB2_ALIGNMENT_8K: printf (" EFI_FVB2_ALIGNMENT_8K\n"); break; case EFI_FVB2_ALIGNMENT_16K: printf (" EFI_FVB2_ALIGNMENT_16K\n"); break; case EFI_FVB2_ALIGNMENT_32K: printf (" EFI_FVB2_ALIGNMENT_32K\n"); break; case EFI_FVB2_ALIGNMENT_64K: printf (" EFI_FVB2_ALIGNMENT_64K\n"); break; case EFI_FVB2_ALIGNMENT_128K: printf (" EFI_FVB2_ALIGNMENT_128K\n"); break; case EFI_FVB2_ALIGNMENT_256K: printf (" EFI_FVB2_ALIGNMENT_256K\n"); break; case EFI_FVB2_ALIGNMENT_512K: printf (" EFI_FVB2_ALIGNMENT_512K\n"); break; case EFI_FVB2_ALIGNMENT_1M: printf (" EFI_FVB2_ALIGNMENT_1M\n"); break; case EFI_FVB2_ALIGNMENT_2M: printf (" EFI_FVB2_ALIGNMENT_2M\n"); break; case EFI_FVB2_ALIGNMENT_4M: printf (" EFI_FVB2_ALIGNMENT_4M\n"); break; case EFI_FVB2_ALIGNMENT_8M: printf (" EFI_FVB2_ALIGNMENT_8M\n"); break; case EFI_FVB2_ALIGNMENT_16M: printf (" EFI_FVB2_ALIGNMENT_16M\n"); break; case EFI_FVB2_ALIGNMENT_32M: printf (" EFI_FVB2_ALIGNMENT_32M\n"); break; case EFI_FVB2_ALIGNMENT_64M: printf (" EFI_FVB2_ALIGNMENT_64M\n"); break; case EFI_FVB2_ALIGNMENT_128M: printf (" EFI_FVB2_ALIGNMENT_128M\n"); break; case EFI_FVB2_ALIGNMENT_256M: printf (" EFI_FVB2_ALIGNMENT_256M\n"); break; case EFI_FVB2_ALIGNMENT_512M: printf (" EFI_FVB2_ALIGNMENT_512M\n"); break; case EFI_FVB2_ALIGNMENT_1G: printf (" EFI_FVB2_ALIGNMENT_1G\n"); break; case EFI_FVB2_ALIGNMENT_2G: printf (" EFI_FVB2_ALIGNMENT_2G\n"); break; } #endif printf ("Header Length: 0x%08X\n", VolumeHeader.HeaderLength); printf ("File System ID: "); PrintGuid (&VolumeHeader.FileSystemGuid); // // printf ("\n"); // printf ("Revision: 0x%04X\n", VolumeHeader.Revision); do { ReadSize = fread (&BlockMap, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile); if (ReadSize != 1) { return EFI_ABORTED; } BytesRead += sizeof (EFI_FV_BLOCK_MAP_ENTRY); if (BlockMap.NumBlocks != 0) { printf ("Number of Blocks: 0x%08X\n", (unsigned) BlockMap.NumBlocks); printf ("Block Length: 0x%08X\n", (unsigned) BlockMap.Length); Size += BlockMap.NumBlocks * BlockMap.Length; } } while (!(BlockMap.NumBlocks == 0 && BlockMap.Length == 0)); if (BytesRead != VolumeHeader.HeaderLength) { printf ("ERROR: Header length not consistent with Block Maps!\n"); return EFI_ABORTED; } if (VolumeHeader.FvLength != Size) { printf ("ERROR: Volume Size not consistent with Block Maps!\n"); return EFI_ABORTED; } printf ("Total Volume Size: 0x%08X\n", (unsigned) Size); *FvSize = Size; // // rewind (InputFile); // return EFI_SUCCESS; } STATIC EFI_STATUS PrintAprioriFile ( EFI_FFS_FILE_HEADER *FileHeader ) /*++ Routine Description: Print GUIDs from the APRIORI file Arguments: FileHeader - The file header Returns: EFI_SUCCESS - The APRIORI file was parsed correctly EFI_SECTION_ERROR - Problem with file parsing --*/ { UINT8 GuidBuffer[PRINTED_GUID_BUFFER_SIZE]; UINT32 HeaderSize; HeaderSize = FvBufGetFfsHeaderSize (FileHeader); if (FileHeader->Type != EFI_FV_FILETYPE_FREEFORM) return EFI_SECTION_ERROR; EFI_COMMON_SECTION_HEADER* SectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINTN) FileHeader + HeaderSize); if (SectionHeader->Type != EFI_SECTION_RAW) return EFI_SECTION_ERROR; UINT32 SectionLength = GetSectionFileLength (SectionHeader); EFI_GUID* FileName = (EFI_GUID *) ((UINT8 *) SectionHeader + sizeof (EFI_COMMON_SECTION_HEADER)); while (((UINT8 *) FileName) < ((UINT8 *) SectionHeader + SectionLength)) { PrintGuidToBuffer (FileName, GuidBuffer, sizeof (GuidBuffer), TRUE); printf ("%s ", GuidBuffer); PrintGuidName (GuidBuffer); printf ("\n"); FileName++; } return EFI_SUCCESS; } STATIC EFI_STATUS PrintFileInfo ( EFI_FIRMWARE_VOLUME_HEADER *FvImage, EFI_FFS_FILE_HEADER *FileHeader, BOOLEAN ErasePolarity ) /*++ Routine Description: GC_TODO: Add function description Arguments: FvImage - GC_TODO: add argument description FileHeader - GC_TODO: add argument description ErasePolarity - GC_TODO: add argument description Returns: EFI_SUCCESS - GC_TODO: Add description for return value EFI_ABORTED - GC_TODO: Add description for return value --*/ { UINT32 FileLength; UINT8 FileState; UINT8 Checksum; EFI_FFS_FILE_HEADER2 BlankHeader; EFI_STATUS Status; UINT8 GuidBuffer[PRINTED_GUID_BUFFER_SIZE]; UINT32 HeaderSize; #if (PI_SPECIFICATION_VERSION < 0x00010000) UINT16 *Tail; #endif // // Check if we have free space // HeaderSize = FvBufGetFfsHeaderSize(FileHeader); if (ErasePolarity) { memset (&BlankHeader, -1, HeaderSize); } else { memset (&BlankHeader, 0, HeaderSize); } if (memcmp (&BlankHeader, FileHeader, HeaderSize) == 0) { return EFI_SUCCESS; } // // Print file information. // printf ("============================================================\n"); printf ("File Name: "); PrintGuidToBuffer (&FileHeader->Name, GuidBuffer, sizeof (GuidBuffer), TRUE); printf ("%s ", GuidBuffer); PrintGuidName (GuidBuffer); printf ("\n"); // // PrintGuid (&FileHeader->Name); // printf ("\n"); // FileLength = FvBufGetFfsFileSize (FileHeader); printf ("File Offset: 0x%08X\n", (unsigned) ((UINTN) FileHeader - (UINTN) FvImage)); printf ("File Length: 0x%08X\n", (unsigned) FileLength); printf ("File Attributes: 0x%02X\n", FileHeader->Attributes); printf ("File State: 0x%02X\n", FileHeader->State); // // Print file state // FileState = GetFileState (ErasePolarity, FileHeader); switch (FileState) { case EFI_FILE_HEADER_CONSTRUCTION: printf (" EFI_FILE_HEADER_CONSTRUCTION\n"); return EFI_SUCCESS; case EFI_FILE_HEADER_INVALID: printf (" EFI_FILE_HEADER_INVALID\n"); return EFI_SUCCESS; case EFI_FILE_HEADER_VALID: printf (" EFI_FILE_HEADER_VALID\n"); Checksum = CalculateSum8 ((UINT8 *) FileHeader, HeaderSize); Checksum = (UINT8) (Checksum - FileHeader->IntegrityCheck.Checksum.File); Checksum = (UINT8) (Checksum - FileHeader->State); if (Checksum != 0) { printf ("ERROR: Header checksum invalid.\n"); return EFI_ABORTED; } return EFI_SUCCESS; case EFI_FILE_DELETED: printf (" EFI_FILE_DELETED\n"); case EFI_FILE_MARKED_FOR_UPDATE: printf (" EFI_FILE_MARKED_FOR_UPDATE\n"); case EFI_FILE_DATA_VALID: printf (" EFI_FILE_DATA_VALID\n"); // // Calculate header checksum // Checksum = CalculateSum8 ((UINT8 *) FileHeader, HeaderSize); Checksum = (UINT8) (Checksum - FileHeader->IntegrityCheck.Checksum.File); Checksum = (UINT8) (Checksum - FileHeader->State); if (Checksum != 0) { Error (NULL, 0, 0003, "error parsing FFS file", "FFS file with Guid %s has invalid header checksum", GuidBuffer); return EFI_ABORTED; } FileLength = FvBufGetFfsFileSize (FileHeader); if (FileHeader->Attributes & FFS_ATTRIB_CHECKSUM) { // // Calculate file checksum // Checksum = CalculateSum8 ((UINT8 *)FileHeader + HeaderSize, FileLength - HeaderSize); Checksum = Checksum + FileHeader->IntegrityCheck.Checksum.File; if (Checksum != 0) { Error (NULL, 0, 0003, "error parsing FFS file", "FFS file with Guid %s has invalid file checksum", GuidBuffer); return EFI_ABORTED; } } else { if (FileHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) { Error (NULL, 0, 0003, "error parsing FFS file", "FFS file with Guid %s has invalid header checksum -- not set to fixed value of 0xAA", GuidBuffer); return EFI_ABORTED; } } #if (PI_SPECIFICATION_VERSION < 0x00010000) // // Verify tail if present // if (FileHeader->Attributes & FFS_ATTRIB_TAIL_PRESENT) { // // Verify tail is complement of integrity check field in the header. // Tail = (UINT16 *) ((UINTN) FileHeader + GetLength (FileHeader->Size) - sizeof (EFI_FFS_INTEGRITY_CHECK)); if (FileHeader->IntegrityCheck.TailReference != (UINT16)~(*Tail)) { Error (NULL, 0, 0003, "error parsing FFS file", \ "FFS file with Guid %s failed in the integrity check, tail is not the complement of the header field", GuidBuffer); return EFI_ABORTED; } } #endif break; default: Error (NULL, 0, 0003, "error parsing FFS file", "FFS file with Guid %s has the invalid/unrecognized file state bits", GuidBuffer); return EFI_ABORTED; } printf ("File Type: 0x%02X ", FileHeader->Type); switch (FileHeader->Type) { case EFI_FV_FILETYPE_RAW: printf ("EFI_FV_FILETYPE_RAW\n"); break; case EFI_FV_FILETYPE_FREEFORM: printf ("EFI_FV_FILETYPE_FREEFORM\n"); break; case EFI_FV_FILETYPE_SECURITY_CORE: printf ("EFI_FV_FILETYPE_SECURITY_CORE\n"); break; case EFI_FV_FILETYPE_PEI_CORE: printf ("EFI_FV_FILETYPE_PEI_CORE\n"); break; case EFI_FV_FILETYPE_DXE_CORE: printf ("EFI_FV_FILETYPE_DXE_CORE\n"); break; case EFI_FV_FILETYPE_PEIM: printf ("EFI_FV_FILETYPE_PEIM\n"); break; case EFI_FV_FILETYPE_DRIVER: printf ("EFI_FV_FILETYPE_DRIVER\n"); break; case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER: printf ("EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER\n"); break; case EFI_FV_FILETYPE_APPLICATION: printf ("EFI_FV_FILETYPE_APPLICATION\n"); break; case EFI_FV_FILETYPE_SMM: printf ("EFI_FV_FILETYPE_MM\n"); break; case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE: printf ("EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE\n"); break; case EFI_FV_FILETYPE_COMBINED_SMM_DXE: printf ("EFI_FV_FILETYPE_COMBINED_MM_DXE\n"); break; case EFI_FV_FILETYPE_SMM_CORE: printf ("EFI_FV_FILETYPE_MM_CORE\n"); break; case EFI_FV_FILETYPE_MM_STANDALONE: printf ("EFI_FV_FILETYPE_MM_STANDALONE\n"); break; case EFI_FV_FILETYPE_MM_CORE_STANDALONE: printf ("EFI_FV_FILETYPE_MM_CORE_STANDALONE\n"); break; case EFI_FV_FILETYPE_FFS_PAD: printf ("EFI_FV_FILETYPE_FFS_PAD\n"); break; default: printf ("\nERROR: Unrecognized file type %X.\n", FileHeader->Type); return EFI_ABORTED; break; } switch (FileHeader->Type) { case EFI_FV_FILETYPE_ALL: case EFI_FV_FILETYPE_RAW: case EFI_FV_FILETYPE_FFS_PAD: break; default: // // All other files have sections // Status = ParseSection ( (UINT8 *) ((UINTN) FileHeader + HeaderSize), FvBufGetFfsFileSize (FileHeader) - HeaderSize ); if (EFI_ERROR (Status)) { // // printf ("ERROR: Parsing the FFS file.\n"); // return EFI_ABORTED; } break; } if (!CompareGuid ( &FileHeader->Name, &gPeiAprioriFileNameGuid )) { printf("\n"); printf("PEI APRIORI FILE:\n"); return PrintAprioriFile (FileHeader); } if (!CompareGuid ( &FileHeader->Name, &gAprioriGuid )) { printf("\n"); printf("DXE APRIORI FILE:\n"); return PrintAprioriFile (FileHeader); } return EFI_SUCCESS; } EFI_STATUS RebaseImageRead ( IN VOID *FileHandle, IN UINTN FileOffset, IN OUT UINT32 *ReadSize, OUT VOID *Buffer ) /*++ Routine Description: Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file Arguments: FileHandle - The handle to the PE/COFF file FileOffset - The offset, in bytes, into the file to read ReadSize - The number of bytes to read from the file starting at FileOffset Buffer - A pointer to the buffer to read the data into. Returns: EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset --*/ { CHAR8 *Destination8; CHAR8 *Source8; UINT32 Length; Destination8 = Buffer; Source8 = (CHAR8 *) ((UINTN) FileHandle + FileOffset); Length = *ReadSize; while (Length--) { *(Destination8++) = *(Source8++); } return EFI_SUCCESS; } EFI_STATUS SetAddressToSectionHeader ( IN CHAR8 *FileName, IN OUT UINT8 *FileBuffer, IN UINT64 NewPe32BaseAddress ) /*++ Routine Description: Set new base address into the section header of PeImage Arguments: FileName - Name of file FileBuffer - Pointer to PeImage. NewPe32BaseAddress - New Base Address for PE image. Returns: EFI_SUCCESS Set new base address into this image successfully. --*/ { EFI_STATUS Status; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; UINTN Index; EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr; EFI_IMAGE_SECTION_HEADER *SectionHeader; // // Initialize context // memset (&ImageContext, 0, sizeof (ImageContext)); ImageContext.Handle = (VOID *) FileBuffer; ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) RebaseImageRead; Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { Error (NULL, 0, 3000, "Invalid", "The input PeImage %s is not valid", FileName); return Status; } if (ImageContext.RelocationsStripped) { Error (NULL, 0, 3000, "Invalid", "The input PeImage %s has no relocation to be fixed up", FileName); return Status; } // // Get PeHeader pointer // ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer + ImageContext.PeCoffHeaderOffset); // // Get section header list // SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ( (UINTN) ImgHdr + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader ); // // Set base address into the first section header that doesn't point to code section. // for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) { if ((SectionHeader->Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) { *(UINT64 *) &SectionHeader->PointerToRelocations = NewPe32BaseAddress; break; } } // // BaseAddress is set to section header. // return EFI_SUCCESS; } EFI_STATUS RebaseImage ( IN CHAR8 *FileName, IN OUT UINT8 *FileBuffer, IN UINT64 NewPe32BaseAddress ) /*++ Routine Description: Set new base address into PeImage, and fix up PeImage based on new address. Arguments: FileName - Name of file FileBuffer - Pointer to PeImage. NewPe32BaseAddress - New Base Address for PE image. Returns: EFI_INVALID_PARAMETER - BaseAddress is not valid. EFI_SUCCESS - Update PeImage is correctly. --*/ { EFI_STATUS Status; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; UINTN Index; EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr; UINT8 *MemoryImagePointer; EFI_IMAGE_SECTION_HEADER *SectionHeader; // // Initialize context // memset (&ImageContext, 0, sizeof (ImageContext)); ImageContext.Handle = (VOID *) FileBuffer; ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) RebaseImageRead; Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { Error (NULL, 0, 3000, "Invalid", "The input PeImage %s is not valid", FileName); return Status; } if (ImageContext.RelocationsStripped) { Error (NULL, 0, 3000, "Invalid", "The input PeImage %s has no relocation to be fixed up", FileName); return Status; } // // Get PeHeader pointer // ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)(FileBuffer + ImageContext.PeCoffHeaderOffset); // // Load and Relocate Image Data // MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment); if (MemoryImagePointer == NULL) { Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName); return EFI_OUT_OF_RESOURCES; } memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment); ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((INT64)ImageContext.SectionAlignment - 1)); Status = PeCoffLoaderLoadImage (&ImageContext); if (EFI_ERROR (Status)) { Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName); free ((VOID *) MemoryImagePointer); return Status; } ImageContext.DestinationAddress = NewPe32BaseAddress; Status = PeCoffLoaderRelocateImage (&ImageContext); if (EFI_ERROR (Status)) { Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName); free ((VOID *) MemoryImagePointer); return Status; } // // Copy Relocated data to raw image file. // SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ( (UINTN) ImgHdr + sizeof (UINT32) + sizeof (EFI_IMAGE_FILE_HEADER) + ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader ); for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) { CopyMem ( FileBuffer + SectionHeader->PointerToRawData, (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress), SectionHeader->SizeOfRawData ); } free ((VOID *) MemoryImagePointer); // // Update Image Base Address // if (ImgHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { ImgHdr->Pe32.OptionalHeader.ImageBase = (UINT32) NewPe32BaseAddress; } else if (ImgHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { ImgHdr->Pe32Plus.OptionalHeader.ImageBase = NewPe32BaseAddress; } else { Error (NULL, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s", ImgHdr->Pe32.OptionalHeader.Magic, FileName ); return EFI_ABORTED; } // // Set new base address into section header // Status = SetAddressToSectionHeader (FileName, FileBuffer, NewPe32BaseAddress); return Status; } EFI_STATUS CombinePath ( IN CHAR8* DefaultPath, IN CHAR8* AppendPath, OUT CHAR8* NewPath ) { UINT32 DefaultPathLen; UINT64 Index; CHAR8 QuotesStr[] = "\""; strcpy(NewPath, QuotesStr); DefaultPathLen = strlen(DefaultPath); strcat(NewPath, DefaultPath); Index = 0; for (; Index < DefaultPathLen + 1; Index ++) { if (NewPath[Index] == '\\' || NewPath[Index] == '/') { if (NewPath[Index + 1] != '\0') { NewPath[Index] = '/'; } } } if (NewPath[Index -1] != '/') { NewPath[Index] = '/'; NewPath[Index + 1] = '\0'; } strcat(NewPath, AppendPath); strcat(NewPath, QuotesStr); return EFI_SUCCESS; } EFI_STATUS ParseSection ( IN UINT8 *SectionBuffer, IN UINT32 BufferLength ) /*++ Routine Description: Parses EFI Sections Arguments: SectionBuffer - Buffer containing the section to parse. BufferLength - Length of SectionBuffer Returns: EFI_SECTION_ERROR - Problem with section parsing. (a) compression errors (b) unrecognized section EFI_UNSUPPORTED - Do not know how to parse the section. EFI_SUCCESS - Section successfully parsed. EFI_OUT_OF_RESOURCES - Memory allocation failed. --*/ { EFI_SECTION_TYPE Type; UINT8 *Ptr; UINT32 SectionLength; UINT32 SectionHeaderLen; CHAR8 *SectionName; EFI_STATUS Status; UINT32 ParsedLength; UINT8 *CompressedBuffer; UINT32 CompressedLength; UINT8 *UncompressedBuffer; UINT32 UncompressedLength; UINT8 *ToolOutputBuffer; UINT32 ToolOutputLength; UINT8 CompressionType; UINT32 DstSize; UINT32 ScratchSize; UINT8 *ScratchBuffer; DECOMPRESS_FUNCTION DecompressFunction; GETINFO_FUNCTION GetInfoFunction; // CHAR16 *name; CHAR8 *ExtractionTool; CHAR8 *ToolInputFile; CHAR8 *ToolOutputFile; CHAR8 *SystemCommand; EFI_GUID *EfiGuid; UINT16 DataOffset; UINT16 Attributes; UINT32 RealHdrLen; CHAR8 *ToolInputFileName; CHAR8 *ToolOutputFileName; CHAR8 *UIFileName; CHAR8 *VersionString; ParsedLength = 0; ToolInputFileName = NULL; ToolOutputFileName = NULL; while (ParsedLength < BufferLength) { Ptr = SectionBuffer + ParsedLength; SectionLength = GetLength (((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; } // // Get real section file size // SectionLength = GetSectionFileLength ((EFI_COMMON_SECTION_HEADER *) Ptr); SectionHeaderLen = GetSectionHeaderLength((EFI_COMMON_SECTION_HEADER *)Ptr); SectionName = SectionNameToStr (Type); if (SectionName != NULL) { printf ("------------------------------------------------------------\n"); printf (" Type: %s\n Size: 0x%08X\n", SectionName, (unsigned) SectionLength); free (SectionName); } switch (Type) { case EFI_SECTION_RAW: case EFI_SECTION_PIC: case EFI_SECTION_TE: // default is no more information break; case EFI_SECTION_PE32: if (EnableHash) { ToolInputFileName = "edk2Temp_InputEfi.tmp"; ToolOutputFileName = "edk2Temp_OutputHash.tmp"; RebaseImage(ToolInputFileName, (UINT8*)Ptr + SectionHeaderLen, 0); PutFileImage ( ToolInputFileName, (CHAR8*)Ptr + SectionHeaderLen, SectionLength - SectionHeaderLen ); SystemCommand = malloc ( strlen (OPENSSL_COMMAND_FORMAT_STRING) + strlen (OpenSslPath) + strlen (ToolInputFileName) + strlen (ToolOutputFileName) + 1 ); if (SystemCommand == NULL) { Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); return EFI_OUT_OF_RESOURCES; } sprintf ( SystemCommand, OPENSSL_COMMAND_FORMAT_STRING, OpenSslPath, ToolOutputFileName, ToolInputFileName ); if (system (SystemCommand) != EFI_SUCCESS) { Error (NULL, 0, 3000, "Open SSL command not available. Please verify PATH or set OPENSSL_PATH.", NULL); } else { FILE *fp; CHAR8 *StrLine; CHAR8 *NewStr; UINT32 nFileLen; if((fp = fopen(ToolOutputFileName,"r")) == NULL) { Error (NULL, 0, 0004, "Hash the PE32 image failed.", NULL); } else { fseek(fp,0,SEEK_SET); fseek(fp,0,SEEK_END); nFileLen = ftell(fp); fseek(fp,0,SEEK_SET); StrLine = malloc(nFileLen); if (StrLine == NULL) { fclose(fp); free (SystemCommand); Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); return EFI_OUT_OF_RESOURCES; } fgets(StrLine, nFileLen, fp); NewStr = strrchr (StrLine, '='); printf (" SHA1: %s\n", NewStr + 1); free (StrLine); fclose(fp); } } remove(ToolInputFileName); remove(ToolOutputFileName); free (SystemCommand); } break; case EFI_SECTION_USER_INTERFACE: UIFileName = (CHAR8 *) malloc (UnicodeStrLen (((EFI_USER_INTERFACE_SECTION *) Ptr)->FileNameString) + 1); if (UIFileName == NULL) { Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); return EFI_OUT_OF_RESOURCES; } Unicode2AsciiString (((EFI_USER_INTERFACE_SECTION *) Ptr)->FileNameString, UIFileName); printf (" String: %s\n", UIFileName); free (UIFileName); break; case EFI_SECTION_FIRMWARE_VOLUME_IMAGE: printf ("/------------ Firmware Volume section start ---------------\\\n"); Status = PrintFvInfo (Ptr + SectionHeaderLen, TRUE); if (EFI_ERROR (Status)) { Error (NULL, 0, 0003, "printing of FV section contents failed", NULL); return EFI_SECTION_ERROR; } printf ("\\------------ Firmware Volume section end -----------------/\n"); break; case EFI_SECTION_COMPATIBILITY16: // // Section does not contain any further header information. // break; case EFI_SECTION_FREEFORM_SUBTYPE_GUID: printf (" Guid: "); if (SectionHeaderLen == sizeof (EFI_COMMON_SECTION_HEADER)) PrintGuid (&((EFI_FREEFORM_SUBTYPE_GUID_SECTION *)Ptr)->SubTypeGuid); else PrintGuid (&((EFI_FREEFORM_SUBTYPE_GUID_SECTION2 *)Ptr)->SubTypeGuid); printf ("\n"); break; case EFI_SECTION_PEI_DEPEX: case EFI_SECTION_DXE_DEPEX: case EFI_SECTION_SMM_DEPEX: DumpDepexSection (Ptr, SectionLength); break; case EFI_SECTION_VERSION: printf (" Build Number: 0x%04X\n", *(UINT16 *)(Ptr + SectionHeaderLen)); VersionString = (CHAR8 *) malloc (UnicodeStrLen (((EFI_VERSION_SECTION *) Ptr)->VersionString) + 1); if (VersionString == NULL) { Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); return EFI_OUT_OF_RESOURCES; } Unicode2AsciiString (((EFI_VERSION_SECTION *) Ptr)->VersionString, VersionString); printf (" Version String: %s\n", VersionString); break; case EFI_SECTION_COMPRESSION: UncompressedBuffer = NULL; if (SectionHeaderLen == sizeof (EFI_COMMON_SECTION_HEADER)) { RealHdrLen = sizeof(EFI_COMPRESSION_SECTION); UncompressedLength = ((EFI_COMPRESSION_SECTION *)Ptr)->UncompressedLength; CompressionType = ((EFI_COMPRESSION_SECTION *)Ptr)->CompressionType; } else { RealHdrLen = sizeof(EFI_COMPRESSION_SECTION2); UncompressedLength = ((EFI_COMPRESSION_SECTION2 *)Ptr)->UncompressedLength; CompressionType = ((EFI_COMPRESSION_SECTION2 *)Ptr)->CompressionType; } CompressedLength = SectionLength - RealHdrLen; printf (" Uncompressed Length: 0x%08X\n", (unsigned) UncompressedLength); if (CompressionType == EFI_NOT_COMPRESSED) { printf (" Compression Type: EFI_NOT_COMPRESSED\n"); if (CompressedLength != UncompressedLength) { Error ( NULL, 0, 0, "file is not compressed, but the compressed length does not match the uncompressed length", NULL ); return EFI_SECTION_ERROR; } UncompressedBuffer = Ptr + RealHdrLen; } else if (CompressionType == EFI_STANDARD_COMPRESSION) { GetInfoFunction = EfiGetInfo; DecompressFunction = EfiDecompress; printf (" Compression Type: EFI_STANDARD_COMPRESSION\n"); CompressedBuffer = Ptr + RealHdrLen; Status = GetInfoFunction (CompressedBuffer, CompressedLength, &DstSize, &ScratchSize); if (EFI_ERROR (Status)) { Error (NULL, 0, 0003, "error getting compression info from compression section", NULL); return EFI_SECTION_ERROR; } if (DstSize != UncompressedLength) { Error (NULL, 0, 0003, "compression error in the compression section", NULL); return EFI_SECTION_ERROR; } ScratchBuffer = malloc (ScratchSize); if (ScratchBuffer == NULL) { Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); return EFI_OUT_OF_RESOURCES; } UncompressedBuffer = malloc (UncompressedLength); if (UncompressedBuffer == NULL) { free (ScratchBuffer); Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); return EFI_OUT_OF_RESOURCES; } Status = DecompressFunction ( CompressedBuffer, CompressedLength, UncompressedBuffer, UncompressedLength, ScratchBuffer, ScratchSize ); free (ScratchBuffer); if (EFI_ERROR (Status)) { Error (NULL, 0, 0003, "decompress failed", NULL); free (UncompressedBuffer); return EFI_SECTION_ERROR; } } else { Error (NULL, 0, 0003, "unrecognized compression type", "type 0x%X", CompressionType); return EFI_SECTION_ERROR; } printf ("/------------ Encapsulation section start -----------------\\\n"); Status = ParseSection (UncompressedBuffer, UncompressedLength); printf ("\\------------ Encapsulation section end -------------------/\n"); if (CompressionType == EFI_STANDARD_COMPRESSION) { // // We need to deallocate Buffer // free (UncompressedBuffer); } if (EFI_ERROR (Status)) { Error (NULL, 0, 0003, "failed to parse section", NULL); return EFI_SECTION_ERROR; } break; case EFI_SECTION_GUID_DEFINED: if (SectionHeaderLen == sizeof(EFI_COMMON_SECTION_HEADER)) { EfiGuid = &((EFI_GUID_DEFINED_SECTION *) Ptr)->SectionDefinitionGuid; DataOffset = ((EFI_GUID_DEFINED_SECTION *) Ptr)->DataOffset; Attributes = ((EFI_GUID_DEFINED_SECTION *) Ptr)->Attributes; } else { EfiGuid = &((EFI_GUID_DEFINED_SECTION2 *) Ptr)->SectionDefinitionGuid; DataOffset = ((EFI_GUID_DEFINED_SECTION2 *) Ptr)->DataOffset; Attributes = ((EFI_GUID_DEFINED_SECTION2 *) Ptr)->Attributes; } printf (" SectionDefinitionGuid: "); PrintGuid (EfiGuid); printf ("\n"); printf (" DataOffset: 0x%04X\n", (unsigned) DataOffset); printf (" Attributes: 0x%04X\n", (unsigned) Attributes); ExtractionTool = LookupGuidedSectionToolPath ( mParsedGuidedSectionTools, EfiGuid ); if (ExtractionTool != NULL) { #ifndef __GNUC__ ToolInputFile = CloneString (tmpnam (NULL)); ToolOutputFile = CloneString (tmpnam (NULL)); #else char tmp1[] = "/tmp/fileXXXXXX"; char tmp2[] = "/tmp/fileXXXXXX"; int fd1; int fd2; fd1 = mkstemp(tmp1); fd2 = mkstemp(tmp2); ToolInputFile = CloneString(tmp1); ToolOutputFile = CloneString(tmp2); close(fd1); close(fd2); #endif if ((ToolInputFile == NULL) || (ToolOutputFile == NULL)) { if (ToolInputFile != NULL) { free (ToolInputFile); } if (ToolOutputFile != NULL) { free (ToolOutputFile); } free (ExtractionTool); Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); return EFI_OUT_OF_RESOURCES; } // // Construction 'system' command string // SystemCommand = malloc ( strlen (EXTRACT_COMMAND_FORMAT_STRING) + strlen (ExtractionTool) + strlen (ToolInputFile) + strlen (ToolOutputFile) + 1 ); if (SystemCommand == NULL) { free (ToolInputFile); free (ToolOutputFile); free (ExtractionTool); Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); return EFI_OUT_OF_RESOURCES; } sprintf ( SystemCommand, EXTRACT_COMMAND_FORMAT_STRING, ExtractionTool, ToolOutputFile, ToolInputFile ); free (ExtractionTool); if (!CompareGuid ( EfiGuid, &gEfiCrc32GuidedSectionExtractionProtocolGuid ) ) { DataOffset -= 4; } Status = PutFileImage ( ToolInputFile, (CHAR8*)Ptr + DataOffset, SectionLength - DataOffset ); system (SystemCommand); remove (ToolInputFile); free (ToolInputFile); Status = GetFileImage ( ToolOutputFile, (CHAR8 **)&ToolOutputBuffer, &ToolOutputLength ); remove (ToolOutputFile); free (ToolOutputFile); free (SystemCommand); if (EFI_ERROR (Status)) { Error (NULL, 0, 0004, "unable to read decoded GUIDED section", NULL); return EFI_SECTION_ERROR; } printf ("/------------ Encapsulation section start -----------------\\\n"); Status = ParseSection ( ToolOutputBuffer, ToolOutputLength ); if (EFI_ERROR (Status)) { Error (NULL, 0, 0003, "parse of decoded GUIDED section failed", NULL); return EFI_SECTION_ERROR; } printf ("\\------------ Encapsulation section end -------------------/\n"); // // Check for CRC32 sections which we can handle internally if needed. // } else if (!CompareGuid ( EfiGuid, &gEfiCrc32GuidedSectionExtractionProtocolGuid ) ) { // // CRC32 guided section // printf ("/------------ Encapsulation section start -----------------\\\n"); Status = ParseSection ( Ptr + DataOffset, SectionLength - DataOffset ); if (EFI_ERROR (Status)) { Error (NULL, 0, 0003, "parse of CRC32 GUIDED section failed", NULL); return EFI_SECTION_ERROR; } printf ("\\------------ Encapsulation section end -------------------/\n"); } else { // // We don't know how to parse it now. // Error (NULL, 0, 0003, "Error parsing section", \ "EFI_SECTION_GUID_DEFINED cannot be parsed at this time. Tool to decode this section should have been defined in GuidedSectionTools.txt (built in the FV directory)."); return EFI_UNSUPPORTED; } break; default: // // Unknown section, return error // Error (NULL, 0, 0003, "unrecognized section type found", "section type = 0x%X", Type); return EFI_SECTION_ERROR; } ParsedLength += SectionLength; // // We make then next section begin on a 4-byte boundary // ParsedLength = GetOccupiedSize (ParsedLength, 4); } if (ParsedLength < BufferLength) { Error (NULL, 0, 0003, "sections do not completely fill the sectioned buffer being parsed", NULL); return EFI_SECTION_ERROR; } return EFI_SUCCESS; } EFI_STATUS DumpDepexSection ( IN UINT8 *Ptr, IN UINT32 SectionLength ) /*++ Routine Description: GC_TODO: Add function description Arguments: Ptr - GC_TODO: add argument description SectionLength - GC_TODO: add argument description Returns: EFI_SUCCESS - GC_TODO: Add description for return value --*/ { UINT8 GuidBuffer[PRINTED_GUID_BUFFER_SIZE]; // // Need at least a section header + data // if (SectionLength <= sizeof (EFI_COMMON_SECTION_HEADER)) { return EFI_SUCCESS; } Ptr += GetSectionHeaderLength((EFI_COMMON_SECTION_HEADER *)Ptr); SectionLength -= GetSectionHeaderLength((EFI_COMMON_SECTION_HEADER *)Ptr); while (SectionLength > 0) { printf (" "); switch (*Ptr) { case EFI_DEP_BEFORE: printf ("BEFORE\n"); Ptr++; SectionLength--; break; case EFI_DEP_AFTER: printf ("AFTER\n"); Ptr++; SectionLength--; break; case EFI_DEP_PUSH: printf ("PUSH\n "); PrintGuidToBuffer ((EFI_GUID *) (Ptr + 1), GuidBuffer, sizeof (GuidBuffer), TRUE); printf ("%s ", GuidBuffer); PrintGuidName (GuidBuffer); printf ("\n"); // // PrintGuid ((EFI_GUID *)(Ptr + 1)); // Ptr += 17; SectionLength -= 17; break; case EFI_DEP_AND: printf ("AND\n"); Ptr++; SectionLength--; break; case EFI_DEP_OR: printf ("OR\n"); Ptr++; SectionLength--; break; case EFI_DEP_NOT: printf ("NOT\n"); Ptr++; SectionLength--; break; case EFI_DEP_TRUE: printf ("TRUE\n"); Ptr++; SectionLength--; break; case EFI_DEP_FALSE: printf ("FALSE\n"); Ptr++; SectionLength--; break; case EFI_DEP_END: printf ("END DEPEX\n"); Ptr++; SectionLength--; break; case EFI_DEP_SOR: printf ("SOR\n"); Ptr++; SectionLength--; break; default: printf ("Unrecognized byte in depex: 0x%X\n", *Ptr); return EFI_SUCCESS; } } return EFI_SUCCESS; } EFI_STATUS PrintGuidName ( IN UINT8 *GuidStr ) /*++ Routine Description: GC_TODO: Add function description Arguments: GuidStr - GC_TODO: add argument description Returns: EFI_SUCCESS - GC_TODO: Add description for return value EFI_INVALID_PARAMETER - GC_TODO: Add description for return value --*/ { GUID_TO_BASENAME *GPtr; // // If we have a list of guid-to-basenames, then go through the list to // look for a guid string match. If found, print the basename to stdout, // otherwise return a failure. // GPtr = mGuidBaseNameList; while (GPtr != NULL) { if (_stricmp ((CHAR8*) GuidStr, (CHAR8*) GPtr->Guid) == 0) { printf ("%s", GPtr->BaseName); return EFI_SUCCESS; } GPtr = GPtr->Next; } return EFI_INVALID_PARAMETER; } EFI_STATUS ParseGuidBaseNameFile ( CHAR8 *FileName ) /*++ Routine Description: GC_TODO: Add function description Arguments: FileName - GC_TODO: add argument description Returns: EFI_DEVICE_ERROR - GC_TODO: Add description for return value EFI_OUT_OF_RESOURCES - GC_TODO: Add description for return value EFI_SUCCESS - GC_TODO: Add description for return value --*/ { FILE *Fptr; CHAR8 Line[MAX_LINE_LEN]; CHAR8 FormatString[MAX_LINE_LEN]; GUID_TO_BASENAME *GPtr; if ((Fptr = fopen (LongFilePath (FileName), "r")) == NULL) { printf ("ERROR: Failed to open input cross-reference file '%s'\n", FileName); return EFI_DEVICE_ERROR; } // // Generate the format string for fscanf // sprintf ( FormatString, "%%%us %%%us", (unsigned) sizeof (GPtr->Guid) - 1, (unsigned) sizeof (GPtr->BaseName) - 1 ); while (fgets (Line, sizeof (Line), Fptr) != NULL) { // // Allocate space for another guid/basename element // GPtr = malloc (sizeof (GUID_TO_BASENAME)); if (GPtr == NULL) { fclose (Fptr); return EFI_OUT_OF_RESOURCES; } memset ((char *) GPtr, 0, sizeof (GUID_TO_BASENAME)); if (sscanf (Line, FormatString, GPtr->Guid, GPtr->BaseName) == 2) { GPtr->Next = mGuidBaseNameList; mGuidBaseNameList = GPtr; } else { // // Some sort of error. Just continue. // free (GPtr); } } fclose (Fptr); return EFI_SUCCESS; } EFI_STATUS FreeGuidBaseNameList ( VOID ) /*++ Routine Description: GC_TODO: Add function description Arguments: None Returns: EFI_SUCCESS - GC_TODO: Add description for return value --*/ { GUID_TO_BASENAME *Next; while (mGuidBaseNameList != NULL) { Next = mGuidBaseNameList->Next; free (mGuidBaseNameList); mGuidBaseNameList = Next; } return EFI_SUCCESS; } static VOID LoadGuidedSectionToolsTxt ( IN CHAR8* FirmwareVolumeFilename ) { CHAR8* PeerFilename; CHAR8* Places[] = { NULL, //NULL, }; UINTN Index; Places[0] = FirmwareVolumeFilename; //Places[1] = mUtilityFilename; mParsedGuidedSectionTools = NULL; for (Index = 0; Index < (sizeof(Places)/sizeof(Places[0])); Index++) { PeerFilename = OsPathPeerFilePath (Places[Index], "GuidedSectionTools.txt"); //printf("Loading %s...\n", PeerFilename); if (OsPathExists (PeerFilename)) { mParsedGuidedSectionTools = ParseGuidedSectionToolsFile (PeerFilename); } free (PeerFilename); if (mParsedGuidedSectionTools != NULL) { return; } } } void Usage ( VOID ) /*++ Routine Description: GC_TODO: Add function description Arguments: None Returns: GC_TODO: add return values --*/ { // // Summary usage // fprintf (stdout, "Usage: %s [options] \n\n", UTILITY_NAME); // // Copyright declaration // fprintf (stdout, "Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.\n\n"); fprintf (stdout, " Display Tiano Firmware Volume FFS image information\n\n"); // // Details Option // fprintf (stdout, "optional arguments:\n"); fprintf (stdout, " -h, --help\n\ Show this help message and exit\n"); fprintf (stdout, " --version\n\ Show program's version number and exit\n"); fprintf (stdout, " -d [DEBUG], --debug [DEBUG]\n\ Output DEBUG statements, where DEBUG_LEVEL is 0 (min) - 9 (max)\n"); fprintf (stdout, " -v, --verbose\n\ Print informational statements\n"); fprintf (stdout, " -q, --quiet\n\ Returns the exit code, error messages will be displayed\n"); fprintf (stdout, " -s, --silent\n\ Returns only the exit code; informational and error\n\ messages are not displayed\n"); fprintf (stdout, " -x XREF_FILENAME, --xref XREF_FILENAME\n\ Parse the basename to file-guid cross reference file(s)\n"); fprintf (stdout, " -f OFFSET, --offset OFFSET\n\ The offset from the start of the input file to start \n\ processing an FV\n"); fprintf (stdout, " --hash\n\ Generate HASH value of the entire PE image\n"); fprintf (stdout, " --sfo\n\ Reserved for future use\n"); }