]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/C/EfiRom/EfiRom.c
BaseTools: Fix a bug for Size incorrect of Void* Fixatbuild Pcd
[mirror_edk2.git] / BaseTools / Source / C / EfiRom / EfiRom.c
index 981786c705b9b85f46e8dff300b796c164d0562e..fc3b5ad277a60db17bd7b3fda5a8a2bbf39932ee 100644 (file)
@@ -1,6 +1,7 @@
 /** @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\r
+Copyright (c) 1999 - 2017, 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
@@ -9,15 +10,6 @@ http://opensource.org/licenses/bsd-license.php
 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
@@ -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,6 +192,16 @@ 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
@@ -237,6 +246,7 @@ Returns:
   PCI_3_0_DATA_STRUCTURE    *PciDs30;\r
   UINT32                    Index;\r
   UINT8                     ByteCheckSum;\r
+  UINT16                    CodeType;\r
  \r
   PciDs23 = NULL;\r
   PciDs30 = NULL;\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,8 +347,10 @@ 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
+    CodeType = PciDs30->CodeType;\r
        }\r
 \r
   //\r
@@ -359,14 +371,16 @@ Returns:
                }\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
@@ -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
@@ -492,7 +509,16 @@ Returns:
   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,6 +585,18 @@ 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
@@ -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
@@ -686,11 +731,38 @@ Returns:
       goto BailOut;\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
@@ -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
@@ -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,7 +1219,8 @@ 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
@@ -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
+    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
+   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 0;\r
+  return ReturnStatus;\r
 }\r
 \r
 static\r
@@ -1173,7 +1319,7 @@ Returns:
   Nothing.\r
 --*/\r
 {\r
- fprintf (stdout, "%s Version %d.%d\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);\r
+ fprintf (stdout, "%s Version %d.%d %s \n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);\r
 }\r
    \r
 static\r
@@ -1200,19 +1346,19 @@ Returns:
   //\r
   // Summary usage\r
   //\r
-  fprintf (stdout, "Usage: %s [options] [file name<s>] \n\n", UTILITY_NAME);\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
+  fprintf (stdout, "Copyright (c) 2007 - 2017, 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
@@ -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
@@ -1369,6 +1516,30 @@ Returns:
     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
+    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