]> git.proxmox.com Git - mirror_edk2.git/blobdiff - Tools/CCode/Source/FlashMap/FlashDefFile.c
More moves for Tool Packages
[mirror_edk2.git] / Tools / CCode / Source / FlashMap / FlashDefFile.c
diff --git a/Tools/CCode/Source/FlashMap/FlashDefFile.c b/Tools/CCode/Source/FlashMap/FlashDefFile.c
new file mode 100644 (file)
index 0000000..cdbf788
--- /dev/null
@@ -0,0 +1,2788 @@
+/*++\r
+\r
+Copyright (c)  2004-2006 Intel Corporation. All rights reserved\r
+This program and the accompanying materials are licensed and made available \r
+under the terms and conditions of the BSD License which accompanies this \r
+distribution.  The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+Module Name:\r
+\r
+  FlashDefFile.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
+\r
+#include <Common/UefiBaseTypes.h>\r
+#include <Common/FirmwareVolumeHeader.h>\r
+#include <Common/MultiPhase.h>\r
+\r
+#include "EfiUtilityMsgs.h"\r
+#include "FlashDefFile.h"\r
+#include "SimpleFileParsing.h"\r
+#include "Symbols.h"\r
+\r
+//\r
+// #include "TrackMallocFree.h"\r
+//\r
+#define WCHAR_T           char\r
+#define MAX_STRING_LEN    256\r
+#define MAX_NAME_LEN      128\r
+#define BUFFER_SIZE       1024\r
+#define MAX_ATTR_LEN      128\r
+#define MAX_AREATYPE_LEN  128\r
+#define COLUMN2_START     60\r
+#define COLUMN3_START     70\r
+//\r
+// Information for each subregions defined in the fdf file will be saved in these\r
+//\r
+typedef struct _FLASH_SUBREGION_DESCRIPTION {\r
+  struct _FLASH_SUBREGION_DESCRIPTION *Next;\r
+  int                                 CreateHob;                  // to add to the auto-created HOB array\r
+  WCHAR_T                             Name[MAX_NAME_LEN];         // each subregion within a region must have a unique name\r
+  unsigned int                        Size;                       // size, in bytes, of this subregion\r
+  unsigned int                        SizeLeft;                   // used when creating the image\r
+  WCHAR_T                             Attributes[MAX_ATTR_LEN];   // subregion attributes used in the output HOB\r
+  WCHAR_T                             AreaType[MAX_AREATYPE_LEN]; // subregion area type used in the output HOB\r
+  EFI_GUID                            NameGuid;                   // used in the output HOB\r
+  WCHAR_T                             NameGuidString[MAX_NAME_LEN];\r
+  EFI_GUID                            AreaTypeGuid;               // used in the output HOB\r
+  WCHAR_T                             AreaTypeGuidString[MAX_NAME_LEN];\r
+  EFI_GUID                            FileSystemGuid;             // used in the output HOB\r
+  WCHAR_T                             FileSystemGuidString[MAX_NAME_LEN];\r
+} FLASH_SUBREGION_DESCRIPTION;\r
+\r
+//\r
+// Information for each block in a flash device will be saved in one of these.\r
+// We'll also use it for region definitions.\r
+//\r
+typedef struct _FLASH_BLOCK_DESCRIPTION {\r
+  struct _FLASH_BLOCK_DESCRIPTION *Next;                      // next block in the linked list\r
+  WCHAR_T                         Name[MAX_NAME_LEN];         // each block must have a unique name\r
+  unsigned int                    Size;                       // size, in bytes, of this block\r
+  unsigned int                    SizeLeft;                   // for use when creating image\r
+  unsigned int                    Flags;                      // user-defined flags for the block\r
+  unsigned int                    Alignment;                  // power of 2 alignment\r
+  WCHAR_T                         Attributes[MAX_ATTR_LEN];   // only used for Region definitions\r
+  WCHAR_T                         AreaType[MAX_AREATYPE_LEN]; // only used for Region definitions\r
+  FLASH_SUBREGION_DESCRIPTION     *Subregions;\r
+  FLASH_SUBREGION_DESCRIPTION     *LastSubregion;\r
+} FLASH_BLOCK_DESCRIPTION;\r
+\r
+//\r
+// Information for each flash device will be saved in one of these\r
+//\r
+typedef struct _FLASH_DEVICE_DESCRIPTION {\r
+  struct _FLASH_DEVICE_DESCRIPTION  *Next;              // next flash device in our linked list\r
+  int                               ErasePolarity;      // erase polarity of the flash device\r
+  unsigned int                      BaseAddress;        // base address of the flash device\r
+  unsigned int                      Size;               // total size, in bytes, of the flash device\r
+  WCHAR_T                           Name[MAX_NAME_LEN]; // name of the flash device\r
+  FLASH_BLOCK_DESCRIPTION           *PBlocks;           // linked list of physical block descriptors\r
+  FLASH_BLOCK_DESCRIPTION           *LastPBlock;        // last block in the linked list\r
+  FLASH_BLOCK_DESCRIPTION           *Regions;           // linked list of flash region descriptors\r
+  FLASH_BLOCK_DESCRIPTION           *LastRegion;        // last region in the linked list\r
+} FLASH_DEVICE_DESCRIPTION;\r
+\r
+//\r
+// For image definitions, they can specify a file name or raw data bytes. Keep a linked list.\r
+//\r
+typedef struct _IMAGE_DEFINITION_ENTRY {\r
+  struct _IMAGE_DEFINITION_ENTRY  *Next;\r
+  WCHAR_T                         RegionName[MAX_NAME_LEN];\r
+  WCHAR_T                         SubregionName[MAX_NAME_LEN];\r
+  WCHAR_T                         Name[MAX_NAME_LEN]; // file or data name\r
+  int                             IsRawData;          // non-zero if raw data bytes\r
+  unsigned int                    RawDataSize;\r
+  char                            *RawData;\r
+  int                             Optional;           // optional file (don't include if it doesn't exist)\r
+} IMAGE_DEFINITION_ENTRY;\r
+\r
+//\r
+// When we parse an image definition, save all the data for each in one of these\r
+//\r
+typedef struct _IMAGE_DEFINITION {\r
+  struct _IMAGE_DEFINITION  *Next;\r
+  WCHAR_T                   Name[MAX_NAME_LEN];\r
+  IMAGE_DEFINITION_ENTRY    *Entries;\r
+  IMAGE_DEFINITION_ENTRY    *LastEntry;\r
+} IMAGE_DEFINITION;\r
+\r
+typedef struct {\r
+  char  *BufferStart;\r
+  char  *BufferEnd;\r
+  char  *BufferPos;\r
+} BUFFER_DATA;\r
+\r
+static const char               *CIncludeHeader = "/*++\n\n"\r
+"  DO NOT EDIT -- file auto-generated by FlashMap utility\n\n""--*/\n""\n""#ifndef _FLASH_MAP_H_\n"\r
+"#define _FLASH_MAP_H_\n\n";\r
+//\r
+//  "#include \"EfiFlashMap.h\"\n\n";\r
+//\r
+static const char               *CIncludeFooter = "#endif // #ifndef _FLASH_MAP_H_\n\n";\r
+\r
+static const char               *CFlashMapDataFileHeader = "/*++\n\n"\r
+"  DO NOT EDIT -- file auto-generated by FlashMap utility\n\n""--*/\n""\n";\r
+\r
+static FLASH_DEVICE_DESCRIPTION *mFlashDevices      = NULL;\r
+static IMAGE_DEFINITION         *mImageDefinitions  = NULL;\r
+\r
+//\r
+// Local function prototypes\r
+//\r
+static\r
+BUFFER_DATA                     *\r
+CreateBufferData (\r
+  VOID\r
+  );\r
+\r
+static\r
+BOOLEAN\r
+AddBufferDataByte (\r
+  BUFFER_DATA *Buffer,\r
+  char        Data\r
+  );\r
+\r
+static\r
+void\r
+FreeBufferData (\r
+  BUFFER_DATA *Buffer,\r
+  BOOLEAN     FreeData\r
+  );\r
+\r
+static\r
+char                            *\r
+GetBufferData (\r
+  BUFFER_DATA *Buffer,\r
+  int         *BufferSize\r
+  );\r
+\r
+static\r
+FLASH_SUBREGION_DESCRIPTION     *\r
+ParseSubregionDefinition (\r
+  unsigned int  SizeLeft\r
+  );\r
+\r
+void\r
+FDFConstructor (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Initialization routine for the services that operate on a flash\r
+  definition file.\r
+\r
+Arguments:\r
+  None.\r
+\r
+Returns:\r
+  NA\r
+\r
+--*/\r
+{\r
+  mFlashDevices     = NULL;\r
+  mImageDefinitions = NULL;\r
+}\r
+\r
+void\r
+FDFDestructor (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Finalization/cleanup routine for the services that operate on a flash\r
+  definition file.\r
+\r
+Arguments:\r
+  None.\r
+\r
+Returns:\r
+  NA\r
+\r
+--*/\r
+{\r
+  FLASH_BLOCK_DESCRIPTION     *FBNext;\r
+  FLASH_DEVICE_DESCRIPTION    *FDNext;\r
+  IMAGE_DEFINITION            *IDNext;\r
+  IMAGE_DEFINITION_ENTRY      *IDENext;\r
+  FLASH_SUBREGION_DESCRIPTION *SubNext;\r
+  //\r
+  // Go through all our flash devices and free the memory\r
+  //\r
+  while (mFlashDevices != NULL) {\r
+    //\r
+    // Free the physical block definitions\r
+    //\r
+    while (mFlashDevices->PBlocks != NULL) {\r
+      FBNext = mFlashDevices->PBlocks->Next;\r
+      _free (mFlashDevices->PBlocks);\r
+      mFlashDevices->PBlocks = FBNext;\r
+    }\r
+    //\r
+    // Free the region definitions\r
+    //\r
+    while (mFlashDevices->Regions != NULL) {\r
+      FBNext = mFlashDevices->Regions->Next;\r
+      //\r
+      // First free the subregion definitions\r
+      //\r
+      while (mFlashDevices->Regions->Subregions != NULL) {\r
+        SubNext = mFlashDevices->Regions->Subregions->Next;\r
+        _free (mFlashDevices->Regions->Subregions);\r
+        mFlashDevices->Regions->Subregions = SubNext;\r
+      }\r
+\r
+      _free (mFlashDevices->Regions);\r
+      mFlashDevices->Regions = FBNext;\r
+    }\r
+\r
+    FDNext = mFlashDevices->Next;\r
+    _free (mFlashDevices);\r
+    mFlashDevices = FDNext;\r
+  }\r
+  //\r
+  // Free up the image definitions, and the data\r
+  //\r
+  while (mImageDefinitions != NULL) {\r
+    //\r
+    // Free the entries\r
+    //\r
+    while (mImageDefinitions->Entries != NULL) {\r
+      IDENext = mImageDefinitions->Entries->Next;\r
+      if (mImageDefinitions->Entries->RawData != NULL) {\r
+        _free (mImageDefinitions->Entries->RawData);\r
+      }\r
+\r
+      _free (mImageDefinitions->Entries);\r
+      mImageDefinitions->Entries = IDENext;\r
+    }\r
+\r
+    IDNext = mImageDefinitions->Next;\r
+    _free (mImageDefinitions);\r
+    mImageDefinitions = IDNext;\r
+  }\r
+}\r
+\r
+STATUS\r
+FDFParseFile (\r
+  char    *FileName\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Parse the specified flash definition file, saving the definitions in\r
+  file-static variables for use by other functions.\r
+  \r
+Arguments:\r
+  FileName    - name of the input flash definition text file.\r
+\r
+Returns:\r
+  STATUS_SUCCESS    - file parsed with no errors or warnings\r
+  STATUS_WARNING    - warnings, but no errors, were encountered while parsing\r
+  STATUS_ERROR      - errors were encountered while parsing\r
+  \r
+--*/\r
+{\r
+  FILE                        *Fptr;\r
+  STATUS                      Status;\r
+  unsigned int                Num;\r
+  FLASH_DEVICE_DESCRIPTION    *FDDesc;\r
+  FLASH_BLOCK_DESCRIPTION     *FBlockDesc;\r
+  FLASH_BLOCK_DESCRIPTION     *TempBlockDesc;\r
+  FLASH_SUBREGION_DESCRIPTION *Subregion;\r
+  FLASH_SUBREGION_DESCRIPTION *TempSubregion;\r
+  unsigned int                BlockSizeLeft;\r
+  unsigned int                RegionSizeLeft;\r
+  unsigned int                SubregionSizeLeft;\r
+  int                         ErrorCount;\r
+  int                         WarningCount;\r
+  IMAGE_DEFINITION            *ImageDef;\r
+  IMAGE_DEFINITION_ENTRY      *ImageDefEntry;\r
+  IMAGE_DEFINITION_ENTRY      *TempImageDefEntry;\r
+  BUFFER_DATA                 *BufferData;\r
+  char                        Str[100];\r
+  BOOLEAN                     PreviousComma;\r
+\r
+  if ((Fptr = fopen (FileName, "r")) == NULL) {\r
+    Error (NULL, 0, 0, FileName, "failed to open input flash definition file for reading");\r
+    return STATUS_ERROR;\r
+  }\r
+\r
+  fclose (Fptr);\r
+  Status        = STATUS_SUCCESS;\r
+  ErrorCount    = 0;\r
+  WarningCount  = 0;\r
+  //\r
+  // Initialize the simple-file-parsing routines\r
+  //\r
+  SFPInit ();\r
+  //\r
+  // Open the file\r
+  //\r
+  if ((Status = SFPOpenFile (FileName)) != STATUS_SUCCESS) {\r
+    return Status;\r
+  }\r
+  //\r
+  // Parse the file. Should start with a series of these:\r
+  // FlashDevice {\r
+  //   Name = "FLASH_1234", Size = 0x2004, BaseAddress = 0xFFF0000, ErasePolarity = 1,\r
+  //   Block { Name = "BLOCK1",  Size = 0x1000, Flags = 0x0001 }\r
+  //   Block { Name = "BLOCK2",  Size = 0x1004, Flags = 0x0002 }\r
+  //   Region  { Name = "REGION_NAME", Size = 0x2004, Align= 4 }\r
+  // }\r
+  //\r
+  while (SFPIsKeyword ("FlashDevice")) {\r
+    //\r
+    // Allocate memory for new flash device description block\r
+    //\r
+    FDDesc = (FLASH_DEVICE_DESCRIPTION *) _malloc (sizeof (FLASH_DEVICE_DESCRIPTION));\r
+    if (FDDesc == NULL) {\r
+      Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
+      ErrorCount++;\r
+      goto Done;\r
+    }\r
+\r
+    memset (FDDesc, 0, sizeof (FLASH_DEVICE_DESCRIPTION));\r
+    //\r
+    // Open brace -- warning if not there\r
+    //\r
+    if (!SFPIsToken ("{")) {\r
+      Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected {", NULL);\r
+      WarningCount++;\r
+    }\r
+    //\r
+    // Parse:  Name = "DeviceName",\r
+    //\r
+    if (!SFPIsKeyword ("Name")) {\r
+      Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Name'", NULL);\r
+      ErrorCount++;\r
+      goto Done;\r
+    }\r
+\r
+    if (!SFPIsToken ("=")) {\r
+      Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+      WarningCount++;\r
+    }\r
+\r
+    if (!SFPGetQuotedString (FDDesc->Name, sizeof (FDDesc->Name))) {\r
+      Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted name of flash device", NULL);\r
+      ErrorCount++;\r
+      goto Done;\r
+    }\r
+\r
+    if (!SFPIsToken (",")) {\r
+      Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following flash device name", NULL);\r
+      WarningCount++;\r
+    }\r
+    //\r
+    // Parse: Size = 0x20000,\r
+    //\r
+    if (!SFPIsKeyword ("Size")) {\r
+      Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Size'", NULL);\r
+      ErrorCount++;\r
+      goto Done;\r
+    }\r
+\r
+    if (!SFPIsToken ("=")) {\r
+      Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+      WarningCount++;\r
+    }\r
+\r
+    if (!SFPGetNumber (&FDDesc->Size)) {\r
+      Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected numeric Size value", NULL);\r
+      ErrorCount++;\r
+      goto Done;\r
+    }\r
+    //\r
+    // Check for 0 size\r
+    //\r
+    if (FDDesc->Size == 0) {\r
+      Error (SFPGetFileName (), SFPGetLineNumber (), 0, FDDesc->Name, "Size field cannot be 0", NULL);\r
+      ErrorCount++;\r
+      goto Done;\r
+    }\r
+\r
+    SFPIsToken (",");\r
+    //\r
+    // Parse: BaseAddress = 0xFFF0000,\r
+    //\r
+    if (!SFPIsKeyword ("BaseAddress")) {\r
+      Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'BaseAddress'", NULL);\r
+      ErrorCount++;\r
+      goto Done;\r
+    }\r
+\r
+    if (!SFPIsToken ("=")) {\r
+      Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+      WarningCount++;\r
+    }\r
+\r
+    if (!SFPGetNumber (&FDDesc->BaseAddress)) {\r
+      Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected numeric value for BaseAddress", NULL);\r
+      ErrorCount++;\r
+      goto Done;\r
+    }\r
+\r
+    if (!SFPIsToken (",")) {\r
+      Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following BaseAddress value", NULL);\r
+      WarningCount++;\r
+    }\r
+    //\r
+    // Parse: ErasePolarity = 1,\r
+    //\r
+    if (!SFPIsKeyword ("ErasePolarity")) {\r
+      Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'ErasePolarity'", NULL);\r
+      ErrorCount++;\r
+      goto Done;\r
+    }\r
+\r
+    if (!SFPIsToken ("=")) {\r
+      Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+      WarningCount++;\r
+    }\r
+\r
+    if (!SFPGetNumber (&Num) || ((Num != 0) && (Num != 1))) {\r
+      Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected numeric erase polarity value 1 or 0", NULL);\r
+      ErrorCount++;\r
+      goto Done;\r
+    }\r
+\r
+    FDDesc->ErasePolarity = Num;\r
+    if (!SFPIsToken (",")) {\r
+      Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following erase polarity value", NULL);\r
+      WarningCount++;\r
+    }\r
+    //\r
+    // Parse array of:\r
+    //   Block {  Name = "BLOCK1", Size = 0x1000, Flags = 0x0001 }\r
+    //\r
+    // Keep track of size to make sure the sum of the physical blocks and region sizes do not\r
+    // exceed the size of the flash device.\r
+    //\r
+    BlockSizeLeft   = FDDesc->Size;\r
+    RegionSizeLeft  = FDDesc->Size;\r
+    while (SFPIsKeyword ("Block")) {\r
+      //\r
+      // Allocate memory for a new physical block descriptor\r
+      //\r
+      FBlockDesc = (FLASH_BLOCK_DESCRIPTION *) _malloc (sizeof (FLASH_BLOCK_DESCRIPTION));\r
+      if (FBlockDesc == NULL) {\r
+        Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
+        ErrorCount++;\r
+        goto Done;\r
+      }\r
+\r
+      memset (FBlockDesc, 0, sizeof (FLASH_BLOCK_DESCRIPTION));\r
+      //\r
+      // Open brace -- warning if not there\r
+      //\r
+      if (!SFPIsToken ("{")) {\r
+        Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected {", NULL);\r
+        WarningCount++;\r
+      }\r
+      //\r
+      // Parse:  Name = "BlockName",\r
+      //\r
+      if (!SFPIsKeyword ("Name")) {\r
+        Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Name'", NULL);\r
+        ErrorCount++;\r
+        goto Done;\r
+      }\r
+\r
+      if (!SFPIsToken ("=")) {\r
+        Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+        WarningCount++;\r
+      }\r
+\r
+      if (!SFPGetQuotedString (FBlockDesc->Name, sizeof (FBlockDesc->Name))) {\r
+        Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted name of physical block", NULL);\r
+        ErrorCount++;\r
+        goto Done;\r
+      }\r
+      //\r
+      // Make sure there are no other physical block names with this same name\r
+      //\r
+      for (TempBlockDesc = FDDesc->PBlocks; TempBlockDesc != NULL; TempBlockDesc = TempBlockDesc->Next) {\r
+        if (strcmp (TempBlockDesc->Name, FBlockDesc->Name) == 0) {\r
+          Error (\r
+            SFPGetFileName (),\r
+            SFPGetLineNumber (),\r
+            0,\r
+            TempBlockDesc->Name,\r
+            "physical block with this name already defined"\r
+            );\r
+          ErrorCount++;\r
+        }\r
+      }\r
+\r
+      if (!SFPIsToken (",")) {\r
+        Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following physical block name", NULL);\r
+        WarningCount++;\r
+      }\r
+      //\r
+      // Parse: Size = 0x2000,\r
+      //\r
+      if (!SFPIsKeyword ("Size")) {\r
+        Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Size'", NULL);\r
+        ErrorCount++;\r
+        goto Done;\r
+      }\r
+\r
+      if (!SFPIsToken ("=")) {\r
+        Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+        WarningCount++;\r
+      }\r
+\r
+      if (!SFPGetNumber (&FBlockDesc->Size)) {\r
+        Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected numeric Size value", NULL);\r
+        ErrorCount++;\r
+        goto Done;\r
+      }\r
+      //\r
+      // Make sure the sum of physical blocks so far does not exceed flash device size\r
+      //\r
+      if (BlockSizeLeft < FBlockDesc->Size) {\r
+        Error (\r
+          SFPGetFileName (),\r
+          SFPGetLineNumber (),\r
+          0,\r
+          "sum of physical block sizes exceeds flash device size",\r
+          NULL\r
+          );\r
+        ErrorCount++;\r
+      }\r
+\r
+      BlockSizeLeft -= FBlockDesc->Size;\r
+      SFPIsToken (",");\r
+      //\r
+      // Optional parse: Flags = 0xFFF0000,\r
+      //\r
+      if (SFPIsKeyword ("Flags")) {\r
+        if (!SFPIsToken ("=")) {\r
+          Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+          WarningCount++;\r
+        }\r
+\r
+        if (!SFPGetNumber (&FBlockDesc->Flags)) {\r
+          Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected numeric value for Flags", NULL);\r
+          ErrorCount++;\r
+          goto Done;\r
+        }\r
+      }\r
+\r
+      if (!SFPIsToken ("}")) {\r
+        Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected PhysicalBlock closing brace '}'", NULL);\r
+        WarningCount++;\r
+      }\r
+      //\r
+      // Add the physical block descriptor to the end of the linked list\r
+      //\r
+      if (FDDesc->LastPBlock != NULL) {\r
+        FDDesc->LastPBlock->Next = FBlockDesc;\r
+      } else {\r
+        FDDesc->PBlocks = FBlockDesc;\r
+      }\r
+\r
+      FDDesc->LastPBlock = FBlockDesc;\r
+    }\r
+    //\r
+    // Make sure sum of sizes of physical blocks added up to size of flash device\r
+    //\r
+    if (BlockSizeLeft != 0) {\r
+      Error (\r
+        SFPGetFileName (),\r
+        SFPGetLineNumber (),\r
+        0,\r
+        NULL,\r
+        "sum of sizes of physical blocks (0x%08X) != flash device size (0x%08X) : delta = 0x%08X",\r
+        FDDesc->Size - BlockSizeLeft,\r
+        FDDesc->Size,\r
+        BlockSizeLeft\r
+        );\r
+      ErrorCount++;\r
+    }\r
+    //\r
+    // Parse array of:\r
+    //   Region { Name = "REGION_1", Size = 0x2000, Flags = 0x1234, Alignment = 4, Attributes = "str", AreaType = "str" }\r
+    //\r
+    while (SFPIsKeyword ("Region")) {\r
+      //\r
+      // Allocate memory for a new physical block descriptor\r
+      //\r
+      FBlockDesc = (FLASH_BLOCK_DESCRIPTION *) _malloc (sizeof (FLASH_BLOCK_DESCRIPTION));\r
+      if (FBlockDesc == NULL) {\r
+        Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
+        ErrorCount++;\r
+        goto Done;\r
+      }\r
+\r
+      memset (FBlockDesc, 0, sizeof (FLASH_BLOCK_DESCRIPTION));\r
+      //\r
+      // Open brace -- warning if not there\r
+      //\r
+      if (!SFPIsToken ("{")) {\r
+        Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected {", NULL);\r
+        WarningCount++;\r
+      }\r
+      //\r
+      // Parse:  Name = "BlockName",\r
+      //\r
+      if (!SFPIsKeyword ("Name")) {\r
+        Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Name'", NULL);\r
+        ErrorCount++;\r
+        goto Done;\r
+      }\r
+\r
+      if (!SFPIsToken ("=")) {\r
+        Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+        WarningCount++;\r
+      }\r
+\r
+      if (!SFPGetQuotedString (FBlockDesc->Name, sizeof (FBlockDesc->Name))) {\r
+        Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted Region name", NULL);\r
+        ErrorCount++;\r
+        goto Done;\r
+      }\r
+      //\r
+      // Make sure there are no other region names with this same name\r
+      //\r
+      for (TempBlockDesc = FDDesc->Regions; TempBlockDesc != NULL; TempBlockDesc = TempBlockDesc->Next) {\r
+        if (strcmp (TempBlockDesc->Name, FBlockDesc->Name) == 0) {\r
+          Error (\r
+            SFPGetFileName (),\r
+            SFPGetLineNumber (),\r
+            0,\r
+            TempBlockDesc->Name,\r
+            "Region with this name already defined"\r
+            );\r
+          ErrorCount++;\r
+        }\r
+      }\r
+\r
+      if (!SFPIsToken (",")) {\r
+        Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following Region name", NULL);\r
+        WarningCount++;\r
+      }\r
+      //\r
+      // Parse: Size = 0x2000,\r
+      //\r
+      if (!SFPIsKeyword ("Size")) {\r
+        Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Size'", NULL);\r
+        ErrorCount++;\r
+        goto Done;\r
+      }\r
+\r
+      if (!SFPIsToken ("=")) {\r
+        Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+        WarningCount++;\r
+      }\r
+\r
+      if (!SFPGetNumber (&FBlockDesc->Size)) {\r
+        Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected numeric Size value", NULL);\r
+        ErrorCount++;\r
+        goto Done;\r
+      }\r
+\r
+      if (!SFPIsToken (",")) {\r
+        Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected ','", NULL);\r
+      }\r
+      //\r
+      // Make sure the sum of regions so far does not exceed flash device size\r
+      //\r
+      if (RegionSizeLeft < FBlockDesc->Size) {\r
+        Error (SFPGetFileName (), SFPGetLineNumber (), 0, "sum of Region sizes exceeds flash device size", NULL);\r
+        ErrorCount++;\r
+      }\r
+\r
+      RegionSizeLeft -= FBlockDesc->Size;\r
+      //\r
+      // Optional parse: Flags = 0xFFF0000,\r
+      //\r
+      if (SFPIsKeyword ("Flags")) {\r
+        if (!SFPIsToken ("=")) {\r
+          Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+          WarningCount++;\r
+        }\r
+\r
+        if (!SFPGetNumber (&FBlockDesc->Flags)) {\r
+          Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected numeric value for Flags", NULL);\r
+          ErrorCount++;\r
+          goto Done;\r
+        }\r
+        //\r
+        // comma\r
+        //\r
+        if (!SFPIsToken (",")) {\r
+          Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected ','", NULL);\r
+        }\r
+      }\r
+      //\r
+      // Optional parse: Alignment = 4\r
+      //\r
+      if (SFPIsKeyword ("Alignment")) {\r
+        if (!SFPIsToken ("=")) {\r
+          Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+          WarningCount++;\r
+        }\r
+\r
+        if (!SFPGetNumber (&FBlockDesc->Alignment)) {\r
+          Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected numeric Alignment value", NULL);\r
+          ErrorCount++;\r
+          goto Done;\r
+        }\r
+        //\r
+        // comma\r
+        //\r
+        if (!SFPIsToken (",")) {\r
+          Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected ','", NULL);\r
+        }\r
+      }\r
+      //\r
+      // Parse:  Attributes = "String",\r
+      //\r
+      if (!SFPIsKeyword ("Attributes")) {\r
+        Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Attributes'", NULL);\r
+        ErrorCount++;\r
+        goto Done;\r
+      }\r
+\r
+      if (!SFPIsToken ("=")) {\r
+        Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+        WarningCount++;\r
+      }\r
+\r
+      if (!SFPGetQuotedString (FBlockDesc->Attributes, sizeof (FBlockDesc->Attributes))) {\r
+        Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted Attributes string", NULL);\r
+        ErrorCount++;\r
+        goto Done;\r
+      }\r
+\r
+      if (!SFPIsToken (",")) {\r
+        Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected ','", NULL);\r
+      }\r
+      //\r
+      // Parse:  AreaType = "String",\r
+      //\r
+      if (!SFPIsKeyword ("AreaType")) {\r
+        Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'AreaType'", NULL);\r
+        ErrorCount++;\r
+        goto Done;\r
+      }\r
+\r
+      if (!SFPIsToken ("=")) {\r
+        Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+        WarningCount++;\r
+      }\r
+\r
+      if (!SFPGetQuotedString (FBlockDesc->AreaType, sizeof (FBlockDesc->AreaType))) {\r
+        Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted AreaType string", NULL);\r
+        ErrorCount++;\r
+        goto Done;\r
+      }\r
+\r
+      PreviousComma = SFPIsToken (",");\r
+      //\r
+      // Parse optional Subregion definitions\r
+      //\r
+      SubregionSizeLeft = FBlockDesc->Size;\r
+      while (SFPIsToken ("Subregion")) {\r
+        if (!PreviousComma) {\r
+          Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected ',' before 'Subregion'", NULL);\r
+          WarningCount++;\r
+          PreviousComma = TRUE;\r
+        }\r
+\r
+        Subregion = ParseSubregionDefinition (SubregionSizeLeft);\r
+        if (Subregion == NULL) {\r
+          ErrorCount++;\r
+          goto Done;\r
+        }\r
+\r
+        SubregionSizeLeft -= Subregion->Size;\r
+        //\r
+        // Add it to the end of our list\r
+        //\r
+        if (FBlockDesc->Subregions == NULL) {\r
+          FBlockDesc->Subregions = Subregion;\r
+        } else {\r
+          FBlockDesc->LastSubregion->Next = Subregion;\r
+        }\r
+\r
+        FBlockDesc->LastSubregion = Subregion;\r
+        //\r
+        // Make sure all subregion names are unique. We do this each time\r
+        // through so that we catch the error immediately after it happens, in\r
+        // which case the reported line number is at least close to where the\r
+        // problem lies. We don't exit on the error because we can continue parsing\r
+        // the script to perhaps catch other errors or warnings.\r
+        //\r
+        for (Subregion = FBlockDesc->Subregions; Subregion != NULL; Subregion = Subregion->Next) {\r
+          for (TempSubregion = Subregion->Next; TempSubregion != NULL; TempSubregion = TempSubregion->Next) {\r
+            if (strcmp (Subregion->Name, TempSubregion->Name) == 0) {\r
+              Error (SFPGetFileName (), SFPGetLineNumber (), 0, Subregion->Name, "duplicate Subregion name");\r
+              ErrorCount++;\r
+            }\r
+          }\r
+        }\r
+      }\r
+\r
+      if (!SFPIsToken ("}")) {\r
+        Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected Region closing brace '}'", NULL);\r
+        WarningCount++;\r
+      }\r
+      //\r
+      // Add the region descriptor to the end of the linked list\r
+      //\r
+      if (FDDesc->LastRegion != NULL) {\r
+        FDDesc->LastRegion->Next = FBlockDesc;\r
+      } else {\r
+        FDDesc->Regions = FBlockDesc;\r
+      }\r
+\r
+      FDDesc->LastRegion = FBlockDesc;\r
+    }\r
+    //\r
+    // Make sure sum of sizes of regions adds up to size of flash device\r
+    //\r
+    if (RegionSizeLeft != 0) {\r
+      Error (\r
+        SFPGetFileName (),\r
+        SFPGetLineNumber (),\r
+        0,\r
+        NULL,\r
+        "sum of sizes of Regions (0x%08X) != flash device size (0x%08X) : delta = 0x%08X",\r
+        FDDesc->Size - RegionSizeLeft,\r
+        FDDesc->Size,\r
+        RegionSizeLeft\r
+        );\r
+      ErrorCount++;\r
+    }\r
+    //\r
+    // Look for closing brace\r
+    //\r
+    if (!SFPIsToken ("}")) {\r
+      Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected FlashDevice closing brace '}'", NULL);\r
+      WarningCount++;\r
+    }\r
+    //\r
+    // Add this flash description to the list\r
+    //\r
+    FDDesc->Next  = mFlashDevices;\r
+    mFlashDevices = FDDesc;\r
+  }\r
+\r
+  while (SFPIsKeyword ("FlashDeviceImage")) {\r
+    //\r
+    // Allocate memory for a new FD image definition\r
+    //\r
+    ImageDef = (IMAGE_DEFINITION *) _malloc (sizeof (IMAGE_DEFINITION));\r
+    if (ImageDef == NULL) {\r
+      Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
+      ErrorCount++;\r
+      goto Done;\r
+    }\r
+\r
+    memset (ImageDef, 0, sizeof (IMAGE_DEFINITION));\r
+    //\r
+    // Open brace -- warning if not there\r
+    //\r
+    if (!SFPIsToken ("{")) {\r
+      Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected {", NULL);\r
+      WarningCount++;\r
+    }\r
+    //\r
+    // Parse:  Name = "ImageName",\r
+    //\r
+    if (!SFPIsKeyword ("Name")) {\r
+      Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Name'", NULL);\r
+      ErrorCount++;\r
+      goto Done;\r
+    }\r
+\r
+    if (!SFPIsToken ("=")) {\r
+      Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+      WarningCount++;\r
+    }\r
+\r
+    if (!SFPGetQuotedString (ImageDef->Name, sizeof (ImageDef->Name))) {\r
+      Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted name of image", NULL);\r
+      ErrorCount++;\r
+      goto Done;\r
+    }\r
+\r
+    if (!SFPIsToken (",")) {\r
+      Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following image name", NULL);\r
+      WarningCount++;\r
+    }\r
+\r
+    while (1) {\r
+      //\r
+      // Parse: File { Name = "FV\FvOem.fv", Region = "REGION_OEM", Optional = TRUE }\r
+      //\r
+      if (SFPIsKeyword ("File")) {\r
+        ImageDefEntry = (IMAGE_DEFINITION_ENTRY *) _malloc (sizeof (IMAGE_DEFINITION_ENTRY));\r
+        if (ImageDefEntry == NULL) {\r
+          Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
+          ErrorCount++;\r
+          goto Done;\r
+        }\r
+\r
+        memset (ImageDefEntry, 0, sizeof (IMAGE_DEFINITION_ENTRY));\r
+        //\r
+        // Open brace -- warning if not there\r
+        //\r
+        if (!SFPIsToken ("{")) {\r
+          Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected {", NULL);\r
+          WarningCount++;\r
+        }\r
+        //\r
+        // Parse: Name = "FileName.txt"\r
+        //\r
+        if (!SFPIsKeyword ("Name")) {\r
+          Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Name'", NULL);\r
+          ErrorCount++;\r
+          goto Done;\r
+        }\r
+\r
+        if (!SFPIsToken ("=")) {\r
+          Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+          WarningCount++;\r
+        }\r
+\r
+        if (!SFPGetQuotedString (ImageDefEntry->Name, sizeof (ImageDefEntry->Name))) {\r
+          Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted name of file", NULL);\r
+          ErrorCount++;\r
+          goto Done;\r
+        }\r
+\r
+        if (!SFPIsToken (",")) {\r
+          Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following file name", NULL);\r
+          WarningCount++;\r
+        }\r
+        //\r
+        // Parse: Region = "REGION_NAME"\r
+        //\r
+        if (!SFPIsKeyword ("Region")) {\r
+          Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Region'", NULL);\r
+          ErrorCount++;\r
+          goto Done;\r
+        }\r
+\r
+        if (!SFPIsToken ("=")) {\r
+          Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+          WarningCount++;\r
+        }\r
+\r
+        if (!SFPGetQuotedString (ImageDefEntry->RegionName, sizeof (ImageDefEntry->RegionName))) {\r
+          Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted Region name", NULL);\r
+          ErrorCount++;\r
+          goto Done;\r
+        }\r
+\r
+        if (!SFPIsToken (",")) {\r
+          Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following Region name", NULL);\r
+          WarningCount++;\r
+        }\r
+        //\r
+        // Parse optional: Subregion = "SUBREGION_NAME"\r
+        //\r
+        if (SFPIsKeyword ("Subregion")) {\r
+          if (!SFPIsToken ("=")) {\r
+            Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+            WarningCount++;\r
+          }\r
+\r
+          if (!SFPGetQuotedString (ImageDefEntry->SubregionName, sizeof (ImageDefEntry->SubregionName))) {\r
+            Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted Subegion name", NULL);\r
+            ErrorCount++;\r
+            goto Done;\r
+          }\r
+\r
+          if (!SFPIsToken (",")) {\r
+            Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following Subregion name", NULL);\r
+            WarningCount++;\r
+          }\r
+          //\r
+          // For a given region, you can only place data using the region name, or the subregion names.\r
+          // In other words, you can't say File1->Region1 and File2->Region1.Subregion1. Enforce that\r
+          // here by checking that any previous entries with the same Region name had a Subregion specified\r
+          // as well.\r
+          //\r
+          for (TempImageDefEntry = ImageDef->Entries;\r
+               TempImageDefEntry != NULL;\r
+               TempImageDefEntry = TempImageDefEntry->Next\r
+              ) {\r
+            if (strcmp (TempImageDefEntry->Name, ImageDefEntry->Name) == 0) {\r
+              if (TempImageDefEntry->SubregionName[0] == 0) {\r
+                Error (\r
+                  SFPGetFileName (),\r
+                  SFPGetLineNumber (),\r
+                  0,\r
+                  TempImageDefEntry->RegionName,\r
+                  "data already placed on a region-basis in the region, can't place data using subregions"\r
+                  );\r
+                ErrorCount++;\r
+              }\r
+            }\r
+          }\r
+        }\r
+        //\r
+        // Optional parse: Optional = TRUE | FALSE\r
+        //\r
+        if (SFPIsKeyword ("Optional")) {\r
+          if (!SFPIsToken ("=")) {\r
+            Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+            WarningCount++;\r
+          }\r
+\r
+          if (!SFPIsKeyword ("TRUE")) {\r
+            ImageDefEntry->Optional = 1;\r
+          } else if (SFPIsKeyword ("FALSE")) {\r
+            //\r
+            // Already set to 0\r
+            //\r
+          } else {\r
+            Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL);\r
+            ErrorCount++;\r
+            goto Done;\r
+          }\r
+\r
+          SFPIsToken (",");\r
+        }\r
+        //\r
+        // Closing brace\r
+        //\r
+        if (!SFPIsToken ("}")) {\r
+          Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '}' closing brace to File entry", NULL);\r
+          ErrorCount++;\r
+          goto Done;\r
+        }\r
+        //\r
+        // Add the entry to the end of the list\r
+        //\r
+        if (ImageDef->LastEntry != NULL) {\r
+          ImageDef->LastEntry->Next = ImageDefEntry;\r
+        } else {\r
+          ImageDef->Entries = ImageDefEntry;\r
+        }\r
+\r
+        ImageDef->LastEntry = ImageDefEntry;\r
+      } else if (SFPIsKeyword ("RawData")) {\r
+        //\r
+        // Parse: RawData { Name = "PadBytes", Region = "REGION_1", Data = { 0x78, 0x56, 0x34, 0x12 }}\r
+        //\r
+        ImageDefEntry = (IMAGE_DEFINITION_ENTRY *) _malloc (sizeof (IMAGE_DEFINITION_ENTRY));\r
+        if (ImageDefEntry == NULL) {\r
+          Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
+          ErrorCount++;\r
+          goto Done;\r
+        }\r
+\r
+        memset (ImageDefEntry, 0, sizeof (IMAGE_DEFINITION_ENTRY));\r
+        ImageDefEntry->IsRawData = 1;\r
+        //\r
+        // Open brace -- warning if not there\r
+        //\r
+        if (!SFPIsToken ("{")) {\r
+          Warning (\r
+            SFPGetFileName (),\r
+            SFPGetLineNumber (),\r
+            0,\r
+            "expected '{' opening brace for RawData definition",\r
+            NULL\r
+            );\r
+          WarningCount++;\r
+        }\r
+        //\r
+        // Parse: Name = "PadBytes"\r
+        //\r
+        if (!SFPIsKeyword ("Name")) {\r
+          Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Name'", NULL);\r
+          ErrorCount++;\r
+          goto Done;\r
+        }\r
+\r
+        if (!SFPIsToken ("=")) {\r
+          Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+          WarningCount++;\r
+        }\r
+\r
+        if (!SFPGetQuotedString (ImageDefEntry->Name, sizeof (ImageDefEntry->Name))) {\r
+          Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted name of raw data", NULL);\r
+          ErrorCount++;\r
+          goto Done;\r
+        }\r
+\r
+        if (!SFPIsToken (",")) {\r
+          Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following raw data name", NULL);\r
+          WarningCount++;\r
+        }\r
+        //\r
+        // Parse: Region = "REGION_NAME"\r
+        //\r
+        if (!SFPIsKeyword ("Region")) {\r
+          Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Region'", NULL);\r
+          ErrorCount++;\r
+          goto Done;\r
+        }\r
+\r
+        if (!SFPIsToken ("=")) {\r
+          Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+          WarningCount++;\r
+        }\r
+\r
+        if (!SFPGetQuotedString (ImageDefEntry->RegionName, sizeof (ImageDefEntry->RegionName))) {\r
+          Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted Region name", NULL);\r
+          ErrorCount++;\r
+          goto Done;\r
+        }\r
+\r
+        if (!SFPIsToken (",")) {\r
+          Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following Region name", NULL);\r
+          WarningCount++;\r
+        }\r
+        //\r
+        // Parse optional: Subregion = "SUBREGION_NAME"\r
+        //\r
+        if (SFPIsKeyword ("Subregion")) {\r
+          if (!SFPIsToken ("=")) {\r
+            Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+            WarningCount++;\r
+          }\r
+\r
+          if (!SFPGetQuotedString (ImageDefEntry->SubregionName, sizeof (ImageDefEntry->SubregionName))) {\r
+            Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted Subegion name", NULL);\r
+            ErrorCount++;\r
+            goto Done;\r
+          }\r
+\r
+          if (!SFPIsToken (",")) {\r
+            Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following Subregion name", NULL);\r
+            WarningCount++;\r
+          }\r
+          //\r
+          // For a given region, you can only place data using the region name, or the subregion names.\r
+          // In other words, you can't say File1->Region1 and File2->Region1.Subregion1. Enforce that\r
+          // here by checking that any previous entries with the same Region name had a Subregion specified\r
+          // as well.\r
+          //\r
+          for (TempImageDefEntry = ImageDef->Entries;\r
+               TempImageDefEntry != NULL;\r
+               TempImageDefEntry = TempImageDefEntry->Next\r
+              ) {\r
+            if (strcmp (TempImageDefEntry->Name, ImageDefEntry->Name) == 0) {\r
+              if (TempImageDefEntry->SubregionName[0] == 0) {\r
+                Error (\r
+                  SFPGetFileName (),\r
+                  SFPGetLineNumber (),\r
+                  0,\r
+                  TempImageDefEntry->RegionName,\r
+                  "data already placed on a region-basis in the region, can't place data using subregions"\r
+                  );\r
+                ErrorCount++;\r
+              }\r
+            }\r
+          }\r
+        }\r
+        //\r
+        // Parse: Data = { 0x78, 0x56, 0x34, 0x12 }\r
+        //\r
+        if (!SFPIsKeyword ("Data")) {\r
+          Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Data'", NULL);\r
+          ErrorCount++;\r
+          goto Done;\r
+        }\r
+\r
+        if (!SFPIsToken ("=")) {\r
+          Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+          WarningCount++;\r
+        }\r
+\r
+        if (!SFPIsToken ("{")) {\r
+          Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '{' preceeding data list", NULL);\r
+          WarningCount++;\r
+        }\r
+\r
+        if ((BufferData = CreateBufferData ()) == NULL) {\r
+          ErrorCount++;\r
+          goto Done;\r
+        }\r
+        //\r
+        // Read bytes from input file until closing brace\r
+        //\r
+        while (!SFPIsToken ("}")) {\r
+          if (!SFPGetNumber (&Num)) {\r
+            SFPGetNextToken (Str, sizeof (Str));\r
+            Error (SFPGetFileName (), SFPGetLineNumber (), 0, Str, "expected data value", Str);\r
+            ErrorCount++;\r
+            FreeBufferData (BufferData, TRUE);\r
+            goto Done;\r
+          } else {\r
+            //\r
+            // Only allow bytes\r
+            //\r
+            if (Num > 0xFF) {\r
+              Error (SFPGetFileName (), SFPGetLineNumber (), 0, "only values 0-255 (0x00-0xFF) allowed", NULL);\r
+              ErrorCount++;\r
+              FreeBufferData (BufferData, TRUE);\r
+              goto Done;\r
+            }\r
+\r
+            AddBufferDataByte (BufferData, (char) Num);\r
+            SFPIsToken (",");\r
+          }\r
+        }\r
+        //\r
+        // Now get the data and save it in our image entry\r
+        //\r
+        ImageDefEntry->RawData = GetBufferData (BufferData, &ImageDefEntry->RawDataSize);\r
+        FreeBufferData (BufferData, 0);\r
+        //\r
+        // Closing brace for RawData {}\r
+        //\r
+        if (!SFPIsToken ("}")) {\r
+          Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '}' closing brace for RawData", NULL);\r
+          ErrorCount++;\r
+          goto Done;\r
+        }\r
+        //\r
+        // Add the entry to the end of the list\r
+        //\r
+        if (ImageDef->LastEntry != NULL) {\r
+          ImageDef->LastEntry->Next = ImageDefEntry;\r
+        } else {\r
+          ImageDef->Entries = ImageDefEntry;\r
+        }\r
+\r
+        ImageDef->LastEntry = ImageDefEntry;\r
+      } else if (SFPIsToken ("}")) {\r
+        //\r
+        // Closing brace for FDImage {}\r
+        //\r
+        break;\r
+      } else {\r
+        SFPGetNextToken (Str, sizeof (Str));\r
+        Error (SFPGetFileName (), SFPGetLineNumber (), 0, Str, "unrecognized token", Str);\r
+        ErrorCount++;\r
+        goto Done;\r
+      }\r
+    }\r
+    //\r
+    // Add this image definition to our global list\r
+    //\r
+    ImageDef->Next    = mImageDefinitions;\r
+    mImageDefinitions = ImageDef;\r
+  }\r
+  //\r
+  // Check for end-of-file\r
+  //\r
+  if (!SFPIsEOF ()) {\r
+    SFPGetNextToken (Str, sizeof (Str));\r
+    Error (SFPGetFileName (), SFPGetLineNumber (), 0, Str, "expected end-of-file", Str);\r
+    ErrorCount++;\r
+  }\r
+\r
+Done:\r
+  SFPCloseFile ();\r
+  if (ErrorCount != 0) {\r
+    return STATUS_ERROR;\r
+  } else if (WarningCount != 0) {\r
+    return STATUS_WARNING;\r
+  }\r
+\r
+  return STATUS_SUCCESS;\r
+}\r
+\r
+static\r
+FLASH_SUBREGION_DESCRIPTION *\r
+ParseSubregionDefinition (\r
+  unsigned int  SizeLeft\r
+  )\r
+/*++\r
+  \r
+Routine Description:\r
+\r
+  Parse Subregion definitions from the input flash definition file. Format:\r
+\r
+    Subregion {\r
+      CreateHob       = TRUE,\r
+      Name            = "FOO",\r
+      Size            = 0xA000,\r
+      Attributes      = "EFI_FLASH_AREA_SUBFV | EFI_FLASH_AREA_MEMMAPPED_FV",\r
+      AreaType        = "EFI_FLASH_AREA_EFI_VARIABLES",\r
+      NameGuid        = 12345678-1234-5678-AAAA-BBBBCCCCDDDD (or "EFI_SOME_GUID"),\r
+      AreaTypeGuid    = 11111111-2222-3333-4444-1, (or "EFI_SOME_GUID") (optional)\r
+      FileSystemGuid  = 11111111-2222-3333-4444-1, (or "EFI_SOME_GUID") (optional)\r
+    }\r
+\r
+    NOTE: The caller has already parsed the "Subregion" token, so start with the opening brace.\r
+\r
+Arguments:\r
+   \r
+   SizeLeft   - in the flash definition file, a Region can be broken up into\r
+                one or more subregions. As we parse the subregion definitions,\r
+                the caller keeps track of how much space is left in the region\r
+                that we're parsing subregions for. SizeLeft is that size, and\r
+                so the size of the subregion we're now parsing better not\r
+                exceed the size left.\r
+  Returns:\r
+\r
+    NULL    - unrecoverable errors detected while parsing the subregion definition\r
+\r
+    pointer to a subregion definition created from the parsed subregion\r
+\r
+--*/\r
+{\r
+  FLASH_SUBREGION_DESCRIPTION *Subregion;\r
+  int                         ErrorCount;\r
+  int                         WarningCount;\r
+  unsigned int                Number;\r
+  BOOLEAN                     PreviousComma;\r
+  //\r
+  // Allocate memory for the new subregion descriptor\r
+  //\r
+  ErrorCount    = 0;\r
+  WarningCount  = 0;\r
+  Subregion     = (FLASH_SUBREGION_DESCRIPTION *) _malloc (sizeof (FLASH_SUBREGION_DESCRIPTION));\r
+  if (Subregion == NULL) {\r
+    Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
+    ErrorCount++;\r
+    goto Done;\r
+  }\r
+\r
+  memset (Subregion, 0, sizeof (FLASH_SUBREGION_DESCRIPTION));\r
+  //\r
+  // Open brace -- warning if not there\r
+  //\r
+  if (!SFPIsToken ("{")) {\r
+    Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected {", NULL);\r
+    WarningCount++;\r
+  }\r
+  //\r
+  // Parse:  CreateHob = TRUE | FALSE,\r
+  //\r
+  if (!SFPIsKeyword ("CreateHob")) {\r
+    Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'CreateHob'", NULL);\r
+    ErrorCount++;\r
+    goto Done;\r
+  }\r
+\r
+  if (!SFPIsToken ("=")) {\r
+    Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+    WarningCount++;\r
+  }\r
+\r
+  if (SFPIsToken ("TRUE")) {\r
+    Subregion->CreateHob = 1;\r
+  } else if (SFPIsToken ("FALSE")) {\r
+    //\r
+    // Subregion->CreateHob = 0; -- not required since we did a memset earlier\r
+    //\r
+  } else {\r
+    Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL);\r
+    ErrorCount++;\r
+    goto Done;\r
+  }\r
+\r
+  if (!SFPIsToken (",")) {\r
+    Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected ',' following CreateHob value", NULL);\r
+    WarningCount++;\r
+  }\r
+  //\r
+  // Parse:  Name = "Name",\r
+  //\r
+  if (!SFPIsKeyword ("Name")) {\r
+    Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Name'", NULL);\r
+    ErrorCount++;\r
+    goto Done;\r
+  }\r
+\r
+  if (!SFPIsToken ("=")) {\r
+    Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+    WarningCount++;\r
+  }\r
+\r
+  if (!SFPGetQuotedString (Subregion->Name, sizeof (Subregion->Name))) {\r
+    Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected Subregion name", NULL);\r
+    ErrorCount++;\r
+    goto Done;\r
+  }\r
+\r
+  if (!SFPIsToken (",")) {\r
+    Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected comma following Region name", NULL);\r
+    WarningCount++;\r
+  }\r
+  //\r
+  // Parse: Size = 0x2000,\r
+  //\r
+  if (!SFPIsKeyword ("Size")) {\r
+    Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Size'", NULL);\r
+    ErrorCount++;\r
+    goto Done;\r
+  }\r
+\r
+  if (!SFPIsToken ("=")) {\r
+    Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+    WarningCount++;\r
+  }\r
+\r
+  if (!SFPGetNumber (&Subregion->Size)) {\r
+    Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected numeric Size value", NULL);\r
+    ErrorCount++;\r
+    goto Done;\r
+  }\r
+\r
+  //\r
+  // Check that the size does not exceed the size left passed in\r
+  //\r
+  if (Subregion->Size > SizeLeft) {\r
+    Error (SFPGetFileName (), SFPGetLineNumber (), 0, "sum of Subregion sizes exceeds Region size", NULL);\r
+    ErrorCount++;\r
+    goto Done;\r
+  }\r
+\r
+  if (!SFPIsToken (",")) {\r
+    Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected ',' following Size value", NULL);\r
+  }\r
+  //\r
+  // Parse:  Attributes = Number | "String",\r
+  //\r
+  if (!SFPIsKeyword ("Attributes")) {\r
+    Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'Attributes'", NULL);\r
+    ErrorCount++;\r
+    goto Done;\r
+  }\r
+\r
+  if (!SFPIsToken ("=")) {\r
+    Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+    WarningCount++;\r
+  }\r
+\r
+  if (SFPGetNumber (&Number)) {\r
+    sprintf (Subregion->Attributes, "0x%X", Number);\r
+  } else if (!SFPGetQuotedString (Subregion->Attributes, sizeof (Subregion->Attributes))) {\r
+    Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted Attributes string", NULL);\r
+    ErrorCount++;\r
+    goto Done;\r
+  }\r
+\r
+  if (!SFPIsToken (",")) {\r
+    Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected ','", NULL);\r
+  }\r
+  //\r
+  // Parse:  AreaType = Number | "String",\r
+  // AreaType is a UINT8, so error if it exceeds the size\r
+  //\r
+  if (!SFPIsKeyword ("AreaType")) {\r
+    Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'AreaType'", NULL);\r
+    ErrorCount++;\r
+    goto Done;\r
+  }\r
+\r
+  if (!SFPIsToken ("=")) {\r
+    Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+    WarningCount++;\r
+  }\r
+\r
+  if (SFPGetNumber (&Number)) {\r
+    if (Number > 0xFF) {\r
+      Error (SFPGetFileName (), SFPGetLineNumber (), 0, "AreaType value exceeds 255", NULL);\r
+      ErrorCount++;\r
+    }\r
+\r
+    sprintf (Subregion->AreaType, "0x%X", Number & 0x00FF);\r
+  } else if (!SFPGetQuotedString (Subregion->AreaType, sizeof (Subregion->AreaType))) {\r
+    Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected quoted AreaType string", NULL);\r
+    ErrorCount++;\r
+    goto Done;\r
+  }\r
+\r
+  if (!SFPIsToken (",")) {\r
+    Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected ',' following AreaType value", NULL);\r
+  }\r
+  //\r
+  // Parse the three GUIDs (last two are optional)\r
+  //\r
+  //    NameGuid        = 12345678-1234-5678-AAAA-BBBBCCCCDDDD, (or "EFI_SOME_GUID")\r
+  //    AreaTypeGuid    = 11111111-2222-3333-4444-1, (or "EFI_SOME_GUID")\r
+  //    FileSysteGuid   = 11111111-2222-3333-4444-1, (or "EFI_SOME_GUID")\r
+  //\r
+  if (!SFPIsKeyword ("NameGuid")) {\r
+    Error (SFPGetFileName (), SFPGetLineNumber (), 0, "expected 'NameGuid'", NULL);\r
+    ErrorCount++;\r
+    goto Done;\r
+  }\r
+\r
+  if (!SFPIsToken ("=")) {\r
+    Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+    WarningCount++;\r
+  }\r
+  //\r
+  // Allow a GUID or a quoted string identifier, which we'll just copy as a string\r
+  //\r
+  if (SFPGetQuotedString (Subregion->NameGuidString, sizeof (Subregion->NameGuidString))) {\r
+    //\r
+    // Nothing else to do\r
+    //\r
+  } else if (!SFPGetGuid (PARSE_GUID_STYLE_5_FIELDS, &Subregion->NameGuid)) {\r
+    Error (\r
+      SFPGetFileName (),\r
+      SFPGetLineNumber (),\r
+      0,\r
+      "expected NameGuid quoted string or GUID of form 12345678-1234-1234-1234-123456789ABC",\r
+      NULL\r
+      );\r
+    ErrorCount++;\r
+    goto Done;\r
+  }\r
+  //\r
+  // Comma following NameGuid is optional if they don't specify AreaTypeGuid or FileSystemGuid\r
+  //\r
+  PreviousComma = SFPIsToken (",");\r
+  if (SFPIsKeyword ("AreaTypeGuid")) {\r
+    //\r
+    // Check for preceeding comma now\r
+    //\r
+    if (!PreviousComma) {\r
+      Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected ',' before 'AreaTypeGuid'", NULL);\r
+      WarningCount++;\r
+    }\r
+\r
+    if (!SFPIsToken ("=")) {\r
+      Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+      WarningCount++;\r
+    }\r
+\r
+    if (SFPGetQuotedString (Subregion->AreaTypeGuidString, sizeof (Subregion->AreaTypeGuidString))) {\r
+      //\r
+      // Nothing else to do\r
+      //\r
+    } else if (!SFPGetGuid (PARSE_GUID_STYLE_5_FIELDS, &Subregion->AreaTypeGuid)) {\r
+      Error (\r
+        SFPGetFileName (),\r
+        SFPGetLineNumber (),\r
+        0,\r
+        "expected AreaTypeGuid quoted string or GUID of form 12345678-1234-1234-1234-123456789ABC",\r
+        NULL\r
+        );\r
+      ErrorCount++;\r
+      goto Done;\r
+    }\r
+\r
+    PreviousComma = SFPIsToken (",");\r
+  }\r
+\r
+  if (SFPIsKeyword ("FileSystemGuid")) {\r
+    //\r
+    // Check for preceeding comma now\r
+    //\r
+    if (!PreviousComma) {\r
+      Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected ',' before 'FileSystemGuid'", NULL);\r
+      WarningCount++;\r
+    }\r
+\r
+    if (!SFPIsToken ("=")) {\r
+      Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected '='", NULL);\r
+      WarningCount++;\r
+    }\r
+    //\r
+    // Allow a GUID or a quoted string identifier, which we'll just copy as a string\r
+    //\r
+    if (SFPGetQuotedString (Subregion->FileSystemGuidString, sizeof (Subregion->FileSystemGuidString))) {\r
+      //\r
+      // Nothing else to do\r
+      //\r
+    } else if (!SFPGetGuid (PARSE_GUID_STYLE_5_FIELDS, &Subregion->FileSystemGuid)) {\r
+      Error (\r
+        SFPGetFileName (),\r
+        SFPGetLineNumber (),\r
+        0,\r
+        "expected FileSystemGuid quoted string or GUID of form 12345678-1234-1234-1234-123456789ABC",\r
+        NULL\r
+        );\r
+      ErrorCount++;\r
+      goto Done;\r
+    }\r
+\r
+    SFPIsToken (",");\r
+  }\r
+  //\r
+  // Look for subregion closing brace\r
+  //\r
+  if (!SFPIsToken ("}")) {\r
+    Warning (SFPGetFileName (), SFPGetLineNumber (), 0, "expected Subregion closing brace '}'", NULL);\r
+    WarningCount++;\r
+  }\r
+\r
+Done:\r
+  //\r
+  // If any errors were encountered, then delete the subregion definition\r
+  //\r
+  if (ErrorCount != 0) {\r
+    _free (Subregion);\r
+    Subregion = NULL;\r
+  }\r
+\r
+  return Subregion;\r
+}\r
+\r
+STATUS\r
+FDFCreateCIncludeFile (\r
+  char      *FlashDeviceName,\r
+  char      *FileName\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Create a header file with #define definitions per an already-parsed\r
+  flash definition file.\r
+\r
+Arguments:\r
+  FlashDeviceName - name of flash device (from the flash definition file)\r
+                    to use\r
+  FileName        - name of output file to create\r
+\r
+Returns:\r
+  STATUS_SUCCESS    - no errors or warnings\r
+  STATUS_WARNING    - warnings, but no errors, were encountered\r
+  STATUS_ERROR      - errors were encountered\r
+\r
+--*/\r
+{\r
+  FILE                        *OutFptr;\r
+  FLASH_BLOCK_DESCRIPTION     *FBlock;\r
+  FLASH_DEVICE_DESCRIPTION    *FDev;\r
+  FLASH_SUBREGION_DESCRIPTION *Subregion;\r
+  unsigned int                Offset;\r
+  unsigned int                SubregionOffset;\r
+  int                         CreateHobs;\r
+  //\r
+  // Find the definition we're supposed to use\r
+  //\r
+  for (FDev = mFlashDevices; FDev != NULL; FDev = FDev->Next) {\r
+    if (strcmp (FDev->Name, FlashDeviceName) == 0) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (FDev == NULL) {\r
+    Error (NULL, 0, 0, NULL, FlashDeviceName, "flash device not found in flash definitions");\r
+    return STATUS_ERROR;\r
+  }\r
+\r
+  if ((OutFptr = fopen (FileName, "w")) == NULL) {\r
+    Error (NULL, 0, 0, FileName, "failed to open output file for writing");\r
+    return STATUS_ERROR;\r
+  }\r
+  //\r
+  // Write a header\r
+  //\r
+  fprintf (OutFptr, CIncludeHeader);\r
+  //\r
+  // Write flash block base and size defines\r
+  //\r
+  fprintf (OutFptr, "#define FLASH_BASE                                          0x%08X\n", FDev->BaseAddress);\r
+  fprintf (OutFptr, "#define FLASH_SIZE                                          0x%08X\n\n", FDev->Size);\r
+  //\r
+  // Write flash regions base, size and offset defines\r
+  //\r
+  Offset      = 0;\r
+  CreateHobs  = 0;\r
+  for (FBlock = FDev->Regions; FBlock != NULL; FBlock = FBlock->Next) {\r
+    fprintf (\r
+      OutFptr,\r
+      "#define FLASH_REGION_%s_BASE              %*c0x%08X\n",\r
+      FBlock->Name,\r
+      COLUMN2_START - 40 - strlen (FBlock->Name),\r
+      ' ',\r
+      Offset + FDev->BaseAddress\r
+      );\r
+    fprintf (\r
+      OutFptr,\r
+      "#define FLASH_REGION_%s_SIZE              %*c0x%08X\n",\r
+      FBlock->Name,\r
+      COLUMN2_START - 40 - strlen (FBlock->Name),\r
+      ' ',\r
+      FBlock->Size\r
+      );\r
+    fprintf (\r
+      OutFptr,\r
+      "#define FLASH_REGION_%s_OFFSET            %*c0x%08X\n",\r
+      FBlock->Name,\r
+      COLUMN2_START - 40 - strlen (FBlock->Name),\r
+      ' ',\r
+      Offset\r
+      );\r
+    //\r
+    // Create defines for any subregions\r
+    //\r
+    SubregionOffset = 0;\r
+    for (Subregion = FBlock->Subregions; Subregion != NULL; Subregion = Subregion->Next) {\r
+      fprintf (\r
+        OutFptr,\r
+        "#define FLASH_REGION_%s_SUBREGION_%s_BASE     %*c0x%08X\n",\r
+        FBlock->Name,\r
+        Subregion->Name,\r
+        COLUMN3_START - 43 - strlen (FBlock->Name) - strlen (Subregion->Name),\r
+        ' ',\r
+        FDev->BaseAddress + Offset + SubregionOffset\r
+        );\r
+      fprintf (\r
+        OutFptr,\r
+        "#define FLASH_REGION_%s_SUBREGION_%s_SIZE     %*c0x%08X\n",\r
+        FBlock->Name,\r
+        Subregion->Name,\r
+        COLUMN3_START - 43 - strlen (FBlock->Name) - strlen (Subregion->Name),\r
+        ' ',\r
+        Subregion->Size\r
+        );\r
+      fprintf (\r
+        OutFptr,\r
+        "#define FLASH_REGION_%s_SUBREGION_%s_OFFSET   %*c0x%08X\n",\r
+        FBlock->Name,\r
+        Subregion->Name,\r
+        COLUMN3_START - 43 - strlen (FBlock->Name) - strlen (Subregion->Name),\r
+        ' ',\r
+        Offset + SubregionOffset\r
+        );\r
+      SubregionOffset += Subregion->Size;\r
+      if (Subregion->CreateHob != 0) {\r
+        CreateHobs = 1;\r
+      }\r
+    }\r
+\r
+    Offset += FBlock->Size;\r
+  }\r
+  //\r
+  // Now create a #define for the flash map data definition\r
+  //\r
+  fprintf (OutFptr, "\n\n#define EFI_FLASH_AREA_DATA_DEFINITION \\\n");\r
+  //\r
+  // Emit entry for each region\r
+  //\r
+  Offset = 0;\r
+  for (FBlock = FDev->Regions; FBlock != NULL; FBlock = FBlock->Next) {\r
+    fprintf (OutFptr, "  /* %s region */\\\n", FBlock->Name);\r
+    fprintf (OutFptr, "  {\\\n");\r
+    fprintf (OutFptr, "    FLASH_REGION_%s_BASE,\\\n", FBlock->Name);\r
+    fprintf (OutFptr, "    FLASH_REGION_%s_SIZE,\\\n", FBlock->Name);\r
+    fprintf (OutFptr, "    %s,\\\n", FBlock->Attributes);\r
+    fprintf (OutFptr, "    %s,\\\n  },\\\n", FBlock->AreaType);\r
+  }\r
+\r
+  fprintf (OutFptr, "\n\n");\r
+  //\r
+  // Now walk the list again to create the EFI_HOB_FLASH_MAP_ENTRY_TYPE definition\r
+  //\r
+  if (CreateHobs != 0) {\r
+    fprintf (OutFptr, "//\n// EFI_HOB_FLASH_MAP_ENTRY_TYPE definition\n//\n");\r
+    fprintf (OutFptr, "#define EFI_HOB_FLASH_MAP_ENTRY_TYPE_DATA_DEFINITION");\r
+    for (FBlock = FDev->Regions; FBlock != NULL; FBlock = FBlock->Next) {\r
+      //\r
+      // See if the block has subregions, and that the CreateHobs flag is set\r
+      // for any of them.\r
+      //\r
+      CreateHobs = 0;\r
+      for (Subregion = FBlock->Subregions; Subregion != NULL; Subregion = Subregion->Next) {\r
+        if (Subregion->CreateHob != 0) {\r
+          CreateHobs = 1;\r
+          break;\r
+        }\r
+      }\r
+      //\r
+      // If any of the subregions had the CreateHobs flag set, then create the entries in the\r
+      // output file\r
+      //\r
+      if (CreateHobs != 0) {\r
+        for (Subregion = FBlock->Subregions; Subregion != NULL; Subregion = Subregion->Next) {\r
+          if (Subregion->CreateHob != 0) {\r
+            fprintf (OutFptr, " \\\n");\r
+            fprintf (OutFptr, "  /* %s.%s Subregion */\\\n", FBlock->Name, Subregion->Name);\r
+            fprintf (OutFptr, "  {\\\n");\r
+            fprintf (OutFptr, "    EFI_HOB_TYPE_GUID_EXTENSION,\\\n");\r
+            fprintf (OutFptr, "    sizeof (EFI_HOB_FLASH_MAP_ENTRY_TYPE ),\\\n");\r
+            fprintf (OutFptr, "    0,\\\n");\r
+            //\r
+            // The NameGuid may have been specified in the input flash definition file as a GUID, or\r
+            // as a quoted string. Do the right one.\r
+            //\r
+            if (Subregion->NameGuidString[0] != 0) {\r
+              fprintf (OutFptr, "    %s, \\\n", Subregion->NameGuidString);\r
+            } else {\r
+              fprintf (\r
+                OutFptr,\r
+                "    { 0x%08X, 0x%04X, 0x%04X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X },\\\n",\r
+                Subregion->NameGuid.Data1,\r
+                (unsigned int) Subregion->NameGuid.Data2,\r
+                (unsigned int) Subregion->NameGuid.Data3,\r
+                (unsigned int) Subregion->NameGuid.Data4[0],\r
+                (unsigned int) Subregion->NameGuid.Data4[1],\r
+                (unsigned int) Subregion->NameGuid.Data4[2],\r
+                (unsigned int) Subregion->NameGuid.Data4[3],\r
+                (unsigned int) Subregion->NameGuid.Data4[4],\r
+                (unsigned int) Subregion->NameGuid.Data4[5],\r
+                (unsigned int) Subregion->NameGuid.Data4[6],\r
+                (unsigned int) Subregion->NameGuid.Data4[7]\r
+                );\r
+            }\r
+\r
+            fprintf (OutFptr, "    0, 0, 0,\\\n");\r
+            fprintf (OutFptr, "    %s,\\\n", Subregion->AreaType);\r
+            //\r
+            // The AreaTypeGuid may have been specified in the input flash definition file as a GUID, or\r
+            // as a quoted string. Do the right one.\r
+            //\r
+            if (Subregion->AreaTypeGuidString[0] != 0) {\r
+              fprintf (OutFptr, "    %s, \\\n", Subregion->AreaTypeGuidString);\r
+            } else {\r
+              fprintf (\r
+                OutFptr,\r
+                "    { 0x%08X, 0x%04X, 0x%04X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X },\\\n",\r
+                Subregion->AreaTypeGuid.Data1,\r
+                (unsigned int) Subregion->AreaTypeGuid.Data2,\r
+                (unsigned int) Subregion->AreaTypeGuid.Data3,\r
+                (unsigned int) Subregion->AreaTypeGuid.Data4[0],\r
+                (unsigned int) Subregion->AreaTypeGuid.Data4[1],\r
+                (unsigned int) Subregion->AreaTypeGuid.Data4[2],\r
+                (unsigned int) Subregion->AreaTypeGuid.Data4[3],\r
+                (unsigned int) Subregion->AreaTypeGuid.Data4[4],\r
+                (unsigned int) Subregion->AreaTypeGuid.Data4[5],\r
+                (unsigned int) Subregion->AreaTypeGuid.Data4[6],\r
+                (unsigned int) Subregion->AreaTypeGuid.Data4[7]\r
+                );\r
+            }\r
+\r
+            fprintf (OutFptr, "    1,\\\n");\r
+            fprintf (OutFptr, "    {\\\n");\r
+            fprintf (OutFptr, "      %s,\\\n", Subregion->Attributes);\r
+            fprintf (OutFptr, "      0,\\\n");\r
+            fprintf (OutFptr, "      FLASH_REGION_%s_SUBREGION_%s_BASE,\\\n", FBlock->Name, Subregion->Name);\r
+            fprintf (OutFptr, "      FLASH_REGION_%s_SUBREGION_%s_SIZE,\\\n", FBlock->Name, Subregion->Name);\r
+            //\r
+            // The FileSystemGuid may have been specified in the input flash definition file as a GUID, or\r
+            // as a quoted string. Do the right one.\r
+            //\r
+            if (Subregion->FileSystemGuidString[0] != 0) {\r
+              fprintf (OutFptr, "      %s, \\\n", Subregion->FileSystemGuidString);\r
+            } else {\r
+              fprintf (\r
+                OutFptr,\r
+                "      { 0x%08X, 0x%04X, 0x%04X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X, 0x%02X },\\\n",\r
+                Subregion->FileSystemGuid.Data1,\r
+                (unsigned int) Subregion->FileSystemGuid.Data2,\r
+                (unsigned int) Subregion->FileSystemGuid.Data3,\r
+                (unsigned int) Subregion->FileSystemGuid.Data4[0],\r
+                (unsigned int) Subregion->FileSystemGuid.Data4[1],\r
+                (unsigned int) Subregion->FileSystemGuid.Data4[2],\r
+                (unsigned int) Subregion->FileSystemGuid.Data4[3],\r
+                (unsigned int) Subregion->FileSystemGuid.Data4[4],\r
+                (unsigned int) Subregion->FileSystemGuid.Data4[5],\r
+                (unsigned int) Subregion->FileSystemGuid.Data4[6],\r
+                (unsigned int) Subregion->FileSystemGuid.Data4[7]\r
+                );\r
+            }\r
+\r
+            fprintf (OutFptr, "    },\\\n");\r
+            fprintf (OutFptr, "  },");\r
+          }\r
+        }\r
+      }\r
+    }\r
+\r
+    fprintf (OutFptr, "\n\n");\r
+  }\r
+\r
+  //\r
+  // Write the file's closing #endif\r
+  //\r
+  fprintf (OutFptr, CIncludeFooter);\r
+  fclose (OutFptr);\r
+  return STATUS_SUCCESS;\r
+}\r
+\r
+STATUS\r
+FDFCreateAsmIncludeFile (\r
+  char      *FlashDeviceName,\r
+  char      *FileName\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Create an assembly header file with equate definitions per an already-parsed\r
+  flash definition file.\r
+\r
+Arguments:\r
+  FlashDeviceName - name of flash device (from the flash definition file)\r
+                    to use\r
+  FileName        - name of output file to create\r
+\r
+Returns:\r
+  STATUS_SUCCESS    - no errors or warnings\r
+  STATUS_WARNING    - warnings, but no errors, were encountered\r
+  STATUS_ERROR      - errors were encountered\r
+\r
+--*/\r
+{\r
+  FILE                        *OutFptr;\r
+  FLASH_BLOCK_DESCRIPTION     *FBlock;\r
+  FLASH_DEVICE_DESCRIPTION    *FDev;\r
+  unsigned int                Offset;\r
+  FLASH_SUBREGION_DESCRIPTION *Subregion;\r
+  unsigned int                SubregionOffset;\r
+  //\r
+  // Find the definition we're supposed to use\r
+  //\r
+  for (FDev = mFlashDevices; FDev != NULL; FDev = FDev->Next) {\r
+    if (strcmp (FDev->Name, FlashDeviceName) == 0) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (FDev == NULL) {\r
+    Error (NULL, 0, 0, NULL, FlashDeviceName, "flash device not found in flash definitions");\r
+    return STATUS_ERROR;\r
+  }\r
+\r
+  if ((OutFptr = fopen (FileName, "w")) == NULL) {\r
+    Error (NULL, 0, 0, FileName, "failed to open output file for writing");\r
+    return STATUS_ERROR;\r
+  }\r
+  //\r
+  // Write a header\r
+  //\r
+  fprintf (OutFptr, "\n\n");\r
+  //\r
+  // Write flash block size and offset defines\r
+  //\r
+  fprintf (\r
+    OutFptr,\r
+    "FLASH_BASE                               %*cequ 0%08Xh\n",\r
+    COLUMN2_START - 40,\r
+    ' ',\r
+    FDev->BaseAddress\r
+    );\r
+  fprintf (OutFptr, "FLASH_SIZE                               %*cequ 0%08Xh\n", COLUMN2_START - 40, ' ', FDev->Size);\r
+  //\r
+  // Write flash region size and offset defines\r
+  //\r
+  fprintf (OutFptr, "\n");\r
+  Offset = 0;\r
+  for (FBlock = FDev->Regions; FBlock != NULL; FBlock = FBlock->Next) {\r
+    fprintf (\r
+      OutFptr,\r
+      "FLASH_REGION_%s_BASE   %*cequ 0%08Xh\n",\r
+      FBlock->Name,\r
+      COLUMN2_START - 20 - strlen (FBlock->Name),\r
+      ' ',\r
+      FDev->BaseAddress + Offset\r
+      );\r
+    fprintf (\r
+      OutFptr,\r
+      "FLASH_REGION_%s_SIZE   %*cequ 0%08Xh\n",\r
+      FBlock->Name,\r
+      COLUMN2_START - 20 - strlen (FBlock->Name),\r
+      ' ',\r
+      FBlock->Size\r
+      );\r
+    fprintf (\r
+      OutFptr,\r
+      "FLASH_REGION_%s_OFFSET %*cequ 0%08Xh\n",\r
+      FBlock->Name,\r
+      COLUMN2_START - 20 - strlen (FBlock->Name),\r
+      ' ',\r
+      Offset\r
+      );\r
+    //\r
+    // Create defines for any subregions\r
+    //\r
+    SubregionOffset = 0;\r
+    for (Subregion = FBlock->Subregions; Subregion != NULL; Subregion = Subregion->Next) {\r
+      fprintf (\r
+        OutFptr,\r
+        "FLASH_REGION_%s_SUBREGION_%s_BASE     %*cequ 0%08Xh\n",\r
+        FBlock->Name,\r
+        Subregion->Name,\r
+        COLUMN3_START - 39 - strlen (FBlock->Name) - strlen (Subregion->Name),\r
+        ' ',\r
+        FDev->BaseAddress + Offset + SubregionOffset\r
+        );\r
+      fprintf (\r
+        OutFptr,\r
+        "FLASH_REGION_%s_SUBREGION_%s_SIZE     %*cequ 0%08Xh\n",\r
+        FBlock->Name,\r
+        Subregion->Name,\r
+        COLUMN3_START - 39 - strlen (FBlock->Name) - strlen (Subregion->Name),\r
+        ' ',\r
+        Subregion->Size\r
+        );\r
+      fprintf (\r
+        OutFptr,\r
+        "FLASH_REGION_%s_SUBREGION_%s_OFFSET   %*cequ 0%08Xh\n",\r
+        FBlock->Name,\r
+        Subregion->Name,\r
+        COLUMN3_START - 39 - strlen (FBlock->Name) - strlen (Subregion->Name),\r
+        ' ',\r
+        Offset + SubregionOffset\r
+        );\r
+      SubregionOffset += Subregion->Size;\r
+    }\r
+\r
+    Offset += FBlock->Size;\r
+  }\r
+\r
+  //\r
+  // Write closing \n\r
+  //\r
+  fprintf (OutFptr, "\n\n");\r
+  fclose (OutFptr);\r
+  return STATUS_SUCCESS;\r
+}\r
+\r
+STATUS\r
+FDFCreateSymbols (\r
+  char      *FlashDeviceName\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Using the given flash device name, add symbols to the global symbol table. This\r
+  allows other functions to use the symbol definitions for other purposes.\r
+\r
+Arguments:\r
+  FlashDeviceName - name of flash device (from the flash definition file)\r
+                    to use\r
+\r
+Returns:\r
+  STATUS_SUCCESS    - no errors or warnings\r
+  STATUS_WARNING    - warnings, but no errors, were encountered\r
+  STATUS_ERROR      - errors were encountered\r
+\r
+--*/\r
+{\r
+  FLASH_BLOCK_DESCRIPTION     *FBlock;\r
+  FLASH_DEVICE_DESCRIPTION    *FDev;\r
+  unsigned int                Offset;\r
+  char                        SymName[120];\r
+  char                        SymValue[120];\r
+  FLASH_SUBREGION_DESCRIPTION *Subregion;\r
+  unsigned int                SubregionOffset;\r
+  //\r
+  // Find the definition we're supposed to use\r
+  //\r
+  for (FDev = mFlashDevices; FDev != NULL; FDev = FDev->Next) {\r
+    if (strcmp (FDev->Name, FlashDeviceName) == 0) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (FDev == NULL) {\r
+    Error (NULL, 0, 0, NULL, FlashDeviceName, "flash device not found in flash definitions");\r
+    return STATUS_ERROR;\r
+  }\r
+\r
+  sprintf (SymValue, "0x%08X", FDev->BaseAddress);\r
+  SymbolAdd ("FLASH_BASE", SymValue, 0);\r
+  sprintf (SymValue, "0x%08X", FDev->Size);\r
+  SymbolAdd ("FLASH_SIZE", SymValue, 0);\r
+  //\r
+  // Add flash block size and offset defines\r
+  //\r
+  // Offset = 0;\r
+  // for (FBlock = FDev->PBlocks; FBlock != NULL; FBlock = FBlock->Next) {\r
+  //  sprintf (SymName, "FLASH_BLOCK_%s_BASE", FBlock->Name);\r
+  //  sprintf (SymValue, "0x%08X", FDev->BaseAddress + Offset);\r
+  //  SymbolAdd (SymName, SymValue, 0);\r
+  //  sprintf (SymName, "FLASH_BLOCK_%s_SIZE", FBlock->Name);\r
+  //  sprintf (SymValue, "0x%08X", FBlock->Size);\r
+  //  SymbolAdd (SymName, SymValue, 0);\r
+  //  sprintf (SymName, "FLASH_BLOCK_%s_OFFSET", FBlock->Name);\r
+  //  sprintf (SymValue, "0x%08X", Offset);\r
+  //  SymbolAdd (SymName, SymValue, 0);\r
+  //  Offset += FBlock->Size;\r
+  // }\r
+  //\r
+  // Add flash region block base, size, and offset defines\r
+  //\r
+  Offset = 0;\r
+  for (FBlock = FDev->Regions; FBlock != NULL; FBlock = FBlock->Next) {\r
+    sprintf (SymName, "FLASH_REGION_%s_BASE", FBlock->Name);\r
+    sprintf (SymValue, "0x%08X", FDev->BaseAddress + Offset);\r
+    SymbolAdd (SymName, SymValue, 0);\r
+    sprintf (SymName, "FLASH_REGION_%s_SIZE", FBlock->Name);\r
+    sprintf (SymValue, "0x%08X", FBlock->Size);\r
+    SymbolAdd (SymName, SymValue, 0);\r
+    sprintf (SymName, "FLASH_REGION_%s_OFFSET", FBlock->Name);\r
+    sprintf (SymValue, "0x%08X", Offset);\r
+    SymbolAdd (SymName, SymValue, 0);\r
+    //\r
+    // Add subregion symbols\r
+    //\r
+    if (FBlock->Subregions != NULL) {\r
+      SubregionOffset = 0;\r
+      for (Subregion = FBlock->Subregions; Subregion != NULL; Subregion = Subregion->Next) {\r
+        sprintf (SymName, "FLASH_REGION_%s_SUBREGION_%s_BASE", FBlock->Name, Subregion->Name);\r
+        sprintf (SymValue, "0x%08X", FDev->BaseAddress + Offset + SubregionOffset);\r
+        SymbolAdd (SymName, SymValue, 0);\r
+        sprintf (SymName, "FLASH_REGION_%s_SUBREGION_%s_SIZE", FBlock->Name, Subregion->Name);\r
+        sprintf (SymValue, "0x%08X", Subregion->Size);\r
+        SymbolAdd (SymName, SymValue, 0);\r
+        sprintf (SymName, "FLASH_REGION_%s_SUBREGION_%s_OFFSET", FBlock->Name, Subregion->Name);\r
+        sprintf (SymValue, "0x%08X", Offset + SubregionOffset);\r
+        SymbolAdd (SymName, SymValue, 0);\r
+        SubregionOffset += Subregion->Size;\r
+      }\r
+    }\r
+\r
+    Offset += FBlock->Size;\r
+  }\r
+\r
+  return STATUS_SUCCESS;\r
+}\r
+\r
+STATUS\r
+FDFCreateImage (\r
+  char      *FlashDeviceName,\r
+  char      *ImageName,\r
+  char      *FileName\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Create a flash image using the given device and image names.\r
+\r
+Arguments:\r
+  FlashDeviceName - name of flash device (from the flash definition file)\r
+                    to use\r
+  ImageName       - name of image (from the flash definition file) to create\r
+  FileName        - name of output file to create\r
+\r
+Returns:\r
+  STATUS_SUCCESS    - no errors or warnings\r
+  STATUS_WARNING    - warnings, but no errors, were encountered\r
+  STATUS_ERROR      - errors were encountered\r
+\r
+--*/\r
+{\r
+  STATUS                      Status;\r
+  FILE                        *OutFptr;\r
+  FLASH_BLOCK_DESCRIPTION     *RegionDef;\r
+  FLASH_DEVICE_DESCRIPTION    *FDev;\r
+  IMAGE_DEFINITION            *ImageDef;\r
+  unsigned int                Offset;\r
+  char                        *Buffer;\r
+  FILE                        *InFptr;\r
+  long                        FileSize;\r
+  IMAGE_DEFINITION_ENTRY      *IDefEntry;\r
+  FLASH_SUBREGION_DESCRIPTION *SubregionDef;\r
+  //\r
+  // Find the flash definition we're supposed to use\r
+  //\r
+  InFptr  = NULL;\r
+  Status  = STATUS_ERROR;\r
+  for (FDev = mFlashDevices; FDev != NULL; FDev = FDev->Next) {\r
+    if (strcmp (FDev->Name, FlashDeviceName) == 0) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (FDev == NULL) {\r
+    Error (NULL, 0, 0, FlashDeviceName, "flash device not found in flash definitions");\r
+    return STATUS_ERROR;\r
+  }\r
+  //\r
+  // Find the image name we're supposed to create\r
+  //\r
+  for (ImageDef = mImageDefinitions; ImageDef != NULL; ImageDef = ImageDef->Next) {\r
+    if (strcmp (ImageDef->Name, ImageName) == 0) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (ImageDef == NULL) {\r
+    Error (NULL, 0, 0, ImageName, "image definition not found in image definitions");\r
+    return STATUS_ERROR;\r
+  }\r
+  //\r
+  // Open the output file\r
+  //\r
+  if ((OutFptr = fopen (FileName, "wb")) == NULL) {\r
+    Error (NULL, 0, 0, FileName, "failed to open output file for writing");\r
+    return STATUS_ERROR;\r
+  }\r
+  //\r
+  // Allocate a buffer to copy the input data to\r
+  //\r
+  Buffer = (char *) _malloc (FDev->Size);\r
+  if (Buffer == NULL) {\r
+    Error (NULL, 0, 0, (INT8 *) "failed to allocate memory", NULL);\r
+    goto Done;\r
+  }\r
+  //\r
+  // Set contents of buffer to the erased value\r
+  //\r
+  if (FDev->ErasePolarity) {\r
+    memset (Buffer, 0xFF, FDev->Size);\r
+  } else {\r
+    memset (Buffer, 0, FDev->Size);\r
+  }\r
+  //\r
+  // Set all region and subregion size-left fields to the size of the region/subregion\r
+  //\r
+  for (RegionDef = FDev->Regions; RegionDef != NULL; RegionDef = RegionDef->Next) {\r
+    RegionDef->SizeLeft = RegionDef->Size;\r
+    for (SubregionDef = RegionDef->Subregions; SubregionDef != NULL; SubregionDef = SubregionDef->Next) {\r
+      SubregionDef->SizeLeft = SubregionDef->Size;\r
+    }\r
+  }\r
+  //\r
+  // Now go through the image list, read files into the buffer.\r
+  //\r
+  for (IDefEntry = ImageDef->Entries; IDefEntry != NULL; IDefEntry = IDefEntry->Next) {\r
+    //\r
+    // If it's a file name, open the file, get the size, find the corresponding\r
+    // flash region it's in, and copy the data.\r
+    //\r
+    if (IDefEntry->IsRawData == 0) {\r
+      if ((InFptr = fopen (IDefEntry->Name, "rb")) == NULL) {\r
+        Error (NULL, 0, 0, IDefEntry->Name, "failed to open input file for reading");\r
+        goto Done;\r
+      }\r
+\r
+      fseek (InFptr, 0, SEEK_END);\r
+      FileSize = ftell (InFptr);\r
+      fseek (InFptr, 0, SEEK_SET);\r
+    } else {\r
+      FileSize = IDefEntry->RawDataSize;\r
+    }\r
+    //\r
+    // Find the region/subregion it's in, see if we have space left\r
+    //\r
+    Offset = 0;\r
+    for (RegionDef = FDev->Regions; RegionDef != NULL; RegionDef = RegionDef->Next) {\r
+      if (strcmp (RegionDef->Name, IDefEntry->RegionName) == 0) {\r
+        break;\r
+      }\r
+\r
+      Offset += RegionDef->Size;\r
+    }\r
+\r
+    if (RegionDef == NULL) {\r
+      Error (NULL, 0, 0, IDefEntry->RegionName, "Region name not found in FlashDevice %s definition", FDev->Name);\r
+      goto Done;\r
+    }\r
+\r
+    //\r
+    // Check for subregion\r
+    //\r
+    if (IDefEntry->SubregionName[0] != 0) {\r
+      for (SubregionDef = RegionDef->Subregions; SubregionDef != NULL; SubregionDef = SubregionDef->Next) {\r
+        if (strcmp (SubregionDef->Name, IDefEntry->SubregionName) == 0) {\r
+          break;\r
+        }\r
+\r
+        Offset += SubregionDef->Size;\r
+      }\r
+\r
+      if (SubregionDef == NULL) {\r
+        Error (\r
+          NULL,\r
+          0,\r
+          0,\r
+          IDefEntry->SubregionName,\r
+          "Subregion name not found in FlashDevice %s.%s Region definition",\r
+          FDev->Name,\r
+          RegionDef->Name\r
+          );\r
+        goto Done;\r
+      }\r
+      //\r
+      // Enough space in the subregion?\r
+      //\r
+      if (SubregionDef->SizeLeft < (unsigned int) FileSize) {\r
+        Error (\r
+          NULL,\r
+          0,\r
+          0,\r
+          IDefEntry->Name,\r
+          "insufficient space in Subregion (at least 0x%X additional bytes required)",\r
+          FileSize - SubregionDef->SizeLeft\r
+          );\r
+        goto Done;\r
+      }\r
+\r
+      //\r
+      // Read the file into the buffer if it's a file. Otherwise copy the raw data\r
+      //\r
+      if (IDefEntry->IsRawData == 0) {\r
+        if (fread (Buffer + Offset + (SubregionDef->Size - SubregionDef->SizeLeft), FileSize, 1, InFptr) != 1) {\r
+          Error (NULL, 0, 0, IDefEntry->Name, "failed to read file contents");\r
+          goto Done;\r
+        }\r
+\r
+        fclose (InFptr);\r
+        InFptr = NULL;\r
+      } else {\r
+        memcpy (\r
+          Buffer + Offset + (SubregionDef->Size - SubregionDef->SizeLeft),\r
+          IDefEntry->RawData,\r
+          IDefEntry->RawDataSize\r
+          );\r
+      }\r
+\r
+      SubregionDef->SizeLeft -= FileSize;\r
+      //\r
+      // Align based on the Region alignment requirements.\r
+      //\r
+      if (RegionDef->Alignment != 0) {\r
+        while (((unsigned int) (SubregionDef->Size - SubregionDef->SizeLeft) &~RegionDef->Alignment) != 0) {\r
+          if (SubregionDef->SizeLeft == 0) {\r
+            break;\r
+          }\r
+\r
+          SubregionDef->SizeLeft--;\r
+        }\r
+      }\r
+    } else {\r
+      //\r
+      // Placing data in a region. Check for enough space in the region left.\r
+      //\r
+      if (RegionDef->SizeLeft < (unsigned int) FileSize) {\r
+        Error (\r
+          NULL,\r
+          0,\r
+          0,\r
+          IDefEntry->Name,\r
+          "insufficient space in Region (at least 0x%X additional bytes required)",\r
+          FileSize - RegionDef->SizeLeft\r
+          );\r
+        goto Done;\r
+      }\r
+\r
+      //\r
+      // Read the file into the buffer if it's a file. Otherwise copy the raw data\r
+      //\r
+      if (IDefEntry->IsRawData == 0) {\r
+        if (fread (Buffer + Offset + (RegionDef->Size - RegionDef->SizeLeft), FileSize, 1, InFptr) != 1) {\r
+          Error (NULL, 0, 0, IDefEntry->Name, "failed to read file contents");\r
+          goto Done;\r
+        }\r
+\r
+        fclose (InFptr);\r
+        InFptr = NULL;\r
+      } else {\r
+        memcpy (Buffer + Offset + (RegionDef->Size - RegionDef->SizeLeft), IDefEntry->RawData, IDefEntry->RawDataSize);\r
+      }\r
+\r
+      RegionDef->SizeLeft -= FileSize;\r
+      //\r
+      // Align\r
+      //\r
+      if (RegionDef->Alignment != 0) {\r
+        while (((unsigned int) (RegionDef->Size - RegionDef->SizeLeft) &~RegionDef->Alignment) != 0) {\r
+          if (RegionDef->SizeLeft == 0) {\r
+            break;\r
+          }\r
+\r
+          RegionDef->SizeLeft--;\r
+        }\r
+      }\r
+    }\r
+  }\r
+\r
+  if (fwrite (Buffer, FDev->Size, 1, OutFptr) != 1) {\r
+    Error (NULL, 0, 0, "failed to write buffer contents to output file", NULL);\r
+    goto Done;\r
+  }\r
+\r
+  Status = STATUS_SUCCESS;\r
+Done:\r
+  if (InFptr != NULL) {\r
+    fclose (InFptr);\r
+  }\r
+\r
+  if (Buffer != NULL) {\r
+    _free (Buffer);\r
+  }\r
+\r
+  if (OutFptr != NULL) {\r
+    fclose (OutFptr);\r
+    if (Status == STATUS_ERROR) {\r
+      remove (FileName);\r
+    }\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+STATUS\r
+FDFCreateDscFile (\r
+  char      *FlashDeviceName,\r
+  char      *FileName\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Create a DSC-style output file with equates for flash management.\r
+\r
+Arguments:\r
+  FlashDeviceName - name of flash device (from the flash definition file)\r
+                    to use\r
+  FileName        - name of output file to create\r
+\r
+Returns:\r
+  STATUS_SUCCESS    - no errors or warnings\r
+  STATUS_WARNING    - warnings, but no errors, were encountered\r
+  STATUS_ERROR      - errors were encountered\r
+\r
+--*/\r
+{\r
+  FILE                        *OutFptr;\r
+  FLASH_BLOCK_DESCRIPTION     *FBlock;\r
+  FLASH_DEVICE_DESCRIPTION    *FDev;\r
+  unsigned int                Offset;\r
+  FLASH_SUBREGION_DESCRIPTION *Subregion;\r
+  unsigned int                SubregionOffset;\r
+  //\r
+  // Find the definition we're supposed to use\r
+  //\r
+  for (FDev = mFlashDevices; FDev != NULL; FDev = FDev->Next) {\r
+    if (strcmp (FDev->Name, FlashDeviceName) == 0) {\r
+      break;\r
+    }\r
+  }\r
+\r
+  if (FDev == NULL) {\r
+    Error (NULL, 0, 0, FlashDeviceName, "flash device not found in flash definitions");\r
+    return STATUS_ERROR;\r
+  }\r
+\r
+  if ((OutFptr = fopen (FileName, "w")) == NULL) {\r
+    Error (NULL, 0, 0, FileName, "failed to open output file for writing");\r
+    return STATUS_ERROR;\r
+  }\r
+  //\r
+  // Write the flash base address and size\r
+  //\r
+  fprintf (OutFptr, "\n");\r
+  fprintf (OutFptr, "FLASH_BASE                                      = 0x%08X\n", FDev->BaseAddress);\r
+  fprintf (OutFptr, "FLASH_SIZE                                      = 0x%08X\n\n", FDev->Size);\r
+  //\r
+  // Write flash block size and offset defines\r
+  //\r
+  Offset = 0;\r
+  for (FBlock = FDev->Regions; FBlock != NULL; FBlock = FBlock->Next) {\r
+    fprintf (\r
+      OutFptr,\r
+      "FLASH_REGION_%s_BASE          %*c= 0x%08X\n",\r
+      FBlock->Name,\r
+      COLUMN2_START - 40 - strlen (FBlock->Name),\r
+      ' ',\r
+      Offset + FDev->BaseAddress\r
+      );\r
+    fprintf (\r
+      OutFptr,\r
+      "FLASH_REGION_%s_SIZE          %*c= 0x%08X\n",\r
+      FBlock->Name,\r
+      COLUMN2_START - 40 - strlen (FBlock->Name),\r
+      ' ',\r
+      FBlock->Size\r
+      );\r
+    fprintf (\r
+      OutFptr,\r
+      "FLASH_REGION_%s_SIZE_BLOCKS   %*c= 0x%x\n",\r
+      FBlock->Name,\r
+      COLUMN2_START - 40 - strlen (FBlock->Name),\r
+      ' ',\r
+      (FBlock->Size)/(FDev->PBlocks->Size)\r
+      );      \r
+    //\r
+    // Create defines for any subregions\r
+    //\r
+    SubregionOffset = 0;\r
+    for (Subregion = FBlock->Subregions; Subregion != NULL; Subregion = Subregion->Next) {\r
+      fprintf (\r
+        OutFptr,\r
+        "FLASH_REGION_%s_SUBREGION_%s_BASE     %*c= 0x%08X\n",\r
+        FBlock->Name,\r
+        Subregion->Name,\r
+        COLUMN3_START - 48 - strlen (FBlock->Name) - strlen (Subregion->Name),\r
+        ' ',\r
+        FDev->BaseAddress + Offset + SubregionOffset\r
+        );\r
+      fprintf (\r
+        OutFptr,\r
+        "FLASH_REGION_%s_SUBREGION_%s_SIZE     %*c= 0x%08X\n",\r
+        FBlock->Name,\r
+        Subregion->Name,\r
+        COLUMN3_START - 48 - strlen (FBlock->Name) - strlen (Subregion->Name),\r
+        ' ',\r
+        Subregion->Size\r
+        );\r
+      fprintf (\r
+        OutFptr,\r
+        "FLASH_REGION_%s_SUBREGION_%s_OFFSET   %*c= 0x%08X\n",\r
+        FBlock->Name,\r
+        Subregion->Name,\r
+        COLUMN3_START - 48 - strlen (FBlock->Name) - strlen (Subregion->Name),\r
+        ' ',\r
+        Offset + SubregionOffset\r
+        );\r
+\r
+      SubregionOffset += Subregion->Size;\r
+    }\r
+\r
+    Offset += FBlock->Size;\r
+  }\r
+  //\r
+  // Close file\r
+  //\r
+  fprintf (OutFptr, "\n");\r
+  fclose (OutFptr);\r
+  return STATUS_SUCCESS;\r
+}\r
+\r
+\r
+/*++\r
+\r
+Routine Description:\r
+  The following buffer management routines are used to encapsulate functionality\r
+  for managing a growable data buffer.\r
+\r
+Arguments:\r
+  BUFFER_DATA     - structure that is used to maintain a data buffer\r
+\r
+Returns:\r
+  NA\r
+\r
+--*/\r
+static\r
+BUFFER_DATA *\r
+CreateBufferData (\r
+  VOID\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Create a growable data buffer with default buffer length.\r
+\r
+Arguments:\r
+\r
+  None\r
+\r
+Returns:\r
+\r
+  NULL          - error occured during data buffer creation\r
+  Not NULL      - the pointer to the newly created data buffer\r
+\r
+--*/\r
+{\r
+  BUFFER_DATA *BD;\r
+  BD = (BUFFER_DATA *) _malloc (sizeof (BUFFER_DATA));\r
+  if (BD == NULL) {\r
+    Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
+    return NULL;\r
+  }\r
+\r
+  memset (BD, 0, sizeof (BUFFER_DATA));\r
+  BD->BufferStart = (char *) _malloc (BUFFER_SIZE);\r
+  if (BD->BufferStart == NULL) {\r
+    _free (BD);\r
+    Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
+    return NULL;\r
+  }\r
+\r
+  BD->BufferEnd = BD->BufferStart + BUFFER_SIZE;\r
+  BD->BufferPos = BD->BufferStart;\r
+  return BD;\r
+}\r
+\r
+static\r
+BOOLEAN\r
+AddBufferDataByte (\r
+  BUFFER_DATA *Buffer,\r
+  char        Data\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Add a single byte to a growable data buffer, growing the buffer if required.\r
+\r
+Arguments:\r
+\r
+  Buffer  - pointer to the growable data buffer to add a single byte to\r
+  Data    - value of the single byte data to be added\r
+\r
+Returns:\r
+\r
+  TRUE    - the single byte data was successfully added\r
+  FALSE   - error occurred, the single byte data was not added\r
+\r
+--*/\r
+{\r
+  int   Size;\r
+  char  *NewBuffer;\r
+  //\r
+  // See if we have to grow the buffer\r
+  //\r
+  if (Buffer->BufferPos >= Buffer->BufferEnd) {\r
+    Size      = (int) Buffer->BufferEnd - (int) Buffer->BufferStart;\r
+    NewBuffer = (char *) _malloc (Size + BUFFER_SIZE);\r
+    if (NewBuffer == NULL) {\r
+      Error (__FILE__, __LINE__, 0, "memory allocation failure", NULL);\r
+      return FALSE;\r
+    }\r
+\r
+    memcpy (NewBuffer, Buffer->BufferStart, Size);\r
+    _free (Buffer->BufferStart);\r
+    Buffer->BufferStart = NewBuffer;\r
+    Buffer->BufferPos   = Buffer->BufferStart + Size;\r
+    Buffer->BufferEnd   = Buffer->BufferStart + Size + BUFFER_SIZE;\r
+  }\r
+\r
+  *Buffer->BufferPos = Data;\r
+  Buffer->BufferPos++;\r
+  return TRUE;\r
+}\r
+\r
+static\r
+void\r
+FreeBufferData (\r
+  BUFFER_DATA *Buffer,\r
+  BOOLEAN     FreeData\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Free memory used to manage a growable data buffer.\r
+\r
+Arguments:\r
+\r
+  Buffer    - pointer to the growable data buffer to be destructed\r
+  FreeData  - TRUE, free memory containing the buffered data\r
+              FALSE, do not free the buffered data memory\r
+\r
+Returns:\r
+\r
+  None\r
+\r
+--*/\r
+{\r
+  if (Buffer != NULL) {\r
+    if (FreeData && (Buffer->BufferStart != NULL)) {\r
+      _free (Buffer->BufferStart);\r
+    }\r
+\r
+    _free (Buffer);\r
+  }\r
+}\r
+\r
+static\r
+char *\r
+GetBufferData (\r
+  BUFFER_DATA *Buffer,\r
+  int         *BufferSize\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+  Return a pointer and size of the data in a growable data buffer.\r
+\r
+Arguments:\r
+\r
+  Buffer      - pointer to the growable data buffer\r
+  BufferSize  - size of the data in the growable data buffer\r
+\r
+Returns:\r
+\r
+  pointer of the data in the growable data buffer\r
+\r
+--*/\r
+{\r
+  *BufferSize = (int) Buffer->BufferPos - (int) Buffer->BufferStart;\r
+  return Buffer->BufferStart;\r
+}\r
+\r
+STATUS\r
+FDDiscover (\r
+  char          *FDFileName,\r
+  unsigned int  BaseAddr\r
+  )\r
+/*++\r
+\r
+Routine Description:\r
+  Walk a binary image and see if you find anything that looks like a\r
+  firmware volume.\r
+\r
+Arguments:\r
+  FDFileName        - name of input FD image to parse\r
+  BaseAddr          - base address of input FD image\r
+\r
+Returns:\r
+  STATUS_SUCCESS    - no errors or warnings\r
+  STATUS_WARNING    - warnings, but no errors, were encountered\r
+  STATUS_ERROR      - errors were encountered\r
+\r
+NOTE:\r
+  This routine is used for debug purposes only.\r
+\r
+--*/\r
+{\r
+  FILE                        *InFptr;\r
+  long                        FileSize;\r
+  long                        Offset;\r
+  EFI_FIRMWARE_VOLUME_HEADER  FVHeader;\r
+  EFI_GUID\r
+    FileSystemGuid = { 0x7A9354D9, 0x0468, 0x444a, 0x81, 0xCE, 0x0B, 0xF6, 0x17, 0xD8, 0x90, 0xDF };\r
+\r
+  if ((InFptr = fopen (FDFileName, "rb")) == NULL) {\r
+    Error (NULL, 0, 0, FDFileName, "failed to open file for reading");\r
+    return STATUS_ERROR;\r
+  }\r
+\r
+  fseek (InFptr, 0, SEEK_END);\r
+  FileSize = ftell (InFptr);\r
+  fseek (InFptr, 0, SEEK_SET);\r
+  Offset = 0;\r
+  while (Offset < FileSize) {\r
+    fseek (InFptr, Offset, SEEK_SET);\r
+    //\r
+    // Read the contents of the file, see if it's an FV header\r
+    //\r
+    if (fread (&FVHeader, sizeof (EFI_FIRMWARE_VOLUME_HEADER), 1, InFptr) == 1) {\r
+      //\r
+      // Check version and GUID\r
+      //\r
+      if ((FVHeader.Revision == EFI_FVH_REVISION) && (FVHeader.Signature == EFI_FVH_SIGNATURE)) {\r
+        fprintf (stdout, "FV header at 0x%08X FVSize=0x%08X ", Offset + BaseAddr, (UINT32) FVHeader.FvLength);\r
+        if (memcmp (&FVHeader.FileSystemGuid, &FileSystemGuid, sizeof (EFI_GUID)) == 0) {\r
+          fprintf (stdout, "standard FFS file system\n");\r
+        } else {\r
+          fprintf (stdout, "non-standard FFS file system\n");\r
+        }\r
+      }\r
+    }\r
+\r
+    Offset += 16 * 1024;\r
+  }\r
+\r
+  fclose (InFptr);\r
+  return STATUS_SUCCESS;\r
+}\r