git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@2196 6f19259b-4bc3-4df7-8a09-765794883524
		
			
				
	
	
		
			2695 lines
		
	
	
		
			71 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			2695 lines
		
	
	
		
			71 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /*++
 | |
| 
 | |
| Copyright (c) 2004-2007, Intel Corporation                                                         
 | |
| All rights reserved. This program and the accompanying materials                          
 | |
| are licensed and made available under the terms and conditions of the BSD License         
 | |
| which accompanies this distribution.  The full text of the license may be found at        
 | |
| http://opensource.org/licenses/bsd-license.php                                            
 | |
|                                                                                           
 | |
| THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     
 | |
| WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             
 | |
| 
 | |
| Module Name:
 | |
| 
 | |
|   GenFfsFile.c
 | |
| 
 | |
| Abstract:
 | |
| 
 | |
|   This file contains functions required to generate a Firmware File System
 | |
|   file.
 | |
| 
 | |
| --*/
 | |
| 
 | |
| #include <stdio.h>
 | |
| #include <ctype.h>  // for isalpha()
 | |
| //
 | |
| // include file for _spawnv
 | |
| //
 | |
| #ifndef __GNUC__
 | |
| #include <process.h>
 | |
| #endif
 | |
| #include <stdlib.h>
 | |
| #include <string.h>
 | |
| 
 | |
| #include <Common/UefiBaseTypes.h>
 | |
| #include <Common/FirmwareVolumeImageFormat.h>
 | |
| #include <Common/FirmwareFileSystem.h>
 | |
| #include <Common/FirmwareVolumeHeader.h>
 | |
| #include <Common/FirmwareVolumeImageFormat.h>
 | |
| 
 | |
| #include "ParseInf.h"
 | |
| #include "Compress.h"
 | |
| #include "EfiCustomizedCompress.h"
 | |
| #include "Crc32.h"
 | |
| #include "GenFfsFile.h"
 | |
| #include "CommonLib.h"
 | |
| #include "EfiUtilityMsgs.h"
 | |
| #include "SimpleFileParsing.h"
 | |
| 
 | |
| #define UTILITY_NAME            "GenFfsFile"
 | |
| #define UTILITY_MAJOR_VERSION   0
 | |
| #define UTILITY_MINOR_VERSION   32
 | |
| 
 | |
| #define MAX_ARRAY_SIZE  100
 | |
| 
 | |
| static
 | |
| INT32
 | |
| GetNextLine (
 | |
|   OUT CHAR8       *Destination,
 | |
|   IN FILE         *Package,
 | |
|   IN OUT UINT32   *LineNumber
 | |
|   );
 | |
| 
 | |
| static
 | |
| void
 | |
| CheckSlash (
 | |
|   IN OUT CHAR8  *String,
 | |
|   IN FILE       *In,
 | |
|   IN OUT UINT32 *LineNumber
 | |
|   );
 | |
| 
 | |
| static
 | |
| INT32
 | |
| FindSectionInPackage (
 | |
|   IN CHAR8        *BuildDirectory,
 | |
|   IN FILE         *OverridePackage,
 | |
|   IN OUT UINT32   *LineNumber
 | |
|   );
 | |
| 
 | |
| static
 | |
| STATUS
 | |
| ProcessCommandLineArgs (
 | |
|   int     Argc,
 | |
|   char    *Argv[]
 | |
|   );
 | |
| 
 | |
| static
 | |
| void
 | |
| Version (
 | |
|   void
 | |
|   );
 | |
| 
 | |
| static
 | |
| void
 | |
| Usage (
 | |
|   void
 | |
|   );
 | |
| 
 | |
| //
 | |
| // Keep globals in this structure
 | |
| //
 | |
| static struct {
 | |
|   UINT8   BuildDirectory[_MAX_PATH];
 | |
|   UINT8   PrimaryPackagePath[_MAX_PATH];
 | |
|   UINT8   OverridePackagePath[_MAX_PATH];
 | |
|   BOOLEAN Verbose;
 | |
| } mGlobals;
 | |
| 
 | |
| static EFI_GUID mZeroGuid = { 0 };
 | |
| 
 | |
| static
 | |
| void
 | |
| StripQuotes (
 | |
|   IN OUT CHAR8 *String
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Removes quotes and/or whitespace from around a string
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|  String    - String to remove quotes from
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   None
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINTN Index;
 | |
|   UINTN Index2;
 | |
|   UINTN StrLen;
 | |
| 
 | |
|   Index2  = strspn (String, "\" \t\n");
 | |
|   StrLen  = strlen (String);
 | |
| 
 | |
|   for (Index = Index2; String[Index] != '\"', Index < StrLen; Index++) {
 | |
|     String[Index - Index2] = String[Index];
 | |
|   }
 | |
| 
 | |
|   String[Index - Index2] = 0;
 | |
| }
 | |
| 
 | |
| static
 | |
| void 
 | |
