]> git.proxmox.com Git - mirror_edk2.git/blobdiff - Tools/Source/TianoTools/FlashMap/FlashMap.c
Adding Additional Tools that are needed for Platform Image creation.
[mirror_edk2.git] / Tools / Source / TianoTools / FlashMap / FlashMap.c
diff --git a/Tools/Source/TianoTools/FlashMap/FlashMap.c b/Tools/Source/TianoTools/FlashMap/FlashMap.c
new file mode 100644 (file)
index 0000000..86e26b6
--- /dev/null
@@ -0,0 +1,745 @@
+/*++\r
+\r
+Copyright (c)  2004-2005 Intel Corporation. All rights reserved\r
+This software and associated documentation (if any) is furnished\r
+under a license and may only be used or copied in accordance\r
+with the terms of the license. Except as permitted by such\r
+license, no part of this software or documentation may be\r
+reproduced, stored in a retrieval system, or transmitted in any\r
+form or by any means without the express written consent of\r
+Intel Corporation.\r
+\r
+Module Name:\r
+\r
+  FlashMap.c\r
+\r
+Abstract:\r
+\r
+  Utility for flash management in the Intel Platform Innovation Framework\r
+  for EFI build environment.\r
+\r
+--*/\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <stdlib.h>\r
+#include <ctype.h>\r
+\r
+#include "Tiano.h"\r
+\r
+#ifndef INT8\r
+#define INT8  char\r
+#endif\r
+\r
+#include "EfiUtilityMsgs.h"\r
+#include "Microcode.h"\r
+#include "FlashDefFile.h"\r
+#include "Symbols.h"\r
+\r
+#define UTILITY_NAME  "FlashMap"\r
+\r
+typedef struct _STRING_LIST {\r
+  struct _STRING_LIST *Next;\r
+  char                *Str;\r
+} STRING_LIST;\r
+\r
+//\r
+// Keep our globals in one of these structures\r
+//\r
+static struct {\r
+  char          *CIncludeFileName;\r
+  char          *FlashDevice;\r
+  char          *FlashDeviceImage;\r
+  char          *MCIFileName;\r
+  char          *MCOFileName;\r
+  char          *ImageOutFileName;\r
+  char          *DscFileName;\r
+  char          *AsmIncludeFileName;\r
+  char          *FlashDefinitionFileName;\r
+  char          *StringReplaceInFileName;\r
+  char          *StringReplaceOutFileName;\r
+  char          *DiscoverFDImageName;\r
+  char          MicrocodePadByteValue;\r
+  unsigned int  MicrocodeAlignment;\r
+  STRING_LIST   *MCIFileNames;\r
+  STRING_LIST   *LastMCIFileNames;\r
+  unsigned int  BaseAddress;\r
+} mGlobals;\r
+\r
+#define DEFAULT_MC_PAD_BYTE_VALUE 0xFF\r
+#define DEFAULT_MC_ALIGNMENT      16\r
+\r
+static\r
+STATUS\r
+ProcessCommandLine (\r
+  int     argc,\r
+  char    *argv[]\r
+  );\r
+\r
+static\r
+STATUS\r
+MergeMicrocodeFiles (\r
+  char            *OutFileName,\r
+  STRING_LIST     *FileNames,\r
+  unsigned int    Alignment,\r
+  char            PadByteValue\r
+  );\r
+\r
+static\r
+void\r
+Usage (\r
+  VOID\r
+  );\r
+\r
+int\r
+main (\r
+  int   argc,\r
+  char  *argv[]\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Parse the command line arguments and then call worker functions to do the work\r
+  \r
+Arguments:\r
+  argc      - number of elements in argv\r
+  argv      - array of command-line arguments\r
+\r
+Returns:\r
+  STATUS_SUCCESS    - no problems encountered while processing\r
+  STATUS_WARNING    - warnings, but no errors, were encountered while processing\r
+  STATUS_ERROR      - errors were encountered while processing\r
+  \r
+--*/\r
+{\r
+  STATUS  Status;\r
+\r
+  SetUtilityName (UTILITY_NAME);\r
+  Status = ProcessCommandLine (argc, argv);\r
+  if (Status != STATUS_SUCCESS) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Check for discovery of an FD (command line option)\r
+  //\r
+  if (mGlobals.DiscoverFDImageName != NULL) {\r
+    Status = FDDiscover (mGlobals.DiscoverFDImageName, mGlobals.BaseAddress);\r
+    goto Done;\r
+  }\r
+  //\r
+  // If they're doing microcode file parsing, then do that\r
+  //\r
+  if (mGlobals.MCIFileName != NULL) {\r
+    MicrocodeConstructor ();\r
+    MicrocodeParseFile (mGlobals.MCIFileName, mGlobals.MCOFileName);\r
+    MicrocodeDestructor ();\r
+  }\r
+  //\r
+  // If they're doing microcode file merging, then do that now\r
+  //\r
+  if (mGlobals.MCIFileNames != NULL) {\r
+    MergeMicrocodeFiles (\r
+      mGlobals.MCOFileName,\r
+      mGlobals.MCIFileNames,\r
+      mGlobals.MicrocodeAlignment,\r
+      mGlobals.MicrocodePadByteValue\r
+      );\r
+  }\r
+  //\r
+  // If using a flash definition file, then process that and return\r
+  //\r
+  if (mGlobals.FlashDefinitionFileName != NULL) {\r
+    FDFConstructor ();\r
+    SymbolsConstructor ();\r
+    Status = FDFParseFile (mGlobals.FlashDefinitionFileName);\r
+    if (GetUtilityStatus () != STATUS_ERROR) {\r
+      //\r
+      // If they want us to do a string-replace on a file, then add the symbol definitions to\r
+      // the symbol table, and then do the string replace.\r
+      //\r
+      if (mGlobals.StringReplaceInFileName != NULL) {\r
+        Status  = FDFCreateSymbols (mGlobals.FlashDevice);\r
+        Status  = SymbolsFileStringsReplace (mGlobals.StringReplaceInFileName, mGlobals.StringReplaceOutFileName);\r
+      }\r
+      //\r
+      // If they want us to create a .h defines file or .c flashmap data file, then do so now\r
+      //\r
+      if (mGlobals.CIncludeFileName != NULL) {\r
+        Status = FDFCreateCIncludeFile (mGlobals.FlashDevice, mGlobals.CIncludeFileName);\r
+      }\r
+      if (mGlobals.AsmIncludeFileName != NULL) {\r
+        Status = FDFCreateAsmIncludeFile (mGlobals.FlashDevice, mGlobals.AsmIncludeFileName);\r
+      }\r
+      //\r
+      // If they want us to create an image, do that now\r
+      //\r
+      if (mGlobals.ImageOutFileName != NULL) {\r
+        Status = FDFCreateImage (mGlobals.FlashDevice, mGlobals.FlashDeviceImage, mGlobals.ImageOutFileName);\r
+      }\r
+      //\r
+      // If they want to create an output DSC file, do that now\r
+      //\r
+      if (mGlobals.DscFileName != NULL) {\r
+        Status = FDFCreateDscFile (mGlobals.FlashDevice, mGlobals.DscFileName);\r
+      }\r
+    }\r
+    SymbolsDestructor ();\r
+    FDFDestructor ();\r
+  }\r
+Done:\r
+  //\r
+  // Free up memory\r
+  //\r
+  while (mGlobals.MCIFileNames != NULL) {\r
+    mGlobals.LastMCIFileNames = mGlobals.MCIFileNames->Next;\r
+    _free (mGlobals.MCIFileNames);\r
+    mGlobals.MCIFileNames = mGlobals.LastMCIFileNames;\r
+  }\r
+  return GetUtilityStatus ();\r
+}\r
+\r
+static\r
+STATUS\r
+MergeMicrocodeFiles (\r
+  char            *OutFileName,\r
+  STRING_LIST     *FileNames,\r
+  unsigned int    Alignment,\r
+  char            PadByteValue\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Merge binary microcode files into a single file, taking into consideration\r
+  the alignment and pad value.\r
+\r
+Arguments:\r
+\r
+  OutFileName     - name of the output file to create\r
+  FileNames       - linked list of input microcode files to merge\r
+  Alignment       - alignment for each microcode file in the output image\r
+  PadByteValue    - value to use when padding to meet alignment requirements\r
+\r
+Returns:\r
+\r
+  STATUS_SUCCESS  - merge completed successfully or with acceptable warnings\r
+  STATUS_ERROR    - merge failed, output file not created\r
+\r
+--*/\r
+{\r
+  long    FileSize;\r
+  long    TotalFileSize;\r
+  FILE    *InFptr;\r
+  FILE    *OutFptr;\r
+  char    *Buffer;\r
+  STATUS  Status;\r
+\r
+  //\r
+  // Open the output file\r
+  //\r
+  if ((OutFptr = fopen (OutFileName, "wb")) == NULL) {\r
+    Error (NULL, 0, 0, OutFileName, "failed to open output file for writing");\r
+    return STATUS_ERROR;\r
+  }\r
+  //\r
+  // Walk the list of files\r
+  //\r
+  Status        = STATUS_ERROR;\r
+  Buffer        = NULL;\r
+  InFptr        = NULL;\r
+  TotalFileSize = 0;\r
+  while (FileNames != NULL) {\r
+    //\r
+    // Open the file, determine the size, then read it in and write\r
+    // it back out.\r
+    //\r
+    if ((InFptr = fopen (FileNames->Str, "rb")) == NULL) {\r
+      Error (NULL, 0, 0, FileNames->Str, "failed to open input file for reading");\r
+      goto Done;\r
+    }\r
+    fseek (InFptr, 0, SEEK_END);\r
+    FileSize = ftell (InFptr);\r
+    fseek (InFptr, 0, SEEK_SET);\r
+    if (FileSize != 0) {\r
+      Buffer = (char *) _malloc (FileSize);\r
+      if (Buffer == NULL) {\r
+        Error (NULL, 0, 0, "memory allocation failure", NULL);\r
+        goto Done;\r
+      }\r
+      if (fread (Buffer, FileSize, 1, InFptr) != 1) {\r
+        Error (NULL, 0, 0, FileNames->Str, "failed to read file contents");\r
+        goto Done;\r
+      }\r
+      //\r
+      // Align\r
+      //\r
+      if (Alignment != 0) {\r
+        while ((TotalFileSize % Alignment) != 0) {\r
+          if (fwrite (&PadByteValue, 1, 1, OutFptr) != 1) {\r
+            Error (NULL, 0, 0, OutFileName, "failed to write pad bytes to output file");\r
+            goto Done;\r
+          }\r
+          TotalFileSize++;\r
+        }\r
+      }\r
+      TotalFileSize += FileSize;\r
+      if (fwrite (Buffer, FileSize, 1, OutFptr) != 1) {\r
+        Error (NULL, 0, 0, OutFileName, "failed to write to output file");\r
+        goto Done;\r
+      }\r
+      _free (Buffer);\r
+      Buffer = NULL;\r
+    } else {\r
+      Warning (NULL, 0, 0, FileNames->Str, "0-size file encountered");\r
+    }\r
+    fclose (InFptr);\r
+    InFptr    = NULL;\r
+    FileNames = FileNames->Next;\r
+  }\r
+  Status = STATUS_SUCCESS;\r
+Done:\r
+  fclose (OutFptr);\r
+  if (InFptr != NULL) {\r
+    fclose (InFptr);\r
+  }\r
+  if (Buffer != NULL) {\r
+    _free (Buffer);\r
+  }\r
+  if (Status == STATUS_ERROR) {\r
+    remove (OutFileName);\r
+  }\r
+  return Status;\r
+}\r
+\r
+static\r
+STATUS\r
+ProcessCommandLine (\r
+  int   argc,\r
+  char  *argv[]\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Process the command line arguments\r
+  \r
+Arguments:\r
+  argc   - Standard C entry point arguments\r
+  argv[] - Standard C entry point arguments\r
+\r
+Returns:\r
+  STATUS_SUCCESS    - no problems encountered while processing\r
+  STATUS_WARNING    - warnings, but no errors, were encountered while processing\r
+  STATUS_ERROR      - errors were encountered while processing\r
+  \r
+--*/\r
+{\r
+  int           ThingsToDo;\r
+  unsigned int  Temp;\r
+  STRING_LIST   *Str;\r
+  //\r
+  // Skip program name arg, process others\r
+  //\r
+  argc--;\r
+  argv++;\r
+  if (argc == 0) {\r
+    Usage ();\r
+    return STATUS_ERROR;\r
+  }\r
+  //\r
+  // Clear out our globals, then start walking the arguments\r
+  //\r
+  memset ((void *) &mGlobals, 0, sizeof (mGlobals));\r
+  mGlobals.MicrocodePadByteValue  = DEFAULT_MC_PAD_BYTE_VALUE;\r
+  mGlobals.MicrocodeAlignment     = DEFAULT_MC_ALIGNMENT;\r
+  ThingsToDo                      = 0;\r
+  while (argc > 0) {\r
+    if (strcmp (argv[0], "-?") == 0) {\r
+      Usage ();\r
+      return STATUS_ERROR;\r
+    } else if (strcmp (argv[0], "-hfile") == 0) {\r
+      //\r
+      // -hfile FileName\r
+      //\r
+      // Used to specify an output C #include file to create that contains\r
+      // #define statements for all the flashmap region offsets and sizes.\r
+      // Check for additional argument.\r
+      //\r
+      if (argc < 2) {\r
+        Error (NULL, 0, 0, argv[0], "option requires an output file name");\r
+        return STATUS_ERROR;\r
+      }\r
+      argc--;\r
+      argv++;\r
+      mGlobals.CIncludeFileName = argv[0];\r
+      ThingsToDo++;\r
+    } else if (strcmp (argv[0], "-flashdevice") == 0) {\r
+      //\r
+      // -flashdevice FLASH_DEVICE_NAME\r
+      //\r
+      // Used to select which flash device definition to operate on.\r
+      // Check for additional argument\r
+      //\r
+      if (argc < 2) {\r
+        Error (NULL, 0, 0, argv[0], "option requires a flash device name to use");\r
+        return STATUS_ERROR;\r
+      }\r
+      argc--;\r
+      argv++;\r
+      mGlobals.FlashDevice = argv[0];\r
+    } else if (strcmp (argv[0], "-mco") == 0) {\r
+      //\r
+      // -mco OutFileName\r
+      //\r
+      // Used to specify a microcode output binary file to create.\r
+      // Check for additional argument.\r
+      //\r
+      if (argc < 2) {\r
+        Error (NULL, 0, 0, (INT8 *) argv[0], (INT8 *) "option requires an output microcode file name to create");\r
+        return STATUS_ERROR;\r
+      }\r
+      argc--;\r
+      argv++;\r
+      mGlobals.MCOFileName = argv[0];\r
+      ThingsToDo++;\r
+    } else if (strcmp (argv[0], "-asmincfile") == 0) {\r
+      //\r
+      // -asmincfile FileName\r
+      //\r
+      // Used to specify the name of the output assembly include file that contains\r
+      // equates for the flash region addresses and sizes.\r
+      // Check for additional argument.\r
+      //\r
+      if (argc < 2) {\r
+        Error (NULL, 0, 0, argv[0], "option requires an output ASM include file name to create");\r
+        return STATUS_ERROR;\r
+      }\r
+      argc--;\r
+      argv++;\r
+      mGlobals.AsmIncludeFileName = argv[0];\r
+      ThingsToDo++;\r
+    } else if (strcmp (argv[0], "-mci") == 0) {\r
+      //\r
+      // -mci FileName\r
+      //\r
+      // Used to specify an input microcode text file to parse.\r
+      // Check for additional argument\r
+      //\r
+      if (argc < 2) {\r
+        Error (NULL, 0, 0, (INT8 *) argv[0], (INT8 *) "option requires an input microcode text file name to parse");\r
+        return STATUS_ERROR;\r
+      }\r
+      argc--;\r
+      argv++;\r
+      mGlobals.MCIFileName = argv[0];\r
+    } else if (strcmp (argv[0], "-flashdeviceimage") == 0) {\r
+      //\r
+      // -flashdeviceimage FlashDeviceImage\r
+      //\r
+      // Used to specify which flash device image definition from the input flash definition file\r
+      // to create.\r
+      // Check for additional argument.\r
+      //\r
+      if (argc < 2) {\r
+        Error (NULL, 0, 0, argv[0], "option requires the name of a flash definition image to use");\r
+        return STATUS_ERROR;\r
+      }\r
+      argc--;\r
+      argv++;\r
+      mGlobals.FlashDeviceImage = argv[0];\r
+    } else if (strcmp (argv[0], "-imageout") == 0) {\r
+      //\r
+      // -imageout FileName\r
+      //\r
+      // Used to specify the name of the output FD image file to create.\r
+      // Check for additional argument.\r
+      //\r
+      if (argc < 2) {\r
+        Error (NULL, 0, 0, argv[0], "option requires an output image filename to create");\r
+        return STATUS_ERROR;\r
+      }\r
+      argc--;\r
+      argv++;\r
+      mGlobals.ImageOutFileName = argv[0];\r
+      ThingsToDo++;\r
+    } else if (strcmp (argv[0], "-dsc") == 0) {\r
+      //\r
+      // -dsc FileName\r
+      //\r
+      // Used to specify the name of the output DSC file to create.\r
+      // Check for additional argument.\r
+      //\r
+      if (argc < 2) {\r
+        Error (NULL, 0, 0, argv[0], "option requires an output DSC filename to create");\r
+        return STATUS_ERROR;\r
+      }\r
+      argc--;\r
+      argv++;\r
+      mGlobals.DscFileName = argv[0];\r
+      ThingsToDo++;\r
+    } else if (strcmp (argv[0], "-fdf") == 0) {\r
+      //\r
+      // -fdf FileName\r
+      //\r
+      // Used to specify the name of the input flash definition file.\r
+      // Check for additional argument.\r
+      //\r
+      if (argc < 2) {\r
+        Error (NULL, 0, 0, argv[0], "option requires an input flash definition file name");\r
+        return STATUS_ERROR;\r
+      }\r
+      argc--;\r
+      argv++;\r
+      mGlobals.FlashDefinitionFileName = argv[0];\r
+    } else if (strcmp (argv[0], "-discover") == 0) {\r
+      //\r
+      // -discover FDFileName\r
+      //\r
+      // Debug functionality used to scan an existing FD image, trying to find\r
+      // firmware volumes at 64K boundaries.\r
+      // Check for additional argument.\r
+      //\r
+      if (argc < 2) {\r
+        Error (NULL, 0, 0, argv[0], "option requires an input FD image file name");\r
+        return STATUS_ERROR;\r
+      }\r
+      argc--;\r
+      argv++;\r
+      mGlobals.DiscoverFDImageName = argv[0];\r
+      ThingsToDo++;\r
+    } else if (strcmp (argv[0], "-baseaddr") == 0) {\r
+      //\r
+      // -baseaddr Addr\r
+      //\r
+      // Used to specify a base address when doing a discover of an FD image.\r
+      // Check for additional argument.\r
+      //\r
+      if (argc < 2) {\r
+        Error (NULL, 0, 0, argv[0], "option requires a base address");\r
+        return STATUS_ERROR;\r
+      }\r
+      argc--;\r
+      argv++;\r
+      if (tolower (argv[0][1]) == 'x') {\r
+        sscanf (argv[0] + 2, "%x", &mGlobals.BaseAddress);\r
+      } else {\r
+        sscanf (argv[0], "%d", &mGlobals.BaseAddress);\r
+      }\r
+    } else if (strcmp (argv[0], "-padvalue") == 0) {\r
+      //\r
+      // -padvalue Value\r
+      //\r
+      // Used to specify the value to pad with when aligning data while\r
+      // creating an FD image. Check for additional argument.\r
+      //\r
+      if (argc < 2) {\r
+        Error (NULL, 0, 0, argv[0], "option requires a byte value");\r
+        return STATUS_ERROR;\r
+      }\r
+      argc--;\r
+      argv++;\r
+      if (tolower (argv[0][1]) == 'x') {\r
+        sscanf (argv[0] + 2, "%x", &Temp);\r
+        mGlobals.MicrocodePadByteValue = (char) Temp;\r
+      } else {\r
+        sscanf (argv[0], "%d", &Temp);\r
+        mGlobals.MicrocodePadByteValue = (char) Temp;\r
+      }\r
+    } else if (strcmp (argv[0], "-align") == 0) {\r
+      //\r
+      // -align Alignment\r
+      //\r
+      // Used to specify how each data file is aligned in the region\r
+      // when creating an FD image. Check for additional argument.\r
+      //\r
+      if (argc < 2) {\r
+        Error (NULL, 0, 0, argv[0], "option requires an alignment");\r
+        return STATUS_ERROR;\r
+      }\r
+      argc--;\r
+      argv++;\r
+      if (tolower (argv[0][1]) == 'x') {\r
+        sscanf (argv[0] + 2, "%x", &mGlobals.MicrocodeAlignment);\r
+      } else {\r
+        sscanf (argv[0], "%d", &mGlobals.MicrocodeAlignment);\r
+      }\r
+    } else if (strcmp (argv[0], "-mcmerge") == 0) {\r
+      //\r
+      // -mcmerge FileName(s)\r
+      //\r
+      // Used to concatenate multiple microde binary files. Can specify\r
+      // multiple file names with the one -mcmerge flag. Check for additional argument.\r
+      //\r
+      if ((argc < 2) || (argv[1][0] == '-')) {\r
+        Error (NULL, 0, 0, argv[0], "option requires one or more input file names");\r
+        return STATUS_ERROR;\r
+      }\r
+      //\r
+      // Take input files until another option or end of list\r
+      //\r
+      ThingsToDo++;\r
+      while ((argc > 1) && (argv[1][0] != '-')) {\r
+        Str = (STRING_LIST *) _malloc (sizeof (STRING_LIST));\r
+        if (Str == NULL) {\r
+          Error (NULL, 0, 0, "memory allocation failure", NULL);\r
+          return STATUS_ERROR;\r
+        }\r
+        memset (Str, 0, sizeof (STRING_LIST));\r
+        Str->Str = argv[1];\r
+        if (mGlobals.MCIFileNames == NULL) {\r
+          mGlobals.MCIFileNames = Str;\r
+        } else {\r
+          mGlobals.LastMCIFileNames->Next = Str;\r
+        }\r
+        mGlobals.LastMCIFileNames = Str;\r
+        argc--;\r
+        argv++;\r
+      }\r
+    } else if (strcmp (argv[0], "-strsub") == 0) {\r
+      //\r
+      // -strsub SrcFile DestFile\r
+      //\r
+      // Used to perform string substitutions on a file, writing the result to a new\r
+      // file. Check for two additional arguments.\r
+      //\r
+      if (argc < 3) {\r
+        Error (NULL, 0, 0, argv[0], "option requires input and output file names for string substitution");\r
+        return STATUS_ERROR;\r
+      }\r
+      argc--;\r
+      argv++;\r
+      mGlobals.StringReplaceInFileName = argv[0];\r
+      argc--;\r
+      argv++;\r
+      mGlobals.StringReplaceOutFileName = argv[0];\r
+      ThingsToDo++;\r
+    } else {\r
+      Error (NULL, 0, 0, argv[0], "invalid option");\r
+      return STATUS_ERROR;\r
+    }\r
+    argc--;\r
+    argv++;\r
+  }\r
+  //\r
+  // If no outputs requested, then report an error\r
+  //\r
+  if (ThingsToDo == 0) {\r
+    Error (NULL, 0, 0, "nothing to do", NULL);\r
+    return STATUS_ERROR;\r
+  }\r
+  //\r
+  // If they want an asm file, #include file, or C file to be created, then they have to specify a\r
+  // flash device name and flash definition file name.\r
+  //\r
+  if ((mGlobals.CIncludeFileName != NULL) &&\r
+      ((mGlobals.FlashDevice == NULL) || (mGlobals.FlashDefinitionFileName == NULL))) {\r
+    Error (NULL, 0, 0, "must specify -flashdevice and -fdf with -hfile", NULL);\r
+    return STATUS_ERROR;\r
+  }\r
+  if ((mGlobals.AsmIncludeFileName != NULL) &&\r
+      ((mGlobals.FlashDevice == NULL) || (mGlobals.FlashDefinitionFileName == NULL))) {\r
+    Error (NULL, 0, 0, "must specify -flashdevice and -fdf with -asmincfile", NULL);\r
+    return STATUS_ERROR;\r
+  }\r
+  //\r
+  // If they want a dsc file to be created, then they have to specify a\r
+  // flash device name and a flash definition file name\r
+  //\r
+  if (mGlobals.DscFileName != NULL) {\r
+    if (mGlobals.FlashDevice == NULL) {\r
+      Error (NULL, 0, 0, "must specify -flashdevice with -dsc", NULL);\r
+      return STATUS_ERROR;\r
+    }\r
+    if (mGlobals.FlashDefinitionFileName == NULL) {\r
+      Error (NULL, 0, 0, "must specify -fdf with -dsc", NULL);\r
+      return STATUS_ERROR;\r
+    }\r
+  }\r
+  //\r
+  // If they specified an output microcode file name, then they have to specify an input\r
+  // file name, and vice versa.\r
+  //\r
+  if ((mGlobals.MCIFileName != NULL) && (mGlobals.MCOFileName == NULL)) {\r
+    Error (NULL, 0, 0, "must specify output microcode file name", NULL);\r
+    return STATUS_ERROR;\r
+  }\r
+  if ((mGlobals.MCOFileName != NULL) && (mGlobals.MCIFileName == NULL) && (mGlobals.MCIFileNames == NULL)) {\r
+    Error (NULL, 0, 0, "must specify input microcode file name", NULL);\r
+    return STATUS_ERROR;\r
+  }\r
+  //\r
+  // If doing merge, then have to specify output file name\r
+  //\r
+  if ((mGlobals.MCIFileNames != NULL) && (mGlobals.MCOFileName == NULL)) {\r
+    Error (NULL, 0, 0, "must specify output microcode file name", NULL);\r
+    return STATUS_ERROR;\r
+  }\r
+  //\r
+  // If they want an output image to be created, then they have to specify\r
+  // the flash device and the flash device image to use.\r
+  //\r
+  if (mGlobals.ImageOutFileName != NULL) {\r
+    if (mGlobals.FlashDevice == NULL) {\r
+      Error (NULL, 0, 0, "must specify -flashdevice with -imageout", NULL);\r
+      return STATUS_ERROR;\r
+    }\r
+    if (mGlobals.FlashDeviceImage == NULL) {\r
+      Error (NULL, 0, 0, "must specify -flashdeviceimage with -imageout", NULL);\r
+      return STATUS_ERROR;\r
+    }\r
+    if (mGlobals.FlashDefinitionFileName == NULL) {\r
+      Error (NULL, 0, 0, "must specify -c or -fdf with -imageout", NULL);\r
+      return STATUS_ERROR;\r
+    }\r
+  }\r
+  return STATUS_SUCCESS;\r
+}\r
+\r
+static\r
+void\r
+Usage (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Print utility command line help\r
+  \r
+Arguments:\r
+  None\r
+\r
+Returns:\r
+  NA\r
+\r
+--*/\r
+{\r
+  int   i;\r
+  char  *Msg[] = {\r
+    "Usage: FlashTool -fdf FlashDefFile -flashdevice FlashDevice",\r
+    "                 -flashdeviceimage FlashDeviceImage -mci MCIFile -mco MCOFile",\r
+    "                 -discover FDImage -dsc DscFile -asmincfile AsmIncFile",\r
+    "                 -imageOut ImageOutFile -hfile HFile -strsub InStrFile OutStrFile",\r
+    "                 -baseaddr BaseAddr -align Alignment -padvalue PadValue",\r
+    "                 -mcmerge MCIFile(s)",\r
+    "  where",\r
+    "    FlashDefFile     - input Flash Definition File",\r
+    "    FlashDevice      - flash device to use (from flash definition file)",\r
+    "    FlashDeviceImage - flash device image to use (from flash definition file)",\r
+    "    MCIFile          - input microcode file to parse",\r
+    "    MCOFile          - output binary microcode image to create from MCIFile",\r
+    "    HFile            - output #include file to create",\r
+    "    FDImage          - name of input FDImage file to scan",\r
+    "    ImageOutFile     - output image file to create",\r
+    "    DscFile          - output DSC file to create",\r
+    "    AsmIncFile       - output ASM include file to create",\r
+    "    InStrFile        - input file to replace symbol names, writing result to OutStrFile",\r
+    "    BaseAddr         - base address of FDImage (used with -discover)",\r
+    "    Alignment        - alignment to use when merging microcode binaries",\r
+    "    PadValue         - byte value to use as pad value when aligning microcode binaries",\r
+    "    MCIFile(s)       - one or more microcode binary files to merge/concatenate",\r
+    "",\r
+    NULL\r
+  };\r
+  for (i = 0; Msg[i] != NULL; i++) {\r
+    fprintf (stdout, "%s\n", Msg[i]);\r
+  }\r
+}\r