]> git.proxmox.com Git - mirror_edk2.git/blobdiff - BaseTools/Source/C/EfiRom/EfiRom.c
BaseTools/EfiRom: Add multiple device id support
[mirror_edk2.git] / BaseTools / Source / C / EfiRom / EfiRom.c
index 838ee25cba74c9212342cb7a5f65105a090eb1c9..0f8928025119a8f9fbbfc3b98d1de02fa77b83e3 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 - 2014, Intel Corporation. All rights reserved.<BR>\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,26 @@ 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
+      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
 \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,7 +122,7 @@ 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
@@ -150,7 +144,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 +170,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 +184,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
@@ -247,7 +248,7 @@ Returns:
   // Try to open the input file\r
   //\r
   if ((InFptr = fopen (LongFilePath (InFile->FileName), "rb")) == NULL) {\r
-    Error (NULL, 0, 0001, "Error opening file", InFile->FileName);\r
+    Error (NULL, 0, 0001, "Error opening file", "%s", InFile->FileName);\r
     return STATUS_ERROR;\r
   }\r
   //\r
@@ -456,6 +457,7 @@ Returns:
   UINT32                        HeaderPadBytes;\r
   UINT32                        PadBytesBeforeImage;\r
   UINT32                        PadBytesAfterImage;\r
+  UINT32                        DevIdListSize;\r
 \r
   //\r
   // Try to open the input file\r
@@ -499,7 +501,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
@@ -636,7 +647,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
@@ -706,6 +724,26 @@ Returns:
     } \r
   }\r
 \r
+  //\r
+  // Write the Device ID list to the output file\r
+  //\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
@@ -889,9 +927,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
@@ -905,6 +947,9 @@ Returns:
   //\r
   FileList                = PrevFileList = NULL;\r
 \r
+  Options->DevIdList      = NULL;\r
+  Options->DevIdCount     = 0;\r
+\r
   ClassCode               = 0;\r
   CodeRevision            = 0;\r
   //\r
@@ -946,11 +991,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
@@ -958,24 +1005,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
@@ -983,9 +1059,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
@@ -994,7 +1077,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
@@ -1022,11 +1106,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
@@ -1046,7 +1132,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
@@ -1056,12 +1142,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
@@ -1077,12 +1165,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
@@ -1096,7 +1186,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
@@ -1105,7 +1196,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
@@ -1119,7 +1211,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
@@ -1157,6 +1250,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
@@ -1166,16 +1262,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
-  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
@@ -1230,7 +1343,7 @@ Returns:
   //\r
   // Copyright declaration\r
   // \r
-  fprintf (stdout, "Copyright (c) 2007 - 2014, 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
@@ -1251,7 +1364,7 @@ Returns:
   fprintf (stdout, "  -f VendorId\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, must be specified\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
@@ -1296,6 +1409,7 @@ 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
@@ -1394,6 +1508,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