| Version(
 | |
|   void
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Print out version information for this utility.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   None
 | |
|   
 | |
| Returns:
 | |
| 
 | |
|   None
 | |
|   
 | |
| --*/ 
 | |
| {
 | |
|   printf ("%s v%d.%d -EDK utility to generate a Firmware File System files.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);
 | |
|   printf ("Copyright (c) 1999-2007 Intel Corporation. All rights reserved.\n");
 | |
| }
 | |
| 
 | |
| static
 | |
| void
 | |
| Usage (
 | |
|   void
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Print Error / Help message.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   void
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   None
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   Version();
 | |
|   
 | |
|   printf ("\nUsage:\n");
 | |
|   printf (UTILITY_NAME " -b \"build directory\" -p1 \"package1.inf\" -p2 \"package2.inf\" -v\n");
 | |
|   printf ("   -b \"build directory\":\n ");
 | |
|   printf ("       specifies the full path to the component build directory.\n");
 | |
|   printf ("   -p1 \"P1_path\":\n");
 | |
|   printf ("       specifies fully qualified file name to the primary package file.\n");
 | |
|   printf ("       This file will normally exist in the same directory as the makefile\n");
 | |
|   printf ("       for the component. Required.\n");
 | |
|   printf ("   -p2 \"P2_path\":\n");
 | |
|   printf ("       specifies fully qualified file name to the override package file.\n");
 | |
|   printf ("       This file will normally exist in the build tip. Optional.\n");
 | |
| }
 | |
| 
 | |
| static
 | |
| INT32
 | |
| TestComment (
 | |
|   IN CHAR8  *String,
 | |
|   IN FILE   *In
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Tests input string to see if it is a comment, and if so goes to the next line in the file that is not a comment
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   String      - String to test
 | |
| 
 | |
|   In          - Open file to move pointer within
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   -1          - End of file reached
 | |
|    0          - Not a comment
 | |
|    1          - Comment bypassed
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   CHAR8 CharBuffer;
 | |
| 
 | |
|   CharBuffer = 0;
 | |
|   if ((String[0] == '/') && (String[1] == '/')) {
 | |
|     while (CharBuffer != '\n') {
 | |
|       fscanf (In, "%c", &CharBuffer);
 | |
|       if (feof (In)) {
 | |
|         return -1;
 | |
|       }
 | |
|     }
 | |
|   } else {
 | |
|     return 0;
 | |
|   }
 | |
| 
 | |
|   return 1;
 | |
| }
 | |
| 
 | |
| static
 | |
| void
 | |
| BreakString (
 | |
|   IN CONST CHAR8 *Source,
 | |
|   OUT CHAR8      *Destination,
 | |
|   IN INTN        Direction
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Takes an input string and returns either the part before the =, or the part after the =, depending on direction
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Source      - String to break
 | |
| 
 | |
|   Destination - Buffer to place new string in
 | |
| 
 | |
|   Direction   - 0 to return all of source string before =
 | |
|                 1 to return all of source string after =
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   None
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINTN Index;
 | |
|   UINTN Index2;
 | |
| 
 | |
|   Index   = 0;
 | |
|   Index2  = 0;
 | |
| 
 | |
|   if (strchr (Source, '=') == NULL) {
 | |
|     strcpy (Destination, Source);
 | |
| 
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   if (Direction == 0) {
 | |
|     //
 | |
|     // return part of string before =
 | |
|     //
 | |
|     while (Source[Index] != '=') {
 | |
|       Destination[Index] = Source[Index++];
 | |
|     }
 | |
| 
 | |
|     Destination[Index] = 0;
 | |
|   } else {
 | |
|     //
 | |
|     // return part of string after =
 | |
|     //
 | |
|     strcpy (Destination, strchr (Source, '=') + 1);
 | |
|   }
 | |
| }
 | |
| 
 | |
| static
 | |
| INT32
 | |
| GetNextLine (
 | |
|   OUT CHAR8       *Destination,
 | |
|   IN FILE         *Package,
 | |
|   IN OUT UINT32   *LineNumber
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Gets the next non-commented line from the file
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Destination - Where to put string
 | |
| 
 | |
|   Package     - Package to get string from
 | |
|   
 | |
|   LineNumber  - The actual line number.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   -1          - End of file reached
 | |
|    0          - Success
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   CHAR8 String[_MAX_PATH];
 | |
|   fscanf (Package, "%s", &String);
 | |
|   if (feof (Package)) {
 | |
|     return -1;
 | |
|   }
 | |
| 
 | |
|   while (TestComment (String, Package) == 1) {
 | |
|     fscanf (Package, "%s", &String);
 | |
|     if (feof (Package)) {
 | |
|       return -1;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   strcpy (Destination, String);
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static
 | |
| VOID
 | |
| CheckSlash (
 | |
|   IN OUT CHAR8  *String,
 | |
|   IN FILE       *In,
 | |
|   IN OUT UINT32 *LineNumber
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Checks to see if string is line continuation character, if so goes to next valid line
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   String      - String to test
 | |
| 
 | |
|   In          - Open file to move pointer within
 | |
|   
 | |
|   LineNumber  - The line number.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   None
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   CHAR8 ByteBuffer;
 | |
|   ByteBuffer = 0;
 | |
| 
 | |
|   switch (String[0]) {
 | |
| 
 | |
|   case '\\':
 | |
|     while (String[0] == '\\') {
 | |
|       while (ByteBuffer != '\n') {
 | |
|         fscanf (In, "%c", &ByteBuffer);
 | |
|       }
 | |
|       (*LineNumber)++;
 | |
|       if (GetNextLine (String, In, LineNumber) == -1) {
 | |
|         return ;
 | |
|       }
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   case '\n':
 | |
|     (*LineNumber)++;
 | |
|     while (String[0] == '\n') {
 | |
|       if (GetNextLine (String, In, LineNumber) == -1) {
 | |
|         return ;
 | |
|       }
 | |
|     }
 | |
|     break;
 | |
| 
 | |
|   default:
 | |
|     break;
 | |
| 
 | |
|   }
 | |
| 
 | |
| }
 | |
| 
 | |
| static
 | |
| INT32
 | |
| FindSectionInPackage (
 | |
|   IN CHAR8        *BuildDirectory,
 | |
|   IN FILE         *OverridePackage,
 | |
|   IN OUT UINT32   *LineNumber
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Finds the matching section within the package
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   BuildDirectory  - name of section to find
 | |
| 
 | |
|   OverridePackage - Package file to search within
 | |
|   
 | |
|   LineNumber      - The line number.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   -1          - End of file reached
 | |
|    0          - Success
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   CHAR8 String[_MAX_PATH];
 | |
|   CHAR8 NewString[_MAX_PATH];
 | |
|   String[0] = 0;
 | |
| 
 | |
|   while (strcmp (BuildDirectory, String) != 0) {
 | |
|     if (GetNextLine (NewString, OverridePackage, LineNumber) != 0) {
 | |
|       return -1;
 | |
|     }
 | |
| 
 | |
|     if (NewString[0] == '[') {
 | |
|       if (NewString[strlen (NewString) - 1] != ']') {
 | |
|         //
 | |
|         // have to construct string.
 | |
|         //
 | |
|         strcpy (String, NewString + 1);
 | |
| 
 | |
|         while (1) {
 | |
|           fscanf (OverridePackage, "%s", &NewString);
 | |
|           if (feof (OverridePackage)) {
 | |
|             return -1;
 | |
|           }
 | |
| 
 | |
|           if (NewString[0] != ']') {
 | |
|             if (strlen (String) != 0) {
 | |
|               strcat (String, " ");
 | |
|             }
 | |
| 
 | |
|             strcat (String, NewString);
 | |
|             if (String[strlen (String) - 1] == ']') {
 | |
|               String[strlen (String) - 1] = 0;
 | |
|               break;
 | |
|             }
 | |
|           } else {
 | |
|             break;
 | |
|           }
 | |
|         }
 | |
|       } else {
 | |
|         NewString[strlen (NewString) - 1] = 0;
 | |
|         strcpy (String, NewString + 1);
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return 0;
 | |
| }
 | |
| 
 | |
| static
 | |
| EFI_STATUS
 | |
| GenSimpleGuidSection (
 | |
|   IN OUT UINT8  *FileBuffer,
 | |
|   IN OUT UINT32 *BufferSize,
 | |
|   IN UINT32     DataSize,
 | |
|   IN EFI_GUID   SignGuid,
 | |
|   IN UINT16     GuidedSectionAttributes
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   add GUIDed section header for the data buffer.
 | |
|   data stays in same location (overwrites source data).
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   FileBuffer  - Buffer containing data to sign
 | |
| 
 | |
|   BufferSize  - On input, the size of FileBuffer. On output, the size of
 | |
|                 actual section data (including added section header).
 | |
| 
 | |
|   DataSize    - Length of data to Sign
 | |
| 
 | |
|   SignGuid    - Guid to be add.
 | |
|   
 | |
|   GuidedSectionAttributes - The section attribute.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_SUCCESS           - Successful
 | |
|   EFI_OUT_OF_RESOURCES  - Not enough resource.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINT32                    TotalSize;
 | |
| 
 | |
|   EFI_GUID_DEFINED_SECTION  GuidSectionHeader;
 | |
|   UINT8                     *SwapBuffer;
 | |
| 
 | |
|   SwapBuffer = NULL;
 | |
| 
 | |
|   if (DataSize == 0) {
 | |
|     *BufferSize = 0;
 | |
| 
 | |
|     return EFI_SUCCESS;
 | |
|   }
 | |
| 
 | |
|   TotalSize = DataSize + sizeof (EFI_GUID_DEFINED_SECTION);
 | |
|   GuidSectionHeader.CommonHeader.Type     = EFI_SECTION_GUID_DEFINED;
 | |
|   GuidSectionHeader.CommonHeader.Size[0]  = (UINT8) (TotalSize & 0xff);
 | |
|   GuidSectionHeader.CommonHeader.Size[1]  = (UINT8) ((TotalSize & 0xff00) >> 8);
 | |
|   GuidSectionHeader.CommonHeader.Size[2]  = (UINT8) ((TotalSize & 0xff0000) >> 16);
 | |
|   memcpy (&(GuidSectionHeader.SectionDefinitionGuid), &SignGuid, sizeof (EFI_GUID));
 | |
|   GuidSectionHeader.Attributes  = GuidedSectionAttributes;
 | |
|   GuidSectionHeader.DataOffset  = sizeof (EFI_GUID_DEFINED_SECTION);
 | |
| 
 | |
|   SwapBuffer                    = (UINT8 *) malloc (DataSize);
 | |
|   if (SwapBuffer == NULL) {
 | |
|     return EFI_OUT_OF_RESOURCES;
 | |
|   }
 | |
| 
 | |
|   memcpy (SwapBuffer, FileBuffer, DataSize);
 | |
|   memcpy (FileBuffer, &GuidSectionHeader, sizeof (EFI_GUID_DEFINED_SECTION));
 | |
|   memcpy (FileBuffer + sizeof (EFI_GUID_DEFINED_SECTION), SwapBuffer, DataSize);
 | |
| 
 | |
|   //
 | |
|   // Make sure section ends on a DWORD boundary
 | |
|   //
 | |
|   while ((TotalSize & 0x03) != 0) {
 | |
|     FileBuffer[TotalSize] = 0;
 | |
|     TotalSize++;
 | |
|   }
 | |
| 
 | |
|   *BufferSize = TotalSize;
 | |
| 
 | |
|   if (SwapBuffer != NULL) {
 | |
|     free (SwapBuffer);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| static
 | |
| EFI_STATUS
 | |
| CompressSection (
 | |
|   UINT8  *FileBuffer,
 | |
|   UINT32 *BufferSize,
 | |
|   UINT32 DataSize,
 | |
|   CHAR8  *Type
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Compress the data and add section header for the compressed data.
 | |
|   Compressed data (with section header) stays in same location as the source
 | |
|   (overwrites source data).
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   FileBuffer  - Buffer containing data to Compress
 | |
| 
 | |
|   BufferSize  - On input, the size of FileBuffer. On output, the size of
 | |
|                 actual compressed data (including added section header).
 | |
|                 When buffer is too small, this value indicates the size needed.
 | |
| 
 | |
|   DataSize    - The size of data to compress
 | |
| 
 | |
|   Type        - The compression type (not used currently).
 | |
|                 Assume EFI_HEAVY_COMPRESSION.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   EFI_BUFFER_TOO_SMALL - Buffer size is too small.
 | |
|   EFI_UNSUPPORTED      - Compress type can not be supported.
 | |
|   EFI_SUCCESS          - Successful
 | |
|   EFI_OUT_OF_RESOURCES - Not enough resource.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS              Status;
 | |
|   UINT8                   *CompData;
 | |
|   UINT32                  CompSize;
 | |
|   UINT32                  TotalSize;
 | |
|   EFI_COMPRESSION_SECTION CompressionSet;
 | |
|   UINT8                   CompressionType;
 | |
|   COMPRESS_FUNCTION       CompressFunction;
 | |
| 
 | |
|   Status            = EFI_SUCCESS;
 | |
|   CompData          = NULL;
 | |
|   CompSize          = 0;
 | |
|   TotalSize         = 0;
 | |
|   CompressFunction  = NULL;
 | |
| 
 | |
|   //
 | |
|   // Get the compress type
 | |
|   //
 | |
|   if (strcmpi (Type, "Dummy") == 0) {
 | |
|     //
 | |
|     // Added "Dummy" to keep backward compatibility.
 | |
|     //
 | |
|     CompressionType   = EFI_STANDARD_COMPRESSION;
 | |
|     CompressFunction  = (COMPRESS_FUNCTION) EfiCompress;
 | |
| 
 | |
|   } else if (strcmpi (Type, "LZH") == 0) {
 | |
|     //
 | |
|     // EFI stardard compression (LZH)
 | |
|     //
 | |
|     CompressionType   = EFI_STANDARD_COMPRESSION;
 | |
|     CompressFunction  = (COMPRESS_FUNCTION) EfiCompress;
 | |
| 
 | |
|   } else {
 | |
|     //
 | |
|     // Customized compression
 | |
|     //
 | |
|     Status = SetCustomizedCompressionType (Type);
 | |
|     if (EFI_ERROR (Status)) {
 | |
|       return Status;
 | |
|     }
 | |
| 
 | |
|     CompressionType   = EFI_CUSTOMIZED_COMPRESSION;
 | |
|     CompressFunction  = (COMPRESS_FUNCTION) CustomizedCompress;
 | |
|   }
 | |
|   //
 | |
|   // Compress the raw data
 | |
|   //
 | |
|   Status = CompressFunction (FileBuffer, DataSize, CompData, &CompSize);
 | |
|   if (Status == EFI_BUFFER_TOO_SMALL) {
 | |
|     CompData = malloc (CompSize);
 | |
|     if (!CompData) {
 | |
|       return EFI_OUT_OF_RESOURCES;
 | |
|     }
 | |
| 
 | |
|     Status = CompressFunction (FileBuffer, DataSize, CompData, &CompSize);
 | |
|   }
 | |
| 
 | |
|   if (EFI_ERROR (Status)) {
 | |
|     if (CompData != NULL) {
 | |
|       free (CompData);
 | |
|     }
 | |
| 
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   TotalSize = CompSize + sizeof (EFI_COMPRESSION_SECTION);
 | |
| 
 | |
|   //
 | |
|   // Buffer too small?
 | |
|   //
 | |
|   if (TotalSize > *BufferSize) {
 | |
|     *BufferSize = TotalSize;
 | |
|     if (CompData != NULL) {
 | |
|       free (CompData);
 | |
|     }
 | |
| 
 | |
|     return EFI_BUFFER_TOO_SMALL;
 | |
|   }
 | |
|   //
 | |
|   // Add the section header for the compressed data
 | |
|   //
 | |
|   CompressionSet.CommonHeader.Type    = EFI_SECTION_COMPRESSION;
 | |
|   CompressionSet.CommonHeader.Size[0] = (UINT8) (TotalSize & 0xff);
 | |
|   CompressionSet.CommonHeader.Size[1] = (UINT8) ((TotalSize & 0xff00) >> 8);
 | |
|   CompressionSet.CommonHeader.Size[2] = (UINT8) ((TotalSize & 0xff0000) >> 16);
 | |
|   CompressionSet.CompressionType      = CompressionType;
 | |
|   CompressionSet.UncompressedLength   = DataSize;
 | |
| 
 | |
|   //
 | |
|   // Copy header and data to the buffer
 | |
|   //
 | |
|   memcpy (FileBuffer, &CompressionSet, sizeof (EFI_COMPRESSION_SECTION));
 | |
|   memcpy (FileBuffer + sizeof (CompressionSet), CompData, CompSize);
 | |
| 
 | |
|   //
 | |
|   // Make sure section ends on a DWORD boundary
 | |
|   //
 | |
|   while ((TotalSize & 0x03) != 0) {
 | |
|     FileBuffer[TotalSize] = 0;
 | |
|     TotalSize++;
 | |
|   }
 | |
| 
 | |
|   *BufferSize = TotalSize;
 | |
| 
 | |
|   if (CompData != NULL) {
 | |
|     free (CompData);
 | |
|   }
 | |
| 
 | |
|   return EFI_SUCCESS;
 | |
| }
 | |
| 
 | |
| static
 | |
| void
 | |
| StripParens (
 | |
|   IN OUT CHAR8 *String
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Removes Parenthesis from around a string
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|  String    - String to remove parens from
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   None
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   INT32 Index;
 | |
| 
 | |
|   if (String[0] != '(') {
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   for (Index = 1; String[Index] != ')'; Index++) {
 | |
|     String[Index - 1] = String[Index];
 | |
|     if (String[Index] == 0) {
 | |
|       return ;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   String[Index - 1] = 0;
 | |
| 
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| static
 | |
| void
 | |
| StripEqualMark (
 | |
|   IN OUT CHAR8 *String
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Removes Equal Mark from around a string
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|  String    - String to remove equal mark from
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   None
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   INT32 Index;
 | |
| 
 | |
|   if (String[0] != '=' && String[strlen (String) - 1] != '=') {
 | |
|     return ;
 | |
|   }
 | |
| 
 | |
|   if (String[0] == '=') {
 | |
| 
 | |
|     for (Index = 1; String[Index] != 0; Index++) {
 | |
|       String[Index - 1] = String[Index];
 | |
|     }
 | |
| 
 | |
|     String[Index - 1] = 0;
 | |
|   }
 | |
| 
 | |
|   if (String[strlen (String) - 1] == '=') {
 | |
|     String[strlen (String) - 1] = 0;
 | |
|   }
 | |
| 
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| static
 | |
| INT32
 | |
| ProcessEnvironmentVariable (
 | |
|   IN CHAR8  *Buffer,
 | |
|   OUT CHAR8 *NewBuffer
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Converts environment variables to values
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   Buffer      - Buffer containing Environment Variable String
 | |
| 
 | |
|   NewBuffer   - Buffer containing value of environment variable
 | |
| 
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   Number of characters from Buffer used
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   INT32 Index;
 | |
|   INT32 Index2;
 | |
|   CHAR8 VariableBuffer[_MAX_PATH];
 | |
| 
 | |
|   Index   = 2;
 | |
|   Index2  = 0;
 | |
| 
 | |
|   while (Buffer[Index] != ')') {
 | |
|     VariableBuffer[Index - 2] = Buffer[Index++];
 | |
|   }
 | |
| 
 | |
|   VariableBuffer[Index - 2] = 0;
 | |
|   Index++;
 | |
| 
 | |
|   if (getenv (VariableBuffer) != NULL) {
 | |
|     strcpy (NewBuffer, getenv (VariableBuffer));
 | |
|   } else {
 | |
|     printf ("Environment variable %s not found!\n", VariableBuffer);
 | |
|   }
 | |
| 
 | |
|   return Index;
 | |
| }
 | |
| 
 | |
| static
 | |
| void
 | |
| SplitAttributesField (
 | |
|   IN CHAR8       *Buffer,
 | |
|   IN CHAR8       *AttributesArray[],
 | |
|   IN OUT UINT32  *NumberOfAttributes
 | |
|   )
 | |
| /*
 | |
|   NumberOfAttributes: on input, it specifies the current number of attributes
 | |
|                       stored in AttributeArray.
 | |
|                       on output, it is updated to the latest number of attributes
 | |
|                       stored in AttributesArray.
 | |
| */
 | |
| {
 | |
|   UINT32  Index;
 | |
|   UINT32  Index2;
 | |
|   UINT32  z;
 | |
|   CHAR8   *CharBuffer;
 | |
| 
 | |
|   CharBuffer  = NULL;
 | |
|   CharBuffer  = (CHAR8 *) malloc (_MAX_PATH);
 | |
|   ZeroMem (CharBuffer, _MAX_PATH);
 | |
| 
 | |
|   for (Index = 0, z = 0, Index2 = 0; Index < strlen (Buffer); Index++) {
 | |
| 
 | |
|     if (Buffer[Index] != '|') {
 | |
|       CharBuffer[z] = Buffer[Index];
 | |
|       z++;
 | |
|     } else {
 | |
| 
 | |
|       CharBuffer[z] = 0;
 | |
|       AttributesArray[*NumberOfAttributes + Index2] = CharBuffer;
 | |
|       Index2++;
 | |
| 
 | |
|       //
 | |
|       // allocate new char buffer for the next attributes string
 | |
|       //
 | |
|       CharBuffer = (CHAR8 *) malloc (_MAX_PATH);
 | |
|       ZeroMem (CharBuffer, _MAX_PATH);
 | |
|       z = 0;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   CharBuffer[z] = 0;
 | |
|   //
 | |
|   // record the last attributes string in the Buffer
 | |
|   //
 | |
|   AttributesArray[*NumberOfAttributes + Index2] = CharBuffer;
 | |
|   Index2++;
 | |
| 
 | |
|   *NumberOfAttributes += Index2;
 | |
| 
 | |
|   return ;
 | |
| }
 | |
| 
 | |
| static
 | |
| INT32
 | |
| GetToolArguments (
 | |
|   CHAR8       *ToolArgumentsArray[],
 | |
|   FILE        *Package,
 | |
|   CHAR8       **PtrInputFileName,
 | |
|   CHAR8       **PtrOutputFileName,
 | |
|   EFI_GUID    *Guid,
 | |
|   UINT16      *GuidedSectionAttributes
 | |
|   )
 | |
| {
 | |
|   CHAR8       Buffer[_MAX_PATH];
 | |
|   BOOLEAN     ArgumentsFlag;
 | |
|   BOOLEAN     InputFlag;
 | |
|   BOOLEAN     OutputFlag;
 | |
|   BOOLEAN     GuidFlag;
 | |
|   BOOLEAN     AttributesFlag;
 | |
|   UINT32      argc;
 | |
|   UINT32      Index2;
 | |
|   UINT32      z;
 | |
|   CHAR8       *CharBuffer;
 | |
|   INT32       Index;
 | |
|   INT32       ReturnValue;
 | |
|   EFI_STATUS  Status;
 | |
| 
 | |
|   CHAR8       *AttributesArray[MAX_ARRAY_SIZE];
 | |
|   UINT32      NumberOfAttributes;
 | |
|   CHAR8       *InputFileName;
 | |
|   CHAR8       *OutputFileName;
 | |
|   UINT32      LineNumber;
 | |
|   Buffer[_MAX_PATH];
 | |
| 
 | |
|   ArgumentsFlag   = FALSE;
 | |
|   InputFlag       = FALSE;
 | |
|   OutputFlag      = FALSE;
 | |
|   GuidFlag        = FALSE;
 | |
|   AttributesFlag  = FALSE;
 | |
|   //
 | |
|   // Start at 1, since ToolArgumentsArray[0]
 | |
|   // is the program name.
 | |
|   //
 | |
|   argc            = 1;
 | |
|   Index2              = 0;
 | |
| 
 | |
|   z                   = 0;
 | |
|   ReturnValue         = 0;
 | |
|   NumberOfAttributes  = 0;
 | |
|   InputFileName       = NULL;
 | |
|   OutputFileName      = NULL;
 | |
| 
 | |
|   ZeroMem (Buffer, _MAX_PATH);
 | |
|   ZeroMem (AttributesArray, sizeof (CHAR8 *) * MAX_ARRAY_SIZE);
 | |
|   LineNumber = 0;
 | |
|   while (Buffer[0] != ')') {
 | |
| 
 | |
|     if (GetNextLine (Buffer, Package, &LineNumber) != -1) {
 | |
|       CheckSlash (Buffer, Package, &LineNumber);
 | |
|       StripEqualMark (Buffer);
 | |
|     } else {
 | |
|       Error (NULL, 0, 0, "failed to get next line from package file", NULL);
 | |
|       return -1;
 | |
|     }
 | |
| 
 | |
|     if (Buffer[0] == ')') {
 | |
|       break;
 | |
|     } else if (strcmpi (Buffer, "ARGS") == 0) {
 | |
| 
 | |
|       ArgumentsFlag   = TRUE;
 | |
|       AttributesFlag  = FALSE;
 | |
|       continue;
 | |
| 
 | |
|     } else if (strcmpi (Buffer, "INPUT") == 0) {
 | |
| 
 | |
|       InputFlag       = TRUE;
 | |
|       ArgumentsFlag   = FALSE;
 | |
|       AttributesFlag  = FALSE;
 | |
|       continue;
 | |
| 
 | |
|     } else if (strcmpi (Buffer, "OUTPUT") == 0) {
 | |
| 
 | |
|       OutputFlag      = TRUE;
 | |
|       ArgumentsFlag   = FALSE;
 | |
|       AttributesFlag  = FALSE;
 | |
|       continue;
 | |
| 
 | |
|     } else if (strcmpi (Buffer, "GUID") == 0) {
 | |
| 
 | |
|       GuidFlag        = TRUE;
 | |
|       ArgumentsFlag   = FALSE;
 | |
|       AttributesFlag  = FALSE;
 | |
|       //
 | |
|       // fetch the GUID for the section
 | |
|       //
 | |
|       continue;
 | |
| 
 | |
|     } else if (strcmpi (Buffer, "ATTRIBUTES") == 0) {
 | |
| 
 | |
|       AttributesFlag  = TRUE;
 | |
|       ArgumentsFlag   = FALSE;
 | |
|       //
 | |
|       // fetch the GUIDed Section's Attributes
 | |
|       //
 | |
|       continue;
 | |
| 
 | |
|     } else if (strcmpi (Buffer, "") == 0) {
 | |
|       continue;
 | |
|     }
 | |
|     //
 | |
|     // get all command arguments into ToolArgumentsArray
 | |
|     //
 | |
|     if (ArgumentsFlag) {
 | |
| 
 | |
|       StripEqualMark (Buffer);
 | |
| 
 | |
|       CharBuffer = (CHAR8 *) malloc (_MAX_PATH);
 | |
|       if (CharBuffer == NULL) {
 | |
|         goto ErrorExit;
 | |
|       }
 | |
| 
 | |
|       ZeroMem (CharBuffer, sizeof (_MAX_PATH));
 | |
| 
 | |
|       ToolArgumentsArray[argc] = CharBuffer;
 | |
| 
 | |
|       if (Buffer[0] == '$') {
 | |
|         Index = ProcessEnvironmentVariable (&Buffer[0], ToolArgumentsArray[argc]);
 | |
|         //
 | |
|         // if there is string after the environment variable, cat it.
 | |
|         //
 | |
|         if ((UINT32) Index < strlen (Buffer)) {
 | |
|           strcat (ToolArgumentsArray[argc], &Buffer[Index]);
 | |
|         }
 | |
|       } else {
 | |
|         strcpy (ToolArgumentsArray[argc], Buffer);
 | |
|       }
 | |
| 
 | |
|       argc += 1;
 | |
|       ToolArgumentsArray[argc] = NULL;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (InputFlag) {
 | |
| 
 | |
|       StripEqualMark (Buffer);
 | |
| 
 | |
|       InputFileName = (CHAR8 *) malloc (_MAX_PATH);
 | |
|       if (InputFileName == NULL) {
 | |
|         goto ErrorExit;
 | |
|       }
 | |
| 
 | |
|       ZeroMem (InputFileName, sizeof (_MAX_PATH));
 | |
| 
 | |
|       if (Buffer[0] == '$') {
 | |
|         Index = ProcessEnvironmentVariable (&Buffer[0], InputFileName);
 | |
|         //
 | |
|         // if there is string after the environment variable, cat it.
 | |
|         //
 | |
|         if ((UINT32) Index < strlen (Buffer)) {
 | |
|           strcat (InputFileName, &Buffer[Index]);
 | |
|         }
 | |
|       } else {
 | |
|         strcpy (InputFileName, Buffer);
 | |
|       }
 | |
| 
 | |
|       InputFlag = FALSE;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (OutputFlag) {
 | |
| 
 | |
|       StripEqualMark (Buffer);
 | |
| 
 | |
|       OutputFileName = (CHAR8 *) malloc (_MAX_PATH);
 | |
|       if (OutputFileName == NULL) {
 | |
|         goto ErrorExit;
 | |
|       }
 | |
| 
 | |
|       ZeroMem (OutputFileName, sizeof (_MAX_PATH));
 | |
| 
 | |
|       if (Buffer[0] == '$') {
 | |
|         Index = ProcessEnvironmentVariable (&Buffer[0], OutputFileName);
 | |
|         //
 | |
|         // if there is string after the environment variable, cat it.
 | |
|         //
 | |
|         if ((UINT32) Index < strlen (Buffer)) {
 | |
|           strcat (OutputFileName, &Buffer[Index]);
 | |
|         }
 | |
|       } else {
 | |
|         strcpy (OutputFileName, Buffer);
 | |
|       }
 | |
| 
 | |
|       OutputFlag = FALSE;
 | |
|       continue;
 | |
|     }
 | |
| 
 | |
|     if (GuidFlag) {
 | |
| 
 | |
|       StripEqualMark (Buffer);
 | |
| 
 | |
|       Status = StringToGuid (Buffer, Guid);
 | |
|       if (EFI_ERROR (Status)) {
 | |
|         ReturnValue = -1;
 | |
|         goto ErrorExit;
 | |
|       }
 | |
| 
 | |
|       GuidFlag = FALSE;
 | |
|     }
 | |
| 
 | |
|     if (AttributesFlag) {
 | |
| 
 | |
|       StripEqualMark (Buffer);
 | |
| 
 | |
|       //
 | |
|       // there might be no space between each attribute in the statement,
 | |
|       // split them aside and return each attribute string
 | |
|       // in the AttributesArray
 | |
|       //
 | |
|       SplitAttributesField (Buffer, AttributesArray, &NumberOfAttributes);
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // ReplaceVariableInBuffer (ToolArgumentsArray,&i,"INPUT",InputVariable,j);
 | |
|   // ReplaceVariableInBuffer (ToolArgumentsArray,&i,"OUTPUT",&TargetFileName,1);
 | |
|   //
 | |
|   for (z = 0; z < NumberOfAttributes; z++) {
 | |
|     if (strcmpi (AttributesArray[z], "PROCESSING_REQUIRED") == 0) {
 | |
|       *GuidedSectionAttributes |= EFI_GUIDED_SECTION_PROCESSING_REQUIRED;
 | |
|     } else if (strcmpi (AttributesArray[z], "AUTH_STATUS_VALID") == 0) {
 | |
|       *GuidedSectionAttributes |= EFI_GUIDED_SECTION_AUTH_STATUS_VALID;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| ErrorExit:
 | |
| 
 | |
|   for (Index2 = 0; Index2 < MAX_ARRAY_SIZE; Index2++) {
 | |
|     if (AttributesArray[Index2] == NULL) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     free (AttributesArray[Index2]);
 | |
|   }
 | |
| 
 | |
|   *PtrInputFileName   = InputFileName;
 | |
|   *PtrOutputFileName  = OutputFileName;
 | |
| 
 | |
|   return ReturnValue;
 | |
| }
 | |
| 
 | |
| static
 | |
| INT32
 | |
| ProcessScript (
 | |
|   IN OUT UINT8   *FileBuffer,
 | |
|   IN FILE        *Package,
 | |
|   IN CHAR8       *BuildDirectory,
 | |
|   IN BOOLEAN     ForceUncompress
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Signs the section, data stays in same location
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   FileBuffer  - Data Buffer
 | |
| 
 | |
|   Package     - Points to curly brace in Image Script
 | |
| 
 | |
|   BuildDirectory     - Name of the source directory parameter
 | |
|   
 | |
|   ForceUncompress   - Whether to force uncompress.
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   Number of bytes added to file buffer
 | |
|   -1 on error
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   EFI_STATUS  Status;
 | |
|   UINT32      Size;
 | |
|   CHAR8       Buffer[_MAX_PATH];
 | |
|   CHAR8       Type[_MAX_PATH];
 | |
|   CHAR8       FileName[_MAX_PATH];
 | |
|   CHAR8       NewBuffer[_MAX_PATH];
 | |
|   INT32       Index3;
 | |
|   INT32       Index2;
 | |
|   UINT32      ReturnValue;
 | |
|   UINT8       ByteBuffer;
 | |
|   FILE        *InFile;
 | |
|   UINT32      SourceDataSize;
 | |
|   CHAR8       *ToolArgumentsArray[MAX_ARRAY_SIZE];
 | |
|   CHAR8       *OutputFileName;
 | |
|   CHAR8       *InputFileName;
 | |
|   CHAR8       ToolName[_MAX_PATH];
 | |
|   FILE        *OutputFile;
 | |
|   FILE        *InputFile;
 | |
|   UINT8       Temp;
 | |
|   int         returnint;
 | |
|   INT32       Index;
 | |
|   UINT32      LineNumber;
 | |
|   BOOLEAN     IsError;
 | |
|   EFI_GUID    SignGuid;
 | |
|   UINT16      GuidedSectionAttributes;
 | |
|   UINT8       *TargetFileBuffer;
 | |
| 
 | |
|   OutputFileName          = NULL;
 | |
|   InputFileName           = NULL;
 | |
|   OutputFile              = NULL;
 | |
|   InputFile               = NULL;
 | |
|   IsError                 = FALSE;
 | |
|   GuidedSectionAttributes = 0;
 | |
|   TargetFileBuffer        = NULL;
 | |
| 
 | |
|   Size                    = 0;
 | |
|   LineNumber              = 0;
 | |
|   Buffer[0]               = 0;
 | |
|   for (Index3 = 0; Index3 < MAX_ARRAY_SIZE; ++Index3) {
 | |
|     ToolArgumentsArray[Index3] = NULL;
 | |
|   }
 | |
| 
 | |
|   while (Buffer[0] != '}') {
 | |
|     if (GetNextLine (Buffer, Package, &LineNumber) != -1) {
 | |
|       CheckSlash (Buffer, Package, &LineNumber);
 | |
|     } else {
 | |
|       printf ("ERROR in IMAGE SCRIPT!\n");
 | |
|       IsError = TRUE;
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     if (strcmpi (Buffer, "Compress") == 0) {
 | |
|       //
 | |
|       // Handle compress
 | |
|       //
 | |
|       //
 | |
|       // read compression type
 | |
|       //
 | |
|       if (GetNextLine (Buffer, Package, &LineNumber) != -1) {
 | |
|         CheckSlash (Buffer, Package, &LineNumber);
 | |
|       }
 | |
| 
 | |
|       StripParens (Buffer);
 | |
|       if (Buffer[0] == '$') {
 | |
|         ProcessEnvironmentVariable (&Buffer[0], Type);
 | |
|       } else {
 | |
|         strcpy (Type, Buffer);
 | |
|       }
 | |
|       //
 | |
|       // build buffer
 | |
|       //
 | |
|       while (Buffer[0] != '{') {
 | |
|         if (GetNextLine (Buffer, Package, &LineNumber) != -1) {
 | |
|           CheckSlash (Buffer, Package, &LineNumber);
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       ReturnValue = ProcessScript (&FileBuffer[Size], Package, BuildDirectory, ForceUncompress);
 | |
|       if (ReturnValue == -1) {
 | |
|         IsError = TRUE;
 | |
|         goto Done;
 | |
|       }
 | |
|       //
 | |
|       // Call compress routine on buffer.
 | |
|       // Occasionally, compressed data + section header would
 | |
|       // be largere than the source and EFI_BUFFER_TOO_SMALL is
 | |
|       // returned from CompressSection()
 | |
|       //
 | |
|       SourceDataSize = ReturnValue;
 | |
| 
 | |
|       if (!ForceUncompress) {
 | |
| 
 | |
|         Status = CompressSection (
 | |
|                   &FileBuffer[Size],
 | |
|                   &ReturnValue,
 | |
|                   SourceDataSize,
 | |
|                   Type
 | |
|                   );
 | |
| 
 | |
|         if (Status == EFI_BUFFER_TOO_SMALL) {
 | |
|           Status = CompressSection (
 | |
|                     &FileBuffer[Size],
 | |
|                     &ReturnValue,
 | |
|                     SourceDataSize,
 | |
|                     Type
 | |
|                     );
 | |
|         }
 | |
| 
 | |
|         if (EFI_ERROR (Status)) {
 | |
|           IsError = TRUE;
 | |
|           goto Done;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       Size += ReturnValue;
 | |
| 
 | |
|     } else if (strcmpi (Buffer, "Tool") == 0) {
 | |
| 
 | |
|       ZeroMem (ToolName, _MAX_PATH);
 | |
|       ZeroMem (ToolArgumentsArray, sizeof (CHAR8 *) * MAX_ARRAY_SIZE);
 | |
|       ZeroMem (&SignGuid, sizeof (EFI_GUID));
 | |
| 
 | |
|       //
 | |
|       // handle signing Tool
 | |
|       //
 | |
|       while (Buffer[0] != '(') {
 | |
|         if (GetNextLine (Buffer, Package, &LineNumber) != -1) {
 | |
|           CheckSlash (Buffer, Package, &LineNumber);
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       if (strcmpi (Buffer, "(") == 0) {
 | |
|         if (GetNextLine (Buffer, Package, &LineNumber) != -1) {
 | |
|           CheckSlash (Buffer, Package, &LineNumber);
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       StripParens (Buffer);
 | |
| 
 | |
|       if (Buffer[0] == '$') {
 | |
|         Index = ProcessEnvironmentVariable (&Buffer[0], ToolName);
 | |
|         //
 | |
|         // if there is string after the environment variable, cat it.
 | |
|         //
 | |
|         if ((UINT32) Index < strlen (Buffer)) {
 | |
|           strcat (ToolName, &Buffer[Index]);
 | |
|         }
 | |
|       } else {
 | |
|         strcpy (ToolName, Buffer);
 | |
|       }
 | |
| 
 | |
|       ToolArgumentsArray[0] = ToolName;
 | |
| 
 | |
|       //
 | |
|       // read ARGS
 | |
|       //
 | |
|       if (GetToolArguments (
 | |
|             ToolArgumentsArray,
 | |
|             Package,
 | |
|             &InputFileName,
 | |
|             &OutputFileName,
 | |
|             &SignGuid,
 | |
|             &GuidedSectionAttributes
 | |
|             ) == -1) {
 | |
|         IsError = TRUE;
 | |
|         goto Done;
 | |
|       }
 | |
|       //
 | |
|       // if the tool need input file,
 | |
|       // dump the file buffer to the specified input file.
 | |
|       //
 | |
|       if (InputFileName != NULL) {
 | |
|         InputFile = fopen (InputFileName, "wb");
 | |
|         if (InputFile == NULL) {
 | |
|           Error (NULL, 0, 0, InputFileName, "failed to open output file for writing");
 | |
|           IsError = TRUE;
 | |
|           goto Done;
 | |
|         }
 | |
| 
 | |
|         fwrite (FileBuffer, sizeof (UINT8), Size, InputFile);
 | |
|         fclose (InputFile);
 | |
|         InputFile = NULL;
 | |
|         free (InputFileName);
 | |
|         InputFileName = NULL;
 | |
|       }
 | |
|       //
 | |
|       // dispatch signing tool
 | |
|       //
 | |
| #ifdef __GNUC__
 | |
|       {
 | |
|         char CommandLine[1000];
 | |
|         sprintf(CommandLine, "%s %s", ToolName, ToolArgumentsArray);
 | |
|         returnint = system(CommandLine);
 | |
|       }
 | |
| #else
 | |
|       returnint = _spawnv (_P_WAIT, ToolName, ToolArgumentsArray);
 | |
| #endif
 | |
|       if (returnint != 0) {
 | |
|         Error (NULL, 0, 0, ToolName, "external tool failed");
 | |
|         IsError = TRUE;
 | |
|         goto Done;
 | |
|       }
 | |
|       //
 | |
|       // if the tool has output file,
 | |
|       // dump the output file to the file buffer
 | |
|       //
 | |
|       if (OutputFileName != NULL) {
 | |
| 
 | |
|         OutputFile = fopen (OutputFileName, "rb");
 | |
|         if (OutputFile == NULL) {
 | |
|           Error (NULL, 0, 0, OutputFileName, "failed to open output file for writing");
 | |
|           IsError = TRUE;
 | |
|           goto Done;
 | |
|         }
 | |
| 
 | |
|         TargetFileBuffer  = &FileBuffer[Size];
 | |
|         SourceDataSize    = Size;
 | |
| 
 | |
|         fread (&Temp, sizeof (UINT8), 1, OutputFile);
 | |
|         while (!feof (OutputFile)) {
 | |
|           FileBuffer[Size++] = Temp;
 | |
|           fread (&Temp, sizeof (UINT8), 1, OutputFile);
 | |
|         }
 | |
| 
 | |
|         while ((Size & 0x03) != 0) {
 | |
|           FileBuffer[Size] = 0;
 | |
|           Size++;
 | |
|         }
 | |
| 
 | |
|         SourceDataSize = Size - SourceDataSize;
 | |
| 
 | |
|         fclose (OutputFile);
 | |
|         OutputFile = NULL;
 | |
|         free (OutputFileName);
 | |
|         OutputFileName = NULL;
 | |
| 
 | |
|         if (CompareGuid (&SignGuid, &mZeroGuid) != 0) {
 | |
|           ReturnValue = SourceDataSize;
 | |
|           Status = GenSimpleGuidSection (
 | |
|                     TargetFileBuffer,
 | |
|                     &ReturnValue,
 | |
|                     SourceDataSize,
 | |
|                     SignGuid,
 | |
|                     GuidedSectionAttributes
 | |
|                     );
 | |
|           if (EFI_ERROR (Status)) {
 | |
|             IsError = TRUE;
 | |
|             goto Done;
 | |
|           }
 | |
| 
 | |
|           Size = ReturnValue;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|     } else if (Buffer[0] != '}') {
 | |
|       //
 | |
|       // if we are here, we should see either a file name,
 | |
|       // or a }.
 | |
|       //
 | |
|       Index3      = 0;
 | |
|       FileName[0] = 0;
 | |
|       //
 | |
|       // Prepend the build directory to the file name if the
 | |
|       // file name does not already contain a full path.
 | |
|       //
 | |
|       if (!isalpha (Buffer[0]) || (Buffer[1] != ':')) {
 | |
|         sprintf (FileName, "%s\\", BuildDirectory);
 | |
|       }
 | |
| 
 | |
|       while (Buffer[Index3] != '\n') {
 | |
|         if (Buffer[Index3] == '$') {
 | |
|           Index3 += ProcessEnvironmentVariable (&Buffer[Index3], NewBuffer);
 | |
|           strcat (FileName, NewBuffer);
 | |
|         }
 | |
| 
 | |
|         if (Buffer[Index3] == 0) {
 | |
|           break;
 | |
|         } else {
 | |
|           Index2              = strlen (FileName);
 | |
|           FileName[Index2++]  = Buffer[Index3++];
 | |
|           FileName[Index2]    = 0;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       InFile = fopen (FileName, "rb");
 | |
|       if (InFile == NULL) {
 | |
|         Error (NULL, 0, 0, FileName, "failed to open file for reading");
 | |
|         IsError = TRUE;
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       fread (&ByteBuffer, sizeof (UINT8), 1, InFile);
 | |
|       while (!feof (InFile)) {
 | |
|         FileBuffer[Size++] = ByteBuffer;
 | |
|         fread (&ByteBuffer, sizeof (UINT8), 1, InFile);
 | |
|       }
 | |
| 
 | |
|       fclose (InFile);
 | |
|       InFile = NULL;
 | |
| 
 | |
|       //
 | |
|       // Make sure section ends on a DWORD boundary
 | |
|       //
 | |
|       while ((Size & 0x03) != 0) {
 | |
|         FileBuffer[Size] = 0;
 | |
|         Size++;
 | |
|       }
 | |
| 
 | |
|     }
 | |
|   }
 | |
| 
 | |
| Done:
 | |
|   for (Index3 = 1; Index3 < MAX_ARRAY_SIZE; Index3++) {
 | |
|     if (ToolArgumentsArray[Index3] == NULL) {
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     free (ToolArgumentsArray[Index3]);
 | |
|   }
 | |
| 
 | |
|   if (IsError) {
 | |
|     return -1;
 | |
|   }
 | |
| 
 | |
|   return Size;
 | |
| 
 | |
| }
 | |
| 
 | |
| static
 | |
| UINT8
 | |
| StringToType (
 | |
|   IN CHAR8 *String
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Converts File Type String to value.  EFI_FV_FILETYPE_ALL indicates that an
 | |
|   unrecognized file type was specified.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   String    - File type string
 | |
| 
 | |
| Returns:
 | |
| 
 | |
|   File Type Value
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   if (strcmpi (String, "EFI_FV_FILETYPE_RAW") == 0) {
 | |
|     return EFI_FV_FILETYPE_RAW;
 | |
|   }
 | |
| 
 | |
|   if (strcmpi (String, "EFI_FV_FILETYPE_FREEFORM") == 0) {
 | |
|     return EFI_FV_FILETYPE_FREEFORM;
 | |
|   }
 | |
| 
 | |
|   if (strcmpi (String, "EFI_FV_FILETYPE_SECURITY_CORE") == 0) {
 | |
|     return EFI_FV_FILETYPE_SECURITY_CORE;
 | |
|   }
 | |
| 
 | |
|   if (strcmpi (String, "EFI_FV_FILETYPE_PEI_CORE") == 0) {
 | |
|     return EFI_FV_FILETYPE_PEI_CORE;
 | |
|   }
 | |
| 
 | |
|   if (strcmpi (String, "EFI_FV_FILETYPE_DXE_CORE") == 0) {
 | |
|     return EFI_FV_FILETYPE_DXE_CORE;
 | |
|   }
 | |
| 
 | |
|   if (strcmpi (String, "EFI_FV_FILETYPE_PEIM") == 0) {
 | |
|     return EFI_FV_FILETYPE_PEIM;
 | |
|   }
 | |
| 
 | |
|   if (strcmpi (String, "EFI_FV_FILETYPE_DRIVER") == 0) {
 | |
|     return EFI_FV_FILETYPE_DRIVER;
 | |
|   }
 | |
| 
 | |
|   if (strcmpi (String, "EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER") == 0) {
 | |
|     return EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER;
 | |
|   }
 | |
| 
 | |
|   if (strcmpi (String, "EFI_FV_FILETYPE_APPLICATION") == 0) {
 | |
|     return EFI_FV_FILETYPE_APPLICATION;
 | |
|   }
 | |
| 
 | |
|   if (strcmpi (String, "EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE") == 0) {
 | |
|     return EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE;
 | |
|   }
 | |
| 
 | |
|   return EFI_FV_FILETYPE_ALL;
 | |
| }
 | |
| 
 | |
| static
 | |
| UINT32
 | |
| AdjustFileSize (
 | |
|   IN UINT8  *FileBuffer,
 | |
|   IN UINT32 FileSize
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Adjusts file size to insure sectioned file is exactly the right length such
 | |
|   that it ends on exactly the last byte of the last section.  ProcessScript()
 | |
|   may have padded beyond the end of the last section out to a 4 byte boundary.
 | |
|   This padding is stripped.
 | |
| 
 | |
| Arguments:
 | |
|   FileBuffer  - Data Buffer - contains a section stream
 | |
|   FileSize    - Size of FileBuffer as returned from ProcessScript()
 | |
| 
 | |
| Returns:
 | |
|   Corrected size of file.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   UINT32                    TotalLength;
 | |
|   UINT32                    CurrentLength;
 | |
|   UINT32                    SectionLength;
 | |
|   UINT32                    SectionStreamLength;
 | |
|   EFI_COMMON_SECTION_HEADER *SectionHeader;
 | |
|   EFI_COMMON_SECTION_HEADER *NextSectionHeader;
 | |
| 
 | |
|   TotalLength         = 0;
 | |
|   CurrentLength       = 0;
 | |
|   SectionStreamLength = FileSize;
 | |
| 
 | |
|   SectionHeader       = (EFI_COMMON_SECTION_HEADER *) FileBuffer;
 | |
| 
 | |
|   while (TotalLength < SectionStreamLength) {
 | |
|     SectionLength = *((UINT32 *) SectionHeader->Size) & 0x00ffffff;
 | |
|     TotalLength += SectionLength;
 | |
| 
 | |
|     if (TotalLength == SectionStreamLength) {
 | |
|       return TotalLength;
 | |
|     }
 | |
|     //
 | |
|     // Move to the next byte following the section...
 | |
|     //
 | |
|     SectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) SectionHeader + SectionLength);
 | |
|     CurrentLength = (UINTN) SectionHeader - (UINTN) FileBuffer;
 | |
| 
 | |
|     //
 | |
|     // Figure out where the next section begins
 | |
|     //
 | |
|     NextSectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) SectionHeader + 3);
 | |
|     NextSectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINTN) NextSectionHeader &~ (UINTN) 3);
 | |
|     TotalLength += (UINTN) NextSectionHeader - (UINTN) SectionHeader;
 | |
|     SectionHeader = NextSectionHeader;
 | |
|   }
 | |
| 
 | |
|   return CurrentLength;
 | |
| }
 | |
| 
 | |
| static
 | |
| INT32
 | |
| MainEntry (
 | |
|   INT32     argc,
 | |
|   CHAR8     *argv[],
 | |
|   BOOLEAN   ForceUncompress
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   MainEntry function.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   argc            - Number of command line parameters.
 | |
|   argv            - Array of pointers to command line parameter strings.
 | |
|   ForceUncompress - If TRUE, force to do not compress the sections even if compression
 | |
|                     is specified in the script. Otherwise, FALSE.
 | |
| 
 | |
| Returns:
 | |
|   STATUS_SUCCESS  - Function exits successfully.
 | |
|   STATUS_ERROR    - Some error occurred during execution.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   FILE                    *PrimaryPackage;
 | |
|   FILE                    *OverridePackage;
 | |
|   FILE                    *Out;
 | |
|   CHAR8                   BaseName[_MAX_PATH];
 | |
|   EFI_GUID                FfsGuid;
 | |
|   CHAR8                   GuidString[_MAX_PATH];
 | |
|   EFI_FFS_FILE_HEADER     FileHeader;
 | |
|   CHAR8                   FileType[_MAX_PATH];
 | |
|   EFI_FFS_FILE_ATTRIBUTES FfsAttrib;
 | |
|   EFI_FFS_FILE_ATTRIBUTES FfsAttribDefined;
 | |
|   UINT64                  FfsAlignment;
 | |
|   UINT32                  FfsAlignment32;
 | |
|   CHAR8                   InputString[_MAX_PATH];
 | |
|   BOOLEAN                 ImageScriptInOveride;
 | |
|   UINT32                  FileSize;
 | |
|   UINT8                   *FileBuffer;
 | |
|   EFI_STATUS              Status;
 | |
|   UINT32                  LineNumber;
 | |
|   EFI_FFS_FILE_TAIL       TailValue;
 | |
| 
 | |
|   BaseName[0]       = 0;
 | |
|   FileType[0]       = 0;
 | |
|   FfsAttrib         = 0;
 | |
|   FfsAttribDefined  = 0;
 | |
|   FfsAlignment      = 0;
 | |
|   FfsAlignment32    = 0;
 | |
|   PrimaryPackage    = NULL;
 | |
|   Out               = NULL;
 | |
|   OverridePackage   = NULL;
 | |
|   FileBuffer        = NULL;
 | |
| 
 | |
|   strcpy (GuidString, "00000000-0000-0000-0000-000000000000");
 | |
|   Status = StringToGuid (GuidString, &FfsGuid);
 | |
|   if (Status != 0) {
 | |
|     Error (NULL, 0, 0, GuidString, "error parsing GUID string");
 | |
|     return STATUS_ERROR;
 | |
|   }
 | |
| 
 | |
|   GuidString[0]         = 0;
 | |
|   ImageScriptInOveride  = FALSE;
 | |
|   //
 | |
|   // Initialize the simple file parsing routines. Then open
 | |
|   // the primary package file for parsing.
 | |
|   //
 | |
|   SFPInit ();
 | |
|   if (SFPOpenFile (mGlobals.PrimaryPackagePath) != STATUS_SUCCESS) {
 | |
|     Error (NULL, 0, 0, mGlobals.PrimaryPackagePath, "unable to open primary package file");
 | |
|     goto Done;
 | |
|   }
 | |
|   //
 | |
|   // First token in the file must be "PACKAGE.INF"
 | |
|   //
 | |
|   if (!SFPIsToken ("PACKAGE.INF")) {
 | |
|     Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'PACKAGE.INF'", NULL);
 | |
|     goto Done;
 | |
|   }
 | |
|   //
 | |
|   // Find the [.] section
 | |
|   //
 | |
|   if (!SFPSkipToToken ("[.]")) {
 | |
|     Error (mGlobals.PrimaryPackagePath, 1, 0, "could not locate [.] section in package file", NULL);
 | |
|     goto Done;
 | |
|   }
 | |
|   //
 | |
|   // Start parsing the data. The algorithm is essentially the same for each keyword:
 | |
|   //   1. Identify the keyword
 | |
|   //   2. Verify that the keyword/value pair has not already been defined
 | |
|   //   3. Set some flag indicating that the keyword/value pair has been defined
 | |
|   //   4. Skip over the "="
 | |
|   //   5. Get the value, which may be a number, TRUE, FALSE, or a string.
 | |
|   //
 | |
|   while (1) {
 | |
|     if (SFPIsToken ("BASE_NAME")) {
 | |
|       //
 | |
|       // Found BASE_NAME, format:
 | |
|       //   BASE_NAME = MyBaseName
 | |
|       //
 | |
|       if (BaseName[0] != 0) {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "BASE_NAME already defined", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       if (!SFPIsToken ("=")) {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       if (!SFPGetNextToken (BaseName, sizeof (BaseName))) {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected valid base name", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
|     } else if (SFPIsToken ("IMAGE_SCRIPT")) {
 | |
|       //
 | |
|       // Found IMAGE_SCRIPT. Break out and process below.
 | |
|       //
 | |
|       break;
 | |
|     } else if (SFPIsToken ("FFS_FILEGUID")) {
 | |
|       //
 | |
|       // found FILEGUID, format:
 | |
|       //   FFS_FILEGUID = F7845C4F-EDF5-42C5-BD8F-A02AF63DD93A
 | |
|       //
 | |
|       if (GuidString[0] != 0) {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_FILEGUID already defined", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       if (!SFPIsToken ("=")) {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       if (SFPGetGuidToken (GuidString, sizeof (GuidString)) != TRUE) {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected file GUID", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       Status = StringToGuid (GuidString, &FfsGuid);
 | |
|       if (Status != 0) {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected valid file GUID", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
|     } else if (SFPIsToken ("FFS_FILETYPE")) {
 | |
|       //
 | |
|       // ***********************************************************************
 | |
|       //
 | |
|       // Found FFS_FILETYPE, format:
 | |
|       //  FFS_FILETYPE = EFI_FV_FILETYPE_APPLICATION
 | |
|       //
 | |
|       if (FileType[0] != 0) {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_FILETYPE previously defined", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       if (!SFPIsToken ("=")) {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       if (!SFPGetNextToken (FileType, sizeof (FileType))) {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected valid FFS_FILETYPE", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
|     } else if (SFPIsToken ("FFS_ATTRIB_HEADER_EXTENSION")) {
 | |
|       //
 | |
|       // ***********************************************************************
 | |
|       //
 | |
|       // Found: FFS_ATTRIB_HEADER_EXTENSION = FALSE
 | |
|       // Spec says the bit is for future expansion, and must be false.
 | |
|       //
 | |
|       if (FfsAttribDefined & FFS_ATTRIB_HEADER_EXTENSION) {
 | |
|         Error (
 | |
|           mGlobals.PrimaryPackagePath,
 | |
|           SFPGetLineNumber (),
 | |
|           0,
 | |
|           "FFS_ATTRIB_HEADER_EXTENSION previously defined",
 | |
|           NULL
 | |
|           );
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       FfsAttribDefined |= FFS_ATTRIB_HEADER_EXTENSION;
 | |
|       if (!SFPIsToken ("=")) {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       if (SFPIsToken ("TRUE")) {
 | |
|         Error (
 | |
|           mGlobals.PrimaryPackagePath,
 | |
|           SFPGetLineNumber (),
 | |
|           0,
 | |
|           "only FFS_ATTRIB_HEADER_EXTENSION = FALSE is supported",
 | |
|           NULL
 | |
|           );
 | |
|         goto Done;
 | |
|       } else if (SFPIsToken ("FALSE")) {
 | |
|         //
 | |
|         // Default is FALSE
 | |
|         //
 | |
|       } else {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'FALSE'", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
|     } else if (SFPIsToken ("FFS_ATTRIB_TAIL_PRESENT")) {
 | |
|       //
 | |
|       // ***********************************************************************
 | |
|       //
 | |
|       // Found: FFS_ATTRIB_TAIL_PRESENT = TRUE | FALSE
 | |
|       //
 | |
|       if (FfsAttribDefined & FFS_ATTRIB_TAIL_PRESENT) {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_TAIL_PRESENT previously defined", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       FfsAttribDefined |= FFS_ATTRIB_TAIL_PRESENT;
 | |
|       if (!SFPIsToken ("=")) {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       if (SFPIsToken ("TRUE")) {
 | |
|         FfsAttrib |= FFS_ATTRIB_TAIL_PRESENT;
 | |
|       } else if (SFPIsToken ("FALSE")) {
 | |
|         //
 | |
|         // Default is FALSE
 | |
|         //
 | |
|       } else {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
|     } else if (SFPIsToken ("FFS_ATTRIB_RECOVERY")) {
 | |
|       //
 | |
|       // ***********************************************************************
 | |
|       //
 | |
|       // Found: FFS_ATTRIB_RECOVERY = TRUE | FALSE
 | |
|       //
 | |
|       if (FfsAttribDefined & FFS_ATTRIB_RECOVERY) {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_RECOVERY previously defined", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       FfsAttribDefined |= FFS_ATTRIB_RECOVERY;
 | |
|       if (!SFPIsToken ("=")) {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       if (SFPIsToken ("TRUE")) {
 | |
|         FfsAttrib |= FFS_ATTRIB_RECOVERY;
 | |
|       } else if (SFPIsToken ("FALSE")) {
 | |
|         //
 | |
|         // Default is FALSE
 | |
|         //
 | |
|       } else {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
|     } else if (SFPIsToken ("FFS_ATTRIB_CHECKSUM")) {
 | |
|       //
 | |
|       // ***********************************************************************
 | |
|       //
 | |
|       // Found: FFS_ATTRIB_CHECKSUM = TRUE | FALSE
 | |
|       //
 | |
|       if (FfsAttribDefined & FFS_ATTRIB_CHECKSUM) {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_CHECKSUM previously defined", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       FfsAttribDefined |= FFS_ATTRIB_CHECKSUM;
 | |
|       if (!SFPIsToken ("=")) {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       if (SFPIsToken ("TRUE")) {
 | |
|         FfsAttrib |= FFS_ATTRIB_CHECKSUM;
 | |
|       } else if (SFPIsToken ("FALSE")) {
 | |
|         //
 | |
|         // Default is FALSE
 | |
|         //
 | |
|       } else {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
|     } else if (SFPIsToken ("FFS_ALIGNMENT") || SFPIsToken ("FFS_ATTRIB_DATA_ALIGNMENT")) {
 | |
|       //
 | |
|       // ***********************************************************************
 | |
|       //
 | |
|       // Found FFS_ALIGNMENT, formats:
 | |
|       //   FFS_ALIGNMENT = 0-7
 | |
|       //   FFS_ATTRIB_DATA_ALIGNMENT = 0-7
 | |
|       //
 | |
|       if (FfsAttribDefined & FFS_ATTRIB_DATA_ALIGNMENT) {
 | |
|         Error (
 | |
|           mGlobals.PrimaryPackagePath,
 | |
|           SFPGetLineNumber (),
 | |
|           0,
 | |
|           "FFS_ALIGNMENT/FFS_ATTRIB_DATA_ALIGNMENT previously defined",
 | |
|           NULL
 | |
|           );
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       FfsAttribDefined |= FFS_ATTRIB_DATA_ALIGNMENT;
 | |
|       if (!SFPIsToken ("=")) {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       if (!SFPGetNumber (&FfsAlignment32)) {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected numeric value for alignment", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       if (FfsAlignment32 > 7) {
 | |
|         Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 0 <= alignment <= 7", NULL);
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       FfsAttrib |= (((EFI_FFS_FILE_ATTRIBUTES) FfsAlignment32) << 3);
 | |
|     } else {
 | |
|       SFPGetNextToken (InputString, sizeof (InputString));
 | |
|       Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, InputString, "unrecognized/unexpected token");
 | |
|       goto Done;
 | |
|     }
 | |
|   }
 | |
|   //
 | |
|   // Close the primary package file
 | |
|   //
 | |
|   SFPCloseFile ();
 | |
|   //
 | |
|   // TODO: replace code below with basically a copy of the code above. Don't
 | |
|   // forget to reset the FfsAttribDefined variable first. Also, you'll need
 | |
|   // to somehow keep track of whether or not the basename is defined multiple
 | |
|   // times in the override package. Ditto on the file GUID.
 | |
|   //
 | |
|   if (mGlobals.OverridePackagePath[0] != 0) {
 | |
|     OverridePackage = fopen (mGlobals.OverridePackagePath, "r");
 | |
|     //
 | |
|     // NOTE: For package override to work correctly, the code below must be modified to
 | |
|     //       SET or CLEAR bits properly. For example, if the primary package set
 | |
|     //       FFS_ATTRIB_CHECKSUM = TRUE, and the override set FFS_ATTRIB_CHECKSUM = FALSE, then
 | |
|     //       we'd need to clear the bit below. Since this is not happening, I'm guessing that
 | |
|     //       the override functionality is not being used, so should be made obsolete. If I'm
 | |
|     //       wrong, and it is being used, then it needs to be fixed. Thus emit an error if it is
 | |
|     //       used, and we'll address it then.  4/10/2003
 | |
|     //
 | |
|     Error (__FILE__, __LINE__, 0, "package override functionality is not implemented correctly", NULL);
 | |
|     goto Done;
 | |
|   } else {
 | |
|     OverridePackage = NULL;
 | |
|   }
 | |
| 
 | |
| #ifdef OVERRIDE_SUPPORTED
 | |
|   if (OverridePackage != NULL) {
 | |
|     //
 | |
|     // Parse override package file
 | |
|     //
 | |
|     fscanf (OverridePackage, "%s", &InputString);
 | |
|     if (strcmpi (InputString, "PACKAGE.INF") != 0) {
 | |
|       Error (mGlobals.OverridePackagePath, 1, 0, "invalid package file", "expected 'PACKAGE.INF'");
 | |
|       goto Done;
 | |
|     }
 | |
|     //
 | |
|     // Match [dir] to Build Directory
 | |
|     //
 | |
|     if (FindSectionInPackage (mGlobals.BuildDirectory, OverridePackage, &LineNumber) != 0) {
 | |
|       Error (mGlobals.OverridePackagePath, 1, 0, mGlobals.BuildDirectory, "section not found in package file");
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     InputString[0] = 0;
 | |
|     while ((InputString[0] != '[') && (!feof (OverridePackage))) {
 | |
|       if (GetNextLine (InputString, OverridePackage, &LineNumber) != -1) {
 | |
|         if (InputString[0] != '[') {
 | |
| here:
 | |
|           if (strcmpi (InputString, "BASE_NAME") == 0) {
 | |
|             //
 | |
|             // found BASE_NAME, next is = and string.
 | |
|             //
 | |
|             fscanf (OverridePackage, "%s", &InputString);
 | |
|             CheckSlash (InputString, OverridePackage, &LineNumber);
 | |
|             if (strlen (InputString) == 1) {
 | |
|               //
 | |
|               // string is just =
 | |
|               //
 | |
|               fscanf (OverridePackage, "%s", &InputString);
 | |
|               CheckSlash (InputString, OverridePackage, &LineNumber);
 | |
|               strcpy (BaseName, InputString);
 | |
|             } else {
 | |
|               BreakString (InputString, InputString, 1);
 | |
|               strcpy (BaseName, InputString);
 | |
|             }
 | |
|           } else if (strcmpi (InputString, "IMAGE_SCRIPT") == 0) {
 | |
|             //
 | |
|             // found IMAGE_SCRIPT, come back later to process it
 | |
|             //
 | |
|             ImageScriptInOveride = TRUE;
 | |
|             fscanf (OverridePackage, "%s", &InputString);
 | |
|           } else if (strcmpi (InputString, "FFS_FILEGUID") == 0) {
 | |
|             //
 | |
|             // found FILEGUID, next is = and string.
 | |
|             //
 | |
|             fscanf (OverridePackage, "%s", &InputString);
 | |
|             CheckSlash (InputString, OverridePackage, &LineNumber);
 | |
|             if (strlen (InputString) == 1) {
 | |
|               //
 | |
|               // string is just =
 | |
|               //
 | |
|               fscanf (OverridePackage, "%s", &InputString);
 | |
|               CheckSlash (InputString, OverridePackage, &LineNumber);
 | |
|               Status = StringToGuid (InputString, &FfsGuid);
 | |
|               if (Status != 0) {
 | |
|                 Error (mGlobals.OverridePackagePath, 1, 0, InputString, "bad FFS_FILEGUID format");
 | |
|                 goto Done;
 | |
|               }
 | |
|             } else {
 | |
|               BreakString (InputString, InputString, 1);
 | |
|               Status = StringToGuid (InputString, &FfsGuid);
 | |
|               if (Status != 0) {
 | |
|                 Error (mGlobals.OverridePackagePath, 1, 0, InputString, "bad FFS_FILEGUID format");
 | |
|                 goto Done;
 | |
|               }
 | |
|             }
 | |
|           } else if (strcmpi (InputString, "FFS_FILETYPE") == 0) {
 | |
|             //
 | |
|             // found FILETYPE, next is = and string.
 | |
|             //
 | |
|             fscanf (OverridePackage, "%s", &InputString);
 | |
|             CheckSlash (InputString, OverridePackage, &LineNumber);
 | |
|             if (strlen (InputString) == 1) {
 | |
|               //
 | |
|               // string is just =
 | |
|               //
 | |
|               fscanf (OverridePackage, "%s", &InputString);
 | |
|               CheckSlash (InputString, OverridePackage, &LineNumber);
 | |
|               strcpy (FileType, InputString);
 | |
|             } else {
 | |
|               BreakString (InputString, InputString, 1);
 | |
|               strcpy (FileType, InputString);
 | |
|             }
 | |
| 
 | |
|           } else if (strcmpi (InputString, "FFS_ATTRIB_RECOVERY") == 0) {
 | |
|             //
 | |
|             // found FFS_ATTRIB_RECOVERY, next is = and string.
 | |
|             //
 | |
|             fscanf (OverridePackage, "%s", &InputString);
 | |
|             CheckSlash (InputString, OverridePackage, &LineNumber);
 | |
|             if (strlen (InputString) == 1) {
 | |
|               //
 | |
|               // string is just =
 | |
|               //
 | |
|               fscanf (OverridePackage, "%s", &InputString);
 | |
|               CheckSlash (InputString, OverridePackage, &LineNumber);
 | |
|               if (strcmpi (InputString, "TRUE") == 0) {
 | |
|                 FfsAttrib |= FFS_ATTRIB_RECOVERY;
 | |
|               }
 | |
|             } else {
 | |
|               BreakString (InputString, InputString, 1);
 | |
|               if (strcmpi (InputString, "TRUE") == 0) {
 | |
|                 FfsAttrib |= FFS_ATTRIB_RECOVERY;
 | |
|               }
 | |
|             }
 | |
|           } else if (strcmpi (InputString, "FFS_ATTRIB_CHECKSUM") == 0) {
 | |
|             //
 | |
|             // found FFS_ATTRIB_CHECKSUM, next is = and string.
 | |
|             //
 | |
|             fscanf (OverridePackage, "%s", &InputString);
 | |
|             CheckSlash (InputString, OverridePackage, &LineNumber);
 | |
|             if (strlen (InputString) == 1) {
 | |
|               //
 | |
|               // string is just =
 | |
|               //
 | |
|               fscanf (OverridePackage, "%s", &InputString);
 | |
|               CheckSlash (InputString, OverridePackage, &LineNumber);
 | |
|               if (strcmpi (InputString, "TRUE") == 0) {
 | |
|                 FfsAttrib |= FFS_ATTRIB_CHECKSUM;
 | |
|               }
 | |
|             } else {
 | |
|               BreakString (InputString, InputString, 1);
 | |
|               if (strcmpi (InputString, "TRUE") == 0) {
 | |
|                 FfsAttrib |= FFS_ATTRIB_CHECKSUM;
 | |
|               }
 | |
|             }
 | |
|           } else if (strcmpi (InputString, "FFS_ALIGNMENT") == 0) {
 | |
|             //
 | |
|             // found FFS_ALIGNMENT, next is = and string.
 | |
|             //
 | |
|             fscanf (OverridePackage, "%s", &InputString);
 | |
|             CheckSlash (InputString, OverridePackage, &LineNumber);
 | |
|             if (strlen (InputString) == 1) {
 | |
|               //
 | |
|               // string is just =
 | |
|               //
 | |
|               fscanf (OverridePackage, "%s", &InputString);
 | |
|               CheckSlash (InputString, OverridePackage, &LineNumber);
 | |
|             } else {
 | |
|               BreakString (InputString, InputString, 1);
 | |
|             }
 | |
| 
 | |
|             AsciiStringToUint64 (InputString, FALSE, &FfsAlignment);
 | |
|             if (FfsAlignment > 7) {
 | |
|               Error (mGlobals.OverridePackagePath, 1, 0, InputString, "invalid FFS_ALIGNMENT value");
 | |
|               goto Done;
 | |
|             }
 | |
| 
 | |
|             FfsAttrib |= (((EFI_FFS_FILE_ATTRIBUTES) FfsAlignment) << 3);
 | |
|           } else if (strchr (InputString, '=') != NULL) {
 | |
|             BreakString (InputString, String, 1);
 | |
|             fseek (OverridePackage, (-1 * (strlen (String) + 1)), SEEK_CUR);
 | |
|             BreakString (InputString, InputString, 0);
 | |
|             goto here;
 | |
|           }
 | |
|         }
 | |
|       }
 | |
|     }
 | |
|   }
 | |
| #endif // #ifdef OVERRIDE_SUPPORTED
 | |
|   //
 | |
|   // Require that they specified a file GUID at least, since that's how we're
 | |
|   // naming the file.
 | |
|   //
 | |
|   if (GuidString[0] == 0) {
 | |
|     Error (mGlobals.PrimaryPackagePath, 1, 0, "FFS_FILEGUID must be specified", NULL);
 | |
|     return STATUS_ERROR;
 | |
|   }
 | |
|   //
 | |
|   // Build Header and process image script
 | |
|   //
 | |
|   FileBuffer = (UINT8 *) malloc ((1024 * 1024 * 16) * sizeof (UINT8));
 | |
|   if (FileBuffer == NULL) {
 | |
|     Error (__FILE__, __LINE__, 0, "memory allocation failed", NULL);
 | |
|     goto Done;
 | |
|   }
 | |
| 
 | |
|   FileSize = 0;
 | |
|   if (ImageScriptInOveride) {
 | |
| #ifdef OVERRIDE_SUPORTED
 | |
|     rewind (OverridePackage);
 | |
|     LineNumber = 0;
 | |
|     FindSectionInPackage (mGlobals.BuildDirectory, OverridePackage, &LineNumber);
 | |
|     while (strcmpi (InputString, "IMAGE_SCRIPT") != 0) {
 | |
|       GetNextLine (InputString, OverridePackage, &LineNumber);
 | |
|       CheckSlash (InputString, OverridePackage, &LineNumber);
 | |
|       if (strchr (InputString, '=') != NULL) {
 | |
|         BreakString (InputString, InputString, 0);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     while (InputString[0] != '{') {
 | |
|       GetNextLine (InputString, OverridePackage, &LineNumber);
 | |
|       CheckSlash (InputString, OverridePackage, &LineNumber);
 | |
|     }
 | |
|     //
 | |
|     // Found start of image script, process it
 | |
|     //
 | |
|     FileSize += ProcessScript (FileBuffer, OverridePackage, mGlobals.BuildDirectory, ForceUncompress);
 | |
|     if (FileSize == -1) {
 | |
|       return -1;
 | |
|     }
 | |
| 
 | |
|     if (StringToType (FileType) != EFI_FV_FILETYPE_RAW) {
 | |
|       FileSize = AdjustFileSize (FileBuffer, FileSize);
 | |
|     }
 | |
| 
 | |
|     if (BaseName[0] == '\"') {
 | |
|       StripQuotes (BaseName);
 | |
|     }
 | |
| 
 | |
|     if (BaseName[0] != 0) {
 | |
|       sprintf (InputString, "%s-%s", GuidString, BaseName);
 | |
|     } else {
 | |
|       strcpy (InputString, GuidString);
 | |
|     }
 | |
| 
 | |
|     switch (StringToType (FileType)) {
 | |
| 
 | |
|     case EFI_FV_FILETYPE_SECURITY_CORE:
 | |
|       strcat (InputString, ".SEC");
 | |
|       break;
 | |
| 
 | |
|     case EFI_FV_FILETYPE_PEIM:
 | |
|     case EFI_FV_FILETYPE_PEI_CORE:
 | |
|     case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
 | |
|       strcat (InputString, ".PEI");
 | |
|       break;
 | |
| 
 | |
|     case EFI_FV_FILETYPE_DRIVER:
 | |
|     case EFI_FV_FILETYPE_DXE_CORE:
 | |
|       strcat (InputString, ".DXE");
 | |
|       break;
 | |
| 
 | |
|     case EFI_FV_FILETYPE_APPLICATION:
 | |
|       strcat (InputString, ".APP");
 | |
|       break;
 | |
| 
 | |
|     case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE:
 | |
|       strcat (InputString, ".FVI");
 | |
|       break;
 | |
| 
 | |
|     case EFI_FV_FILETYPE_ALL:
 | |
|       Error (mGlobals.OverridePackagePath, 1, 0, "invalid FFS file type for this utility", NULL);
 | |
|       goto Done;
 | |
| 
 | |
|     default:
 | |
|       strcat (InputString, ".FFS");
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     if (ForceUncompress) {
 | |
|       strcat (InputString, ".ORG");
 | |
|     }
 | |
| 
 | |
|     Out = fopen (InputString, "wb");
 | |
|     if (Out == NULL) {
 | |
|       Error (NULL, 0, 0, InputString, "could not open output file for writing");
 | |
|       goto Done;
 | |
|     }
 | |
|     //
 | |
|     // create ffs header
 | |
|     //
 | |
|     memset (&FileHeader, 0, sizeof (EFI_FFS_FILE_HEADER));
 | |
|     memcpy (&FileHeader.Name, &FfsGuid, sizeof (EFI_GUID));
 | |
|     FileHeader.Type       = StringToType (FileType);
 | |
|     FileHeader.Attributes = FfsAttrib;
 | |
|     //
 | |
|     // Now FileSize includes the EFI_FFS_FILE_HEADER
 | |
|     //
 | |
|     FileSize += sizeof (EFI_FFS_FILE_HEADER);
 | |
|     FileHeader.Size[0]  = (UINT8) (FileSize & 0xFF);
 | |
|     FileHeader.Size[1]  = (UINT8) ((FileSize & 0xFF00) >> 8);
 | |
|     FileHeader.Size[2]  = (UINT8) ((FileSize & 0xFF0000) >> 16);
 | |
|     //
 | |
|     // Fill in checksums and state, these must be zero for checksumming
 | |
|     //
 | |
|     // FileHeader.IntegrityCheck.Checksum.Header = 0;
 | |
|     // FileHeader.IntegrityCheck.Checksum.File = 0;
 | |
|     // FileHeader.State = 0;
 | |
|     //
 | |
|     FileHeader.IntegrityCheck.Checksum.Header = CalculateChecksum8 (
 | |
|                                                   (UINT8 *) &FileHeader,
 | |
|                                                   sizeof (EFI_FFS_FILE_HEADER)
 | |
|                                                   );
 | |
|     if (FileHeader.Attributes & FFS_ATTRIB_CHECKSUM) {
 | |
|       FileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 ((UINT8 *) &FileHeader, FileSize);
 | |
|     } else {
 | |
|       FileHeader.IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
 | |
|     }
 | |
| 
 | |
|     FileHeader.State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
 | |
|     //
 | |
|     // write header
 | |
|     //
 | |
|     if (fwrite (&FileHeader, sizeof (FileHeader), 1, Out) != 1) {
 | |
|       Error (NULL, 0, 0, "failed to write file header to output file", NULL);
 | |
|       goto Done;
 | |
|     }
 | |
|     //
 | |
|     // write data
 | |
|     //
 | |
|     if (fwrite (FileBuffer, FileSize - sizeof (EFI_FFS_FILE_HEADER), 1, Out) != 1) {
 | |
|       Error (NULL, 0, 0, "failed to write all bytes to output file", NULL);
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     fclose (Out);
 | |
|     Out = NULL;
 | |
| #endif // #ifdef OVERRIDE_SUPPORTED
 | |
|   } else {
 | |
|     //
 | |
|     // Open primary package file and process the IMAGE_SCRIPT section
 | |
|     //
 | |
|     PrimaryPackage = fopen (mGlobals.PrimaryPackagePath, "r");
 | |
|     if (PrimaryPackage == NULL) {
 | |
|       Error (NULL, 0, 0, mGlobals.PrimaryPackagePath, "unable to open primary package file");
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     LineNumber = 1;
 | |
|     FindSectionInPackage (".", PrimaryPackage, &LineNumber);
 | |
|     while (strcmpi (InputString, "IMAGE_SCRIPT") != 0) {
 | |
|       GetNextLine (InputString, PrimaryPackage, &LineNumber);
 | |
|       CheckSlash (InputString, PrimaryPackage, &LineNumber);
 | |
|       if (strchr (InputString, '=') != NULL) {
 | |
|         BreakString (InputString, InputString, 0);
 | |
|       }
 | |
|     }
 | |
| 
 | |
|     while (InputString[0] != '{') {
 | |
|       GetNextLine (InputString, PrimaryPackage, &LineNumber);
 | |
|       CheckSlash (InputString, PrimaryPackage, &LineNumber);
 | |
|     }
 | |
|     //
 | |
|     // Found start of image script, process it
 | |
|     //
 | |
|     FileSize += ProcessScript (FileBuffer, PrimaryPackage, mGlobals.BuildDirectory, ForceUncompress);
 | |
|     if (FileSize == -1) {
 | |
|       goto Done;
 | |
|     }
 | |
| 
 | |
|     if (StringToType (FileType) != EFI_FV_FILETYPE_RAW) {
 | |
|       FileSize = AdjustFileSize (FileBuffer, FileSize);
 | |
|     }
 | |
| 
 | |
|     if (BaseName[0] == '\"') {
 | |
|       StripQuotes (BaseName);
 | |
|     }
 | |
| 
 | |
|     if (BaseName[0] != 0) {
 | |
|       sprintf (InputString, "%s-%s", GuidString, BaseName);
 | |
|     } else {
 | |
|       strcpy (InputString, GuidString);
 | |
|     }
 | |
| 
 | |
|     switch (StringToType (FileType)) {
 | |
| 
 | |
|     case EFI_FV_FILETYPE_SECURITY_CORE:
 | |
|       strcat (InputString, ".SEC");
 | |
|       break;
 | |
| 
 | |
|     case EFI_FV_FILETYPE_PEIM:
 | |
|     case EFI_FV_FILETYPE_PEI_CORE:
 | |
|     case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
 | |
|       strcat (InputString, ".PEI");
 | |
|       break;
 | |
| 
 | |
|     case EFI_FV_FILETYPE_DRIVER:
 | |
|     case EFI_FV_FILETYPE_DXE_CORE:
 | |
|       strcat (InputString, ".DXE");
 | |
|       break;
 | |
| 
 | |
|     case EFI_FV_FILETYPE_APPLICATION:
 | |
|       strcat (InputString, ".APP");
 | |
|       break;
 | |
| 
 | |
|     case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE:
 | |
|       strcat (InputString, ".FVI");
 | |
|       break;
 | |
| 
 | |
|     case EFI_FV_FILETYPE_ALL:
 | |
|       Error (mGlobals.PrimaryPackagePath, 1, 0, "invalid FFS file type for this utility", NULL);
 | |
|       goto Done;
 | |
| 
 | |
|     default:
 | |
|       strcat (InputString, ".FFS");
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|     if (ForceUncompress) {
 | |
|       strcat (InputString, ".ORG");
 | |
|     }
 | |
| 
 | |
|     Out = fopen (InputString, "wb");
 | |
|     if (Out == NULL) {
 | |
|       Error (NULL, 0, 0, InputString, "failed to open output file for writing");
 | |
|       goto Done;
 | |
|     }
 | |
|     //
 | |
|     // Initialize the FFS file header
 | |
|     //
 | |
|     memset (&FileHeader, 0, sizeof (EFI_FFS_FILE_HEADER));
 | |
|     memcpy (&FileHeader.Name, &FfsGuid, sizeof (EFI_GUID));
 | |
|     FileHeader.Type       = StringToType (FileType);
 | |
|     FileHeader.Attributes = FfsAttrib;
 | |
|     //
 | |
|     // From this point on FileSize includes the size of the EFI_FFS_FILE_HEADER
 | |
|     //
 | |
|     FileSize += sizeof (EFI_FFS_FILE_HEADER);
 | |
|     //
 | |
|     // If using a tail, then it adds two bytes
 | |
|     //
 | |
|     if (FileHeader.Attributes & FFS_ATTRIB_TAIL_PRESENT) {
 | |
|       //
 | |
|       // Tail is not allowed for pad and 0-length files
 | |
|       //
 | |
|       if ((FileHeader.Type == EFI_FV_FILETYPE_FFS_PAD) || (FileSize == sizeof (EFI_FFS_FILE_HEADER))) {
 | |
|         Error (
 | |
|           mGlobals.PrimaryPackagePath,
 | |
|           1,
 | |
|           0,
 | |
|           "FFS_ATTRIB_TAIL_PRESENT=TRUE is invalid for PAD or 0-length files",
 | |
|           NULL
 | |
|           );
 | |
|         goto Done;
 | |
|       }
 | |
| 
 | |
|       FileSize += sizeof (EFI_FFS_FILE_TAIL);
 | |
|     }
 | |
| 
 | |
|     FileHeader.Size[0]  = (UINT8) (FileSize & 0xFF);
 | |
|     FileHeader.Size[1]  = (UINT8) ((FileSize & 0xFF00) >> 8);
 | |
|     FileHeader.Size[2]  = (UINT8) ((FileSize & 0xFF0000) >> 16);
 | |
|     //
 | |
|     // Fill in checksums and state, they must be 0 for checksumming.
 | |
|     //
 | |
|     // FileHeader.IntegrityCheck.Checksum.Header = 0;
 | |
|     // FileHeader.IntegrityCheck.Checksum.File = 0;
 | |
|     // FileHeader.State = 0;
 | |
|     //
 | |
|     FileHeader.IntegrityCheck.Checksum.Header = CalculateChecksum8 (
 | |
|                                                   (UINT8 *) &FileHeader,
 | |
|                                                   sizeof (EFI_FFS_FILE_HEADER)
 | |
|                                                   );
 | |
|     if (FileHeader.Attributes & FFS_ATTRIB_CHECKSUM) {
 | |
|       //
 | |
|       // Cheating here.  Since the header checksums, just calculate the checksum of the body.
 | |
|       // Checksum does not include the tail
 | |
|       //
 | |
|       if (FileHeader.Attributes & FFS_ATTRIB_TAIL_PRESENT) {
 | |
|         FileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 (
 | |
|                                                     FileBuffer,
 | |
|                                                     FileSize - sizeof (EFI_FFS_FILE_HEADER) - sizeof (EFI_FFS_FILE_TAIL)
 | |
|                                                     );
 | |
|       } else {
 | |
|         FileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 (
 | |
|                                                     FileBuffer,
 | |
|                                                     FileSize - sizeof (EFI_FFS_FILE_HEADER)
 | |
|                                                     );
 | |
|       }
 | |
|     } else {
 | |
|       FileHeader.IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
 | |
|     }
 | |
|     //
 | |
|     // Set the state now. Spec says the checksum assumes the state is 0
 | |
|     //
 | |
|     FileHeader.State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
 | |
|     //
 | |
|     // If there is a tail, then set it
 | |
|     //
 | |
|     if (FileHeader.Attributes & FFS_ATTRIB_TAIL_PRESENT) {
 | |
|       TailValue = FileHeader.IntegrityCheck.TailReference;
 | |
|       TailValue = (UINT16) (~TailValue);
 | |
|       memcpy (
 | |
|         (UINT8 *) FileBuffer + FileSize - sizeof (EFI_FFS_FILE_HEADER) - sizeof (EFI_FFS_FILE_TAIL),
 | |
|         &TailValue,
 | |
|         sizeof (TailValue)
 | |
|         );
 | |
|     }
 | |
|     //
 | |
|     // Write the FFS file header
 | |
|     //
 | |
|     if (fwrite (&FileHeader, sizeof (FileHeader), 1, Out) != 1) {
 | |
|       Error (NULL, 0, 0, "failed to write file header contents", NULL);
 | |
|       goto Done;
 | |
|     }
 | |
|     //
 | |
|     // Write data
 | |
|     //
 | |
|     if (fwrite (FileBuffer, FileSize - sizeof (EFI_FFS_FILE_HEADER), 1, Out) != 1) {
 | |
|       Error (NULL, 0, 0, "failed to write file contents", NULL);
 | |
|       goto Done;
 | |
|     }
 | |
|   }
 | |
| 
 | |
| Done:
 | |
|   SFPCloseFile ();
 | |
|   if (Out != NULL) {
 | |
|     fclose (Out);
 | |
|   }
 | |
| 
 | |
|   if (PrimaryPackage != NULL) {
 | |
|     fclose (PrimaryPackage);
 | |
|   }
 | |
| 
 | |
|   if (FileBuffer != NULL) {
 | |
|     free (FileBuffer);
 | |
|   }
 | |
| 
 | |
|   if (OverridePackage != NULL) {
 | |
|     fclose (OverridePackage);
 | |
|   }
 | |
| 
 | |
|   return GetUtilityStatus ();
 | |
| }
 | |
| 
 | |
| int
 | |
| main (
 | |
|   INT32 argc,
 | |
|   CHAR8 *argv[]
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
| 
 | |
|   Main function.
 | |
| 
 | |
| Arguments:
 | |
| 
 | |
|   argc - Number of command line parameters.
 | |
|   argv - Array of pointers to parameter strings.
 | |
| 
 | |
| Returns:
 | |
|   STATUS_SUCCESS - Utility exits successfully.
 | |
|   STATUS_ERROR   - Some error occurred during execution.
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   STATUS  Status;
 | |
|   //
 | |
|   // Set the name of our utility for error reporting purposes.
 | |
|   //
 | |
|   SetUtilityName (UTILITY_NAME);
 | |
|   Status = ProcessCommandLineArgs (argc, argv);
 | |
|   if (Status != STATUS_SUCCESS) {
 | |
|     return Status;
 | |
|   }
 | |
| 
 | |
|   Status = MainEntry (argc, argv, TRUE);
 | |
|   if (Status == STATUS_SUCCESS) {
 | |
|     MainEntry (argc, argv, FALSE);
 | |
|   }
 | |
|   //
 | |
|   // If any errors were reported via the standard error reporting
 | |
|   // routines, then the status has been saved. Get the value and
 | |
|   // return it to the caller.
 | |
|   //
 | |
|   return GetUtilityStatus ();
 | |
| }
 | |
| 
 | |
| static
 | |
| STATUS
 | |
| ProcessCommandLineArgs (
 | |
|   int     Argc,
 | |
|   char    *Argv[]
 | |
|   )
 | |
| /*++
 | |
| 
 | |
| Routine Description:
 | |
|   Process the command line arguments.
 | |
| 
 | |
| Arguments:
 | |
|   Argc - as passed in to main()
 | |
|   Argv - as passed in to main()
 | |
| 
 | |
| Returns:
 | |
|   STATUS_SUCCESS    - arguments all ok
 | |
|   STATUS_ERROR      - problem with args, so caller should exit
 | |
| 
 | |
| --*/
 | |
| {
 | |
|   //
 | |
|   // If no args, then print usage instructions and return an error
 | |
|   //
 | |
|   Argc--;
 | |
|   Argv++;
 | |
|   
 | |
|   if (Argc < 1) {
 | |
|     Usage ();
 | |
|     return STATUS_ERROR;
 | |
|   }
 | |
|   
 | |
|   if ((strcmp(Argv[0], "-h") == 0) || (strcmp(Argv[0], "--help") == 0) ||
 | |
|       (strcmp(Argv[0], "-?") == 0) || (strcmp(Argv[0], "/?") == 0)) {
 | |
|     Usage();
 | |
|     return STATUS_ERROR;
 | |
|   }
 | |
|   
 | |
|   if ((strcmp(Argv[0], "-V") == 0) || (strcmp(Argv[0], "--version") == 0)) {
 | |
|     Version();
 | |
|     return STATUS_ERROR;
 | |
|   }
 | |
|   
 | |
|   memset (&mGlobals, 0, sizeof (mGlobals));
 | |
|  
 | |
|   while (Argc > 0) {
 | |
|     if (strcmpi (Argv[0], "-b") == 0) {
 | |
|       //
 | |
|       // OPTION: -b BuildDirectory
 | |
|       // Make sure there is another argument, then save it to our globals.
 | |
|       //
 | |
|       if (Argc < 2) {
 | |
|         Error (NULL, 0, 0, "-b option requires the build directory name", NULL);
 | |
|         return STATUS_ERROR;
 | |
|       }
 | |
| 
 | |
|       if (mGlobals.BuildDirectory[0]) {
 | |
|         Error (NULL, 0, 0, Argv[0], "option can only be specified once");
 | |
|         return STATUS_ERROR;
 | |
|       }
 | |
| 
 | |
|       strcpy (mGlobals.BuildDirectory, Argv[1]);
 | |
|       Argc--;
 | |
|       Argv++;
 | |
|     } else if (strcmpi (Argv[0], "-p1") == 0) {
 | |
|       //
 | |
|       // OPTION: -p1 PrimaryPackageFile
 | |
|       // Make sure there is another argument, then save it to our globals.
 | |
|       //
 | |
|       if (Argc < 2) {
 | |
|         Error (NULL, 0, 0, Argv[0], "option requires the primary package file name");
 | |
|         return STATUS_ERROR;
 | |
|       }
 | |
| 
 | |
|       if (mGlobals.PrimaryPackagePath[0]) {
 | |
|         Error (NULL, 0, 0, Argv[0], "option can only be specified once");
 | |
|         return STATUS_ERROR;
 | |
|       }
 | |
| 
 | |
|       strcpy (mGlobals.PrimaryPackagePath, Argv[1]);
 | |
|       Argc--;
 | |
|       Argv++;
 | |
|     } else if (strcmpi (Argv[0], "-p2") == 0) {
 | |
|       //
 | |
|       // OPTION: -p2 OverridePackageFile
 | |
|       // Make sure there is another argument, then save it to our globals.
 | |
|       //
 | |
|       if (Argc < 2) {
 | |
|         Error (NULL, 0, 0, Argv[0], "option requires the override package file name");
 | |
|         return STATUS_ERROR;
 | |
|       }
 | |
| 
 | |
|       if (mGlobals.OverridePackagePath[0]) {
 | |
|         Error (NULL, 0, 0, Argv[0], "option can only be specified once");
 | |
|         return STATUS_ERROR;
 | |
|       }
 | |
| 
 | |
|       strcpy (mGlobals.OverridePackagePath, Argv[1]);
 | |
|       Argc--;
 | |
|       Argv++;
 | |
|     } else if (strcmpi (Argv[0], "-v") == 0) {
 | |
|       //
 | |
|       // OPTION: -v       verbose
 | |
|       //
 | |
|       mGlobals.Verbose = TRUE;
 | |
|     } else if (strcmpi (Argv[0], "-h") == 0) {
 | |
|       //
 | |
|       // OPTION: -h      help
 | |
|       //
 | |
|       Usage ();
 | |
|       return STATUS_ERROR;
 | |
|     } else if (strcmpi (Argv[0], "-?") == 0) {
 | |
|       //
 | |
|       // OPTION:  -?      help
 | |
|       //
 | |
|       Usage ();
 | |
|       return STATUS_ERROR;
 | |
|     } else {
 | |
|       Error (NULL, 0, 0, Argv[0], "unrecognized option");
 | |
|       Usage ();
 | |
|       return STATUS_ERROR;
 | |
|     }
 | |
| 
 | |
|     Argv++;
 | |
|     Argc--;
 | |
|   }
 | |
|   //
 | |
|   // Must have at least specified the package file name
 | |
|   //
 | |
|   if (mGlobals.PrimaryPackagePath[0] == 0) {
 | |
|     Error (NULL, 0, 0, "must specify primary package file", NULL);
 | |
|     return STATUS_ERROR;
 | |
|   }
 | |
| 
 | |
|   return STATUS_SUCCESS;
 | |
| }
 |