diff --git a/Tools/Source/TianoTools/CreateMtFile/CreateMtFile.c b/Tools/Source/TianoTools/CreateMtFile/CreateMtFile.c new file mode 100644 index 0000000000..e769b8835e --- /dev/null +++ b/Tools/Source/TianoTools/CreateMtFile/CreateMtFile.c @@ -0,0 +1,246 @@ +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + + +Module Name: + + CreateMtFile.c + +Abstract: + + Simple utility to create a pad file containing fixed data. + +--*/ + +#include +#include +#include +#include "TianoCommon.h" + +#define PROGRAM_NAME "CreateMtFile" + +typedef struct { + INT8 *OutFileName; + INT8 ByteValue; + UINT32 FileSize; +} OPTIONS; + +static +EFI_STATUS +ProcessArgs ( + IN INT32 Argc, + IN INT8 *Argv[], + IN OUT OPTIONS *Options + ); + +static +void +Usage ( + VOID + ); + +int +main ( + IN INT32 Argc, + IN INT8 *Argv[] + ) +/*++ + +Routine Description: + + Main entry point for this utility. + +Arguments: + + Standard C entry point args Argc and Argv + +Returns: + + EFI_SUCCESS if good to go + +--*/ +// GC_TODO: ] - add argument and description to function comment +// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment +// GC_TODO: EFI_DEVICE_ERROR - add return value to function comment +// GC_TODO: EFI_DEVICE_ERROR - add return value to function comment +{ + FILE *OutFptr; + OPTIONS Options; + + // + // Process the command-line arguments. + // + if (ProcessArgs (Argc, Argv, &Options) != EFI_SUCCESS) { + return EFI_INVALID_PARAMETER; + } + // + // Open the output file + // + if ((OutFptr = fopen (Options.OutFileName, "wb")) == NULL) { + fprintf ( + stdout, + PROGRAM_NAME " ERROR: Could not open output file '%s' for writing\n", + Options.OutFileName + ); + return EFI_DEVICE_ERROR; + } + // + // Write the pad bytes. Do it the slow way (one at a time) for now. + // + while (Options.FileSize > 0) { + if (fwrite (&Options.ByteValue, 1, 1, OutFptr) != 1) { + fclose (OutFptr); + fprintf (stdout, PROGRAM_NAME " ERROR: Failed to write to output file\n"); + return EFI_DEVICE_ERROR; + } + + Options.FileSize--; + } + // + // Close the file + // + fclose (OutFptr); + return EFI_SUCCESS; +} + +static +EFI_STATUS +ProcessArgs ( + IN INT32 Argc, + IN INT8 *Argv[], + IN OUT OPTIONS *Options + ) +/*++ + +Routine Description: + + Process the command line arguments. + +Arguments: + + Argc - argument count as passed in to the entry point function + Argv - array of arguments as passed in to the entry point function + Options - stucture of where to put the values of the parsed arguments + +Returns: + + EFI_SUCCESS if everything looks good + EFI_INVALID_PARAMETER otherwise + +--*/ +// GC_TODO: ] - add argument and description to function comment +{ + UINT32 Multiplier; + + // + // Clear the options + // + memset ((char *) Options, 0, sizeof (OPTIONS)); + + // + // Skip program name + // + Argv++; + Argc--; + if (Argc < 2) { + Usage (); + return EFI_INVALID_PARAMETER; + } + // + // If first arg is dash-option, then print usage. + // + if (Argv[0][0] == '-') { + Usage (); + return EFI_INVALID_PARAMETER; + } + // + // First arg is file name + // + Options->OutFileName = Argv[0]; + Argc--; + Argv++; + + // + // Second arg is file size. Allow 0x1000, 0x100K, 1024, 1K + // + Multiplier = 1; + if ((Argv[0][strlen (Argv[0]) - 1] == 'k') || (Argv[0][strlen (Argv[0]) - 1] == 'K')) { + Multiplier = 1024; + } + // + // Look for 0x prefix on file size + // + if ((Argv[0][0] == '0') && ((Argv[0][1] == 'x') || (Argv[0][1] == 'X'))) { + if (sscanf (Argv[0], "%x", &Options->FileSize) != 1) { + fprintf (stdout, PROGRAM_NAME " ERROR: Invalid file size '%s'\n", Argv[0]); + Usage (); + return EFI_INVALID_PARAMETER; + } + // + // Otherwise must be a decimal number + // + } else { + if (sscanf (Argv[0], "%d", &Options->FileSize) != 1) { + fprintf (stdout, PROGRAM_NAME " ERROR: Invalid file size '%s'\n", Argv[0]); + Usage (); + return EFI_INVALID_PARAMETER; + } + } + + Options->FileSize *= Multiplier; + // + // Assume byte value of 0xff + // + Options->ByteValue = (INT8) (UINT8) 0xFF; + return EFI_SUCCESS; +} +// +// Print utility usage info +// +static +void +Usage ( + VOID + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + None + +Returns: + + GC_TODO: add return values + +--*/ +{ + UINT32 Index; + static const INT8 *Text[] = { + " ", + "Usage: "PROGRAM_NAME " OutFileName FileSize", + " where:", + " OutFileName is the name of the output file to generate", + " FileSize is the size of the file to create", + " Examples:", + " "PROGRAM_NAME " OutFile.bin 32K", + " "PROGRAM_NAME " OutFile.bin 0x1000", + " ", + NULL + }; + + for (Index = 0; Text[Index] != NULL; Index++) { + fprintf (stdout, "%s\n", Text[Index]); + } +} diff --git a/Tools/Source/TianoTools/CreateMtFile/Makefile b/Tools/Source/TianoTools/CreateMtFile/Makefile new file mode 100644 index 0000000000..d6574fc09f --- /dev/null +++ b/Tools/Source/TianoTools/CreateMtFile/Makefile @@ -0,0 +1,67 @@ +#/*++ +# +# Copyright (c) 1999 - 2001 Intel Corporation. All rights reserved +# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. Except as permitted by such +# license, no part of this software or documentation may be +# reproduced, stored in a retrieval system, or transmitted in any +# form or by any means without the express written consent of +# Intel Corporation. +# +# +# Module Name: +# +# Makefile +# +# Abstract: +# +# makefile for building the CreateMtFile utility. +# +# Revision History +# +#--*/ + +# +# Make sure environmental variable EFI_SOURCE is set +# +!IFNDEF EFI_SOURCE +!ERROR EFI_SOURCE environmental variable not set +!ENDIF + +# +# Define the toolchain which is used to set build options and toolchain paths +# +TOOLCHAIN = TOOLCHAIN_MSVC + +!INCLUDE PlatformTools.env + +# +# Target specific information +# + +TARGET_NAME = CreateMtFile +TARGET_SRC_DIR = $(TIANO_TOOLS_SOURCE)\$(TARGET_NAME) +TARGET_EXE = $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).exe + +# +# Build targets +# + +all: $(TARGET_EXE) + +OBJECTS = $(TIANO_TOOLS_OUTPUT)\CreateMtFile.obj + +# +# Build the EXE by compiling the source files, then linking the resultant +# object files together. +# + +$(TIANO_TOOLS_OUTPUT)\CreateMtFile.obj : $(TARGET_SRC_DIR)\CreateMtFile.c + $(CC) $(C_FLAGS) $(TARGET_SRC_DIR)\CreateMtFile.c /Fo$@ + +$(TARGET_EXE): $(OBJECTS) $(TARGET_EXE_LIBS) + $(LINK) $(MSVS_LINK_LIBPATHS) $(L_FLAGS) $(LIBS) /out:$(TARGET_EXE) $(OBJECTS) + +clean: + @if exist $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).* del $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).* > NUL diff --git a/Tools/Source/TianoTools/EfiCompress/EfiCompressMain.c b/Tools/Source/TianoTools/EfiCompress/EfiCompressMain.c new file mode 100644 index 0000000000..db3e184e57 --- /dev/null +++ b/Tools/Source/TianoTools/EfiCompress/EfiCompressMain.c @@ -0,0 +1,163 @@ +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + + +Module Name: + + EfiCompressMain.c + +Abstract: + + The main function for the compression utility. + +--*/ + +#include +#include +#include +#include +#include +#include "TianoCommon.h" +#include "EfiCompress.h" + +int +main ( + INT32 argc, + CHAR8 *argv[] + ) +/*++ + +Routine Description: + + Compresses the input files + +Arguments: + + argc - number of arguments passed into the command line. + argv[] - files to compress and files to output compressed data to. + +Returns: + + int: 0 for successful execution of the function. + +--*/ +{ + EFI_STATUS Status; + FILE *infile; + FILE *outfile; + UINT32 SrcSize; + UINT32 DstSize; + UINT8 *SrcBuffer; + UINT8 *DstBuffer; + UINT8 Buffer[8]; + + // + // Added for makefile debug - KCE + // + INT32 arg_counter; + printf ("\n\n"); + for (arg_counter = 0; arg_counter < argc; arg_counter++) { + printf ("%s ", argv[arg_counter]); + } + + printf ("\n\n"); + + SrcBuffer = DstBuffer = NULL; + + infile = outfile = NULL; + + if (argc != 3) { + printf ("Usage: EFICOMPRESS \n"); + goto Done; + } + + if ((outfile = fopen (argv[2], "wb")) == NULL) { + printf ("Can't open output file\n"); + goto Done; + } + + if ((infile = fopen (argv[1], "rb")) == NULL) { + printf ("Can't open input file\n"); + goto Done; + } + // + // Get the size of source file + // + SrcSize = 0; + while (fread (Buffer, 1, 1, infile)) { + SrcSize++; + + } + // + // Read in the source data + // + if ((SrcBuffer = malloc (SrcSize)) == NULL) { + printf ("Can't allocate memory\n"); + goto Done; + } + + rewind (infile); + if (fread (SrcBuffer, 1, SrcSize, infile) != SrcSize) { + printf ("Can't read from source\n"); + goto Done; + } + // + // Get destination data size and do the compression + // + DstSize = 0; + Status = Compress (SrcBuffer, SrcSize, DstBuffer, &DstSize); + if (Status == EFI_BUFFER_TOO_SMALL) { + if ((DstBuffer = malloc (DstSize)) == NULL) { + printf ("Can't allocate memory\n"); + goto Done; + } + + Status = Compress (SrcBuffer, SrcSize, DstBuffer, &DstSize); + } + + if (EFI_ERROR (Status)) { + printf ("Compress Error\n"); + goto Done; + } + + printf ("\nOrig Size = %ld\n", SrcSize); + printf ("Comp Size = %ld\n", DstSize); + + if (DstBuffer == NULL) { + printf ("No destination to write to.\n"); + goto Done; + } + // + // Write out the result + // + if (fwrite (DstBuffer, 1, DstSize, outfile) != DstSize) { + printf ("Can't write to destination file\n"); + } + +Done: + if (SrcBuffer) { + free (SrcBuffer); + } + + if (DstBuffer) { + free (DstBuffer); + } + + if (infile) { + fclose (infile); + } + + if (outfile) { + fclose (outfile); + } + + return 0; +} diff --git a/Tools/Source/TianoTools/EfiCompress/makefile b/Tools/Source/TianoTools/EfiCompress/makefile new file mode 100644 index 0000000000..b20a21947d --- /dev/null +++ b/Tools/Source/TianoTools/EfiCompress/makefile @@ -0,0 +1,77 @@ +#/*++ +# +# Copyright (c) 2001 Intel Corporation. All rights reserved. +# +# This software and associated documentation (if any) is furnished under +# a license and may only be used or copied in accordance with the terms +# of the license. Except as permitted by such license, no part of this +# software or documentation may be reproduced, stored in a retrieval +# system, or transmitted in any form or by any means without the express +# written consent of Intel Corporation. +# +# Module Name: makefile +# +# Abstract: +# +# This file is used to build the EFI utility. +# +#--*/ + +# +# Do this if you want to compile from this directory +# +!IFNDEF TOOLCHAIN +TOOLCHAIN = TOOLCHAIN_MSVC +!ENDIF + +!INCLUDE PlatformTools.env + +# +# Define some macros we use here. Should get rid of them someday and +# get rid of the extra level of indirection. +# +COMMON_SOURCE = $(EDK_TOOLS_COMMON) + +# +# BUGBUG: Override standard flags, cannot be built without warnings. +# + +C_FLAGS=/nologo /W4 /GX /Zi /Od /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /c + +# +# Common information +# + +INC=$(INC) + +# +# Target specific information +# + +TARGET_NAME=EfiCompress +TARGET_SOURCE_DIR = $(TIANO_TOOLS_SOURCE)\$(TARGET_NAME) + +TARGET_EXE = $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).exe + +TARGET_EXE_SOURCE = "$(TARGET_SOURCE_DIR)\EfiCompressMain.c" +TARGET_EXE_INCLUDE = "$(COMMON_SOURCE)\EfiCompress.h" +TARGET_EXE_LIBS = "$(TIANO_TOOLS_OUTPUT)\Common.lib" + +# +# Build targets +# + +all: $(TARGET_EXE) + +# +# Build EXE +# + +$(TIANO_TOOLS_OUTPUT)\EfiCompressMain.obj: $(TARGET_EXE_SOURCE) $(TARGET_EXE_INCLUDE) + $(CC) $(C_FLAGS) $(INC) $(TARGET_EXE_SOURCE) /Fo$(TIANO_TOOLS_OUTPUT)\EfiCompressMain.obj + +$(TARGET_EXE): $(TIANO_TOOLS_OUTPUT)\EfiCompressMain.obj $(TARGET_EXE_LIBS) $(TARGET_DLL) + $(LINK) $(MSVS_LINK_LIBPATHS) $(L_FLAGS) $(LIBS) /out:$(TARGET_EXE) $(TIANO_TOOLS_OUTPUT)\EfiCompressMain.obj $(TARGET_LIB) $(TARGET_EXE_LIBS) + +clean: + @if exist $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME)Main.* del /q $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME)Main.* > NUL diff --git a/Tools/Source/TianoTools/EfiRom/EfiRom.c b/Tools/Source/TianoTools/EfiRom/EfiRom.c new file mode 100644 index 0000000000..fc168ed14b --- /dev/null +++ b/Tools/Source/TianoTools/EfiRom/EfiRom.c @@ -0,0 +1,1543 @@ +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + EfiRom.c + +Abstract: + + Utility program to create an EFI option ROM image from binary and + EFI PE32 files. + + +--*/ + +#include +#include +#include + +// +// Includes for EFI 1.1 build +// +// #include "Tiano.h" // required defines for Compress.h +// #include "EfiImage.h" // for PE32 structure definitions +// #include "Compress.h" // for compression function +// Includes for Tiano build +// +#include "TianoCommon.h" +#include "EfiImage.h" // for PE32 structure definitions +#include "EfiCompress.h" + +// +// END include differences +// +#include "Pci22.h" // for option ROM header structures +// +// Version of this utility +// +#define UTILITY_VERSION "v2.5" + +// +// Define some status return values +// +#define STATUS_SUCCESS 0 +#define STATUS_WARNING 1 +#define STATUS_ERROR 2 + +// +// Define the max length of a filename +// +#define MAX_PATH 200 + +#define DEFAULT_OUTPUT_EXTENSION ".rom" + +// +// Max size for an option ROM image +// +#define MAX_OPTION_ROM_SIZE (1024 * 1024 * 16) // 16MB +// +// Values for the indicator field in the PCI data structure +// +#define INDICATOR_LAST 0x80 // last file in series of files +// +// Masks for the FILE_LIST.FileFlags field +// +#define FILE_FLAG_BINARY 0x01 +#define FILE_FLAG_EFI 0x02 +#define FILE_FLAG_COMPRESS 0x04 + +// +// Use this linked list structure to keep track of all the filenames +// specified on the command line. +// +typedef struct _FILE_LIST { + struct _FILE_LIST *Next; + INT8 *FileName; + UINT32 FileFlags; + UINT32 ClassCode; + UINT16 CodeRevision; +} FILE_LIST; + +// +// Use this to track our command-line options +// +typedef struct { + INT8 OutFileName[MAX_PATH]; + INT8 NoLast; + INT8 Verbose; + INT8 DumpOption; + UINT8 DevIdValid; + UINT8 VendIdValid; + UINT16 VendId; + UINT16 DevId; + FILE_LIST *FileList; +} OPTIONS; + +// +// Make a global structure to keep track of command-line options +// +static OPTIONS mOptions; + +// +// Use these to convert from machine type value to a named type +// +typedef struct { + UINT16 Value; + char *Name; +} STRING_LOOKUP; + +static STRING_LOOKUP mMachineTypes[] = { + EFI_IMAGE_MACHINE_IA32, + "IA32", + EFI_IMAGE_MACHINE_IA64, + "IA64", + EFI_IMAGE_MACHINE_EBC, + "EBC", + 0, + NULL +}; + +static STRING_LOOKUP mSubsystemTypes[] = { + EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION, + "EFI application", + EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, + "EFI boot service driver", + EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER, + "EFI runtime driver", + 0, + NULL +}; +// +// Function prototypes +// +static +void +Usage ( + VOID + ); + +static +int +ParseCommandLine ( + int Argc, + char *Argv[], + OPTIONS *Options + ); + +static +int +CheckPE32File ( + FILE *Fptr, + UINT16 *MachineType, + UINT16 *SubSystem + ); + +static +int +ProcessEfiFile ( + FILE *OutFptr, + FILE_LIST *InFile, + UINT16 VendId, + UINT16 DevId, + UINT32 *Size + ); + +static +int +ProcessBinFile ( + FILE *OutFptr, + FILE_LIST *InFile, + UINT32 *Size + ); + +static +void +DumpImage ( + FILE_LIST *InFile + ); + +char * +GetMachineTypeStr ( + UINT16 MachineType + ); + +static +char * +GetSubsystemTypeStr ( + UINT16 SubsystemType + ); + +main ( + int Argc, + char *Argv[] + ) +/*++ + +Routine Description: + + Given an EFI image filename, create a ROM-able image by creating an option + ROM header and PCI data structure, filling them in, and then writing the + option ROM header + PCI data structure + EFI image out to the output file. + +Arguments: + + Argc - standard C main() argument count + + Argv - standard C main() argument list + +Returns: + + 0 success + non-zero otherwise + +--*/ +// GC_TODO: ] - add argument and description to function comment +{ + INT8 *Ext; + FILE *FptrOut; + UINT32 Status; + FILE_LIST *FList; + UINT32 TotalSize; + UINT32 Size; + + Status = STATUS_SUCCESS; + FptrOut = NULL; + + // + // Parse the command line arguments + // + if (ParseCommandLine (Argc, Argv, &mOptions)) { + return STATUS_ERROR; + } + // + // If dumping an image, then do that and quit + // + if (mOptions.DumpOption) { + DumpImage (mOptions.FileList); + goto BailOut; + } + // + // Determine the output filename. Either what they specified on + // the command line, or the first input filename with a different extension. + // + if (!mOptions.OutFileName[0]) { + strcpy (mOptions.OutFileName, mOptions.FileList->FileName); + // + // Find the last . on the line and replace the filename extension with + // the default + // + for (Ext = mOptions.OutFileName + strlen (mOptions.OutFileName) - 1; + (Ext >= mOptions.OutFileName) && (*Ext != '.') && (*Ext != '\\'); + Ext-- + ) + ; + // + // If dot here, then insert extension here, otherwise append + // + if (*Ext != '.') { + Ext = mOptions.OutFileName + strlen (mOptions.OutFileName); + } + + strcpy (Ext, DEFAULT_OUTPUT_EXTENSION); + } + // + // Make sure we don't have the same filename for input and output files + // + for (FList = mOptions.FileList; FList != NULL; FList = FList->Next) { + if (stricmp (mOptions.OutFileName, FList->FileName) == 0) { + Status = STATUS_ERROR; + fprintf ( + stdout, + "ERROR: Input and output file names must be different - %s = %s\n", + FList->FileName, + mOptions.OutFileName + ); + goto BailOut; + } + } + // + // Now open our output file + // + if ((FptrOut = fopen (mOptions.OutFileName, "w+b")) == NULL) { + fprintf (stdout, "ERROR: Failed to open output file %s\n", mOptions.OutFileName); + goto BailOut; + } + // + // Process all our files + // + TotalSize = 0; + for (FList = mOptions.FileList; FList != NULL; FList = FList->Next) { + Size = 0; + if (FList->FileFlags & FILE_FLAG_EFI) { + if (mOptions.Verbose) { + fprintf (stdout, "Processing EFI file %s\n", FList->FileName); + } + + Status = ProcessEfiFile (FptrOut, FList, mOptions.VendId, mOptions.DevId, &Size); + } else if (FList->FileFlags & FILE_FLAG_BINARY) { + if (mOptions.Verbose) { + fprintf (stdout, "Processing binary file %s\n", FList->FileName); + } + + Status = ProcessBinFile (FptrOut, FList, &Size); + } else { + fprintf (stdout, "ERROR: File not specified as EFI or binary: %s\n", FList->FileName); + Status = STATUS_ERROR; + } + + if (mOptions.Verbose) { + fprintf (stdout, " Output size = 0x%X\n", Size); + } + + if (Status != STATUS_SUCCESS) { + break; + } + + TotalSize += Size; + } + // + // Check total size + // + if (TotalSize > MAX_OPTION_ROM_SIZE) { + fprintf ( + stdout, + "ERROR: Option ROM image size exceeds limit 0x%X bytes\n", + MAX_OPTION_ROM_SIZE + ); + Status = STATUS_ERROR; + } + +BailOut: + if (FptrOut != NULL) { + fclose (FptrOut); + } + // + // Clean up our file list + // + while (mOptions.FileList != NULL) { + FList = mOptions.FileList->Next; + free (mOptions.FileList); + mOptions.FileList = FList; + } + + return Status; +} + +static +int +ProcessBinFile ( + FILE *OutFptr, + FILE_LIST *InFile, + UINT32 *Size + ) +/*++ + +Routine Description: + + Process a binary input file. + +Arguments: + + OutFptr - file pointer to output binary ROM image file we're creating + InFile - structure contains information on the binary file to process + Size - pointer to where to return the size added to the output file + +Returns: + + 0 - successful + +--*/ +{ + FILE *InFptr; + UINT32 TotalSize; + UINT32 FileSize; + UINT8 *Buffer; + UINT32 Status; + PCI_EXPANSION_ROM_HEADER *RomHdr; + PCI_DATA_STRUCTURE *PciDs; + UINT32 Index; + UINT8 ByteCheckSum; + + Status = STATUS_SUCCESS; + + // + // Try to open the input file + // + if ((InFptr = fopen (InFile->FileName, "rb")) == NULL) { + fprintf (stdout, "ERROR: Failed to open input file %s\n", InFile->FileName); + return STATUS_ERROR; + } + // + // Seek to the end of the input file and get the file size. Then allocate + // a buffer to read it in to. + // + fseek (InFptr, 0, SEEK_END); + FileSize = ftell (InFptr); + if (mOptions.Verbose) { + fprintf (stdout, " File size = 0x%X\n", FileSize); + } + + fseek (InFptr, 0, SEEK_SET); + Buffer = (INT8 *) malloc (FileSize); + if (Buffer == NULL) { + fprintf (stdout, "ERROR: Memory allocation failed\n"); + Status = STATUS_ERROR; + goto BailOut; + } + + if (fread (Buffer, FileSize, 1, InFptr) != 1) { + fprintf (stdout, "ERROR: Failed to read all bytes from input file\n"); + Status = STATUS_ERROR; + goto BailOut; + } + // + // Total size must be an even multiple of 512 bytes, and can't exceed + // the option ROM image size. + // + TotalSize = FileSize; + if (TotalSize & 0x1FF) { + TotalSize = (TotalSize + 0x200) &~0x1ff; + } + + if (TotalSize > MAX_OPTION_ROM_SIZE) { + fprintf ( + stdout, + "ERROR: Option ROM image %s size exceeds limit 0x%X bytes\n", + InFile->FileName, + MAX_OPTION_ROM_SIZE + ); + Status = STATUS_ERROR; + goto BailOut; + } + // + // Return the size to the caller so they can keep track of the running total. + // + *Size = TotalSize; + + // + // Crude check to make sure it's a legitimate ROM image + // + RomHdr = (PCI_EXPANSION_ROM_HEADER *) Buffer; + if (RomHdr->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) { + fprintf (stdout, "ERROR: ROM image file has invalid ROM signature\n"); + Status = STATUS_ERROR; + goto BailOut; + } + // + // Make sure the pointer to the PCI data structure is within the size of the image. + // Then check it for valid signature. + // + if ((RomHdr->PcirOffset > FileSize) || (RomHdr->PcirOffset == 0)) { + fprintf (stdout, "ERROR: Invalid PCI data structure offset\n"); + Status = STATUS_ERROR; + goto BailOut; + } + + PciDs = (PCI_DATA_STRUCTURE *) (Buffer + RomHdr->PcirOffset); + if (PciDs->Signature != PCI_DATA_STRUCTURE_SIGNATURE) { + fprintf (stdout, "ERROR: PCI data structure has invalid signature\n"); + Status = STATUS_ERROR; + goto BailOut; + } + // + // If this is the last image, then set the LAST bit unless requested not + // to via the command-line -l argument. Otherwise, make sure you clear it. + // + if ((InFile->Next == NULL) && (mOptions.NoLast == 0)) { + PciDs->Indicator = INDICATOR_LAST; + } else { + PciDs->Indicator = 0; + } + + ByteCheckSum = 0; + for (Index = 0; Index < FileSize - 1; Index++) { + ByteCheckSum = (UINT8) (ByteCheckSum + Buffer[Index]); + } + + Buffer[FileSize - 1] = (UINT8) ((~ByteCheckSum) + 1); + fprintf (stdout, "CheckSUm = %02x\n", (UINT32) Buffer[FileSize - 1]); + + // + // Now copy the input file contents out to the output file + // + if (fwrite (Buffer, FileSize, 1, OutFptr) != 1) { + fprintf (stdout, "ERROR: Failed to write all file bytes to output file\n"); + Status = STATUS_ERROR; + goto BailOut; + } + + TotalSize -= FileSize; + // + // Pad the rest of the image to make it a multiple of 512 bytes + // + while (TotalSize > 0) { + putc (~0, OutFptr); + TotalSize--; + } + +BailOut: + if (InFptr != NULL) { + fclose (InFptr); + } + + if (Buffer != NULL) { + free (Buffer); + } + // + // Print the file name if errors occurred + // + if (Status != STATUS_SUCCESS) { + fprintf (stdout, "Error processing binary file %s\n", InFile->FileName); + } + + return Status; +} + +static +int +ProcessEfiFile ( + FILE *OutFptr, + FILE_LIST *InFile, + UINT16 VendId, + UINT16 DevId, + UINT32 *Size + ) +/*++ + +Routine Description: + + Process a PE32 EFI file. + +Arguments: + + OutFptr - file pointer to output binary ROM image file we're creating + InFile - structure contains information on the PE32 file to process + VendId - vendor ID as required in the option ROM header + DevId - device ID as required in the option ROM header + Size - pointer to where to return the size added to the output file + +Returns: + + 0 - successful + +--*/ +{ + UINT32 Status; + FILE *InFptr; + EFI_PCI_EXPANSION_ROM_HEADER RomHdr; + PCI_DATA_STRUCTURE PciDs; + UINT32 FileSize; + UINT32 CompressedFileSize; + UINT8 *Buffer; + UINT8 *CompressedBuffer; + UINT8 *TempBufferPtr; + UINT32 TotalSize; + UINT32 HeaderSize; + UINT16 MachineType; + UINT16 SubSystem; + UINT32 HeaderPadBytes; + + // + // Try to open the input file + // + if ((InFptr = fopen (InFile->FileName, "rb")) == NULL) { + fprintf (stdout, "ERROR: Failed to open input file %s\n", InFile->FileName); + return STATUS_ERROR; + } + // + // Initialize our buffer pointers to null. + // + Buffer = NULL; + CompressedBuffer = NULL; + + // + // Double-check the file to make sure it's what we expect it to be + // + Status = CheckPE32File (InFptr, &MachineType, &SubSystem); + if (Status != STATUS_SUCCESS) { + goto BailOut; + } + // + // Seek to the end of the input file and get the file size + // + fseek (InFptr, 0, SEEK_END); + FileSize = ftell (InFptr); + + // + // Get the size of the headers we're going to put in front of the image. The + // EFI header must be aligned on a 4-byte boundary, so pad accordingly. + // + if (sizeof (RomHdr) & 0x03) { + HeaderPadBytes = 4 - (sizeof (RomHdr) & 0x03); + } else { + HeaderPadBytes = 0; + } + + HeaderSize = sizeof (PCI_DATA_STRUCTURE) + HeaderPadBytes + sizeof (EFI_PCI_EXPANSION_ROM_HEADER); + if (mOptions.Verbose) { + fprintf (stdout, " File size = 0x%X\n", FileSize); + } + // + // Allocate memory for the entire file (in case we have to compress), then + // seek back to the beginning of the file and read it into our buffer. + // + Buffer = (INT8 *) malloc (FileSize); + if (Buffer == NULL) { + fprintf (stdout, "ERROR: Memory allocation failed\n"); + Status = STATUS_ERROR; + goto BailOut; + } + + fseek (InFptr, 0, SEEK_SET); + if (fread (Buffer, FileSize, 1, InFptr) != 1) { + fprintf (stdout, "ERROR: Failed to read all bytes from input file\n"); + Status = STATUS_ERROR; + goto BailOut; + } + // + // Now determine the size of the final output file. It's either the header size + // plus the file's size, or the header size plus the compressed file size. + // + if (InFile->FileFlags & FILE_FLAG_COMPRESS) { + // + // Allocate a buffer into which we can compress the image, compress it, + // and use that size as the new size. + // + CompressedBuffer = (INT8 *) malloc (FileSize); + if (CompressedBuffer == NULL) { + fprintf (stdout, "ERROR: Memory allocation failed\n"); + Status = STATUS_ERROR; + goto BailOut; + } + + CompressedFileSize = FileSize; + Status = Compress (Buffer, FileSize, CompressedBuffer, &CompressedFileSize); + if (Status != STATUS_SUCCESS) { + fprintf (stdout, "ERROR: Compression failed\n"); + goto BailOut; + } + // + // Now compute the size, then swap buffer pointers. + // + if (mOptions.Verbose) { + fprintf (stdout, " Comp size = 0x%X\n", CompressedFileSize); + } + + TotalSize = CompressedFileSize + HeaderSize; + FileSize = CompressedFileSize; + TempBufferPtr = Buffer; + Buffer = CompressedBuffer; + CompressedBuffer = TempBufferPtr; + } else { + TotalSize = FileSize + HeaderSize; + } + // + // Total size must be an even multiple of 512 bytes + // + if (TotalSize & 0x1FF) { + TotalSize = (TotalSize + 0x200) &~0x1ff; + } + // + // Check size + // + if (TotalSize > MAX_OPTION_ROM_SIZE) { + fprintf ( + stdout, + "ERROR: Option ROM image %s size exceeds limit 0x%X bytes\n", + InFile->FileName, + MAX_OPTION_ROM_SIZE + ); + Status = STATUS_ERROR; + goto BailOut; + } + // + // Return the size to the caller so they can keep track of the running total. + // + *Size = TotalSize; + + // + // Now fill in the ROM header. These values come from chapter 18 of the + // EFI 1.02 specification. + // + memset (&RomHdr, 0, sizeof (RomHdr)); + RomHdr.Signature = PCI_EXPANSION_ROM_HEADER_SIGNATURE; + RomHdr.InitializationSize = (UINT16) (TotalSize / 512); + RomHdr.EfiSignature = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE; + RomHdr.EfiSubsystem = SubSystem; + RomHdr.EfiMachineType = MachineType; + RomHdr.EfiImageHeaderOffset = (UINT16) HeaderSize; + RomHdr.PcirOffset = (UINT16) (sizeof (RomHdr) + HeaderPadBytes); + // + // Set image as compressed or not + // + if (InFile->FileFlags & FILE_FLAG_COMPRESS) { + RomHdr.CompressionType = EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED; + } + // + // Fill in the PCI data structure + // + memset (&PciDs, 0, sizeof (PCI_DATA_STRUCTURE)); + + PciDs.Signature = PCI_DATA_STRUCTURE_SIGNATURE; + PciDs.VendorId = VendId; + PciDs.DeviceId = DevId; + PciDs.Length = (UINT16) sizeof (PCI_DATA_STRUCTURE); + PciDs.Revision = 0; + // + // Class code and code revision from the command line (optional) + // + PciDs.ClassCode[0] = (UINT8) InFile->ClassCode; + PciDs.ClassCode[1] = (UINT8) (InFile->ClassCode >> 8); + PciDs.ClassCode[2] = (UINT8) (InFile->ClassCode >> 16); + PciDs.ImageLength = RomHdr.InitializationSize; + PciDs.CodeRevision = InFile->CodeRevision; + PciDs.CodeType = PCI_CODE_TYPE_EFI_IMAGE; + + // + // If this is the last image, then set the LAST bit unless requested not + // to via the command-line -l argument. + // + if ((InFile->Next == NULL) && (mOptions.NoLast == 0)) { + PciDs.Indicator = INDICATOR_LAST; + } + // + // Write the ROM header to the output file + // + if (fwrite (&RomHdr, sizeof (RomHdr), 1, OutFptr) != 1) { + fprintf (stdout, "ERROR: Failed to write ROM header to output file\n"); + Status = STATUS_ERROR; + goto BailOut; + } + + // + // Write pad bytes to align the PciDs + // + while (HeaderPadBytes > 0) { + if (putc (0, OutFptr) == EOF) { + fprintf (stdout, "ERROR: Failed to write ROM header pad bytes to output file\n"); + Status = STATUS_ERROR; + goto BailOut; + } + + HeaderPadBytes--; + } + // + // Write the PCI data structure header to the output file + // + if (fwrite (&PciDs, sizeof (PciDs), 1, OutFptr) != 1) { + fprintf (stdout, "ERROR: Failed to write PCI ROM header to output file\n"); + Status = STATUS_ERROR; + goto BailOut; + } + // + // Keep track of how many bytes left to write + // + TotalSize -= HeaderSize; + + // + // Now dump the input file's contents to the output file + // + if (fwrite (Buffer, FileSize, 1, OutFptr) != 1) { + fprintf (stdout, "ERROR: Failed to write all file bytes to output file\n"); + Status = STATUS_ERROR; + goto BailOut; + } + + TotalSize -= FileSize; + // + // Pad the rest of the image to make it a multiple of 512 bytes + // + while (TotalSize > 0) { + if (putc (~0, OutFptr) == EOF) { + fprintf (stdout, "ERROR: Failed to write trailing pad bytes output file\n"); + Status = STATUS_ERROR; + goto BailOut; + } + + TotalSize--; + } + +BailOut: + if (InFptr != NULL) { + fclose (InFptr); + } + + // + // Free up our buffers + // + if (Buffer != NULL) { + free (Buffer); + } + + if (CompressedBuffer != NULL) { + free (CompressedBuffer); + } + // + // Print the file name if errors occurred + // + if (Status != STATUS_SUCCESS) { + fprintf (stdout, "Error processing EFI file %s\n", InFile->FileName); + } + + return Status; +} + +static +int +CheckPE32File ( + FILE *Fptr, + UINT16 *MachineType, + UINT16 *SubSystem + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Fptr - GC_TODO: add argument description + MachineType - GC_TODO: add argument description + SubSystem - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + /*++ + +Routine Description: + + Given a file pointer to a supposed PE32 image file, verify that it is indeed a + PE32 image file, and then return the machine type in the supplied pointer. + +Arguments: + + Fptr File pointer to the already-opened PE32 file + MachineType Location to stuff the machine type of the PE32 file. This is needed + because the image may be Itanium-based, IA32, or EBC. + +Returns: + + 0 success + non-zero otherwise + +--*/ + EFI_IMAGE_DOS_HEADER DosHeader; + EFI_IMAGE_FILE_HEADER FileHdr; + EFI_IMAGE_OPTIONAL_HEADER OptionalHdr; + UINT32 PESig; + + // + // Position to the start of the file + // + fseek (Fptr, 0, SEEK_SET); + + // + // Read the DOS header + // + if (fread (&DosHeader, sizeof (DosHeader), 1, Fptr) != 1) { + fprintf (stdout, "ERROR: Failed to read the DOS stub from the input file\n"); + return STATUS_ERROR; + } + // + // Check the magic number (0x5A4D) + // + if (DosHeader.e_magic != EFI_IMAGE_DOS_SIGNATURE) { + fprintf (stdout, "ERROR: Input file does not appear to be a PE32 image (magic number)\n"); + return STATUS_ERROR; + } + // + // Position into the file and check the PE signature + // + fseek (Fptr, (long) DosHeader.e_lfanew, SEEK_SET); + if (fread (&PESig, sizeof (PESig), 1, Fptr) != 1) { + fprintf (stdout, "ERROR: Failed to read PE signature bytes from input file\n"); + return STATUS_ERROR; + } + // + // Check the PE signature in the header "PE\0\0" + // + if (PESig != EFI_IMAGE_NT_SIGNATURE) { + fprintf (stdout, "ERROR: Input file does not appear to be a PE32 image (signature)\n"); + return STATUS_ERROR; + } + // + // Read the file header and stuff their MachineType + // + if (fread (&FileHdr, sizeof (FileHdr), 1, Fptr) != 1) { + fprintf (stdout, "ERROR: Failed to read PE file header from input file\n"); + return STATUS_ERROR; + } + + memcpy ((char *) MachineType, &FileHdr.Machine, 2); + + // + // Read the optional header so we can get the subsystem + // + if (fread (&OptionalHdr, sizeof (OptionalHdr), 1, Fptr) != 1) { + fprintf (stdout, "ERROR: Failed to read COFF optional header from input file\n"); + return STATUS_ERROR; + } + + *SubSystem = OptionalHdr.Subsystem; + if (mOptions.Verbose) { + fprintf (stdout, " Got subsystem = 0x%X from image\n", (int) *SubSystem); + } + // + // Good to go + // + return STATUS_SUCCESS; +} + +static +int +ParseCommandLine ( + int Argc, + char *Argv[], + OPTIONS *Options + ) +/*++ + +Routine Description: + + Given the Argc/Argv program arguments, and a pointer to an options structure, + parse the command-line options and check their validity. + + +Arguments: + + Argc - standard C main() argument count + Argv[] - standard C main() argument list + Options - pointer to a structure to store the options in + +Returns: + + STATUS_SUCCESS success + non-zero otherwise + +--*/ +// +{ + FILE_LIST *FileList; + + FILE_LIST *PrevFileList; + UINT32 FileFlags; + UINT32 ClassCode; + UINT32 CodeRevision; + + FileFlags = 0; + + // + // Clear out the options + // + memset ((char *) Options, 0, sizeof (OPTIONS)); + + // + // To avoid compile warnings + // + FileList = PrevFileList = NULL; + + ClassCode = 0; + CodeRevision = 0; + // + // Skip over the program name + // + Argc--; + Argv++; + + // + // If no arguments, assume they want usage info + // + if (Argc == 0) { + Usage (); + return STATUS_ERROR; + } + // + // Process until no more arguments + // + while (Argc > 0) { + if ((Argv[0][0] == '-') || (Argv[0][0] == '/')) { + // + // To simplify string comparisons, replace slashes with dashes + // + Argv[0][0] = '-'; + + // + // Vendor ID specified with -v + // + if (stricmp (Argv[0], "-v") == 0) { + // + // Make sure there's another parameter + // + if (Argc > 1) { + Options->VendId = (UINT16) strtol (Argv[1], NULL, 16); + Options->VendIdValid = 1; + } else { + fprintf ( + stdout, + "ERROR: Missing Vendor ID with %s\n\n", + Argv[0] + ); + Usage (); + return STATUS_ERROR; + } + + Argv++; + Argc--; + } else if (stricmp (Argv[0], "-d") == 0) { + // + // Device ID specified with -d + // Make sure there's another parameter + // + if (Argc > 1) { + Options->DevId = (UINT16) strtol (Argv[1], NULL, 16); + Options->DevIdValid = 1; + } else { + fprintf ( + stdout, + "ERROR: Missing Device ID with %s\n\n", + Argv[0] + ); + Usage (); + return STATUS_ERROR; + } + + Argv++; + Argc--; + } else if (stricmp (Argv[0], "-o") == 0) { + // + // Output filename specified with -o + // Make sure there's another parameter + // + if (Argc > 1) { + strcpy (Options->OutFileName, Argv[1]); + } else { + fprintf ( + stdout, + "ERROR: Missing output file name with %s\n\n", + Argv[0] + ); + Usage (); + return STATUS_ERROR; + } + + Argv++; + Argc--; + } else if ((stricmp (Argv[0], "-h") == 0) || (strcmp (Argv[0], "-?") == 0)) { + // + // Help option + // + Usage (); + return STATUS_ERROR; + } else if (stricmp (Argv[0], "-b") == 0) { + // + // Specify binary files with -b + // + FileFlags = (FileFlags &~FILE_FLAG_EFI) | FILE_FLAG_BINARY; + } else if ((stricmp (Argv[0], "-e") == 0) || (stricmp (Argv[0], "-ec") == 0)) { + // + // Specify EFI files with -e. Specify EFI-compressed with -ec. + // + FileFlags = (FileFlags &~FILE_FLAG_BINARY) | FILE_FLAG_EFI; + if ((Argv[0][2] == 'c') || (Argv[0][2] == 'C')) { + FileFlags |= FILE_FLAG_COMPRESS; + } + // + // Specify not to set the LAST bit in the last file with -l + // + } else if (stricmp (Argv[0], "-l") == 0) { + Options->NoLast = 1; + } else if (stricmp (Argv[0], "-p") == 0) { + // + // -v for verbose would have been nicer, but it's already used. Let's use + // -p for prolix (wordy) output + // + Options->Verbose = 1; + } else if (stricmp (Argv[0], "-dump") == 0) { + // + // -dump for dumping a ROM image. In this case, say that the device id + // and vendor id are valid so we don't have to specify bogus ones on the + // command line. + // + Options->DumpOption = 1; + + Options->VendIdValid = 1; + Options->DevIdValid = 1; + FileFlags = FILE_FLAG_BINARY; + } else if (stricmp (Argv[0], "-cc") == 0) { + // + // Class code value for the next file in the list. + // Make sure there's another parameter + // + if (Argc > 1) { + // + // No error checking on the return value. Could check for LONG_MAX, + // LONG_MIN, or 0 class code value if desired. Check range (3 bytes) + // at least. + // + ClassCode = (UINT32) strtol (Argv[1], NULL, 16); + if (ClassCode & 0xFF000000) { + fprintf (stdout, "ERROR: Class code %s out of range\n", Argv[1]); + return STATUS_ERROR; + } + } else { + fprintf ( + stdout, + "ERROR: Missing class code value with %s\n\n", + Argv[0] + ); + Usage (); + return STATUS_ERROR; + } + + Argv++; + Argc--; + } else if (stricmp (Argv[0], "-rev") == 0) { + // + // Code revision in the PCI data structure. The value is for the next + // file in the list. + // Make sure there's another parameter + // + if (Argc > 1) { + // + // No error checking on the return value. Could check for LONG_MAX, + // LONG_MIN, or 0 value if desired. Check range (2 bytes) + // at least. + // + CodeRevision = (UINT32) strtol (Argv[1], NULL, 16); + if (CodeRevision & 0xFFFF0000) { + fprintf (stdout, "ERROR: Code revision %s out of range\n", Argv[1]); + return STATUS_ERROR; + } + } else { + fprintf ( + stdout, + "ERROR: Missing code revision value with %s\n\n", + Argv[0] + ); + Usage (); + return STATUS_ERROR; + } + + Argv++; + Argc--; + } else { + fprintf (stdout, "ERROR: Invalid option specified: %s\n\n", Argv[0]); + Usage (); + return STATUS_ERROR; + } + } else { + // + // Not a slash-option argument. Must be a file name. Make sure they've specified + // -e or -b already. + // + if ((FileFlags & (FILE_FLAG_BINARY | FILE_FLAG_EFI)) == 0) { + fprintf (stdout, "ERROR: Missing -e or -b with input file %s\n", Argv[0]); + return STATUS_ERROR; + } + // + // Create a new file structure + // + FileList = (FILE_LIST *) malloc (sizeof (FILE_LIST)); + if (FileList == NULL) { + fprintf (stdout, "ERROR: Memory allocation failure\n"); + return STATUS_ERROR; + } + + memset ((char *) FileList, 0, sizeof (FILE_LIST)); + FileList->FileName = Argv[0]; + FileList->FileFlags = FileFlags; + if (Options->FileList == NULL) { + Options->FileList = FileList; + } else { + if (PrevFileList == NULL) { + PrevFileList = FileList; + } else { + PrevFileList->Next = FileList; + } + } + + PrevFileList = FileList; + // + // Set the class code and code revision for this file, then reset the values. + // + FileList->ClassCode = ClassCode; + FileList->CodeRevision = (UINT16) CodeRevision; + ClassCode = 0; + CodeRevision = 0; + } + // + // Next argument + // + Argv++; + Argc--; + } + // + // Make sure they specified a device ID and vendor ID + // + if (!Options->VendIdValid) { + fprintf (stdout, "ERROR: Missing Vendor ID on command line\n\n"); + Usage (); + return STATUS_ERROR; + } + + if (!Options->DevIdValid) { + fprintf (stdout, "ERROR: Missing Device ID on command line\n\n"); + Usage (); + return STATUS_ERROR; + } + // + // Must have specified some files + // + if (Options->FileList == NULL) { + fprintf (stdout, "ERROR: Missing input file name\n"); + Usage (); + return STATUS_ERROR; + } + + return 0; +} + +static +void +Usage ( + VOID + ) +/*++ + +Routine Description: + + Print usage information for this utility. + +Arguments: + + None. + +Returns: + + Nothing. + +--*/ +{ + int Index; + static const char *Msg[] = { + "EfiRom "UTILITY_VERSION " - Intel EFI Make Option ROM utility", + " Copyright (C), 1999-2002 Intel Coproration\n", + " Create an option ROM image from a list of input files", + " Usage: efirom {-p} [-v VendorId] [-d DeviceId] {-o OutFileName} ", + " [-e|-b] [FileName(s)]", + " where:", + " VendorId - required hex PCI Vendor ID for the device", + " DeviceId - required hex PCI Device ID for the device", + " OutFileName - optional output file name. Default is the first input", + " file name with a "DEFAULT_OUTPUT_EXTENSION " file extension", + " FileNames - input PE32 or binary file name(s)", + " BinFileName - input binary file name(s)", + " -p - for verbose output", + " -l - to not automatically set the LAST bit on the last file", + " -b - following FileNames are binary files", + " -e - following FileNames are EFI PE32 image files", + " -ec - following FileNames are EFI PE32 image files, and should", + " be compressed by this utility", + " -cc ClassCode - to use hex ClassCode in the PCI data structure header for", + " the following FileName", + " -rev Revision - to use hex Revision in the PCI data structure header for", + " the following FileName", + " -dump - to dump the headers of an existing option ROM image", + "", + "Example usage: EfiRom -v 0xABCD -d 0x1234 -b File1.bin File2.bin -e File1.efi File2.efi ", + "", + NULL + }; + + for (Index = 0; Msg[Index] != NULL; Index++) { + fprintf (stdout, "%s\n", Msg[Index]); + } +} + +static +void +DumpImage ( + FILE_LIST *InFile + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + InFile - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + PCI_EXPANSION_ROM_HEADER PciRomHdr; + FILE *InFptr; + UINT32 ImageStart; + UINT32 ImageCount; + EFI_PCI_EXPANSION_ROM_HEADER EfiRomHdr; + PCI_DATA_STRUCTURE PciDs; + + // + // Open the input file + // + if ((InFptr = fopen (InFile->FileName, "rb")) == NULL) { + fprintf ( + stdout, + "ERROR: Could not open input file %s\n", + InFile->FileName + ); + return ; + } + // + // Go through the image and dump the header stuff for each + // + ImageCount = 0; + for (;;) { + // + // Save our postition in the file, since offsets in the headers + // are relative to the particular image. + // + ImageStart = ftell (InFptr); + ImageCount++; + + // + // Read the option ROM header. Have to assume a raw binary image for now. + // + if (fread (&PciRomHdr, sizeof (PciRomHdr), 1, InFptr) != 1) { + fprintf (stdout, "ERROR: Failed to read PCI ROM header from file\n"); + goto BailOut; + } + + // + // Dump the contents of the header + // + fprintf (stdout, "Image %d -- Offset 0x%X\n", ImageCount, ImageStart); + fprintf (stdout, " ROM header contents\n"); + fprintf (stdout, " Signature 0x%04X\n", (UINT32) PciRomHdr.Signature); + fprintf (stdout, " PCIR offset 0x%04X\n", (UINT32) PciRomHdr.PcirOffset); + // + // Find PCI data structure + // + if (fseek (InFptr, ImageStart + PciRomHdr.PcirOffset, SEEK_SET)) { + fprintf (stdout, "ERROR: Failed to seek to PCI data structure\n"); + goto BailOut; + } + // + // Read and dump the PCI data structure + // + if (fread (&PciDs, sizeof (PciDs), 1, InFptr) != 1) { + fprintf (stdout, "ERROR: Failed to read PCI data structure from file\n"); + goto BailOut; + } + + fprintf (stdout, " PCI Data Structure\n"); + fprintf ( + stdout, + " Signature %c%c%c%c\n", + (char) PciDs.Signature, + (char) (PciDs.Signature >> 8), + (char) (PciDs.Signature >> 16), + (char) (PciDs.Signature >> 24) + ); + fprintf (stdout, " Vendor ID 0x%04X\n", PciDs.VendorId); + fprintf (stdout, " Device ID 0x%04X\n", PciDs.DeviceId); + fprintf ( + stdout, + " Class Code 0x%06X\n", + (UINT32) (PciDs.ClassCode[0] | (PciDs.ClassCode[1] << 8) | (PciDs.ClassCode[2] << 16)) + ); + fprintf (stdout, " Image size 0x%X\n", PciDs.ImageLength * 512); + fprintf (stdout, " Code revision: 0x%04X\n", PciDs.CodeRevision); + fprintf (stdout, " Indicator 0x%02X", (UINT32) PciDs.Indicator); + // + // Print the indicator, used to flag the last image + // + if (PciDs.Indicator == INDICATOR_LAST) { + fprintf (stdout, " (last image)\n"); + } else { + fprintf (stdout, "\n"); + } + // + // Print the code type. If EFI code, then we can provide more info. + // + fprintf (stdout, " Code type 0x%02X", (UINT32) PciDs.CodeType); + if (PciDs.CodeType == PCI_CODE_TYPE_EFI_IMAGE) { + fprintf (stdout, " (EFI image)\n"); + // + // Re-read the header as an EFI ROM header, then dump more info + // + fprintf (stdout, " EFI ROM header contents\n"); + if (fseek (InFptr, ImageStart, SEEK_SET)) { + fprintf (stdout, "ERROR: Failed to re-seek to ROM header structure\n"); + goto BailOut; + } + + if (fread (&EfiRomHdr, sizeof (EfiRomHdr), 1, InFptr) != 1) { + fprintf (stdout, "ERROR: Failed to read EFI PCI ROM header from file\n"); + goto BailOut; + } + // + // Now dump more info + // + fprintf (stdout, " EFI Signature 0x%04X\n", EfiRomHdr.EfiSignature); + fprintf ( + stdout, + " Compression Type 0x%04X ", + (UINT32) EfiRomHdr.CompressionType + ); + if (EfiRomHdr.CompressionType == EFI_PCI_EXPANSION_ROM_HEADER_COMPRESSED) { + fprintf (stdout, "(compressed)\n"); + } else { + fprintf (stdout, "(not compressed)\n"); + } + + fprintf ( + stdout, + " Machine type 0x%04X (%s)\n", + EfiRomHdr.EfiMachineType, + GetMachineTypeStr (EfiRomHdr.EfiMachineType) + ); + fprintf ( + stdout, + " Subsystem 0x%04X (%s)\n", + EfiRomHdr.EfiSubsystem, + GetSubsystemTypeStr (EfiRomHdr.EfiSubsystem) + ); + fprintf ( + stdout, + " EFI image offset 0x%04X (@0x%X)\n", + (UINT32) EfiRomHdr.EfiImageHeaderOffset, + (UINT32) (EfiRomHdr.EfiImageHeaderOffset + ImageStart) + ); + + } else { + // + // Not an EFI image + // + fprintf (stdout, "\n"); + } + // + // If code type is EFI image, then dump it as well? + // + // if (PciDs.CodeType == PCI_CODE_TYPE_EFI_IMAGE) { + // } + // + // If last image, then we're done + // + if (PciDs.Indicator == INDICATOR_LAST) { + goto BailOut; + } + // + // Seek to the start of the next image + // + if (fseek (InFptr, ImageStart + (PciDs.ImageLength * 512), SEEK_SET)) { + fprintf (stdout, "ERROR: Failed to seek to next image\n"); + goto BailOut; + } + } + +BailOut: + fclose (InFptr); +} + +char * +GetMachineTypeStr ( + UINT16 MachineType + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + MachineType - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + int Index; + + for (Index = 0; mMachineTypes[Index].Name != NULL; Index++) { + if (mMachineTypes[Index].Value == MachineType) { + return mMachineTypes[Index].Name; + } + } + + return "unknown"; +} + +static +char * +GetSubsystemTypeStr ( + UINT16 SubsystemType + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + SubsystemType - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + int Index; + + for (Index = 0; mSubsystemTypes[Index].Name != NULL; Index++) { + if (mSubsystemTypes[Index].Value == SubsystemType) { + return mSubsystemTypes[Index].Name; + } + } + + return "unknown"; +} diff --git a/Tools/Source/TianoTools/EfiRom/Makefile b/Tools/Source/TianoTools/EfiRom/Makefile new file mode 100644 index 0000000000..5ba3607549 --- /dev/null +++ b/Tools/Source/TianoTools/EfiRom/Makefile @@ -0,0 +1,70 @@ +#/*++ +# +# Copyright (c) 2001 Intel Corporation. All rights reserved. +# +# This software and associated documentation (if any) is furnished under +# a license and may only be used or copied in accordance with the terms +# of the license. Except as permitted by such license, no part of this +# software or documentation may be reproduced, stored in a retrieval +# system, or transmitted in any form or by any means without the express +# written consent of Intel Corporation. +# +# Module Name: +# +# makefile +# +# Abstract: +# +# makefile for building the EfiRom utility. +# +# Revision History +# +#--*/ + +# +# Make sure environmental variable EFI_SOURCE is set +# +!IFNDEF EFI_SOURCE +!ERROR EFI_SOURCE environmental variable not set +!ENDIF + +# +# Define the toolchain which is used to set build options and toolchain paths +# +TOOLCHAIN = TOOLCHAIN_MSVC + +!INCLUDE PlatformTools.env + +# +# Target specific information +# + +TARGET_NAME = EfiRom +TARGET_SRC_DIR = $(TIANO_TOOLS_SOURCE)\$(TARGET_NAME) +TARGET_EXE = $(TIANO_TOOLS_OUTPUT)\EfiRom.exe + +# +# Build targets +# + +all: $(TARGET_EXE) + +OBJECTS = $(TIANO_TOOLS_OUTPUT)\EfiRom.obj \ + $(TIANO_TOOLS_OUTPUT)\EfiCompress.obj + +# +# Build the EXE by compiling the source files, then linking the resultant +# object files together. +# + +$(TIANO_TOOLS_OUTPUT)\EfiRom.obj : $(TARGET_SRC_DIR)\EfiRom.c + $(CC) $(C_FLAGS) $(TARGET_SRC_DIR)\EfiRom.c /Fo$@ + +$(TIANO_TOOLS_OUTPUT)\EfiCompress.obj : $(EDK_TOOLS_SOURCE)\Common\EfiCompress.c + $(CC) $(C_FLAGS) $(EDK_TOOLS_SOURCE)\Common\EfiCompress.c /Fo$@ + +$(TARGET_EXE): $(OBJECTS) $(TARGET_EXE_LIBS) + $(LINK) $(MSVS_LINK_LIBPATHS) $(L_FLAGS) $(LIBS) /out:$(TARGET_EXE) $(OBJECTS) + +clean: + @if exist $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).* del $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).* > NUL diff --git a/Tools/Source/TianoTools/FlashMap/FlashDefFile.c b/Tools/Source/TianoTools/FlashMap/FlashDefFile.c new file mode 100644 index 0000000000..fa31863d47 --- /dev/null +++ b/Tools/Source/TianoTools/FlashMap/FlashDefFile.c @@ -0,0 +1,2787 @@ +/*++ + +Copyright (c) 2004-2005 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + + +Module Name: + + FlashDefFile.c + +Abstract: + + Utility for flash management in the Intel Platform Innovation Framework + for EFI build environment. + +--*/ + +#include +#include +#include + +#include "Tiano.h" +#include "EfiUtilityMsgs.h" +#include "FlashDefFile.h" +#include "SimpleFileParsing.h" +#include "Symbols.h" +#include "EfiFirmwareVolumeHeader.h" + +// +// #include "TrackMallocFree.h" +// +#define WCHAR_T char +#define MAX_STRING_LEN 256 +#define MAX_NAME_LEN 128 +#define BUFFER_SIZE 1024 +#define MAX_ATTR_LEN 128 +#define MAX_AREATYPE_LEN 128 +#define COLUMN2_START 60 +#define COLUMN3_START 70 +// +// Information for each subregions defined in the fdf file will be saved in these +// +typedef struct _FLASH_SUBREGION_DESCRIPTION { + struct _FLASH_SUBREGION_DESCRIPTION *Next; + int CreateHob; // to add to the auto-created HOB array + WCHAR_T Name[MAX_NAME_LEN]; // each subregion within a region must have a unique name + unsigned int Size; // size, in bytes, of this subregion + unsigned int SizeLeft; // used when creating the image + WCHAR_T Attributes[MAX_ATTR_LEN]; // subregion attributes used in the output HOB + WCHAR_T AreaType[MAX_AREATYPE_LEN]; // subregion area type used in the output HOB + EFI_GUID NameGuid; // used in the output HOB + WCHAR_T NameGuidString[MAX_NAME_LEN]; + EFI_GUID AreaTypeGuid; // used in the output HOB + WCHAR_T AreaTypeGuidString[MAX_NAME_LEN]; + EFI_GUID FileSystemGuid; // used in the output HOB + WCHAR_T FileSystemGuidString[MAX_NAME_LEN]; +} FLASH_SUBREGION_DESCRIPTION; + +// +// Information for each block in a flash device will be saved in one of these. +// We'll also use it for region definitions. +// +typedef struct _FLASH_BLOCK_DESCRIPTION { + struct _FLASH_BLOCK_DESCRIPTION *Next; // next block in the linked list + WCHAR_T Name[MAX_NAME_LEN]; // each block must have a unique name + unsigned int Size; // size, in bytes, of this block + unsigned int SizeLeft; // for use when creating image + unsigned int Flags; // user-defined flags for the block + unsigned int Alignment; // power of 2 alignment + WCHAR_T Attributes[MAX_ATTR_LEN]; // only used for Region definitions + WCHAR_T AreaType[MAX_AREATYPE_LEN]; // only used for Region definitions + FLASH_SUBREGION_DESCRIPTION *Subregions; + FLASH_SUBREGION_DESCRIPTION *LastSubregion; +} FLASH_BLOCK_DESCRIPTION; + +// +// Information for each flash device will be saved in one of these +// +typedef struct _FLASH_DEVICE_DESCRIPTION { + struct _FLASH_DEVICE_DESCRIPTION *Next; // next flash device in our linked list + int ErasePolarity; // erase polarity of the flash device + unsigned int BaseAddress; // base address of the flash device + unsigned int Size; // total size, in bytes, of the flash device + WCHAR_T Name[MAX_NAME_LEN]; // name of the flash device + FLASH_BLOCK_DESCRIPTION *PBlocks; // linked list of physical block descriptors + FLASH_BLOCK_DESCRIPTION *LastPBlock; // last block in the linked list + FLASH_BLOCK_DESCRIPTION *Regions; // linked list of flash region descriptors + FLASH_BLOCK_DESCRIPTION *LastRegion; // last region in the linked list +} FLASH_DEVICE_DESCRIPTION; + +// +// For image definitions, they can specify a file name or raw data bytes. Keep a linked list. +// +typedef struct _IMAGE_DEFINITION_ENTRY { + struct _IMAGE_DEFINITION_ENTRY *Next; + WCHAR_T RegionName[MAX_NAME_LEN]; + WCHAR_T SubregionName[MAX_NAME_LEN]; + WCHAR_T Name[MAX_NAME_LEN]; // file or data name + int IsRawData; // non-zero if raw data bytes + unsigned int RawDataSize; + char *RawData; + int Optional; // optional file (don't include if it doesn't exist) +} IMAGE_DEFINITION_ENTRY; + +// +// When we parse an image definition, save all the data for each in one of these +// +typedef struct _IMAGE_DEFINITION { + struct _IMAGE_DEFINITION *Next; + WCHAR_T Name[MAX_NAME_LEN]; + IMAGE_DEFINITION_ENTRY *Entries; + IMAGE_DEFINITION_ENTRY *LastEntry; +} IMAGE_DEFINITION; + +typedef struct { + char *BufferStart; + char *BufferEnd; + char *BufferPos; +} BUFFER_DATA; + +static const char *CIncludeHeader = "/*++\n\n" +" DO NOT EDIT -- file auto-generated by FlashMap utility\n\n""--*/\n""\n""#ifndef _FLASH_MAP_H_\n" +"#define _FLASH_MAP_H_\n\n"; +// +// "#include \"EfiFlashMap.h\"\n\n"; +// +static const char *CIncludeFooter = "#endif // #ifndef _FLASH_MAP_H_\n\n"; + +static const char *CFlashMapDataFileHeader = "/*++\n\n" +" DO NOT EDIT -- file auto-generated by FlashMap utility\n\n""--*/\n""\n"; + +static FLASH_DEVICE_DESCRIPTION *mFlashDevices = NULL; +static IMAGE_DEFINITION *mImageDefinitions = NULL; + +// +// Local function prototypes +// +static +BUFFER_DATA * +CreateBufferData ( + VOID + ); + +static +BOOLEAN +AddBufferDataByte ( + BUFFER_DATA *Buffer, + char Data + ); + +static +void +FreeBufferData ( + BUFFER_DATA *Buffer, + BOOLEAN FreeData + ); + +static +char * +GetBufferData ( + BUFFER_DATA *Buffer, + int *BufferSize + ); + +static +FLASH_SUBREGION_DESCRIPTION * +ParseSubregionDefinition ( + unsigned int SizeLeft + ); + +void +FDFConstructor ( + VOID + ) +/*++ + +Routine Description: + Initialization routine for the services that operate on a flash + definition file. + +Arguments: + None. + +Returns: + NA + +--*/ +{ + mFlashDevices = NULL; + mImageDefinitions = NULL; +} + +void +FDFDestructor ( + VOID + ) +/*++ + +Routine Description: + Finalization/cleanup routine for the services that operate on a flash + definition file. + +Arguments: + None. + +Returns: + NA + +--*/ +{ + FLASH_BLOCK_DESCRIPTION *FBNext; + FLASH_DEVICE_DESCRIPTION *FDNext; + IMAGE_DEFINITION *IDNext; + IMAGE_DEFINITION_ENTRY *IDENext; + FLASH_SUBREGION_DESCRIPTION *SubNext; + // + // Go through all our flash devices and free the memory + // + while (mFlashDevices != NULL) { + // + // Free the physical block definitions + // + while (mFlashDevices->PBlocks != NULL) { + FBNext = mFlashDevices->PBlocks->Next; + _free (mFlashDevices->PBlocks); + mFlashDevices->PBlocks = FBNext; + } + // + // Free the region definitions + // + while (mFlashDevices->Regions != NULL) { + FBNext = mFlashDevices->Regions->Next; + // + // First free the subregion definitions + // + while (mFlashDevices->Regions->Subregions != NULL) { + SubNext = mFlashDevices->Regions->Subregions->Next; + _free (mFlashDevices->Regions->Subregions); + mFlashDevices->Regions->Subregions = SubNext; + } + + _free (mFlashDevices->Regions); + mFlashDevices->Regions = FBNext; + } + + FDNext = mFlashDevices->Next; + _free (mFlashDevices); + mFlashDevices = FDNext; + } + // + // Free up the image definitions, and the data + // + while (mImageDefinitions != NULL) { + // + // Free the entries + // + while (mImageDefinitions->Entries != NULL) { + IDENext = mImageDefinitions->Entries->Next; + if (mImageDefinitions->Entries->RawData != NULL) { + _free (mImageDefinitions->Entries->RawData); + } + + _free (mImageDefinitions->Entries); + mImageDefinitions->Entries = IDENext; + } + + IDNext = mImageDefinitions->Next; + _free (mImageDefinitions); + mImageDefinitions = IDNext; + } +} + +STATUS +FDFParseFile ( + char *FileName + ) +/*++ + +Routine Description: + Parse the specified flash definition file, saving the definitions in + file-static variables for use by other functions. + +Arguments: + FileName - name of the input flash definition text file. + +Returns: + STATUS_SUCCESS - file parsed with no errors or warnings + STATUS_WARNING - warnings, but no errors, were encountered while parsing + STATUS_ERROR - errors were encountered while parsing + +--*/ +{ + FILE *Fptr; + STATUS Status; + unsigned int Num; + FLASH_DEVICE_DESCRIPTION *FDDesc; + FLASH_BLOCK_DESCRIPTION *FBlockDesc; + FLASH_BLOCK_DESCRIPTION *TempBlockDesc; + FLASH_SUBREGION_DESCRIPTION *Subregion; + FLASH_SUBREGION_DESCRIPTION *TempSubregion; + unsigned int BlockSizeLeft; + unsigned int RegionSizeLeft; + unsigned int SubregionSizeLeft; + int ErrorCount; + int WarningCount; + IMAGE_DEFINITION *ImageDef; + IMAGE_DEFINITION_ENTRY *ImageDefEntry; + IMAGE_DEFINITION_ENTRY *TempImageDefEntry; + BUFFER_DATA *BufferData; + char Str[100]; + BOOLEAN PreviousComma; + + if ((Fptr = fopen (FileName, "r")) == NULL) { + Error (NULL, 0, 0, FileName, "failed to open input flash definition file for reading"); + return STATUS_ERROR; + } + + fclose (Fptr); + Status = STATUS_SUCCESS; + ErrorCount = 0; + WarningCount = 0; + // + // Initialize the simple-file-parsing routines + // + SFPInit (); + // + // Open the file + // + if ((Status = SFPOpenFile (FileName)) != STATUS_SUCCESS) { + return Status; + } + // + // Parse the file. Should start with a series of these: + // FlashDevice { + // Name = "FLASH_1234", Size = 0x2004, BaseAddress = 0xFFF0000, ErasePolarity = 1, + // Block { Name = "BLOCK1", Size = 0x1000, Flags = 0x0001 } + // Block { Name = "BLOCK2", Size = 0x1004, Flags = 0x0002 } + // Region { Name = "REGION_NAME", Size = 0x2004, Align= 4 } + // } + // + while (SFPIsKeyword ("FlashDevice")) { + // + // Allocate memory for new flash device description block + // + FDDesc = (FLASH_DEVICE_DESCRIPTION *) _malloc (sizeof (FLASH_DEVICE_DESCRIPTION)); + if (FDDesc == NULL) { + Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL); + ErrorCount++; + goto Done; + } + + memset (FDDesc, 0, sizeof (FLASH_DEVICE_DESCRIPTION)); + // + // Open brace -- warning if not there + // + if (!SFPIsToken ("{")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected {", NULL); + WarningCount++; + } + // + // Parse: Name = "DeviceName", + // + if (!SFPIsKeyword ("Name")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Name'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPGetQuotedString (FDDesc->Name, sizeof (FDDesc->Name))) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted name of flash device", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken (",")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following flash device name", NULL); + WarningCount++; + } + // + // Parse: Size = 0x20000, + // + if (!SFPIsKeyword ("Size")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Size'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPGetNumber (&FDDesc->Size)) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected numeric Size value", NULL); + ErrorCount++; + goto Done; + } + // + // Check for 0 size + // + if (FDDesc->Size == 0) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, FDDesc->Name, "Size field cannot be 0", NULL); + ErrorCount++; + goto Done; + } + + SFPIsToken (","); + // + // Parse: BaseAddress = 0xFFF0000, + // + if (!SFPIsKeyword ("BaseAddress")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'BaseAddress'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPGetNumber (&FDDesc->BaseAddress)) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected numeric value for BaseAddress", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken (",")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following BaseAddress value", NULL); + WarningCount++; + } + // + // Parse: ErasePolarity = 1, + // + if (!SFPIsKeyword ("ErasePolarity")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'ErasePolarity'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPGetNumber (&Num) || ((Num != 0) && (Num != 1))) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected numeric erase polarity value 1 or 0", NULL); + ErrorCount++; + goto Done; + } + + FDDesc->ErasePolarity = Num; + if (!SFPIsToken (",")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following erase polarity value", NULL); + WarningCount++; + } + // + // Parse array of: + // Block { Name = "BLOCK1", Size = 0x1000, Flags = 0x0001 } + // + // Keep track of size to make sure the sum of the physical blocks and region sizes do not + // exceed the size of the flash device. + // + BlockSizeLeft = FDDesc->Size; + RegionSizeLeft = FDDesc->Size; + while (SFPIsKeyword ("Block")) { + // + // Allocate memory for a new physical block descriptor + // + FBlockDesc = (FLASH_BLOCK_DESCRIPTION *) _malloc (sizeof (FLASH_BLOCK_DESCRIPTION)); + if (FBlockDesc == NULL) { + Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL); + ErrorCount++; + goto Done; + } + + memset (FBlockDesc, 0, sizeof (FLASH_BLOCK_DESCRIPTION)); + // + // Open brace -- warning if not there + // + if (!SFPIsToken ("{")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected {", NULL); + WarningCount++; + } + // + // Parse: Name = "BlockName", + // + if (!SFPIsKeyword ("Name")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Name'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPGetQuotedString (FBlockDesc->Name, sizeof (FBlockDesc->Name))) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted name of physical block", NULL); + ErrorCount++; + goto Done; + } + // + // Make sure there are no other physical block names with this same name + // + for (TempBlockDesc = FDDesc->PBlocks; TempBlockDesc != NULL; TempBlockDesc = TempBlockDesc->Next) { + if (strcmp (TempBlockDesc->Name, FBlockDesc->Name) == 0) { + Error ( + SFPGetFileName (), + SFPGetLineNumber (), + 0, + TempBlockDesc->Name, + "physical block with this name already defined" + ); + ErrorCount++; + } + } + + if (!SFPIsToken (",")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following physical block name", NULL); + WarningCount++; + } + // + // Parse: Size = 0x2000, + // + if (!SFPIsKeyword ("Size")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Size'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPGetNumber (&FBlockDesc->Size)) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected numeric Size value", NULL); + ErrorCount++; + goto Done; + } + // + // Make sure the sum of physical blocks so far does not exceed flash device size + // + if (BlockSizeLeft < FBlockDesc->Size) { + Error ( + SFPGetFileName (), + SFPGetLineNumber (), + 0, + "sum of physical block sizes exceeds flash device size", + NULL + ); + ErrorCount++; + } + + BlockSizeLeft -= FBlockDesc->Size; + SFPIsToken (","); + // + // Optional parse: Flags = 0xFFF0000, + // + if (SFPIsKeyword ("Flags")) { + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPGetNumber (&FBlockDesc->Flags)) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected numeric value for Flags", NULL); + ErrorCount++; + goto Done; + } + } + + if (!SFPIsToken ("}")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected PhysicalBlock closing brace '}'", NULL); + WarningCount++; + } + // + // Add the physical block descriptor to the end of the linked list + // + if (FDDesc->LastPBlock != NULL) { + FDDesc->LastPBlock->Next = FBlockDesc; + } else { + FDDesc->PBlocks = FBlockDesc; + } + + FDDesc->LastPBlock = FBlockDesc; + } + // + // Make sure sum of sizes of physical blocks added up to size of flash device + // + if (BlockSizeLeft != 0) { + Error ( + SFPGetFileName (), + SFPGetLineNumber (), + 0, + NULL, + "sum of sizes of physical blocks (0x%08X) != flash device size (0x%08X) : delta = 0x%08X", + FDDesc->Size - BlockSizeLeft, + FDDesc->Size, + BlockSizeLeft + ); + ErrorCount++; + } + // + // Parse array of: + // Region { Name = "REGION_1", Size = 0x2000, Flags = 0x1234, Alignment = 4, Attributes = "str", AreaType = "str" } + // + while (SFPIsKeyword ("Region")) { + // + // Allocate memory for a new physical block descriptor + // + FBlockDesc = (FLASH_BLOCK_DESCRIPTION *) _malloc (sizeof (FLASH_BLOCK_DESCRIPTION)); + if (FBlockDesc == NULL) { + Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL); + ErrorCount++; + goto Done; + } + + memset (FBlockDesc, 0, sizeof (FLASH_BLOCK_DESCRIPTION)); + // + // Open brace -- warning if not there + // + if (!SFPIsToken ("{")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected {", NULL); + WarningCount++; + } + // + // Parse: Name = "BlockName", + // + if (!SFPIsKeyword ("Name")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Name'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPGetQuotedString (FBlockDesc->Name, sizeof (FBlockDesc->Name))) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted Region name", NULL); + ErrorCount++; + goto Done; + } + // + // Make sure there are no other region names with this same name + // + for (TempBlockDesc = FDDesc->Regions; TempBlockDesc != NULL; TempBlockDesc = TempBlockDesc->Next) { + if (strcmp (TempBlockDesc->Name, FBlockDesc->Name) == 0) { + Error ( + SFPGetFileName (), + SFPGetLineNumber (), + 0, + TempBlockDesc->Name, + "Region with this name already defined" + ); + ErrorCount++; + } + } + + if (!SFPIsToken (",")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following Region name", NULL); + WarningCount++; + } + // + // Parse: Size = 0x2000, + // + if (!SFPIsKeyword ("Size")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Size'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPGetNumber (&FBlockDesc->Size)) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected numeric Size value", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken (",")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected ','", NULL); + } + // + // Make sure the sum of regions so far does not exceed flash device size + // + if (RegionSizeLeft < FBlockDesc->Size) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "sum of Region sizes exceeds flash device size", NULL); + ErrorCount++; + } + + RegionSizeLeft -= FBlockDesc->Size; + // + // Optional parse: Flags = 0xFFF0000, + // + if (SFPIsKeyword ("Flags")) { + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPGetNumber (&FBlockDesc->Flags)) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected numeric value for Flags", NULL); + ErrorCount++; + goto Done; + } + // + // comma + // + if (!SFPIsToken (",")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected ','", NULL); + } + } + // + // Optional parse: Alignment = 4 + // + if (SFPIsKeyword ("Alignment")) { + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPGetNumber (&FBlockDesc->Alignment)) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected numeric Alignment value", NULL); + ErrorCount++; + goto Done; + } + // + // comma + // + if (!SFPIsToken (",")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected ','", NULL); + } + } + // + // Parse: Attributes = "String", + // + if (!SFPIsKeyword ("Attributes")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Attributes'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPGetQuotedString (FBlockDesc->Attributes, sizeof (FBlockDesc->Attributes))) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted Attributes string", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken (",")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected ','", NULL); + } + // + // Parse: AreaType = "String", + // + if (!SFPIsKeyword ("AreaType")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'AreaType'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPGetQuotedString (FBlockDesc->AreaType, sizeof (FBlockDesc->AreaType))) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted AreaType string", NULL); + ErrorCount++; + goto Done; + } + + PreviousComma = SFPIsToken (","); + // + // Parse optional Subregion definitions + // + SubregionSizeLeft = FBlockDesc->Size; + while (SFPIsToken ("Subregion")) { + if (!PreviousComma) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected ',' before 'Subregion'", NULL); + WarningCount++; + PreviousComma = TRUE; + } + + Subregion = ParseSubregionDefinition (SubregionSizeLeft); + if (Subregion == NULL) { + ErrorCount++; + goto Done; + } + + SubregionSizeLeft -= Subregion->Size; + // + // Add it to the end of our list + // + if (FBlockDesc->Subregions == NULL) { + FBlockDesc->Subregions = Subregion; + } else { + FBlockDesc->LastSubregion->Next = Subregion; + } + + FBlockDesc->LastSubregion = Subregion; + // + // Make sure all subregion names are unique. We do this each time + // through so that we catch the error immediately after it happens, in + // which case the reported line number is at least close to where the + // problem lies. We don't exit on the error because we can continue parsing + // the script to perhaps catch other errors or warnings. + // + for (Subregion = FBlockDesc->Subregions; Subregion != NULL; Subregion = Subregion->Next) { + for (TempSubregion = Subregion->Next; TempSubregion != NULL; TempSubregion = TempSubregion->Next) { + if (strcmp (Subregion->Name, TempSubregion->Name) == 0) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, Subregion->Name, "duplicate Subregion name"); + ErrorCount++; + } + } + } + } + + if (!SFPIsToken ("}")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected Region closing brace '}'", NULL); + WarningCount++; + } + // + // Add the region descriptor to the end of the linked list + // + if (FDDesc->LastRegion != NULL) { + FDDesc->LastRegion->Next = FBlockDesc; + } else { + FDDesc->Regions = FBlockDesc; + } + + FDDesc->LastRegion = FBlockDesc; + } + // + // Make sure sum of sizes of regions adds up to size of flash device + // + if (RegionSizeLeft != 0) { + Error ( + SFPGetFileName (), + SFPGetLineNumber (), + 0, + NULL, + "sum of sizes of Regions (0x%08X) != flash device size (0x%08X) : delta = 0x%08X", + FDDesc->Size - RegionSizeLeft, + FDDesc->Size, + RegionSizeLeft + ); + ErrorCount++; + } + // + // Look for closing brace + // + if (!SFPIsToken ("}")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected FlashDevice closing brace '}'", NULL); + WarningCount++; + } + // + // Add this flash description to the list + // + FDDesc->Next = mFlashDevices; + mFlashDevices = FDDesc; + } + + while (SFPIsKeyword ("FlashDeviceImage")) { + // + // Allocate memory for a new FD image definition + // + ImageDef = (IMAGE_DEFINITION *) _malloc (sizeof (IMAGE_DEFINITION)); + if (ImageDef == NULL) { + Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL); + ErrorCount++; + goto Done; + } + + memset (ImageDef, 0, sizeof (IMAGE_DEFINITION)); + // + // Open brace -- warning if not there + // + if (!SFPIsToken ("{")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected {", NULL); + WarningCount++; + } + // + // Parse: Name = "ImageName", + // + if (!SFPIsKeyword ("Name")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Name'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPGetQuotedString (ImageDef->Name, sizeof (ImageDef->Name))) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted name of image", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken (",")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following image name", NULL); + WarningCount++; + } + + while (1) { + // + // Parse: File { Name = "FV\FvOem.fv", Region = "REGION_OEM", Optional = TRUE } + // + if (SFPIsKeyword ("File")) { + ImageDefEntry = (IMAGE_DEFINITION_ENTRY *) _malloc (sizeof (IMAGE_DEFINITION_ENTRY)); + if (ImageDefEntry == NULL) { + Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL); + ErrorCount++; + goto Done; + } + + memset (ImageDefEntry, 0, sizeof (IMAGE_DEFINITION_ENTRY)); + // + // Open brace -- warning if not there + // + if (!SFPIsToken ("{")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected {", NULL); + WarningCount++; + } + // + // Parse: Name = "FileName.txt" + // + if (!SFPIsKeyword ("Name")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Name'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPGetQuotedString (ImageDefEntry->Name, sizeof (ImageDefEntry->Name))) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted name of file", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken (",")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following file name", NULL); + WarningCount++; + } + // + // Parse: Region = "REGION_NAME" + // + if (!SFPIsKeyword ("Region")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Region'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPGetQuotedString (ImageDefEntry->RegionName, sizeof (ImageDefEntry->RegionName))) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted Region name", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken (",")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following Region name", NULL); + WarningCount++; + } + // + // Parse optional: Subregion = "SUBREGION_NAME" + // + if (SFPIsKeyword ("Subregion")) { + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPGetQuotedString (ImageDefEntry->SubregionName, sizeof (ImageDefEntry->SubregionName))) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted Subegion name", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken (",")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following Subregion name", NULL); + WarningCount++; + } + // + // For a given region, you can only place data using the region name, or the subregion names. + // In other words, you can't say File1->Region1 and File2->Region1.Subregion1. Enforce that + // here by checking that any previous entries with the same Region name had a Subregion specified + // as well. + // + for (TempImageDefEntry = ImageDef->Entries; + TempImageDefEntry != NULL; + TempImageDefEntry = TempImageDefEntry->Next + ) { + if (strcmp (TempImageDefEntry->Name, ImageDefEntry->Name) == 0) { + if (TempImageDefEntry->SubregionName[0] == 0) { + Error ( + SFPGetFileName (), + SFPGetLineNumber (), + 0, + TempImageDefEntry->RegionName, + "data already placed on a region-basis in the region, can't place data using subregions" + ); + ErrorCount++; + } + } + } + } + // + // Optional parse: Optional = TRUE | FALSE + // + if (SFPIsKeyword ("Optional")) { + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPIsKeyword ("TRUE")) { + ImageDefEntry->Optional = 1; + } else if (SFPIsKeyword ("FALSE")) { + // + // Already set to 0 + // + } else { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL); + ErrorCount++; + goto Done; + } + + SFPIsToken (","); + } + // + // Closing brace + // + if (!SFPIsToken ("}")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '}' closing brace to File entry", NULL); + ErrorCount++; + goto Done; + } + // + // Add the entry to the end of the list + // + if (ImageDef->LastEntry != NULL) { + ImageDef->LastEntry->Next = ImageDefEntry; + } else { + ImageDef->Entries = ImageDefEntry; + } + + ImageDef->LastEntry = ImageDefEntry; + } else if (SFPIsKeyword ("RawData")) { + // + // Parse: RawData { Name = "PadBytes", Region = "REGION_1", Data = { 0x78, 0x56, 0x34, 0x12 }} + // + ImageDefEntry = (IMAGE_DEFINITION_ENTRY *) _malloc (sizeof (IMAGE_DEFINITION_ENTRY)); + if (ImageDefEntry == NULL) { + Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL); + ErrorCount++; + goto Done; + } + + memset (ImageDefEntry, 0, sizeof (IMAGE_DEFINITION_ENTRY)); + ImageDefEntry->IsRawData = 1; + // + // Open brace -- warning if not there + // + if (!SFPIsToken ("{")) { + Warning ( + SFPGetFileName (), + SFPGetLineNumber (), + 0, + "expected '{' opening brace for RawData definition", + NULL + ); + WarningCount++; + } + // + // Parse: Name = "PadBytes" + // + if (!SFPIsKeyword ("Name")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Name'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPGetQuotedString (ImageDefEntry->Name, sizeof (ImageDefEntry->Name))) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted name of raw data", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken (",")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following raw data name", NULL); + WarningCount++; + } + // + // Parse: Region = "REGION_NAME" + // + if (!SFPIsKeyword ("Region")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Region'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPGetQuotedString (ImageDefEntry->RegionName, sizeof (ImageDefEntry->RegionName))) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted Region name", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken (",")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following Region name", NULL); + WarningCount++; + } + // + // Parse optional: Subregion = "SUBREGION_NAME" + // + if (SFPIsKeyword ("Subregion")) { + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPGetQuotedString (ImageDefEntry->SubregionName, sizeof (ImageDefEntry->SubregionName))) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted Subegion name", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken (",")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following Subregion name", NULL); + WarningCount++; + } + // + // For a given region, you can only place data using the region name, or the subregion names. + // In other words, you can't say File1->Region1 and File2->Region1.Subregion1. Enforce that + // here by checking that any previous entries with the same Region name had a Subregion specified + // as well. + // + for (TempImageDefEntry = ImageDef->Entries; + TempImageDefEntry != NULL; + TempImageDefEntry = TempImageDefEntry->Next + ) { + if (strcmp (TempImageDefEntry->Name, ImageDefEntry->Name) == 0) { + if (TempImageDefEntry->SubregionName[0] == 0) { + Error ( + SFPGetFileName (), + SFPGetLineNumber (), + 0, + TempImageDefEntry->RegionName, + "data already placed on a region-basis in the region, can't place data using subregions" + ); + ErrorCount++; + } + } + } + } + // + // Parse: Data = { 0x78, 0x56, 0x34, 0x12 } + // + if (!SFPIsKeyword ("Data")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Data'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPIsToken ("{")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '{' preceeding data list", NULL); + WarningCount++; + } + + if ((BufferData = CreateBufferData ()) == NULL) { + ErrorCount++; + goto Done; + } + // + // Read bytes from input file until closing brace + // + while (!SFPIsToken ("}")) { + if (!SFPGetNumber (&Num)) { + SFPGetNextToken (Str, sizeof (Str)); + Error (SFPGetFileName (), SFPGetLineNumber (), 0, Str, "expected data value", Str); + ErrorCount++; + FreeBufferData (BufferData, TRUE); + goto Done; + } else { + // + // Only allow bytes + // + if (Num > 0xFF) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "only values 0-255 (0x00-0xFF) allowed", NULL); + ErrorCount++; + FreeBufferData (BufferData, TRUE); + goto Done; + } + + AddBufferDataByte (BufferData, (char) Num); + SFPIsToken (","); + } + } + // + // Now get the data and save it in our image entry + // + ImageDefEntry->RawData = GetBufferData (BufferData, &ImageDefEntry->RawDataSize); + FreeBufferData (BufferData, 0); + // + // Closing brace for RawData {} + // + if (!SFPIsToken ("}")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '}' closing brace for RawData", NULL); + ErrorCount++; + goto Done; + } + // + // Add the entry to the end of the list + // + if (ImageDef->LastEntry != NULL) { + ImageDef->LastEntry->Next = ImageDefEntry; + } else { + ImageDef->Entries = ImageDefEntry; + } + + ImageDef->LastEntry = ImageDefEntry; + } else if (SFPIsToken ("}")) { + // + // Closing brace for FDImage {} + // + break; + } else { + SFPGetNextToken (Str, sizeof (Str)); + Error (SFPGetFileName (), SFPGetLineNumber (), 0, Str, "unrecognized token", Str); + ErrorCount++; + goto Done; + } + } + // + // Add this image definition to our global list + // + ImageDef->Next = mImageDefinitions; + mImageDefinitions = ImageDef; + } + // + // Check for end-of-file + // + if (!SFPIsEOF ()) { + SFPGetNextToken (Str, sizeof (Str)); + Error (SFPGetFileName (), SFPGetLineNumber (), 0, Str, "expected end-of-file", Str); + ErrorCount++; + } + +Done: + SFPCloseFile (); + if (ErrorCount != 0) { + return STATUS_ERROR; + } else if (WarningCount != 0) { + return STATUS_WARNING; + } + + return STATUS_SUCCESS; +} + +static +FLASH_SUBREGION_DESCRIPTION * +ParseSubregionDefinition ( + unsigned int SizeLeft + ) +/*++ + +Routine Description: + + Parse Subregion definitions from the input flash definition file. Format: + + Subregion { + CreateHob = TRUE, + Name = "FOO", + Size = 0xA000, + Attributes = "EFI_FLASH_AREA_SUBFV | EFI_FLASH_AREA_MEMMAPPED_FV", + AreaType = "EFI_FLASH_AREA_EFI_VARIABLES", + NameGuid = 12345678-1234-5678-AAAA-BBBBCCCCDDDD (or "EFI_SOME_GUID"), + AreaTypeGuid = 11111111-2222-3333-4444-1, (or "EFI_SOME_GUID") (optional) + FileSystemGuid = 11111111-2222-3333-4444-1, (or "EFI_SOME_GUID") (optional) + } + + NOTE: The caller has already parsed the "Subregion" token, so start with the opening brace. + +Arguments: + + SizeLeft - in the flash definition file, a Region can be broken up into + one or more subregions. As we parse the subregion definitions, + the caller keeps track of how much space is left in the region + that we're parsing subregions for. SizeLeft is that size, and + so the size of the subregion we're now parsing better not + exceed the size left. + Returns: + + NULL - unrecoverable errors detected while parsing the subregion definition + + pointer to a subregion definition created from the parsed subregion + +--*/ +{ + FLASH_SUBREGION_DESCRIPTION *Subregion; + int ErrorCount; + int WarningCount; + unsigned int Number; + BOOLEAN PreviousComma; + // + // Allocate memory for the new subregion descriptor + // + ErrorCount = 0; + WarningCount = 0; + Subregion = (FLASH_SUBREGION_DESCRIPTION *) _malloc (sizeof (FLASH_SUBREGION_DESCRIPTION)); + if (Subregion == NULL) { + Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL); + ErrorCount++; + goto Done; + } + + memset (Subregion, 0, sizeof (FLASH_SUBREGION_DESCRIPTION)); + // + // Open brace -- warning if not there + // + if (!SFPIsToken ("{")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected {", NULL); + WarningCount++; + } + // + // Parse: CreateHob = TRUE | FALSE, + // + if (!SFPIsKeyword ("CreateHob")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'CreateHob'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (SFPIsToken ("TRUE")) { + Subregion->CreateHob = 1; + } else if (SFPIsToken ("FALSE")) { + // + // Subregion->CreateHob = 0; -- not required since we did a memset earlier + // + } else { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken (",")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected ',' following CreateHob value", NULL); + WarningCount++; + } + // + // Parse: Name = "Name", + // + if (!SFPIsKeyword ("Name")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Name'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPGetQuotedString (Subregion->Name, sizeof (Subregion->Name))) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected Subregion name", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken (",")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following Region name", NULL); + WarningCount++; + } + // + // Parse: Size = 0x2000, + // + if (!SFPIsKeyword ("Size")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Size'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (!SFPGetNumber (&Subregion->Size)) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected numeric Size value", NULL); + ErrorCount++; + goto Done; + } + + // + // Check that the size does not exceed the size left passed in + // + if (Subregion->Size > SizeLeft) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "sum of Subregion sizes exceeds Region size", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken (",")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected ',' following Size value", NULL); + } + // + // Parse: Attributes = Number | "String", + // + if (!SFPIsKeyword ("Attributes")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Attributes'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (SFPGetNumber (&Number)) { + sprintf (Subregion->Attributes, "0x%X", Number); + } else if (!SFPGetQuotedString (Subregion->Attributes, sizeof (Subregion->Attributes))) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted Attributes string", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken (",")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected ','", NULL); + } + // + // Parse: AreaType = Number | "String", + // AreaType is a UINT8, so error if it exceeds the size + // + if (!SFPIsKeyword ("AreaType")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'AreaType'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (SFPGetNumber (&Number)) { + if (Number > 0xFF) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "AreaType value exceeds 255", NULL); + ErrorCount++; + } + + sprintf (Subregion->AreaType, "0x%X", Number & 0x00FF); + } else if (!SFPGetQuotedString (Subregion->AreaType, sizeof (Subregion->AreaType))) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted AreaType string", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken (",")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected ',' following AreaType value", NULL); + } + // + // Parse the three GUIDs (last two are optional) + // + // NameGuid = 12345678-1234-5678-AAAA-BBBBCCCCDDDD, (or "EFI_SOME_GUID") + // AreaTypeGuid = 11111111-2222-3333-4444-1, (or "EFI_SOME_GUID") + // FileSysteGuid = 11111111-2222-3333-4444-1, (or "EFI_SOME_GUID") + // + if (!SFPIsKeyword ("NameGuid")) { + Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'NameGuid'", NULL); + ErrorCount++; + goto Done; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + // + // Allow a GUID or a quoted string identifier, which we'll just copy as a string + // + if (SFPGetQuotedString (Subregion->NameGuidString, sizeof (Subregion->NameGuidString))) { + // + // Nothing else to do + // + } else if (!SFPGetGuid (PARSE_GUID_STYLE_5_FIELDS, &Subregion->NameGuid)) { + Error ( + SFPGetFileName (), + SFPGetLineNumber (), + 0, + "expected NameGuid quoted string or GUID of form 12345678-1234-1234-1234-123456789ABC", + NULL + ); + ErrorCount++; + goto Done; + } + // + // Comma following NameGuid is optional if they don't specify AreaTypeGuid or FileSystemGuid + // + PreviousComma = SFPIsToken (","); + if (SFPIsKeyword ("AreaTypeGuid")) { + // + // Check for preceeding comma now + // + if (!PreviousComma) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected ',' before 'AreaTypeGuid'", NULL); + WarningCount++; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + + if (SFPGetQuotedString (Subregion->AreaTypeGuidString, sizeof (Subregion->AreaTypeGuidString))) { + // + // Nothing else to do + // + } else if (!SFPGetGuid (PARSE_GUID_STYLE_5_FIELDS, &Subregion->AreaTypeGuid)) { + Error ( + SFPGetFileName (), + SFPGetLineNumber (), + 0, + "expected AreaTypeGuid quoted string or GUID of form 12345678-1234-1234-1234-123456789ABC", + NULL + ); + ErrorCount++; + goto Done; + } + + PreviousComma = SFPIsToken (","); + } + + if (SFPIsKeyword ("FileSystemGuid")) { + // + // Check for preceeding comma now + // + if (!PreviousComma) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected ',' before 'FileSystemGuid'", NULL); + WarningCount++; + } + + if (!SFPIsToken ("=")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL); + WarningCount++; + } + // + // Allow a GUID or a quoted string identifier, which we'll just copy as a string + // + if (SFPGetQuotedString (Subregion->FileSystemGuidString, sizeof (Subregion->FileSystemGuidString))) { + // + // Nothing else to do + // + } else if (!SFPGetGuid (PARSE_GUID_STYLE_5_FIELDS, &Subregion->FileSystemGuid)) { + Error ( + SFPGetFileName (), + SFPGetLineNumber (), + 0, + "expected FileSystemGuid quoted string or GUID of form 12345678-1234-1234-1234-123456789ABC", + NULL + ); + ErrorCount++; + goto Done; + } + + SFPIsToken (","); + } + // + // Look for subregion closing brace + // + if (!SFPIsToken ("}")) { + Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected Subregion closing brace '}'", NULL); + WarningCount++; + } + +Done: + // + // If any errors were encountered, then delete the subregion definition + // + if (ErrorCount != 0) { + _free (Subregion); + Subregion = NULL; + } + + return Subregion; +} + +STATUS +FDFCreateCIncludeFile ( + char *FlashDeviceName, + char *FileName + ) +/*++ + +Routine Description: + Create a header file with #define definitions per an already-parsed + flash definition file. + +Arguments: + FlashDeviceName - name of flash device (from the flash definition file) + to use + FileName - name of output file to create + +Returns: + STATUS_SUCCESS - no errors or warnings + STATUS_WARNING - warnings, but no errors, were encountered + STATUS_ERROR - errors were encountered + +--*/ +{ + FILE *OutFptr; + FLASH_BLOCK_DESCRIPTION *FBlock; + FLASH_DEVICE_DESCRIPTION *FDev; + FLASH_SUBREGION_DESCRIPTION *Subregion; + unsigned int Offset; + unsigned int SubregionOffset; + int CreateHobs; + // + // Find the definition we're supposed to use + // + for (FDev = mFlashDevices; FDev != NULL; FDev = FDev->Next) { + if (strcmp (FDev->Name, FlashDeviceName) == 0) { + break; + } + } + + if (FDev == NULL) { + Error (NULL, 0, 0, NULL, FlashDeviceName, "flash device not found in flash definitions"); + return STATUS_ERROR; + } + + if ((OutFptr = fopen (FileName, "w")) == NULL) { + Error (NULL, 0, 0, FileName, "failed to open output file for writing"); + return STATUS_ERROR; + } + // + // Write a header + // + fprintf (OutFptr, CIncludeHeader); + // + // Write flash block base and size defines + // + fprintf (OutFptr, "#define FLASH_BASE 0x%08X\n", FDev->BaseAddress); + fprintf (OutFptr, "#define FLASH_SIZE 0x%08X\n\n", FDev->Size); + // + // Write flash regions base, size and offset defines + // + Offset = 0; + CreateHobs = 0; + for (FBlock = FDev->Regions; FBlock != NULL; FBlock = FBlock->Next) { + fprintf ( + OutFptr, + "#define FLASH_REGION_%s_BASE %*c0x%08X\n", + FBlock->Name, + COLUMN2_START - 40 - strlen (FBlock->Name), + ' ', + Offset + FDev->BaseAddress + ); + fprintf ( + OutFptr, + "#define FLASH_REGION_%s_SIZE %*c0x%08X\n", + FBlock->Name, + COLUMN2_START - 40 - strlen (FBlock->Name), + ' ', + FBlock->Size + ); + fprintf ( + OutFptr, + "#define FLASH_REGION_%s_OFFSET %*c0x%08X\n", + FBlock->Name, + COLUMN2_START - 40 - strlen (FBlock->Name), + ' ', + Offset + ); + // + // Create defines for any subregions + // + SubregionOffset = 0; + for (Subregion = FBlock->Subregions; Subregion != NULL; Subregion = Subregion->Next) { + fprintf ( + OutFptr, + "#define FLASH_REGION_%s_SUBREGION_%s_BASE %*c0x%08X\n", + FBlock->Name, + Subregion->Name, + COLUMN3_START - 43 - strlen (FBlock->Name) - strlen (Subregion->Name), + ' ', + FDev->BaseAddress + Offset + SubregionOffset + ); + fprintf ( + OutFptr, + "#define FLASH_REGION_%s_SUBREGION_%s_SIZE %*c0x%08X\n", + FBlock->Name, + Subregion->Name, + COLUMN3_START - 43 - strlen (FBlock->Name) - strlen (Subregion->Name), + ' ', + Subregion->Size + ); + fprintf ( + OutFptr, + "#define FLASH_REGION_%s_SUBREGION_%s_OFFSET %*c0x%08X\n", + FBlock->Name, + Subregion->Name, + COLUMN3_START - 43 - strlen (FBlock->Name) - strlen (Subregion->Name), + ' ', + Offset + SubregionOffset + ); + SubregionOffset += Subregion->Size; + if (Subregion->CreateHob != 0) { + CreateHobs = 1; + } + } + + Offset += FBlock->Size; + } + // + // Now create a #define for the flash map data definition + // + fprintf (OutFptr, "\n\n#define EFI_FLASH_AREA_DATA_DEFINITION \\\n"); + // + // Emit entry for each region + // + Offset = 0; + for (FBlock = FDev->Regions; FBlock != NULL; FBlock = FBlock->Next) { + fprintf (OutFptr, " /* %s region */\\\n", FBlock->Name); + fprintf (OutFptr, " {\\\n"); + fprintf (OutFptr, " FLASH_REGION_%s_BASE,\\\n", FBlock->Name); + fprintf (OutFptr, " FLASH_REGION_%s_SIZE,\\\n", FBlock->Name); + fprintf (OutFptr, " %s,\\\n", FBlock->Attributes); + fprintf (OutFptr, " %s,\\\n },\\\n", FBlock->AreaType); + } + + fprintf (OutFptr, "\n\n"); + // + // Now walk the list again to create the EFI_HOB_FLASH_MAP_ENTRY_TYPE definition + // + if (CreateHobs != 0) { + fprintf (OutFptr, "//\n// EFI_HOB_FLASH_MAP_ENTRY_TYPE definition\n//\n"); + fprintf (OutFptr, "#define EFI_HOB_FLASH_MAP_ENTRY_TYPE_DATA_DEFINITION"); + for (FBlock = FDev->Regions; FBlock != NULL; FBlock = FBlock->Next) { + // + // See if the block has subregions, and that the CreateHobs flag is set + // for any of them. + // + CreateHobs = 0; + for (Subregion = FBlock->Subregions; Subregion != NULL; Subregion = Subregion->Next) { + if (Subregion->CreateHob != 0) { + CreateHobs = 1; + break; + } + } + // + // If any of the subregions had the CreateHobs flag set, then create the entries in the + // output file + // + if (CreateHobs != 0) { + for (Subregion = FBlock->Subregions; Subregion != NULL; Subregion = Subregion->Next) { + if (Subregion->CreateHob != 0) { + fprintf (OutFptr, " \\\n"); + fprintf (OutFptr, " /* %s.%s Subregion */\\\n", FBlock->Name, Subregion->Name); + fprintf (OutFptr, " {\\\n"); + fprintf (OutFptr, " EFI_HOB_TYPE_GUID_EXTENSION,\\\n"); + fprintf (OutFptr, " sizeof (EFI_HOB_FLASH_MAP_ENTRY_TYPE ),\\\n"); + fprintf (OutFptr, " 0,\\\n"); + // + // The NameGuid may have been specified in the input flash definition file as a GUID, or + // as a quoted string. Do the right one. + // + if (Subregion->NameGuidString[0] != 0) { + fprintf (OutFptr, " %s, \\\n", Subregion->NameGuidString); + } else { + fprintf ( + OutFptr, + " { 0x%08X, 0x%04X, 0x%04X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X },\\\n", + Subregion->NameGuid.Data1, + (unsigned int) Subregion->NameGuid.Data2, + (unsigned int) Subregion->NameGuid.Data3, + (unsigned int) Subregion->NameGuid.Data4[0], + (unsigned int) Subregion->NameGuid.Data4[1], + (unsigned int) Subregion->NameGuid.Data4[2], + (unsigned int) Subregion->NameGuid.Data4[3], + (unsigned int) Subregion->NameGuid.Data4[4], + (unsigned int) Subregion->NameGuid.Data4[5], + (unsigned int) Subregion->NameGuid.Data4[6], + (unsigned int) Subregion->NameGuid.Data4[7] + ); + } + + fprintf (OutFptr, " 0, 0, 0,\\\n"); + fprintf (OutFptr, " %s,\\\n", Subregion->AreaType); + // + // The AreaTypeGuid may have been specified in the input flash definition file as a GUID, or + // as a quoted string. Do the right one. + // + if (Subregion->AreaTypeGuidString[0] != 0) { + fprintf (OutFptr, " %s, \\\n", Subregion->AreaTypeGuidString); + } else { + fprintf ( + OutFptr, + " { 0x%08X, 0x%04X, 0x%04X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X },\\\n", + Subregion->AreaTypeGuid.Data1, + (unsigned int) Subregion->AreaTypeGuid.Data2, + (unsigned int) Subregion->AreaTypeGuid.Data3, + (unsigned int) Subregion->AreaTypeGuid.Data4[0], + (unsigned int) Subregion->AreaTypeGuid.Data4[1], + (unsigned int) Subregion->AreaTypeGuid.Data4[2], + (unsigned int) Subregion->AreaTypeGuid.Data4[3], + (unsigned int) Subregion->AreaTypeGuid.Data4[4], + (unsigned int) Subregion->AreaTypeGuid.Data4[5], + (unsigned int) Subregion->AreaTypeGuid.Data4[6], + (unsigned int) Subregion->AreaTypeGuid.Data4[7] + ); + } + + fprintf (OutFptr, " 1,\\\n"); + fprintf (OutFptr, " {\\\n"); + fprintf (OutFptr, " %s,\\\n", Subregion->Attributes); + fprintf (OutFptr, " 0,\\\n"); + fprintf (OutFptr, " FLASH_REGION_%s_SUBREGION_%s_BASE,\\\n", FBlock->Name, Subregion->Name); + fprintf (OutFptr, " FLASH_REGION_%s_SUBREGION_%s_SIZE,\\\n", FBlock->Name, Subregion->Name); + // + // The FileSystemGuid may have been specified in the input flash definition file as a GUID, or + // as a quoted string. Do the right one. + // + if (Subregion->FileSystemGuidString[0] != 0) { + fprintf (OutFptr, " %s, \\\n", Subregion->FileSystemGuidString); + } else { + fprintf ( + OutFptr, + " { 0x%08X, 0x%04X, 0x%04X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X },\\\n", + Subregion->FileSystemGuid.Data1, + (unsigned int) Subregion->FileSystemGuid.Data2, + (unsigned int) Subregion->FileSystemGuid.Data3, + (unsigned int) Subregion->FileSystemGuid.Data4[0], + (unsigned int) Subregion->FileSystemGuid.Data4[1], + (unsigned int) Subregion->FileSystemGuid.Data4[2], + (unsigned int) Subregion->FileSystemGuid.Data4[3], + (unsigned int) Subregion->FileSystemGuid.Data4[4], + (unsigned int) Subregion->FileSystemGuid.Data4[5], + (unsigned int) Subregion->FileSystemGuid.Data4[6], + (unsigned int) Subregion->FileSystemGuid.Data4[7] + ); + } + + fprintf (OutFptr, " },\\\n"); + fprintf (OutFptr, " },"); + } + } + } + } + + fprintf (OutFptr, "\n\n"); + } + + // + // Write the file's closing #endif + // + fprintf (OutFptr, CIncludeFooter); + fclose (OutFptr); + return STATUS_SUCCESS; +} + +STATUS +FDFCreateAsmIncludeFile ( + char *FlashDeviceName, + char *FileName + ) +/*++ + +Routine Description: + Create an assembly header file with equate definitions per an already-parsed + flash definition file. + +Arguments: + FlashDeviceName - name of flash device (from the flash definition file) + to use + FileName - name of output file to create + +Returns: + STATUS_SUCCESS - no errors or warnings + STATUS_WARNING - warnings, but no errors, were encountered + STATUS_ERROR - errors were encountered + +--*/ +{ + FILE *OutFptr; + FLASH_BLOCK_DESCRIPTION *FBlock; + FLASH_DEVICE_DESCRIPTION *FDev; + unsigned int Offset; + FLASH_SUBREGION_DESCRIPTION *Subregion; + unsigned int SubregionOffset; + // + // Find the definition we're supposed to use + // + for (FDev = mFlashDevices; FDev != NULL; FDev = FDev->Next) { + if (strcmp (FDev->Name, FlashDeviceName) == 0) { + break; + } + } + + if (FDev == NULL) { + Error (NULL, 0, 0, NULL, FlashDeviceName, "flash device not found in flash definitions"); + return STATUS_ERROR; + } + + if ((OutFptr = fopen (FileName, "w")) == NULL) { + Error (NULL, 0, 0, FileName, "failed to open output file for writing"); + return STATUS_ERROR; + } + // + // Write a header + // + fprintf (OutFptr, "\n\n"); + // + // Write flash block size and offset defines + // + fprintf ( + OutFptr, + "FLASH_BASE %*cequ 0%08Xh\n", + COLUMN2_START - 40, + ' ', + FDev->BaseAddress + ); + fprintf (OutFptr, "FLASH_SIZE %*cequ 0%08Xh\n", COLUMN2_START - 40, ' ', FDev->Size); + // + // Write flash region size and offset defines + // + fprintf (OutFptr, "\n"); + Offset = 0; + for (FBlock = FDev->Regions; FBlock != NULL; FBlock = FBlock->Next) { + fprintf ( + OutFptr, + "FLASH_REGION_%s_BASE %*cequ 0%08Xh\n", + FBlock->Name, + COLUMN2_START - 20 - strlen (FBlock->Name), + ' ', + FDev->BaseAddress + Offset + ); + fprintf ( + OutFptr, + "FLASH_REGION_%s_SIZE %*cequ 0%08Xh\n", + FBlock->Name, + COLUMN2_START - 20 - strlen (FBlock->Name), + ' ', + FBlock->Size + ); + fprintf ( + OutFptr, + "FLASH_REGION_%s_OFFSET %*cequ 0%08Xh\n", + FBlock->Name, + COLUMN2_START - 20 - strlen (FBlock->Name), + ' ', + Offset + ); + // + // Create defines for any subregions + // + SubregionOffset = 0; + for (Subregion = FBlock->Subregions; Subregion != NULL; Subregion = Subregion->Next) { + fprintf ( + OutFptr, + "FLASH_REGION_%s_SUBREGION_%s_BASE %*cequ 0%08Xh\n", + FBlock->Name, + Subregion->Name, + COLUMN3_START - 39 - strlen (FBlock->Name) - strlen (Subregion->Name), + ' ', + FDev->BaseAddress + Offset + SubregionOffset + ); + fprintf ( + OutFptr, + "FLASH_REGION_%s_SUBREGION_%s_SIZE %*cequ 0%08Xh\n", + FBlock->Name, + Subregion->Name, + COLUMN3_START - 39 - strlen (FBlock->Name) - strlen (Subregion->Name), + ' ', + Subregion->Size + ); + fprintf ( + OutFptr, + "FLASH_REGION_%s_SUBREGION_%s_OFFSET %*cequ 0%08Xh\n", + FBlock->Name, + Subregion->Name, + COLUMN3_START - 39 - strlen (FBlock->Name) - strlen (Subregion->Name), + ' ', + Offset + SubregionOffset + ); + SubregionOffset += Subregion->Size; + } + + Offset += FBlock->Size; + } + + // + // Write closing \n + // + fprintf (OutFptr, "\n\n"); + fclose (OutFptr); + return STATUS_SUCCESS; +} + +STATUS +FDFCreateSymbols ( + char *FlashDeviceName + ) +/*++ + +Routine Description: + Using the given flash device name, add symbols to the global symbol table. This + allows other functions to use the symbol definitions for other purposes. + +Arguments: + FlashDeviceName - name of flash device (from the flash definition file) + to use + +Returns: + STATUS_SUCCESS - no errors or warnings + STATUS_WARNING - warnings, but no errors, were encountered + STATUS_ERROR - errors were encountered + +--*/ +{ + FLASH_BLOCK_DESCRIPTION *FBlock; + FLASH_DEVICE_DESCRIPTION *FDev; + unsigned int Offset; + char SymName[120]; + char SymValue[120]; + FLASH_SUBREGION_DESCRIPTION *Subregion; + unsigned int SubregionOffset; + // + // Find the definition we're supposed to use + // + for (FDev = mFlashDevices; FDev != NULL; FDev = FDev->Next) { + if (strcmp (FDev->Name, FlashDeviceName) == 0) { + break; + } + } + + if (FDev == NULL) { + Error (NULL, 0, 0, NULL, FlashDeviceName, "flash device not found in flash definitions"); + return STATUS_ERROR; + } + + sprintf (SymValue, "0x%08X", FDev->BaseAddress); + SymbolAdd ("FLASH_BASE", SymValue, 0); + sprintf (SymValue, "0x%08X", FDev->Size); + SymbolAdd ("FLASH_SIZE", SymValue, 0); + // + // Add flash block size and offset defines + // + // Offset = 0; + // for (FBlock = FDev->PBlocks; FBlock != NULL; FBlock = FBlock->Next) { + // sprintf (SymName, "FLASH_BLOCK_%s_BASE", FBlock->Name); + // sprintf (SymValue, "0x%08X", FDev->BaseAddress + Offset); + // SymbolAdd (SymName, SymValue, 0); + // sprintf (SymName, "FLASH_BLOCK_%s_SIZE", FBlock->Name); + // sprintf (SymValue, "0x%08X", FBlock->Size); + // SymbolAdd (SymName, SymValue, 0); + // sprintf (SymName, "FLASH_BLOCK_%s_OFFSET", FBlock->Name); + // sprintf (SymValue, "0x%08X", Offset); + // SymbolAdd (SymName, SymValue, 0); + // Offset += FBlock->Size; + // } + // + // Add flash region block base, size, and offset defines + // + Offset = 0; + for (FBlock = FDev->Regions; FBlock != NULL; FBlock = FBlock->Next) { + sprintf (SymName, "FLASH_REGION_%s_BASE", FBlock->Name); + sprintf (SymValue, "0x%08X", FDev->BaseAddress + Offset); + SymbolAdd (SymName, SymValue, 0); + sprintf (SymName, "FLASH_REGION_%s_SIZE", FBlock->Name); + sprintf (SymValue, "0x%08X", FBlock->Size); + SymbolAdd (SymName, SymValue, 0); + sprintf (SymName, "FLASH_REGION_%s_OFFSET", FBlock->Name); + sprintf (SymValue, "0x%08X", Offset); + SymbolAdd (SymName, SymValue, 0); + // + // Add subregion symbols + // + if (FBlock->Subregions != NULL) { + SubregionOffset = 0; + for (Subregion = FBlock->Subregions; Subregion != NULL; Subregion = Subregion->Next) { + sprintf (SymName, "FLASH_REGION_%s_SUBREGION_%s_BASE", FBlock->Name, Subregion->Name); + sprintf (SymValue, "0x%08X", FDev->BaseAddress + Offset + SubregionOffset); + SymbolAdd (SymName, SymValue, 0); + sprintf (SymName, "FLASH_REGION_%s_SUBREGION_%s_SIZE", FBlock->Name, Subregion->Name); + sprintf (SymValue, "0x%08X", Subregion->Size); + SymbolAdd (SymName, SymValue, 0); + sprintf (SymName, "FLASH_REGION_%s_SUBREGION_%s_OFFSET", FBlock->Name, Subregion->Name); + sprintf (SymValue, "0x%08X", Offset + SubregionOffset); + SymbolAdd (SymName, SymValue, 0); + SubregionOffset += Subregion->Size; + } + } + + Offset += FBlock->Size; + } + + return STATUS_SUCCESS; +} + +STATUS +FDFCreateImage ( + char *FlashDeviceName, + char *ImageName, + char *FileName + ) +/*++ + +Routine Description: + Create a flash image using the given device and image names. + +Arguments: + FlashDeviceName - name of flash device (from the flash definition file) + to use + ImageName - name of image (from the flash definition file) to create + FileName - name of output file to create + +Returns: + STATUS_SUCCESS - no errors or warnings + STATUS_WARNING - warnings, but no errors, were encountered + STATUS_ERROR - errors were encountered + +--*/ +{ + STATUS Status; + FILE *OutFptr; + FLASH_BLOCK_DESCRIPTION *RegionDef; + FLASH_DEVICE_DESCRIPTION *FDev; + IMAGE_DEFINITION *ImageDef; + unsigned int Offset; + char *Buffer; + FILE *InFptr; + long FileSize; + IMAGE_DEFINITION_ENTRY *IDefEntry; + FLASH_SUBREGION_DESCRIPTION *SubregionDef; + // + // Find the flash definition we're supposed to use + // + InFptr = NULL; + Status = STATUS_ERROR; + for (FDev = mFlashDevices; FDev != NULL; FDev = FDev->Next) { + if (strcmp (FDev->Name, FlashDeviceName) == 0) { + break; + } + } + + if (FDev == NULL) { + Error (NULL, 0, 0, FlashDeviceName, "flash device not found in flash definitions"); + return STATUS_ERROR; + } + // + // Find the image name we're supposed to create + // + for (ImageDef = mImageDefinitions; ImageDef != NULL; ImageDef = ImageDef->Next) { + if (strcmp (ImageDef->Name, ImageName) == 0) { + break; + } + } + + if (ImageDef == NULL) { + Error (NULL, 0, 0, ImageName, "image definition not found in image definitions"); + return STATUS_ERROR; + } + // + // Open the output file + // + if ((OutFptr = fopen (FileName, "wb")) == NULL) { + Error (NULL, 0, 0, FileName, "failed to open output file for writing"); + return STATUS_ERROR; + } + // + // Allocate a buffer to copy the input data to + // + Buffer = (char *) _malloc (FDev->Size); + if (Buffer == NULL) { + Error (NULL, 0, 0, (INT8 *) "failed to allocate memory", NULL); + goto Done; + } + // + // Set contents of buffer to the erased value + // + if (FDev->ErasePolarity) { + memset (Buffer, 0xFF, FDev->Size); + } else { + memset (Buffer, 0, FDev->Size); + } + // + // Set all region and subregion size-left fields to the size of the region/subregion + // + for (RegionDef = FDev->Regions; RegionDef != NULL; RegionDef = RegionDef->Next) { + RegionDef->SizeLeft = RegionDef->Size; + for (SubregionDef = RegionDef->Subregions; SubregionDef != NULL; SubregionDef = SubregionDef->Next) { + SubregionDef->SizeLeft = SubregionDef->Size; + } + } + // + // Now go through the image list, read files into the buffer. + // + for (IDefEntry = ImageDef->Entries; IDefEntry != NULL; IDefEntry = IDefEntry->Next) { + // + // If it's a file name, open the file, get the size, find the corresponding + // flash region it's in, and copy the data. + // + if (IDefEntry->IsRawData == 0) { + if ((InFptr = fopen (IDefEntry->Name, "rb")) == NULL) { + Error (NULL, 0, 0, IDefEntry->Name, "failed to open input file for reading"); + goto Done; + } + + fseek (InFptr, 0, SEEK_END); + FileSize = ftell (InFptr); + fseek (InFptr, 0, SEEK_SET); + } else { + FileSize = IDefEntry->RawDataSize; + } + // + // Find the region/subregion it's in, see if we have space left + // + Offset = 0; + for (RegionDef = FDev->Regions; RegionDef != NULL; RegionDef = RegionDef->Next) { + if (strcmp (RegionDef->Name, IDefEntry->RegionName) == 0) { + break; + } + + Offset += RegionDef->Size; + } + + if (RegionDef == NULL) { + Error (NULL, 0, 0, IDefEntry->RegionName, "Region name not found in FlashDevice %s definition", FDev->Name); + goto Done; + } + + // + // Check for subregion + // + if (IDefEntry->SubregionName[0] != 0) { + for (SubregionDef = RegionDef->Subregions; SubregionDef != NULL; SubregionDef = SubregionDef->Next) { + if (strcmp (SubregionDef->Name, IDefEntry->SubregionName) == 0) { + break; + } + + Offset += SubregionDef->Size; + } + + if (SubregionDef == NULL) { + Error ( + NULL, + 0, + 0, + IDefEntry->SubregionName, + "Subregion name not found in FlashDevice %s.%s Region definition", + FDev->Name, + RegionDef->Name + ); + goto Done; + } + // + // Enough space in the subregion? + // + if (SubregionDef->SizeLeft < (unsigned int) FileSize) { + Error ( + NULL, + 0, + 0, + IDefEntry->Name, + "insufficient space in Subregion (at least 0x%X additional bytes required)", + FileSize - SubregionDef->SizeLeft + ); + goto Done; + } + + // + // Read the file into the buffer if it's a file. Otherwise copy the raw data + // + if (IDefEntry->IsRawData == 0) { + if (fread (Buffer + Offset + (SubregionDef->Size - SubregionDef->SizeLeft), FileSize, 1, InFptr) != 1) { + Error (NULL, 0, 0, IDefEntry->Name, "failed to read file contents"); + goto Done; + } + + fclose (InFptr); + InFptr = NULL; + } else { + memcpy ( + Buffer + Offset + (SubregionDef->Size - SubregionDef->SizeLeft), + IDefEntry->RawData, + IDefEntry->RawDataSize + ); + } + + SubregionDef->SizeLeft -= FileSize; + // + // Align based on the Region alignment requirements. + // + if (RegionDef->Alignment != 0) { + while (((unsigned int) (SubregionDef->Size - SubregionDef->SizeLeft) &~RegionDef->Alignment) != 0) { + if (SubregionDef->SizeLeft == 0) { + break; + } + + SubregionDef->SizeLeft--; + } + } + } else { + // + // Placing data in a region. Check for enough space in the region left. + // + if (RegionDef->SizeLeft < (unsigned int) FileSize) { + Error ( + NULL, + 0, + 0, + IDefEntry->Name, + "insufficient space in Region (at least 0x%X additional bytes required)", + FileSize - RegionDef->SizeLeft + ); + goto Done; + } + + // + // Read the file into the buffer if it's a file. Otherwise copy the raw data + // + if (IDefEntry->IsRawData == 0) { + if (fread (Buffer + Offset + (RegionDef->Size - RegionDef->SizeLeft), FileSize, 1, InFptr) != 1) { + Error (NULL, 0, 0, IDefEntry->Name, "failed to read file contents"); + goto Done; + } + + fclose (InFptr); + InFptr = NULL; + } else { + memcpy (Buffer + Offset + (RegionDef->Size - RegionDef->SizeLeft), IDefEntry->RawData, IDefEntry->RawDataSize); + } + + RegionDef->SizeLeft -= FileSize; + // + // Align + // + if (RegionDef->Alignment != 0) { + while (((unsigned int) (RegionDef->Size - RegionDef->SizeLeft) &~RegionDef->Alignment) != 0) { + if (RegionDef->SizeLeft == 0) { + break; + } + + RegionDef->SizeLeft--; + } + } + } + } + + if (fwrite (Buffer, FDev->Size, 1, OutFptr) != 1) { + Error (NULL, 0, 0, "failed to write buffer contents to output file", NULL); + goto Done; + } + + Status = STATUS_SUCCESS; +Done: + if (InFptr != NULL) { + fclose (InFptr); + } + + if (Buffer != NULL) { + _free (Buffer); + } + + if (OutFptr != NULL) { + fclose (OutFptr); + if (Status == STATUS_ERROR) { + remove (FileName); + } + } + + return Status; +} + +STATUS +FDFCreateDscFile ( + char *FlashDeviceName, + char *FileName + ) +/*++ + +Routine Description: + Create a DSC-style output file with equates for flash management. + +Arguments: + FlashDeviceName - name of flash device (from the flash definition file) + to use + FileName - name of output file to create + +Returns: + STATUS_SUCCESS - no errors or warnings + STATUS_WARNING - warnings, but no errors, were encountered + STATUS_ERROR - errors were encountered + +--*/ +{ + FILE *OutFptr; + FLASH_BLOCK_DESCRIPTION *FBlock; + FLASH_DEVICE_DESCRIPTION *FDev; + unsigned int Offset; + FLASH_SUBREGION_DESCRIPTION *Subregion; + unsigned int SubregionOffset; + // + // Find the definition we're supposed to use + // + for (FDev = mFlashDevices; FDev != NULL; FDev = FDev->Next) { + if (strcmp (FDev->Name, FlashDeviceName) == 0) { + break; + } + } + + if (FDev == NULL) { + Error (NULL, 0, 0, FlashDeviceName, "flash device not found in flash definitions"); + return STATUS_ERROR; + } + + if ((OutFptr = fopen (FileName, "w")) == NULL) { + Error (NULL, 0, 0, FileName, "failed to open output file for writing"); + return STATUS_ERROR; + } + // + // Write the flash base address and size + // + fprintf (OutFptr, "\n"); + fprintf (OutFptr, "FLASH_BASE = 0x%08X\n", FDev->BaseAddress); + fprintf (OutFptr, "FLASH_SIZE = 0x%08X\n\n", FDev->Size); + // + // Write flash block size and offset defines + // + Offset = 0; + for (FBlock = FDev->Regions; FBlock != NULL; FBlock = FBlock->Next) { + fprintf ( + OutFptr, + "FLASH_REGION_%s_BASE %*c= 0x%08X\n", + FBlock->Name, + COLUMN2_START - 40 - strlen (FBlock->Name), + ' ', + Offset + FDev->BaseAddress + ); + fprintf ( + OutFptr, + "FLASH_REGION_%s_SIZE %*c= 0x%08X\n", + FBlock->Name, + COLUMN2_START - 40 - strlen (FBlock->Name), + ' ', + FBlock->Size + ); + fprintf ( + OutFptr, + "FLASH_REGION_%s_SIZE_BLOCKS %*c= 0x%x\n", + FBlock->Name, + COLUMN2_START - 40 - strlen (FBlock->Name), + ' ', + (FBlock->Size)/(FDev->PBlocks->Size) + ); + // + // Create defines for any subregions + // + SubregionOffset = 0; + for (Subregion = FBlock->Subregions; Subregion != NULL; Subregion = Subregion->Next) { + fprintf ( + OutFptr, + "FLASH_REGION_%s_SUBREGION_%s_BASE %*c= 0x%08X\n", + FBlock->Name, + Subregion->Name, + COLUMN3_START - 48 - strlen (FBlock->Name) - strlen (Subregion->Name), + ' ', + FDev->BaseAddress + Offset + SubregionOffset + ); + fprintf ( + OutFptr, + "FLASH_REGION_%s_SUBREGION_%s_SIZE %*c= 0x%08X\n", + FBlock->Name, + Subregion->Name, + COLUMN3_START - 48 - strlen (FBlock->Name) - strlen (Subregion->Name), + ' ', + Subregion->Size + ); + fprintf ( + OutFptr, + "FLASH_REGION_%s_SUBREGION_%s_OFFSET %*c= 0x%08X\n", + FBlock->Name, + Subregion->Name, + COLUMN3_START - 48 - strlen (FBlock->Name) - strlen (Subregion->Name), + ' ', + Offset + SubregionOffset + ); + + SubregionOffset += Subregion->Size; + } + + Offset += FBlock->Size; + } + // + // Close file + // + fprintf (OutFptr, "\n"); + fclose (OutFptr); + return STATUS_SUCCESS; +} + + +/*++ + +Routine Description: + The following buffer management routines are used to encapsulate functionality + for managing a growable data buffer. + +Arguments: + BUFFER_DATA - structure that is used to maintain a data buffer + +Returns: + NA + +--*/ +static +BUFFER_DATA * +CreateBufferData ( + VOID + ) +/*++ + +Routine Description: + + Create a growable data buffer with default buffer length. + +Arguments: + + None + +Returns: + + NULL - error occured during data buffer creation + Not NULL - the pointer to the newly created data buffer + +--*/ +{ + BUFFER_DATA *BD; + BD = (BUFFER_DATA *) _malloc (sizeof (BUFFER_DATA)); + if (BD == NULL) { + Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL); + return NULL; + } + + memset (BD, 0, sizeof (BUFFER_DATA)); + BD->BufferStart = (char *) _malloc (BUFFER_SIZE); + if (BD->BufferStart == NULL) { + _free (BD); + Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL); + return NULL; + } + + BD->BufferEnd = BD->BufferStart + BUFFER_SIZE; + BD->BufferPos = BD->BufferStart; + return BD; +} + +static +BOOLEAN +AddBufferDataByte ( + BUFFER_DATA *Buffer, + char Data + ) +/*++ + +Routine Description: + + Add a single byte to a growable data buffer, growing the buffer if required. + +Arguments: + + Buffer - pointer to the growable data buffer to add a single byte to + Data - value of the single byte data to be added + +Returns: + + TRUE - the single byte data was successfully added + FALSE - error occurred, the single byte data was not added + +--*/ +{ + int Size; + char *NewBuffer; + // + // See if we have to grow the buffer + // + if (Buffer->BufferPos >= Buffer->BufferEnd) { + Size = (int) Buffer->BufferEnd - (int) Buffer->BufferStart; + NewBuffer = (char *) _malloc (Size + BUFFER_SIZE); + if (NewBuffer == NULL) { + Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL); + return FALSE; + } + + memcpy (NewBuffer, Buffer->BufferStart, Size); + _free (Buffer->BufferStart); + Buffer->BufferStart = NewBuffer; + Buffer->BufferPos = Buffer->BufferStart + Size; + Buffer->BufferEnd = Buffer->BufferStart + Size + BUFFER_SIZE; + } + + *Buffer->BufferPos = Data; + Buffer->BufferPos++; + return TRUE; +} + +static +void +FreeBufferData ( + BUFFER_DATA *Buffer, + BOOLEAN FreeData + ) +/*++ + +Routine Description: + + Free memory used to manage a growable data buffer. + +Arguments: + + Buffer - pointer to the growable data buffer to be destructed + FreeData - TRUE, free memory containing the buffered data + FALSE, do not free the buffered data memory + +Returns: + + None + +--*/ +{ + if (Buffer != NULL) { + if (FreeData && (Buffer->BufferStart != NULL)) { + _free (Buffer->BufferStart); + } + + _free (Buffer); + } +} + +static +char * +GetBufferData ( + BUFFER_DATA *Buffer, + int *BufferSize + ) +/*++ + +Routine Description: + + Return a pointer and size of the data in a growable data buffer. + +Arguments: + + Buffer - pointer to the growable data buffer + BufferSize - size of the data in the growable data buffer + +Returns: + + pointer of the data in the growable data buffer + +--*/ +{ + *BufferSize = (int) Buffer->BufferPos - (int) Buffer->BufferStart; + return Buffer->BufferStart; +} + +STATUS +FDDiscover ( + char *FDFileName, + unsigned int BaseAddr + ) +/*++ + +Routine Description: + Walk a binary image and see if you find anything that looks like a + firmware volume. + +Arguments: + FDFileName - name of input FD image to parse + BaseAddr - base address of input FD image + +Returns: + STATUS_SUCCESS - no errors or warnings + STATUS_WARNING - warnings, but no errors, were encountered + STATUS_ERROR - errors were encountered + +NOTE: + This routine is used for debug purposes only. + +--*/ +{ + FILE *InFptr; + long FileSize; + long Offset; + EFI_FIRMWARE_VOLUME_HEADER FVHeader; + EFI_GUID + FileSystemGuid = { 0x7A9354D9, 0x0468, 0x444a, 0x81, 0xCE, 0x0B, 0xF6, 0x17, 0xD8, 0x90, 0xDF }; + + if ((InFptr = fopen (FDFileName, "rb")) == NULL) { + Error (NULL, 0, 0, FDFileName, "failed to open file for reading"); + return STATUS_ERROR; + } + + fseek (InFptr, 0, SEEK_END); + FileSize = ftell (InFptr); + fseek (InFptr, 0, SEEK_SET); + Offset = 0; + while (Offset < FileSize) { + fseek (InFptr, Offset, SEEK_SET); + // + // Read the contents of the file, see if it's an FV header + // + if (fread (&FVHeader, sizeof (EFI_FIRMWARE_VOLUME_HEADER), 1, InFptr) == 1) { + // + // Check version and GUID + // + if ((FVHeader.Revision == EFI_FVH_REVISION) && (FVHeader.Signature == EFI_FVH_SIGNATURE)) { + fprintf (stdout, "FV header at 0x%08X FVSize=0x%08X ", Offset + BaseAddr, (UINT32) FVHeader.FvLength); + if (memcmp (&FVHeader.FileSystemGuid, &FileSystemGuid, sizeof (EFI_GUID)) == 0) { + fprintf (stdout, "standard FFS file system\n"); + } else { + fprintf (stdout, "non-standard FFS file system\n"); + } + } + } + + Offset += 16 * 1024; + } + + fclose (InFptr); + return STATUS_SUCCESS; +} diff --git a/Tools/Source/TianoTools/FlashMap/FlashDefFile.h b/Tools/Source/TianoTools/FlashMap/FlashDefFile.h new file mode 100644 index 0000000000..1ffbfb1508 --- /dev/null +++ b/Tools/Source/TianoTools/FlashMap/FlashDefFile.h @@ -0,0 +1,281 @@ +/*++ + +Copyright (c) 2004 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + + +Module Name: + + FlashDefFile.h + +Abstract: + + Header file for flash management utility in the Intel Platform + Innovation Framework for EFI build environment. + +--*/ + +#ifndef _FLASH_DEF_FILE_H_ +#define _FLASH_DEF_FILE_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +void +FDFConstructor ( + VOID + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + None + +Returns: + + GC_TODO: add return values + +--*/ +; + +void +FDFDestructor ( + VOID + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + None + +Returns: + + GC_TODO: add return values + +--*/ +; + +STATUS +FDFParseFile ( + char *FileName + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + FileName - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +STATUS +FDFCreateCIncludeFile ( + char *FlashDeviceName, + char *FileName + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + FlashDeviceName - GC_TODO: add argument description + FileName - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +STATUS +FDFCreateCFlashMapDataFile ( + char *FlashDeviceName, + char *FileName + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + FlashDeviceName - GC_TODO: add argument description + FileName - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +STATUS +FDFCreateAsmIncludeFile ( + char *FlashDeviceName, + char *FileName + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + FlashDeviceName - GC_TODO: add argument description + FileName - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +STATUS +FDFParseFile ( + char *FileName + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + FileName - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +STATUS +FDFCreateImage ( + char *FlashDeviceName, + char *ImageName, + char *FileName + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + FlashDeviceName - GC_TODO: add argument description + ImageName - GC_TODO: add argument description + FileName - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +STATUS +FDFCreateDscFile ( + char *FlashDeviceName, + char *FileName + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + FlashDeviceName - GC_TODO: add argument description + FileName - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +STATUS +FDFCreateSymbols ( + char *FlashDeviceName + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + FlashDeviceName - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +STATUS +FDDiscover ( + char *FDFileName, + unsigned int BaseAddr + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + FDFileName - GC_TODO: add argument description + BaseAddr - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +#ifdef __cplusplus +} +#endif + +#endif // #ifndef _FLASH_DEF_FILE_H_ diff --git a/Tools/Source/TianoTools/FlashMap/FlashMap.c b/Tools/Source/TianoTools/FlashMap/FlashMap.c new file mode 100644 index 0000000000..86e26b6fc7 --- /dev/null +++ b/Tools/Source/TianoTools/FlashMap/FlashMap.c @@ -0,0 +1,745 @@ +/*++ + +Copyright (c) 2004-2005 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + FlashMap.c + +Abstract: + + Utility for flash management in the Intel Platform Innovation Framework + for EFI build environment. + +--*/ + +#include +#include +#include +#include + +#include "Tiano.h" + +#ifndef INT8 +#define INT8 char +#endif + +#include "EfiUtilityMsgs.h" +#include "Microcode.h" +#include "FlashDefFile.h" +#include "Symbols.h" + +#define UTILITY_NAME "FlashMap" + +typedef struct _STRING_LIST { + struct _STRING_LIST *Next; + char *Str; +} STRING_LIST; + +// +// Keep our globals in one of these structures +// +static struct { + char *CIncludeFileName; + char *FlashDevice; + char *FlashDeviceImage; + char *MCIFileName; + char *MCOFileName; + char *ImageOutFileName; + char *DscFileName; + char *AsmIncludeFileName; + char *FlashDefinitionFileName; + char *StringReplaceInFileName; + char *StringReplaceOutFileName; + char *DiscoverFDImageName; + char MicrocodePadByteValue; + unsigned int MicrocodeAlignment; + STRING_LIST *MCIFileNames; + STRING_LIST *LastMCIFileNames; + unsigned int BaseAddress; +} mGlobals; + +#define DEFAULT_MC_PAD_BYTE_VALUE 0xFF +#define DEFAULT_MC_ALIGNMENT 16 + +static +STATUS +ProcessCommandLine ( + int argc, + char *argv[] + ); + +static +STATUS +MergeMicrocodeFiles ( + char *OutFileName, + STRING_LIST *FileNames, + unsigned int Alignment, + char PadByteValue + ); + +static +void +Usage ( + VOID + ); + +int +main ( + int argc, + char *argv[] + ) +/*++ + +Routine Description: + Parse the command line arguments and then call worker functions to do the work + +Arguments: + argc - number of elements in argv + argv - array of command-line arguments + +Returns: + STATUS_SUCCESS - no problems encountered while processing + STATUS_WARNING - warnings, but no errors, were encountered while processing + STATUS_ERROR - errors were encountered while processing + +--*/ +{ + STATUS Status; + + SetUtilityName (UTILITY_NAME); + Status = ProcessCommandLine (argc, argv); + if (Status != STATUS_SUCCESS) { + return Status; + } + // + // Check for discovery of an FD (command line option) + // + if (mGlobals.DiscoverFDImageName != NULL) { + Status = FDDiscover (mGlobals.DiscoverFDImageName, mGlobals.BaseAddress); + goto Done; + } + // + // If they're doing microcode file parsing, then do that + // + if (mGlobals.MCIFileName != NULL) { + MicrocodeConstructor (); + MicrocodeParseFile (mGlobals.MCIFileName, mGlobals.MCOFileName); + MicrocodeDestructor (); + } + // + // If they're doing microcode file merging, then do that now + // + if (mGlobals.MCIFileNames != NULL) { + MergeMicrocodeFiles ( + mGlobals.MCOFileName, + mGlobals.MCIFileNames, + mGlobals.MicrocodeAlignment, + mGlobals.MicrocodePadByteValue + ); + } + // + // If using a flash definition file, then process that and return + // + if (mGlobals.FlashDefinitionFileName != NULL) { + FDFConstructor (); + SymbolsConstructor (); + Status = FDFParseFile (mGlobals.FlashDefinitionFileName); + if (GetUtilityStatus () != STATUS_ERROR) { + // + // If they want us to do a string-replace on a file, then add the symbol definitions to + // the symbol table, and then do the string replace. + // + if (mGlobals.StringReplaceInFileName != NULL) { + Status = FDFCreateSymbols (mGlobals.FlashDevice); + Status = SymbolsFileStringsReplace (mGlobals.StringReplaceInFileName, mGlobals.StringReplaceOutFileName); + } + // + // If they want us to create a .h defines file or .c flashmap data file, then do so now + // + if (mGlobals.CIncludeFileName != NULL) { + Status = FDFCreateCIncludeFile (mGlobals.FlashDevice, mGlobals.CIncludeFileName); + } + if (mGlobals.AsmIncludeFileName != NULL) { + Status = FDFCreateAsmIncludeFile (mGlobals.FlashDevice, mGlobals.AsmIncludeFileName); + } + // + // If they want us to create an image, do that now + // + if (mGlobals.ImageOutFileName != NULL) { + Status = FDFCreateImage (mGlobals.FlashDevice, mGlobals.FlashDeviceImage, mGlobals.ImageOutFileName); + } + // + // If they want to create an output DSC file, do that now + // + if (mGlobals.DscFileName != NULL) { + Status = FDFCreateDscFile (mGlobals.FlashDevice, mGlobals.DscFileName); + } + } + SymbolsDestructor (); + FDFDestructor (); + } +Done: + // + // Free up memory + // + while (mGlobals.MCIFileNames != NULL) { + mGlobals.LastMCIFileNames = mGlobals.MCIFileNames->Next; + _free (mGlobals.MCIFileNames); + mGlobals.MCIFileNames = mGlobals.LastMCIFileNames; + } + return GetUtilityStatus (); +} + +static +STATUS +MergeMicrocodeFiles ( + char *OutFileName, + STRING_LIST *FileNames, + unsigned int Alignment, + char PadByteValue + ) +/*++ + +Routine Description: + + Merge binary microcode files into a single file, taking into consideration + the alignment and pad value. + +Arguments: + + OutFileName - name of the output file to create + FileNames - linked list of input microcode files to merge + Alignment - alignment for each microcode file in the output image + PadByteValue - value to use when padding to meet alignment requirements + +Returns: + + STATUS_SUCCESS - merge completed successfully or with acceptable warnings + STATUS_ERROR - merge failed, output file not created + +--*/ +{ + long FileSize; + long TotalFileSize; + FILE *InFptr; + FILE *OutFptr; + char *Buffer; + STATUS Status; + + // + // Open the output file + // + if ((OutFptr = fopen (OutFileName, "wb")) == NULL) { + Error (NULL, 0, 0, OutFileName, "failed to open output file for writing"); + return STATUS_ERROR; + } + // + // Walk the list of files + // + Status = STATUS_ERROR; + Buffer = NULL; + InFptr = NULL; + TotalFileSize = 0; + while (FileNames != NULL) { + // + // Open the file, determine the size, then read it in and write + // it back out. + // + if ((InFptr = fopen (FileNames->Str, "rb")) == NULL) { + Error (NULL, 0, 0, FileNames->Str, "failed to open input file for reading"); + goto Done; + } + fseek (InFptr, 0, SEEK_END); + FileSize = ftell (InFptr); + fseek (InFptr, 0, SEEK_SET); + if (FileSize != 0) { + Buffer = (char *) _malloc (FileSize); + if (Buffer == NULL) { + Error (NULL, 0, 0, "memory allocation failure", NULL); + goto Done; + } + if (fread (Buffer, FileSize, 1, InFptr) != 1) { + Error (NULL, 0, 0, FileNames->Str, "failed to read file contents"); + goto Done; + } + // + // Align + // + if (Alignment != 0) { + while ((TotalFileSize % Alignment) != 0) { + if (fwrite (&PadByteValue, 1, 1, OutFptr) != 1) { + Error (NULL, 0, 0, OutFileName, "failed to write pad bytes to output file"); + goto Done; + } + TotalFileSize++; + } + } + TotalFileSize += FileSize; + if (fwrite (Buffer, FileSize, 1, OutFptr) != 1) { + Error (NULL, 0, 0, OutFileName, "failed to write to output file"); + goto Done; + } + _free (Buffer); + Buffer = NULL; + } else { + Warning (NULL, 0, 0, FileNames->Str, "0-size file encountered"); + } + fclose (InFptr); + InFptr = NULL; + FileNames = FileNames->Next; + } + Status = STATUS_SUCCESS; +Done: + fclose (OutFptr); + if (InFptr != NULL) { + fclose (InFptr); + } + if (Buffer != NULL) { + _free (Buffer); + } + if (Status == STATUS_ERROR) { + remove (OutFileName); + } + return Status; +} + +static +STATUS +ProcessCommandLine ( + int argc, + char *argv[] + ) +/*++ + +Routine Description: + Process the command line arguments + +Arguments: + argc - Standard C entry point arguments + argv[] - Standard C entry point arguments + +Returns: + STATUS_SUCCESS - no problems encountered while processing + STATUS_WARNING - warnings, but no errors, were encountered while processing + STATUS_ERROR - errors were encountered while processing + +--*/ +{ + int ThingsToDo; + unsigned int Temp; + STRING_LIST *Str; + // + // Skip program name arg, process others + // + argc--; + argv++; + if (argc == 0) { + Usage (); + return STATUS_ERROR; + } + // + // Clear out our globals, then start walking the arguments + // + memset ((void *) &mGlobals, 0, sizeof (mGlobals)); + mGlobals.MicrocodePadByteValue = DEFAULT_MC_PAD_BYTE_VALUE; + mGlobals.MicrocodeAlignment = DEFAULT_MC_ALIGNMENT; + ThingsToDo = 0; + while (argc > 0) { + if (strcmp (argv[0], "-?") == 0) { + Usage (); + return STATUS_ERROR; + } else if (strcmp (argv[0], "-hfile") == 0) { + // + // -hfile FileName + // + // Used to specify an output C #include file to create that contains + // #define statements for all the flashmap region offsets and sizes. + // Check for additional argument. + // + if (argc < 2) { + Error (NULL, 0, 0, argv[0], "option requires an output file name"); + return STATUS_ERROR; + } + argc--; + argv++; + mGlobals.CIncludeFileName = argv[0]; + ThingsToDo++; + } else if (strcmp (argv[0], "-flashdevice") == 0) { + // + // -flashdevice FLASH_DEVICE_NAME + // + // Used to select which flash device definition to operate on. + // Check for additional argument + // + if (argc < 2) { + Error (NULL, 0, 0, argv[0], "option requires a flash device name to use"); + return STATUS_ERROR; + } + argc--; + argv++; + mGlobals.FlashDevice = argv[0]; + } else if (strcmp (argv[0], "-mco") == 0) { + // + // -mco OutFileName + // + // Used to specify a microcode output binary file to create. + // Check for additional argument. + // + if (argc < 2) { + Error (NULL, 0, 0, (INT8 *) argv[0], (INT8 *) "option requires an output microcode file name to create"); + return STATUS_ERROR; + } + argc--; + argv++; + mGlobals.MCOFileName = argv[0]; + ThingsToDo++; + } else if (strcmp (argv[0], "-asmincfile") == 0) { + // + // -asmincfile FileName + // + // Used to specify the name of the output assembly include file that contains + // equates for the flash region addresses and sizes. + // Check for additional argument. + // + if (argc < 2) { + Error (NULL, 0, 0, argv[0], "option requires an output ASM include file name to create"); + return STATUS_ERROR; + } + argc--; + argv++; + mGlobals.AsmIncludeFileName = argv[0]; + ThingsToDo++; + } else if (strcmp (argv[0], "-mci") == 0) { + // + // -mci FileName + // + // Used to specify an input microcode text file to parse. + // Check for additional argument + // + if (argc < 2) { + Error (NULL, 0, 0, (INT8 *) argv[0], (INT8 *) "option requires an input microcode text file name to parse"); + return STATUS_ERROR; + } + argc--; + argv++; + mGlobals.MCIFileName = argv[0]; + } else if (strcmp (argv[0], "-flashdeviceimage") == 0) { + // + // -flashdeviceimage FlashDeviceImage + // + // Used to specify which flash device image definition from the input flash definition file + // to create. + // Check for additional argument. + // + if (argc < 2) { + Error (NULL, 0, 0, argv[0], "option requires the name of a flash definition image to use"); + return STATUS_ERROR; + } + argc--; + argv++; + mGlobals.FlashDeviceImage = argv[0]; + } else if (strcmp (argv[0], "-imageout") == 0) { + // + // -imageout FileName + // + // Used to specify the name of the output FD image file to create. + // Check for additional argument. + // + if (argc < 2) { + Error (NULL, 0, 0, argv[0], "option requires an output image filename to create"); + return STATUS_ERROR; + } + argc--; + argv++; + mGlobals.ImageOutFileName = argv[0]; + ThingsToDo++; + } else if (strcmp (argv[0], "-dsc") == 0) { + // + // -dsc FileName + // + // Used to specify the name of the output DSC file to create. + // Check for additional argument. + // + if (argc < 2) { + Error (NULL, 0, 0, argv[0], "option requires an output DSC filename to create"); + return STATUS_ERROR; + } + argc--; + argv++; + mGlobals.DscFileName = argv[0]; + ThingsToDo++; + } else if (strcmp (argv[0], "-fdf") == 0) { + // + // -fdf FileName + // + // Used to specify the name of the input flash definition file. + // Check for additional argument. + // + if (argc < 2) { + Error (NULL, 0, 0, argv[0], "option requires an input flash definition file name"); + return STATUS_ERROR; + } + argc--; + argv++; + mGlobals.FlashDefinitionFileName = argv[0]; + } else if (strcmp (argv[0], "-discover") == 0) { + // + // -discover FDFileName + // + // Debug functionality used to scan an existing FD image, trying to find + // firmware volumes at 64K boundaries. + // Check for additional argument. + // + if (argc < 2) { + Error (NULL, 0, 0, argv[0], "option requires an input FD image file name"); + return STATUS_ERROR; + } + argc--; + argv++; + mGlobals.DiscoverFDImageName = argv[0]; + ThingsToDo++; + } else if (strcmp (argv[0], "-baseaddr") == 0) { + // + // -baseaddr Addr + // + // Used to specify a base address when doing a discover of an FD image. + // Check for additional argument. + // + if (argc < 2) { + Error (NULL, 0, 0, argv[0], "option requires a base address"); + return STATUS_ERROR; + } + argc--; + argv++; + if (tolower (argv[0][1]) == 'x') { + sscanf (argv[0] + 2, "%x", &mGlobals.BaseAddress); + } else { + sscanf (argv[0], "%d", &mGlobals.BaseAddress); + } + } else if (strcmp (argv[0], "-padvalue") == 0) { + // + // -padvalue Value + // + // Used to specify the value to pad with when aligning data while + // creating an FD image. Check for additional argument. + // + if (argc < 2) { + Error (NULL, 0, 0, argv[0], "option requires a byte value"); + return STATUS_ERROR; + } + argc--; + argv++; + if (tolower (argv[0][1]) == 'x') { + sscanf (argv[0] + 2, "%x", &Temp); + mGlobals.MicrocodePadByteValue = (char) Temp; + } else { + sscanf (argv[0], "%d", &Temp); + mGlobals.MicrocodePadByteValue = (char) Temp; + } + } else if (strcmp (argv[0], "-align") == 0) { + // + // -align Alignment + // + // Used to specify how each data file is aligned in the region + // when creating an FD image. Check for additional argument. + // + if (argc < 2) { + Error (NULL, 0, 0, argv[0], "option requires an alignment"); + return STATUS_ERROR; + } + argc--; + argv++; + if (tolower (argv[0][1]) == 'x') { + sscanf (argv[0] + 2, "%x", &mGlobals.MicrocodeAlignment); + } else { + sscanf (argv[0], "%d", &mGlobals.MicrocodeAlignment); + } + } else if (strcmp (argv[0], "-mcmerge") == 0) { + // + // -mcmerge FileName(s) + // + // Used to concatenate multiple microde binary files. Can specify + // multiple file names with the one -mcmerge flag. Check for additional argument. + // + if ((argc < 2) || (argv[1][0] == '-')) { + Error (NULL, 0, 0, argv[0], "option requires one or more input file names"); + return STATUS_ERROR; + } + // + // Take input files until another option or end of list + // + ThingsToDo++; + while ((argc > 1) && (argv[1][0] != '-')) { + Str = (STRING_LIST *) _malloc (sizeof (STRING_LIST)); + if (Str == NULL) { + Error (NULL, 0, 0, "memory allocation failure", NULL); + return STATUS_ERROR; + } + memset (Str, 0, sizeof (STRING_LIST)); + Str->Str = argv[1]; + if (mGlobals.MCIFileNames == NULL) { + mGlobals.MCIFileNames = Str; + } else { + mGlobals.LastMCIFileNames->Next = Str; + } + mGlobals.LastMCIFileNames = Str; + argc--; + argv++; + } + } else if (strcmp (argv[0], "-strsub") == 0) { + // + // -strsub SrcFile DestFile + // + // Used to perform string substitutions on a file, writing the result to a new + // file. Check for two additional arguments. + // + if (argc < 3) { + Error (NULL, 0, 0, argv[0], "option requires input and output file names for string substitution"); + return STATUS_ERROR; + } + argc--; + argv++; + mGlobals.StringReplaceInFileName = argv[0]; + argc--; + argv++; + mGlobals.StringReplaceOutFileName = argv[0]; + ThingsToDo++; + } else { + Error (NULL, 0, 0, argv[0], "invalid option"); + return STATUS_ERROR; + } + argc--; + argv++; + } + // + // If no outputs requested, then report an error + // + if (ThingsToDo == 0) { + Error (NULL, 0, 0, "nothing to do", NULL); + return STATUS_ERROR; + } + // + // If they want an asm file, #include file, or C file to be created, then they have to specify a + // flash device name and flash definition file name. + // + if ((mGlobals.CIncludeFileName != NULL) && + ((mGlobals.FlashDevice == NULL) || (mGlobals.FlashDefinitionFileName == NULL))) { + Error (NULL, 0, 0, "must specify -flashdevice and -fdf with -hfile", NULL); + return STATUS_ERROR; + } + if ((mGlobals.AsmIncludeFileName != NULL) && + ((mGlobals.FlashDevice == NULL) || (mGlobals.FlashDefinitionFileName == NULL))) { + Error (NULL, 0, 0, "must specify -flashdevice and -fdf with -asmincfile", NULL); + return STATUS_ERROR; + } + // + // If they want a dsc file to be created, then they have to specify a + // flash device name and a flash definition file name + // + if (mGlobals.DscFileName != NULL) { + if (mGlobals.FlashDevice == NULL) { + Error (NULL, 0, 0, "must specify -flashdevice with -dsc", NULL); + return STATUS_ERROR; + } + if (mGlobals.FlashDefinitionFileName == NULL) { + Error (NULL, 0, 0, "must specify -fdf with -dsc", NULL); + return STATUS_ERROR; + } + } + // + // If they specified an output microcode file name, then they have to specify an input + // file name, and vice versa. + // + if ((mGlobals.MCIFileName != NULL) && (mGlobals.MCOFileName == NULL)) { + Error (NULL, 0, 0, "must specify output microcode file name", NULL); + return STATUS_ERROR; + } + if ((mGlobals.MCOFileName != NULL) && (mGlobals.MCIFileName == NULL) && (mGlobals.MCIFileNames == NULL)) { + Error (NULL, 0, 0, "must specify input microcode file name", NULL); + return STATUS_ERROR; + } + // + // If doing merge, then have to specify output file name + // + if ((mGlobals.MCIFileNames != NULL) && (mGlobals.MCOFileName == NULL)) { + Error (NULL, 0, 0, "must specify output microcode file name", NULL); + return STATUS_ERROR; + } + // + // If they want an output image to be created, then they have to specify + // the flash device and the flash device image to use. + // + if (mGlobals.ImageOutFileName != NULL) { + if (mGlobals.FlashDevice == NULL) { + Error (NULL, 0, 0, "must specify -flashdevice with -imageout", NULL); + return STATUS_ERROR; + } + if (mGlobals.FlashDeviceImage == NULL) { + Error (NULL, 0, 0, "must specify -flashdeviceimage with -imageout", NULL); + return STATUS_ERROR; + } + if (mGlobals.FlashDefinitionFileName == NULL) { + Error (NULL, 0, 0, "must specify -c or -fdf with -imageout", NULL); + return STATUS_ERROR; + } + } + return STATUS_SUCCESS; +} + +static +void +Usage ( + VOID + ) +/*++ + +Routine Description: + Print utility command line help + +Arguments: + None + +Returns: + NA + +--*/ +{ + int i; + char *Msg[] = { + "Usage: FlashTool -fdf FlashDefFile -flashdevice FlashDevice", + " -flashdeviceimage FlashDeviceImage -mci MCIFile -mco MCOFile", + " -discover FDImage -dsc DscFile -asmincfile AsmIncFile", + " -imageOut ImageOutFile -hfile HFile -strsub InStrFile OutStrFile", + " -baseaddr BaseAddr -align Alignment -padvalue PadValue", + " -mcmerge MCIFile(s)", + " where", + " FlashDefFile - input Flash Definition File", + " FlashDevice - flash device to use (from flash definition file)", + " FlashDeviceImage - flash device image to use (from flash definition file)", + " MCIFile - input microcode file to parse", + " MCOFile - output binary microcode image to create from MCIFile", + " HFile - output #include file to create", + " FDImage - name of input FDImage file to scan", + " ImageOutFile - output image file to create", + " DscFile - output DSC file to create", + " AsmIncFile - output ASM include file to create", + " InStrFile - input file to replace symbol names, writing result to OutStrFile", + " BaseAddr - base address of FDImage (used with -discover)", + " Alignment - alignment to use when merging microcode binaries", + " PadValue - byte value to use as pad value when aligning microcode binaries", + " MCIFile(s) - one or more microcode binary files to merge/concatenate", + "", + NULL + }; + for (i = 0; Msg[i] != NULL; i++) { + fprintf (stdout, "%s\n", Msg[i]); + } +} diff --git a/Tools/Source/TianoTools/FlashMap/Makefile b/Tools/Source/TianoTools/FlashMap/Makefile new file mode 100644 index 0000000000..6b6d011c1d --- /dev/null +++ b/Tools/Source/TianoTools/FlashMap/Makefile @@ -0,0 +1,81 @@ +#/*++ +# +# Copyright (c) 2004 Intel Corporation. All rights reserved +# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. Except as permitted by such +# license, no part of this software or documentation may be +# reproduced, stored in a retrieval system, or transmitted in any +# form or by any means without the express written consent of +# Intel Corporation. +# +# +# Module Name: +# +# Makefile +# +# Abstract: +# +# makefile for building the FlashMap utility +# +#--*/ + +# +# Make sure environmental variable EFI_SOURCE is set +# +!IFNDEF EFI_SOURCE +!ERROR EFI_SOURCE environmental variable not set +!ENDIF + + +!INCLUDE PlatformTools.env + +INCLUDE_PATHS = -I $(TIANO_TOOLS_SOURCE)\Common + +# +# Target specific information +# +TARGET_NAME = FlashMap +TARGET_SRC_DIR = $(TIANO_TOOLS_SOURCE)\$(TARGET_NAME) +TARGET_EXE = $(TIANO_TOOLS_OUTPUT)\FlashMap.exe +LIBS = $(LIBS) "$(TIANO_TOOLS_OUTPUT)\Common.lib" + +# +# Build targets +# +all: $(TARGET_EXE) + +OBJECTS = $(TIANO_TOOLS_OUTPUT)\FlashMap.obj \ + $(TIANO_TOOLS_OUTPUT)\FlashDefFile.obj \ + $(TIANO_TOOLS_OUTPUT)\Symbols.obj \ + $(TIANO_TOOLS_OUTPUT)\Microcode.obj + +# $(TIANO_TOOLS_OUTPUT)\TrackMallocFree.obj + +#C_FLAGS = $(C_FLAGS) /D TRACK_MALLOC_FREE +C_FLAGS = $(C_FLAGS) /D _malloc=malloc /D _free=free + +# +# Compile each source file +# +$(TIANO_TOOLS_OUTPUT)\FlashMap.obj : $(TARGET_SRC_DIR)\FlashMap.c $(TARGET_SRC_DIR)\Symbols.h $(INC_DEPS) + $(CC) $(C_FLAGS) $(INCLUDE_PATHS) $(TARGET_SRC_DIR)\FlashMap.c /Fo$@ + +$(TIANO_TOOLS_OUTPUT)\Symbols.obj : $(TARGET_SRC_DIR)\Symbols.c $(INC_DEPS) + $(CC) $(C_FLAGS) $(INCLUDE_PATHS) $(TARGET_SRC_DIR)\Symbols.c /Fo$@ + +$(TIANO_TOOLS_OUTPUT)\Microcode.obj : $(TARGET_SRC_DIR)\Microcode.c $(INC_DEPS) + $(CC) $(C_FLAGS) $(INC) $(TARGET_SRC_DIR)\Microcode.c /Fo$@ + +$(TIANO_TOOLS_OUTPUT)\FlashDefFile.obj : $(TARGET_SRC_DIR)\FlashDefFile.c $(INC_DEPS) + $(CC) $(C_FLAGS) $(INC) $(TARGET_SRC_DIR)\FlashDefFile.c /Fo$@ + +$(TIANO_TOOLS_OUTPUT)\TrackMallocFree.obj : $(TARGET_SRC_DIR)\TrackMallocFree.c $(INC_DEPS) + $(CC) $(C_FLAGS) $(INC) $(TARGET_SRC_DIR)\TrackMallocFree.c /Fo$@ + +# +# Link the object files together to create the final executable +# +$(TARGET_EXE) : $(OBJECTS) $(LIBS) + $(LINK) $(MSVS_LINK_LIBPATHS) $(L_FLAGS) $(LIBS) /out:$(TARGET_EXE) $(OBJECTS) + diff --git a/Tools/Source/TianoTools/FlashMap/Microcode.c b/Tools/Source/TianoTools/FlashMap/Microcode.c new file mode 100644 index 0000000000..51ae20e9f5 --- /dev/null +++ b/Tools/Source/TianoTools/FlashMap/Microcode.c @@ -0,0 +1,306 @@ +/*++ + +Copyright (c) 2004 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + Microcode.c + +Abstract: + + Utility for working with microcode patch files in the Intel + Platform Innovation Framework for EFI build environment. + +--*/ + +#include +#include // for memset() +#include +#include // for malloc() +#define INT8 char +#define UINT32 unsigned int + +#include "EfiUtilityMsgs.h" +#include "Microcode.h" + +#define MAX_LINE_LEN 256 + +// +// Structure definition for a microcode header +// +typedef struct { + unsigned int HeaderVersion; + unsigned int PatchId; + unsigned int Date; + unsigned int CpuId; + unsigned int Checksum; + unsigned int LoaderVersion; + unsigned int PlatformId; + unsigned int DataSize; // if 0, then TotalSize = 2048, and TotalSize field is invalid + unsigned int TotalSize; // number of bytes + unsigned int Reserved[3]; +} MICROCODE_IMAGE_HEADER; + +static +STATUS +MicrocodeReadData ( + FILE *InFptr, + unsigned int *Data + ); + +void +MicrocodeConstructor ( + void + ) +/*++ + +Routine Description: + + Constructor of module Microcode + +Arguments: + + None + +Returns: + + None + +--*/ +{ +} + +void +MicrocodeDestructor ( + void + ) +/*++ + +Routine Description: + + Destructor of module Microcode + +Arguments: + + None + +Returns: + + None + +--*/ +{ +} + +static +STATUS +MicrocodeReadData ( + FILE *InFptr, + unsigned int *Data + ) +/*++ + +Routine Description: + Read a 32-bit microcode data value from a text file and convert to raw binary form. + +Arguments: + InFptr - file pointer to input text file + Data - pointer to where to return the data parsed + +Returns: + STATUS_SUCCESS - no errors or warnings, Data contains valid information + STATUS_ERROR - errors were encountered + +--*/ +{ + char Line[MAX_LINE_LEN]; + char *cptr; + + Line[MAX_LINE_LEN - 1] = 0; + *Data = 0; + if (fgets (Line, MAX_LINE_LEN, InFptr) == NULL) { + return STATUS_ERROR; + } + // + // If it was a binary file, then it may have overwritten our null terminator + // + if (Line[MAX_LINE_LEN - 1] != 0) { + return STATUS_ERROR; + } + // + // Look for + // dd 000000001h ; comment + // dd XXXXXXXX + // DD XXXXXXXXX + // DD XXXXXXXXX + // + for (cptr = Line; *cptr && isspace(*cptr); cptr++) { + } + if ((tolower(cptr[0]) == 'd') && (tolower(cptr[1]) == 'd') && isspace (cptr[2])) { + // + // Skip blanks and look for a hex digit + // + cptr += 3; + for (; *cptr && isspace(*cptr); cptr++) { + } + if (isxdigit (*cptr)) { + if (sscanf (cptr, "%X", Data) != 1) { + return STATUS_ERROR; + } + } + return STATUS_SUCCESS; + } + return STATUS_ERROR; +} + +STATUS +MicrocodeParseFile ( + char *InFileName, + char *OutFileName + ) +/*++ + +Routine Description: + Parse a microcode text file, and write the binary results to an output file. + +Arguments: + InFileName - input text file to parse + OutFileName - output file to write raw binary data from parsed input file + +Returns: + STATUS_SUCCESS - no errors or warnings + STATUS_ERROR - errors were encountered + +--*/ +{ + FILE *InFptr; + FILE *OutFptr; + STATUS Status; + MICROCODE_IMAGE_HEADER *Header; + unsigned int Size; + unsigned int Size2; + unsigned int Data; + unsigned int Checksum; + char *Buffer; + char *Ptr; + unsigned int TotalSize; + + Status = STATUS_ERROR; + InFptr = NULL; + OutFptr = NULL; + Buffer = NULL; + // + // Open the input text file + // + if ((InFptr = fopen (InFileName, "r")) == NULL) { + Error (NULL, 0, 0, InFileName, "failed to open input microcode file for reading"); + return STATUS_ERROR; + } + // + // Make two passes on the input file. The first pass is to determine how + // much data is in the file so we can allocate a working buffer. Then + // we'll allocate a buffer and re-read the file into the buffer for processing. + // + Size = 0; + do { + Status = MicrocodeReadData (InFptr, &Data); + if (Status == STATUS_SUCCESS) { + Size += sizeof (Data); + } + } while (Status == STATUS_SUCCESS); + // + // Error if no data. + // + if (Size == 0) { + Error (NULL, 0, 0, InFileName, "no parse-able data found in file"); + goto Done; + } + if (Size < sizeof (MICROCODE_IMAGE_HEADER)) { + Error (NULL, 0, 0, InFileName, "amount of parse-able data is insufficient to contain a microcode header"); + goto Done; + } + // + // Allocate a buffer for the data + // + Buffer = (char *) _malloc (Size); + if (Buffer == NULL) { + Error (NULL, 0, 0, "memory allocation failure", NULL); + goto Done; + } + // + // Re-read the file, storing the data into our buffer + // + fseek (InFptr, 0, SEEK_SET); + Ptr = Buffer; + do { + Status = MicrocodeReadData (InFptr, &Data); + if (Status == STATUS_SUCCESS) { + *(unsigned int *) Ptr = Data; + Ptr += sizeof (Data); + } + } while (Status == STATUS_SUCCESS); + // + // Can't do much checking on the header because, per the spec, the + // DataSize field may be 0, which means DataSize = 2000 and TotalSize = 2K, + // and the TotalSize field is invalid (actually missing). Thus we can't + // even verify the Reserved fields are 0. + // + Header = (MICROCODE_IMAGE_HEADER *) Buffer; + if (Header->DataSize == 0) { + TotalSize = 2048; + } else { + TotalSize = Header->TotalSize; + } + if (TotalSize != Size) { + Error (NULL, 0, 0, InFileName, "file contents do not contain expected TotalSize 0x%04X", TotalSize); + goto Done; + } + // + // Checksum the contents + // + Ptr = Buffer; + Checksum = 0; + Size2 = 0; + while (Size2 < Size) { + Checksum += *(unsigned int *) Ptr; + Ptr += 4; + Size2 += 4; + } + if (Checksum != 0) { + Error (NULL, 0, 0, InFileName, "checksum failed on file contents"); + goto Done; + } + // + // Open the output file and write the buffer contents + // + if ((OutFptr = fopen (OutFileName, "wb")) == NULL) { + Error (NULL, 0, 0, OutFileName, "failed to open output microcode file for writing"); + goto Done; + } + if (fwrite (Buffer, Size, 1, OutFptr) != 1) { + Error (NULL, 0, 0, OutFileName, "failed to write microcode data to output file"); + goto Done; + } + Status = STATUS_SUCCESS; +Done: + if (Buffer != NULL) { + free (Buffer); + } + if (InFptr != NULL) { + fclose (InFptr); + } + if (OutFptr != NULL) { + fclose (OutFptr); + if (Status == STATUS_ERROR) { + remove (OutFileName); + } + } + return Status; +} diff --git a/Tools/Source/TianoTools/FlashMap/Microcode.h b/Tools/Source/TianoTools/FlashMap/Microcode.h new file mode 100644 index 0000000000..5f5a13ee63 --- /dev/null +++ b/Tools/Source/TianoTools/FlashMap/Microcode.h @@ -0,0 +1,87 @@ +/*++ + +Copyright (c) 2004 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + Microcode.h + +Abstract: + + Header file for flash management utility in the Intel Platform + Innovation Framework for EFI build environment. + +--*/ + +#ifndef _MICROCODE_H_ +#define _MICROCODE_H_ + +void +MicrocodeConstructor ( + void + ); +/*++ + +Routine Description: + + Constructor of module Microcode + +Arguments: + + None + +Returns: + + None + +--*/ + +void +MicrocodeDestructor ( + void + ); +/*++ + +Routine Description: + + Destructor of module Microcode + +Arguments: + + None + +Returns: + + None + +--*/ + +STATUS +MicrocodeParseFile ( + char *InFileName, + char *OutFileName + ); +/*++ + +Routine Description: + Parse a microcode text file, and write the binary results to an output file. + +Arguments: + InFileName - input text file to parse + OutFileName - output file to write raw binary data from parsed input file + +Returns: + STATUS_SUCCESS - no errors or warnings + STATUS_ERROR - errors were encountered + +--*/ + + +#endif // #ifndef _MICROCODE_H_ diff --git a/Tools/Source/TianoTools/FlashMap/Symbols.c b/Tools/Source/TianoTools/FlashMap/Symbols.c new file mode 100644 index 0000000000..471128a6b6 --- /dev/null +++ b/Tools/Source/TianoTools/FlashMap/Symbols.c @@ -0,0 +1,647 @@ +/*++ + +Copyright (c) 2004 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + + +Module Name: + + Symbol.c + +Abstract: + + Class-like implementation for a symbol table. + +--*/ + +// GC_TODO: fix comment to set correct module name: Symbols.c +#include +#include +#include +// +// for isspace() +// +#include + +#include "Tiano.h" +#include "EfiUtilityMsgs.h" +#include "Symbols.h" + +#define MAX_LINE_LEN 512 + +// +// Linked list to keep track of all symbols +// +typedef struct _SYMBOL { + struct _SYMBOL *Next; + int Type; + char *Name; + char *Value; +} SYMBOL; + +static +SYMBOL * +FreeSymbols ( + SYMBOL *Syms + ); + +static +int +ExpandMacros ( + char *SourceLine, + char *DestLine, + int LineLen + ); + +static SYMBOL *mSymbolTable = NULL; + +void +SymbolsConstructor ( + VOID + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + None + +Returns: + + GC_TODO: add return values + +--*/ +{ + SymbolsDestructor (); +} + +void +SymbolsDestructor ( + VOID + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + None + +Returns: + + GC_TODO: add return values + +--*/ +{ + mSymbolTable = FreeSymbols (mSymbolTable); +} + +char * +GetSymbolValue ( + char *SymbolName + ) +/*++ + +Routine Description: + + Look up a symbol in our symbol table. + +Arguments: + + SymbolName + +Returns: + + Pointer to the value of the symbol if found + NULL if the symbol is not found + +--*/ +// GC_TODO: SymbolName - add argument and description to function comment +{ + SYMBOL *Symbol; + // + // Walk the symbol table + // + Symbol = mSymbolTable; + while (Symbol) { + if (stricmp (SymbolName, Symbol->Name) == 0) { + return Symbol->Value; + } + + Symbol = Symbol->Next; + } + + return NULL; +} + +int +SymbolAdd ( + char *Name, + char *Value, + int Mode + ) +/*++ + +Routine Description: + + Add a symbol name/value to the symbol table + +Arguments: + + Name - name of symbol to add + Value - value of symbol to add + Mode - currrently unused + +Returns: + + Length of symbol added. + +Notes: + If Value == NULL, then this routine will assume that the Name field + looks something like "MySymName = MySymValue", and will try to parse + it that way and add the symbol name/pair from the string. + +--*/ +{ + SYMBOL *Symbol; + + SYMBOL *NewSymbol; + int Len; + char *Start; + char *Cptr; + char CSave; + char *SaveCptr; + + Len = 0; + SaveCptr = NULL; + CSave = 0; + // + // If value pointer is null, then they passed us a line something like: + // varname = value, or simply var = + // + if (Value == NULL) { + Start = Name; + while (*Name && isspace (*Name)) { + Name++; + } + + if (Name == NULL) { + return -1; + } + // + // Find the end of the name. Either space or a '='. + // + for (Value = Name; *Value && !isspace (*Value) && (*Value != '='); Value++) + ; + if (Value == NULL) { + return -1; + } + // + // Look for the '=' + // + Cptr = Value; + while (*Value && (*Value != '=')) { + Value++; + } + + if (Value == NULL) { + return -1; + } + // + // Now truncate the name + // + *Cptr = 0; + // + // Skip over the = and then any spaces + // + Value++; + while (*Value && isspace (*Value)) { + Value++; + + } + // + // Find end of string, checking for quoted string + // + if (*Value == '\"') { + Value++; + for (Cptr = Value; *Cptr && *Cptr != '\"'; Cptr++) + ; + } else { + for (Cptr = Value; *Cptr && !isspace (*Cptr); Cptr++) + ; + } + // + // Null terminate the value string + // + CSave = *Cptr; + SaveCptr = Cptr; + *Cptr = 0; + Len = (int) (Cptr - Start); + } + // + // We now have a symbol name and a value. Look for an existing variable + // and overwrite it. + // + Symbol = mSymbolTable; + while (Symbol) { + // + // Check for symbol name match + // + if (stricmp (Name, Symbol->Name) == 0) { + _free (Symbol->Value); + Symbol->Value = (char *) _malloc (strlen (Value) + 1); + if (Symbol->Value == NULL) { + Error (NULL, 0, 0, NULL, "failed to allocate memory"); + return -1; + } + + strcpy (Symbol->Value, Value); + // + // If value == "NULL", then make it a 0-length string + // + if (stricmp (Symbol->Value, "NULL") == 0) { + Symbol->Value[0] = 0; + } + + return Len; + } + + Symbol = Symbol->Next; + } + // + // Does not exist, create a new one + // + NewSymbol = (SYMBOL *) _malloc (sizeof (SYMBOL)); + if (NewSymbol == NULL) { + Error (NULL, 0, 0, NULL, "memory allocation failure"); + return -1; + } + + memset ((char *) NewSymbol, 0, sizeof (SYMBOL)); + NewSymbol->Name = (char *) _malloc (strlen (Name) + 1); + if (NewSymbol->Name == NULL) { + Error (NULL, 0, 0, NULL, "memory allocation failure"); + _free (NewSymbol); + return -1; + } + + NewSymbol->Value = (char *) _malloc (strlen (Value) + 1); + if (NewSymbol->Value == NULL) { + Error (NULL, 0, 0, NULL, "memory allocation failure"); + _free (NewSymbol->Name); + _free (NewSymbol); + return -1; + } + + strcpy (NewSymbol->Name, Name); + strcpy (NewSymbol->Value, Value); + // + // Remove trailing spaces + // + Cptr = NewSymbol->Value + strlen (NewSymbol->Value) - 1; + while (Cptr > NewSymbol->Value) { + if (isspace (*Cptr)) { + *Cptr = 0; + Cptr--; + } else { + break; + } + } + // + // Add it to the head of the list. + // + NewSymbol->Next = mSymbolTable; + mSymbolTable = NewSymbol; + // + // If value == "NULL", then make it a 0-length string + // + if (stricmp (NewSymbol->Value, "NULL") == 0) { + NewSymbol->Value[0] = 0; + } + // + // Restore the terminator we inserted if they passed in var=value + // + if (SaveCptr != NULL) { + *SaveCptr = CSave; + } + _free (NewSymbol->Value); + _free (NewSymbol->Name); + _free (NewSymbol); + return Len; +} + +static +STATUS +RemoveSymbol ( + char *Name, + char SymbolType + ) +/*++ + +Routine Description: + + Remove a symbol name/value from the symbol table + +Arguments: + + Name - name of symbol to remove + SymbolType - type of symbol to remove + +Returns: + + STATUS_SUCCESS - matching symbol found and removed + STATUS_ERROR - matching symbol not found in symbol table + +--*/ +{ + SYMBOL *Symbol; + + SYMBOL *PrevSymbol; + + PrevSymbol = NULL; + Symbol = mSymbolTable; + // + // Walk the linked list of symbols in the symbol table looking + // for a match of both symbol name and type. + // + while (Symbol) { + if ((stricmp (Name, Symbol->Name) == 0) && (Symbol->Type & SymbolType)) { + // + // If the symbol has a value associated with it, free the memory + // allocated for the value. + // Then free the memory allocated for the symbols string name. + // + if (Symbol->Value) { + _free (Symbol->Value); + } + + _free (Symbol->Name); + // + // Link the previous symbol to the next symbol to effectively + // remove this symbol from the linked list. + // + if (PrevSymbol) { + PrevSymbol->Next = Symbol->Next; + } else { + mSymbolTable = Symbol->Next; + } + + _free (Symbol); + return STATUS_SUCCESS; + } + + PrevSymbol = Symbol; + Symbol = Symbol->Next; + } + + return STATUS_WARNING; +} + +static +SYMBOL * +FreeSymbols ( + SYMBOL *Syms + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Syms - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + SYMBOL *Next; + while (Syms) { + if (Syms->Name != NULL) { + _free (Syms->Name); + } + + if (Syms->Value != NULL) { + _free (Syms->Value); + } + + Next = Syms->Next; + _free (Syms); + Syms = Next; + } + + return Syms; +} + +static +int +ExpandMacros ( + char *SourceLine, + char *DestLine, + int LineLen + ) +/*++ + +Routine Description: + + Given a line of text, replace all variables of format $(NAME) with values + from our symbol table. + +Arguments: + + SourceLine - input line of text to do symbol replacements on + DestLine - on output, SourceLine with symbols replaced + LineLen - length of DestLine, so we don't exceed its allocated length + +Returns: + + STATUS_SUCCESS - no problems encountered + STATUS_WARNING - missing closing parenthesis on a symbol reference in SourceLine + STATUS_ERROR - memory allocation failure + +--*/ +{ + static int NestDepth = 0; + char *FromPtr; + char *ToPtr; + char *SaveStart; + char *Cptr; + char *value; + int Expanded; + int ExpandedCount; + INT8 *LocalDestLine; + STATUS Status; + int LocalLineLen; + + NestDepth++; + Status = STATUS_SUCCESS; + LocalDestLine = (char *) _malloc (LineLen); + if (LocalDestLine == NULL) { + Error (__FILE__, __LINE__, 0, "memory allocation failed", NULL); + return STATUS_ERROR; + } + + FromPtr = SourceLine; + ToPtr = LocalDestLine; + // + // Walk the entire line, replacing $(MACRO_NAME). + // + LocalLineLen = LineLen; + ExpandedCount = 0; + while (*FromPtr && (LocalLineLen > 0)) { + if ((*FromPtr == '$') && (*(FromPtr + 1) == '(')) { + // + // Save the start in case it's undefined, in which case we copy it as-is. + // + SaveStart = FromPtr; + Expanded = 0; + // + // Macro expansion time. Find the end (no spaces allowed) + // + FromPtr += 2; + for (Cptr = FromPtr; *Cptr && (*Cptr != ')'); Cptr++) + ; + if (*Cptr) { + // + // Truncate the string at the closing parenthesis for ease-of-use. + // Then copy the string directly to the destination line in case we don't find + // a definition for it. + // + *Cptr = 0; + strcpy (ToPtr, SaveStart); + if ((value = GetSymbolValue (FromPtr)) != NULL) { + strcpy (ToPtr, value); + LocalLineLen -= strlen (value); + ToPtr += strlen (value); + Expanded = 1; + ExpandedCount++; + } + + if (!Expanded) { + // + // Restore closing parenthesis, and advance to next character + // + *Cptr = ')'; + FromPtr = SaveStart + 1; + ToPtr++; + } else { + FromPtr = Cptr + 1; + } + } else { + Error (NULL, 0, 0, SourceLine, "missing closing parenthesis on macro"); + strcpy (ToPtr, FromPtr); + Status = STATUS_WARNING; + goto Done; + } + } else { + *ToPtr = *FromPtr; + FromPtr++; + ToPtr++; + LocalLineLen--; + } + } + + if (*FromPtr == 0) { + *ToPtr = 0; + } + + // + // If we expanded at least one string successfully, then make a recursive call to try again. + // + if ((ExpandedCount != 0) && (Status == STATUS_SUCCESS) && (NestDepth < 10)) { + Status = ExpandMacros (LocalDestLine, DestLine, LineLen); + _free (LocalDestLine); + NestDepth = 0; + return Status; + } + +Done: + if (Status != STATUS_ERROR) { + strcpy (DestLine, LocalDestLine); + } + + NestDepth = 0; + _free (LocalDestLine); + return Status; +} + +STATUS +SymbolsFileStringsReplace ( + char *InFileName, + char *OutFileName + ) +/*++ + +Routine Description: + + Given input and output file names, read in the input file, replace variable + references of format $(NAME) with appropriate values from our symbol table, + and write the result out to the output file. + +Arguments: + + InFileName - name of input text file to replace variable references + OutFileName - name of output text file to write results to + +Returns: + + STATUS_SUCCESS - no problems encountered + STATUS_ERROR - failed to open input or output file + +--*/ +{ + STATUS Status; + FILE *InFptr; + FILE *OutFptr; + char Line[MAX_LINE_LEN]; + char OutLine[MAX_LINE_LEN]; + + Status = STATUS_ERROR; + // + // Open input and output files + // + InFptr = NULL; + OutFptr = NULL; + if ((InFptr = fopen (InFileName, "r")) == NULL) { + Error (NULL, 0, 0, InFileName, "failed to open input file for reading"); + goto Done; + } + + if ((OutFptr = fopen (OutFileName, "w")) == NULL) { + Error (NULL, 0, 0, OutFileName, "failed to open output file for writing"); + goto Done; + } + // + // Read lines from input file until done + // + while (fgets (Line, sizeof (Line), InFptr) != NULL) { + ExpandMacros (Line, OutLine, sizeof (OutLine)); + fprintf (OutFptr, OutLine); + } + + Status = STATUS_SUCCESS; +Done: + if (InFptr != NULL) { + fclose (InFptr); + } + + if (OutFptr != NULL) { + fclose (OutFptr); + } + + return Status; +} diff --git a/Tools/Source/TianoTools/FlashMap/Symbols.h b/Tools/Source/TianoTools/FlashMap/Symbols.h new file mode 100644 index 0000000000..1d93910c8a --- /dev/null +++ b/Tools/Source/TianoTools/FlashMap/Symbols.h @@ -0,0 +1,125 @@ +/*++ + +Copyright (c) 2004 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + + +Module Name: + + Symbols.h + +Abstract: + + Defines and prototypes for a class-like symbol table service. + +--*/ + +#ifndef _SYMBOLS_H_ +#define _SYMBOLS_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +int +SymbolAdd ( + char *Name, + char *Value, + int Mode + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Name - GC_TODO: add argument description + Value - GC_TODO: add argument description + Mode - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +STATUS +SymbolsFileStringsReplace ( + char *InFileName, + char *OutFileName + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + InFileName - GC_TODO: add argument description + OutFileName - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +void +SymbolsConstructor ( + VOID + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + None + +Returns: + + GC_TODO: add return values + +--*/ +; + +void +SymbolsDestructor ( + VOID + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + None + +Returns: + + GC_TODO: add return values + +--*/ +; + +#ifdef __cplusplus +} +#endif + +#endif // #ifndef _SYMBOLS_H_ diff --git a/Tools/Source/TianoTools/GenAcpiTable/GenAcpiTable.c b/Tools/Source/TianoTools/GenAcpiTable/GenAcpiTable.c new file mode 100644 index 0000000000..6c1ec5f76b --- /dev/null +++ b/Tools/Source/TianoTools/GenAcpiTable/GenAcpiTable.c @@ -0,0 +1,542 @@ +/*++ + +Copyright (c) 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + GenAcpiTable.c + +Abstract: + + A utility that extracts the .DATA section from a PE/COFF image. + +--*/ + +#include +#include +#include + +#include "Tiano.h" +#include "TianoCommon.h" +#include "EfiImage.h" // for PE32 structure definitions +#include "EfiUtilityMsgs.h" + +// +// Version of this utility +// +#define UTILITY_NAME "GenAcpiTable" +#define UTILITY_VERSION "v0.11" + +// +// Define the max length of a filename +// +#define MAX_PATH 256 +#define DEFAULT_OUTPUT_EXTENSION ".acpi" + +// +// Use this to track our command-line options and globals +// +struct { + INT8 OutFileName[MAX_PATH]; + INT8 InFileName[MAX_PATH]; +} mOptions; + +// +// Use these to convert from machine type value to a named type +// +typedef struct { + UINT16 Value; + INT8 *Name; +} STRING_LOOKUP; + +static STRING_LOOKUP mMachineTypes[] = { + EFI_IMAGE_MACHINE_IA32, + "IA32", + EFI_IMAGE_MACHINE_IA64, + "IA64", + EFI_IMAGE_MACHINE_EBC, + "EBC", + 0, + NULL +}; + +static STRING_LOOKUP mSubsystemTypes[] = { + EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION, + "EFI application", + EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, + "EFI boot service driver", + EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER, + "EFI runtime driver", + 0, + NULL +}; +// +// Function prototypes +// +static +void +Usage ( + VOID + ); + +static +STATUS +ParseCommandLine ( + int Argc, + char *Argv[] + ); + +static +STATUS +CheckPE32File ( + INT8 *FileName, + FILE *Fptr, + UINT16 *MachineType, + UINT16 *SubSystem + ); + +static +STATUS +ProcessFile ( + INT8 *InFileName, + INT8 *OutFileName + ); + +static +void +DumpImage ( + INT8 *FileName + ); + +main ( + int Argc, + char *Argv[] + ) +/*++ + +Routine Description: + + +Arguments: + + Argc - standard C main() argument count + + Argv - standard C main() argument list + +Returns: + + 0 success + non-zero otherwise + +--*/ +// GC_TODO: ] - add argument and description to function comment +{ + UINT32 Status; + + SetUtilityName (UTILITY_NAME); + // + // Parse the command line arguments + // + if (ParseCommandLine (Argc, Argv)) { + return STATUS_ERROR; + } + // + // Make sure we don't have the same filename for input and output files + // + if (stricmp (mOptions.OutFileName, mOptions.InFileName) == 0) { + Error (NULL, 0, 0, mOptions.OutFileName, "input and output file names must be different"); + goto Finish; + } + // + // Process the file + // + ProcessFile (mOptions.InFileName, mOptions.OutFileName); +Finish: + Status = GetUtilityStatus (); + return Status; +} + +static +STATUS +ProcessFile ( + INT8 *InFileName, + INT8 *OutFileName + ) +/*++ + +Routine Description: + + Process a PE32 EFI file. + +Arguments: + + InFileName - Name of the PE32 EFI file to process. + OutFileName - Name of the output file for the processed data. + +Returns: + + 0 - successful + +--*/ +{ + STATUS Status; + UINTN Index; + FILE *InFptr; + FILE *OutFptr; + UINT16 MachineType; + UINT16 SubSystem; + UINT32 PESigOffset; + EFI_IMAGE_FILE_HEADER FileHeader; + EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader32; + EFI_IMAGE_SECTION_HEADER SectionHeader; + UINT8 *Buffer; + long SaveFilePosition; + + InFptr = NULL; + OutFptr = NULL; + Buffer = NULL; + Status = STATUS_ERROR; + // + // Try to open the input file + // + if ((InFptr = fopen (InFileName, "rb")) == NULL) { + Error (NULL, 0, 0, InFileName, "failed to open input file for reading"); + return STATUS_ERROR; + } + // + // Double-check the file to make sure it's what we expect it to be + // + if (CheckPE32File (InFileName, InFptr, &MachineType, &SubSystem) != STATUS_SUCCESS) { + goto Finish; + } + // + // Per the PE/COFF specification, at offset 0x3C in the file is a 32-bit + // offset (from the start of the file) to the PE signature, which always + // follows the MSDOS stub. The PE signature is immediately followed by the + // COFF file header. + // + // + if (fseek (InFptr, 0x3C, SEEK_SET) != 0) { + Error (NULL, 0, 0, InFileName, "failed to seek to PE signature in file", NULL); + goto Finish; + } + + if (fread (&PESigOffset, sizeof (PESigOffset), 1, InFptr) != 1) { + Error (NULL, 0, 0, InFileName, "failed to read PE signature offset from file"); + goto Finish; + } + + if (fseek (InFptr, PESigOffset + 4, SEEK_SET) != 0) { + Error (NULL, 0, 0, InFileName, "failed to seek to PE signature"); + goto Finish; + } + // + // We should now be at the COFF file header. Read it in and verify it's + // of an image type we support. + // + if (fread (&FileHeader, sizeof (EFI_IMAGE_FILE_HEADER), 1, InFptr) != 1) { + Error (NULL, 0, 0, InFileName, "failed to read file header from image"); + goto Finish; + } + + if ((FileHeader.Machine != EFI_IMAGE_MACHINE_IA32) && (FileHeader.Machine != EFI_IMAGE_MACHINE_IA64) && (FileHeader.Machine != EFI_IMAGE_MACHINE_X64)) { + Error (NULL, 0, 0, InFileName, "image is of an unsupported machine type 0x%X", (UINT32) FileHeader.Machine); + goto Finish; + } + // + // Read in the optional header. Assume PE32, and if not, then re-read as PE32+ + // + SaveFilePosition = ftell (InFptr); + if (fread (&OptionalHeader32, sizeof (EFI_IMAGE_OPTIONAL_HEADER32), 1, InFptr) != 1) { + Error (NULL, 0, 0, InFileName, "failed to read optional header from input file"); + goto Finish; + } + + if (OptionalHeader32.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + if (fseek (InFptr, SaveFilePosition, SEEK_SET) != 0) { + Error (NULL, 0, 0, InFileName, "failed to seek to .data section"); + goto Finish; + } + + if (fread (&OptionalHeader32, sizeof (EFI_IMAGE_OPTIONAL_HEADER64), 1, InFptr) != 1) { + Error (NULL, 0, 0, InFileName, "failed to read optional header from input file"); + goto Finish; + } + } + // + // Search for the ".data" section + // + for (Index = 0; Index < FileHeader.NumberOfSections; Index++) { + if (fread (&SectionHeader, sizeof (EFI_IMAGE_SECTION_HEADER), 1, InFptr) != 1) { + Error (NULL, 0, 0, InFileName, "failed to read optional header from input file"); + goto Finish; + } + + if (strcmp (SectionHeader.Name, ".data") == 0) { + if (fseek (InFptr, SectionHeader.PointerToRawData, SEEK_SET) != 0) { + Error (NULL, 0, 0, InFileName, "failed to seek to .data section"); + goto Finish; + } + + Buffer = (UINT8 *) malloc (SectionHeader.Misc.VirtualSize); + if (Buffer == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Finish; + } + if (fread (Buffer, SectionHeader.Misc.VirtualSize, 1, InFptr) != 1) { + Error (NULL, 0, 0, InFileName, "failed to .data section"); + goto Finish; + } + // + // Now open our output file + // + if ((OutFptr = fopen (OutFileName, "wb")) == NULL) { + Error (NULL, 0, 0, OutFileName, "failed to open output file for writing"); + goto Finish; + } + + if (fwrite (Buffer, SectionHeader.Misc.VirtualSize, 1, OutFptr) != 1) { + Error (NULL, 0, 0, OutFileName, "failed to write .data section"); + goto Finish; + } + + Status = STATUS_SUCCESS; + goto Finish; + } + } + + Status = STATUS_ERROR; + +Finish: + if (InFptr != NULL) { + fclose (InFptr); + } + // + // Close the output file. If there was an error, delete the output file so + // that a subsequent build will rebuild it. + // + if (OutFptr != NULL) { + fclose (OutFptr); + if (GetUtilityStatus () == STATUS_ERROR) { + remove (OutFileName); + } + } + + // + // Free up our buffer + // + if (Buffer != NULL) { + free (Buffer); + } + + return Status; +} + +static +STATUS +CheckPE32File ( + INT8 *FileName, + FILE *Fptr, + UINT16 *MachineType, + UINT16 *SubSystem + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + FileName - GC_TODO: add argument description + Fptr - GC_TODO: add argument description + MachineType - GC_TODO: add argument description + SubSystem - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + /*++ + +Routine Description: + + Given a file pointer to a supposed PE32 image file, verify that it is indeed a + PE32 image file, and then return the machine type in the supplied pointer. + +Arguments: + + Fptr File pointer to the already-opened PE32 file + MachineType Location to stuff the machine type of the PE32 file. This is needed + because the image may be Itanium-based, IA32, or EBC. + +Returns: + + 0 success + non-zero otherwise + +--*/ + EFI_IMAGE_DOS_HEADER DosHeader; + EFI_IMAGE_FILE_HEADER FileHdr; + EFI_IMAGE_OPTIONAL_HEADER OptionalHdr; + UINT32 PESig; + STATUS Status; + + Status = STATUS_ERROR; + // + // Position to the start of the file + // + fseek (Fptr, 0, SEEK_SET); + // + // Read the DOS header + // + if (fread (&DosHeader, sizeof (DosHeader), 1, Fptr) != 1) { + Error (NULL, 0, 0, FileName, "failed to read the DOS stub from the input file"); + goto Finish; + } + // + // Check the magic number (0x5A4D) + // + if (DosHeader.e_magic != EFI_IMAGE_DOS_SIGNATURE) { + Error (NULL, 0, 0, FileName, "input file does not appear to be a PE32 image (magic number)"); + goto Finish; + } + // + // Position into the file and check the PE signature + // + fseek (Fptr, (long) DosHeader.e_lfanew, SEEK_SET); + if (fread (&PESig, sizeof (PESig), 1, Fptr) != 1) { + Error (NULL, 0, 0, FileName, "failed to read PE signature bytes"); + goto Finish; + } + // + // Check the PE signature in the header "PE\0\0" + // + if (PESig != EFI_IMAGE_NT_SIGNATURE) { + Error (NULL, 0, 0, FileName, "file does not appear to be a PE32 image (signature)"); + goto Finish; + } + // + // Read the file header + // + if (fread (&FileHdr, sizeof (FileHdr), 1, Fptr) != 1) { + Error (NULL, 0, 0, FileName, "failed to read PE file header from input file"); + goto Finish; + } + // + // Read the optional header so we can get the subsystem + // + if (fread (&OptionalHdr, sizeof (OptionalHdr), 1, Fptr) != 1) { + Error (NULL, 0, 0, FileName, "failed to read COFF optional header from input file"); + goto Finish; + } + + *SubSystem = OptionalHdr.Subsystem; + // + // Good to go + // + Status = STATUS_SUCCESS; +Finish: + fseek (Fptr, 0, SEEK_SET); + return Status; +} + +static +int +ParseCommandLine ( + int Argc, + char *Argv[] + ) +/*++ + +Routine Description: + + Given the Argc/Argv program arguments, and a pointer to an options structure, + parse the command-line options and check their validity. + + +Arguments: + + Argc - standard C main() argument count + Argv - standard C main() argument list + +Returns: + + STATUS_SUCCESS success + non-zero otherwise + +--*/ +// GC_TODO: ] - add argument and description to function comment +{ + // + // Clear out the options + // + memset ((char *) &mOptions, 0, sizeof (mOptions)); + // + // Skip over the program name + // + Argc--; + Argv++; + + if (Argc != 2) { + Usage (); + return STATUS_ERROR; + } + + strcpy (mOptions.InFileName, Argv[0]); + // + // Next argument + // + Argv++; + Argc--; + + strcpy (mOptions.OutFileName, Argv[0]); + + return STATUS_SUCCESS; +} + +static +void +Usage ( + VOID + ) +/*++ + +Routine Description: + + Print usage information for this utility. + +Arguments: + + None. + +Returns: + + Nothing. + +--*/ +{ + int Index; + static const char *Msg[] = { + UTILITY_NAME " version "UTILITY_VERSION " - Generate ACPI Table image utility", + " Generate an ACPI Table image from an EFI PE32 image", + " Usage: "UTILITY_NAME " InFileName OutFileName", + " where:", + " InFileName - name of the input PE32 file", + " OutFileName - to write output to OutFileName rather than InFileName"DEFAULT_OUTPUT_EXTENSION, + "", + NULL + }; + for (Index = 0; Msg[Index] != NULL; Index++) { + fprintf (stdout, "%s\n", Msg[Index]); + } +} diff --git a/Tools/Source/TianoTools/GenAcpiTable/Makefile b/Tools/Source/TianoTools/GenAcpiTable/Makefile new file mode 100644 index 0000000000..c4df9bcbb7 --- /dev/null +++ b/Tools/Source/TianoTools/GenAcpiTable/Makefile @@ -0,0 +1,68 @@ +#/*++ +# +# Copyright (c) 2002 Intel Corporation. All rights reserved. +# +# This software and associated documentation (if any) is furnished under +# a license and may only be used or copied in accordance with the terms +# of the license. Except as permitted by such license, no part of this +# software or documentation may be reproduced, stored in a retrieval +# system, or transmitted in any form or by any means without the express +# written consent of Intel Corporation. +# +# Module Name: +# +# makefile +# +# Abstract: +# +# makefile for building the GenAcpiTable utility. +# +#--*/ + +# +# Make sure environmental variable EFI_SOURCE is set +# +!IFNDEF EFI_SOURCE +!ERROR EFI_SOURCE environmental variable not set +!ENDIF + +# +# Define the toolchain which is used to set build options and toolchain paths +# +TOOLCHAIN = TOOLCHAIN_MSVC + +!INCLUDE PlatformTools.env + +# +# Target specific information +# + +TARGET_NAME = GenAcpiTable +TARGET_SRC_DIR = $(TIANO_TOOLS_SOURCE)\$(TARGET_NAME) +TARGET_EXE = $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).exe + +# +# Build targets +# + +all: $(TARGET_EXE) + +OBJECTS = $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).obj + +LIBS = $(TIANO_TOOLS_OUTPUT)\Common.lib + +INC_DEPS = $(EDK_SOURCE)\Foundation\Efi\Include\EfiImage.h + +# +# Build the EXE by compiling the source files, then linking the resultant +# object files together. +# + +$(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).obj : $(TARGET_SRC_DIR)\$(TARGET_NAME).c $(INC_DEPS) + $(CC) $(C_FLAGS) $(TARGET_SRC_DIR)\$(TARGET_NAME).c /Fo$@ + +$(TARGET_EXE): $(OBJECTS) $(TARGET_EXE_LIBS) + $(LINK) $(MSVS_LINK_LIBPATHS) $(L_FLAGS) $(LIBS) /out:$(TARGET_EXE) $(OBJECTS) + +clean: + @if exist $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).* del $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).* > NUL diff --git a/Tools/Source/TianoTools/GenCapsuleHdr/CreateGuid.c b/Tools/Source/TianoTools/GenCapsuleHdr/CreateGuid.c new file mode 100644 index 0000000000..05234e8e7c --- /dev/null +++ b/Tools/Source/TianoTools/GenCapsuleHdr/CreateGuid.c @@ -0,0 +1,50 @@ +/*++ + +Copyright (c) 2003 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + + +Module Name: + + CreateGuid.c + +Abstract: + + Library routine to create a GUID + +--*/ + +#include +#include +#include +#include +#include + +void +CreateGuid ( + GUID *Guid + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Guid - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + CoCreateGuid (Guid); +} diff --git a/Tools/Source/TianoTools/GenCapsuleHdr/GenCapsuleHdr.c b/Tools/Source/TianoTools/GenCapsuleHdr/GenCapsuleHdr.c new file mode 100644 index 0000000000..87195e735b --- /dev/null +++ b/Tools/Source/TianoTools/GenCapsuleHdr/GenCapsuleHdr.c @@ -0,0 +1,2667 @@ +/*++ + +Copyright (c) 2002 - 2005, Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + + +Module Name: + + GenCapsuleHdr.c + +Abstract: + + Generate a capsule header for a file, and optionally prepend the + header to a file or list of files. + +--*/ + +#define _UNICODE + +#include +#include +#include +#include + +#include "Tiano.h" // need a guid definition +#include "EfiUtilityMsgs.h" +#include "EfiCapsule.h" +#include "EfiFirmwareVolumeHeader.h" +#include "EfiFirmwareFileSystem.h" // for FV header GUID +#define MAX_PATH 256 +#define PROGRAM_NAME "GenCapsuleHdr" + +#define UNICODE_BACKSLASH L'\\' +#define UNICODE_FILE_START 0xFEFF +#define UNICODE_CR 0x000D +#define UNICODE_LF 0x000A +#define UNICODE_NULL 0x0000 +#define UNICODE_SPACE L' ' +#define UNICODE_SLASH L'/' +#define UNICODE_DOUBLE_QUOTE L'"' +#define UNICODE_A L'A' +#define UNICODE_F L'F' +#define UNICODE_Z L'Z' +#define UNICODE_a L'a' +#define UNICODE_f L'f' +#define UNICODE_z L'z' +#define UNICODE_0 L'0' +#define UNICODE_9 L'9' +#define UNICODE_TAB L'\t' + +#define OEM_HEADER_STRING L"OemHeader" +#define AUTHOR_INFO_STRING L"AuthorInfo" +#define REVISION_INFO_STRING L"RevisionInfo" +#define SHORT_DESCRIPTION_STRING L"ShortDescription" +#define LONG_DESCRIPTION_STRING L"LongDescription" +#define EQUAL_STRING L"=" +#define OPEN_BRACE_STRING L"{" +#define CLOSE_BRACE_STRING L"}" +#define GUID_STRING L"GUID" +#define DATA_STRING L"DATA" + +#if (EFI_SPECIFICATION_VERSION >= 0x00020000) +#define UEFI_CAPSULE_HEADER_NO_FALAGS 0 +#define UEFI_CAPSULE_HEADER_RESET_FALAGS CAPSULE_FLAGS_PERSIST_ACROSS_RESET +#define UEFI_CAPSULE_HEADER_ALL_FALAGS (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) +#endif + +typedef wchar_t WCHAR; + +typedef struct _FILE_LIST { + struct _FILE_LIST *Next; + INT8 FileName[MAX_PATH]; +} FILE_LIST; + +typedef struct _SIZE_LIST { + struct _SIZE_LIST *Next; + UINT32 Size; +} SIZE_LIST; + +typedef struct { + INT8 FileName[MAX_PATH]; + WCHAR *FileBuffer; + WCHAR *FileBufferPtr; + UINT32 FileSize; + FILE *FilePtr; + BOOLEAN EndOfFile; + UINT32 LineNum; +} SOURCE_FILE; + +// +// Here's all our globals. +// +static struct { + BOOLEAN Dump; + BOOLEAN Verbose; + BOOLEAN JoinMode; + INT8 ScriptFileName[MAX_PATH]; + INT8 OutputFileName[MAX_PATH]; + FILE_LIST *FileList; + FILE *OutFptr; + SIZE_LIST *SizeList; + SIZE_LIST *LastSize; + SIZE_LIST *CurrentSize; +} mOptions; + +static EFI_GUID mEfiCapsuleHeaderGuid = EFI_CAPSULE_GUID; + +void +CreateGuid ( + EFI_GUID *Guid + ); + +static +STATUS +ProcessArgs ( + int Argc, + char *Argv[] + ); + +static +void +SkipWhiteSpace ( + SOURCE_FILE *SourceFile + ); + +static +STATUS +GetHexValue ( + SOURCE_FILE *SourceFile, + UINT32 *Value, + UINT32 NumDigits + ); + +static +BOOLEAN +GetSplitFileName ( + INT8 *BaseFileName, + INT8 *NewFileName, + UINT32 SequenceNumber + ); + +static +STATUS +SplitCapsule ( + INT8 *CapsuleFileName + ); + +static +void +Usage ( + VOID + ); + +static +void +DumpCapsule ( + VOID + ); + +static +STATUS +JoinCapsule ( + VOID + ); + +static +STATUS +DumpCapsuleHeaderStrings ( + UINT8 *SectionName, + WCHAR *Buffer + ); + +static +STATUS +CheckFirmwareVolumeHeader ( + INT8 *FileName, + INT8 *Buffer, + UINT32 BufferSize + ); + +static +BOOLEAN +IsToken ( + SOURCE_FILE *File, + WCHAR *Token + ); + +static +BOOLEAN +GetNumber ( + INT8 *Str, + UINT32 *Value + ); + +static +STATUS +ProcessScriptFile ( + INT8 *ScriptFileName, + FILE *OutFptr, + EFI_CAPSULE_HEADER *CapsuleHeader + ); + +static +STATUS +ParseCapsuleInfo ( + SOURCE_FILE *SourceFile, + FILE *OutFptr, + WCHAR *SectionName + ); + +static +STATUS +CreateCapsule ( + VOID + ); + +static +STATUS +ParseOemInfo ( + SOURCE_FILE *SourceFile, + FILE *OutFptr + ); + +static +BOOLEAN +IsWhiteSpace ( + WCHAR Char + ); + +static +BOOLEAN +EndOfFile ( + SOURCE_FILE *File + ); + +int +main ( + int Argc, + char *Argv[] + ) +/*++ + +Routine Description: + Call the routine to process the command-line arguments, then + dispatch to the appropriate function. + +Arguments: + Standard C main() argc and argv. + +Returns: + 0 if successful + nonzero otherwise + +--*/ +// GC_TODO: Argc - add argument and description to function comment +// GC_TODO: ] - add argument and description to function comment +{ + STATUS Status; + FILE_LIST *NextFile; + // + // Specify our program name to the error printing routines. + // + SetUtilityName (PROGRAM_NAME); + // + // Process the command-line arguments + // + Status = ProcessArgs (Argc, Argv); + if (Status == STATUS_SUCCESS) { + if (mOptions.Dump) { + DumpCapsule (); + } else if (mOptions.JoinMode) { + JoinCapsule (); + } else { + CreateCapsule (); + } + } + // + // Cleanup + // + while (mOptions.FileList != NULL) { + NextFile = mOptions.FileList->Next; + free (mOptions.FileList); + mOptions.FileList = NextFile; + } + + while (mOptions.SizeList != NULL) { + mOptions.CurrentSize = mOptions.SizeList->Next; + free (mOptions.SizeList); + mOptions.SizeList = mOptions.CurrentSize; + } + + return GetUtilityStatus (); +} + +static +STATUS +CreateCapsule ( + VOID + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + None + +Returns: + + GC_TODO: add return values + +--*/ +{ + FILE *InFptr; + FILE_LIST *FileList; + INT8 *Buffer; + UINT32 Size; + EFI_CAPSULE_HEADER CapsuleHeader; + UINT8 Zero; + UINT8 FirstFile; + UINT32 CapsuleHeaderSize; + long InsertedBlockMapEntryOffset; + EFI_FV_BLOCK_MAP_ENTRY InsertedBlockMapEntry; + UINT64 FirmwareVolumeSize; + long FileSize; + EFI_FIRMWARE_VOLUME_HEADER FVHeader; + + Buffer = NULL; + InFptr = NULL; + FirmwareVolumeSize = 0; + CapsuleHeaderSize = 0; + InsertedBlockMapEntryOffset = 0; + memset (&InsertedBlockMapEntry, 0, sizeof (EFI_FV_BLOCK_MAP_ENTRY)); + memset (&FVHeader, 0, sizeof (EFI_FIRMWARE_VOLUME_HEADER)); + + if ((mOptions.OutFptr = fopen (mOptions.OutputFileName, "wb")) == NULL) { + Error (NULL, 0, 0, mOptions.OutputFileName, "failed to open output file for writing"); + return STATUS_ERROR; + } + + memset ((char *) &CapsuleHeader, 0, sizeof (CapsuleHeader)); + memcpy ((void *) &CapsuleHeader.CapsuleGuid, (void *) &mEfiCapsuleHeaderGuid, sizeof (EFI_GUID)); + CapsuleHeader.HeaderSize = sizeof (EFI_CAPSULE_HEADER); + CapsuleHeader.CapsuleImageSize = sizeof (EFI_CAPSULE_HEADER); + if (mOptions.ScriptFileName[0] != 0) { + if (ProcessScriptFile (mOptions.ScriptFileName, mOptions.OutFptr, &CapsuleHeader) != STATUS_SUCCESS) { + goto Done; + } + } else { + // + // Insert a default capsule header +#if (EFI_SPECIFICATION_VERSION >= 0x00020000) + CapsuleHeader.HeaderSize = sizeof (EFI_CAPSULE_HEADER); + CapsuleHeader.Flags = UEFI_CAPSULE_HEADER_ALL_FALAGS; +#endif + CapsuleHeader.OffsetToCapsuleBody = sizeof (EFI_CAPSULE_HEADER); + + if (fwrite ((void *) &CapsuleHeader, sizeof (CapsuleHeader), 1, mOptions.OutFptr) != 1) { + Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file"); + goto Done; + } + } + + CapsuleHeaderSize = CapsuleHeader.OffsetToCapsuleBody; + // + // Now copy the contents of any other files specified on the command + // line to the output file. Files must be FFS files, which are aligned + // on 8-byte boundaries. Don't align the first file, since it's the start + // of the image once the capsule header has been removed. + // + FileList = mOptions.FileList; + FirstFile = 1; + Zero = 0; + while (FileList != NULL) { + if ((InFptr = fopen (FileList->FileName, "rb")) == NULL) { + Error (NULL, 0, 0, FileList->FileName, "failed to open file for reading"); + goto Done; + } + // + // Allocate a buffer into which we can read the file. + // + fseek (InFptr, 0, SEEK_END); + Size = ftell (InFptr); + rewind (InFptr); + Buffer = (char *) malloc (Size); + if (Buffer == NULL) { + Error (__FILE__, __LINE__, 0, FileList->FileName, "failed to allocate buffer to read file into"); + goto Done; + } + + if (fread ((void *) Buffer, Size, 1, InFptr) != 1) { + Error (NULL, 0, 0, FileList->FileName, "failed to read file contents"); + goto Done; + } + + if (Size > 0) { + // + // Align the write of the first bytes from the file if not the first file + // + if (FirstFile) { + // + // First file must be a firmware volume. Double-check, and then insert + // an additional block map entry so we can add more files from the command line + // + if (CheckFirmwareVolumeHeader (FileList->FileName, Buffer, Size) != STATUS_SUCCESS) { + goto Done; + } + // + // Save a copy of the firmware volume header for later + // + memcpy (&FVHeader, Buffer, sizeof (EFI_FIRMWARE_VOLUME_HEADER)); + FirmwareVolumeSize = FVHeader.FvLength; + if (FileList->Next != NULL) { + // + // Copy the firmware volume header + // + InsertedBlockMapEntryOffset = CapsuleHeaderSize + FVHeader.HeaderLength; + if (fwrite (Buffer, FVHeader.HeaderLength, 1, mOptions.OutFptr) != 1) { + Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file"); + goto Done; + } + + if (fwrite (&InsertedBlockMapEntry, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, mOptions.OutFptr) != 1) { + Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file"); + goto Done; + } + + if (fwrite ( + Buffer + FVHeader.HeaderLength, + Size - FVHeader.HeaderLength, + 1, + mOptions.OutFptr + ) != 1) { + Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file"); + goto Done; + } + } else { + // + // Copy the file contents as-is + // + if (fwrite ((void *) Buffer, Size, 1, mOptions.OutFptr) != 1) { + Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file"); + goto Done; + } + } + } else { + while ((ftell (mOptions.OutFptr) - CapsuleHeaderSize) & 0x07) { + if (fwrite ((void *) &Zero, 1, 1, mOptions.OutFptr) != 1) { + Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file"); + goto Done; + } + } + + if (fwrite ((void *) Buffer, Size, 1, mOptions.OutFptr) != 1) { + Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file"); + goto Done; + } + } + + FirstFile = 0; + } + + free (Buffer); + Buffer = NULL; + fclose (InFptr); + InFptr = NULL; + FileList = FileList->Next; + } + +Done: + if (Buffer != NULL) { + free (Buffer); + } + + if (InFptr != NULL) { + fclose (InFptr); + } + // + // If we inserted an additional block map entry, then fix it up. Fix up the + // FV header as well to reflect our new size. + // + if (InsertedBlockMapEntryOffset != 0) { + FileSize = ftell (mOptions.OutFptr); + InsertedBlockMapEntry.NumBlocks = 1; + InsertedBlockMapEntry.BlockLength = (UINT32) ((UINT64) FileSize - (UINT64) CapsuleHeaderSize - FirmwareVolumeSize - sizeof (EFI_FV_BLOCK_MAP_ENTRY)); + fseek (mOptions.OutFptr, InsertedBlockMapEntryOffset, SEEK_SET); + fwrite (&InsertedBlockMapEntry, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, mOptions.OutFptr); + // + // Fix up the firmware volume header and write it out + // + fseek (mOptions.OutFptr, CapsuleHeaderSize, SEEK_SET); + FVHeader.FvLength = FileSize - CapsuleHeaderSize; + FVHeader.HeaderLength += sizeof (EFI_FV_BLOCK_MAP_ENTRY); + fwrite (&FVHeader, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, mOptions.OutFptr); + // + // Reposition to the end of the file + // + } + // + // Close files and free the global string lists we allocated memory for + // + if (mOptions.OutFptr != NULL) { + // + // We should now know the full capsule image size. Update the header and write it again. + // + fseek (mOptions.OutFptr, 0, SEEK_END); + Size = ftell (mOptions.OutFptr); + CapsuleHeader.CapsuleImageSize = Size; + fseek (mOptions.OutFptr, 0, SEEK_SET); + if (fwrite ((void *) &CapsuleHeader, sizeof (CapsuleHeader), 1, mOptions.OutFptr) != 1) { + Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file"); + } + + fseek (mOptions.OutFptr, 0, SEEK_END); + fclose (mOptions.OutFptr); + mOptions.OutFptr = NULL; + } + // + // If they are doing split capsule output, then split it up now. + // + if ((mOptions.Dump == 0) && (GetUtilityStatus () == STATUS_SUCCESS) && (mOptions.SizeList != NULL)) { + SplitCapsule (mOptions.OutputFileName); + } + + return STATUS_SUCCESS; +} + +static +STATUS +ProcessScriptFile ( + INT8 *ScriptFileName, + FILE *OutFptr, + EFI_CAPSULE_HEADER *CapsuleHeader + ) +/*++ + +Routine Description: + Parse a capsule header script file. + +Arguments: + ScriptFileName - name of script file to parse + OutFptr - output to dump binary data + CapsuleHeader - capsule header to update with size info + of parsed fields in the script file + +Returns: + STATUS_SUCCESS - if all went well + +--*/ +{ +#if 0 + STATUS Status; + SOURCE_FILE SourceFile; + WCHAR *WScriptFileName; + BOOLEAN InComment; + + if (fwrite (CapsuleHeader, sizeof (EFI_CAPSULE_HEADER), 1, OutFptr) != 1) { + Error (NULL, 0, 0, "failed to write capsule header to output file", NULL); + return STATUS_ERROR; + } + + memset (&SourceFile, 0, sizeof (SOURCE_FILE)); + strcpy (SourceFile.FileName, ScriptFileName); + + Status = STATUS_ERROR; + // + // Open the input unicode script file and read it into a buffer + // + WScriptFileName = (WCHAR *) malloc ((strlen (ScriptFileName) + 1) * sizeof (WCHAR)); + if (WScriptFileName == NULL) { + Error (__FILE__, __LINE__, 0, "failed to allocate memory", NULL); + return STATUS_ERROR; + } + + swprintf (WScriptFileName, L"%S", ScriptFileName); + if ((SourceFile.FilePtr = _wfopen (WScriptFileName, L"r")) == NULL) { + free (WScriptFileName); + Error (NULL, 0, 0, ScriptFileName, "failed to open script file for reading"); + goto Done; + } + + free (WScriptFileName); + fseek (SourceFile.FilePtr, 0, SEEK_END); + SourceFile.FileSize = ftell (SourceFile.FilePtr); + rewind (SourceFile.FilePtr); + SourceFile.FileBuffer = (WCHAR *) malloc (SourceFile.FileSize + sizeof (WCHAR)); + if (SourceFile.FileBuffer == NULL) { + Error (__FILE__, __LINE__, 0, ScriptFileName, "failed to allocate memory to read in file contents"); + goto Done; + } + + if (fread (SourceFile.FileBuffer, SourceFile.FileSize, 1, SourceFile.FilePtr) != 1) { + Error (NULL, 0, 0, ScriptFileName, "failed to read file contents"); + goto Done; + } + + SourceFile.FileBufferPtr = SourceFile.FileBuffer; + SourceFile.LineNum = 1; + if (SourceFile.FileBuffer[0] != UNICODE_FILE_START) { + Error (ScriptFileName, 1, 0, "file does not appear to be a unicode file", NULL); + goto Done; + } + + SourceFile.FileBufferPtr++; + SourceFile.FileBuffer[SourceFile.FileSize / sizeof (WCHAR)] = 0; + // + // Walk the source file buffer and replace all carriage returns with 0 so + // we can print from the file contents on parse errors. + // + InComment = 0; + while (!EndOfFile (&SourceFile)) { + if (SourceFile.FileBufferPtr[0] == UNICODE_CR) { + SourceFile.FileBufferPtr[0] = 0; + InComment = 0; + } else if (SourceFile.FileBufferPtr[0] == UNICODE_LF) { + InComment = 0; + } else if (InComment) { + SourceFile.FileBufferPtr[0] = UNICODE_SPACE; + } else if ((SourceFile.FileBufferPtr[0] == UNICODE_SLASH) && (SourceFile.FileBufferPtr[1] == UNICODE_SLASH)) { + InComment = 1; + SourceFile.FileBufferPtr[0] = UNICODE_SPACE; + } + + SourceFile.FileBufferPtr++; + } + // + // Reposition to the start of the file, but skip over the unicode file start + // + SourceFile.FileBufferPtr = SourceFile.FileBuffer; + SourceFile.FileBufferPtr++; + SourceFile.EndOfFile = 0; + CapsuleHeader->OffsetToOemDefinedHeader = ftell (OutFptr); + // + // Parse the OEM bytes + // + if (ParseOemInfo (&SourceFile, OutFptr) != STATUS_SUCCESS) { + goto Done; + } + // + // Parse the author information + // + CapsuleHeader->OffsetToAuthorInformation = ftell (OutFptr); + if (ParseCapsuleInfo (&SourceFile, OutFptr, AUTHOR_INFO_STRING) != STATUS_SUCCESS) { + goto Done; + } + // + // Parse the revision information + // + CapsuleHeader->OffsetToRevisionInformation = ftell (OutFptr); + if (ParseCapsuleInfo (&SourceFile, OutFptr, REVISION_INFO_STRING) != STATUS_SUCCESS) { + goto Done; + } + // + // Parse the short description + // + CapsuleHeader->OffsetToShortDescription = ftell (OutFptr); + if (ParseCapsuleInfo (&SourceFile, OutFptr, SHORT_DESCRIPTION_STRING) != STATUS_SUCCESS) { + goto Done; + } + // + // Parse the long description + // + CapsuleHeader->OffsetToLongDescription = ftell (OutFptr); + if (ParseCapsuleInfo (&SourceFile, OutFptr, LONG_DESCRIPTION_STRING) != STATUS_SUCCESS) { + goto Done; + } + // + // Better be end of contents + // + SkipWhiteSpace (&SourceFile); + if (!EndOfFile (&SourceFile)) { + Error (ScriptFileName, SourceFile.LineNum, 0, NULL, "expected end-of-file, not %.20S", SourceFile.FileBufferPtr); + goto Done; + } + + CapsuleHeader->OffsetToCapsuleBody = ftell (OutFptr); + rewind (OutFptr); + fwrite (CapsuleHeader, sizeof (EFI_CAPSULE_HEADER), 1, OutFptr); + fseek (OutFptr, 0, SEEK_END); + Status = STATUS_SUCCESS; +Done: + if (SourceFile.FilePtr != NULL) { + fclose (SourceFile.FilePtr); + } + + if (SourceFile.FileBuffer != NULL) { + free (SourceFile.FileBuffer); + } + + return Status; + +#endif + return STATUS_SUCCESS; +} +// +// Parse the OEM data of format: +// OemInfo { +// GUID = 12345676-1234-1234-123456789ABC +// DATA = 0x01, 0x02, 0x03... +// } +// +static +STATUS +ParseOemInfo ( + SOURCE_FILE *SourceFile, + FILE *OutFptr + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + SourceFile - GC_TODO: add argument description + OutFptr - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + long OemHeaderOffset; + UINT32 Data; + EFI_CAPSULE_OEM_HEADER OemHeader; + STATUS Status; + UINT32 DigitCount; + WCHAR *SaveFilePos; + UINT8 ByteData; + + Status = STATUS_ERROR; + memset (&OemHeader, 0, sizeof (EFI_CAPSULE_OEM_HEADER)); + OemHeaderOffset = ftell (OutFptr); + OemHeader.HeaderSize = sizeof (EFI_CAPSULE_OEM_HEADER); + if (fwrite (&OemHeader, sizeof (EFI_CAPSULE_OEM_HEADER), 1, OutFptr) != 1) { + Error (NULL, 0, 0, "failed to write OEM header to output file", NULL); + goto Done; + } + + if (!IsToken (SourceFile, OEM_HEADER_STRING)) { + Error ( + SourceFile->FileName, + SourceFile->LineNum, + 0, + NULL, + "expected %S, not %.20S", + OEM_HEADER_STRING, + SourceFile->FileBufferPtr + ); + goto Done; + } + + if (!IsToken (SourceFile, EQUAL_STRING)) { + Error ( + SourceFile->FileName, + SourceFile->LineNum, + 0, + NULL, + "expected %S, not %.20S", + EQUAL_STRING, + SourceFile->FileBufferPtr + ); + goto Done; + } + + if (!IsToken (SourceFile, OPEN_BRACE_STRING)) { + Error ( + SourceFile->FileName, + SourceFile->LineNum, + 0, + NULL, + "expected %S, not %.20S", + OPEN_BRACE_STRING, + SourceFile->FileBufferPtr + ); + goto Done; + } + // + // Look for: GUID = xxxxxxx-xxxx-xxxx-xxxxxxxxxxxxx + // + if (!IsToken (SourceFile, GUID_STRING)) { + Error ( + SourceFile->FileName, + SourceFile->LineNum, + 0, + NULL, + "expected %S, not %.20S", + GUID_STRING, + SourceFile->FileBufferPtr + ); + goto Done; + } + + if (!IsToken (SourceFile, EQUAL_STRING)) { + Error ( + SourceFile->FileName, + SourceFile->LineNum, + 0, + NULL, + "expected %S, not %.20S", + EQUAL_STRING, + SourceFile->FileBufferPtr + ); + goto Done; + } + // + // Parse the xxxxxxxx-xxxx-xxxx-xxxx portion of the GUID + // + SkipWhiteSpace (SourceFile); + if (GetHexValue (SourceFile, &Data, 8) != STATUS_SUCCESS) { + Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid GUID", NULL); + goto Done; + } + + OemHeader.OemGuid.Data1 = Data; + if (!IsToken (SourceFile, L"-")) { + Error ( + SourceFile->FileName, + SourceFile->LineNum, + 0, + NULL, + "expected dash in GUID, not %S", + SourceFile->FileBufferPtr + ); + goto Done; + } + // + // Get 3 word values + // + for (DigitCount = 0; DigitCount < 3; DigitCount++) { + if (GetHexValue (SourceFile, &Data, 4) != STATUS_SUCCESS) { + Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid GUID", NULL); + goto Done; + } + + switch (DigitCount) { + case 0: + OemHeader.OemGuid.Data2 = (UINT16) Data; + break; + + case 1: + OemHeader.OemGuid.Data3 = (UINT16) Data; + break; + + case 2: + OemHeader.OemGuid.Data4[1] = (UINT8) Data; + OemHeader.OemGuid.Data4[0] = (UINT8) (Data >> 8); + break; + } + + if (!IsToken (SourceFile, L"-")) { + Error ( + SourceFile->FileName, + SourceFile->LineNum, + 0, + NULL, + "expected dash in GUID, not %S", + SourceFile->FileBufferPtr + ); + goto Done; + } + } + // + // Pick up the last 6 bytes of the GUID + // + SaveFilePos = SourceFile->FileBufferPtr; + for (DigitCount = 0; DigitCount < 6; DigitCount++) { + if (GetHexValue (SourceFile, &Data, 2) != STATUS_SUCCESS) { + Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid GUID", NULL); + goto Done; + } + + OemHeader.OemGuid.Data4[DigitCount + 2] = (UINT8) Data; + } + // + // Now read raw OEM data bytes. May or may not be present. + // DATA = 0x01, 0x02, 0x02... + // + if (IsToken (SourceFile, CLOSE_BRACE_STRING)) { + Status = STATUS_SUCCESS; + goto Done; + } + + if (!IsToken (SourceFile, DATA_STRING)) { + Error ( + SourceFile->FileName, + SourceFile->LineNum, + 0, + NULL, + "expected %S, not %.20S", + DATA_STRING, + SourceFile->FileBufferPtr + ); + goto Done; + } + + if (!IsToken (SourceFile, EQUAL_STRING)) { + Error ( + SourceFile->FileName, + SourceFile->LineNum, + 0, + NULL, + "expected %S, not %.20S", + EQUAL_STRING, + SourceFile->FileBufferPtr + ); + goto Done; + } + + while (!EndOfFile (SourceFile)) { + if (IsToken (SourceFile, CLOSE_BRACE_STRING)) { + Status = STATUS_SUCCESS; + goto Done; + } + + if (IsToken (SourceFile, L"0x")) { + if (swscanf (SourceFile->FileBufferPtr, L"%x", &Data) != 1) { + Error ( + SourceFile->FileName, + SourceFile->LineNum, + 0, + NULL, + "expected hex byte value, not %.20S", + SourceFile->FileBufferPtr + ); + goto Done; + } + + if (Data &~0xFF) { + Error ( + SourceFile->FileName, + SourceFile->LineNum, + 0, + NULL, + "expected byte hex byte value at %.20S", + SourceFile->FileBufferPtr + ); + goto Done; + } + // + // Skip over the hex digits, then write the data + // + while (iswxdigit (SourceFile->FileBufferPtr[0])) { + SourceFile->FileBufferPtr++; + } + + ByteData = (UINT8) Data; + if (fwrite (&ByteData, 1, 1, OutFptr) != 1) { + Error (NULL, 0, 0, "failed to write OEM data to output file", NULL); + goto Done; + } + + OemHeader.HeaderSize++; + // + // Optional comma + // + IsToken (SourceFile, L","); + } else { + Error ( + SourceFile->FileName, + SourceFile->LineNum, + 0, + NULL, + "expected hex OEM data, not %.20S", + SourceFile->FileBufferPtr + ); + goto Done; + } + } + + if (EndOfFile (SourceFile)) { + Error ( + SourceFile->FileName, + SourceFile->LineNum, + 0, + NULL, + "expected %S close to OEM header data", + CLOSE_BRACE_STRING + ); + goto Done; + } + + Status = STATUS_SUCCESS; +Done: + // + // re-write the oem header if no errors + // + if (Status == STATUS_SUCCESS) { + fseek (OutFptr, OemHeaderOffset, SEEK_SET); + if (fwrite (&OemHeader, sizeof (EFI_CAPSULE_OEM_HEADER), 1, OutFptr) != 1) { + Error (NULL, 0, 0, "failed to write OEM header to output file", NULL); + goto Done; + } + + fseek (OutFptr, 0, SEEK_END); + } + + return Status; +} + +static +STATUS +ParseCapsuleInfo ( + SOURCE_FILE *SourceFile, + FILE *OutFptr, + WCHAR *SectionName + ) +// GC_TODO: function comment should start with '/*++' +// +// GC_TODO: function comment is missing 'Routine Description:' +// GC_TODO: function comment is missing 'Arguments:' +// GC_TODO: function comment is missing 'Returns:' +// GC_TODO: SourceFile - add argument and description to function comment +// GC_TODO: OutFptr - add argument and description to function comment +// GC_TODO: SectionName - add argument and description to function comment +// Parse: eng "string " "parts" +// spa "string " "parts" +// Write out: "eng string parts\0spa string parts\0\0 +// +{ + STATUS Status; + int StringCount; + WCHAR Zero; + WCHAR Spacebar; + + Status = STATUS_ERROR; + Zero = 0; + Spacebar = UNICODE_SPACE; + + if (!IsToken (SourceFile, SectionName)) { + Error ( + SourceFile->FileName, + SourceFile->LineNum, + 0, + NULL, + "expected %S, not %.20S", + SectionName, + SourceFile->FileBufferPtr + ); + goto Done; + } + + if (!IsToken (SourceFile, EQUAL_STRING)) { + Error ( + SourceFile->FileName, + SourceFile->LineNum, + 0, + NULL, + "expected %S, not %.20S", + EQUAL_STRING, + SourceFile->FileBufferPtr + ); + goto Done; + } + + if (!IsToken (SourceFile, OPEN_BRACE_STRING)) { + Error ( + SourceFile->FileName, + SourceFile->LineNum, + 0, + NULL, + "expected %S, not %.20S", + OPEN_BRACE_STRING, + SourceFile->FileBufferPtr + ); + goto Done; + } + + while (!EndOfFile (SourceFile)) { + if (IsToken (SourceFile, CLOSE_BRACE_STRING)) { + break; + } + // + // Look for language identifier (3 lowercase chars) + // + if ((SourceFile->FileBufferPtr[0] >= UNICODE_a) && + (SourceFile->FileBufferPtr[0] <= UNICODE_z) && + (SourceFile->FileBufferPtr[1] >= UNICODE_a) && + (SourceFile->FileBufferPtr[1] <= UNICODE_z) && + (SourceFile->FileBufferPtr[2] >= UNICODE_a) && + (SourceFile->FileBufferPtr[2] <= UNICODE_z) && + IsWhiteSpace (SourceFile->FileBufferPtr[3]) + ) { + // + // Write the 3 chars followed by a spacebar, and then look for opening quote + // + fwrite (SourceFile->FileBufferPtr, sizeof (WCHAR), 1, OutFptr); + SourceFile->FileBufferPtr++; + fwrite (SourceFile->FileBufferPtr, sizeof (WCHAR), 1, OutFptr); + SourceFile->FileBufferPtr++; + fwrite (SourceFile->FileBufferPtr, sizeof (WCHAR), 1, OutFptr); + SourceFile->FileBufferPtr++; + fwrite (&Spacebar, sizeof (WCHAR), 1, OutFptr); + StringCount = 0; + while (IsToken (SourceFile, L"\"")) { + StringCount++; + while (!EndOfFile (SourceFile)) { + if (SourceFile->FileBufferPtr[0] == UNICODE_DOUBLE_QUOTE) { + SourceFile->FileBufferPtr++; + break; + } else if ((SourceFile->FileBufferPtr[0] == UNICODE_LF) || (SourceFile->FileBufferPtr[0] == 0)) { + Error (SourceFile->FileName, SourceFile->LineNum, 0, "missing closing quote on string", NULL); + goto Done; + } else { + fwrite (SourceFile->FileBufferPtr, sizeof (WCHAR), 1, OutFptr); + SourceFile->FileBufferPtr++; + } + } + } + + if (StringCount == 0) { + Error ( + SourceFile->FileName, + SourceFile->LineNum, + 0, + NULL, + "expected quoted string, not %.20S", + SourceFile->FileBufferPtr + ); + goto Done; + } + // + // This string's null terminator + // + fwrite (&Zero, sizeof (WCHAR), 1, OutFptr); + } else { + Error ( + SourceFile->FileName, + SourceFile->LineNum, + 0, + NULL, + "expected valid language identifer, not %.20S", + SourceFile->FileBufferPtr + ); + goto Done; + } + } + // + // Double null terminator + // + fwrite (&Zero, sizeof (WCHAR), 1, OutFptr); + Status = STATUS_SUCCESS; +Done: + return Status; +} + +static +STATUS +SplitCapsule ( + INT8 *CapsuleFileName + ) +/*++ + +Routine Description: + We've created an entire capsule image. Now split it up into the + size pieces they requested. + +Arguments: + CapsuleFileName - name of an existing capsule file on disk + +Returns: + STATUS_SUCCESS - if no problems + +Notes: + This implementation reads in the entire capsule image from + disk, then overwrites the original file with the first + in the series. + +--*/ +{ +#if 0 + EFI_CAPSULE_HEADER *CapHdr; + + EFI_CAPSULE_HEADER Hdr; + FILE *CapFptr; + FILE *OutFptr; + UINT32 SizeLeft; + UINT32 CurrentSize; + UINT32 DataSize; + UINT32 SequenceNumber; + INT8 *Buffer; + INT8 FileName[MAX_PATH]; + STATUS Status; + UINT32 FileSize; + // + // Figure out the total size, then rewind the input file and + // read the entire thing in + // + if ((CapFptr = fopen (CapsuleFileName, "rb")) == NULL) { + Error (NULL, 0, 0, CapsuleFileName, "failed to open capsule image for reading"); + return STATUS_ERROR; + } + + OutFptr = NULL; + Status = STATUS_SUCCESS; + fseek (CapFptr, 0, SEEK_END); + SizeLeft = ftell (CapFptr); + fseek (CapFptr, 0, SEEK_SET); + CapHdr = (EFI_CAPSULE_HEADER *) malloc (SizeLeft); + if (CapHdr == NULL) { + Error (NULL, 0, 0, "memory allocation failure", NULL); + goto FailDone; + } + + if (fread (CapHdr, SizeLeft, 1, CapFptr) != 1) { + Error (NULL, 0, 0, "failed to read capsule contents", "split failed"); + goto FailDone; + } + + fclose (CapFptr); + CapFptr = NULL; + // + // Get a GUID to fill in the InstanceId GUID in the header + // + CreateGuid (&CapHdr->InstanceId); + SequenceNumber = 0; + // + // If the split size is larger than the original capsule image, then + // we're done. + // + if (mOptions.SizeList->Size >= SizeLeft) { + mOptions.SizeList->Size = SizeLeft; + goto Done; + } + // + // First size has to be big enough for the original header + // + if (mOptions.SizeList->Size < CapHdr->OffsetToCapsuleBody) { + Error (NULL, 0, 0, "first split size is insufficient for the original capsule header", NULL); + goto FailDone; + } + // + // Initialize the header we'll use on all but the first part + // + memset (&Hdr, 0, sizeof (Hdr)); + Hdr.CapsuleGuid = CapHdr->CapsuleGuid; + Hdr.HeaderSize = sizeof (Hdr); + Hdr.Flags = CapHdr->Flags; + Hdr.InstanceId = CapHdr->InstanceId; + Hdr.CapsuleImageSize = CapHdr->CapsuleImageSize; + Hdr.OffsetToCapsuleBody = Hdr.HeaderSize; + Hdr.SequenceNumber = 1; + // + // printf ("Created %s - 0x%X bytes\n", CapsuleFileName, mOptions.SizeList->Size); + // + Buffer = (UINT8 *) CapHdr; + // + // Walk the list of sizes and write out a capsule header, and + // then the raw capsule data. + // + // SizeLeft -= mOptions.SizeList->Size; + // + mOptions.CurrentSize = mOptions.SizeList; + while (SizeLeft) { + CurrentSize = mOptions.CurrentSize->Size; + GetSplitFileName (mOptions.OutputFileName, FileName, SequenceNumber); + if ((OutFptr = fopen (FileName, "wb")) == NULL) { + Error (NULL, 0, 0, FileName, "failed to open split file for writing"); + goto FailDone; + } + + if (Buffer == (UINT8 *) CapHdr) { + // + // First part -- write out original header and data + // + if (fwrite (Buffer, CurrentSize, 1, OutFptr) != 1) { + Error (NULL, 0, 0, FileName, "failed to write to split image file"); + goto FailDone; + } + + SizeLeft -= CurrentSize; + Buffer += CurrentSize; + DataSize = CurrentSize; + FileSize = CurrentSize; + } else { + // + // Not the first part. Write the default header, and then the raw bytes from the + // original image. + // + if (CurrentSize <= sizeof (Hdr)) { + Error (NULL, 0, 0, "split size too small for capsule header + data", "0x%X", CurrentSize); + goto FailDone; + } + + DataSize = CurrentSize - sizeof (Hdr); + if (DataSize > SizeLeft) { + DataSize = SizeLeft; + } + + if (fwrite (&Hdr, sizeof (Hdr), 1, OutFptr) != 1) { + Error (NULL, 0, 0, FileName, "failed to write capsule header to output file"); + fclose (OutFptr); + goto FailDone; + } + + if (fwrite (Buffer, DataSize, 1, OutFptr) != 1) { + Error (NULL, 0, 0, FileName, "failed to write capsule data to output file"); + fclose (OutFptr); + goto FailDone; + } + + Hdr.SequenceNumber++; + Buffer += DataSize; + SizeLeft -= DataSize; + FileSize = DataSize + sizeof (Hdr); + } + // + // Next size in list if there is one + // + if (mOptions.CurrentSize->Next != NULL) { + mOptions.CurrentSize = mOptions.CurrentSize->Next; + } + + SequenceNumber++; + fclose (OutFptr); + OutFptr = NULL; + printf ("Created %s - 0x%X bytes (0x%X bytes of data)\n", FileName, FileSize, DataSize); + } + + goto Done; +FailDone: + Status = STATUS_ERROR; +Done: + if (CapHdr != NULL) { + free (CapHdr); + } + + if (CapFptr != NULL) { + fclose (CapFptr); + } + + if (OutFptr != NULL) { + fclose (OutFptr); + } + + return Status; + +#endif + return STATUS_SUCCESS; +} + +static +BOOLEAN +GetSplitFileName ( + INT8 *BaseFileName, + INT8 *NewFileName, + UINT32 SequenceNumber + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + BaseFileName - GC_TODO: add argument description + NewFileName - GC_TODO: add argument description + SequenceNumber - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + /*++ + +Routine Description: + Given an initial split capsule file name and a sequence number, + create an appropriate file name for this split of a capsule image. + +Arguments: + BaseFileName - name of of the first split file in the series + NewFileName - output name of the split file + SequenceNumber - 0-based sequence number of split images + +Returns: + TRUE - name created successfully + FALSE - otherwise + +--*/ + INT8 *Ptr; + INT8 *Part2Start; + UINT32 Digits; + UINT32 Len; + UINT32 BaseOffset; + // + // Work back from the end of the file name and see if there is a number somewhere + // + for (Ptr = BaseFileName + strlen (BaseFileName) - 1; (Ptr > BaseFileName) && !isdigit (*Ptr); Ptr--) + ; + if ((Ptr == BaseFileName) && (!isdigit (*Ptr))) { + // + // Found no number, so just add it to the end + // + sprintf (NewFileName, "%s%d", BaseFileName, SequenceNumber); + return TRUE; + } else { + // + // Found a number. Look back to find the first digit. + // + Part2Start = Ptr + 1; + for (Digits = 1; isdigit (*Ptr) && (Ptr > BaseFileName); Ptr--, Digits++) + ; + if (!isdigit (*Ptr)) { + Ptr++; + Digits--; + } + + BaseOffset = atoi (Ptr); + SequenceNumber = SequenceNumber + BaseOffset; + if (Digits > 1) { + // + // Copy the first part of the original file name to the new filename + // This is the path for filenames with format path\name001.cap + // + Len = (UINT32) Ptr - (UINT32) BaseFileName; + strncpy (NewFileName, BaseFileName, Len); + sprintf (NewFileName + Len, "%0*d", Digits, SequenceNumber); + strcat (NewFileName, Part2Start); + return TRUE; + } else { + // + // Only one digit found. This is the path for filenames with + // format path\name1.cap + // + Len = (UINT32) Ptr - (UINT32) BaseFileName + 1; + strncpy (NewFileName, BaseFileName, Len); + sprintf (NewFileName + Len - 1, "%d", SequenceNumber); + strcat (NewFileName, Part2Start); + return TRUE; + } + } +} + +static +BOOLEAN +IsWhiteSpace ( + WCHAR Char + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Char - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + switch (Char) { + case UNICODE_SPACE: + case UNICODE_TAB: + case UNICODE_NULL: + case UNICODE_CR: + case UNICODE_LF: + return TRUE; + + default: + return FALSE; + } +} + +static +BOOLEAN +IsToken ( + SOURCE_FILE *File, + WCHAR *Token + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + File - GC_TODO: add argument description + Token - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + SkipWhiteSpace (File); + if (EndOfFile (File)) { + return FALSE; + } + + if (wcsncmp (Token, File->FileBufferPtr, wcslen (Token)) == 0) { + File->FileBufferPtr += wcslen (Token); + return TRUE; + } + + return FALSE; +} + +static +STATUS +CheckFirmwareVolumeHeader ( + INT8 *FileName, + INT8 *Buffer, + UINT32 BufferSize + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + FileName - GC_TODO: add argument description + Buffer - GC_TODO: add argument description + BufferSize - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + EFI_FIRMWARE_VOLUME_HEADER *Hdr; + EFI_GUID FVHeaderGuid = EFI_FIRMWARE_FILE_SYSTEM_GUID; + + Hdr = (EFI_FIRMWARE_VOLUME_HEADER *) Buffer; + if (Hdr->Signature != EFI_FVH_SIGNATURE) { + Error (NULL, 0, 0, FileName, "file does not appear to be a firmware volume (bad signature)"); + return STATUS_ERROR; + } + + if (Hdr->Revision != EFI_FVH_REVISION) { + Error (NULL, 0, 0, FileName, "unsupported firmware volume header version"); + return STATUS_ERROR; + } + + if (Hdr->FvLength > BufferSize) { + Error (NULL, 0, 0, FileName, "malformed firmware volume -- FvLength > file size"); + return STATUS_ERROR; + } + + if (memcmp (&Hdr->FileSystemGuid, &FVHeaderGuid, sizeof (EFI_GUID)) != 0) { + Error (NULL, 0, 0, FileName, "invalid FFS GUID in firmware volume header"); + return STATUS_ERROR; + } + + return STATUS_SUCCESS; +} + +static +void +DumpCapsule ( + VOID + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + None + +Returns: + + GC_TODO: add return values + +--*/ +{ +#if 0 + FILE *InFptr; + FILE_LIST *FileList; + EFI_CAPSULE_HEADER CapsuleHeader; + EFI_FIRMWARE_VOLUME_HEADER FVHeader; + EFI_CAPSULE_OEM_HEADER *OemHeader; + UINT8 *BPtr; + UINT32 FileSize; + UINT32 CapsuleHeaderDataSize; + UINT8 ByteCount; + UINT8 *CapsuleHeaderData; + BOOLEAN SplitImage; + + InFptr = NULL; + CapsuleHeaderData = NULL; + FileList = mOptions.FileList; + while (FileList != NULL) { + if ((InFptr = fopen (FileList->FileName, "rb")) == NULL) { + Error (NULL, 0, 0, FileList->FileName, "failed to open file for reading"); + goto Done; + } + + if (fread (&CapsuleHeader, sizeof (EFI_CAPSULE_HEADER), 1, InFptr) != 1) { + Error (NULL, 0, 0, FileList->FileName, "failed to read capsule header"); + goto Done; + } + + fseek (InFptr, 0, SEEK_END); + FileSize = ftell (InFptr); + if (CapsuleHeader.CapsuleImageSize > FileSize) { + SplitImage = TRUE; + } else { + SplitImage = FALSE; + } + + printf ( + "Capsule %s Size=0x%X CargoSize=0x%X\n", + FileList->FileName, + FileSize, + FileSize - CapsuleHeader.OffsetToCapsuleBody + ); + printf ( + " GUID %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + CapsuleHeader.CapsuleGuid.Data1, + (UINT32) CapsuleHeader.CapsuleGuid.Data2, + (UINT32) CapsuleHeader.CapsuleGuid.Data3, + (UINT32) CapsuleHeader.CapsuleGuid.Data4[0], + (UINT32) CapsuleHeader.CapsuleGuid.Data4[1], + (UINT32) CapsuleHeader.CapsuleGuid.Data4[2], + (UINT32) CapsuleHeader.CapsuleGuid.Data4[3], + (UINT32) CapsuleHeader.CapsuleGuid.Data4[4], + (UINT32) CapsuleHeader.CapsuleGuid.Data4[5], + (UINT32) CapsuleHeader.CapsuleGuid.Data4[6], + (UINT32) CapsuleHeader.CapsuleGuid.Data4[7] + ); + if (memcmp (&CapsuleHeader.CapsuleGuid, &mEfiCapsuleHeaderGuid, sizeof (EFI_GUID)) != 0) { + printf (" INVALID GUID"); + } + + printf ("\n"); + printf (" Header size 0x%08X\n", CapsuleHeader.HeaderSize); + printf (" Flags 0x%08X\n", CapsuleHeader.Flags); + if (!SplitImage) { + printf (" Capsule image size 0x%08X\n", CapsuleHeader.CapsuleImageSize); + } else { + printf (" Capsule image size 0x%08X (split)\n", CapsuleHeader.CapsuleImageSize); + } + + printf (" Sequence number %d\n", CapsuleHeader.SequenceNumber); + printf ( + " InstanceId %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n", + CapsuleHeader.InstanceId.Data1, + (UINT32) CapsuleHeader.InstanceId.Data2, + (UINT32) CapsuleHeader.InstanceId.Data3, + (UINT32) CapsuleHeader.InstanceId.Data4[0], + (UINT32) CapsuleHeader.InstanceId.Data4[1], + (UINT32) CapsuleHeader.InstanceId.Data4[2], + (UINT32) CapsuleHeader.InstanceId.Data4[3], + (UINT32) CapsuleHeader.InstanceId.Data4[4], + (UINT32) CapsuleHeader.InstanceId.Data4[5], + (UINT32) CapsuleHeader.InstanceId.Data4[6], + (UINT32) CapsuleHeader.InstanceId.Data4[7] + ); + printf (" Offset to capsule 0x%X\n", CapsuleHeader.OffsetToCapsuleBody); + // + // Dump header data if there + // + CapsuleHeaderDataSize = CapsuleHeader.OffsetToCapsuleBody - CapsuleHeader.HeaderSize; + if (CapsuleHeaderDataSize != 0) { + CapsuleHeaderData = (UINT8 *) malloc (CapsuleHeaderDataSize); + if (CapsuleHeaderData == NULL) { + Error ( + NULL, + 0, + 0, + "failed to allocate memory to read in capsule header data", + "0x%X bytes", + CapsuleHeaderDataSize + ); + goto Done; + } + + fseek (InFptr, CapsuleHeader.HeaderSize, SEEK_SET); + if (fread (CapsuleHeaderData, CapsuleHeaderDataSize, 1, InFptr) != 1) { + Error ( + NULL, + 0, + 0, + "failed to read capsule header data contents from file", + "0x%X bytes", + CapsuleHeaderDataSize + ); + goto Done; + } + // + // ************************************************************************ + // + // OEM HEADER + // + // ************************************************************************ + // + if (CapsuleHeader.OffsetToOemDefinedHeader != 0) { + OemHeader = (EFI_CAPSULE_OEM_HEADER *) (CapsuleHeaderData + CapsuleHeader.OffsetToOemDefinedHeader - CapsuleHeader.HeaderSize); + printf (" OEM Header\n"); + printf ( + " GUID %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n", + OemHeader->OemGuid.Data1, + (UINT32) OemHeader->OemGuid.Data2, + (UINT32) OemHeader->OemGuid.Data3, + (UINT32) OemHeader->OemGuid.Data4[0], + (UINT32) OemHeader->OemGuid.Data4[1], + (UINT32) OemHeader->OemGuid.Data4[2], + (UINT32) OemHeader->OemGuid.Data4[3], + (UINT32) OemHeader->OemGuid.Data4[4], + (UINT32) OemHeader->OemGuid.Data4[5], + (UINT32) OemHeader->OemGuid.Data4[6], + (UINT32) OemHeader->OemGuid.Data4[7] + ); + printf (" Header size: 0x%X\n", OemHeader->HeaderSize); + printf (" OEM data"); + BPtr = (UINT8 *) (OemHeader + 1); + for (ByteCount = 0; ByteCount < OemHeader->HeaderSize - sizeof (EFI_CAPSULE_OEM_HEADER); ByteCount++) { + if ((ByteCount & 0x7) == 0) { + printf ("\n "); + } + + printf ("%02X ", (UINT32) *BPtr); + BPtr++; + } + + printf ("\n"); + } + // + // ************************************************************************ + // + // Author, revision, short description, and long description information + // + // ************************************************************************ + // + if (CapsuleHeader.OffsetToAuthorInformation != 0) { + if (DumpCapsuleHeaderStrings ( + "Author information", + (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToAuthorInformation - CapsuleHeader.HeaderSize) + ) != STATUS_SUCCESS) { + goto Done; + } + } + + if (CapsuleHeader.OffsetToRevisionInformation != 0) { + if (DumpCapsuleHeaderStrings ( + "Revision information", + (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToRevisionInformation - CapsuleHeader.HeaderSize) + ) != STATUS_SUCCESS) { + goto Done; + } + } + + if (CapsuleHeader.OffsetToShortDescription != 0) { + if (DumpCapsuleHeaderStrings ( + "Short description", + (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToShortDescription - CapsuleHeader.HeaderSize) + ) != STATUS_SUCCESS) { + goto Done; + } + } + + if (CapsuleHeader.OffsetToLongDescription != 0) { + if (DumpCapsuleHeaderStrings ( + "Long description", + (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToLongDescription - CapsuleHeader.HeaderSize) + ) != STATUS_SUCCESS) { + goto Done; + } + } + } + // + // If it's not a split image, or it is a split image and this is the first in the series, then + // dump the cargo volume. + // + if ((!SplitImage) || (CapsuleHeader.SequenceNumber == 0)) { + printf (" Cargo FV dump\n"); + fseek (InFptr, CapsuleHeader.OffsetToCapsuleBody, SEEK_SET); + if (fread (&FVHeader, sizeof (EFI_FIRMWARE_VOLUME_HEADER), 1, InFptr) != 1) { + Error (NULL, 0, 0, FileList->FileName, "failed to read cargo FV header"); + goto Done; + } + + printf (" FV length 0x%X", FVHeader.FvLength); + if (FileSize - CapsuleHeader.OffsetToCapsuleBody != FVHeader.FvLength) { + if (!SplitImage) { + printf (" ERROR: expected 0x%X to jive with file size on disk", FileSize - CapsuleHeader.OffsetToCapsuleBody); + } + } + + printf ("\n"); + printf (" Signature 0x%X ", FVHeader.Signature); + if (FVHeader.Signature == EFI_FVH_SIGNATURE) { + printf ("_FVH\n"); + } else { + printf ("INVALID\n"); + } + + printf (" FV header length 0x%X\n", (UINT32) FVHeader.HeaderLength); + printf (" Revision 0x%X\n", (UINT32) FVHeader.Revision); + printf ("\n"); + } + + FileList = FileList->Next; + } + +Done: + if (InFptr != NULL) { + fclose (InFptr); + } + + if (CapsuleHeaderData != NULL) { + free (CapsuleHeaderData); + } +#endif +} + +static +STATUS +JoinCapsule ( + VOID + ) +/*++ + +Routine Description: + Join split capsule images into a single image. This is the + support function for the -j command-line option. + +Arguments: + None. + +Returns: + STATUS_SUCCESS - no problems encountered + +--*/ +{ +#if 0 + UINT32 Size; + FILE *InFptr; + FILE *OutFptr; + INT8 *Buffer; + FILE_LIST *FileList; + STATUS Status; + EFI_CAPSULE_HEADER CapHdr; + EFI_CAPSULE_HEADER *CapHdrPtr; + UINT32 SizeLeft; + UINT32 SequenceNumber; + // + // Must have at least two files for join mode + // + if ((mOptions.FileList == NULL) || (mOptions.FileList->Next == NULL)) { + Error (NULL, 0, 0, "must specify at least two file names to join", NULL); + return STATUS_ERROR; + } + // + // Open the output file + // + if ((OutFptr = fopen (mOptions.OutputFileName, "wb")) == NULL) { + Error (NULL, 0, 0, mOptions.OutputFileName, "failed to open output file for writing"); + return STATUS_ERROR; + } + + FileList = mOptions.FileList; + Buffer = NULL; + SequenceNumber = 0; + InFptr = NULL; + SizeLeft = 0; + while (FileList != NULL) { + if ((InFptr = fopen (FileList->FileName, "rb")) == NULL) { + Error (NULL, 0, 0, FileList->FileName, "failed to open file for reading"); + goto FailDone; + } + // + // Allocate a buffer into which we can read the file. + // + fseek (InFptr, 0, SEEK_END); + Size = ftell (InFptr); + rewind (InFptr); + Buffer = (char *) malloc (Size); + if (Buffer == NULL) { + Error (__FILE__, __LINE__, 0, FileList->FileName, "failed to allocate buffer to read file into"); + goto FailDone; + } + + CapHdrPtr = (EFI_CAPSULE_HEADER *) Buffer; + if (fread ((void *) Buffer, Size, 1, InFptr) != 1) { + Error (NULL, 0, 0, FileList->FileName, "failed to read file contents"); + goto FailDone; + } + // + // Check the header for validity. Check size first. + // + if (Size < sizeof (EFI_CAPSULE_HEADER)) { + Error (NULL, 0, 0, FileList->FileName, "file size is insufficient for a capsule header"); + goto FailDone; + } + // + // Check GUID + // + if (memcmp (&CapHdrPtr->CapsuleGuid, &mEfiCapsuleHeaderGuid, sizeof (EFI_GUID)) != 0) { + Error (NULL, 0, 0, FileList->FileName, "invalid capsule GUID"); + goto FailDone; + } + // + // Check sequence number + // + if (CapHdrPtr->SequenceNumber != SequenceNumber) { + Error ( + NULL, + 0, + 0, + FileList->FileName, + "invalid sequence number %d (expected %d)", + CapHdrPtr->SequenceNumber, + SequenceNumber + ); + goto FailDone; + } + // + // If the first file, read save the capsule header + // + if (SequenceNumber == 0) { + memcpy (&CapHdr, CapHdrPtr, sizeof (EFI_CAPSULE_HEADER)); + // + // Erase the InstanceId GUID + // + memset (&CapHdrPtr->InstanceId, 0, sizeof (EFI_GUID)); + if (fwrite (Buffer, Size, 1, OutFptr) != 1) { + Error (NULL, 0, 0, FileList->FileName, "failed to write contents to output file"); + goto FailDone; + } + + if (CapHdr.CapsuleImageSize < Size) { + Error (NULL, 0, 0, FileList->FileName, "capsule image size in capsule header < image size"); + goto FailDone; + } + + SizeLeft = CapHdr.CapsuleImageSize - Size; + } else { + // + // Check the GUID against the first file's GUID + // + if (memcmp (&CapHdr.CapsuleGuid, &CapHdrPtr->CapsuleGuid, sizeof (EFI_GUID)) != 0) { + Error (NULL, 0, 0, FileList->FileName, "GUID does not match first file's GUID"); + goto FailDone; + } + // + // Make sure we're not throwing out any header info + // + if (CapHdrPtr->OffsetToCapsuleBody > sizeof (EFI_CAPSULE_HEADER)) { + // + // Could be the split information, so just emit a warning + // + Warning ( + NULL, + 0, + 0, + FileList->FileName, + "image appears to have additional capsule header information -- ignoring" + ); + } else if (CapHdrPtr->OffsetToCapsuleBody < sizeof (EFI_CAPSULE_HEADER)) { + Error (NULL, 0, 0, FileList->FileName, "offset to capsule body in capsule header is insufficient"); + goto FailDone; + } + + if (fwrite (Buffer + CapHdrPtr->OffsetToCapsuleBody, Size - CapHdrPtr->OffsetToCapsuleBody, 1, OutFptr) != 1) { + Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file"); + goto FailDone; + } + + if (SizeLeft < (Size - CapHdrPtr->OffsetToCapsuleBody)) { + Error (NULL, 0, 0, "sum of image sizes exceeds size specified in initial capsule header", NULL); + goto FailDone; + } + // + // printf ("FILE: %s OffsetToCapsuleBody=0x%X\n", FileList->FileName, CapHdrPtr->OffsetToCapsuleBody); + // + SizeLeft = SizeLeft - (Size - CapHdrPtr->OffsetToCapsuleBody); + } + // + // printf ("FILE: %s sizeleft=0x%X\n", FileList->FileName, SizeLeft); + // + fclose (InFptr); + InFptr = NULL; + free (Buffer); + Buffer = NULL; + FileList = FileList->Next; + SequenceNumber++; + } + + if (SizeLeft) { + Error (NULL, 0, 0, "sum of capsule images is insufficient", "0x%X bytes missing", SizeLeft); + goto FailDone; + } + + Status = STATUS_SUCCESS; + goto Done; +FailDone: + Status = STATUS_ERROR; +Done: + if (InFptr != NULL) { + fclose (InFptr); + } + + if (OutFptr != NULL) { + fclose (OutFptr); + } + + if (Buffer != NULL) { + free (Buffer); + } + + return Status; + +#endif +return STATUS_SUCCESS; +} + +static +STATUS +DumpCapsuleHeaderStrings ( + UINT8 *SectionName, + WCHAR *Buffer + ) +/*++ + +Routine Description: + Given a pointer to string data from a capsule header, dump + the strings. + +Arguments: + SectionName - name of the capsule header section to which + the string data pertains + Buffer - pointer to string data from a capsule header + +Returns: + STATUS_SUCCESS - all went well + +--*/ +{ + printf (" %s\n", SectionName); + while (*Buffer) { + printf (" Language: %S\n", Buffer); + while (*Buffer) { + Buffer++; + } + + Buffer++; + while (*Buffer) { + if (wcslen (Buffer) > 60) { + printf (" %.60S\n", Buffer); + Buffer += 60; + } else { + printf (" %S\n", Buffer); + Buffer += wcslen (Buffer); + } + } + + Buffer++; + } + + return STATUS_SUCCESS; +} + +static +STATUS +GetHexValue ( + SOURCE_FILE *SourceFile, + UINT32 *Value, + UINT32 NumDigits + ) +/*++ + +Routine Description: + Scan a hex value from the input stream. + +Arguments: + SourceFile - input file contents + Value - returned value + NumDigits - number of digits to read + +Returns: + STATUS_SUCCESS - if NumDigits were read from the file + STATUS_ERROR - otherwise + + +--*/ +{ + WCHAR *SaveFilePos; + UINT32 Digits; + WCHAR Nibble; + + SaveFilePos = SourceFile->FileBufferPtr; + *Value = 0; + Digits = NumDigits; + while (Digits > 0) { + Nibble = SourceFile->FileBufferPtr[0]; + if ((Nibble >= UNICODE_0) && (Nibble <= UNICODE_9)) { + *Value = (*Value << 4) | (Nibble - UNICODE_0); + } else if ((Nibble >= UNICODE_A) && (Nibble <= UNICODE_F)) { + *Value = (*Value << 4) | (Nibble - UNICODE_A + 0x10); + } else if ((Nibble >= UNICODE_a) && (Nibble <= UNICODE_f)) { + *Value = (*Value << 4) | (Nibble - UNICODE_a + 0x10); + } else { + Error ( + SourceFile->FileName, + SourceFile->LineNum, + 0, + NULL, + "expected %d valid hex nibbles at %.20S", + NumDigits, + SaveFilePos + ); + return STATUS_ERROR; + } + + SourceFile->FileBufferPtr++; + Digits--; + } + + return STATUS_SUCCESS; +} + +static +BOOLEAN +EndOfFile ( + SOURCE_FILE *File + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + File - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + if ((UINT32) File->FileBufferPtr - (UINT32) File->FileBuffer >= File->FileSize) { + File->EndOfFile = TRUE; + } + // + // Reposition to the end of the file if we went beyond + // + if (File->EndOfFile) { + File->FileBufferPtr = File->FileBuffer + File->FileSize / sizeof (WCHAR); + } + + return File->EndOfFile; +} + +static +void +SkipWhiteSpace ( + SOURCE_FILE *SourceFile + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + SourceFile - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + while (!EndOfFile (SourceFile)) { + switch (*SourceFile->FileBufferPtr) { + case UNICODE_NULL: + case UNICODE_CR: + case UNICODE_SPACE: + case UNICODE_TAB: + SourceFile->FileBufferPtr++; + break; + + case UNICODE_LF: + SourceFile->FileBufferPtr++; + SourceFile->LineNum++; + break; + + default: + return ; + } + } +} +// +// Parse a number. Possible format: +// 1234 +// 1234k +// 1234K +// 1M +// 1m +// 0x100 +// +static +BOOLEAN +GetNumber ( + INT8 *Str, + UINT32 *Value + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + Str - GC_TODO: add argument description + Value - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + UINT32 LValue; + + *Value = 0; + LValue = 0; + if (!isdigit (Str[0])) { + return FALSE; + } + // + // Look for hex number + // + if ((Str[0] == '0') && (tolower (Str[1]) == 'x')) { + Str += 2; + if (Str[0] == 0) { + return FALSE; + } + + while (Str[0]) { + if ((Str[0] >= '0') && (Str[0] <= '9')) { + LValue = (LValue << 4) | (Str[0] - '0'); + } else if ((Str[0] >= 'A') && (Str[0] <= 'F')) { + LValue = (LValue << 4) | (Str[0] - 'A' + 0x10); + } else if ((Str[0] >= 'a') && (Str[0] <= 'f')) { + LValue = (LValue << 4) | (Str[0] - 'a' + 0x10); + } else { + break; + } + + Str++; + } + } else { + LValue = atoi (Str); + while (isdigit (*Str)) { + Str++; + } + } + // + // If string left over, better be one character we recognize + // + if (Str[0]) { + if (Str[1]) { + return FALSE; + } + + switch (Str[0]) { + case 'k': + case 'K': + LValue *= 1024; + break; + + case 'm': + case 'M': + LValue *= 1024 * 1024; + break; + + default: + return FALSE; + } + } + + *Value = LValue; + return TRUE; +} +// +// Process the command-line arguments +// +static +STATUS +ProcessArgs ( + int Argc, + char *Argv[] + ) +/*++ + +Routine Description: + + Processes command line arguments. + +Arguments: + + Argc - Number of command line arguments + Argv[] - Array of files input on command line + +Returns: + + STATUS_ERROR - Function exited with an error + STATUS_SUCCESS - Function executed successfully + +--*/ +{ + FILE_LIST *NewFile; + + FILE_LIST *LastFile; + SIZE_LIST *NewSize; + + NewFile = NULL; + NewSize = NULL; + + // + // Clear our globals + // + memset ((char *) &mOptions, 0, sizeof (mOptions)); + + // + // Skip program name + // + Argc--; + Argv++; + + if (Argc == 0) { + Usage (); + return STATUS_ERROR; + } + // + // Process until no more options + // + while ((Argc > 0) && (Argv[0][0] == '-')) { + if (stricmp (Argv[0], "-script") == 0) { + // + // Check for one more arg + // + if (Argc > 1) { + // + // Save the file name + // + if (strlen (Argv[1]) >= sizeof (mOptions.ScriptFileName)) { + Error (NULL, 0, 0, NULL, "input script file name length exceeds internal buffer size"); + + if (NewFile != NULL) { + free (NewFile); + } + if (NewSize != NULL) { + free (NewSize); + } + + return STATUS_ERROR; + } + + strcpy (mOptions.ScriptFileName, Argv[1]); + } else { + Error (NULL, 0, 0, Argv[0], "missing script file name with option"); + Usage (); + + if (NewFile != NULL) { + free (NewFile); + } + if (NewSize != NULL) { + free (NewSize); + } + + return STATUS_ERROR; + } + + Argc--; + Argv++; + // + // -o outfilename -- specify output file name (required) + // + } else if (stricmp (Argv[0], "-o") == 0) { + // + // check for one more arg + // + if (Argc > 1) { + // + // Try to open the file + // + // if ((mOptions.OutFptr = fopen (Argv[1], "wb")) == NULL) { + // Error (NULL, 0, 0, Argv[1], "failed to open output file for writing"); + // return STATUS_ERROR; + // } + // + strcpy (mOptions.OutputFileName, Argv[1]); + } else { + Error (NULL, 0, 0, Argv[0], "missing output filename with option"); + Usage (); + + if (NewFile != NULL) { + free (NewFile); + } + if (NewSize != NULL) { + free (NewSize); + } + + return STATUS_ERROR; + } + + Argc--; + Argv++; + } else if (stricmp (Argv[0], "-j") == 0) { + mOptions.JoinMode = TRUE; + // + // -split option (multiple allowed) + // + } else if (stricmp (Argv[0], "-split") == 0) { + if (Argc > 1) { + NewSize = (SIZE_LIST *) malloc (sizeof (SIZE_LIST)); + if (NewSize == NULL) { + Error (NULL, 0, 0, "memory allocation failure", NULL); + + if (NewFile != NULL) { + free (NewFile); + } + if (NewSize != NULL) { + free (NewSize); + } + + return STATUS_ERROR; + } + + memset (NewSize, 0, sizeof (SIZE_LIST)); + // + // Get the size from the next arg, and then add this size + // to our size list + // + if (!GetNumber (Argv[1], &NewSize->Size)) { + Error (NULL, 0, 0, Argv[1], "invalid split size argument"); + + if (NewFile != NULL) { + free (NewFile); + } + if (NewSize != NULL) { + free (NewSize); + } + + return STATUS_ERROR; + } + + if (mOptions.SizeList == NULL) { + mOptions.SizeList = NewSize; + mOptions.CurrentSize = NewSize; + } else { + mOptions.LastSize->Next = NewSize; + } + + mOptions.LastSize = NewSize; + free (NewSize); + } else { + Error (NULL, 0, 0, Argv[0], "missing size parameter with option"); + Usage (); + + if (NewFile != NULL) { + free (NewFile); + } + if (NewSize != NULL) { + free (NewSize); + } + + return STATUS_ERROR; + } + + Argc--; + Argv++; + } else if ((stricmp (Argv[0], "-h") == 0) || (strcmp (Argv[0], "-?") == 0)) { + Usage (); + + if (NewFile != NULL) { + free (NewFile); + } + if (NewSize != NULL) { + free (NewSize); + } + + return STATUS_ERROR; + // + // Default minimum header + // + } else if (stricmp (Argv[0], "-dump") == 0) { + mOptions.Dump = TRUE; + } else if (stricmp (Argv[0], "-v") == 0) { + mOptions.Verbose = TRUE; + } else { + Error (NULL, 0, 0, Argv[0], "unrecognized option"); + Usage (); + + if (NewFile != NULL) { + free (NewFile); + } + if (NewSize != NULL) { + free (NewSize); + } + + return STATUS_ERROR; + } + + Argc--; + Argv++; + } + // + // Can't -j join files and -s split output capsule + // + if ((mOptions.SizeList != NULL) && (mOptions.JoinMode)) { + Error (NULL, 0, 0, "cannot specify both -j and -size", NULL); + + if (NewFile != NULL) { + free (NewFile); + } + if (NewSize != NULL) { + free (NewSize); + } + + return STATUS_ERROR; + } + // + // Must have specified an output file name if not -dump + // + if ((mOptions.Dump == 0) && (mOptions.OutputFileName[0] == 0)) { + Error (NULL, 0, 0, NULL, "-o OutputFileName must be specified"); + Usage (); + + if (NewFile != NULL) { + free (NewFile); + } + if (NewSize != NULL) { + free (NewSize); + } + + return STATUS_ERROR; + } + // + // Rest of arguments are input files. The first one is a firmware + // volume image, and the rest are FFS files that are to be inserted + // into the firmware volume. + // + LastFile = NULL; + while (Argc > 0) { + NewFile = (FILE_LIST *) malloc (sizeof (FILE_LIST)); + if (NewFile == NULL) { + Error (NULL, 0, 0, "memory allocation failure", NULL); + + if (NewFile != NULL) { + free (NewFile); + } + if (NewSize != NULL) { + free (NewSize); + } + + return STATUS_ERROR; + } + + memset ((char *) NewFile, 0, sizeof (FILE_LIST)); + strcpy (NewFile->FileName, Argv[0]); + if (mOptions.FileList == NULL) { + mOptions.FileList = NewFile; + } else { + if (LastFile == NULL) { + LastFile = NewFile; + } else { + LastFile->Next = NewFile; + } + } + + LastFile = NewFile; + Argc--; + Argv++; + } + + // + // Must have provided at least one file name + // + if (mOptions.FileList == NULL) { + Error (NULL, 0, 0, "must specify at least one file name", NULL); + Usage (); + + if (NewFile != NULL) { + free (NewFile); + } + if (NewSize != NULL) { + free (NewSize); + } + + return STATUS_ERROR; + } + + return STATUS_SUCCESS; +} + +static +void +Usage ( + VOID + ) +/*++ + +Routine Description: + + Print usage information for this utility. + +Arguments: + + None. + +Returns: + + Nothing. + +--*/ +{ + int Index; + static const char *Str[] = { + PROGRAM_NAME " -- create a capsule header", + " Usage: "PROGRAM_NAME " {options} [CapsuleFV]", + // + // {FfsFileNames}", + // + " Options include:", + " -h or -? for this help information", + " -script fname to take capsule header info from unicode script", + " file fname", + " -o fname write output to file fname (required)", + " -split size split capsule image into multiple output files", + " -dump to dump a capsule header", + " -v for verbose output\n", + " -j to join split capsule images into a single image", + "", + " CapsuleFV is the name of an existing well-formed Tiano firmware", + " volume file.", + // + // FfsFileNames are the names of one or more Tiano FFS files to", + // " insert into the output capsule image.", + // + NULL + }; + for (Index = 0; Str[Index] != NULL; Index++) { + fprintf (stdout, "%s\n", Str[Index]); + } +} diff --git a/Tools/Source/TianoTools/GenCapsuleHdr/Makefile b/Tools/Source/TianoTools/GenCapsuleHdr/Makefile new file mode 100644 index 0000000000..1979c3d11c --- /dev/null +++ b/Tools/Source/TianoTools/GenCapsuleHdr/Makefile @@ -0,0 +1,75 @@ +#/*++ +# +# Copyright (c) 2002 Intel Corporation. All rights reserved +# This software and associated documentation (if any) is furnished +# under a license and may only be used or copied in accordance +# with the terms of the license. Except as permitted by such +# license, no part of this software or documentation may be +# reproduced, stored in a retrieval system, or transmitted in any +# form or by any means without the express written consent of +# Intel Corporation. +# +# +# Module Name: +# +# Makefile +# +# Abstract: +# +# makefile for the GenCapsuleHdr utility. +# +#--*/ + +# +# Make sure environmental variable EFI_SOURCE is set +# +!IFNDEF EFI_SOURCE +!ERROR EFI_SOURCE environmental variable not set +!ENDIF + +# +# Do this if you want to compile from this directory +# +!IFNDEF TOOLCHAIN +TOOLCHAIN = TOOLCHAIN_MSVC +!ENDIF + +!INCLUDE PlatformTools.env + +# +# Target specific information +# + + +TARGET_NAME = GenCapsuleHdr +TARGET_EXE = $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).exe +SRC = $(TIANO_TOOLS_SOURCE)\$(TARGET_NAME) +ETO = $(TIANO_TOOLS_OUTPUT) + +# +# Build targets +# + +all: $(TARGET_EXE) + +LIBS = $(LIBS) "$(TIANO_TOOLS_OUTPUT)\Common.lib" ole32.lib + +OBJECTS = $(ETO)\$(TARGET_NAME).obj \ + $(ETO)\CreateGuid.obj + +# +# Compile each source file +# +$(ETO)\$(TARGET_NAME).obj : $(SRC)\$(TARGET_NAME).c $(INC_DEPS) + $(CC) $(C_FLAGS) $(SRC)\$(TARGET_NAME).c /Fo$@ + +$(ETO)\CreateGuid.obj : $(SRC)\CreateGuid.c $(INC_DEPS) + $(CC) $(C_FLAGS) $(SRC)\CreateGuid.c /Fo$@ + +# +# Link the object files together +# +$(TARGET_EXE) : $(OBJECTS) + $(LINK) $(MSVS_LINK_LIBPATHS) $(L_FLAGS) $(LIBS) /out:$(TARGET_EXE) $(OBJECTS) + +clean: diff --git a/Tools/Source/TianoTools/GenFdImage/GenFdImage.h b/Tools/Source/TianoTools/GenFdImage/GenFdImage.h new file mode 100644 index 0000000000..68cfa8c5ff --- /dev/null +++ b/Tools/Source/TianoTools/GenFdImage/GenFdImage.h @@ -0,0 +1,89 @@ +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + + +Module Name: + + GenFdImage.h + +Abstract: + + This file contains the relevant declarations required + to generate the Firmware Device + +--*/ + +// +// Coded to EFI 2.0 Coding Standard +// +#ifndef _EFI_GEN_FD_IMAGE_H +#define _EFI_GEN_FD_IMAGE_H + +// +// Included Header files +// +#include +#include +#include +#include +#include +#include "TianoCommon.h" +#include "ParseInf.h" +#include "GenFvImage.h" + +// +// Defines +// +#define FILE_NAME_SIZE 256 + +// +// Type Definition +// +typedef struct { + UINT64 FdSize; + UINT64 FdBaseAddress; + UINT8 PadValue; + CHAR8 OutFileName[FILE_NAME_SIZE]; +} FDINFO; + +// +// Exported Function Prototype +// +EFI_STATUS +GenerateFdImage ( + IN UINT64 BaseAddress, + IN UINT64 Size, + IN UINT8 PadByte, + IN CHAR8 *OutFile, + IN CHAR8 **FileList + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + BaseAddress - GC_TODO: add argument description + Size - GC_TODO: add argument description + PadByte - GC_TODO: add argument description + OutFile - GC_TODO: add argument description + FileList - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +#endif diff --git a/Tools/Source/TianoTools/GenFdImage/GenFdImageDll.c b/Tools/Source/TianoTools/GenFdImage/GenFdImageDll.c new file mode 100644 index 0000000000..c7d9b8b9f1 --- /dev/null +++ b/Tools/Source/TianoTools/GenFdImage/GenFdImageDll.c @@ -0,0 +1,864 @@ +/*++ +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + + + Module Name: + GenFdImageDll.C + + Abstarct: + This file contains the relevant functions required to complete + the API to generate Firmware Device +--*/ + +// GC_TODO: fix comment to add: Abstract: +// +// This tells the compiler to export the DLL functions +// +#define GEN_FD_IMAGE_EXPORTS + +#include +#include +#include +#include +#include +#include "TianoCommon.h" +#include "GenFdImage.h" +#include "GenFvImage.h" +#include "ParseInf.h" + +// +// Global declaration +// +UINTN ValidLineNum = 0; + +UINTN NumFvFiles = 0; +static UINT64 LastAddress = 0; + +CHAR8 **TokenStr; +CHAR8 **OrgStrTokPtr; + +FDINFO *FdInfo; +FDINFO *OrgFdInfoPtr; + +FVINFO **FvInfo; +FVINFO **OrgFvInfoPtr; + +// +// Global function declarations +// +EFI_STATUS +BuildFirmwareDeviceBinaryFromFwVolumes ( + IN UINT64 FvBaseAddress, + IN CHAR8 *FvFileName, + IN CHAR8 *FdFileName + ); + +INTN +CompareItems ( + IN const VOID *Arg1, + IN const VOID *Arg2 + ) +/*++ +Description: + + This function is used by qsort to sort the Fv list based on FvBaseAddress + +Input: + Arg1 + Arg2 + +Return: + + None +--*/ +// GC_TODO: function comment is missing 'Routine Description:' +// GC_TODO: function comment is missing 'Arguments:' +// GC_TODO: function comment is missing 'Returns:' +// GC_TODO: Arg1 - add argument and description to function comment +// GC_TODO: Arg2 - add argument and description to function comment +{ + if ((*(FVINFO **) Arg1)->FvBaseAddress > (*(FVINFO **) Arg2)->FvBaseAddress) { + return 1; + } else if ((*(FVINFO **) Arg1)->FvBaseAddress < (*(FVINFO **) Arg2)->FvBaseAddress) { + return -1; + } else { + return 0; + } +} + +VOID +BuildTokenList ( + IN CHAR8 *Token + ) +/*++ +Description: + + This function builds the token list in an array which will be parsed later + +Input: + Token String, + +Return: + + None +--*/ +// GC_TODO: function comment is missing 'Routine Description:' +// GC_TODO: function comment is missing 'Arguments:' +// GC_TODO: function comment is missing 'Returns:' +// GC_TODO: Token - add argument and description to function comment +{ + + strcpy (*TokenStr, Token); + TokenStr++; +} + +VOID +TrimLine ( + IN CHAR8 *Line + ) +/*++ +Description: + + This function cleans up the line by removing all whitespace and + comments + +Input: + + Line String, + +Return: + None +--*/ +// GC_TODO: function comment is missing 'Routine Description:' +// GC_TODO: function comment is missing 'Arguments:' +// GC_TODO: function comment is missing 'Returns:' +// GC_TODO: Line - add argument and description to function comment +{ + CHAR8 TmpLine[FILE_NAME_SIZE]; + CHAR8 c; + CHAR8 *Ptr0; + UINTN i; + UINTN j; + + // + // Change '#' to '//' for Comment style + // + // if((Ptr0=strchr(Line, '#')) != NULL) { + // + if ((Ptr0 = strstr (Line, "//")) != NULL) { + Line[Ptr0 - Line] = 0; + } + + i = j = 0; + + while ((c = Line[i]) != 0) { + if ((c != ' ') && (c != '\t') && (c != '\n')) { + TmpLine[j++] = c; + } + + i++; + } + + TmpLine[j] = 0; + strcpy (Line, TmpLine); +} + +VOID +ValidLineCount ( + IN FILE *Fp + ) +/*++ + +Description: + + This function calculated number of valid lines in a input file. + +Input: + + Fp Pointer to a file handle which has been opened. + +Return: + + None +--*/ +// GC_TODO: function comment is missing 'Routine Description:' +// GC_TODO: function comment is missing 'Arguments:' +// GC_TODO: function comment is missing 'Returns:' +// GC_TODO: Fp - add argument and description to function comment +{ + CHAR8 Buff[FILE_NAME_SIZE]; + + while (fgets (Buff, sizeof (Buff), Fp)) { + TrimLine (Buff); + if (Buff[0] == 0) { + continue; + } + + ValidLineNum++; + } +} + +VOID +ParseInputFile ( + IN FILE *Fp + ) +/*++ + +Description: + + This function parses the input file and tokenize the string + +Input: + + Fp Pointer to a file handle which has been opened. + +Return: + + None +--*/ +// GC_TODO: function comment is missing 'Routine Description:' +// GC_TODO: function comment is missing 'Arguments:' +// GC_TODO: function comment is missing 'Returns:' +// GC_TODO: Fp - add argument and description to function comment +{ + CHAR8 *Token; + CHAR8 Buff[FILE_NAME_SIZE]; + CHAR8 OrgLine[FILE_NAME_SIZE]; + CHAR8 Str[FILE_NAME_SIZE]; + CHAR8 Delimit[] = "="; + + while (fgets (Buff, sizeof (Buff), Fp) != NULL) { + strcpy (OrgLine, Buff); + TrimLine (Buff); + + if (Buff[0] == 0) { + continue; + } + + Token = strtok (Buff, Delimit); + + while (Token != NULL) { + strcpy (Str, Token); + BuildTokenList (Str); + Token = strtok (NULL, Delimit); + } + } +} + +EFI_STATUS +InitializeComps ( + VOID + ) +/*++ + +Description: + + This function intializes the relevant global variable which is being + used to store the information retrieved from INF file. + +Input: + + None + +Return: + + EFI_STATUS +--*/ +// GC_TODO: function comment is missing 'Routine Description:' +// GC_TODO: function comment is missing 'Arguments:' +// GC_TODO: function comment is missing 'Returns:' +// GC_TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// GC_TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// GC_TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// GC_TODO: EFI_SUCCESS - add return value to function comment +{ + UINTN Index; + + FdInfo = malloc (sizeof (FDINFO)); + + if (FdInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + OrgFdInfoPtr = FdInfo; + + FvInfo = malloc (sizeof (int) * NumFvFiles); + + if (FvInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + OrgFvInfoPtr = FvInfo; + + for (Index = 0; Index < NumFvFiles; Index++) { + *FvInfo = malloc (sizeof (FVINFO)); + + if (*FvInfo == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + memset (*FvInfo, 0, sizeof (FVINFO)); + FvInfo++; + } + + FvInfo = OrgFvInfoPtr; + + return EFI_SUCCESS; +} + +VOID +InitializeInFileInfo ( + VOID + ) +/*++ + +Description: + + This function intializes the relevant global variable which is being + used to store the information retrieved from INF file. + +Input: + + NONE + +Return: + + NONE +--*/ +// GC_TODO: function comment is missing 'Routine Description:' +// GC_TODO: function comment is missing 'Arguments:' +// GC_TODO: function comment is missing 'Returns:' +{ + UINTN OptionFlag; + UINT64 StringValue; + + OptionFlag = 0; + TokenStr = OrgStrTokPtr; + + while (*TokenStr != NULL) { + if (stricmp (*TokenStr, "[options]") == 0) { + OptionFlag = 1; + } + + if (OptionFlag) { + if (stricmp (*TokenStr, "EFI_FV_BASE_ADDRESS") == 0) { + *TokenStr++; + if (AsciiStringToUint64 (*TokenStr, FALSE, &StringValue) != EFI_SUCCESS) { + printf ("\nERROR: Cannot determine the FV base address."); + return ; + } + (*FvInfo)->FvBaseAddress = StringValue; + } else if (stricmp (*TokenStr, "EFI_FV_FILE_NAME") == 0) { + *TokenStr++; + strcpy ((*FvInfo)->FvFile, *TokenStr); + } + } + + TokenStr++; + } +} + +EFI_STATUS +GetFvRelatedInfoFromInfFile ( + IN CHAR8 *FileName + ) +/*++ + +Description: + + This function reads the input file, parse it and create a list of tokens + which is parsed and used, to intialize the data related to Firmware Volume. + +Input: + + FileName FileName which needed to be read to parse data + +Return: + + EFI_STATUS + +--*/ +// GC_TODO: function comment is missing 'Routine Description:' +// GC_TODO: function comment is missing 'Arguments:' +// GC_TODO: function comment is missing 'Returns:' +// GC_TODO: FileName - add argument and description to function comment +// GC_TODO: EFI_ABORTED - add return value to function comment +// GC_TODO: EFI_ABORTED - add return value to function comment +// GC_TODO: EFI_SUCCESS - add return value to function comment +{ + FILE *Fp; + UINTN Index; + + Fp = fopen (FileName, "r"); + + if (Fp == NULL) { + printf ("Error in opening %s file\n", FileName); + return EFI_ABORTED; + } + + ValidLineCount (Fp); + + if (ValidLineNum == 0) { + printf ("\nFile doesn't contain any valid informations"); + return EFI_ABORTED; + } + + TokenStr = (CHAR8 **) malloc (sizeof (UINTN) * (2 * ValidLineNum)); + memset (TokenStr, 0, sizeof (UINTN) * (2 * ValidLineNum)); + OrgStrTokPtr = TokenStr; + + for (Index = 0; Index < (2 * ValidLineNum); Index++) { + *TokenStr = (CHAR8 *) malloc (sizeof (CHAR8) * FILE_NAME_SIZE); + memset (*TokenStr, 0, FILE_NAME_SIZE); + TokenStr++; + } + + *TokenStr = NULL; + TokenStr = OrgStrTokPtr; + fseek (Fp, 0L, SEEK_SET); + + ParseInputFile (Fp); + InitializeInFileInfo (); + + if (Fp) { + fclose (Fp); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +WriteFwBinary ( + IN CHAR8 *FileName, + IN UINT64 StartAddress, + IN UINT64 Size, + IN UINT8 *Buffer + ) +/*++ + +Description: + + This function reads the input file, parse it and create a list of tokens + which is parsed and used, to intialize the data related to Firmware Volume. + +Input: + + FileName FileName which needed to be read to parse data + StartAddress This will set the file position. + Size Size in bytes needed to be written + Buffer Buffer needed to e written + +Return: + + EFI_STATUS + +--*/ +// GC_TODO: function comment is missing 'Routine Description:' +// GC_TODO: function comment is missing 'Arguments:' +// GC_TODO: function comment is missing 'Returns:' +// GC_TODO: FileName - add argument and description to function comment +// GC_TODO: StartAddress - add argument and description to function comment +// GC_TODO: Size - add argument and description to function comment +// GC_TODO: Buffer - add argument and description to function comment +// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment +// GC_TODO: EFI_ABORTED - add return value to function comment +// GC_TODO: EFI_SUCCESS - add return value to function comment +{ + FILE *Fp; + UINTN NumByte; + + Fp = fopen (FileName, "a+b"); + + if (Fp == NULL) { + printf ("\nERROR:Error in opening file %s ", FileName); + return EFI_INVALID_PARAMETER; + } + + fseek (Fp, (UINTN) StartAddress, SEEK_SET); + NumByte = fwrite ((VOID *) Buffer, sizeof (UINT8), (UINTN) Size, Fp); + + // + // Check to ensure that buffer has been copied successfully + // + if (NumByte != Size) { + printf ("\nERROR: Error in copying the buffer into file"); + return EFI_ABORTED; + } + + if (Fp) { + fclose (Fp); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +BuildFirmwareDeviceBinaryFromFwVolumes ( + IN UINT64 FvBaseAddress, + IN CHAR8 *FvFileName, + IN CHAR8 *FdFileName + ) +/*++ + +Description: + + This function reads the input file, parse it and create a list of tokens + which is parsed and used, to intialize the data related to Firmware Volume. + +Input: + + FvBaseAddress Base Address. This info is retrieved from INF file + FvFileName InputFileName + FdFileName Output File Name + +Return: + + EFI_STATUS + +--*/ +// GC_TODO: function comment is missing 'Routine Description:' +// GC_TODO: function comment is missing 'Arguments:' +// GC_TODO: function comment is missing 'Returns:' +// GC_TODO: FvBaseAddress - add argument and description to function comment +// GC_TODO: FvFileName - add argument and description to function comment +// GC_TODO: FdFileName - add argument and description to function comment +// GC_TODO: EFI_ABORTED - add return value to function comment +// GC_TODO: EFI_ABORTED - add return value to function comment +// GC_TODO: EFI_ABORTED - add return value to function comment +// GC_TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// GC_TODO: EFI_SUCCESS - add return value to function comment +{ + FILE *Fp; + UINT64 FileSize; + UINT64 NumByteRead; + UINT64 PadByteSize; + UINTN Index; + UINT64 BaseAddress; + UINT8 *Buffer; + EFI_STATUS Status; + static UINT64 StartAddress = 0; + + Fp = fopen (FvFileName, "r+b"); + + if (Fp == NULL) { + printf ("\nERROR:Error in opening file %s", FvFileName); + return EFI_ABORTED; + } + + BaseAddress = FdInfo->FdBaseAddress; + + // + // Check if Base Address of Firmware Volume falls below the Base Address + // Firmware Device, if yes, then abort this process. + // + if (FvBaseAddress < BaseAddress) { + printf ("\nERROR: Firmware Volume Base Address falls below Firmware Device Address.\n"); + return EFI_ABORTED; + } + // + // Check if there are any hole between two Firmware Volumes. If any hole + // exists, fill the hole with PadByte data. + // + if (FvBaseAddress > LastAddress) { + PadByteSize = (FvBaseAddress - LastAddress); + Buffer = malloc ((UINTN) PadByteSize); + + for (Index = 0; Index < PadByteSize; Index++) { + *Buffer = FdInfo->PadValue; + Buffer++; + } + + Buffer -= PadByteSize; + Status = WriteFwBinary (FdFileName, StartAddress, (UINT64) PadByteSize, Buffer); + + if (Buffer) { + free (Buffer); + } + + if (Status != EFI_SUCCESS) { + printf ("\nERROR: Error in writing the binary image to file"); + return Status; + } + + StartAddress += PadByteSize; + LastAddress += PadByteSize; + } + // + // Proceed with next Firmware Volume updates + // + FileSize = _filelength (fileno (Fp)); + + if ((FvBaseAddress + FileSize) > (FdInfo->FdBaseAddress + FdInfo->FdSize)) { + printf ( + "\nERROR:Unable to update Firmware Device. File %s is larger than \ + available space.", + FvFileName + ); + if (Fp) { + fclose (Fp); + } + + return EFI_ABORTED; + } + + Buffer = malloc ((UINTN) FileSize); + + if (Buffer == NULL) { + printf ("Error in allocating buffer to read specific file\n"); + return EFI_OUT_OF_RESOURCES; + } + + NumByteRead = fread ((VOID *) Buffer, sizeof (UINT8), (UINTN) FileSize, Fp); + + Status = WriteFwBinary (FdFileName, StartAddress, FileSize, Buffer); + + if (Buffer) { + free ((VOID *) Buffer); + } + + if (Fp) { + fclose (Fp); + } + + if (Status != EFI_SUCCESS) { + printf ("\nERROR: Error in writing the binary image to file"); + return Status; + } + + StartAddress += NumByteRead; + LastAddress += FileSize; + + return EFI_SUCCESS; +} + +VOID +CleanUpMemory ( + VOID + ) +/*++ + +Description: + + This function cleans up any allocated buffer + +Input: + + NONE + +Return: + + NONE +--*/ +// GC_TODO: function comment is missing 'Routine Description:' +// GC_TODO: function comment is missing 'Arguments:' +// GC_TODO: function comment is missing 'Returns:' +{ + UINTN Index; + + if (FdInfo) { + free (FdInfo); + } + + FvInfo = OrgFvInfoPtr; + + if (FvInfo) { + for (Index = 0; Index < NumFvFiles; Index++) { + if (*FvInfo) { + free (*FvInfo); + } + + FvInfo++; + } + + FvInfo = OrgFvInfoPtr; + free (FvInfo); + } +} + +GEN_FD_IMAGE_API +EFI_STATUS +GenerateFdImage ( + IN UINT64 BaseAddress, + IN UINT64 Size, + IN UINT8 PadByte, + IN CHAR8 *OutFile, + IN CHAR8 **FileList + ) +/*++ + +Description: + + This function reads the input file, parse it and create a list of tokens + which is parsed and used, to intialize the data related to Firmware Volume. + +Input: + + BaseAddress Base Address for this Firmware Device + Size, Total Size of the Firmware Device + PadByte Pad byte data + OutFile Output File Name + FileList File List pointer to INF file names. + +Return: + + EFI_STATUS + +--*/ +// GC_TODO: function comment is missing 'Routine Description:' +// GC_TODO: function comment is missing 'Arguments:' +// GC_TODO: function comment is missing 'Returns:' +// GC_TODO: BaseAddress - add argument and description to function comment +// GC_TODO: Size - add argument and description to function comment +// GC_TODO: PadByte - add argument and description to function comment +// GC_TODO: OutFile - add argument and description to function comment +// GC_TODO: FileList - add argument and description to function comment +// GC_TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// GC_TODO: EFI_ABORTED - add return value to function comment +// GC_TODO: EFI_ABORTED - add return value to function comment +// GC_TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + UINTN Index; + UINTN PadSize; + UINTN FileSize; + CHAR8 **InFile; + FILE *Fp; + UINT8 *Buffer; + UINTN NumByte; + + // + // Ensure, if there are any previous Firmware Device exists, + // If yes, make it to 0 bytes + // + if ((Fp = fopen (OutFile, "w")) != NULL) { + fclose (Fp); + } + + InFile = FileList; + + while (*InFile != NULL) { + NumFvFiles++; + InFile++; + } + + InitializeComps (); + + // + // Restore the orginal pointers + // + FvInfo = OrgFvInfoPtr; + InFile = FileList; + + while (*InFile != NULL) { + strcpy ((*FvInfo)->FvInfoFile, *InFile); + Status = GetFvRelatedInfoFromInfFile (*InFile); + + if (Status != EFI_SUCCESS) { + printf ("\nERROR: Error occurred in processsing INF file"); + CleanUpMemory (); + return Status; + } + + InFile++; + FvInfo++; + } + + FdInfo->FdSize = Size; + FdInfo->FdBaseAddress = BaseAddress; + FdInfo->PadValue = PadByte; + FvInfo = OrgFvInfoPtr; + strcpy (FdInfo->OutFileName, OutFile); + + for (Index = 0; Index < NumFvFiles; Index++) { + Status = GenerateFvImage ((*FvInfo)->FvInfoFile); + + if (Status != EFI_SUCCESS) { + CleanUpMemory (); + return Status; + } + + FvInfo++; + } + + FvInfo = OrgFvInfoPtr; + + // + // Sort the Firmware Volume informations. Firmware Volume with lower + // base addresses will be processed first and hiher base address one + // will be processed later. + // + qsort ((VOID *) FvInfo, NumFvFiles, sizeof (FVINFO *), CompareItems); + + LastAddress = (*FvInfo)->FvBaseAddress; + + for (Index = 0; Index < NumFvFiles; Index++) { + Status = BuildFirmwareDeviceBinaryFromFwVolumes ( + (*FvInfo)->FvBaseAddress, + (*FvInfo)->FvFile, + FdInfo->OutFileName + ); + if (Status != EFI_SUCCESS) { + CleanUpMemory (); + return Status; + } + + FvInfo++; + } + // + // Check if any space left after copying data from all Firmware Volumes + // If yes, then fill those location with PadValue. + // + if ((FdInfo->FdBaseAddress + Size) > LastAddress) { + + PadSize = (UINTN) ((FdInfo->FdBaseAddress + FdInfo->FdSize) - LastAddress); + Buffer = malloc (PadSize); + + if (Buffer == NULL) { + CleanUpMemory (); + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 0; Index < PadSize; Index++) { + *Buffer = FdInfo->PadValue; + Buffer++; + } + + Buffer -= PadSize; + + Fp = fopen (OutFile, "a+b"); + + if (Fp == NULL) { + printf ("\nERROR:Opening file %s", OutFile); + CleanUpMemory (); + return EFI_ABORTED; + } + + FileSize = _filelength (fileno (Fp)); + fseek (Fp, FileSize, SEEK_SET); + NumByte = fwrite (Buffer, sizeof (UINT8), PadSize, Fp); + + if (Buffer) { + free (Buffer); + } + + fclose (Fp); + + if (NumByte != (sizeof (UINT8) * PadSize)) { + printf ("\nERROR: Copying data from buffer to File %s ", OutFile); + CleanUpMemory (); + return EFI_ABORTED; + } + } + // + // Clean up all the memory which has been allocated so far. + // + CleanUpMemory (); + return EFI_SUCCESS; +} diff --git a/Tools/Source/TianoTools/GenFdImage/GenFdImageExe.c b/Tools/Source/TianoTools/GenFdImage/GenFdImageExe.c new file mode 100644 index 0000000000..9c56d061bc --- /dev/null +++ b/Tools/Source/TianoTools/GenFdImage/GenFdImageExe.c @@ -0,0 +1,330 @@ +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + + +Module Name: + + GenFdImageExe.c + +Abstract: + + This contains all code necessary to build the GenFdImage.exe utility. + This utility relies heavily on the GenFdImage Lib. Definitions for both + can be found in the GenFdImage Utility Specification, review draft. + +--*/ + +// +// Coded to EFI 2.0 Coding Standards +// +// +// Include files +// +#include "GenFdImage.h" +#include "GenFdImageExe.h" + +VOID +PrintUtilityInfo ( + VOID + ) +/*++ + +Routine Description: + + Displays the standard utility information to SDTOUT + +Arguments: + + None + +Returns: + + None + +--*/ +{ + printf ( + "%s, EFI 2.0 Firmware Device Image Generation Utility. ""Version %i.%i, %s.\n\n", + UTILITY_NAME, + UTILITY_MAJOR_VERSION, + UTILITY_MINOR_VERSION, + UTILITY_DATE + ); +} + +VOID +PrintUsage ( + VOID + ) +/*++ + +Routine Description: + + Displays the utility usage syntax to STDOUT + +Arguments: + + None + +Returns: + + None + +--*/ +{ + printf ( + "Usage: %s -B BaseAddress -S Size -F FillByte"" [-I FvInfFileName] -O OutputFileName \n", + UTILITY_NAME + ); + printf (" Where:\n"); + printf ("\tBaseAddress is the starting address of the FD Image\n\n"); + printf ("\tSize is the size of the FD Image.\n\n"); + printf ("\tFillByte is the desired value of free space in the Image\n\n"); + printf ("\tFvInfFileName is the name of an FV Image description file.\n\n"); + printf ("\tOutputFileName is the desired output file name.\n\n"); +} + +EFI_STATUS +main ( + IN INTN argc, + IN CHAR8 **argv + ) +/*++ + +Routine Description: + + This utility uses GenFdImage.lib to build a Firmware Device Image + which will include several Firmware Volume Images. + +Arguments: + + Base Address Base Address of the firmware volume.. + Size Size of the Firmware Volume + FillByte The byte value which would be needed to pad + between various Firmware Volumes + FvInfFile Fv inf file + OutputFileName The name of output file which would be created + +Returns: + + EFI_SUCCESS No error conditions detected. + EFI_INVALID_PARAMETER One or more of the input parameters is invalid. + EFI_OUT_OF_RESOURCES A resource required by the utility was unavailable. + Most commonly this will be memory allocation or + file creation. + EFI_LOAD_ERROR GenFvImage.lib could not be loaded. + EFI_ABORTED Error executing the GenFvImage lib. + +--*/ +// GC_TODO: argc - add argument and description to function comment +// GC_TODO: argv - add argument and description to function comment +{ + UINTN Index; + UINTN FvFilesCount; + + UINT8 i; + + UINT64 StartAddress; + UINT64 Size; + UINT64 FillByteVal; + + CHAR8 **FvInfFileList; + CHAR8 **OrgFvInfFileList; + CHAR8 OutputFileName[_MAX_PATH]; + + EFI_STATUS Status; + + INTN arg_counter; + + // + // Echo for makefile debug + // + printf ("\n\n"); + for (arg_counter = 0; arg_counter < argc; arg_counter++) { + printf ("%s ", argv[arg_counter]); + } + + printf ("\n\n"); + + // + // Display utility information + // + PrintUtilityInfo (); + + // + // Verify the correct number of arguments + // + if (argc < MIN_ARGS) { + printf ("ERROR: missing 1 or more input arguments.\n\n"); + PrintUsage (); + return EFI_INVALID_PARAMETER; + } + // + // Initialize variables + // + StartAddress = 0; + Size = 0; + FillByteVal = 0; + FvFilesCount = 0; + + for (i = 1; i < argc; i++) { + if (stricmp (argv[i], "-I") == 0) { + FvFilesCount++; + } + } + + FvInfFileList = malloc (sizeof (UINTN) * (FvFilesCount + 1)); + if (FvInfFileList == NULL) { + printf ("ERROR: allocating memory for FvInfFileList in -main- function.\n"); + return EFI_OUT_OF_RESOURCES; + } + + memset (FvInfFileList, 0, sizeof (UINTN) * (FvFilesCount + 1)); + + OrgFvInfFileList = FvInfFileList; + + for (Index = 0; Index < FvFilesCount; Index++) { + *FvInfFileList = malloc (_MAX_PATH); + memset (*FvInfFileList, 0, _MAX_PATH); + FvInfFileList++; + } + + strcpy (OutputFileName, ""); + + // + // Parse the command line arguments + // + FvInfFileList = OrgFvInfFileList; + + for (i = 1; i < argc; i += 2) { + // + // Make sure argument pair begin with - or / + // + if (argv[i][0] != '-' && argv[i][0] != '/') { + PrintUsage (); + printf ("ERROR: Argument pair must begin with \"-\" or \"/\"\n"); + return EFI_INVALID_PARAMETER; + } + // + // Make sure argument specifier is only one letter + // + if (argv[i][2] != 0) { + PrintUsage (); + printf ("ERROR: Unrecognized argument \"%s\".\n", argv[i]); + return EFI_INVALID_PARAMETER; + } + // + // Determine argument to read + // + switch (argv[i][1]) { + + case 'I': + case 'i': + if ((FvInfFileList != NULL) && (strlen (*FvInfFileList) == 0)) { + strcpy (*FvInfFileList, argv[i + 1]); + FvInfFileList++; + } else { + printf ("ERROR: FvInfFile Name is more than specifed.\n"); + return EFI_INVALID_PARAMETER; + } + break; + + case 'O': + case 'o': + if (strlen (OutputFileName) == 0) { + strcpy (OutputFileName, argv[i + 1]); + } else { + PrintUsage (); + printf ("ERROR: OutputFileName may only be specified once.\n"); + return EFI_INVALID_PARAMETER; + } + break; + + case 'B': + case 'b': + Status = AsciiStringToUint64 (argv[i + 1], FALSE, &StartAddress); + if (Status != EFI_SUCCESS) { + printf ("\nERROR: Bad FD Image start address specified"); + return EFI_INVALID_PARAMETER; + } + break; + + case 'S': + case 's': + Status = AsciiStringToUint64 (argv[i + 1], FALSE, &Size); + if (Status != EFI_SUCCESS) { + printf ("\nERROR: Bad FD Image size specified"); + return EFI_INVALID_PARAMETER; + } + break; + + case 'F': + case 'f': + Status = AsciiStringToUint64 (argv[i + 1], FALSE, &FillByteVal); + if (Status != EFI_SUCCESS) { + printf ("\nERROR: Not a recognized Fill Byte value"); + return EFI_INVALID_PARAMETER; + } + break; + + default: + PrintUsage (); + printf ("ERROR: Unrecognized argument \"%s\".\n", argv[i]); + return EFI_INVALID_PARAMETER; + break; + } + } + // + // Call the GenFdImage Lib + // + FvInfFileList = OrgFvInfFileList; + + Status = GenerateFdImage ( + StartAddress, + Size, + (UINT8) FillByteVal, + OutputFileName, + FvInfFileList + ); + + if (EFI_ERROR (Status)) { + switch (Status) { + + case EFI_INVALID_PARAMETER: + printf ("\nERROR: Invalid parameter passed to GenFdImage lib.\n"); + break; + + case EFI_ABORTED: + printf ("\nERROR: Error detected while creating the file image.\n"); + break; + + case EFI_OUT_OF_RESOURCES: + printf ("\nERROR: GenFdImage Lib could not allocate required resources.\n"); + break; + + case EFI_VOLUME_CORRUPTED: + printf ("\nERROR: No base address was specified \n"); + break; + + case EFI_LOAD_ERROR: + printf ("\nERROR: An error occurred loading one of the required support Lib.\n"); + break; + + default: + printf ("\nERROR: GenFdImage lib returned unknown status %X.\n", Status); + break; + } + + return Status; + } + + return EFI_SUCCESS; +} diff --git a/Tools/Source/TianoTools/GenFdImage/GenFdImageExe.h b/Tools/Source/TianoTools/GenFdImage/GenFdImageExe.h new file mode 100644 index 0000000000..e07cb237c2 --- /dev/null +++ b/Tools/Source/TianoTools/GenFdImage/GenFdImageExe.h @@ -0,0 +1,91 @@ +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + + +Module Name: + + GenFdImageExe.h + +Abstract: + + Definitions for the Boot Strap File Image generation utility. + +--*/ + +#ifndef _EFI_GEN_FD_IMAGE_EXE_H +#define _EFI_GEN_FD_IMAGE_EXE_H + +// +// Utility Name +// +#define UTILITY_NAME "GenFdImage" + +// +// Utility version information +// +#define UTILITY_MAJOR_VERSION 0 +#define UTILITY_MINOR_VERSION 0 +#define UTILITY_DATE __DATE__ + +// +// The maximum number of arguments accepted from the command line. +// +#define MIN_ARGS 10 + +// +// The function that displays general utility information +// +VOID +PrintUtilityInfo ( + VOID + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + None + +Returns: + + GC_TODO: add return values + +--*/ +; + +// +// The function that displays the utility usage message. +// +VOID +PrintUsage ( + VOID + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + None + +Returns: + + GC_TODO: add return values + +--*/ +; + +#endif diff --git a/Tools/Source/TianoTools/GenFdImage/GenFdImageLib.c b/Tools/Source/TianoTools/GenFdImage/GenFdImageLib.c new file mode 100644 index 0000000000..39698d9abe --- /dev/null +++ b/Tools/Source/TianoTools/GenFdImage/GenFdImageLib.c @@ -0,0 +1,848 @@ +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + + +Module Name: + + GenFdImageLib.C + +Abstract: + + This file contains the functions required to generate + the Firmware Device + +--*/ + +// +// Coded to EFI 2.0 Coding Standards +// +// +// Include file in build +// +#include "GenFdImage.h" + +// +// Global declarations +// +UINTN ValidLineNum = 0; +UINTN NumFvFiles = 0; + +static UINT64 LastAddress = 0; + +CHAR8 **TokenStr; +CHAR8 **OrgStrTokPtr; + +FDINFO *FdInfo; +FDINFO *OrgFdInfoPtr; + +FVINFO **FvInfo; +FVINFO **OrgFvInfoPtr; + +// +// Internal Functions +// +INTN +CompareItems ( + IN const VOID *Arg1, + IN const VOID *Arg2 + ) +/*++ + +Routine Description: + + This function is used by qsort to sort the Fv list based on FvBaseAddress + +Arguments: + + Arg1 + Arg2 + +Returns: + + None + +--*/ +// GC_TODO: Arg1 - add argument and description to function comment +// GC_TODO: Arg2 - add argument and description to function comment +{ + if ((*(FVINFO **) Arg1)->FvBaseAddress > (*(FVINFO **) Arg2)->FvBaseAddress) { + return 1; + } else if ((*(FVINFO **) Arg1)->FvBaseAddress < (*(FVINFO **) Arg2)->FvBaseAddress) { + return -1; + } else { + return 0; + } +} + +VOID +BuildTokenList ( + IN CHAR8 *Token + ) +/*++ + +Routine Description: + + This function builds the token list in an array which will be parsed later + +Arguments: + + Token String, + +Returns: + + None + +--*/ +{ + strcpy (*TokenStr, Token); + TokenStr++; +} + +VOID +TrimLine ( + IN CHAR8 *Line + ) +/*++ + +Routine Description: + + This function cleans up the line by removing all whitespace and + comments. + +Arguments: + + Line String, + +Returns: + + None + +--*/ +{ + CHAR8 TmpLine[FILE_NAME_SIZE]; + CHAR8 c; + CHAR8 *Ptr0; + + UINTN i; + UINTN j; + + // + // Change '#' to '//' for Comment style + // + // if((Ptr0=strchr(Line, '#')) != NULL) { + // + if ((Ptr0 = strstr (Line, "//")) != NULL) { + Line[Ptr0 - Line] = 0; + } + + i = 0; + j = 0; + while ((c = Line[i]) != 0) { + if ((c != ' ') && (c != '\t') && (c != '\n')) { + TmpLine[j++] = c; + } + + i++; + } + + TmpLine[j] = 0; + strcpy (Line, TmpLine); +} + +VOID +ValidLineCount ( + IN FILE *Fp + ) +/*++ + +Routine Description: + + This function calculates number of valid lines in a input file. + +Arguments: + + Fp Pointer to a file handle which has been opened. + +Returns: + + None + +--*/ +{ + CHAR8 Buff[FILE_NAME_SIZE]; + + while (fgets (Buff, sizeof (Buff), Fp)) { + TrimLine (Buff); + if (Buff[0] == 0) { + continue; + } + + ValidLineNum++; + } +} + +VOID +ParseInputFile ( + IN FILE *Fp + ) +/*++ + +Routine Description: + + This function parses the input file and tokenizes the string + +Arguments: + + Fp Pointer to a file handle which has been opened. + +Returns: + + None + +--*/ +{ + CHAR8 *Token; + CHAR8 Buff[FILE_NAME_SIZE]; + CHAR8 OrgLine[FILE_NAME_SIZE]; + CHAR8 Str[FILE_NAME_SIZE]; + CHAR8 Delimit[] = "="; + + while (fgets (Buff, sizeof (Buff), Fp) != NULL) { + strcpy (OrgLine, Buff); + TrimLine (Buff); + + if (Buff[0] == 0) { + continue; + } + + Token = strtok (Buff, Delimit); + + while (Token != NULL) { + strcpy (Str, Token); + BuildTokenList (Str); + Token = strtok (NULL, Delimit); + } + } +} + +EFI_STATUS +InitializeComps ( + VOID + ) +/*++ + +Routine Description: + + This function intializes the relevant global variable + used to store the information retrieved from the INF file. + +Arguments: + + None + +Returns: + + EFI_STATUS + +--*/ +// GC_TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// GC_TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// GC_TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// GC_TODO: EFI_SUCCESS - add return value to function comment +{ + UINTN Index; + + FdInfo = malloc (sizeof (FDINFO)); + + if (FdInfo == NULL) { + printf ("ERROR: allocating memory (struct FDINFO) in"" function InitializeComps.\n"); + return EFI_OUT_OF_RESOURCES; + } + + OrgFdInfoPtr = FdInfo; + + FvInfo = malloc (sizeof (INTN) * NumFvFiles); + + if (FvInfo == NULL) { + printf ("ERROR: allocating memory (INTN * NumFvFiles) in"" function InitializeComps.\n"); + return EFI_OUT_OF_RESOURCES; + } + + OrgFvInfoPtr = FvInfo; + + for (Index = 0; Index < NumFvFiles; Index++) { + *FvInfo = malloc (sizeof (FVINFO)); + + if (*FvInfo == NULL) { + printf ("ERROR: allocating memory (FVINFO) in"" function InitializeComps.\n"); + return EFI_OUT_OF_RESOURCES; + } + + memset (*FvInfo, 0, sizeof (FVINFO)); + FvInfo++; + } + + FvInfo = OrgFvInfoPtr; + + return EFI_SUCCESS; +} + +VOID +InitializeInFileInfo ( + VOID + ) +/*++ + +Routine Description: + + This function intializes the relevant global variable + used to store the information retrieved from the INF file. + +Arguments: + + None + +Returns: + + None + +--*/ +{ + UINTN OptionFlag; + + UINT64 StringValue; + + OptionFlag = 0; + TokenStr = OrgStrTokPtr; + + while (*TokenStr != NULL) { + if (stricmp (*TokenStr, "[options]") == 0) { + OptionFlag = 1; + } + + if (OptionFlag) { + if (stricmp (*TokenStr, "EFI_FV_BASE_ADDRESS") == 0) { + *TokenStr++; + if (AsciiStringToUint64 ( + *TokenStr, + FALSE, + &StringValue + ) != EFI_SUCCESS) { + printf ("\nERROR: Cannot determine the FV base address."); + return ; + } + (*FvInfo)->FvBaseAddress = StringValue; + } else if (stricmp (*TokenStr, "EFI_FV_FILE_NAME") == 0) { + *TokenStr++; + strcpy ((*FvInfo)->FvFile, *TokenStr); + } + } + + TokenStr++; + } +} + +EFI_STATUS +GetFvRelatedInfoFromInfFile ( + IN CHAR8 *FileName + ) +/*++ + +Routine Description: + + This function reads the input file, parses it and create a list of tokens + which are parsed and used, to intialize the data related to the Firmware + Volume. + +Arguments: + + FileName FileName which needed to be read to parse data + +Returns: + + EFI_STATUS + +--*/ +// GC_TODO: EFI_ABORTED - add return value to function comment +// GC_TODO: EFI_ABORTED - add return value to function comment +// GC_TODO: EFI_SUCCESS - add return value to function comment +{ + FILE *Fp; + + UINTN Index; + + Fp = fopen (FileName, "r"); + + if (Fp == NULL) { + printf ("Error in opening %s file\n", FileName); + return EFI_ABORTED; + } + + ValidLineCount (Fp); + + if (ValidLineNum == 0) { + printf ("\nFile doesn't contain any valid informations"); + return EFI_ABORTED; + } + + TokenStr = (CHAR8 **) malloc (sizeof (UINTN) * (2 * ValidLineNum)); + memset (TokenStr, 0, sizeof (UINTN) * (2 * ValidLineNum)); + OrgStrTokPtr = TokenStr; + + for (Index = 0; Index < (2 * ValidLineNum); Index++) { + *TokenStr = (CHAR8 *) malloc (sizeof (CHAR8) * FILE_NAME_SIZE); + memset (*TokenStr, 0, FILE_NAME_SIZE); + TokenStr++; + } + + *TokenStr = NULL; + TokenStr = OrgStrTokPtr; + fseek (Fp, 0L, SEEK_SET); + + ParseInputFile (Fp); + InitializeInFileInfo (); + + if (Fp) { + fclose (Fp); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +WriteFwBinary ( + IN CHAR8 *FileName, + IN UINT64 StartAddress, + IN UINT64 Size, + IN UINT8 *Buffer + ) +/*++ + +Routine Description: + + This function reads the input file, parses it and creates a list of tokens + which are parsed and used to intialize the data related to the Firmware + Volume. + +Arguments: + + FileName FileName which needed to be read to parse data + StartAddress This will set the file position. + Size Size in bytes needed to be written + Buffer Buffer needed to e written + +Returns: + + EFI_STATUS + +--*/ +// GC_TODO: EFI_INVALID_PARAMETER - add return value to function comment +// GC_TODO: EFI_ABORTED - add return value to function comment +// GC_TODO: EFI_SUCCESS - add return value to function comment +{ + FILE *Fp; + + UINTN NumByte; + + Fp = fopen (FileName, "a+b"); + + if (Fp == NULL) { + printf ("\nERROR:Error in opening file %s ", FileName); + return EFI_INVALID_PARAMETER; + } + + fseek (Fp, (UINTN) StartAddress, SEEK_SET); + NumByte = fwrite ((VOID *) Buffer, sizeof (UINT8), (UINTN) Size, Fp); + + // + // Check to ensure that buffer has been copied successfully + // + if (NumByte != Size) { + printf ("\nERROR: Error in copying the buffer into file"); + return EFI_ABORTED; + } + + if (Fp) { + fclose (Fp); + } + + return EFI_SUCCESS; +} + +EFI_STATUS +BuildFirmwareDeviceBinaryFromFwVolumes ( + IN UINT64 FvBaseAddress, + IN CHAR8 *FvFileName, + IN CHAR8 *FdFileName + ) +/*++ + +Routine Description: + + This function reads the input file, parses it and creates a list of tokens + which are parsed and used to intialize the data related to the Firmware + Volume. + +Arguments: + + FvBaseAddress Base Address. This info is retrieved from INF file + FvFileName InputFileName + FdFileName Output File Name + +Returns: + + EFI_STATUS + +--*/ +// GC_TODO: EFI_ABORTED - add return value to function comment +// GC_TODO: EFI_ABORTED - add return value to function comment +// GC_TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// GC_TODO: EFI_ABORTED - add return value to function comment +// GC_TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// GC_TODO: EFI_SUCCESS - add return value to function comment +{ + FILE *Fp; + + UINT64 FileSize; + UINT64 NumByteRead; + UINT64 PadByteSize; + UINT64 BaseAddress; + + UINTN Index; + + UINT8 *Buffer; + + EFI_STATUS Status; + + static UINT64 StartAddress = 0; + + Fp = fopen (FvFileName, "r+b"); + + if (Fp == NULL) { + printf ("\nERROR:Error in opening file %s", FvFileName); + return EFI_ABORTED; + } + + BaseAddress = FdInfo->FdBaseAddress; + + // + // Check if Base Address of Firmware Volume falls below the Base Address + // Firmware Device, if yes, then abort this process. + // + if (FvBaseAddress < BaseAddress) { + printf ("\nERROR: Firmware Volume Base Address falls below Firmware ""Device Address.\n"); + return EFI_ABORTED; + } + // + // Check if there are any holes between two Firmware Volumes. If any holes + // exist, fill the hole with PadByted data. + // + if (FvBaseAddress > LastAddress) { + PadByteSize = (FvBaseAddress - LastAddress); + Buffer = malloc ((UINTN) PadByteSize); + if (Buffer == NULL) { + printf ("ERROR: allocating (Buffer) memory in"" function BuildFirmwareDeviceBinaryFromFwVolumes.\n"); + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 0; Index < PadByteSize; Index++) { + *Buffer = FdInfo->PadValue; + Buffer++; + } + + Buffer -= PadByteSize; + Status = WriteFwBinary ( + FdFileName, + StartAddress, + (UINT64) PadByteSize, + Buffer + ); + + if (Buffer) { + free (Buffer); + } + + if (Status != EFI_SUCCESS) { + printf ("\nERROR: Error in writing the binary image to file"); + return Status; + } + + StartAddress += PadByteSize; + LastAddress += PadByteSize; + } + // + // Proceed with next Firmware Volume updates + // + FileSize = _filelength (fileno (Fp)); + + if ((FvBaseAddress + FileSize) > (FdInfo->FdBaseAddress + FdInfo->FdSize)) { + printf ( + "\nERROR:Unable to update Firmware Device. File %s is larger than \ + available space.", + FvFileName + ); + if (Fp) { + fclose (Fp); + } + + return EFI_ABORTED; + } + + Buffer = malloc ((UINTN) FileSize); + + if (Buffer == NULL) { + printf ("Error in allocating buffer to read specific file\n"); + return EFI_OUT_OF_RESOURCES; + } + + NumByteRead = fread ((VOID *) Buffer, sizeof (UINT8), (UINTN) FileSize, Fp); + + Status = WriteFwBinary (FdFileName, StartAddress, FileSize, Buffer); + + if (Buffer) { + free ((VOID *) Buffer); + } + + if (Fp) { + fclose (Fp); + } + + if (Status != EFI_SUCCESS) { + printf ("\nERROR: Error in writing the binary image to file"); + return Status; + } + + StartAddress += NumByteRead; + LastAddress += FileSize; + + return EFI_SUCCESS; +} + +VOID +CleanUpMemory ( + VOID + ) +/*++ + +Routine Description: + + This function cleans up any allocated buffer + +Arguments: + + None + +Returns: + + None + +--*/ +{ + UINTN Index; + + if (FdInfo) { + free (FdInfo); + } + + FvInfo = OrgFvInfoPtr; + + if (FvInfo) { + for (Index = 0; Index < NumFvFiles; Index++) { + if (*FvInfo) { + free (*FvInfo); + } + + FvInfo++; + } + + FvInfo = OrgFvInfoPtr; + free (FvInfo); + } +} + +EFI_STATUS +GenerateFdImage ( + IN UINT64 BaseAddress, + IN UINT64 Size, + IN UINT8 PadByte, + IN CHAR8 *OutFile, + IN CHAR8 **FileList + ) +/*++ + +Routine Description: + + This function reads the input file, parses it and creates a list of tokens + which are parsed and used to intialize the data related to the Firmware + Volume. + +Arguments: + + BaseAddress Base Address for this Firmware Device + Size, Total Size of the Firmware Device + PadByte Pad byte data + OutFile Output File Name + FileList File List pointer to INF file names. + +Returns: + + EFI_STATUS + +--*/ +// GC_TODO: EFI_OUT_OF_RESOURCES - add return value to function comment +// GC_TODO: EFI_ABORTED - add return value to function comment +// GC_TODO: EFI_ABORTED - add return value to function comment +// GC_TODO: EFI_SUCCESS - add return value to function comment +{ + EFI_STATUS Status; + + UINTN Index; + UINTN PadSize; + UINTN FileSize; + UINTN NumByte; + + CHAR8 **InFile; + + FILE *Fp; + + UINT8 *Buffer; + + // + // If any previous Firmware Device existed, + // make it to 0 bytes + // + if ((Fp = fopen (OutFile, "w")) != NULL) { + fclose (Fp); + } + + InFile = FileList; + + while (*InFile != NULL) { + NumFvFiles++; + InFile++; + } + + InitializeComps (); + + // + // Restore the orginal pointers + // + FvInfo = OrgFvInfoPtr; + InFile = FileList; + + while (*InFile != NULL) { + strcpy ((*FvInfo)->FvInfoFile, *InFile); + Status = GetFvRelatedInfoFromInfFile (*InFile); + + if (Status != EFI_SUCCESS) { + printf ("\nERROR: Error occurred in processsing INF file"); + CleanUpMemory (); + return Status; + } + + InFile++; + FvInfo++; + } + + FdInfo->FdSize = Size; + FdInfo->FdBaseAddress = BaseAddress; + FdInfo->PadValue = PadByte; + FvInfo = OrgFvInfoPtr; + strcpy (FdInfo->OutFileName, OutFile); + + for (Index = 0; Index < NumFvFiles; Index++) { + Status = GenerateFvImage ((*FvInfo)->FvInfoFile); + + if (Status != EFI_SUCCESS) { + CleanUpMemory (); + return Status; + } + + FvInfo++; + } + + FvInfo = OrgFvInfoPtr; + + // + // Sort the Firmware Volume information. Firmware Volume with lower + // base addresses will be processed first and higher base address one + // will be processed later. + // + qsort ((VOID *) FvInfo, NumFvFiles, sizeof (FVINFO *), CompareItems); + + LastAddress = (*FvInfo)->FvBaseAddress; + + for (Index = 0; Index < NumFvFiles; Index++) { + Status = BuildFirmwareDeviceBinaryFromFwVolumes ( + (*FvInfo)->FvBaseAddress, + (*FvInfo)->FvFile, + FdInfo->OutFileName + ); + if (Status != EFI_SUCCESS) { + CleanUpMemory (); + return Status; + } + + FvInfo++; + } + // + // Check if any space left after copying data from all Firmware Volumes + // If yes, then fill those location with PadValue. + // + if ((FdInfo->FdBaseAddress + Size) > LastAddress) { + + PadSize = (UINTN) ((FdInfo->FdBaseAddress + FdInfo->FdSize) - LastAddress); + Buffer = malloc (PadSize); + + if (Buffer == NULL) { + printf ("\nERROR: allocating PadSize memory in function GenerateFdImage.\n"); + CleanUpMemory (); + return EFI_OUT_OF_RESOURCES; + } + + for (Index = 0; Index < PadSize; Index++) { + *Buffer = FdInfo->PadValue; + Buffer++; + } + + Buffer -= PadSize; + + Fp = fopen (OutFile, "a+b"); + + if (Fp == NULL) { + printf ("\nERROR:Opening file %s", OutFile); + CleanUpMemory (); + return EFI_ABORTED; + } + + FileSize = _filelength (fileno (Fp)); + fseek (Fp, FileSize, SEEK_SET); + NumByte = fwrite (Buffer, sizeof (UINT8), PadSize, Fp); + + if (Buffer) { + free (Buffer); + } + + fclose (Fp); + + if (NumByte != (sizeof (UINT8) * PadSize)) { + printf ("\nERROR: Copying data from buffer to File %s ", OutFile); + CleanUpMemory (); + return EFI_ABORTED; + } + } + // + // Clean up all the memory which has been allocated so far. + // + CleanUpMemory (); + + return EFI_SUCCESS; +} diff --git a/Tools/Source/TianoTools/GenFdImage/Makefile b/Tools/Source/TianoTools/GenFdImage/Makefile new file mode 100644 index 0000000000..94fafaf798 --- /dev/null +++ b/Tools/Source/TianoTools/GenFdImage/Makefile @@ -0,0 +1,100 @@ +#/*++ +# +# Copyright (c) 2001 Intel Corporation. All rights reserved. +# +# This software and associated documentation (if any) is furnished under +# a license and may only be used or copied in accordance with the terms +# of the license. Except as permitted by such license, no part of this +# software or documentation may be reproduced, stored in a retrieval +# system, or transmitted in any form or by any means without the express +# written consent of Intel Corporation. +# +# Module Name: makefile +# +# Abstract: +# +# This file is used to build the EFI utility. +# +#--*/ + +# +# Do this if you want to compile from this directory +# +!IFNDEF TOOLCHAIN +TOOLCHAIN = TOOLCHAIN_MSVC +!ENDIF + +!INCLUDE PlatformTools.env + +# +# Define some macros we use here. Should get rid of them someday and +# get rid of the extra level of indirection. +# +COMMON_SOURCE = $(EDK_TOOLS_COMMON) + +# +# Common information +# + +INC=$(INC) \ + -I "$(TIANO_TOOLS_SOURCE)\GenFvImage" + +# +# Target specific information +# + +TARGET_NAME=GenFdImage +TARGET_SOURCE_DIR = $(TIANO_TOOLS_SOURCE)\$(TARGET_NAME) + +TARGET_LIB = $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).lib +TARGET_EXE = $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).exe + +TARGET_EXE_SOURCE = "$(TARGET_SOURCE_DIR)\GenFdImageExe.c" +TARGET_EXE_INCLUDE = "$(TARGET_SOURCE_DIR)\GenFdImageExe.h" \ + "$(TARGET_SOURCE_DIR)\GenFdImage.h" \ + "$(COMMON_SOURCE)\ParseInf.h" \ + "$(EDK_SOURCE)\Foundation\Include\TianoCommon.h" +TARGET_EXE_LIBS = "$(TIANO_TOOLS_OUTPUT)\Common.lib" \ + "$(TIANO_TOOLS_OUTPUT)\GenFvImage.lib" \ + "$(TIANO_TOOLS_OUTPUT)\PeimFixup.lib" + +TARGET_LIB_SOURCE = "$(TARGET_SOURCE_DIR)\GenFdImageLib.c" +TARGET_LIB_INCLUDE = "$(TARGET_SOURCE_DIR)\GenFdImage.h" \ + "$(TIANO_TOOLS_SOURCE)\GenFvImage\GenFvImage.h" \ + "$(COMMON_SOURCE)\ParseInf.h" \ + "$(EDK_SOURCE)\Foundation\Include\TianoCommon.h" +TARGET_LIB_LIBS = "$(TIANO_TOOLS_OUTPUT)\Common.lib" \ + "$(TIANO_TOOLS_OUTPUT)\GenFvImage.lib" \ + "$(TIANO_TOOLS_OUTPUT)\PeimFixup.lib" + + +# +# Build targets +# + +all: $(TARGET_LIB) $(TARGET_EXE) + +# +# Build EXE +# + +$(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).obj: $(TARGET_EXE_SOURCE) $(TARGET_EXE_INCLUDE) + $(CC) $(C_FLAGS) $(INC) $(TARGET_EXE_SOURCE) /Fo$(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).obj + +$(TARGET_EXE): $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).obj $(TARGET_EXE_LIBS) $(TARGET_LIB) + $(LINK) $(MSVS_LINK_LIBPATHS) $(L_FLAGS) $(LIBS) /out:$(TARGET_EXE) $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).obj $(TARGET_LIB) $(TARGET_EXE_LIBS) + +# +# Build LIB +# + +$(TARGET_LIB): $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME)Lib.obj $(TARGET_LIB_LIBS) + $(LIB) $(LIB_FLAGS) $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME)Lib.obj /OUT:$(TARGET_LIB) + +$(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME)Lib.obj: $(TARGET_LIB_SOURCE) $(TARGET_LIB_INCLUDE) + $(CC) $(C_FLAGS) $(INC) $(TARGET_LIB_SOURCE) /Fo$(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME)Lib.obj + + +clean: + @if exist $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME)Lib.* del /q $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME)Lib.* > NUL + @if exist $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).* del /q $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).* > NUL diff --git a/Tools/Source/TianoTools/GenTEImage/GenTEImage.c b/Tools/Source/TianoTools/GenTEImage/GenTEImage.c new file mode 100644 index 0000000000..8aef6d316e --- /dev/null +++ b/Tools/Source/TianoTools/GenTEImage/GenTEImage.c @@ -0,0 +1,919 @@ +/*++ + +Copyright (c) 1999-2004 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +Module Name: + + GenTEImage.c + +Abstract: + + Utility program to shrink a PE32 image down by replacing + the DOS, PE, and optional headers with a minimal header. + +--*/ + +#include +#include +#include + +#include "Tiano.h" +#include "TianoCommon.h" +#include "EfiImage.h" // for PE32 structure definitions +#include "EfiUtilityMsgs.h" + +// +// Version of this utility +// +#define UTILITY_NAME "GenTEImage" +#define UTILITY_VERSION "v0.11" + +// +// Define the max length of a filename +// +#define MAX_PATH 256 +#define DEFAULT_OUTPUT_EXTENSION ".te" + +// +// Use this to track our command-line options and globals +// +struct { + INT8 OutFileName[MAX_PATH]; + INT8 InFileName[MAX_PATH]; + INT8 Verbose; + INT8 Dump; +} mOptions; + +// +// Use these to convert from machine type value to a named type +// +typedef struct { + UINT16 Value; + INT8 *Name; +} STRING_LOOKUP; + +static STRING_LOOKUP mMachineTypes[] = { + EFI_IMAGE_MACHINE_IA32, + "IA32", + EFI_IMAGE_MACHINE_IA64, + "IA64", + EFI_IMAGE_MACHINE_EBC, + "EBC", + 0, + NULL +}; + +static STRING_LOOKUP mSubsystemTypes[] = { + EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION, + "EFI application", + EFI_IMAGE_SUBSYSTEM_EFI_BOOT_SERVICE_DRIVER, + "EFI boot service driver", + EFI_IMAGE_SUBSYSTEM_EFI_RUNTIME_DRIVER, + "EFI runtime driver", + 0, + NULL +}; +// +// Function prototypes +// +static +void +Usage ( + VOID + ); + +static +STATUS +ParseCommandLine ( + int Argc, + char *Argv[] + ); + +static +STATUS +CheckPE32File ( + INT8 *FileName, + FILE *Fptr, + UINT16 *MachineType, + UINT16 *SubSystem + ); + +static +STATUS +ProcessFile ( + INT8 *InFileName, + INT8 *OutFileName + ); + +static +void +DumpImage ( + INT8 *FileName + ); + +static +INT8 * +GetMachineTypeStr ( + UINT16 MachineType + ); + +static +INT8 * +GetSubsystemTypeStr ( + UINT16 SubsystemType + ); + +main ( + int Argc, + char *Argv[] + ) +/*++ + +Routine Description: + + +Arguments: + + Argc - standard C main() argument count + + Argv - standard C main() argument list + +Returns: + + 0 success + non-zero otherwise + +--*/ +// GC_TODO: ] - add argument and description to function comment +{ + INT8 *Ext; + UINT32 Status; + + SetUtilityName (UTILITY_NAME); + // + // Parse the command line arguments + // + if (ParseCommandLine (Argc, Argv)) { + return STATUS_ERROR; + } + // + // If dumping an image, then do that and quit + // + if (mOptions.Dump) { + DumpImage (mOptions.InFileName); + goto Finish; + } + // + // Determine the output filename. Either what they specified on + // the command line, or the first input filename with a different extension. + // + if (!mOptions.OutFileName[0]) { + strcpy (mOptions.OutFileName, mOptions.InFileName); + // + // Find the last . on the line and replace the filename extension with + // the default + // + for (Ext = mOptions.OutFileName + strlen (mOptions.OutFileName) - 1; + (Ext >= mOptions.OutFileName) && (*Ext != '.') && (*Ext != '\\'); + Ext-- + ) + ; + // + // If dot here, then insert extension here, otherwise append + // + if (*Ext != '.') { + Ext = mOptions.OutFileName + strlen (mOptions.OutFileName); + } + + strcpy (Ext, DEFAULT_OUTPUT_EXTENSION); + } + // + // Make sure we don't have the same filename for input and output files + // + if (stricmp (mOptions.OutFileName, mOptions.InFileName) == 0) { + Error (NULL, 0, 0, mOptions.OutFileName, "input and output file names must be different"); + goto Finish; + } + // + // Process the file + // + ProcessFile (mOptions.InFileName, mOptions.OutFileName); +Finish: + Status = GetUtilityStatus (); + return Status; +} + +static +STATUS +ProcessFile ( + INT8 *InFileName, + INT8 *OutFileName + ) +/*++ + +Routine Description: + + Process a PE32 EFI file. + +Arguments: + + InFileName - the file name pointer to the input file + OutFileName - the file name pointer to the output file + +Returns: + + STATUS_SUCCESS - the process has been finished successfully + STATUS_ERROR - error occured during the processing + +--*/ +{ + STATUS Status; + FILE *InFptr; + FILE *OutFptr; + UINT16 MachineType; + UINT16 SubSystem; + EFI_TE_IMAGE_HEADER TEImageHeader; + UINT32 PESigOffset; + EFI_IMAGE_FILE_HEADER FileHeader; + EFI_IMAGE_OPTIONAL_HEADER32 OptionalHeader32; + EFI_IMAGE_OPTIONAL_HEADER64 OptionalHeader64; + UINT32 BytesStripped; + UINT32 FileSize; + UINT8 *Buffer; + long SaveFilePosition; + + InFptr = NULL; + OutFptr = NULL; + Buffer = NULL; + Status = STATUS_ERROR; + + // + // Try to open the input file + // + if ((InFptr = fopen (InFileName, "rb")) == NULL) { + Error (NULL, 0, 0, InFileName, "failed to open input file for reading"); + return STATUS_ERROR; + } + // + // Double-check the file to make sure it's what we expect it to be + // + if (CheckPE32File (InFileName, InFptr, &MachineType, &SubSystem) != STATUS_SUCCESS) { + goto Finish; + } + // + // Initialize our new header + // + memset (&TEImageHeader, 0, sizeof (EFI_TE_IMAGE_HEADER)); + + // + // Seek to the end to get the file size + // + fseek (InFptr, 0, SEEK_END); + FileSize = ftell (InFptr); + fseek (InFptr, 0, SEEK_SET); + + // + // Per the PE/COFF specification, at offset 0x3C in the file is a 32-bit + // offset (from the start of the file) to the PE signature, which always + // follows the MSDOS stub. The PE signature is immediately followed by the + // COFF file header. + // + // + if (fseek (InFptr, 0x3C, SEEK_SET) != 0) { + Error (NULL, 0, 0, InFileName, "failed to seek to PE signature in file", NULL); + goto Finish; + } + + if (fread (&PESigOffset, sizeof (PESigOffset), 1, InFptr) != 1) { + Error (NULL, 0, 0, InFileName, "failed to read PE signature offset from file"); + goto Finish; + } + + if (fseek (InFptr, PESigOffset + 4, SEEK_SET) != 0) { + Error (NULL, 0, 0, InFileName, "failed to seek to PE signature"); + goto Finish; + } + // + // We should now be at the COFF file header. Read it in and verify it's + // of an image type we support. + // + if (fread (&FileHeader, sizeof (EFI_IMAGE_FILE_HEADER), 1, InFptr) != 1) { + Error (NULL, 0, 0, InFileName, "failed to read file header from image"); + goto Finish; + } + + if ((FileHeader.Machine != EFI_IMAGE_MACHINE_IA32) && (FileHeader.Machine != EFI_IMAGE_MACHINE_IA64)) { + Error (NULL, 0, 0, InFileName, "image is of an unsupported machine type 0x%X", (UINT32) FileHeader.Machine); + goto Finish; + } + // + // Calculate the total number of bytes we're going to strip off. The '4' is for the + // PE signature PE\0\0. Then sanity check the size. + // + BytesStripped = PESigOffset + 4 + sizeof (EFI_IMAGE_FILE_HEADER) + FileHeader.SizeOfOptionalHeader; + if (BytesStripped >= FileSize) { + Error (NULL, 0, 0, InFileName, "attempt to strip more bytes than the total file size"); + goto Finish; + } + + if (BytesStripped &~0xFFFF) { + Error (NULL, 0, 0, InFileName, "attempt to strip more than 64K bytes", NULL); + goto Finish; + } + + TEImageHeader.StrippedSize = (UINT16) BytesStripped; + + // + // Read in the optional header. Assume PE32, and if not, then re-read as PE32+ + // + SaveFilePosition = ftell (InFptr); + if (fread (&OptionalHeader32, sizeof (EFI_IMAGE_OPTIONAL_HEADER32), 1, InFptr) != 1) { + Error (NULL, 0, 0, InFileName, "failed to read optional header from input file"); + goto Finish; + } + + if (OptionalHeader32.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) { + // + // Fill in our new header with required data directory entries + // + TEImageHeader.AddressOfEntryPoint = OptionalHeader32.AddressOfEntryPoint; + // + // - BytesStripped + sizeof (EFI_TE_IMAGE_HEADER); + // + // We're going to pack the subsystem into 1 byte. Make sure it fits + // + if (OptionalHeader32.Subsystem &~0xFF) { + Error ( + NULL, + 0, + 0, + InFileName, + NULL, + "image subsystem 0x%X cannot be packed into 1 byte", + (UINT32) OptionalHeader32.Subsystem + ); + goto Finish; + } + + TEImageHeader.Subsystem = (UINT8) OptionalHeader32.Subsystem; + TEImageHeader.BaseOfCode = OptionalHeader32.BaseOfCode; + TEImageHeader.ImageBase = (UINT64) (OptionalHeader32.ImageBase + TEImageHeader.StrippedSize - sizeof (EFI_TE_IMAGE_HEADER)); + if (OptionalHeader32.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = OptionalHeader32.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = OptionalHeader32.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + } + + if (OptionalHeader32.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = OptionalHeader32.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = OptionalHeader32.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size; + } + } else if (OptionalHeader32.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) { + // + // Rewind and re-read the optional header + // + fseek (InFptr, SaveFilePosition, SEEK_SET); + if (fread (&OptionalHeader64, sizeof (EFI_IMAGE_OPTIONAL_HEADER64), 1, InFptr) != 1) { + Error (NULL, 0, 0, InFileName, "failed to re-read optional header from input file"); + goto Finish; + } + + TEImageHeader.AddressOfEntryPoint = OptionalHeader64.AddressOfEntryPoint; + // + // - BytesStripped + sizeof (EFI_TE_IMAGE_HEADER); + // + // We're going to pack the subsystem into 1 byte. Make sure it fits + // + if (OptionalHeader64.Subsystem &~0xFF) { + Error ( + NULL, + 0, + 0, + InFileName, + NULL, + "image subsystem 0x%X cannot be packed into 1 byte", + (UINT32) OptionalHeader64.Subsystem + ); + goto Finish; + } + + TEImageHeader.Subsystem = (UINT8) OptionalHeader64.Subsystem; + TEImageHeader.BaseOfCode = OptionalHeader32.BaseOfCode; + TEImageHeader.ImageBase = (UINT64) (OptionalHeader64.ImageBase + TEImageHeader.StrippedSize - sizeof (EFI_TE_IMAGE_HEADER)); + if (OptionalHeader64.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC) { + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = OptionalHeader64.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = OptionalHeader64.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + } + + if (OptionalHeader64.NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_DEBUG) { + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = OptionalHeader64.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = OptionalHeader64.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size; + } + } else { + Error ( + NULL, + 0, + 0, + InFileName, + "unsupported magic number 0x%X found in optional header", + (UINT32) OptionalHeader32.Magic + ); + goto Finish; + } + // + // Fill in the remainder of our new image header + // + TEImageHeader.Signature = EFI_TE_IMAGE_HEADER_SIGNATURE; + TEImageHeader.Machine = FileHeader.Machine; + // + // We're going to pack the number of sections into a single byte. Make sure it fits. + // + if (FileHeader.NumberOfSections &~0xFF) { + Error ( + NULL, + 0, + 0, + InFileName, + NULL, + "image's number of sections 0x%X cannot be packed into 1 byte", + (UINT32) FileHeader.NumberOfSections + ); + goto Finish; + } + + TEImageHeader.NumberOfSections = (UINT8) FileHeader.NumberOfSections; + + // + // Now open our output file + // + if ((OutFptr = fopen (OutFileName, "wb")) == NULL) { + Error (NULL, 0, 0, OutFileName, "failed to open output file for writing"); + goto Finish; + } + // + // Write the TE header + // + if (fwrite (&TEImageHeader, sizeof (EFI_TE_IMAGE_HEADER), 1, OutFptr) != 1) { + Error (NULL, 0, 0, "failed to write image header to output file", NULL); + goto Finish; + } + // + // Position into the input file, read the part we're not stripping, and + // write it out. + // + fseek (InFptr, BytesStripped, SEEK_SET); + Buffer = (UINT8 *) malloc (FileSize - BytesStripped); + if (Buffer == NULL) { + Error (NULL, 0, 0, "application error", "failed to allocate memory"); + goto Finish; + } + + if (fread (Buffer, FileSize - BytesStripped, 1, InFptr) != 1) { + Error (NULL, 0, 0, InFileName, "failed to read remaining contents of input file"); + goto Finish; + } + + if (fwrite (Buffer, FileSize - BytesStripped, 1, OutFptr) != 1) { + Error (NULL, 0, 0, OutFileName, "failed to write all bytes to output file"); + goto Finish; + } + + Status = STATUS_SUCCESS; + +Finish: + if (InFptr != NULL) { + fclose (InFptr); + } + // + // Close the output file. If there was an error, delete the output file so + // that a subsequent build will rebuild it. + // + if (OutFptr != NULL) { + fclose (OutFptr); + if (GetUtilityStatus () == STATUS_ERROR) { + remove (OutFileName); + } + } + + // + // Free up our buffer + // + if (Buffer != NULL) { + free (Buffer); + } + + return Status; +} + +static +STATUS +CheckPE32File ( + INT8 *FileName, + FILE *Fptr, + UINT16 *MachineType, + UINT16 *SubSystem + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + FileName - GC_TODO: add argument description + Fptr - GC_TODO: add argument description + MachineType - GC_TODO: add argument description + SubSystem - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + /*++ + +Routine Description: + + Given a file pointer to a supposed PE32 image file, verify that it is indeed a + PE32 image file, and then return the machine type in the supplied pointer. + +Arguments: + + Fptr File pointer to the already-opened PE32 file + MachineType Location to stuff the machine type of the PE32 file. This is needed + because the image may be Itanium-based, IA32, or EBC. + +Returns: + + 0 success + non-zero otherwise + +--*/ + EFI_IMAGE_DOS_HEADER DosHeader; + EFI_IMAGE_FILE_HEADER FileHdr; + EFI_IMAGE_OPTIONAL_HEADER OptionalHdr; + UINT32 PESig; + STATUS Status; + + Status = STATUS_ERROR; + // + // Position to the start of the file + // + fseek (Fptr, 0, SEEK_SET); + // + // Read the DOS header + // + if (fread (&DosHeader, sizeof (DosHeader), 1, Fptr) != 1) { + Error (NULL, 0, 0, FileName, "failed to read the DOS stub from the input file"); + goto Finish; + } + // + // Check the magic number (0x5A4D) + // + if (DosHeader.e_magic != EFI_IMAGE_DOS_SIGNATURE) { + Error (NULL, 0, 0, FileName, "input file does not appear to be a PE32 image (magic number)"); + goto Finish; + } + // + // Position into the file and check the PE signature + // + fseek (Fptr, (long) DosHeader.e_lfanew, SEEK_SET); + if (fread (&PESig, sizeof (PESig), 1, Fptr) != 1) { + Error (NULL, 0, 0, FileName, "failed to read PE signature bytes"); + goto Finish; + } + // + // Check the PE signature in the header "PE\0\0" + // + if (PESig != EFI_IMAGE_NT_SIGNATURE) { + Error (NULL, 0, 0, FileName, "file does not appear to be a PE32 image (signature)"); + goto Finish; + } + // + // Read the file header + // + if (fread (&FileHdr, sizeof (FileHdr), 1, Fptr) != 1) { + Error (NULL, 0, 0, FileName, "failed to read PE file header from input file"); + goto Finish; + } + // + // Read the optional header so we can get the subsystem + // + if (fread (&OptionalHdr, sizeof (OptionalHdr), 1, Fptr) != 1) { + Error (NULL, 0, 0, FileName, "failed to read COFF optional header from input file"); + goto Finish; + } + + *SubSystem = OptionalHdr.Subsystem; + if (mOptions.Verbose) { + fprintf (stdout, " Got subsystem = 0x%X from image\n", (int) *SubSystem); + } + // + // Good to go + // + Status = STATUS_SUCCESS; +Finish: + fseek (Fptr, 0, SEEK_SET); + return Status; +} + +static +int +ParseCommandLine ( + int Argc, + char *Argv[] + ) +/*++ + +Routine Description: + + Given the Argc/Argv program arguments, and a pointer to an options structure, + parse the command-line options and check their validity. + + +Arguments: + + Argc - standard C main() argument count + Argv - standard C main() argument list + +Returns: + + STATUS_SUCCESS success + non-zero otherwise + +--*/ +// GC_TODO: ] - add argument and description to function comment +{ + // + // Clear out the options + // + memset ((char *) &mOptions, 0, sizeof (mOptions)); + // + // Skip over the program name + // + Argc--; + Argv++; + // + // If no arguments, assume they want usage info + // + if (Argc == 0) { + Usage (); + return STATUS_ERROR; + } + // + // Process until no more arguments + // + while ((Argc > 0) && ((Argv[0][0] == '-') || (Argv[0][0] == '/'))) { + // + // To simplify string comparisons, replace slashes with dashes + // + Argv[0][0] = '-'; + if (stricmp (Argv[0], "-o") == 0) { + // + // Output filename specified with -o + // Make sure there's another parameter + // + if (Argc > 1) { + strcpy (mOptions.OutFileName, Argv[1]); + } else { + Error (NULL, 0, 0, Argv[0], "missing output file name with option"); + Usage (); + return STATUS_ERROR; + } + + Argv++; + Argc--; + } else if ((stricmp (Argv[0], "-h") == 0) || (strcmp (Argv[0], "-?") == 0)) { + // + // Help option + // + Usage (); + return STATUS_ERROR; + } else if (stricmp (Argv[0], "-v") == 0) { + // + // -v for verbose + // + mOptions.Verbose = 1; + } else if (stricmp (Argv[0], "-dump") == 0) { + // + // -dump for dumping an image + // + mOptions.Dump = 1; + } else { + Error (NULL, 0, 0, Argv[0], "unrecognized option"); + Usage (); + return STATUS_ERROR; + } + // + // Next argument + // + Argv++; + Argc--; + } + // + // Better be one more arg for input file name + // + if (Argc == 0) { + Error (NULL, 0, 0, "input file name required", NULL); + Usage (); + return STATUS_ERROR; + } + + if (Argc != 1) { + Error (NULL, 0, 0, Argv[1], "extra arguments on command line"); + return STATUS_ERROR; + } + + strcpy (mOptions.InFileName, Argv[0]); + return STATUS_SUCCESS; +} + +static +void +Usage ( + VOID + ) +/*++ + +Routine Description: + + Print usage information for this utility. + +Arguments: + + None. + +Returns: + + Nothing. + +--*/ +{ + int Index; + static const char *Msg[] = { + UTILITY_NAME " version "UTILITY_VERSION " - TE image utility", + " Generate a TE image from an EFI PE32 image", + " Usage: "UTILITY_NAME " {-v} {-dump} {-h|-?} {-o OutFileName} InFileName", + " [-e|-b] [FileName(s)]", + " where:", + " -v - for verbose output", + " -dump - to dump the input file to a text file", + " -h -? - for this help information", + " -o OutFileName - to write output to OutFileName rather than InFileName"DEFAULT_OUTPUT_EXTENSION, + " InFileName - name of the input PE32 file", + "", + NULL + }; + for (Index = 0; Msg[Index] != NULL; Index++) { + fprintf (stdout, "%s\n", Msg[Index]); + } +} + +static +VOID +DumpImage ( + INT8 *FileName + ) +/*++ + +Routine Description: + + Dump a specified image information + +Arguments: + + FileName - File name pointer to the image to dump + +Returns: + + Nothing. + +--*/ +{ + FILE *InFptr; + EFI_TE_IMAGE_HEADER TEImageHeader; + INT8 *NamePtr; + + // + // Open the input file + // + InFptr = NULL; + + if ((InFptr = fopen (FileName, "rb")) == NULL) { + Error (NULL, 0, 0, FileName, "failed to open input file for reading"); + return ; + } + + if (fread (&TEImageHeader, sizeof (EFI_TE_IMAGE_HEADER), 1, InFptr) != 1) { + Error (NULL, 0, 0, FileName, "failed to read image header from input file"); + goto Finish; + } + + if (TEImageHeader.Signature != EFI_TE_IMAGE_HEADER_SIGNATURE) { + Error (NULL, 0, 0, FileName, "Image does not appear to be a TE image (bad signature)"); + goto Finish; + } + // + // Dump the header + // + fprintf (stdout, "Header (%d bytes):\n", sizeof (EFI_TE_IMAGE_HEADER)); + fprintf (stdout, " Signature: 0x%04X (TE)\n", (UINT32) TEImageHeader.Signature); + NamePtr = GetMachineTypeStr (TEImageHeader.Machine); + fprintf (stdout, " Machine: 0x%04X (%s)\n", (UINT32) TEImageHeader.Machine, NamePtr); + NamePtr = GetSubsystemTypeStr (TEImageHeader.Subsystem); + fprintf (stdout, " Subsystem: 0x%02X (%s)\n", (UINT32) TEImageHeader.Subsystem, NamePtr); + fprintf (stdout, " Number of sections 0x%02X\n", (UINT32) TEImageHeader.NumberOfSections); + fprintf (stdout, " Stripped size: 0x%04X\n", (UINT32) TEImageHeader.StrippedSize); + fprintf (stdout, " Entry point: 0x%08X\n", TEImageHeader.AddressOfEntryPoint); + fprintf (stdout, " Base of code: 0x%08X\n", TEImageHeader.BaseOfCode); + fprintf (stdout, " Data directories:\n"); + fprintf ( + stdout, + " %8X [%8X] RVA [size] of Base Relocation Directory\n", + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress, + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size + ); + fprintf ( + stdout, + " %8X [%8X] RVA [size] of Debug Directory\n", + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress, + TEImageHeader.DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size + ); + +Finish: + if (InFptr != NULL) { + fclose (InFptr); + } +} + +static +INT8 * +GetMachineTypeStr ( + UINT16 MachineType + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + MachineType - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + int Index; + + for (Index = 0; mMachineTypes[Index].Name != NULL; Index++) { + if (mMachineTypes[Index].Value == MachineType) { + return mMachineTypes[Index].Name; + } + } + + return "unknown"; +} + +static +INT8 * +GetSubsystemTypeStr ( + UINT16 SubsystemType + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + SubsystemType - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +{ + int Index; + + for (Index = 0; mSubsystemTypes[Index].Name != NULL; Index++) { + if (mSubsystemTypes[Index].Value == SubsystemType) { + return mSubsystemTypes[Index].Name; + } + } + + return "unknown"; +} diff --git a/Tools/Source/TianoTools/GenTEImage/Makefile b/Tools/Source/TianoTools/GenTEImage/Makefile new file mode 100644 index 0000000000..f731b6d34e --- /dev/null +++ b/Tools/Source/TianoTools/GenTEImage/Makefile @@ -0,0 +1,68 @@ +#/*++ +# +# Copyright (c) 2002 Intel Corporation. All rights reserved. +# +# This software and associated documentation (if any) is furnished under +# a license and may only be used or copied in accordance with the terms +# of the license. Except as permitted by such license, no part of this +# software or documentation may be reproduced, stored in a retrieval +# system, or transmitted in any form or by any means without the express +# written consent of Intel Corporation. +# +# Module Name: +# +# makefile +# +# Abstract: +# +# makefile for building the GenTEImage utility. +# +#--*/ + +# +# Make sure environmental variable EFI_SOURCE is set +# +!IFNDEF EFI_SOURCE +!ERROR EFI_SOURCE environmental variable not set +!ENDIF + +# +# Define the toolchain which is used to set build options and toolchain paths +# +TOOLCHAIN = TOOLCHAIN_MSVC + +!INCLUDE PlatformTools.env + +# +# Target specific information +# + +TARGET_NAME = GenTEImage +TARGET_SRC_DIR = $(TIANO_TOOLS_SOURCE)\$(TARGET_NAME) +TARGET_EXE = $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).exe + +# +# Build targets +# + +all: $(TARGET_EXE) + +OBJECTS = $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).obj + +LIBS = $(TIANO_TOOLS_OUTPUT)\Common.lib + +INC_DEPS = $(EDK_SOURCE)\Foundation\Efi\Include\EfiImage.h + +# +# Build the EXE by compiling the source files, then linking the resultant +# object files together. +# + +$(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).obj : $(TARGET_SRC_DIR)\$(TARGET_NAME).c $(INC_DEPS) + $(CC) $(C_FLAGS) $(TARGET_SRC_DIR)\$(TARGET_NAME).c /Fo$@ + +$(TARGET_EXE): $(OBJECTS) $(TARGET_EXE_LIBS) + $(LINK) $(MSVS_LINK_LIBPATHS) $(L_FLAGS) $(LIBS) /out:$(TARGET_EXE) $(OBJECTS) + +clean: + @if exist $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).* del $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).* > NUL diff --git a/Tools/Source/TianoTools/PeiRebase/PeiRebaseExe.c b/Tools/Source/TianoTools/PeiRebase/PeiRebaseExe.c new file mode 100644 index 0000000000..1845c48cbd --- /dev/null +++ b/Tools/Source/TianoTools/PeiRebase/PeiRebaseExe.c @@ -0,0 +1,973 @@ +/*++ + +Copyright (c) 1999 - 2005 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + + +Module Name: + + PeiRebaseExe.c + +Abstract: + + This contains all code necessary to build the PeiRebase.exe utility. + This utility relies heavily on the PeiRebase DLL. Definitions for both + can be found in the PEI Rebase Utility Specification, review draft. + +--*/ + +#include "PeiRebaseExe.h" +#include +#include +#include +#include "CommonLib.h" +#include "ParseInf.h" +#include EFI_GUID_DEFINITION (PeiPeCoffLoader) +#include "FvLib.h" + +#include "EfiUtilityMsgs.h" + +extern EFI_PEI_PE_COFF_LOADER_PROTOCOL mPeCoffLoader; + +EFI_STATUS +ReadHeader ( + IN FILE *InputFile, + OUT UINT32 *FvSize, + OUT BOOLEAN *ErasePolarity + ); + +int +main ( + int argc, + char **argv + ) +/*++ + +Routine Description: + + This utility relocates PEI XIP PE32s in a FV. + +Arguments: + + argc - Number of command line arguments + argv[]: + BaseAddress The base address to use for rebasing the FV. The correct + format is a hex number preceded by 0x. + InputFileName The name of the input FV file. + OutputFileName The name of the output FV file. + + Arguments come in pair in any order. + -I InputFileName + -O OutputFileName + -B BaseAddress + +Returns: + + 0 No error conditions detected. + 1 One or more of the input parameters is invalid. + 2 A resource required by the utility was unavailable. + Most commonly this will be memory allocation or file creation. + 3 PeiRebase.dll could not be loaded. + 4 Error executing the PEI rebase. + +--*/ +{ + UINT8 Index; + CHAR8 InputFileName[_MAX_PATH]; + CHAR8 OutputFileName[_MAX_PATH]; + EFI_PHYSICAL_ADDRESS BaseAddress; + BOOLEAN BaseAddressSet; + EFI_STATUS Status; + FILE *InputFile; + FILE *OutputFile; + UINT64 FvOffset; + UINT32 FileCount; + int BytesRead; + EFI_FIRMWARE_VOLUME_HEADER *FvImage; + UINT32 FvSize; + EFI_FFS_FILE_HEADER *CurrentFile; + BOOLEAN ErasePolarity; + EFI_PHYSICAL_ADDRESS CurrentFileBaseAddress; + + ErasePolarity = FALSE; + // + // Set utility name for error/warning reporting purposes. + // + SetUtilityName (UTILITY_NAME); + // + // Verify the correct number of arguments + // + if (argc != MAX_ARGS) { + PrintUsage (); + return STATUS_ERROR; + } + // + // Initialize variables + // + InputFileName[0] = 0; + OutputFileName[0] = 0; + BaseAddress = 0; + BaseAddressSet = FALSE; + FvOffset = 0; + FileCount = 0; + ErasePolarity = FALSE; + InputFile = NULL; + OutputFile = NULL; + FvImage = NULL; + // + // Parse the command line arguments + // + for (Index = 1; Index < MAX_ARGS; Index += 2) { + // + // Make sure argument pair begin with - or / + // + if (argv[Index][0] != '-' && argv[Index][0] != '/') { + PrintUsage (); + Error (NULL, 0, 0, argv[Index], "unrecognized option"); + return STATUS_ERROR; + } + // + // Make sure argument specifier is only one letter + // + if (argv[Index][2] != 0) { + PrintUsage (); + Error (NULL, 0, 0, argv[Index], "unrecognized option"); + return STATUS_ERROR; + } + // + // Determine argument to read + // + switch (argv[Index][1]) { + case 'I': + case 'i': + if (strlen (InputFileName) == 0) { + strcpy (InputFileName, argv[Index + 1]); + } else { + PrintUsage (); + Error (NULL, 0, 0, argv[Index + 1], "only one -i InputFileName may be specified"); + return STATUS_ERROR; + } + break; + + case 'O': + case 'o': + if (strlen (OutputFileName) == 0) { + strcpy (OutputFileName, argv[Index + 1]); + } else { + PrintUsage (); + Error (NULL, 0, 0, argv[Index + 1], "only one -o OutputFileName may be specified"); + return STATUS_ERROR; + } + break; + + case 'B': + case 'b': + if (!BaseAddressSet) { + Status = AsciiStringToUint64 (argv[Index + 1], FALSE, &BaseAddress); + if (EFI_ERROR (Status)) { + PrintUsage (); + Error (NULL, 0, 0, argv[Index + 1], "invalid hex digit given for the base address"); + return STATUS_ERROR; + } + + BaseAddressSet = TRUE; + } else { + PrintUsage (); + Error (NULL, 0, 0, argv[Index + 1], "-b BaseAddress may only be specified once"); + return STATUS_ERROR; + } + break; + + default: + PrintUsage (); + Error (NULL, 0, 0, argv[Index], "unrecognized argument"); + return STATUS_ERROR; + break; + } + } + // + // Open the file containing the FV + // + InputFile = fopen (InputFileName, "rb"); + if (InputFile == NULL) { + Error (NULL, 0, 0, InputFileName, "could not open input file for reading"); + return STATUS_ERROR; + } + // + // Determine size of FV + // + Status = ReadHeader (InputFile, &FvSize, &ErasePolarity); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0, "could not parse the FV header", NULL); + goto Finish; + } + // + // Allocate a buffer for the FV image + // + FvImage = malloc (FvSize); + if (FvImage == NULL) { + Error (NULL, 0, 0, "application error", "memory allocation failed"); + goto Finish; + } + // + // Read the entire FV to the buffer + // + BytesRead = fread (FvImage, 1, FvSize, InputFile); + fclose (InputFile); + InputFile = NULL; + if ((unsigned int) BytesRead != FvSize) { + Error (NULL, 0, 0, InputFileName, "failed to read from file"); + goto Finish; + } + // + // Prepare to walk the FV image + // + InitializeFvLib (FvImage, FvSize); + // + // Get the first file + // + Status = GetNextFile (NULL, &CurrentFile); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0, "cannot find the first file in the FV image", NULL); + goto Finish; + } + // + // Check if each file should be rebased + // + while (CurrentFile != NULL) { + // + // Rebase this file + // + CurrentFileBaseAddress = BaseAddress + ((UINTN) CurrentFile - (UINTN) FvImage); + Status = FfsRebase (CurrentFile, CurrentFileBaseAddress); + + if (EFI_ERROR (Status)) { + switch (Status) { + + case EFI_INVALID_PARAMETER: + Error (NULL, 0, 0, "invalid parameter passed to FfsRebase", NULL); + break; + + case EFI_ABORTED: + Error (NULL, 0, 0, "error detected while rebasing -- aborted", NULL); + break; + + case EFI_OUT_OF_RESOURCES: + Error (NULL, 0, 0, "FfsRebase could not allocate required resources", NULL); + break; + + case EFI_NOT_FOUND: + Error (NULL, 0, 0, "FfsRebase could not locate a PE32 section", NULL); + break; + + default: + Error (NULL, 0, 0, "FfsRebase returned unknown status", "status=0x%08X", Status); + break; + } + + goto Finish; + } + // + // Get the next file + // + Status = GetNextFile (CurrentFile, &CurrentFile); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0, "cannot find the next file in the FV image", NULL); + goto Finish; + } + } + // + // Open the output file + // + OutputFile = fopen (OutputFileName, "wb"); + if (OutputFile == NULL) { + Error (NULL, 0, 0, OutputFileName, "failed to open output file"); + goto Finish; + } + + if (fwrite (FvImage, 1, FvSize, OutputFile) != FvSize) { + Error (NULL, 0, 0, "failed to write to output file", 0); + goto Finish; + } + +Finish: + if (InputFile != NULL) { + fclose (InputFile); + } + // + // If we created an output file, and there was an error, remove it so + // subsequent builds will rebuild it. + // + if (OutputFile != NULL) { + if (GetUtilityStatus () == STATUS_ERROR) { + remove (OutputFileName); + } + + fclose (OutputFile); + } + + if (FvImage != NULL) { + free (FvImage); + } + + return GetUtilityStatus (); +} + +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; + + BytesRead = 0; + Size = 0; + // + // Check input parameters + // + if ((InputFile == NULL) || (FvSize == NULL) || (ErasePolarity == NULL)) { + Error (NULL, 0, 0, "ReadHeader()", "invalid input parameter"); + return EFI_INVALID_PARAMETER; + } + // + // Read the header + // + fread (&VolumeHeader, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile); + BytesRead = sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY); + Signature[0] = VolumeHeader.Signature; + Signature[1] = 0; + + // + // Get erase polarity + // + if (VolumeHeader.Attributes & EFI_FVB_ERASE_POLARITY) { + *ErasePolarity = TRUE; + } + + do { + fread (&BlockMap, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, InputFile); + BytesRead += sizeof (EFI_FV_BLOCK_MAP_ENTRY); + + if (BlockMap.NumBlocks != 0) { + Size += BlockMap.NumBlocks * BlockMap.BlockLength; + } + + } while (!(BlockMap.NumBlocks == 0 && BlockMap.BlockLength == 0)); + + if (VolumeHeader.FvLength != Size) { + Error (NULL, 0, 0, "volume size not consistant with block maps", NULL); + return EFI_ABORTED; + } + + *FvSize = Size; + + rewind (InputFile); + + return EFI_SUCCESS; +} + +VOID +PrintUtilityInfo ( + VOID + ) +/*++ + +Routine Description: + + Displays the standard utility information to SDTOUT + +Arguments: + + None + +Returns: + + None + +--*/ +{ + printf ( + "%s, PEI Rebase Utility. Version %i.%i, %s.\n\n", + UTILITY_NAME, + UTILITY_MAJOR_VERSION, + UTILITY_MINOR_VERSION, + UTILITY_DATE + ); +} + +VOID +PrintUsage ( + VOID + ) +/*++ + +Routine Description: + + Displays the utility usage syntax to STDOUT + +Arguments: + + None + +Returns: + + None + +--*/ +{ + printf ( + "Usage: %s -I InputFileName -O OutputFileName -B BaseAddress\n", + UTILITY_NAME + ); + printf (" Where:\n"); + printf (" InputFileName is the name of the EFI FV file to rebase.\n"); + printf (" OutputFileName is the desired output file name.\n"); + printf (" BaseAddress is the FV base address to rebase agains.\n"); + printf (" Argument pair may be in any order.\n\n"); +} + +EFI_STATUS +FfsRebase ( + IN OUT EFI_FFS_FILE_HEADER *FfsFile, + IN EFI_PHYSICAL_ADDRESS BaseAddress + ) +/*++ + +Routine Description: + + This function determines if a file is XIP and should be rebased. It will + rebase any PE32 sections found in the file using the base address. + +Arguments: + + FfsFile A pointer to Ffs file image. + BaseAddress The base address to use for rebasing the file image. + +Returns: + + EFI_SUCCESS The image was properly rebased. + EFI_INVALID_PARAMETER An input parameter is invalid. + EFI_ABORTED An error occurred while rebasing the input file image. + EFI_OUT_OF_RESOURCES Could not allocate a required resource. + EFI_NOT_FOUND No compressed sections could be found. + +--*/ +{ + EFI_STATUS Status; + EFI_PEI_PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; + UINTN MemoryImagePointer; + UINTN MemoryImagePointerAligned; + EFI_PHYSICAL_ADDRESS ImageAddress; + UINT64 ImageSize; + EFI_PHYSICAL_ADDRESS EntryPoint; + UINT32 Pe32ImageSize; + UINT32 NewPe32BaseAddress; + UINTN Index; + EFI_FILE_SECTION_POINTER CurrentPe32Section; + EFI_FFS_FILE_STATE SavedState; + EFI_IMAGE_NT_HEADERS *PeHdr; + UINT32 *PeHdrSizeOfImage; + UINT32 *PeHdrChecksum; + UINT32 FoundCount; + EFI_TE_IMAGE_HEADER *TEImageHeader; + UINT8 *TEBuffer; + EFI_IMAGE_DOS_HEADER *DosHeader; + UINT8 FileGuidString[80]; + UINT32 TailSize; + EFI_FFS_FILE_TAIL TailValue; + + // + // Verify input parameters + // + if (FfsFile == NULL) { + return EFI_INVALID_PARAMETER; + } + // + // Convert the GUID to a string so we can at least report which file + // if we find an error. + // + PrintGuidToBuffer (&FfsFile->Name, FileGuidString, sizeof (FileGuidString), TRUE); + if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) { + TailSize = sizeof (EFI_FFS_FILE_TAIL); + } else { + TailSize = 0; + } + // + // Do some cursory checks on the FFS file contents + // + Status = VerifyFfsFile (FfsFile); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0, "file does not appear to be a valid FFS file, cannot be rebased", FileGuidString); + return EFI_INVALID_PARAMETER; + } + // + // Check if XIP file type. If not XIP, don't rebase. + // + if (FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE && + FfsFile->Type != EFI_FV_FILETYPE_PEIM && + FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE && + FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER + ) { + return EFI_SUCCESS; + } + // + // Rebase each PE32 section + // + Status = EFI_SUCCESS; + FoundCount = 0; + for (Index = 1;; Index++) { + Status = GetSectionByType (FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section); + if (EFI_ERROR (Status)) { + break; + } + + FoundCount++; + + // + // Calculate the PE32 base address, the FFS file base plus the offset of the PE32 section + // + NewPe32BaseAddress = ((UINT32) BaseAddress) + ((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER) - (UINTN) FfsFile); + + // + // Initialize context + // + memset (&ImageContext, 0, sizeof (ImageContext)); + ImageContext.Handle = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION)); + ImageContext.ImageRead = (EFI_PEI_PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead; + + Status = mPeCoffLoader.GetImageInfo (&mPeCoffLoader, &ImageContext); + + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0, "GetImageInfo() call failed on rebase", FileGuidString); + return Status; + } + // + // Allocate a buffer for the image to be loaded into. + // + Pe32ImageSize = GetLength (CurrentPe32Section.Pe32Section->CommonHeader.Size) - sizeof (EFI_PE32_SECTION); + MemoryImagePointer = (UINTN) (malloc (Pe32ImageSize + 0x1000)); + if (MemoryImagePointer == 0) { + Error (NULL, 0, 0, "memory allocation failure", NULL); + return EFI_OUT_OF_RESOURCES; + } + memset ((void *) MemoryImagePointer, 0, Pe32ImageSize + 0x1000); + MemoryImagePointerAligned = (MemoryImagePointer + 0x0FFF) & (-1 << 12); + + + ImageContext.ImageAddress = MemoryImagePointerAligned; + + Status = mPeCoffLoader.LoadImage (&mPeCoffLoader, &ImageContext); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0, "LoadImage() call failed on rebase", FileGuidString); + free ((VOID *) MemoryImagePointer); + return Status; + } + + ImageContext.DestinationAddress = NewPe32BaseAddress; + Status = mPeCoffLoader.RelocateImage (&mPeCoffLoader, &ImageContext); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0, "RelocateImage() call failed on rebase", FileGuidString); + free ((VOID *) MemoryImagePointer); + return Status; + } + + ImageAddress = ImageContext.ImageAddress; + ImageSize = ImageContext.ImageSize; + EntryPoint = ImageContext.EntryPoint; + + if (ImageSize > Pe32ImageSize) { + Error ( + NULL, + 0, + 0, + "rebased image is larger than original PE32 image", + "0x%X > 0x%X, file %s", + ImageSize, + Pe32ImageSize, + FileGuidString + ); + free ((VOID *) MemoryImagePointer); + return EFI_ABORTED; + } + // + // Since we may have updated the Codeview RVA, we need to insure the PE + // header indicates the image is large enough to contain the Codeview data + // so it will be loaded properly later if the PEIM is reloaded into memory... + // + PeHdr = (VOID *) ((UINTN) ImageAddress + ImageContext.PeCoffHeaderOffset); + if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) { + PeHdrSizeOfImage = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHdr->OptionalHeader).SizeOfImage); + PeHdrChecksum = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHdr->OptionalHeader).CheckSum); + } else if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) { + PeHdrSizeOfImage = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).SizeOfImage); + PeHdrChecksum = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).CheckSum); + } else if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_X64) { + PeHdrSizeOfImage = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).SizeOfImage); + PeHdrChecksum = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).CheckSum); + } else { + Error ( + NULL, + 0, + 0, + "unknown machine type in PE32 image", + "machine type=0x%X, file=%s", + (UINT32) PeHdr->FileHeader.Machine, + FileGuidString + ); + free ((VOID *) MemoryImagePointer); + return EFI_ABORTED; + } + + if (*PeHdrSizeOfImage != ImageContext.ImageSize) { + *PeHdrSizeOfImage = (UINT32) ImageContext.ImageSize; + if (*PeHdrChecksum) { + *PeHdrChecksum = 0; + } + } + + memcpy (CurrentPe32Section.Pe32Section + 1, (VOID *) MemoryImagePointerAligned, (UINT32) ImageSize); + + free ((VOID *) MemoryImagePointer); + + // + // Now update file checksum + // + if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) { + TailSize = sizeof (EFI_FFS_FILE_TAIL); + } else { + TailSize = 0; + } + + if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) { + SavedState = FfsFile->State; + FfsFile->IntegrityCheck.Checksum.File = 0; + FfsFile->State = 0; + if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) { + FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 ( + (UINT8 *) FfsFile, + GetLength (FfsFile->Size) - TailSize + ); + } else { + FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; + } + + FfsFile->State = SavedState; + } + // + // Update tail if present + // + if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) { + TailValue = (EFI_FFS_FILE_TAIL) (~(FfsFile->IntegrityCheck.TailReference)); + *(EFI_FFS_FILE_TAIL *) (((UINTN) FfsFile + GetLength (FfsFile->Size) - sizeof (EFI_FFS_FILE_TAIL))) = TailValue; + } + } + // + // Now process TE sections + // + for (Index = 1;; Index++) { + Status = GetSectionByType (FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section); + if (EFI_ERROR (Status)) { + break; + } + + FoundCount++; + + // + // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off + // by GenTEImage + // + TEImageHeader = (EFI_TE_IMAGE_HEADER *) ((UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER)); + + NewPe32BaseAddress = ((UINT32) BaseAddress) + + ( + (UINTN) CurrentPe32Section.Pe32Section + + sizeof (EFI_COMMON_SECTION_HEADER) + + sizeof (EFI_TE_IMAGE_HEADER) - + TEImageHeader->StrippedSize - + (UINTN) FfsFile + ); + + // + // Allocate a buffer to unshrink the image into. + // + Pe32ImageSize = GetLength (CurrentPe32Section.Pe32Section->CommonHeader.Size) - sizeof (EFI_PE32_SECTION) - + sizeof (EFI_TE_IMAGE_HEADER); + Pe32ImageSize += TEImageHeader->StrippedSize; + TEBuffer = (UINT8 *) malloc (Pe32ImageSize); + if (TEBuffer == NULL) { + Error (NULL, 0, 0, "failed to allocate memory", NULL); + return EFI_OUT_OF_RESOURCES; + } + // + // Expand the image into our buffer and fill in critical fields in the DOS header + // Fill in fields required by the loader. + // At offset 0x3C is the offset to the PE signature. We'll put it immediately following the offset value + // itself. + // + memset (TEBuffer, 0, Pe32ImageSize); + DosHeader = (EFI_IMAGE_DOS_HEADER *) TEBuffer; + DosHeader->e_magic = EFI_IMAGE_DOS_SIGNATURE; + *(UINT32 *) (TEBuffer + 0x3C) = 0x40; + PeHdr = (EFI_IMAGE_NT_HEADERS *) (TEBuffer + 0x40); + PeHdr->Signature = EFI_IMAGE_NT_SIGNATURE; + PeHdr->FileHeader.Machine = TEImageHeader->Machine; + PeHdr->FileHeader.NumberOfSections = TEImageHeader->NumberOfSections; + + // + // Say the size of the optional header is the total we stripped off less the size of a PE file header and PE signature and + // the 0x40 bytes for our DOS header. + // + PeHdr->FileHeader.SizeOfOptionalHeader = (UINT16) (TEImageHeader->StrippedSize - 0x40 - sizeof (UINT32) - sizeof (EFI_IMAGE_FILE_HEADER)); + PeHdr->OptionalHeader.ImageBase = (UINTN) (TEImageHeader->ImageBase - TEImageHeader->StrippedSize + sizeof (EFI_TE_IMAGE_HEADER)); + PeHdr->OptionalHeader.SizeOfImage = Pe32ImageSize; + PeHdr->OptionalHeader.Subsystem = TEImageHeader->Subsystem; + PeHdr->OptionalHeader.SizeOfImage = Pe32ImageSize; + PeHdr->OptionalHeader.SizeOfHeaders = TEImageHeader->StrippedSize + TEImageHeader->NumberOfSections * + sizeof (EFI_IMAGE_SECTION_HEADER) - 12; + + // + // Set NumberOfRvaAndSizes in the optional header to what we had available in the original image + // + if ((TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress != 0) || + (TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size != 0) + ) { + PeHdr->OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC + 1; + PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress = TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].VirtualAddress; + PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size = TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_BASERELOC].Size; + } + + if ((TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress != 0) || + (TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size != 0) + ) { + PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress = TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].VirtualAddress; + PeHdr->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_DEBUG].Size = TEImageHeader->DataDirectory[EFI_TE_IMAGE_DIRECTORY_ENTRY_DEBUG].Size; + if (PeHdr->OptionalHeader.NumberOfRvaAndSizes < EFI_IMAGE_DIRECTORY_ENTRY_DEBUG + 1) { + PeHdr->OptionalHeader.NumberOfRvaAndSizes = EFI_IMAGE_DIRECTORY_ENTRY_DEBUG + 1; + } + } + // + // NOTE: These values are defaults, and should be verified to be correct in the GenTE utility + // + PeHdr->OptionalHeader.SectionAlignment = 0x10; + + // + // Copy the rest of the image to its original offset + // + memcpy ( + TEBuffer + TEImageHeader->StrippedSize, + (UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) + sizeof (EFI_TE_IMAGE_HEADER), + GetLength (CurrentPe32Section.Pe32Section->CommonHeader.Size) - sizeof (EFI_PE32_SECTION) - + sizeof (EFI_TE_IMAGE_HEADER) + ); + + // + // Initialize context + // + memset (&ImageContext, 0, sizeof (ImageContext)); + ImageContext.Handle = (VOID *) TEBuffer; + ImageContext.ImageRead = (EFI_PEI_PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead; + + Status = mPeCoffLoader.GetImageInfo (&mPeCoffLoader, &ImageContext); + + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0, "GetImageInfo() call failed on rebase of TE image", FileGuidString); + free (TEBuffer); + return Status; + } + // + // Allocate a buffer for the image to be loaded into. + // + MemoryImagePointer = (UINTN) (malloc (Pe32ImageSize + 0x1000)); + if (MemoryImagePointer == 0) { + Error (NULL, 0, 0, "memory allocation error on rebase of TE image", FileGuidString); + free (TEBuffer); + return EFI_OUT_OF_RESOURCES; + } + memset ((void *) MemoryImagePointer, 0, Pe32ImageSize + 0x1000); + MemoryImagePointerAligned = (MemoryImagePointer + 0x0FFF) & (-1 << 12); + + + ImageContext.ImageAddress = MemoryImagePointerAligned; + Status = mPeCoffLoader.LoadImage (&mPeCoffLoader, &ImageContext); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0, "LoadImage() call failed on rebase of TE image", FileGuidString); + free (TEBuffer); + free ((VOID *) MemoryImagePointer); + return Status; + } + + ImageContext.DestinationAddress = NewPe32BaseAddress; + Status = mPeCoffLoader.RelocateImage (&mPeCoffLoader, &ImageContext); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0, "RelocateImage() call failed on rebase of TE image", FileGuidString); + free ((VOID *) MemoryImagePointer); + free (TEBuffer); + return Status; + } + + ImageAddress = ImageContext.ImageAddress; + ImageSize = ImageContext.ImageSize; + EntryPoint = ImageContext.EntryPoint; + + // + // Since we may have updated the Codeview RVA, we need to insure the PE + // header indicates the image is large enough to contain the Codeview data + // so it will be loaded properly later if the PEIM is reloaded into memory... + // + PeHdr = (VOID *) ((UINTN) ImageAddress + ImageContext.PeCoffHeaderOffset); + if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA32) { + PeHdrSizeOfImage = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHdr->OptionalHeader).SizeOfImage); + PeHdrChecksum = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER32 *) &PeHdr->OptionalHeader).CheckSum); + } else if (PeHdr->FileHeader.Machine == EFI_IMAGE_MACHINE_IA64) { + PeHdrSizeOfImage = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).SizeOfImage); + PeHdrChecksum = (UINT32 *) (&(*(EFI_IMAGE_OPTIONAL_HEADER64 *) &PeHdr->OptionalHeader).CheckSum); + } else { + Error ( + NULL, + 0, + 0, + "unknown machine type in TE image", + "machine type=0x%X, file=%s", + (UINT32) PeHdr->FileHeader.Machine, + FileGuidString + ); + free ((VOID *) MemoryImagePointer); + free (TEBuffer); + return EFI_ABORTED; + } + + if (*PeHdrSizeOfImage != ImageContext.ImageSize) { + *PeHdrSizeOfImage = (UINT32) ImageContext.ImageSize; + if (*PeHdrChecksum) { + *PeHdrChecksum = 0; + } + } + + TEImageHeader->ImageBase = (UINT64) (NewPe32BaseAddress + TEImageHeader->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER)); + memcpy ( + (UINT8 *) (CurrentPe32Section.Pe32Section + 1) + sizeof (EFI_TE_IMAGE_HEADER), + (VOID *) ((UINT8 *) MemoryImagePointerAligned + TEImageHeader->StrippedSize), + GetLength (CurrentPe32Section.Pe32Section->CommonHeader.Size) - sizeof (EFI_PE32_SECTION) - + sizeof (EFI_TE_IMAGE_HEADER) + ); + free ((VOID *) MemoryImagePointer); + free (TEBuffer); + if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) { + TailSize = sizeof (EFI_FFS_FILE_TAIL); + } else { + TailSize = 0; + } + // + // Now update file checksum + // + if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) { + SavedState = FfsFile->State; + FfsFile->IntegrityCheck.Checksum.File = 0; + FfsFile->State = 0; + if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) { + FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 ( + (UINT8 *) FfsFile, + GetLength (FfsFile->Size) - TailSize + ); + } else { + FfsFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; + } + + FfsFile->State = SavedState; + } + // + // Update tail if present + // + if (FfsFile->Attributes & FFS_ATTRIB_TAIL_PRESENT) { + TailValue = (EFI_FFS_FILE_TAIL) (~(FfsFile->IntegrityCheck.TailReference)); + *(EFI_FFS_FILE_TAIL *) (((UINTN) FfsFile + GetLength (FfsFile->Size) - sizeof (EFI_FFS_FILE_TAIL))) = TailValue; + } + } + // + // If we found no files, then emit an error if no compressed sections either + // + if (FoundCount == 0) { + Status = GetSectionByType (FfsFile, EFI_SECTION_COMPRESSION, Index, &CurrentPe32Section); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 0, "no PE32, TE, nor compressed section found in FV file", FileGuidString); + return EFI_NOT_FOUND; + } + } + + return EFI_SUCCESS; +} + +EFI_STATUS +FfsRebaseImageRead ( + 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; +} diff --git a/Tools/Source/TianoTools/PeiRebase/PeiRebaseExe.h b/Tools/Source/TianoTools/PeiRebase/PeiRebaseExe.h new file mode 100644 index 0000000000..9070d1ce1f --- /dev/null +++ b/Tools/Source/TianoTools/PeiRebase/PeiRebaseExe.h @@ -0,0 +1,153 @@ +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + + +Module Name: + + PeiRebaseExe.h + +Abstract: + + Definitions for the PeiRebase exe utility. + +--*/ + +#ifndef _EFI_PEIM_FIXUP_EXE_H +#define _EFI_PEIM_FIXUP_EXE_H + +#include "Efi2WinNt.h" +#include "EfiFirmwareFileSystem.h" +#include "EfiFirmwareVolumeHeader.h" + +// +// Utility Name +// +#define UTILITY_NAME "PeiRebase" + +// +// Utility version information +// +#define UTILITY_MAJOR_VERSION 0 +#define UTILITY_MINOR_VERSION 1 +#define UTILITY_DATE __DATE__ + +// +// The maximum number of arguments accepted from the command line. +// +#define MAX_ARGS 7 + +// +// The file copy buffer size +// +#define FILE_COPY_BUFFER_SIZE 512 + +// +// The function that displays general utility information +// +VOID +PrintUtilityInfo ( + VOID + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + None + +Returns: + + GC_TODO: add return values + +--*/ +; + +// +// The function that displays the utility usage message. +// +VOID +PrintUsage ( + VOID + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + None + +Returns: + + GC_TODO: add return values + +--*/ +; + +// +// Internal function declarations +// +EFI_STATUS +FfsRebaseImageRead ( + IN VOID *FileHandle, + IN UINTN FileOffset, + IN OUT UINT32 *ReadSize, + OUT VOID *Buffer + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + FileHandle - GC_TODO: add argument description + FileOffset - GC_TODO: add argument description + ReadSize - GC_TODO: add argument description + Buffer - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +EFI_STATUS +FfsRebase ( + IN OUT EFI_FFS_FILE_HEADER *FfsFile, + IN EFI_PHYSICAL_ADDRESS BaseAddress + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + FfsFile - GC_TODO: add argument description + BaseAddress - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +#endif diff --git a/Tools/Source/TianoTools/PeiRebase/makefile b/Tools/Source/TianoTools/PeiRebase/makefile new file mode 100644 index 0000000000..4b19309707 --- /dev/null +++ b/Tools/Source/TianoTools/PeiRebase/makefile @@ -0,0 +1,71 @@ +#/*++ +# +# Copyright (c) 2001 Intel Corporation. All rights reserved. +# +# This software and associated documentation (if any) is furnished under +# a license and may only be used or copied in accordance with the terms +# of the license. Except as permitted by such license, no part of this +# software or documentation may be reproduced, stored in a retrieval +# system, or transmitted in any form or by any means without the express +# written consent of Intel Corporation. +# +# Module Name: +# +# makefile +# +# Abstract: +# +# makefile for building the PeiRebase utility. +# +# Revision History +# +#--*/ + +# +# Make sure environmental variable EFI_SOURCE is set +# +!IFNDEF EFI_SOURCE +!ERROR EFI_SOURCE environmental variable not set +!ENDIF + +# +# Do this if you want to compile from this directory +# +!IFNDEF TOOLCHAIN +TOOLCHAIN = TOOLCHAIN_MSVC +!ENDIF + +!INCLUDE PlatformTools.env + +# +# Target specific information +# + +TARGET_NAME = PeiRebase +TARGET_SRC_DIR = $(TIANO_TOOLS_SOURCE)\$(TARGET_NAME) +TARGET_EXE = $(TIANO_TOOLS_OUTPUT)\PeiRebase.exe +TARGET_EXE_LIBS = $(TIANO_TOOLS_OUTPUT)\Common.lib + +# +# Build targets +# + +all: $(TARGET_EXE) + +OBJECTS = $(TIANO_TOOLS_OUTPUT)\PeiRebase.obj + +# +# Compile each source file +# +$(TIANO_TOOLS_OUTPUT)\PeiRebase.obj : $(TARGET_SRC_DIR)\PeiRebaseExe.c $(INC_DEPS) $(TARGET_EXE_LIBS) + $(CC) $(C_FLAGS) $(TARGET_SRC_DIR)\PeiRebaseExe.c /Fo$@ + +# +# Link the object files together +# +$(TARGET_EXE) : $(OBJECTS) $(TARGET_EXE_LIBS) + @echo LINKING + $(LINK) $(MSVS_LINK_LIBPATHS) $(L_FLAGS) $(LIBS) /out:$(TARGET_EXE) $(OBJECTS) $(TARGET_EXE_LIBS) + +clean: + @if exist $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).* del $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).* > NUL diff --git a/Tools/Source/TianoTools/SecApResetVectorFixup/Makefile b/Tools/Source/TianoTools/SecApResetVectorFixup/Makefile new file mode 100644 index 0000000000..53e6be5b70 --- /dev/null +++ b/Tools/Source/TianoTools/SecApResetVectorFixup/Makefile @@ -0,0 +1,58 @@ +#/*++ +# +# Copyright (c) 2005 Intel Corporation. All rights reserved. +# +# This software and associated documentation (if any) is furnished under +# a license and may only be used or copied in accordance with the terms +# of the license. Except as permitted by such license, no part of this +# software or documentation may be reproduced, stored in a retrieval +# system, or transmitted in any form or by any means without the express +# written consent of Intel Corporation. +# +# Module Name: makefile +# +# Abstract: +# +# This file is used to build the EFI utility. +# +#--*/ + +# +# Do this if you want to compile from this directory +# +!IFNDEF TOOLCHAIN +TOOLCHAIN = TOOLCHAIN_MSVC +!ENDIF + +!INCLUDE PlatformTools.env + +# +# Target specific information +# + +TARGET_NAME = SecApResetVectorFixup +TARGET_SOURCE_DIR = $(TIANO_TOOLS_SOURCE)\$(TARGET_NAME) +TARGET_EXE = $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).exe +TARGET_EXE_SOURCE = $(TARGET_SOURCE_DIR)\$(TARGET_NAME).c + +# +# Build targets +# + +all: $(TARGET_EXE) + +OBJECTS = $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).obj +LIBS = $(TIANO_TOOLS_OUTPUT)\Common.lib + +# +# Build EXE +# + +$(OBJECTS) : $(TARGET_EXE_SOURCE) $(INC_DEPS) + $(CC) $(C_FLAGS) $(TARGET_EXE_SOURCE) /Fo$@ + +$(TARGET_EXE): $(OBJECTS) + $(LINK) $(MSVS_LINK_LIBPATHS) $(L_FLAGS) $(OBJECTS) $(LIBS) /out:$(TARGET_EXE) + +clean: + @if exist $(EDK_TOOLS_OUTPUT)\$(TARGET_NAME).* del $(EDK_TOOLS_OUTPUT)\$(TARGET_NAME).* > NUL diff --git a/Tools/Source/TianoTools/SecApResetVectorFixup/SecApResetVectorFixup.c b/Tools/Source/TianoTools/SecApResetVectorFixup/SecApResetVectorFixup.c new file mode 100644 index 0000000000..5cb03f0398 --- /dev/null +++ b/Tools/Source/TianoTools/SecApResetVectorFixup/SecApResetVectorFixup.c @@ -0,0 +1,363 @@ +/*++ + +Copyright (c) 2005 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + + +Module Name: + + SecApResetVectorFixup.c + +Abstract: + + This utility is part of build process for IA32 Fvrecovery.fv whose total size + is larger than 128kB so that we cannot use GenFvImage utility to put Ap reset + vector at the zero vector of Fv header. + + PEI FV after using the tool + + ------------------------- + |zzz | + | | + | | + | FFS | + | | + | | + | | + |---------------------- | + | PAD | + | | + |.......................| --- + | | | + |xxx | | 128K + |---------------------- | | + | VTF (SEC) | | + ------------------------- --- + + 1. zzz --> Zero vector, which is beyond the 128K limited address space + 2. xxx --> AP reset vector at 4K alignment below 128K and it is in the PAD + file area. + 3. After the build process ,the PAD guid is changed to a new GUID to avoid + the PAD definition confusing. If there is some problem, try to disable + UpdatePadFileGuid + + + +--*/ + +#include "SecApResetVectorFixup.h" + + +EFI_GUID DefaultFvPadFileNameGuid = { 0x78f54d4, 0xcc22, 0x4048, 0x9e, 0x94, 0x87, 0x9c, 0x21, 0x4d, 0x56, 0x2f }; +EFI_GUID NewFvPadFileNameGuid = { 0x145372bc, 0x66b9, 0x476d, 0x81, 0xbc, 0x21, 0x27, 0xc3, 0x76, 0xbb, 0x66 }; + +// +// jmp 0xf000:0xffd0 (0xFFFFFFD0) +// +UINT8 ApResetVector[5] = {0xEA, 0xD0, 0xFF, 0x00, 0xF0}; + +VOID +PrintUtilityInfo ( + VOID + ) +/*++ + +Routine Description: + + Displays the standard utility information to SDTOUT + +Arguments: + + None + +Returns: + + None + +--*/ +{ + printf ( + "%s - Tiano IA32 SEC Ap Reset Vector Fixup Utility."" Version %i.%i\n\n", + UTILITY_NAME, + UTILITY_MAJOR_VERSION, + UTILITY_MINOR_VERSION + ); +} + +VOID +PrintUsage ( + VOID + ) +/*++ + +Routine Description: + + Displays the utility usage syntax to STDOUT + +Arguments: + + None + +Returns: + + None + +--*/ +{ + printf ("Usage: %s InputFvrecoveryFile OutputFvrecoveryFile\n", UTILITY_NAME); + printf (" Where:\n"); + printf ("\tInputFvrecoveryFile - Name of the IA32 input Fvrecovery.fv file.\n"); + printf ("\tOutputFvrecoveryFile - Name of the IA32 output Fvrecovery.fv file.\n"); +} + + +VOID +UpdatePadFileGuid ( + IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader, + IN EFI_FFS_FILE_HEADER *FileHeader, + IN UINT32 FileLength, + IN OUT EFI_GUID *Guid + ) +/*++ + +Routine Description: + + Update the Pad File Guid to change it to other guid and update + the checksum + +Arguments: + FvHeader - EFI_FIRMWARE_VOLUME_HEADER + FileHeader - The FFS PAD file header. + FileLength - The FFS PAD file length. + Guid - The Guid to compare and if it is PAD Guid, update it to new Guid +Returns: + VOID +--*/ + +{ + if ((CompareGuid (Guid, (EFI_GUID *)&DefaultFvPadFileNameGuid)) == 0) { + // + // Set new Pad file guid + // + memcpy (Guid, &NewFvPadFileNameGuid, sizeof (EFI_GUID)); + + + + FileHeader->Type = EFI_FV_FILETYPE_FFS_PAD; + FileHeader->Attributes = 0; + // + // Fill in checksums and state, must be zero during checksum calculation. + // + FileHeader->IntegrityCheck.Checksum.Header = 0; + FileHeader->IntegrityCheck.Checksum.File = 0; + FileHeader->State = 0; + FileHeader->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) FileHeader, sizeof (EFI_FFS_FILE_HEADER)); + if (FileHeader->Attributes & FFS_ATTRIB_CHECKSUM) { + FileHeader->IntegrityCheck.Checksum.File = CalculateChecksum8 ((UINT8 *) FileHeader, FileLength); + } else { + FileHeader->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; + } + + FileHeader->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID; + + if (FvHeader->Attributes & EFI_FVB_ERASE_POLARITY) { + FileHeader->State = (UINT8)~(FileHeader->State); + } + } + +} + + +STATUS +main ( + IN INTN argc, + IN CHAR8 **argv + ) +/*++ + +Routine Description: + + Main function. + +Arguments: + + argc - Number of command line parameters. + argv - Array of pointers to parameter strings. + +Returns: + STATUS_SUCCESS - Utility exits successfully. + STATUS_ERROR - Some error occurred during execution. + +--*/ +{ + FILE *FpIn; + FILE *FpOut; + UINT32 FvrecoveryFileSize; + UINT8 *FileBuffer; + UINT8 *FileBufferRaw; + UINT64 FvLength; + UINT32 Offset; + UINT32 FileLength; + UINT32 FileOccupiedSize; + EFI_FIRMWARE_VOLUME_HEADER *FvHeader; + EFI_FFS_FILE_HEADER *FileHeader; + EFI_GUID *TempGuid; + UINT8 *FixPoint; + UINT32 TempResult; + UINT32 Index; + UINT32 IpiVector; + + TempGuid = NULL; + SetUtilityName (UTILITY_NAME); + + // + // Display utility information + // + PrintUtilityInfo (); + + // + // Verify the correct number of arguments + // + if (argc != MAX_ARGS) { + Error (NULL, 0, 0, "invalid number of input parameters specified", NULL); + PrintUsage (); + return STATUS_ERROR; + } + // + // Open the Input Fvrecovery.fv file + // + if ((FpIn = fopen (argv[1], "rb")) == NULL) { + Error (NULL, 0, 0, "Unable to open file", argv[1]); + return STATUS_ERROR; + } + // + // Get the Input Fvrecovery.fv file size + // + fseek (FpIn, 0, SEEK_END); + FvrecoveryFileSize = ftell (FpIn); + // + // Read the contents of input file to memory buffer + // + FileBuffer = NULL; + FileBufferRaw = NULL; + FileBufferRaw = (UINT8 *) malloc (FvrecoveryFileSize + 0x10000); + if (NULL == FileBufferRaw) { + Error (NULL, 0, 0, "No sufficient memory to allocate!", NULL); + fclose (FpIn); + return STATUS_ERROR; + } + TempResult = 0x10000 - ((UINT32)FileBufferRaw & 0x0FFFF); + FileBuffer = (UINT8 *)((UINT32)FileBufferRaw + TempResult); + fseek (FpIn, 0, SEEK_SET); + TempResult = fread (FileBuffer, 1, FvrecoveryFileSize, FpIn); + if (TempResult != FvrecoveryFileSize) { + Error (NULL, 0, 0, "Read input file error!", NULL); + free ((VOID *)FileBufferRaw); + fclose (FpIn); + return STATUS_ERROR; + } + // + // Close the input Fvrecovery.fv file + // + fclose (FpIn); + // + // Find the pad FFS file + // + FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)FileBuffer; + FvLength = FvHeader->FvLength; + FileHeader = (EFI_FFS_FILE_HEADER *)(FileBuffer + FvHeader->HeaderLength); + FileLength = (*(UINT32 *)(FileHeader->Size)) & 0x00FFFFFF; + FileOccupiedSize = GETOCCUPIEDSIZE(FileLength, 8); + Offset = (UINT32)FileHeader - (UINT32)FileBuffer; + + while (Offset < FvLength) { + TempGuid = (EFI_GUID *)&(FileHeader->Name); + FileLength = (*(UINT32 *)(FileHeader->Size)) & 0x00FFFFFF; + FileOccupiedSize = GETOCCUPIEDSIZE(FileLength, 8); + if ((CompareGuid (TempGuid, (EFI_GUID *)&DefaultFvPadFileNameGuid)) == 0) { + break; + } + FileHeader = (EFI_FFS_FILE_HEADER *)((UINT32)FileHeader + FileOccupiedSize); + Offset = (UINT32)FileHeader - (UINT32)FileBuffer; + } + + if (Offset >= FvLength) { + Error (NULL, 0, 0, "No pad file found!", NULL); + free ((VOID *)FileBufferRaw); + return STATUS_ERROR; + } + // + // Find the position to place Ap reset vector, the offset + // between the position and the end of Fvrecovery.fv file + // should not exceed 128kB to prevent Ap reset vector from + // outside legacy E and F segment + // + FixPoint = (UINT8 *)(FileHeader + sizeof(EFI_FFS_FILE_HEADER)); + TempResult = 0x1000 - ((UINT32)FixPoint & 0x0FFF); + FixPoint +=TempResult; + if (((UINT32)FixPoint - (UINT32)FileHeader + 5) > FileOccupiedSize) { + Error (NULL, 0, 0, "No appropriate space in pad file to add Ap reset vector!", NULL); + free ((VOID *)FileBufferRaw); + return STATUS_ERROR; + } + while (((UINT32)FixPoint - (UINT32)FileHeader + 5) <= FileOccupiedSize) { + FixPoint += 0x1000; + } + FixPoint -= 0x1000; + if ((UINT32)FvHeader + FvLength - (UINT32)FixPoint > 0x20000) { + Error (NULL, 0, 0, "The position to place Ap reset vector is not in E and F segment!", NULL); + free ((VOID *)FileBufferRaw); + return STATUS_ERROR; + } + // + // Fix up Ap reset vector and calculate the IPI vector + // + for (Index = 0; Index < 5; Index++) { + FixPoint[Index] = ApResetVector[Index]; + } + TempResult = 0x0FFFFFFFF - ((UINT32)FvHeader + (UINT32)FvLength - 1 - (UINT32)FixPoint); + TempResult >>= 12; + IpiVector = TempResult & 0x0FF; + + + UpdatePadFileGuid (FvHeader, FileHeader, FileLength, TempGuid); + + // + // Open the output Fvrecovery.fv file + // + if ((FpOut = fopen (argv[2], "w+b")) == NULL) { + Error (NULL, 0, 0, "Unable to open file", argv[2]); + free ((VOID *)FileBufferRaw); + return STATUS_ERROR; + } + // + // Write the output Fvrecovery.fv file + // + if ((fwrite (FileBuffer, 1, FvrecoveryFileSize, FpOut)) != FvrecoveryFileSize) { + Error (NULL, 0, 0, "Write output file error!", NULL); + free ((VOID *)FileBufferRaw); + return STATUS_ERROR; + } + // + // + // + fseek (FpOut, -8, SEEK_END); + if ((fwrite (&IpiVector, 1, sizeof(UINT32), FpOut)) != sizeof(UINT32)) { + Error (NULL, 0, 0, "Write output file error!", NULL); + free ((VOID *)FileBufferRaw); + return STATUS_ERROR; + } + // + // Close the output Fvrecovery.fv file + // + fclose (FpOut); + free ((VOID *)FileBufferRaw); + return STATUS_SUCCESS; +} + diff --git a/Tools/Source/TianoTools/SecApResetVectorFixup/SecApResetVectorFixup.h b/Tools/Source/TianoTools/SecApResetVectorFixup/SecApResetVectorFixup.h new file mode 100644 index 0000000000..2bed5bc547 --- /dev/null +++ b/Tools/Source/TianoTools/SecApResetVectorFixup/SecApResetVectorFixup.h @@ -0,0 +1,102 @@ +/*++ + +Copyright (c) 2005 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + + +Module Name: + + SecApResetVectorFixup.h + +Abstract: + + Definitions for the SecApResetVectorFixup utility. + +--*/ + +#ifndef _SEC_AP_RESET_VECTOR_FIXUP_H +#define _SEC_AP_RESET_VECTOR_FIXUP_H + +#include +#include +#include "EfiCommon.h" +#include "EfiImage.h" +#include "EfiImageFormat.h" +#include "EfiFirmwareFileSystem.h" +#include "EfiFirmwareVolumeHeader.h" +#include "EfiUtilityMsgs.c" +#include "CommonLib.h" + + +// +// Utility Name +// +#define UTILITY_NAME "SecApResetVectorFixup" + +// +// Utility version information +// +#define UTILITY_MAJOR_VERSION 0 +#define UTILITY_MINOR_VERSION 1 +#define UTILITY_DATE __DATE__ + +// +// The maximum number of arguments accepted from the command line. +// +#define MAX_ARGS 3 +#define BUF_SIZE (8 * 1024) + +#define GETOCCUPIEDSIZE(ActualSize, Alignment) \ + (ActualSize) + (((Alignment) - ((ActualSize) & ((Alignment) - 1))) & ((Alignment) - 1)) + + +VOID +PrintUtilityInfo ( + VOID + ) +/*++ + +Routine Description: + + Displays the standard utility information to SDTOUT + +Arguments: + + None + +Returns: + + None + +--*/ +; + +VOID +PrintUsage ( + VOID + ) +/*++ + +Routine Description: + + Displays the utility usage syntax to STDOUT + +Arguments: + + None + +Returns: + + None + +--*/ +; + + +#endif diff --git a/Tools/Source/TianoTools/SecFixup/Makefile b/Tools/Source/TianoTools/SecFixup/Makefile new file mode 100644 index 0000000000..6ae2ebd31a --- /dev/null +++ b/Tools/Source/TianoTools/SecFixup/Makefile @@ -0,0 +1,57 @@ +#/*++ +# +# Copyright (c) 2001 Intel Corporation. All rights reserved. +# +# This software and associated documentation (if any) is furnished under +# a license and may only be used or copied in accordance with the terms +# of the license. Except as permitted by such license, no part of this +# software or documentation may be reproduced, stored in a retrieval +# system, or transmitted in any form or by any means without the express +# written consent of Intel Corporation. +# +# Module Name: makefile +# +# Abstract: +# +# This file is used to build the EFI utility. +# +#--*/ + +# +# Do this if you want to compile from this directory +# +!IFNDEF TOOLCHAIN +TOOLCHAIN = TOOLCHAIN_MSVC +!ENDIF + +!INCLUDE PlatformTools.env + +# +# Target specific information +# + +TARGET_NAME = SecFixup +TARGET_SOURCE_DIR = $(TIANO_TOOLS_SOURCE)\$(TARGET_NAME) +TARGET_EXE = $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).exe +TARGET_EXE_SOURCE = $(TARGET_SOURCE_DIR)\$(TARGET_NAME).c + +# +# Build targets +# + +all: $(TARGET_EXE) + +OBJECTS = $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).obj + +# +# Build EXE +# + +$(OBJECTS) : $(TARGET_EXE_SOURCE) $(INC_DEPS) + $(CC) $(C_FLAGS) $(TARGET_EXE_SOURCE) /Fo$@ + +$(TARGET_EXE): $(OBJECTS) + $(LINK) $(MSVS_LINK_LIBPATHS) $(L_FLAGS) $(OBJECTS) $(LIBS) /out:$(TARGET_EXE) + +clean: + @if exist $(EDK_TOOLS_OUTPUT)\$(TARGET_NAME).* del $(EDK_TOOLS_OUTPUT)\$(TARGET_NAME).* > NUL diff --git a/Tools/Source/TianoTools/SecFixup/SecFixup.c b/Tools/Source/TianoTools/SecFixup/SecFixup.c new file mode 100644 index 0000000000..a8e707fd16 --- /dev/null +++ b/Tools/Source/TianoTools/SecFixup/SecFixup.c @@ -0,0 +1,362 @@ +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + + +Module Name: + + SecFixup.c + +Abstract: + + This utility is part of build process for IA32 SEC FFS file. + + It fixup the reset vector data. The reset vector data binary file + will be wrapped as a RAW section and be located immediately after + the PE/TE section. + + The SEC EXE file can be either PE or TE file. + +--*/ + +#include + +#include "EfiCommon.h" +#include "EfiImage.h" +#include "EfiImageFormat.h" +#include "EfiUtilityMsgs.c" + +#include "SecFixup.h" + +VOID +PrintUtilityInfo ( + VOID + ) +/*++ + +Routine Description: + + Displays the standard utility information to SDTOUT + +Arguments: + + None + +Returns: + + None + +--*/ +{ + printf ( + "%s - Tiano IA32 SEC Fixup Utility."" Version %i.%i\n\n", + UTILITY_NAME, + UTILITY_MAJOR_VERSION, + UTILITY_MINOR_VERSION + ); +} + +VOID +PrintUsage ( + VOID + ) +/*++ + +Routine Description: + + Displays the utility usage syntax to STDOUT + +Arguments: + + None + +Returns: + + None + +--*/ +{ + printf ("Usage: %s SecExeFile ResetVectorDataFile OutputFile\n", UTILITY_NAME); + printf (" Where:\n"); + printf ("\tSecExeFile - Name of the IA32 SEC EXE file.\n"); + printf ("\tResetVectorDataFile - Name of the reset vector data binary file.\n"); + printf ("\tOutputFileName - Name of the output file.\n\n"); +} + +STATUS +main ( + IN INTN argc, + IN CHAR8 **argv + ) +/*++ + +Routine Description: + + Main function. + +Arguments: + + argc - Number of command line parameters. + argv - Array of pointers to parameter strings. + +Returns: + STATUS_SUCCESS - Utility exits successfully. + STATUS_ERROR - Some error occurred during execution. + +--*/ +{ + FILE *FpIn; + + FILE *FpOut; + UINT32 AddressOfEntryPoint; + INT32 DestRel; + STATUS Status; + UINT32 SecFileSize; + + SetUtilityName (UTILITY_NAME); + + // + // Display utility information + // + PrintUtilityInfo (); + + // + // Verify the correct number of arguments + // + if (argc != MAX_ARGS) { + Error (NULL, 0, 0, "invalid number of input parameters specified", NULL); + PrintUsage (); + return STATUS_ERROR; + } + // + // Open the SEC exe file + // + if ((FpIn = fopen (argv[1], "rb")) == NULL) { + Error (NULL, 0, 0, "Unable to open file", argv[1]); + return STATUS_ERROR; + } + // + // Get the entry point of the EXE file + // + Status = GetEntryPoint (FpIn, &AddressOfEntryPoint); + if (Status != STATUS_SUCCESS) { + fclose (FpIn); + return STATUS_ERROR; + } + // + // Get the SEC file size + // + fseek (FpIn, 0, SEEK_END); + SecFileSize = ftell (FpIn); + + // + // Close the SEC file + // + fclose (FpIn); + + // + // Open the reset vector data file + // + if ((FpIn = fopen (argv[2], "rb")) == NULL) { + Error (NULL, 0, 0, "Unable to open file", argv[2]); + return STATUS_ERROR; + } + // + // Open the output file + // + if ((FpOut = fopen (argv[3], "w+b")) == NULL) { + Error (NULL, 0, 0, "Unable to open file", argv[3]); + fclose (FpIn); + return STATUS_ERROR; + } + // + // Copy the input file to the output file + // + if (CopyFile (FpIn, FpOut) != STATUS_SUCCESS) { + fclose (FpIn); + fclose (FpOut); + return STATUS_ERROR; + } + // + // Close the reset vector data file + // + fclose (FpIn); + + // + // Fix the destination relative in the jmp instruction + // in the reset vector data structure + // + fseek (FpOut, -DEST_REL_OFFSET, SEEK_END); + DestRel = AddressOfEntryPoint - (SecFileSize + sizeof (EFI_COMMON_SECTION_HEADER) + (UINT32) (ftell (FpOut)) + 2); + if (DestRel <= -65536) { + Error (NULL, 0, 0, "The SEC EXE file size is too big", NULL); + fclose (FpOut); + return STATUS_ERROR; + } + + if (fwrite (&DestRel, sizeof (UINT16), 1, FpOut) != 1) { + Error (NULL, 0, 0, "Failed to write to the output file", NULL); + fclose (FpOut); + return STATUS_ERROR; + } + // + // Close the output file + // + fclose (FpOut); + + return STATUS_SUCCESS; +} + +STATUS +GetEntryPoint ( + IN FILE *ExeFile, + OUT UINT32 *EntryPoint + ) +/*++ + +Routine Description: + + Get the address of the entry point of a PE/TE file. + +Arguments: + + PeFile - File pointer to the specified PE/TE file. + EntryPoint - Buffer for the address of the entry point to be returned. + +Returns: + STATUS_SUCCESS - Function completed successfully. + STATUS_ERROR - Error occured. + +--*/ +// GC_TODO: ExeFile - add argument and description to function comment +{ + EFI_IMAGE_DOS_HEADER DosHeader; + EFI_IMAGE_NT_HEADERS32 NtHeader; + EFI_TE_IMAGE_HEADER TeHeader; + + // + // Check if it is a TE file + // + fseek (ExeFile, 0, SEEK_SET); + // + // Attempt to read the TE header + // + if (fread (&TeHeader, sizeof (TeHeader), 1, ExeFile) == 1) { + if (TeHeader.Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) { + if (TeHeader.Machine != EFI_IMAGE_MACHINE_IA32) { + Error (NULL, 0, 0, "The SEC file is PE but is not PE32 for IA32", NULL); + return STATUS_ERROR; + } + + *EntryPoint = TeHeader.AddressOfEntryPoint + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader.StrippedSize; + return STATUS_SUCCESS; + } + } + // + // Check if it is a PE file + // + fseek (ExeFile, 0, SEEK_SET); + // + // Attempt to read the DOS header + // + if (fread (&DosHeader, sizeof (DosHeader), 1, ExeFile) != 1) { + goto InvalidFile; + } + // + // Check the magic number + // + if (DosHeader.e_magic != EFI_IMAGE_DOS_SIGNATURE) { + goto InvalidFile; + } + // + // Position into the file and read the NT PE header + // + fseek (ExeFile, (long) DosHeader.e_lfanew, SEEK_SET); + if (fread (&NtHeader, sizeof (NtHeader), 1, ExeFile) != 1) { + goto InvalidFile; + } + // + // Check the PE signature in the header + // + if (NtHeader.Signature != EFI_IMAGE_NT_SIGNATURE) { + goto InvalidFile; + } + // + // Make sure the PE file is PE32 for IA32 + // + if (NtHeader.FileHeader.Machine != EFI_IMAGE_MACHINE_IA32 || + NtHeader.OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC + ) { + Error (NULL, 0, 0, "The SEC file is PE but is not PE32 for IA32", NULL); + return STATUS_ERROR; + } + // + // Get the entry point from the optional header + // + *EntryPoint = NtHeader.OptionalHeader.AddressOfEntryPoint; + return STATUS_SUCCESS; + +InvalidFile: + Error (NULL, 0, 0, "The SEC file is neither PE nor TE file", NULL); + return STATUS_ERROR; +} + +STATUS +CopyFile ( + FILE *FpIn, + FILE *FpOut + ) +/*++ + +Routine Description: + + Copy file. + +Arguments: + + FpIn - File pointer to the source file. + FpOut - File pointer to the destination file. + +Returns: + STATUS_SUCCESS - Function completed successfully. + STATUS_ERROR - Error occured. + +--*/ +{ + INTN FileSize; + + INTN Offset; + + INTN Length; + UINT8 Buffer[BUF_SIZE]; + + fseek (FpIn, 0, SEEK_END); + FileSize = ftell (FpIn); + + fseek (FpIn, 0, SEEK_SET); + fseek (FpOut, 0, SEEK_SET); + + Offset = 0; + while (Offset < FileSize) { + Length = sizeof (Buffer); + if (FileSize - Offset < Length) { + Length = FileSize - Offset; + } + + if (fread (Buffer, Length, 1, FpIn) != 1 || fwrite (Buffer, Length, 1, FpOut) != 1) { + Error (NULL, 0, 0, "Copy file error", NULL); + return STATUS_ERROR; + } + + Offset += Length; + } + + return STATUS_SUCCESS; +} diff --git a/Tools/Source/TianoTools/SecFixup/SecFixup.h b/Tools/Source/TianoTools/SecFixup/SecFixup.h new file mode 100644 index 0000000000..5571dc34a2 --- /dev/null +++ b/Tools/Source/TianoTools/SecFixup/SecFixup.h @@ -0,0 +1,146 @@ +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + + +Module Name: + + SecFixup.h + +Abstract: + + Definitions for the SecFixup utility. + +--*/ + +#ifndef _SEC_FIXUP_H +#define _SEC_FIXUP_H + +// +// Utility Name +// +#define UTILITY_NAME "SecFixup" + +// +// Utility version information +// +#define UTILITY_MAJOR_VERSION 0 +#define UTILITY_MINOR_VERSION 1 +#define UTILITY_DATE __DATE__ + +// +// The maximum number of arguments accepted from the command line. +// +#define MAX_ARGS 4 + +#define DEST_REL_OFFSET 13 +#define BUF_SIZE (8 * 1024) + +// +// The function that displays general utility information +// +VOID +PrintUtilityInfo ( + VOID + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + None + +Returns: + + GC_TODO: add return values + +--*/ +; + +// +// The function that displays the utility usage message. +// +VOID +PrintUsage ( + VOID + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + None + +Returns: + + GC_TODO: add return values + +--*/ +; + +// +// The function that gets the entry point of a PE/TE file. +// +STATUS +GetEntryPoint ( + IN FILE *ExeFile, + OUT UINT32 *EntryPoint + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + ExeFile - GC_TODO: add argument description + EntryPoint - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +// +// The function that copies a file. +// +STATUS +CopyFile ( + FILE *FpIn, + FILE *FpOut + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + FpIn - GC_TODO: add argument description + FpOut - GC_TODO: add argument description + +Returns: + + GC_TODO: add return values + +--*/ +; + +#endif diff --git a/Tools/Source/TianoTools/SplitFile/Makefile b/Tools/Source/TianoTools/SplitFile/Makefile new file mode 100644 index 0000000000..3cd45f9b2d --- /dev/null +++ b/Tools/Source/TianoTools/SplitFile/Makefile @@ -0,0 +1,70 @@ +#/*++ +# +# Copyright (c) 2001 Intel Corporation. All rights reserved. +# +# This software and associated documentation (if any) is furnished under +# a license and may only be used or copied in accordance with the terms +# of the license. Except as permitted by such license, no part of this +# software or documentation may be reproduced, stored in a retrieval +# system, or transmitted in any form or by any means without the express +# written consent of Intel Corporation. +# +# Module Name: makefile +# +# Abstract: +# +# This file is used to build the EFI utility. +# +#--*/ + +# +# Do this if you want to compile from this directory +# +!IFNDEF TOOLCHAIN +TOOLCHAIN = TOOLCHAIN_MSVC +!ENDIF + +!INCLUDE PlatformTools.env + +# +# Define some macros we use here. Should get rid of them someday and +# get rid of the extra level of indirection. +# +COMMON_SOURCE = $(EDK_TOOLS_COMMON) + +# +# Common information +# + +INC=$(INC) + +# +# Target specific information +# + +TARGET_NAME=SplitFile +TARGET_SOURCE_DIR = $(TIANO_TOOLS_SOURCE)\$(TARGET_NAME) + +TARGET_EXE = $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).exe + +TARGET_EXE_SOURCE = "$(TARGET_SOURCE_DIR)\SplitFile.c" +TARGET_EXE_INCLUDE = + +# +# Build targets +# + +all: $(TARGET_EXE) + +# +# Build EXE +# + +$(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).obj: $(TARGET_EXE_SOURCE) $(TARGET_EXE_INCLUDE) + $(CC) $(C_FLAGS) $(INC) $(TARGET_EXE_SOURCE) /Fo$(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).obj + +$(TARGET_EXE): $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).obj $(TARGET_EXE_LIBS) $(TARGET_DLL) + $(LINK) $(MSVS_LINK_LIBPATHS) $(L_FLAGS) $(LIBS) /out:$(TARGET_EXE) $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).obj $(TARGET_LIB) $(TARGET_EXE_LIBS) + +clean: + @if exist $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).* del $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).* > NUL diff --git a/Tools/Source/TianoTools/SplitFile/SplitFile.c b/Tools/Source/TianoTools/SplitFile/SplitFile.c new file mode 100644 index 0000000000..b1af1a8a6e --- /dev/null +++ b/Tools/Source/TianoTools/SplitFile/SplitFile.c @@ -0,0 +1,131 @@ +/* + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + +*/ + +// GC_TODO: fix comment to start with /*++ +#include "stdio.h" +#include "string.h" +#include "stdlib.h" + +void +helpmsg ( + void + ) +/*++ + +Routine Description: + + GC_TODO: Add function description + +Arguments: + + +Returns: + + GC_TODO: add return values + +--*/ +{ + printf ( + "SplitFile Filename Offset\n"" Filename = Input file to split\n"" Offset = offset at which to split file\n" + "\n\n""SplitFile will break a file in two pieces at the requested offset\n" + " outputting Filename1 and Filename2\n" + ); +} + +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 *In; + + FILE *Out1; + + FILE *Out2; + char OutName1[512]; + char OutName2[512]; + unsigned long Index; + unsigned long splitpoint; + char CharC; + + if (argc != 3) { + helpmsg (); + return -1; + } + + In = fopen (argv[1], "rb"); + if (In == NULL) { + printf ("Unable to open file \"%s\"\n", argv[1]); + return -1; + } + + strncpy (OutName1, argv[1], 510); + strncpy (OutName2, argv[1], 510); + strcat (OutName1, "1"); + strcat (OutName2, "2"); + + Out1 = fopen (OutName1, "wb"); + if (Out1 == NULL) { + printf ("Unable to open file \"%s\"\n", OutName1); + return -1; + } + + Out2 = fopen (OutName2, "wb"); + if (Out2 == NULL) { + printf ("Unable to open file \"%s\"\n", OutName2); + return -1; + } + + splitpoint = atoi (argv[2]); + + for (Index = 0; Index < splitpoint; Index++) { + CharC = (char) fgetc (In); + if (feof (In)) { + break; + } + + fputc (CharC, Out1); + } + + for (;;) { + CharC = (char) fgetc (In); + if (feof (In)) { + break; + } + + fputc (CharC, Out2); + } + + fclose (In); + fclose (Out1); + fclose (Out2); + + return 0; +} diff --git a/Tools/Source/TianoTools/Strip/Makefile b/Tools/Source/TianoTools/Strip/Makefile new file mode 100644 index 0000000000..f47a68fa5b --- /dev/null +++ b/Tools/Source/TianoTools/Strip/Makefile @@ -0,0 +1,70 @@ +#/*++ +# +# Copyright (c) 2001 Intel Corporation. All rights reserved. +# +# This software and associated documentation (if any) is furnished under +# a license and may only be used or copied in accordance with the terms +# of the license. Except as permitted by such license, no part of this +# software or documentation may be reproduced, stored in a retrieval +# system, or transmitted in any form or by any means without the express +# written consent of Intel Corporation. +# +# Module Name: makefile +# +# Abstract: +# +# This file is used to build the EFI utility. +# +#--*/ + +# +# Do this if you want to compile from this directory +# +!IFNDEF TOOLCHAIN +TOOLCHAIN = TOOLCHAIN_MSVC +!ENDIF + +!INCLUDE PlatformTools.env + +# +# Define some macros we use here. Should get rid of them someday and +# get rid of the extra level of indirection. +# +COMMON_SOURCE = $(EDK_TOOLS_COMMON) + +# +# Common information +# + +INC=$(INC) + +# +# Target specific information +# + +TARGET_NAME=Strip +TARGET_SOURCE_DIR = $(TIANO_TOOLS_SOURCE)\$(TARGET_NAME) + +TARGET_EXE = $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).exe + +TARGET_EXE_SOURCE = "$(TARGET_SOURCE_DIR)\Strip.c" +TARGET_EXE_INCLUDE = + +# +# Build targets +# + +all: $(TARGET_EXE) + +# +# Build EXE +# + +$(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).obj: $(TARGET_EXE_SOURCE) $(TARGET_EXE_INCLUDE) + $(CC) $(C_FLAGS) $(INC) $(TARGET_EXE_SOURCE) /Fo$(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).obj + +$(TARGET_EXE): $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).obj $(TARGET_EXE_LIBS) $(TARGET_DLL) + $(LINK) $(MSVS_LINK_LIBPATHS) $(L_FLAGS) $(LIBS) /out:$(TARGET_EXE) $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).obj $(TARGET_LIB) $(TARGET_EXE_LIBS) + +clean: + @if exist $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).* del $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).* > NUL diff --git a/Tools/Source/TianoTools/Strip/Strip.c b/Tools/Source/TianoTools/Strip/Strip.c new file mode 100644 index 0000000000..3fd6ad7d46 --- /dev/null +++ b/Tools/Source/TianoTools/Strip/Strip.c @@ -0,0 +1,105 @@ +/*++ + +Copyright (c) 1999 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + + +Module Name: + + Strip.c + +Abstract: + + Quick Exe2Bin equivalent. + +--*/ + +#include +#include +#include +#include + +int +main ( + int argc, + char *argv[] + ) +/*++ + +Routine Description: + + Converts executable files to binary files. + +Arguments: + + argc - Number of command line arguments + argv[] - Array of pointers to the command line arguments + +Returns: + + Zero - Function completed successfully. + Non-zero - Function exited with errors. + +--*/ +{ + FILE *InFile; + FILE *OutFile; + int Index; + int FileSize; + char *Buffer; + char *Ptrx; + + if (argc < 3) { + printf ("Need more args, such as file name to convert and output name\n"); + return -1; + } + + InFile = fopen (argv[1], "rb"); + OutFile = fopen (argv[2], "wb"); + + if (!InFile) { + printf ("no file, exit\n"); + return -1; + } + + if (OutFile == NULL) { + printf ("Unable to open output file.\n"); + return -1; + } + + fseek (InFile, 0, SEEK_END); + FileSize = ftell (InFile); + + if (FileSize < 0x200) { + printf ("%d is not a legal size, exit\n", FileSize); + return -1; + } + + fseek (InFile, 0, SEEK_SET); + + Buffer = malloc (FileSize); + if (Buffer == NULL) { + printf ("Error: Out of resources.\n"); + return -1; + } + + fread (Buffer, 1, FileSize, InFile); + + Ptrx = Buffer + 0x200; + + Index = FileSize - 0x200; + + fwrite (Ptrx, Index, 1, OutFile); + + fclose (InFile); + fclose (OutFile); + free (Buffer); + + return 0; +} diff --git a/Tools/Source/TianoTools/ZeroDebugData/Makefile b/Tools/Source/TianoTools/ZeroDebugData/Makefile new file mode 100644 index 0000000000..c20fd85d8c --- /dev/null +++ b/Tools/Source/TianoTools/ZeroDebugData/Makefile @@ -0,0 +1,63 @@ +#/*++ +# +# Copyright (c) 2001 Intel Corporation +# +# Module Name: makefile +# +# Abstract: +# +# This file is used to build the EFI utility. +# +#--*/ + +# +# Do this if you want to compile from this directory +# +!IFNDEF TOOLCHAIN +TOOLCHAIN = TOOLCHAIN_MSVC +!ENDIF + +!INCLUDE PlatformTools.env + +# +# Define some macros we use here. Should get rid of them someday and +# get rid of the extra level of indirection. +# +COMMON_SOURCE = $(EDK_TOOLS_COMMON) + +# +# Common information +# + +INC=$(INC) + +# +# Target specific information +# + +TARGET_NAME=ZeroDebugData +TARGET_SOURCE_DIR = $(TIANO_TOOLS_SOURCE)\$(TARGET_NAME) + +TARGET_EXE = $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).exe + +TARGET_EXE_SOURCE = "$(TARGET_SOURCE_DIR)\ZeroDebugData.c" +TARGET_EXE_INCLUDE = + +# +# Build targets +# + +all: $(TARGET_EXE) + +# +# Build EXE +# + +$(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).obj: $(TARGET_EXE_SOURCE) + $(CC) $(C_FLAGS) $(INC) $(TARGET_EXE_SOURCE) /Fo$(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).obj + +$(TARGET_EXE): $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).obj $(TARGET_EXE_LIBS) $(TARGET_DLL) + $(LINK) $(MSVS_LINK_LIBPATHS) $(L_FLAGS) $(LIBS) /out:$(TARGET_EXE) $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).obj $(TARGET_LIB) $(TARGET_EXE_LIBS) + +clean: + @if exist $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).* del $(TIANO_TOOLS_OUTPUT)\$(TARGET_NAME).* diff --git a/Tools/Source/TianoTools/ZeroDebugData/ZeroDebugData.c b/Tools/Source/TianoTools/ZeroDebugData/ZeroDebugData.c new file mode 100644 index 0000000000..2f2003956a --- /dev/null +++ b/Tools/Source/TianoTools/ZeroDebugData/ZeroDebugData.c @@ -0,0 +1,390 @@ +/*++ + +Copyright (c) 2001 - 2002 Intel Corporation. All rights reserved +This software and associated documentation (if any) is furnished +under a license and may only be used or copied in accordance +with the terms of the license. Except as permitted by such +license, no part of this software or documentation may be +reproduced, stored in a retrieval system, or transmitted in any +form or by any means without the express written consent of +Intel Corporation. + + +Module Name: + ZeroDebugData.c + +Abstract: + Zero the Debug Data Fields of Portable Executable (PE) format file. + +--*/ + +#include +#include +#include +#include + +void +PrintUsage ( + void + ) +/*++ +Routine Description: + print usage of ZeroDebugData command + +Arguments: + None + +Returns: + None +--*/ +// GC_TODO: void - add argument and description to function comment +{ + // + // print usage of command + // + printf ("\nUsage: ZeroDebugData [DebugData-File]\n"); +} + +int +ReadFromFile ( + FILE *fp, + long offset, + void *buffer, + int size + ) +/*++ +Routine Description: + read data from a specified location of file + +Arguments: + fp - file pointer + offset - number of bytes from beginning of file + buffer - buffer used to store data + size - size of buffer + +Returns: + = 0 - Success + = -1 - Failed +--*/ +{ + // + // set file pointer to the specified location of file + // + if (fseek (fp, offset, SEEK_SET) != 0) { + printf ("Error: Cannot move the current location of the file.\n"); + return -1; + } + // + // read data from the file + // + if (fread (buffer, size, 1, fp) != 1) { + printf ("Error: Cannot read data from the file.\n"); + return -1; + } + + return 0; +} + +int +ZeroDebugData ( + FILE *fp, + FILE *fpData + ) +/*++ + +Routine Description: + + Zero the debug data fields of the file + +Arguments: + + fp - file pointer + fpData - pointer to output file that ZeroDebugData progress is written to + +Returns: + + = 0 - Success + = -1 - Failed + +--*/ +{ + unsigned char header[4]; + unsigned long offset; + unsigned long NumberOfRvaAndSizes; + unsigned int nvalue; + unsigned long lvalue; + unsigned long Size; + unsigned long Pointer; + unsigned char *Buffer; + unsigned long Index; + + // + // read the header of file + // + if (ReadFromFile (fp, 0, header, 2) != 0) { + printf ("Error: open image file\n"); + return -1; + } + // + // "MZ" -- the header of image file (PE) + // + if (strncmp ((char *) header, "MZ", 2) != 0) { + printf ("Error: Invalid Image file.\n"); + return -1; + } + // + // At location 0x3C, the stub has the file offset to the + // PE signature. + // + if (ReadFromFile (fp, 0x3C, &offset, 4) != 0) { + return -1; + } + // + // read the header of optional + // + if (ReadFromFile (fp, offset, header, 4) != 0) { + return -1; + } + // + // "PE\0\0" -- the signature of optional header + // + if (strncmp ((char *) header, "PE\0\0", 4) != 0) { + printf ("Error: Invalid PE format file.\n"); + return -1; + } + // + // Add 16 to skip COFF file header, and get to optional header. + // + offset += 24; + + // + // Check the magic field, 0x10B for PE32 and 0x20B for PE32+ + // + if (ReadFromFile (fp, offset, &nvalue, 2) != 0) { + return -1; + } + // + // If this is PE32 image file, offset of NumberOfRvaAndSizes is 92. + // Else it is 108. + // + switch (nvalue & 0xFFFF) { + case 0x10B: + offset += 92; + printf ("Info: Image is PE32. "); + break; + + case 0x20B: + offset += 108; + printf ("Info: Image is PE32+. "); + break; + + default: + printf ("Error: Magic value is unknown.\n"); + return -1; + } + // + // get the value of NumberOfRvaAndSizes + // + if (ReadFromFile (fp, offset, &NumberOfRvaAndSizes, 4) != 0) { + printf ("Error: read NumberOfRvaAndSizes error.\n"); + return -1; + } + // + // printf ("Info: NumberOfRvaAndSizes = %d\n", NumberOfRvaAndSizes); + // + // + // Finding Debug Table, offset of Debug Table + // is 4 + 6 * 8 = 52. + // + if (NumberOfRvaAndSizes >= 7) { + if (ReadFromFile (fp, offset + 52, &lvalue, 4) != 0) { + return -1; + } + // + // Read the SizeOfData(16) and PointerToRawData(24) + // + if (ReadFromFile (fp, lvalue + 16, &Size, 4) != 0) { + printf ("error: Size = %d\n", Size); + return -1; + } + + printf ("Debug data: size = %xh, ", Size); + fprintf (fpData, "Debug data: size = %xh, ", Size); + + if (ReadFromFile (fp, lvalue + 20, &Pointer, 4) != 0) { + printf ("error: LoadOffset = %xh\n", Pointer); + return -1; + } + // + // printf ("LoadOffset = %xh, ", Pointer); + // + fprintf (fpData, "LoadOffset = %xh, ", Pointer); + + if (ReadFromFile (fp, lvalue + 24, &Pointer, 4) != 0) { + printf ("error: FileOffset = %xh\n", Pointer); + return -1; + } + + printf ("FileOffset = %xh, ", Pointer); + fprintf (fpData, "FileOffset = %xh, \n", Pointer); + + if ((lvalue != 0) && (Pointer != 0)) { + // + // prepare buffer + // + Buffer = malloc (Size + 1); + if (Buffer == NULL) { + printf ("Error: Cannot allocate memory.\n"); + return -1; + } + // + // set file pointer to the specified location of file + // + if (fseek (fp, Pointer, SEEK_SET) != 0) { + printf ("Error: Cannot move the current location of the file.\n"); + free (Buffer); + return -1; + } + // + // read data from PE file + // + if (fread (Buffer, Size, 1, fp) != 1) { + printf ("Error: Cannot read data from the file.\n"); + free (Buffer); + return -1; + } + // + // write to data file + // + for (Index = 0; Index < Size;) { + fprintf (fpData, "%02x ", Buffer[Index]); + + Index++; + if (Index % 8 == 0) { + fprintf (fpData, "\n"); + } + } + + fprintf (fpData, "\n"); + + // + // zero buffer and write back to PE file + // + if (fseek (fp, Pointer, SEEK_SET) != 0) { + printf ("Error: Cannot move the current location of the file.\n"); + free (Buffer); + return -1; + } + + memset (Buffer, 0, Size); + if (fwrite (Buffer, Size, 1, fp) != 1) { + perror ("Error: Cannot write zero to the file.\n"); + free (Buffer); + return -1; + } + // + // set file pointer to the specified location of file + // + if (fseek (fp, lvalue + 4, SEEK_SET) != 0) { + printf ("Error: Cannot move the current location of the file.\n"); + free (Buffer); + return -1; + } + + if (fwrite (Buffer, 4, 1, fp) != 1) { + perror ("Error: Cannot write zero to the file.\n"); + free (Buffer); + return -1; + } + + free (Buffer); + } + } + + return 0; +} + +int +main ( + int argc, + char *argv[] + ) +/*++ + +Routine Description: + + Prints the zero debug data of the PE file to the DebugData file. + Executes the ZeroDebugData function. + +Arguments: + + argc - Standard C argument, number of command line arguments. + argv[] - Standard C argument, array of pointers to the input files, + such as the PE and DebugData files. + +Returns: + + zero - success + nonzero - failure + +--*/ +{ + FILE *fp; + FILE *fpData; + char DataFile[1024] = ""; + + // + // check the number of parameters + // + if (argc < 2) { + printf ("\nUsage: ZeroDebugData [DebugData-File]\n"); + return -1; + } + // + // open the DebugData file, if not exists, return + // + if (argc >= 3) { + strcpy (DataFile, argv[2]); + } else { + strcpy (DataFile, "DebugData.dat"); + } + + fpData = fopen (DataFile, "a+"); + if (fpData == NULL) { + fpData = fopen (DataFile, "w"); + if (fpData == NULL) { + printf ("Error: Cannot open the data file!\n"); + return -1; + } + } + // + // open the PE file + // + fp = fopen (argv[1], "r+b"); + if (fp == NULL) { + printf ("Error: Cannot open the PE file!\n"); + return -1; + } + // + // Zero the Debug Data to the PE file + // + printf ("Zero Debug Data to file %s:\n", argv[1]); + fprintf (fpData, "\nZero Debug Data to file %s:\n", argv[1]); + if ((int *) ZeroDebugData (fp, fpData) != 0) { + printf ("Error: Zero Debug Data PE file\n"); + fclose (fp); + return -1; + } + + printf (" success\n"); + + // + // close the PE file + // + fflush (fpData); + fflush (fp); + fclose (fpData); + fclose (fp); + + return 0; +}