blob: ce20157795a0d03111186780fc0b6d75a45b7194 [file] [log] [blame]
/*++
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 <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
#include <UefiBaseTypes.h>
#include <Base.h>
#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]);
}
}