]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/C/EfiRom/EfiRom.c
BaseTools: Various typo
[mirror_edk2.git] / BaseTools / Source / C / EfiRom / EfiRom.c
index 9f71b19323e9eea951bf984691e5cc73aa97c2bd..0c52eb74845947de772bbfd2ebf41e5073d81ab3 100644 (file)
@@ -1,23 +1,15 @@
 /** @file\r
+Utility program to create an EFI option ROM image from binary and EFI PE32 files.\r
 \r
-Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>\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
+Copyright (c) 1999 - 2018, Intel Corporation. All rights reserved.<BR>\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
-  EfiRom.c\r
-  \r
-Abstract:\r
-\r
-  Utility program to create an EFI option ROM image from binary and \r
-  EFI PE32 files.\r
-\r
 **/\r
 \r
 #include "EfiUtilityMsgs.h"\r
@@ -34,8 +26,8 @@ main (
 /*++\r
 \r
 Routine Description:\r
-  \r
-  Given an EFI image filename, create a ROM-able image by creating an option \r
+\r
+  Given an EFI image filename, create a ROM-able image by creating an option\r
   ROM header and PCI data structure, filling them in, and then writing the\r
   option ROM header + PCI data structure + EFI image out to the output file.\r
 \r
@@ -79,11 +71,11 @@ Returns:
   } else if (mOptions.Debug) {\r
     SetPrintLevel(DebugLevel);\r
   }\r
-  \r
+\r
   if (mOptions.Verbose) {\r
     VerboseMsg("%s tool start.\n", UTILITY_NAME);\r
   }\r
-  \r
+\r
   //\r
   // If dumping an image, then do that and quit\r
   //\r
@@ -103,24 +95,34 @@ Returns:
   // the command line, or the first input filename with a different extension.\r
   //\r
   if (!mOptions.OutFileName[0]) {\r
-    strcpy (mOptions.OutFileName, mOptions.FileList->FileName);\r
-    //\r
-    // Find the last . on the line and replace the filename extension with\r
-    // the default\r
-    //\r
-    for (Ext = mOptions.OutFileName + strlen (mOptions.OutFileName) - 1;\r
-         (Ext >= mOptions.OutFileName) && (*Ext != '.') && (*Ext != '\\');\r
-         Ext--\r
-        )\r
-      ;\r
-    //\r
-    // If dot here, then insert extension here, otherwise append\r
-    //\r
-    if (*Ext != '.') {\r
-      Ext = mOptions.OutFileName + strlen (mOptions.OutFileName);\r
-    }\r
+    if (mOptions.FileList != NULL) {\r
+      if (strlen (mOptions.FileList->FileName) >= MAX_PATH) {\r
+        Status = STATUS_ERROR;\r
+        Error (NULL, 0, 2000, "Invalid parameter", "Input file name is too long - %s.", mOptions.FileList->FileName);\r
+        goto BailOut;\r
+      }\r
+      strncpy (mOptions.OutFileName, mOptions.FileList->FileName, MAX_PATH - 1);\r
+      mOptions.OutFileName[MAX_PATH - 1] = 0;\r
+      //\r
+      // Find the last . on the line and replace the filename extension with\r
+      // the default\r
+      //\r
+      Ext = mOptions.OutFileName + strlen (mOptions.OutFileName) - 1;\r
+      while (Ext >= mOptions.OutFileName) {\r
+        if ((*Ext == '.') || (*Ext == '\\')) {\r
+          break;\r
+        }\r
+        Ext--;\r
+      }\r
+      //\r
+      // If dot here, then insert extension here, otherwise append\r
+      //\r
+      if (*Ext != '.') {\r
+        Ext = mOptions.OutFileName + strlen (mOptions.OutFileName);\r
+      }\r
 \r
-    strcpy (Ext, DEFAULT_OUTPUT_EXTENSION);\r
+      strcpy (Ext, DEFAULT_OUTPUT_EXTENSION);\r
+    }\r
   }\r
   //\r
   // Make sure we don't have the same filename for input and output files\r
@@ -128,14 +130,14 @@ Returns:
   for (FList = mOptions.FileList; FList != NULL; FList = FList->Next) {\r
     if (stricmp (mOptions.OutFileName, FList->FileName) == 0) {\r
       Status = STATUS_ERROR;\r
-      Error (NULL, 0, 1002, "Invalid input paramter", "Input and output file names must be different - %s = %s.", FList->FileName, mOptions.OutFileName);\r
+      Error (NULL, 0, 1002, "Invalid input parameter", "Input and output file names must be different - %s = %s.", FList->FileName, mOptions.OutFileName);\r
       goto BailOut;\r
     }\r
   }\r
   //\r
   // Now open our output file\r
   //\r
-  if ((FptrOut = fopen (mOptions.OutFileName, "wb")) == NULL) {\r
+  if ((FptrOut = fopen (LongFilePath (mOptions.OutFileName), "wb")) == NULL) {\r
     Error (NULL, 0, 0001, "Error opening file", "Error opening file %s", mOptions.OutFileName);\r
     goto BailOut;\r
   }\r
@@ -150,7 +152,7 @@ Returns:
         VerboseMsg("Processing EFI file    %s\n", FList->FileName);\r
       }\r
 \r
-      Status = ProcessEfiFile (FptrOut, FList, mOptions.VendId, mOptions.DevId, &Size);\r
+      Status = ProcessEfiFile (FptrOut, FList, mOptions.VendId, mOptions.DevIdList[0], &Size);\r
     } else if ((FList->FileFlags & FILE_FLAG_BINARY) !=0 ) {\r
       if (mOptions.Verbose) {\r
         VerboseMsg("Processing binary file %s\n", FList->FileName);\r
@@ -176,15 +178,12 @@ Returns:
   // Check total size\r
   //\r
   if (TotalSize > MAX_OPTION_ROM_SIZE) {\r
-    Error (NULL, 0, 2000, "Invalid paramter", "Option ROM image size exceeds limit of 0x%X bytes.", MAX_OPTION_ROM_SIZE);\r
+    Error (NULL, 0, 2000, "Invalid parameter", "Option ROM image size exceeds limit of 0x%X bytes.", MAX_OPTION_ROM_SIZE);\r
     Status = STATUS_ERROR;\r
   }\r
 \r
 BailOut:\r
   if (Status == STATUS_SUCCESS) {\r
-    if (FptrOut != NULL) {\r
-      fclose (FptrOut);\r
-    }\r
     //\r
     // Clean up our file list\r
     //\r
@@ -193,13 +192,23 @@ BailOut:
       free (mOptions.FileList);\r
       mOptions.FileList = FList;\r
     }\r
+\r
+    //\r
+    // Clean up device ID list\r
+    //\r
+    if (mOptions.DevIdList != NULL) {\r
+      free (mOptions.DevIdList);\r
+    }\r
+  }\r
+  if (FptrOut != NULL) {\r
+    fclose (FptrOut);\r
   }\r
 \r
   if (mOptions.Verbose) {\r
     VerboseMsg("%s tool done with return code is 0x%x.\n", UTILITY_NAME, GetUtilityStatus ());\r
   }\r
 \r
-  return GetUtilityStatus (); \r
+  return GetUtilityStatus ();\r
 }\r
 \r
 static\r
@@ -212,7 +221,7 @@ ProcessBinFile (
 /*++\r
 \r
 Routine Description:\r
-  \r
+\r
   Process a binary input file.\r
 \r
 Arguments:\r
@@ -237,7 +246,8 @@ Returns:
   PCI_3_0_DATA_STRUCTURE    *PciDs30;\r
   UINT32                    Index;\r
   UINT8                     ByteCheckSum;\r
\r
+  UINT16                    CodeType;\r
+\r
   PciDs23 = NULL;\r
   PciDs30 = NULL;\r
   Status = STATUS_SUCCESS;\r
@@ -245,8 +255,8 @@ Returns:
   //\r
   // Try to open the input file\r
   //\r
-  if ((InFptr = fopen (InFile->FileName, "rb")) == NULL) {\r
-    Error (NULL, 0, 0001, "Error opening file", InFile->FileName);\r
+  if ((InFptr = fopen (LongFilePath (InFile->FileName), "rb")) == NULL) {\r
+    Error (NULL, 0, 0001, "Error opening file", "%s", InFile->FileName);\r
     return STATUS_ERROR;\r
   }\r
   //\r
@@ -337,9 +347,11 @@ Returns:
   //\r
   if (mOptions.Pci23 == 1) {\r
     PciDs23->ImageLength = (UINT16) (TotalSize / 512);\r
+    CodeType = PciDs23->CodeType;\r
   } else {\r
     PciDs30->ImageLength = (UINT16) (TotalSize / 512);\r
-       }\r
+    CodeType = PciDs30->CodeType;\r
+  }\r
 \r
   //\r
   // If this is the last image, then set the LAST bit unless requested not\r
@@ -350,23 +362,25 @@ Returns:
       PciDs23->Indicator = INDICATOR_LAST;\r
     } else {\r
       PciDs30->Indicator = INDICATOR_LAST;\r
-               }\r
+    }\r
   } else {\r
     if (mOptions.Pci23 == 1) {\r
       PciDs23->Indicator = 0;\r
     } else {\r
       PciDs30->Indicator = 0;\r
-               }\r
+    }\r
   }\r
 \r
-  ByteCheckSum = 0;\r
-  for (Index = 0; Index < FileSize - 1; Index++) {\r
-    ByteCheckSum = (UINT8) (ByteCheckSum + Buffer[Index]);\r
-  }\r
+  if (CodeType != PCI_CODE_TYPE_EFI_IMAGE) {\r
+    ByteCheckSum = 0;\r
+    for (Index = 0; Index < FileSize - 1; Index++) {\r
+      ByteCheckSum = (UINT8) (ByteCheckSum + Buffer[Index]);\r
+    }\r
 \r
-  Buffer[FileSize - 1] = (UINT8) ((~ByteCheckSum) + 1);\r
-  if (mOptions.Verbose) {\r
-    VerboseMsg("  Checksum = %02x\n\n", Buffer[FileSize - 1]);\r
+    Buffer[FileSize - 1] = (UINT8) ((~ByteCheckSum) + 1);\r
+    if (mOptions.Verbose) {\r
+      VerboseMsg("  Checksum = %02x\n\n", Buffer[FileSize - 1]);\r
+    }\r
   }\r
 \r
   //\r
@@ -417,7 +431,7 @@ ProcessEfiFile (
 /*++\r
 \r
 Routine Description:\r
-  \r
+\r
   Process a PE32 EFI file.\r
 \r
 Arguments:\r
@@ -449,11 +463,14 @@ Returns:
   UINT16                        MachineType;\r
   UINT16                        SubSystem;\r
   UINT32                        HeaderPadBytes;\r
+  UINT32                        PadBytesBeforeImage;\r
+  UINT32                        PadBytesAfterImage;\r
+  UINT32                        DevIdListSize;\r
 \r
   //\r
   // Try to open the input file\r
   //\r
-  if ((InFptr = fopen (InFile->FileName, "rb")) == NULL) {\r
+  if ((InFptr = fopen (LongFilePath (InFile->FileName), "rb")) == NULL) {\r
     Error (NULL, 0, 0001, "Open file error", "Error opening file: %s", InFile->FileName);\r
     return STATUS_ERROR;\r
   }\r
@@ -485,14 +502,23 @@ Returns:
   } else {\r
     HeaderPadBytes = 0;\r
   }\r
-  \r
+\r
   //\r
   // For Pci3.0 to use the different data structure.\r
   //\r
   if (mOptions.Pci23 == 1) {\r
     HeaderSize = sizeof (PCI_DATA_STRUCTURE) + HeaderPadBytes + sizeof (EFI_PCI_EXPANSION_ROM_HEADER);\r
   } else {\r
-    HeaderSize = sizeof (PCI_3_0_DATA_STRUCTURE) + HeaderPadBytes + sizeof (EFI_PCI_EXPANSION_ROM_HEADER);\r
+    if (mOptions.DevIdCount > 1) {\r
+      //\r
+      // Write device ID list when more than one device ID is specified.\r
+      // Leave space for list plus terminator.\r
+      //\r
+      DevIdListSize = (mOptions.DevIdCount + 1) * sizeof (UINT16);\r
+    } else {\r
+      DevIdListSize = 0;\r
+    }\r
+    HeaderSize = sizeof (PCI_3_0_DATA_STRUCTURE) + HeaderPadBytes + DevIdListSize + sizeof (EFI_PCI_EXPANSION_ROM_HEADER);\r
   }\r
 \r
   if (mOptions.Verbose) {\r
@@ -559,10 +585,22 @@ Returns:
     TotalSize = (TotalSize + 0x200) &~0x1ff;\r
   }\r
   //\r
+  // Workaround:\r
+  //   If compressed, put the pad bytes after the image,\r
+  //   else put the pad bytes before the image.\r
+  //\r
+  if ((InFile->FileFlags & FILE_FLAG_COMPRESS) != 0) {\r
+    PadBytesBeforeImage = 0;\r
+    PadBytesAfterImage = TotalSize - (FileSize + HeaderSize);\r
+  } else {\r
+    PadBytesBeforeImage = TotalSize - (FileSize + HeaderSize);\r
+    PadBytesAfterImage = 0;\r
+  }\r
+  //\r
   // Check size\r
   //\r
   if (TotalSize > MAX_OPTION_ROM_SIZE) {\r
-    Error (NULL, 0, 2000, "Invalid", "Option ROM image %s size exceeds limit of 0x%X bytes.", InFile->FileName, MAX_OPTION_ROM_SIZE);  \r
+    Error (NULL, 0, 2000, "Invalid", "Option ROM image %s size exceeds limit of 0x%X bytes.", InFile->FileName, MAX_OPTION_ROM_SIZE);\r
     Status = STATUS_ERROR;\r
     goto BailOut;\r
   }\r
@@ -581,7 +619,7 @@ Returns:
   RomHdr.EfiSignature         = EFI_PCI_EXPANSION_ROM_HEADER_EFISIGNATURE;\r
   RomHdr.EfiSubsystem         = SubSystem;\r
   RomHdr.EfiMachineType       = MachineType;\r
-  RomHdr.EfiImageHeaderOffset = (UINT16) HeaderSize;\r
+  RomHdr.EfiImageHeaderOffset = (UINT16) (HeaderSize + PadBytesBeforeImage);\r
   RomHdr.PcirOffset           = (UINT16) (sizeof (RomHdr) + HeaderPadBytes);\r
   //\r
   // Set image as compressed or not\r
@@ -617,7 +655,14 @@ Returns:
     PciDs30.Signature = PCI_DATA_STRUCTURE_SIGNATURE;\r
     PciDs30.VendorId  = VendId;\r
     PciDs30.DeviceId  = DevId;\r
-    PciDs30.DeviceListOffset = 0; // to be fixed\r
+    if (mOptions.DevIdCount > 1) {\r
+      //\r
+      // Place device list immediately after PCI structure\r
+      //\r
+      PciDs30.DeviceListOffset = (UINT16) sizeof (PCI_3_0_DATA_STRUCTURE);\r
+    } else {\r
+      PciDs30.DeviceListOffset = 0;\r
+    }\r
     PciDs30.Length    = (UINT16) sizeof (PCI_3_0_DATA_STRUCTURE);\r
     PciDs30.Revision  = 0x3;\r
     //\r
@@ -640,12 +685,12 @@ Returns:
   if ((InFile->Next == NULL) && (mOptions.NoLast == 0)) {\r
     if (mOptions.Pci23 == 1) {\r
       PciDs23.Indicator = INDICATOR_LAST;\r
-         } else {\r
+    } else {\r
     PciDs30.Indicator = INDICATOR_LAST;}\r
   } else {\r
     if (mOptions.Pci23 == 1) {\r
       PciDs23.Indicator = 0;\r
-       } else {\r
+  } else {\r
       PciDs30.Indicator = 0;\r
     }\r
   }\r
@@ -678,19 +723,46 @@ Returns:
       Error (NULL, 0, 0002, "Failed to write PCI ROM header to output file!", NULL);\r
       Status = STATUS_ERROR;\r
       goto BailOut;\r
-    } \r
+    }\r
   } else {\r
     if (fwrite (&PciDs30, sizeof (PciDs30), 1, OutFptr) != 1) {\r
       Error (NULL, 0, 0002, "Failed to write PCI ROM header to output file!", NULL);\r
       Status = STATUS_ERROR;\r
       goto BailOut;\r
-    } \r
+    }\r
   }\r
+\r
   //\r
-  // Keep track of how many bytes left to write\r
+  // Write the Device ID list to the output file\r
   //\r
-  TotalSize -= HeaderSize;\r
+  if (mOptions.DevIdCount > 1) {\r
+    if (fwrite (mOptions.DevIdList, sizeof (UINT16), mOptions.DevIdCount, OutFptr) != mOptions.DevIdCount) {\r
+      Error (NULL, 0, 0002, "Failed to write PCI device list to output file!", NULL);\r
+      Status = STATUS_ERROR;\r
+      goto BailOut;\r
+    }\r
+    //\r
+    // Write two-byte terminating 0 at the end of the device list\r
+    //\r
+    if (putc (0, OutFptr) == EOF || putc (0, OutFptr) == EOF) {\r
+      Error (NULL, 0, 0002, "Failed to write PCI device list to output file!", NULL);\r
+      Status = STATUS_ERROR;\r
+      goto BailOut;\r
+    }\r
+  }\r
 \r
+\r
+  //\r
+  // Pad head to make it a multiple of 512 bytes\r
+  //\r
+  while (PadBytesBeforeImage > 0) {\r
+    if (putc (~0, OutFptr) == EOF) {\r
+      Error (NULL, 0, 2000, "Failed to write trailing pad bytes output file!", NULL);\r
+      Status = STATUS_ERROR;\r
+      goto BailOut;\r
+    }\r
+    PadBytesBeforeImage--;\r
+  }\r
   //\r
   // Now dump the input file's contents to the output file\r
   //\r
@@ -700,18 +772,17 @@ Returns:
     goto BailOut;\r
   }\r
 \r
-  TotalSize -= FileSize;\r
   //\r
   // Pad the rest of the image to make it a multiple of 512 bytes\r
   //\r
-  while (TotalSize > 0) {\r
+  while (PadBytesAfterImage > 0) {\r
     if (putc (~0, OutFptr) == EOF) {\r
       Error (NULL, 0, 2000, "Failed to write trailing pad bytes output file!", NULL);\r
       Status = STATUS_ERROR;\r
       goto BailOut;\r
     }\r
 \r
-    TotalSize--;\r
+    PadBytesAfterImage--;\r
   }\r
 \r
 BailOut:\r
@@ -748,7 +819,7 @@ CheckPE32File (
 /*++\r
 \r
 Routine Description:\r
-  \r
+\r
   Given a file pointer to a supposed PE32 image file, verify that it is indeed a\r
   PE32 image file, and then return the machine type in the supplied pointer.\r
 \r
@@ -840,7 +911,7 @@ ParseCommandLine (
 /*++\r
 \r
 Routine Description:\r
-  \r
+\r
   Given the Argc/Argv program arguments, and a pointer to an options structure,\r
   parse the command-line options and check their validity.\r
 \r
@@ -864,9 +935,13 @@ Returns:
   UINT32    ClassCode;\r
   UINT32    CodeRevision;\r
   EFI_STATUS Status;\r
+  INTN       ReturnStatus;\r
   BOOLEAN    EfiRomFlag;\r
   UINT64     TempValue;\r
+  char       *OptionName;\r
+  UINT16     *DevIdList;\r
 \r
+  ReturnStatus = 0;\r
   FileFlags = 0;\r
   EfiRomFlag = FALSE;\r
 \r
@@ -880,6 +955,9 @@ Returns:
   //\r
   FileList                = PrevFileList = NULL;\r
 \r
+  Options->DevIdList      = NULL;\r
+  Options->DevIdCount     = 0;\r
+\r
   ClassCode               = 0;\r
   CodeRevision            = 0;\r
   //\r
@@ -895,12 +973,12 @@ Returns:
     Usage ();\r
     return STATUS_ERROR;\r
   }\r
-  \r
+\r
   if ((stricmp(Argv[0], "-h") == 0) || (stricmp(Argv[0], "--help") == 0)) {\r
     Usage();\r
     return STATUS_ERROR;\r
   }\r
-  \r
+\r
   if ((stricmp(Argv[0], "--version") == 0)) {\r
     Version();\r
     return STATUS_ERROR;\r
@@ -921,11 +999,13 @@ Returns:
         Status = AsciiStringToUint64(Argv[1], FALSE, &TempValue);\r
         if (EFI_ERROR (Status)) {\r
           Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);\r
-          return 1;\r
+          ReturnStatus = 1;\r
+          goto Done;\r
         }\r
         if (TempValue >= 0x10000) {\r
           Error (NULL, 0, 2000, "Invalid option value", "Vendor Id %s out of range!", Argv[1]);\r
-          return 1;\r
+          ReturnStatus = 1;\r
+          goto Done;\r
         }\r
         Options->VendId       = (UINT16) TempValue;\r
         Options->VendIdValid  = 1;\r
@@ -933,24 +1013,53 @@ Returns:
         Argv++;\r
         Argc--;\r
       } else if (stricmp (Argv[0], "-i") == 0) {\r
+\r
+        OptionName = Argv[0];\r
+\r
         //\r
-        // Device ID specified with -i\r
-        // Make sure there's another parameter\r
+        // Device IDs specified with -i\r
+        // Make sure there's at least one more parameter\r
         //\r
-        Status = AsciiStringToUint64(Argv[1], FALSE, &TempValue);\r
-        if (EFI_ERROR (Status)) {\r
-          Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);\r
-          return 1;\r
+        if (Argc < 1) {\r
+          Error (NULL, 0, 2000, "Invalid parameter", "Missing Device Id with %s option!", OptionName);\r
+          ReturnStatus = 1;\r
+          goto Done;\r
         }\r
-        if (TempValue >= 0x10000) {\r
-          Error (NULL, 0, 2000, "Invalid option value", "Device Id %s out of range!", Argv[1]);\r
-          return 1;\r
+\r
+        //\r
+        // Process until another dash-argument parameter or the end of the list\r
+        //\r
+        while (Argc > 1 && Argv[1][0] != '-') {\r
+          Status = AsciiStringToUint64(Argv[1], FALSE, &TempValue);\r
+          if (EFI_ERROR (Status)) {\r
+            Error (NULL, 0, 2000, "Invalid option value", "%s = %s", OptionName, Argv[1]);\r
+            ReturnStatus = 1;\r
+            goto Done;\r
+          }\r
+          //\r
+          // Don't allow device IDs greater than 16 bits\r
+          // Don't allow 0, since it is used as a list terminator\r
+          //\r
+          if (TempValue >= 0x10000 || TempValue == 0) {\r
+            Error (NULL, 0, 2000, "Invalid option value", "Device Id %s out of range!", Argv[1]);\r
+            ReturnStatus = 1;\r
+            goto Done;\r
+          }\r
+\r
+          DevIdList = (UINT16*) realloc (Options->DevIdList, (Options->DevIdCount + 1) * sizeof (UINT16));\r
+          if (DevIdList == NULL) {\r
+            Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!", NULL);\r
+            ReturnStatus = 1;\r
+            goto Done;\r
+          }\r
+          Options->DevIdList = DevIdList;\r
+\r
+          Options->DevIdList[Options->DevIdCount++] = (UINT16) TempValue;\r
+\r
+          Argv++;\r
+          Argc--;\r
         }\r
-        Options->DevId      = (UINT16) TempValue;\r
-        Options->DevIdValid = 1;\r
 \r
-        Argv++;\r
-        Argc--;\r
       } else if ((stricmp (Argv[0], "-o") == 0) || (stricmp (Argv[0], "--output") == 0)) {\r
         //\r
         // Output filename specified with -o\r
@@ -958,9 +1067,16 @@ Returns:
         //\r
         if (Argv[1] == NULL || Argv[1][0] == '-') {\r
           Error (NULL, 0, 2000, "Invalid parameter", "Missing output file name with %s option!", Argv[0]);\r
-          return STATUS_ERROR;\r
+          ReturnStatus = STATUS_ERROR;\r
+          goto Done;\r
         }\r
-        strcpy (Options->OutFileName, Argv[1]);\r
+        if (strlen (Argv[1]) > MAX_PATH - 1) {\r
+          Error (NULL, 0, 2000, "Invalid parameter", "Output file name %s is too long!", Argv[1]);\r
+          ReturnStatus = STATUS_ERROR;\r
+          goto Done;\r
+        }\r
+        strncpy (Options->OutFileName, Argv[1], MAX_PATH - 1);\r
+        Options->OutFileName[MAX_PATH - 1] = 0;\r
 \r
         Argv++;\r
         Argc--;\r
@@ -969,7 +1085,8 @@ Returns:
         // Help option\r
         //\r
         Usage ();\r
-        return STATUS_ERROR;\r
+        ReturnStatus = STATUS_ERROR;\r
+        goto Done;\r
       } else if (stricmp (Argv[0], "-b") == 0) {\r
         //\r
         // Specify binary files with -b\r
@@ -997,11 +1114,13 @@ Returns:
         Status = AsciiStringToUint64(Argv[1], FALSE, &DebugLevel);\r
         if (EFI_ERROR (Status)) {\r
           Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);\r
-          return 1;\r
+          ReturnStatus = 1;\r
+          goto Done;\r
         }\r
         if (DebugLevel > 9)  {\r
           Error (NULL, 0, 2000, "Invalid option value", "Debug Level range is 0-9, current input level is %d", Argv[1]);\r
-          return 1;\r
+          ReturnStatus = 1;\r
+          goto Done;\r
         }\r
         if (DebugLevel>=5 && DebugLevel<=9) {\r
           Options->Debug = TRUE;\r
@@ -1021,7 +1140,7 @@ Returns:
         Options->DumpOption   = 1;\r
 \r
         Options->VendIdValid  = 1;\r
-        Options->DevIdValid   = 1;\r
+        Options->DevIdCount   = 1;\r
         FileFlags             = FILE_FLAG_BINARY;\r
       } else if ((stricmp (Argv[0], "-l") == 0) || (stricmp (Argv[0], "--class-code") == 0)) {\r
         //\r
@@ -1031,12 +1150,14 @@ Returns:
         Status = AsciiStringToUint64(Argv[1], FALSE, &TempValue);\r
         if (EFI_ERROR (Status)) {\r
           Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);\r
-          return 1;\r
+          ReturnStatus = 1;\r
+          goto Done;\r
         }\r
         ClassCode = (UINT32) TempValue;\r
         if (ClassCode & 0xFF000000) {\r
           Error (NULL, 0, 2000, "Invalid parameter", "Class code %s out of range!", Argv[1]);\r
-          return STATUS_ERROR;\r
+          ReturnStatus = STATUS_ERROR;\r
+          goto Done;\r
         }\r
         if (FileList != NULL && FileList->ClassCode == 0) {\r
           FileList->ClassCode = ClassCode;\r
@@ -1052,12 +1173,14 @@ Returns:
         Status = AsciiStringToUint64(Argv[1], FALSE, &TempValue);\r
         if (EFI_ERROR (Status)) {\r
           Error (NULL, 0, 2000, "Invalid option value", "%s = %s", Argv[0], Argv[1]);\r
-          return 1;\r
+          ReturnStatus = 1;\r
+          goto Done;\r
         }\r
         CodeRevision = (UINT32) TempValue;\r
         if (CodeRevision & 0xFFFF0000) {\r
           Error (NULL, 0, 2000, "Invalid parameter", "Code revision %s out of range!", Argv[1]);\r
-          return STATUS_ERROR;\r
+          ReturnStatus = STATUS_ERROR;\r
+          goto Done;\r
         }\r
         if (FileList != NULL && FileList->CodeRevision == 0) {\r
           FileList->CodeRevision = (UINT16) CodeRevision;\r
@@ -1071,7 +1194,8 @@ Returns:
         mOptions.Pci23 = 1;\r
       } else {\r
         Error (NULL, 0, 2000, "Invalid parameter", "Invalid option specified: %s", Argv[0]);\r
-        return STATUS_ERROR;\r
+        ReturnStatus = STATUS_ERROR;\r
+        goto Done;\r
       }\r
     } else {\r
       //\r
@@ -1080,7 +1204,8 @@ Returns:
       //\r
       if ((FileFlags & (FILE_FLAG_BINARY | FILE_FLAG_EFI)) == 0) {\r
         Error (NULL, 0, 2000, "Invalid parameter", "Missing -e or -b with input file %s!", Argv[0]);\r
-        return STATUS_ERROR;\r
+        ReturnStatus = STATUS_ERROR;\r
+        goto Done;\r
       }\r
       //\r
       // Check Efi Option RomImage\r
@@ -1094,9 +1219,10 @@ Returns:
       FileList = (FILE_LIST *) malloc (sizeof (FILE_LIST));\r
       if (FileList == NULL) {\r
         Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!", NULL);\r
-        return STATUS_ERROR;\r
+        ReturnStatus = STATUS_ERROR;\r
+        goto Done;\r
       }\r
-      \r
+\r
       //\r
       // set flag and class code for this image.\r
       //\r
@@ -1113,7 +1239,7 @@ Returns:
       } else {\r
         if (PrevFileList == NULL) {\r
           PrevFileList = FileList;\r
-        } else {          \r
+        } else {\r
           PrevFileList->Next = FileList;\r
         }\r
       }\r
@@ -1132,6 +1258,9 @@ Returns:
   //\r
   if (Options->FileList == NULL) {\r
     Error (NULL, 0, 2000, "Invalid parameter", "Missing input file name!");\r
+    //\r
+    // No memory allocation, return directly.\r
+    //\r
     return STATUS_ERROR;\r
   }\r
 \r
@@ -1141,16 +1270,33 @@ Returns:
   if (EfiRomFlag) {\r
     if (!Options->VendIdValid) {\r
       Error (NULL, 0, 2000, "Missing Vendor ID in command line", NULL);\r
-      return STATUS_ERROR;\r
+      ReturnStatus = STATUS_ERROR;\r
+      goto Done;\r
     }\r
-  \r
-    if (!Options->DevIdValid) {\r
+\r
+    if (!Options->DevIdCount) {\r
       Error (NULL, 0, 2000, "Missing Device ID in command line", NULL);\r
-      return STATUS_ERROR;\r
+      ReturnStatus = STATUS_ERROR;\r
+      goto Done;\r
     }\r
   }\r
 \r
-  return 0;\r
+   if (Options->DevIdCount > 1 && Options->Pci23) {\r
+     Error (NULL, 0, 2000, "Invalid parameter", "PCI 3.0 is required when specifying multiple Device IDs");\r
+     ReturnStatus = STATUS_ERROR;\r
+     goto Done;\r
+   }\r
+\r
+Done:\r
+  if (ReturnStatus != 0) {\r
+    while (Options->FileList != NULL) {\r
+      FileList = Options->FileList->Next;\r
+      free (Options->FileList);\r
+      Options->FileList = FileList;\r
+    }\r
+  }\r
+\r
+  return ReturnStatus;\r
 }\r
 \r
 static\r
@@ -1161,7 +1307,7 @@ Version (
 /*++\r
 \r
 Routine Description:\r
-  \r
+\r
   Print version information for this utility.\r
 \r
 Arguments:\r
@@ -1175,7 +1321,7 @@ Returns:
 {\r
  fprintf (stdout, "%s Version %d.%d %s \n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);\r
 }\r
-   \r
+\r
 static\r
 void\r
 Usage (\r
@@ -1184,7 +1330,7 @@ Usage (
 /*++\r
 \r
 Routine Description:\r
-  \r
+\r
   Print usage information for this utility.\r
 \r
 Arguments:\r
@@ -1200,19 +1346,19 @@ Returns:
   //\r
   // Summary usage\r
   //\r
-  fprintf (stdout, "Usage: %s [options] [file name<s>] \n\n", UTILITY_NAME);\r
-  \r
+  fprintf (stdout, "Usage: %s -f VendorId -i DeviceId [options] [file name<s>] \n\n", UTILITY_NAME);\r
+\r
   //\r
   // Copyright declaration\r
-  // \r
-  fprintf (stdout, "Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.\n\n");\r
+  //\r
+  fprintf (stdout, "Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.\n\n");\r
 \r
   //\r
   // Details Option\r
   //\r
   fprintf (stdout, "Options:\n");\r
   fprintf (stdout, "  -o FileName, --output FileName\n\\r
-            File will be created to store the ouput content.\n");\r
+            File will be created to store the output content.\n");\r
   fprintf (stdout, "  -e EfiFileName\n\\r
             EFI PE32 image files.\n");\r
   fprintf (stdout, "  -ec EfiFileName\n\\r
@@ -1224,9 +1370,9 @@ Returns:
   fprintf (stdout, "  -r Rev    Hex Revision in the PCI data structure header.\n");\r
   fprintf (stdout, "  -n        Not to automatically set the LAST bit in the last file.\n");\r
   fprintf (stdout, "  -f VendorId\n\\r
-            Hex PCI Vendor ID for the device OpROM.\n");\r
+            Hex PCI Vendor ID for the device OpROM, must be specified\n");\r
   fprintf (stdout, "  -i DeviceId\n\\r
-            Hex PCI Device ID for the device OpROM.\n");\r
+            One or more hex PCI Device IDs for the device OpROM, must be specified\n");\r
   fprintf (stdout, "  -p, --pci23\n\\r
             Default layout meets PCI 3.0 specifications\n\\r
             specifying this flag will for a PCI 2.3 layout.\n");\r
@@ -1240,7 +1386,7 @@ Returns:
   fprintf (stdout, "  -q, --quiet\n\\r
             Disable all messages except FATAL ERRORS.\n");\r
   fprintf (stdout, "  --debug [#,0-9]\n\\r
-            Enable debug messages at level #.\n");  \r
+            Enable debug messages at level #.\n");\r
 }\r
 \r
 static\r
@@ -1271,11 +1417,12 @@ Returns:
   EFI_PCI_EXPANSION_ROM_HEADER  EfiRomHdr;\r
   PCI_DATA_STRUCTURE            PciDs23;\r
   PCI_3_0_DATA_STRUCTURE        PciDs30;\r
+  UINT16                        DevId;\r
 \r
   //\r
   // Open the input file\r
   //\r
-  if ((InFptr = fopen (InFile->FileName, "rb")) == NULL) {\r
+  if ((InFptr = fopen (LongFilePath (InFile->FileName), "rb")) == NULL) {\r
     Error (NULL, 0, 0001, "Error opening file", InFile->FileName);\r
     return ;\r
   }\r
@@ -1285,7 +1432,7 @@ Returns:
   ImageCount = 0;\r
   for (;;) {\r
     //\r
-    // Save our postition in the file, since offsets in the headers\r
+    // Save our position in the file, since offsets in the headers\r
     // are relative to the particular image.\r
     //\r
     ImageStart = ftell (InFptr);\r
@@ -1368,7 +1515,31 @@ Returns:
     fprintf (stdout, "    Device ID               0x%04X\n", PciDs30.DeviceId);\r
     fprintf (stdout, "    Length                  0x%04X\n", PciDs30.Length);\r
     fprintf (stdout, "    Revision                0x%04X\n", PciDs30.Revision);\r
-    fprintf (stdout, "    DeviceListOffset        0x%02X\n", PciDs30.DeviceListOffset);    \r
+    fprintf (stdout, "    DeviceListOffset        0x%02X\n", PciDs30.DeviceListOffset);\r
+    if (PciDs30.DeviceListOffset) {\r
+      //\r
+      // Print device ID list\r
+      //\r
+      fprintf (stdout, "    Device list contents\n");\r
+      if (fseek (InFptr, ImageStart + PciRomHdr.PcirOffset + PciDs30.DeviceListOffset, SEEK_SET)) {\r
+        Error (NULL, 0, 3001, "Not supported", "Failed to seek to PCI device ID list!");\r
+        goto BailOut;\r
+      }\r
+\r
+      //\r
+      // Loop until terminating 0\r
+      //\r
+      do {\r
+        if (fread (&DevId, sizeof (DevId), 1, InFptr) != 1) {\r
+          Error (NULL, 0, 3001, "Not supported", "Failed to read PCI device ID list from file %s!", InFile->FileName);\r
+          goto BailOut;\r
+        }\r
+        if (DevId) {\r
+          fprintf (stdout, "      0x%04X\n", DevId);\r
+        }\r
+      } while (DevId);\r
+\r
+    }\r
     fprintf (\r
       stdout,\r
       "    Class Code              0x%06X\n",\r
@@ -1378,8 +1549,8 @@ Returns:
     fprintf (stdout, "    Code revision:          0x%04X\n", PciDs30.CodeRevision);\r
     fprintf (stdout, "    MaxRuntimeImageLength   0x%02X\n", PciDs30.MaxRuntimeImageLength);\r
     fprintf (stdout, "    ConfigUtilityCodeHeaderOffset 0x%02X\n", PciDs30.ConfigUtilityCodeHeaderOffset);\r
-    fprintf (stdout, "    DMTFCLPEntryPointOffset 0x%02X\n", PciDs30.DMTFCLPEntryPointOffset);   \r
-    fprintf (stdout, "    Indicator               0x%02X", PciDs30.Indicator);    \r
+    fprintf (stdout, "    DMTFCLPEntryPointOffset 0x%02X\n", PciDs30.DMTFCLPEntryPointOffset);\r
+    fprintf (stdout, "    Indicator               0x%02X", PciDs30.Indicator);\r
     }\r
     //\r
     // Print the indicator, used to flag the last image\r
@@ -1395,7 +1566,7 @@ Returns:
     if (mOptions.Pci23 == 1) {\r
       fprintf (stdout, "    Code type              0x%02X", PciDs23.CodeType);\r
     } else {\r
-      fprintf (stdout, "    Code type               0x%02X", PciDs30.CodeType); \r
+      fprintf (stdout, "    Code type               0x%02X", PciDs30.CodeType);\r
     }\r
     if (PciDs23.CodeType == PCI_CODE_TYPE_EFI_IMAGE || PciDs30.CodeType == PCI_CODE_TYPE_EFI_IMAGE) {\r
       fprintf (stdout, "   (EFI image)\n");\r