--- /dev/null
+/*++\r
+\r
+Copyright (c) 2002-2006 Intel Corporation. All rights reserved\r
+This program and the accompanying materials are licensed and made available \r
+under the terms and conditions of the BSD License which accompanies this \r
+distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+\r
+Module Name:\r
+\r
+ GenCapsuleHdr.c \r
+\r
+Abstract:\r
+\r
+ Generate a capsule header for a file, and optionally prepend the\r
+ header to a file or list of files.\r
+\r
+--*/\r
+\r
+#define _UNICODE\r
+\r
+#include <stdio.h>\r
+#include <string.h>\r
+#include <stdlib.h>\r
+#include <ctype.h>\r
+\r
+#include <Common/UefiBaseTypes.h>\r
+#include <Common/MultiPhase.h>\r
+#include <Common/Capsule.h>\r
+#include <Common/FirmwareVolumeImageFormat.h>\r
+#include <Common/FirmwareVolumeHeader.h>\r
+#include <Common/FirmwareFileSystem.h> // for FV header GUID\r
+#include <Guid/Capsule.h>\r
+#include <Guid/FirmwareFileSystem.h> // for FV header GUID\r
+\r
+#include "CommonLib.h"\r
+#include "EfiUtilityMsgs.h"\r
+\r
+#define MAX_PATH 256\r
+#define PROGRAM_NAME "GenCapsuleHdr"\r
+\r
+#define UNICODE_BACKSLASH L'\\'\r
+#define UNICODE_FILE_START 0xFEFF\r
+#define UNICODE_CR 0x000D\r
+#define UNICODE_LF 0x000A\r
+#define UNICODE_NULL 0x0000\r
+#define UNICODE_SPACE L' '\r
+#define UNICODE_SLASH L'/'\r
+#define UNICODE_DOUBLE_QUOTE L'"'\r
+#define UNICODE_A L'A'\r
+#define UNICODE_F L'F'\r
+#define UNICODE_Z L'Z'\r
+#define UNICODE_a L'a'\r
+#define UNICODE_f L'f'\r
+#define UNICODE_z L'z'\r
+#define UNICODE_0 L'0'\r
+#define UNICODE_9 L'9'\r
+#define UNICODE_TAB L'\t'\r
+\r
+#define OEM_HEADER_STRING L"OemHeader"\r
+#define AUTHOR_INFO_STRING L"AuthorInfo"\r
+#define REVISION_INFO_STRING L"RevisionInfo"\r
+#define SHORT_DESCRIPTION_STRING L"ShortDescription"\r
+#define LONG_DESCRIPTION_STRING L"LongDescription"\r
+#define EQUAL_STRING L"="\r
+#define OPEN_BRACE_STRING L"{"\r
+#define CLOSE_BRACE_STRING L"}"\r
+#define GUID_STRING L"GUID"\r
+#define DATA_STRING L"DATA"\r
+\r
+#if (EFI_SPECIFICATION_VERSION >= 0x00020000)\r
+#define UEFI_CAPSULE_HEADER_NO_FALAGS 0\r
+#define UEFI_CAPSULE_HEADER_RESET_FALAGS CAPSULE_FLAGS_PERSIST_ACROSS_RESET\r
+#define UEFI_CAPSULE_HEADER_ALL_FALAGS (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)\r
+#endif\r
+\r
+typedef wchar_t WCHAR;\r
+\r
+typedef struct _FILE_LIST {\r
+ struct _FILE_LIST *Next;\r
+ INT8 FileName[MAX_PATH];\r
+} FILE_LIST;\r
+\r
+typedef struct _SIZE_LIST {\r
+ struct _SIZE_LIST *Next;\r
+ UINT32 Size;\r
+} SIZE_LIST;\r
+\r
+typedef struct {\r
+ INT8 FileName[MAX_PATH];\r
+ WCHAR *FileBuffer;\r
+ WCHAR *FileBufferPtr;\r
+ UINT32 FileSize;\r
+ FILE *FilePtr;\r
+ BOOLEAN EndOfFile;\r
+ UINT32 LineNum;\r
+} SOURCE_FILE;\r
+\r
+//\r
+// Here's all our globals.\r
+//\r
+static struct {\r
+ BOOLEAN Dump;\r
+ BOOLEAN Verbose;\r
+ BOOLEAN JoinMode;\r
+ INT8 ScriptFileName[MAX_PATH];\r
+ INT8 OutputFileName[MAX_PATH];\r
+ FILE_LIST *FileList;\r
+ FILE *OutFptr;\r
+ SIZE_LIST *SizeList;\r
+ SIZE_LIST *LastSize;\r
+ SIZE_LIST *CurrentSize;\r
+} mOptions;\r
+\r
+static EFI_GUID mEfiCapsuleHeaderGuid = EFI_CAPSULE_GUID;\r
+\r
+void\r
+CreateGuid (\r
+ EFI_GUID *Guid\r
+ );\r
+\r
+static\r
+STATUS\r
+ProcessArgs (\r
+ int Argc,\r
+ char *Argv[]\r
+ );\r
+\r
+static\r
+void\r
+SkipWhiteSpace (\r
+ SOURCE_FILE *SourceFile\r
+ );\r
+\r
+static\r
+STATUS\r
+GetHexValue (\r
+ SOURCE_FILE *SourceFile,\r
+ UINT32 *Value,\r
+ UINT32 NumDigits\r
+ );\r
+\r
+static\r
+BOOLEAN\r
+GetSplitFileName (\r
+ INT8 *BaseFileName,\r
+ INT8 *NewFileName,\r
+ UINT32 SequenceNumber\r
+ );\r
+\r
+static\r
+STATUS\r
+SplitCapsule (\r
+ INT8 *CapsuleFileName\r
+ );\r
+\r
+static\r
+void\r
+Usage (\r
+ VOID\r
+ );\r
+\r
+static\r
+void\r
+DumpCapsule (\r
+ VOID\r
+ );\r
+\r
+static\r
+STATUS\r
+JoinCapsule (\r
+ VOID\r
+ );\r
+\r
+static\r
+STATUS\r
+DumpCapsuleHeaderStrings (\r
+ UINT8 *SectionName,\r
+ WCHAR *Buffer\r
+ );\r
+\r
+static\r
+STATUS\r
+CheckFirmwareVolumeHeader (\r
+ INT8 *FileName,\r
+ INT8 *Buffer,\r
+ UINT32 BufferSize\r
+ );\r
+\r
+static\r
+BOOLEAN\r
+IsToken (\r
+ SOURCE_FILE *File,\r
+ WCHAR *Token\r
+ );\r
+\r
+static\r
+BOOLEAN\r
+GetNumber (\r
+ INT8 *Str,\r
+ UINT32 *Value\r
+ );\r
+\r
+static\r
+STATUS\r
+ProcessScriptFile (\r
+ INT8 *ScriptFileName,\r
+ FILE *OutFptr,\r
+ EFI_CAPSULE_HEADER *CapsuleHeader\r
+ );\r
+\r
+static\r
+STATUS\r
+ParseCapsuleInfo (\r
+ SOURCE_FILE *SourceFile,\r
+ FILE *OutFptr,\r
+ WCHAR *SectionName\r
+ );\r
+\r
+static\r
+STATUS\r
+CreateCapsule (\r
+ VOID\r
+ );\r
+\r
+static\r
+STATUS\r
+ParseOemInfo (\r
+ SOURCE_FILE *SourceFile,\r
+ FILE *OutFptr\r
+ );\r
+\r
+static\r
+BOOLEAN\r
+IsWhiteSpace (\r
+ WCHAR Char\r
+ );\r
+\r
+static\r
+BOOLEAN\r
+EndOfFile (\r
+ SOURCE_FILE *File\r
+ );\r
+\r
+int\r
+main (\r
+ int Argc,\r
+ char *Argv[]\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Call the routine to process the command-line arguments, then\r
+ dispatch to the appropriate function.\r
+ \r
+Arguments:\r
+ Standard C main() argc and argv.\r
+\r
+Returns:\r
+ 0 if successful\r
+ nonzero otherwise\r
+ \r
+--*/\r
+// GC_TODO: Argc - add argument and description to function comment\r
+// GC_TODO: ] - add argument and description to function comment\r
+{\r
+ STATUS Status;\r
+ FILE_LIST *NextFile;\r
+ //\r
+ // Specify our program name to the error printing routines.\r
+ //\r
+ SetUtilityName (PROGRAM_NAME);\r
+ //\r
+ // Process the command-line arguments\r
+ //\r
+ Status = ProcessArgs (Argc, Argv);\r
+ if (Status == STATUS_SUCCESS) {\r
+ if (mOptions.Dump) {\r
+ DumpCapsule ();\r
+ } else if (mOptions.JoinMode) {\r
+ JoinCapsule ();\r
+ } else {\r
+ CreateCapsule ();\r
+ }\r
+ }\r
+ //\r
+ // Cleanup\r
+ //\r
+ while (mOptions.FileList != NULL) {\r
+ NextFile = mOptions.FileList->Next;\r
+ free (mOptions.FileList);\r
+ mOptions.FileList = NextFile;\r
+ }\r
+\r
+ while (mOptions.SizeList != NULL) {\r
+ mOptions.CurrentSize = mOptions.SizeList->Next;\r
+ free (mOptions.SizeList);\r
+ mOptions.SizeList = mOptions.CurrentSize;\r
+ }\r
+\r
+ return GetUtilityStatus ();\r
+}\r
+\r
+static\r
+STATUS\r
+CreateCapsule (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ None\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ FILE *InFptr;\r
+ FILE_LIST *FileList;\r
+ INT8 *Buffer;\r
+ UINT32 Size;\r
+ EFI_CAPSULE_HEADER CapsuleHeader;\r
+ UINT8 Zero;\r
+ UINT8 FirstFile;\r
+ UINT32 CapsuleHeaderSize;\r
+ long InsertedBlockMapEntryOffset;\r
+ EFI_FV_BLOCK_MAP_ENTRY InsertedBlockMapEntry;\r
+ UINT64 FirmwareVolumeSize;\r
+ long FileSize;\r
+ EFI_FIRMWARE_VOLUME_HEADER FVHeader;\r
+\r
+ Buffer = NULL;\r
+ InFptr = NULL;\r
+ FirmwareVolumeSize = 0;\r
+ CapsuleHeaderSize = 0;\r
+ InsertedBlockMapEntryOffset = 0;\r
+ memset (&InsertedBlockMapEntry, 0, sizeof (EFI_FV_BLOCK_MAP_ENTRY));\r
+ memset (&FVHeader, 0, sizeof (EFI_FIRMWARE_VOLUME_HEADER));\r
+\r
+ if ((mOptions.OutFptr = fopen (mOptions.OutputFileName, "wb")) == NULL) {\r
+ Error (NULL, 0, 0, mOptions.OutputFileName, "failed to open output file for writing");\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ memset ((char *) &CapsuleHeader, 0, sizeof (CapsuleHeader));\r
+ memcpy ((void *) &CapsuleHeader.CapsuleGuid, (void *) &mEfiCapsuleHeaderGuid, sizeof (EFI_GUID));\r
+ CapsuleHeader.HeaderSize = sizeof (EFI_CAPSULE_HEADER);\r
+ CapsuleHeader.CapsuleImageSize = sizeof (EFI_CAPSULE_HEADER);\r
+ if (mOptions.ScriptFileName[0] != 0) {\r
+ if (ProcessScriptFile (mOptions.ScriptFileName, mOptions.OutFptr, &CapsuleHeader) != STATUS_SUCCESS) {\r
+ goto Done;\r
+ }\r
+ } else {\r
+ //\r
+ // Insert a default capsule header\r
+#if (EFI_SPECIFICATION_VERSION >= 0x00020000)\r
+ CapsuleHeader.HeaderSize = sizeof (EFI_CAPSULE_HEADER);\r
+ CapsuleHeader.Flags = UEFI_CAPSULE_HEADER_ALL_FALAGS;\r
+#endif\r
+ CapsuleHeader.OffsetToCapsuleBody = sizeof (EFI_CAPSULE_HEADER);\r
+\r
+ if (fwrite ((void *) &CapsuleHeader, sizeof (CapsuleHeader), 1, mOptions.OutFptr) != 1) {\r
+ Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ CapsuleHeaderSize = CapsuleHeader.OffsetToCapsuleBody;\r
+ //\r
+ // Now copy the contents of any other files specified on the command\r
+ // line to the output file. Files must be FFS files, which are aligned\r
+ // on 8-byte boundaries. Don't align the first file, since it's the start\r
+ // of the image once the capsule header has been removed.\r
+ //\r
+ FileList = mOptions.FileList;\r
+ FirstFile = 1;\r
+ Zero = 0;\r
+ while (FileList != NULL) {\r
+ if ((InFptr = fopen (FileList->FileName, "rb")) == NULL) {\r
+ Error (NULL, 0, 0, FileList->FileName, "failed to open file for reading");\r
+ goto Done;\r
+ }\r
+ //\r
+ // Allocate a buffer into which we can read the file.\r
+ //\r
+ fseek (InFptr, 0, SEEK_END);\r
+ Size = ftell (InFptr);\r
+ rewind (InFptr);\r
+ Buffer = (char *) malloc (Size);\r
+ if (Buffer == NULL) {\r
+ Error (__FILE__, __LINE__, 0, FileList->FileName, "failed to allocate buffer to read file into");\r
+ goto Done;\r
+ }\r
+\r
+ if (fread ((void *) Buffer, Size, 1, InFptr) != 1) {\r
+ Error (NULL, 0, 0, FileList->FileName, "failed to read file contents");\r
+ goto Done;\r
+ }\r
+\r
+ if (Size > 0) {\r
+ //\r
+ // Align the write of the first bytes from the file if not the first file\r
+ //\r
+ if (FirstFile) {\r
+ //\r
+ // First file must be a firmware volume. Double-check, and then insert\r
+ // an additional block map entry so we can add more files from the command line\r
+ //\r
+ if (CheckFirmwareVolumeHeader (FileList->FileName, Buffer, Size) != STATUS_SUCCESS) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Save a copy of the firmware volume header for later\r
+ //\r
+ memcpy (&FVHeader, Buffer, sizeof (EFI_FIRMWARE_VOLUME_HEADER));\r
+ FirmwareVolumeSize = FVHeader.FvLength;\r
+ if (FileList->Next != NULL) {\r
+ //\r
+ // Copy the firmware volume header\r
+ //\r
+ InsertedBlockMapEntryOffset = CapsuleHeaderSize + FVHeader.HeaderLength;\r
+ if (fwrite (Buffer, FVHeader.HeaderLength, 1, mOptions.OutFptr) != 1) {\r
+ Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
+ goto Done;\r
+ }\r
+\r
+ if (fwrite (&InsertedBlockMapEntry, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, mOptions.OutFptr) != 1) {\r
+ Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
+ goto Done;\r
+ }\r
+\r
+ if (fwrite (\r
+ Buffer + FVHeader.HeaderLength,\r
+ Size - FVHeader.HeaderLength,\r
+ 1,\r
+ mOptions.OutFptr\r
+ ) != 1) {\r
+ Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
+ goto Done;\r
+ }\r
+ } else {\r
+ //\r
+ // Copy the file contents as-is\r
+ //\r
+ if (fwrite ((void *) Buffer, Size, 1, mOptions.OutFptr) != 1) {\r
+ Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
+ goto Done;\r
+ }\r
+ }\r
+ } else {\r
+ while ((ftell (mOptions.OutFptr) - CapsuleHeaderSize) & 0x07) {\r
+ if (fwrite ((void *) &Zero, 1, 1, mOptions.OutFptr) != 1) {\r
+ Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ if (fwrite ((void *) Buffer, Size, 1, mOptions.OutFptr) != 1) {\r
+ Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ FirstFile = 0;\r
+ }\r
+\r
+ free (Buffer);\r
+ Buffer = NULL;\r
+ fclose (InFptr);\r
+ InFptr = NULL;\r
+ FileList = FileList->Next;\r
+ }\r
+\r
+Done:\r
+ if (Buffer != NULL) {\r
+ free (Buffer);\r
+ }\r
+\r
+ if (InFptr != NULL) {\r
+ fclose (InFptr);\r
+ }\r
+ //\r
+ // If we inserted an additional block map entry, then fix it up. Fix up the\r
+ // FV header as well to reflect our new size.\r
+ //\r
+ if (InsertedBlockMapEntryOffset != 0) {\r
+ FileSize = ftell (mOptions.OutFptr);\r
+ InsertedBlockMapEntry.NumBlocks = 1;\r
+ InsertedBlockMapEntry.BlockLength = (UINT32) ((UINT64) FileSize - (UINT64) CapsuleHeaderSize - FirmwareVolumeSize - sizeof (EFI_FV_BLOCK_MAP_ENTRY));\r
+ fseek (mOptions.OutFptr, InsertedBlockMapEntryOffset, SEEK_SET);\r
+ fwrite (&InsertedBlockMapEntry, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, mOptions.OutFptr);\r
+ //\r
+ // Fix up the firmware volume header and write it out\r
+ //\r
+ fseek (mOptions.OutFptr, CapsuleHeaderSize, SEEK_SET);\r
+ FVHeader.FvLength = FileSize - CapsuleHeaderSize;\r
+ FVHeader.HeaderLength += sizeof (EFI_FV_BLOCK_MAP_ENTRY);\r
+ fwrite (&FVHeader, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, mOptions.OutFptr);\r
+ //\r
+ // Reposition to the end of the file\r
+ //\r
+ }\r
+ //\r
+ // Close files and free the global string lists we allocated memory for\r
+ //\r
+ if (mOptions.OutFptr != NULL) {\r
+ //\r
+ // We should now know the full capsule image size. Update the header and write it again.\r
+ //\r
+ fseek (mOptions.OutFptr, 0, SEEK_END);\r
+ Size = ftell (mOptions.OutFptr);\r
+ CapsuleHeader.CapsuleImageSize = Size;\r
+ fseek (mOptions.OutFptr, 0, SEEK_SET);\r
+ if (fwrite ((void *) &CapsuleHeader, sizeof (CapsuleHeader), 1, mOptions.OutFptr) != 1) {\r
+ Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
+ }\r
+\r
+ fseek (mOptions.OutFptr, 0, SEEK_END);\r
+ fclose (mOptions.OutFptr);\r
+ mOptions.OutFptr = NULL;\r
+ }\r
+ //\r
+ // If they are doing split capsule output, then split it up now.\r
+ //\r
+ if ((mOptions.Dump == 0) && (GetUtilityStatus () == STATUS_SUCCESS) && (mOptions.SizeList != NULL)) {\r
+ SplitCapsule (mOptions.OutputFileName);\r
+ }\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+static\r
+STATUS\r
+ProcessScriptFile (\r
+ INT8 *ScriptFileName,\r
+ FILE *OutFptr,\r
+ EFI_CAPSULE_HEADER *CapsuleHeader\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Parse a capsule header script file.\r
+\r
+Arguments:\r
+ ScriptFileName - name of script file to parse\r
+ OutFptr - output to dump binary data\r
+ CapsuleHeader - capsule header to update with size info\r
+ of parsed fields in the script file\r
+\r
+Returns:\r
+ STATUS_SUCCESS - if all went well\r
+\r
+--*/\r
+{\r
+#if 0\r
+ STATUS Status;\r
+ SOURCE_FILE SourceFile;\r
+ WCHAR *WScriptFileName;\r
+ BOOLEAN InComment;\r
+\r
+ if (fwrite (CapsuleHeader, sizeof (EFI_CAPSULE_HEADER), 1, OutFptr) != 1) {\r
+ Error (NULL, 0, 0, "failed to write capsule header to output file", NULL);\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ memset (&SourceFile, 0, sizeof (SOURCE_FILE));\r
+ strcpy (SourceFile.FileName, ScriptFileName);\r
+\r
+ Status = STATUS_ERROR;\r
+ //\r
+ // Open the input unicode script file and read it into a buffer\r
+ //\r
+ WScriptFileName = (WCHAR *) malloc ((strlen (ScriptFileName) + 1) * sizeof (WCHAR));\r
+ if (WScriptFileName == NULL) {\r
+ Error (__FILE__, __LINE__, 0, "failed to allocate memory", NULL);\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ swprintf (WScriptFileName, L"%S", ScriptFileName);\r
+ if ((SourceFile.FilePtr = _wfopen (WScriptFileName, L"r")) == NULL) {\r
+ free (WScriptFileName);\r
+ Error (NULL, 0, 0, ScriptFileName, "failed to open script file for reading");\r
+ goto Done;\r
+ }\r
+\r
+ free (WScriptFileName);\r
+ fseek (SourceFile.FilePtr, 0, SEEK_END);\r
+ SourceFile.FileSize = ftell (SourceFile.FilePtr);\r
+ rewind (SourceFile.FilePtr);\r
+ SourceFile.FileBuffer = (WCHAR *) malloc (SourceFile.FileSize + sizeof (WCHAR));\r
+ if (SourceFile.FileBuffer == NULL) {\r
+ Error (__FILE__, __LINE__, 0, ScriptFileName, "failed to allocate memory to read in file contents");\r
+ goto Done;\r
+ }\r
+\r
+ if (fread (SourceFile.FileBuffer, SourceFile.FileSize, 1, SourceFile.FilePtr) != 1) {\r
+ Error (NULL, 0, 0, ScriptFileName, "failed to read file contents");\r
+ goto Done;\r
+ }\r
+\r
+ SourceFile.FileBufferPtr = SourceFile.FileBuffer;\r
+ SourceFile.LineNum = 1;\r
+ if (SourceFile.FileBuffer[0] != UNICODE_FILE_START) {\r
+ Error (ScriptFileName, 1, 0, "file does not appear to be a unicode file", NULL);\r
+ goto Done;\r
+ }\r
+\r
+ SourceFile.FileBufferPtr++;\r
+ SourceFile.FileBuffer[SourceFile.FileSize / sizeof (WCHAR)] = 0;\r
+ //\r
+ // Walk the source file buffer and replace all carriage returns with 0 so\r
+ // we can print from the file contents on parse errors.\r
+ //\r
+ InComment = 0;\r
+ while (!EndOfFile (&SourceFile)) {\r
+ if (SourceFile.FileBufferPtr[0] == UNICODE_CR) {\r
+ SourceFile.FileBufferPtr[0] = 0;\r
+ InComment = 0;\r
+ } else if (SourceFile.FileBufferPtr[0] == UNICODE_LF) {\r
+ InComment = 0;\r
+ } else if (InComment) {\r
+ SourceFile.FileBufferPtr[0] = UNICODE_SPACE;\r
+ } else if ((SourceFile.FileBufferPtr[0] == UNICODE_SLASH) && (SourceFile.FileBufferPtr[1] == UNICODE_SLASH)) {\r
+ InComment = 1;\r
+ SourceFile.FileBufferPtr[0] = UNICODE_SPACE;\r
+ }\r
+\r
+ SourceFile.FileBufferPtr++;\r
+ }\r
+ //\r
+ // Reposition to the start of the file, but skip over the unicode file start\r
+ //\r
+ SourceFile.FileBufferPtr = SourceFile.FileBuffer;\r
+ SourceFile.FileBufferPtr++;\r
+ SourceFile.EndOfFile = 0;\r
+ CapsuleHeader->OffsetToOemDefinedHeader = ftell (OutFptr);\r
+ //\r
+ // Parse the OEM bytes\r
+ //\r
+ if (ParseOemInfo (&SourceFile, OutFptr) != STATUS_SUCCESS) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Parse the author information\r
+ //\r
+ CapsuleHeader->OffsetToAuthorInformation = ftell (OutFptr);\r
+ if (ParseCapsuleInfo (&SourceFile, OutFptr, AUTHOR_INFO_STRING) != STATUS_SUCCESS) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Parse the revision information\r
+ //\r
+ CapsuleHeader->OffsetToRevisionInformation = ftell (OutFptr);\r
+ if (ParseCapsuleInfo (&SourceFile, OutFptr, REVISION_INFO_STRING) != STATUS_SUCCESS) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Parse the short description\r
+ //\r
+ CapsuleHeader->OffsetToShortDescription = ftell (OutFptr);\r
+ if (ParseCapsuleInfo (&SourceFile, OutFptr, SHORT_DESCRIPTION_STRING) != STATUS_SUCCESS) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Parse the long description\r
+ //\r
+ CapsuleHeader->OffsetToLongDescription = ftell (OutFptr);\r
+ if (ParseCapsuleInfo (&SourceFile, OutFptr, LONG_DESCRIPTION_STRING) != STATUS_SUCCESS) {\r
+ goto Done;\r
+ }\r
+ //\r
+ // Better be end of contents\r
+ //\r
+ SkipWhiteSpace (&SourceFile);\r
+ if (!EndOfFile (&SourceFile)) {\r
+ Error (ScriptFileName, SourceFile.LineNum, 0, NULL, "expected end-of-file, not %.20S", SourceFile.FileBufferPtr);\r
+ goto Done;\r
+ }\r
+\r
+ CapsuleHeader->OffsetToCapsuleBody = ftell (OutFptr);\r
+ rewind (OutFptr);\r
+ fwrite (CapsuleHeader, sizeof (EFI_CAPSULE_HEADER), 1, OutFptr);\r
+ fseek (OutFptr, 0, SEEK_END);\r
+ Status = STATUS_SUCCESS;\r
+Done:\r
+ if (SourceFile.FilePtr != NULL) {\r
+ fclose (SourceFile.FilePtr);\r
+ }\r
+\r
+ if (SourceFile.FileBuffer != NULL) {\r
+ free (SourceFile.FileBuffer);\r
+ }\r
+\r
+ return Status;\r
+\r
+#endif\r
+ return STATUS_SUCCESS;\r
+}\r
+//\r
+// Parse the OEM data of format:\r
+// OemInfo {\r
+// GUID = 12345676-1234-1234-123456789ABC\r
+// DATA = 0x01, 0x02, 0x03...\r
+// }\r
+//\r
+static\r
+STATUS\r
+ParseOemInfo (\r
+ SOURCE_FILE *SourceFile,\r
+ FILE *OutFptr\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ SourceFile - GC_TODO: add argument description\r
+ OutFptr - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ long OemHeaderOffset;\r
+ UINT32 Data;\r
+ EFI_CAPSULE_OEM_HEADER OemHeader;\r
+ STATUS Status;\r
+ UINT32 DigitCount;\r
+ WCHAR *SaveFilePos;\r
+ UINT8 ByteData;\r
+\r
+ Status = STATUS_ERROR;\r
+ memset (&OemHeader, 0, sizeof (EFI_CAPSULE_OEM_HEADER));\r
+ OemHeaderOffset = ftell (OutFptr);\r
+ OemHeader.HeaderSize = sizeof (EFI_CAPSULE_OEM_HEADER);\r
+ if (fwrite (&OemHeader, sizeof (EFI_CAPSULE_OEM_HEADER), 1, OutFptr) != 1) {\r
+ Error (NULL, 0, 0, "failed to write OEM header to output file", NULL);\r
+ goto Done;\r
+ }\r
+\r
+ if (!IsToken (SourceFile, OEM_HEADER_STRING)) {\r
+ Error (\r
+ SourceFile->FileName,\r
+ SourceFile->LineNum,\r
+ 0,\r
+ NULL,\r
+ "expected %S, not %.20S",\r
+ OEM_HEADER_STRING,\r
+ SourceFile->FileBufferPtr\r
+ );\r
+ goto Done;\r
+ }\r
+\r
+ if (!IsToken (SourceFile, EQUAL_STRING)) {\r
+ Error (\r
+ SourceFile->FileName,\r
+ SourceFile->LineNum,\r
+ 0,\r
+ NULL,\r
+ "expected %S, not %.20S",\r
+ EQUAL_STRING,\r
+ SourceFile->FileBufferPtr\r
+ );\r
+ goto Done;\r
+ }\r
+\r
+ if (!IsToken (SourceFile, OPEN_BRACE_STRING)) {\r
+ Error (\r
+ SourceFile->FileName,\r
+ SourceFile->LineNum,\r
+ 0,\r
+ NULL,\r
+ "expected %S, not %.20S",\r
+ OPEN_BRACE_STRING,\r
+ SourceFile->FileBufferPtr\r
+ );\r
+ goto Done;\r
+ }\r
+ //\r
+ // Look for: GUID = xxxxxxx-xxxx-xxxx-xxxxxxxxxxxxx\r
+ //\r
+ if (!IsToken (SourceFile, GUID_STRING)) {\r
+ Error (\r
+ SourceFile->FileName,\r
+ SourceFile->LineNum,\r
+ 0,\r
+ NULL,\r
+ "expected %S, not %.20S",\r
+ GUID_STRING,\r
+ SourceFile->FileBufferPtr\r
+ );\r
+ goto Done;\r
+ }\r
+\r
+ if (!IsToken (SourceFile, EQUAL_STRING)) {\r
+ Error (\r
+ SourceFile->FileName,\r
+ SourceFile->LineNum,\r
+ 0,\r
+ NULL,\r
+ "expected %S, not %.20S",\r
+ EQUAL_STRING,\r
+ SourceFile->FileBufferPtr\r
+ );\r
+ goto Done;\r
+ }\r
+ //\r
+ // Parse the xxxxxxxx-xxxx-xxxx-xxxx portion of the GUID\r
+ //\r
+ SkipWhiteSpace (SourceFile);\r
+ if (GetHexValue (SourceFile, &Data, 8) != STATUS_SUCCESS) {\r
+ Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid GUID", NULL);\r
+ goto Done;\r
+ }\r
+\r
+ OemHeader.OemGuid.Data1 = Data;\r
+ if (!IsToken (SourceFile, L"-")) {\r
+ Error (\r
+ SourceFile->FileName,\r
+ SourceFile->LineNum,\r
+ 0,\r
+ NULL,\r
+ "expected dash in GUID, not %S",\r
+ SourceFile->FileBufferPtr\r
+ );\r
+ goto Done;\r
+ }\r
+ //\r
+ // Get 3 word values\r
+ //\r
+ for (DigitCount = 0; DigitCount < 3; DigitCount++) {\r
+ if (GetHexValue (SourceFile, &Data, 4) != STATUS_SUCCESS) {\r
+ Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid GUID", NULL);\r
+ goto Done;\r
+ }\r
+\r
+ switch (DigitCount) {\r
+ case 0:\r
+ OemHeader.OemGuid.Data2 = (UINT16) Data;\r
+ break;\r
+\r
+ case 1:\r
+ OemHeader.OemGuid.Data3 = (UINT16) Data;\r
+ break;\r
+\r
+ case 2:\r
+ OemHeader.OemGuid.Data4[1] = (UINT8) Data;\r
+ OemHeader.OemGuid.Data4[0] = (UINT8) (Data >> 8);\r
+ break;\r
+ }\r
+\r
+ if (!IsToken (SourceFile, L"-")) {\r
+ Error (\r
+ SourceFile->FileName,\r
+ SourceFile->LineNum,\r
+ 0,\r
+ NULL,\r
+ "expected dash in GUID, not %S",\r
+ SourceFile->FileBufferPtr\r
+ );\r
+ goto Done;\r
+ }\r
+ }\r
+ //\r
+ // Pick up the last 6 bytes of the GUID\r
+ //\r
+ SaveFilePos = SourceFile->FileBufferPtr;\r
+ for (DigitCount = 0; DigitCount < 6; DigitCount++) {\r
+ if (GetHexValue (SourceFile, &Data, 2) != STATUS_SUCCESS) {\r
+ Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid GUID", NULL);\r
+ goto Done;\r
+ }\r
+\r
+ OemHeader.OemGuid.Data4[DigitCount + 2] = (UINT8) Data;\r
+ }\r
+ //\r
+ // Now read raw OEM data bytes. May or may not be present.\r
+ // DATA = 0x01, 0x02, 0x02...\r
+ //\r
+ if (IsToken (SourceFile, CLOSE_BRACE_STRING)) {\r
+ Status = STATUS_SUCCESS;\r
+ goto Done;\r
+ }\r
+\r
+ if (!IsToken (SourceFile, DATA_STRING)) {\r
+ Error (\r
+ SourceFile->FileName,\r
+ SourceFile->LineNum,\r
+ 0,\r
+ NULL,\r
+ "expected %S, not %.20S",\r
+ DATA_STRING,\r
+ SourceFile->FileBufferPtr\r
+ );\r
+ goto Done;\r
+ }\r
+\r
+ if (!IsToken (SourceFile, EQUAL_STRING)) {\r
+ Error (\r
+ SourceFile->FileName,\r
+ SourceFile->LineNum,\r
+ 0,\r
+ NULL,\r
+ "expected %S, not %.20S",\r
+ EQUAL_STRING,\r
+ SourceFile->FileBufferPtr\r
+ );\r
+ goto Done;\r
+ }\r
+\r
+ while (!EndOfFile (SourceFile)) {\r
+ if (IsToken (SourceFile, CLOSE_BRACE_STRING)) {\r
+ Status = STATUS_SUCCESS;\r
+ goto Done;\r
+ }\r
+\r
+ if (IsToken (SourceFile, L"0x")) {\r
+ if (swscanf (SourceFile->FileBufferPtr, L"%x", &Data) != 1) {\r
+ Error (\r
+ SourceFile->FileName,\r
+ SourceFile->LineNum,\r
+ 0,\r
+ NULL,\r
+ "expected hex byte value, not %.20S",\r
+ SourceFile->FileBufferPtr\r
+ );\r
+ goto Done;\r
+ }\r
+\r
+ if (Data &~0xFF) {\r
+ Error (\r
+ SourceFile->FileName,\r
+ SourceFile->LineNum,\r
+ 0,\r
+ NULL,\r
+ "expected byte hex byte value at %.20S",\r
+ SourceFile->FileBufferPtr\r
+ );\r
+ goto Done;\r
+ }\r
+ //\r
+ // Skip over the hex digits, then write the data\r
+ //\r
+ while (iswxdigit (SourceFile->FileBufferPtr[0])) {\r
+ SourceFile->FileBufferPtr++;\r
+ }\r
+\r
+ ByteData = (UINT8) Data;\r
+ if (fwrite (&ByteData, 1, 1, OutFptr) != 1) {\r
+ Error (NULL, 0, 0, "failed to write OEM data to output file", NULL);\r
+ goto Done;\r
+ }\r
+\r
+ OemHeader.HeaderSize++;\r
+ //\r
+ // Optional comma\r
+ //\r
+ IsToken (SourceFile, L",");\r
+ } else {\r
+ Error (\r
+ SourceFile->FileName,\r
+ SourceFile->LineNum,\r
+ 0,\r
+ NULL,\r
+ "expected hex OEM data, not %.20S",\r
+ SourceFile->FileBufferPtr\r
+ );\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ if (EndOfFile (SourceFile)) {\r
+ Error (\r
+ SourceFile->FileName,\r
+ SourceFile->LineNum,\r
+ 0,\r
+ NULL,\r
+ "expected %S close to OEM header data",\r
+ CLOSE_BRACE_STRING\r
+ );\r
+ goto Done;\r
+ }\r
+\r
+ Status = STATUS_SUCCESS;\r
+Done:\r
+ //\r
+ // re-write the oem header if no errors\r
+ //\r
+ if (Status == STATUS_SUCCESS) {\r
+ fseek (OutFptr, OemHeaderOffset, SEEK_SET);\r
+ if (fwrite (&OemHeader, sizeof (EFI_CAPSULE_OEM_HEADER), 1, OutFptr) != 1) {\r
+ Error (NULL, 0, 0, "failed to write OEM header to output file", NULL);\r
+ goto Done;\r
+ }\r
+\r
+ fseek (OutFptr, 0, SEEK_END);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r
+static\r
+STATUS\r
+ParseCapsuleInfo (\r
+ SOURCE_FILE *SourceFile,\r
+ FILE *OutFptr,\r
+ WCHAR *SectionName\r
+ )\r
+// GC_TODO: function comment should start with '/*++'\r
+//\r
+// GC_TODO: function comment is missing 'Routine Description:'\r
+// GC_TODO: function comment is missing 'Arguments:'\r
+// GC_TODO: function comment is missing 'Returns:'\r
+// GC_TODO: SourceFile - add argument and description to function comment\r
+// GC_TODO: OutFptr - add argument and description to function comment\r
+// GC_TODO: SectionName - add argument and description to function comment\r
+// Parse: eng "string " "parts"\r
+// spa "string " "parts"\r
+// Write out: "eng string parts\0spa string parts\0\0\r
+//\r
+{\r
+ STATUS Status;\r
+ int StringCount;\r
+ WCHAR Zero;\r
+ WCHAR Spacebar;\r
+\r
+ Status = STATUS_ERROR;\r
+ Zero = 0;\r
+ Spacebar = UNICODE_SPACE;\r
+\r
+ if (!IsToken (SourceFile, SectionName)) {\r
+ Error (\r
+ SourceFile->FileName,\r
+ SourceFile->LineNum,\r
+ 0,\r
+ NULL,\r
+ "expected %S, not %.20S",\r
+ SectionName,\r
+ SourceFile->FileBufferPtr\r
+ );\r
+ goto Done;\r
+ }\r
+\r
+ if (!IsToken (SourceFile, EQUAL_STRING)) {\r
+ Error (\r
+ SourceFile->FileName,\r
+ SourceFile->LineNum,\r
+ 0,\r
+ NULL,\r
+ "expected %S, not %.20S",\r
+ EQUAL_STRING,\r
+ SourceFile->FileBufferPtr\r
+ );\r
+ goto Done;\r
+ }\r
+\r
+ if (!IsToken (SourceFile, OPEN_BRACE_STRING)) {\r
+ Error (\r
+ SourceFile->FileName,\r
+ SourceFile->LineNum,\r
+ 0,\r
+ NULL,\r
+ "expected %S, not %.20S",\r
+ OPEN_BRACE_STRING,\r
+ SourceFile->FileBufferPtr\r
+ );\r
+ goto Done;\r
+ }\r
+\r
+ while (!EndOfFile (SourceFile)) {\r
+ if (IsToken (SourceFile, CLOSE_BRACE_STRING)) {\r
+ break;\r
+ }\r
+ //\r
+ // Look for language identifier (3 lowercase chars)\r
+ //\r
+ if ((SourceFile->FileBufferPtr[0] >= UNICODE_a) &&\r
+ (SourceFile->FileBufferPtr[0] <= UNICODE_z) &&\r
+ (SourceFile->FileBufferPtr[1] >= UNICODE_a) &&\r
+ (SourceFile->FileBufferPtr[1] <= UNICODE_z) &&\r
+ (SourceFile->FileBufferPtr[2] >= UNICODE_a) &&\r
+ (SourceFile->FileBufferPtr[2] <= UNICODE_z) &&\r
+ IsWhiteSpace (SourceFile->FileBufferPtr[3])\r
+ ) {\r
+ //\r
+ // Write the 3 chars followed by a spacebar, and then look for opening quote\r
+ //\r
+ fwrite (SourceFile->FileBufferPtr, sizeof (WCHAR), 1, OutFptr);\r
+ SourceFile->FileBufferPtr++;\r
+ fwrite (SourceFile->FileBufferPtr, sizeof (WCHAR), 1, OutFptr);\r
+ SourceFile->FileBufferPtr++;\r
+ fwrite (SourceFile->FileBufferPtr, sizeof (WCHAR), 1, OutFptr);\r
+ SourceFile->FileBufferPtr++;\r
+ fwrite (&Spacebar, sizeof (WCHAR), 1, OutFptr);\r
+ StringCount = 0;\r
+ while (IsToken (SourceFile, L"\"")) {\r
+ StringCount++;\r
+ while (!EndOfFile (SourceFile)) {\r
+ if (SourceFile->FileBufferPtr[0] == UNICODE_DOUBLE_QUOTE) {\r
+ SourceFile->FileBufferPtr++;\r
+ break;\r
+ } else if ((SourceFile->FileBufferPtr[0] == UNICODE_LF) || (SourceFile->FileBufferPtr[0] == 0)) {\r
+ Error (SourceFile->FileName, SourceFile->LineNum, 0, "missing closing quote on string", NULL);\r
+ goto Done;\r
+ } else {\r
+ fwrite (SourceFile->FileBufferPtr, sizeof (WCHAR), 1, OutFptr);\r
+ SourceFile->FileBufferPtr++;\r
+ }\r
+ }\r
+ }\r
+\r
+ if (StringCount == 0) {\r
+ Error (\r
+ SourceFile->FileName,\r
+ SourceFile->LineNum,\r
+ 0,\r
+ NULL,\r
+ "expected quoted string, not %.20S",\r
+ SourceFile->FileBufferPtr\r
+ );\r
+ goto Done;\r
+ }\r
+ //\r
+ // This string's null terminator\r
+ //\r
+ fwrite (&Zero, sizeof (WCHAR), 1, OutFptr);\r
+ } else {\r
+ Error (\r
+ SourceFile->FileName,\r
+ SourceFile->LineNum,\r
+ 0,\r
+ NULL,\r
+ "expected valid language identifer, not %.20S",\r
+ SourceFile->FileBufferPtr\r
+ );\r
+ goto Done;\r
+ }\r
+ }\r
+ //\r
+ // Double null terminator\r
+ //\r
+ fwrite (&Zero, sizeof (WCHAR), 1, OutFptr);\r
+ Status = STATUS_SUCCESS;\r
+Done:\r
+ return Status;\r
+}\r
+\r
+static\r
+STATUS\r
+SplitCapsule (\r
+ INT8 *CapsuleFileName\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ We've created an entire capsule image. Now split it up into the \r
+ size pieces they requested.\r
+\r
+Arguments:\r
+ CapsuleFileName - name of an existing capsule file on disk\r
+\r
+Returns:\r
+ STATUS_SUCCESS - if no problems\r
+\r
+Notes:\r
+ This implementation reads in the entire capsule image from\r
+ disk, then overwrites the original file with the first\r
+ in the series.\r
+\r
+--*/\r
+{\r
+#if 0\r
+ EFI_CAPSULE_HEADER *CapHdr;\r
+\r
+ EFI_CAPSULE_HEADER Hdr;\r
+ FILE *CapFptr;\r
+ FILE *OutFptr;\r
+ UINT32 SizeLeft;\r
+ UINT32 CurrentSize;\r
+ UINT32 DataSize;\r
+ UINT32 SequenceNumber;\r
+ INT8 *Buffer;\r
+ INT8 FileName[MAX_PATH];\r
+ STATUS Status;\r
+ UINT32 FileSize;\r
+ //\r
+ // Figure out the total size, then rewind the input file and\r
+ // read the entire thing in\r
+ //\r
+ if ((CapFptr = fopen (CapsuleFileName, "rb")) == NULL) {\r
+ Error (NULL, 0, 0, CapsuleFileName, "failed to open capsule image for reading");\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ OutFptr = NULL;\r
+ Status = STATUS_SUCCESS;\r
+ fseek (CapFptr, 0, SEEK_END);\r
+ SizeLeft = ftell (CapFptr);\r
+ fseek (CapFptr, 0, SEEK_SET);\r
+ CapHdr = (EFI_CAPSULE_HEADER *) malloc (SizeLeft);\r
+ if (CapHdr == NULL) {\r
+ Error (NULL, 0, 0, "memory allocation failure", NULL);\r
+ goto FailDone;\r
+ }\r
+\r
+ if (fread (CapHdr, SizeLeft, 1, CapFptr) != 1) {\r
+ Error (NULL, 0, 0, "failed to read capsule contents", "split failed");\r
+ goto FailDone;\r
+ }\r
+\r
+ fclose (CapFptr);\r
+ CapFptr = NULL;\r
+ //\r
+ // Get a GUID to fill in the InstanceId GUID in the header\r
+ //\r
+ CreateGuid (&CapHdr->InstanceId);\r
+ SequenceNumber = 0;\r
+ //\r
+ // If the split size is larger than the original capsule image, then\r
+ // we're done.\r
+ //\r
+ if (mOptions.SizeList->Size >= SizeLeft) {\r
+ mOptions.SizeList->Size = SizeLeft;\r
+ goto Done;\r
+ }\r
+ //\r
+ // First size has to be big enough for the original header\r
+ //\r
+ if (mOptions.SizeList->Size < CapHdr->OffsetToCapsuleBody) {\r
+ Error (NULL, 0, 0, "first split size is insufficient for the original capsule header", NULL);\r
+ goto FailDone;\r
+ }\r
+ //\r
+ // Initialize the header we'll use on all but the first part\r
+ //\r
+ memset (&Hdr, 0, sizeof (Hdr));\r
+ Hdr.CapsuleGuid = CapHdr->CapsuleGuid;\r
+ Hdr.HeaderSize = sizeof (Hdr);\r
+ Hdr.Flags = CapHdr->Flags;\r
+ Hdr.InstanceId = CapHdr->InstanceId;\r
+ Hdr.CapsuleImageSize = CapHdr->CapsuleImageSize;\r
+ Hdr.OffsetToCapsuleBody = Hdr.HeaderSize;\r
+ Hdr.SequenceNumber = 1;\r
+ //\r
+ // printf ("Created %s - 0x%X bytes\n", CapsuleFileName, mOptions.SizeList->Size);\r
+ //\r
+ Buffer = (UINT8 *) CapHdr;\r
+ //\r
+ // Walk the list of sizes and write out a capsule header, and\r
+ // then the raw capsule data.\r
+ //\r
+ // SizeLeft -= mOptions.SizeList->Size;\r
+ //\r
+ mOptions.CurrentSize = mOptions.SizeList;\r
+ while (SizeLeft) {\r
+ CurrentSize = mOptions.CurrentSize->Size;\r
+ GetSplitFileName (mOptions.OutputFileName, FileName, SequenceNumber);\r
+ if ((OutFptr = fopen (FileName, "wb")) == NULL) {\r
+ Error (NULL, 0, 0, FileName, "failed to open split file for writing");\r
+ goto FailDone;\r
+ }\r
+\r
+ if (Buffer == (UINT8 *) CapHdr) {\r
+ //\r
+ // First part -- write out original header and data\r
+ //\r
+ if (fwrite (Buffer, CurrentSize, 1, OutFptr) != 1) {\r
+ Error (NULL, 0, 0, FileName, "failed to write to split image file");\r
+ goto FailDone;\r
+ }\r
+\r
+ SizeLeft -= CurrentSize;\r
+ Buffer += CurrentSize;\r
+ DataSize = CurrentSize;\r
+ FileSize = CurrentSize;\r
+ } else {\r
+ //\r
+ // Not the first part. Write the default header, and then the raw bytes from the\r
+ // original image.\r
+ //\r
+ if (CurrentSize <= sizeof (Hdr)) {\r
+ Error (NULL, 0, 0, "split size too small for capsule header + data", "0x%X", CurrentSize);\r
+ goto FailDone;\r
+ }\r
+\r
+ DataSize = CurrentSize - sizeof (Hdr);\r
+ if (DataSize > SizeLeft) {\r
+ DataSize = SizeLeft;\r
+ }\r
+\r
+ if (fwrite (&Hdr, sizeof (Hdr), 1, OutFptr) != 1) {\r
+ Error (NULL, 0, 0, FileName, "failed to write capsule header to output file");\r
+ fclose (OutFptr);\r
+ goto FailDone;\r
+ }\r
+\r
+ if (fwrite (Buffer, DataSize, 1, OutFptr) != 1) {\r
+ Error (NULL, 0, 0, FileName, "failed to write capsule data to output file");\r
+ fclose (OutFptr);\r
+ goto FailDone;\r
+ }\r
+\r
+ Hdr.SequenceNumber++;\r
+ Buffer += DataSize;\r
+ SizeLeft -= DataSize;\r
+ FileSize = DataSize + sizeof (Hdr);\r
+ }\r
+ //\r
+ // Next size in list if there is one\r
+ //\r
+ if (mOptions.CurrentSize->Next != NULL) {\r
+ mOptions.CurrentSize = mOptions.CurrentSize->Next;\r
+ }\r
+\r
+ SequenceNumber++;\r
+ fclose (OutFptr);\r
+ OutFptr = NULL;\r
+ printf ("Created %s - 0x%X bytes (0x%X bytes of data)\n", FileName, FileSize, DataSize);\r
+ }\r
+\r
+ goto Done;\r
+FailDone:\r
+ Status = STATUS_ERROR;\r
+Done:\r
+ if (CapHdr != NULL) {\r
+ free (CapHdr);\r
+ }\r
+\r
+ if (CapFptr != NULL) {\r
+ fclose (CapFptr);\r
+ }\r
+\r
+ if (OutFptr != NULL) {\r
+ fclose (OutFptr);\r
+ }\r
+\r
+ return Status;\r
+\r
+#endif\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+static\r
+BOOLEAN\r
+GetSplitFileName (\r
+ INT8 *BaseFileName,\r
+ INT8 *NewFileName,\r
+ UINT32 SequenceNumber\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ BaseFileName - GC_TODO: add argument description\r
+ NewFileName - GC_TODO: add argument description\r
+ SequenceNumber - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ /*++\r
+\r
+Routine Description:\r
+ Given an initial split capsule file name and a sequence number,\r
+ create an appropriate file name for this split of a capsule image.\r
+\r
+Arguments:\r
+ BaseFileName - name of of the first split file in the series\r
+ NewFileName - output name of the split file\r
+ SequenceNumber - 0-based sequence number of split images\r
+\r
+Returns:\r
+ TRUE - name created successfully\r
+ FALSE - otherwise\r
+\r
+--*/\r
+ INT8 *Ptr;\r
+ INT8 *Part2Start;\r
+ UINT32 Digits;\r
+ UINT32 Len;\r
+ UINT32 BaseOffset;\r
+ //\r
+ // Work back from the end of the file name and see if there is a number somewhere\r
+ //\r
+ for (Ptr = BaseFileName + strlen (BaseFileName) - 1; (Ptr > BaseFileName) && !isdigit (*Ptr); Ptr--)\r
+ ;\r
+ if ((Ptr == BaseFileName) && (!isdigit (*Ptr))) {\r
+ //\r
+ // Found no number, so just add it to the end\r
+ //\r
+ sprintf (NewFileName, "%s%d", BaseFileName, SequenceNumber);\r
+ return TRUE;\r
+ } else {\r
+ //\r
+ // Found a number. Look back to find the first digit.\r
+ //\r
+ Part2Start = Ptr + 1;\r
+ for (Digits = 1; isdigit (*Ptr) && (Ptr > BaseFileName); Ptr--, Digits++)\r
+ ;\r
+ if (!isdigit (*Ptr)) {\r
+ Ptr++;\r
+ Digits--;\r
+ }\r
+\r
+ BaseOffset = atoi (Ptr);\r
+ SequenceNumber = SequenceNumber + BaseOffset;\r
+ if (Digits > 1) {\r
+ //\r
+ // Copy the first part of the original file name to the new filename\r
+ // This is the path for filenames with format path\name001.cap\r
+ //\r
+ Len = (UINT32) Ptr - (UINT32) BaseFileName;\r
+ strncpy (NewFileName, BaseFileName, Len);\r
+ sprintf (NewFileName + Len, "%0*d", Digits, SequenceNumber);\r
+ strcat (NewFileName, Part2Start);\r
+ return TRUE;\r
+ } else {\r
+ //\r
+ // Only one digit found. This is the path for filenames with\r
+ // format path\name1.cap\r
+ //\r
+ Len = (UINT32) Ptr - (UINT32) BaseFileName + 1;\r
+ strncpy (NewFileName, BaseFileName, Len);\r
+ sprintf (NewFileName + Len - 1, "%d", SequenceNumber);\r
+ strcat (NewFileName, Part2Start);\r
+ return TRUE;\r
+ }\r
+ }\r
+}\r
+\r
+static\r
+BOOLEAN\r
+IsWhiteSpace (\r
+ WCHAR Char\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ Char - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ switch (Char) {\r
+ case UNICODE_SPACE:\r
+ case UNICODE_TAB:\r
+ case UNICODE_NULL:\r
+ case UNICODE_CR:\r
+ case UNICODE_LF:\r
+ return TRUE;\r
+\r
+ default:\r
+ return FALSE;\r
+ }\r
+}\r
+\r
+static\r
+BOOLEAN\r
+IsToken (\r
+ SOURCE_FILE *File,\r
+ WCHAR *Token\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ File - GC_TODO: add argument description\r
+ Token - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ SkipWhiteSpace (File);\r
+ if (EndOfFile (File)) {\r
+ return FALSE;\r
+ }\r
+\r
+ if (wcsncmp (Token, File->FileBufferPtr, wcslen (Token)) == 0) {\r
+ File->FileBufferPtr += wcslen (Token);\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+static\r
+STATUS\r
+CheckFirmwareVolumeHeader (\r
+ INT8 *FileName,\r
+ INT8 *Buffer,\r
+ UINT32 BufferSize\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ FileName - GC_TODO: add argument description\r
+ Buffer - GC_TODO: add argument description\r
+ BufferSize - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ EFI_FIRMWARE_VOLUME_HEADER *Hdr;\r
+ EFI_GUID FVHeaderGuid = EFI_FIRMWARE_FILE_SYSTEM_GUID;\r
+\r
+ Hdr = (EFI_FIRMWARE_VOLUME_HEADER *) Buffer;\r
+ if (Hdr->Signature != EFI_FVH_SIGNATURE) {\r
+ Error (NULL, 0, 0, FileName, "file does not appear to be a firmware volume (bad signature)");\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ if (Hdr->Revision != EFI_FVH_REVISION) {\r
+ Error (NULL, 0, 0, FileName, "unsupported firmware volume header version");\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ if (Hdr->FvLength > BufferSize) {\r
+ Error (NULL, 0, 0, FileName, "malformed firmware volume -- FvLength > file size");\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ if (memcmp (&Hdr->FileSystemGuid, &FVHeaderGuid, sizeof (EFI_GUID)) != 0) {\r
+ Error (NULL, 0, 0, FileName, "invalid FFS GUID in firmware volume header");\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+static\r
+void\r
+DumpCapsule (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ None\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+#if 0\r
+ FILE *InFptr;\r
+ FILE_LIST *FileList;\r
+ EFI_CAPSULE_HEADER CapsuleHeader;\r
+ EFI_FIRMWARE_VOLUME_HEADER FVHeader;\r
+ EFI_CAPSULE_OEM_HEADER *OemHeader;\r
+ UINT8 *BPtr;\r
+ UINT32 FileSize;\r
+ UINT32 CapsuleHeaderDataSize;\r
+ UINT8 ByteCount;\r
+ UINT8 *CapsuleHeaderData;\r
+ BOOLEAN SplitImage;\r
+\r
+ InFptr = NULL;\r
+ CapsuleHeaderData = NULL;\r
+ FileList = mOptions.FileList;\r
+ while (FileList != NULL) {\r
+ if ((InFptr = fopen (FileList->FileName, "rb")) == NULL) {\r
+ Error (NULL, 0, 0, FileList->FileName, "failed to open file for reading");\r
+ goto Done;\r
+ }\r
+\r
+ if (fread (&CapsuleHeader, sizeof (EFI_CAPSULE_HEADER), 1, InFptr) != 1) {\r
+ Error (NULL, 0, 0, FileList->FileName, "failed to read capsule header");\r
+ goto Done;\r
+ }\r
+\r
+ fseek (InFptr, 0, SEEK_END);\r
+ FileSize = ftell (InFptr);\r
+ if (CapsuleHeader.CapsuleImageSize > FileSize) {\r
+ SplitImage = TRUE;\r
+ } else {\r
+ SplitImage = FALSE;\r
+ }\r
+\r
+ printf (\r
+ "Capsule %s Size=0x%X CargoSize=0x%X\n",\r
+ FileList->FileName,\r
+ FileSize,\r
+ FileSize - CapsuleHeader.OffsetToCapsuleBody\r
+ );\r
+ printf (\r
+ " GUID %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",\r
+ CapsuleHeader.CapsuleGuid.Data1,\r
+ (UINT32) CapsuleHeader.CapsuleGuid.Data2,\r
+ (UINT32) CapsuleHeader.CapsuleGuid.Data3,\r
+ (UINT32) CapsuleHeader.CapsuleGuid.Data4[0],\r
+ (UINT32) CapsuleHeader.CapsuleGuid.Data4[1],\r
+ (UINT32) CapsuleHeader.CapsuleGuid.Data4[2],\r
+ (UINT32) CapsuleHeader.CapsuleGuid.Data4[3],\r
+ (UINT32) CapsuleHeader.CapsuleGuid.Data4[4],\r
+ (UINT32) CapsuleHeader.CapsuleGuid.Data4[5],\r
+ (UINT32) CapsuleHeader.CapsuleGuid.Data4[6],\r
+ (UINT32) CapsuleHeader.CapsuleGuid.Data4[7]\r
+ );\r
+ if (memcmp (&CapsuleHeader.CapsuleGuid, &mEfiCapsuleHeaderGuid, sizeof (EFI_GUID)) != 0) {\r
+ printf (" INVALID GUID");\r
+ }\r
+\r
+ printf ("\n");\r
+ printf (" Header size 0x%08X\n", CapsuleHeader.HeaderSize);\r
+ printf (" Flags 0x%08X\n", CapsuleHeader.Flags);\r
+ if (!SplitImage) {\r
+ printf (" Capsule image size 0x%08X\n", CapsuleHeader.CapsuleImageSize);\r
+ } else {\r
+ printf (" Capsule image size 0x%08X (split)\n", CapsuleHeader.CapsuleImageSize);\r
+ }\r
+\r
+ printf (" Sequence number %d\n", CapsuleHeader.SequenceNumber);\r
+ printf (\r
+ " InstanceId %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",\r
+ CapsuleHeader.InstanceId.Data1,\r
+ (UINT32) CapsuleHeader.InstanceId.Data2,\r
+ (UINT32) CapsuleHeader.InstanceId.Data3,\r
+ (UINT32) CapsuleHeader.InstanceId.Data4[0],\r
+ (UINT32) CapsuleHeader.InstanceId.Data4[1],\r
+ (UINT32) CapsuleHeader.InstanceId.Data4[2],\r
+ (UINT32) CapsuleHeader.InstanceId.Data4[3],\r
+ (UINT32) CapsuleHeader.InstanceId.Data4[4],\r
+ (UINT32) CapsuleHeader.InstanceId.Data4[5],\r
+ (UINT32) CapsuleHeader.InstanceId.Data4[6],\r
+ (UINT32) CapsuleHeader.InstanceId.Data4[7]\r
+ );\r
+ printf (" Offset to capsule 0x%X\n", CapsuleHeader.OffsetToCapsuleBody);\r
+ //\r
+ // Dump header data if there\r
+ //\r
+ CapsuleHeaderDataSize = CapsuleHeader.OffsetToCapsuleBody - CapsuleHeader.HeaderSize;\r
+ if (CapsuleHeaderDataSize != 0) {\r
+ CapsuleHeaderData = (UINT8 *) malloc (CapsuleHeaderDataSize);\r
+ if (CapsuleHeaderData == NULL) {\r
+ Error (\r
+ NULL,\r
+ 0,\r
+ 0,\r
+ "failed to allocate memory to read in capsule header data",\r
+ "0x%X bytes",\r
+ CapsuleHeaderDataSize\r
+ );\r
+ goto Done;\r
+ }\r
+\r
+ fseek (InFptr, CapsuleHeader.HeaderSize, SEEK_SET);\r
+ if (fread (CapsuleHeaderData, CapsuleHeaderDataSize, 1, InFptr) != 1) {\r
+ Error (\r
+ NULL,\r
+ 0,\r
+ 0,\r
+ "failed to read capsule header data contents from file",\r
+ "0x%X bytes",\r
+ CapsuleHeaderDataSize\r
+ );\r
+ goto Done;\r
+ }\r
+ //\r
+ // ************************************************************************\r
+ //\r
+ // OEM HEADER\r
+ //\r
+ // ************************************************************************\r
+ //\r
+ if (CapsuleHeader.OffsetToOemDefinedHeader != 0) {\r
+ OemHeader = (EFI_CAPSULE_OEM_HEADER *) (CapsuleHeaderData + CapsuleHeader.OffsetToOemDefinedHeader - CapsuleHeader.HeaderSize);\r
+ printf (" OEM Header\n");\r
+ printf (\r
+ " GUID %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",\r
+ OemHeader->OemGuid.Data1,\r
+ (UINT32) OemHeader->OemGuid.Data2,\r
+ (UINT32) OemHeader->OemGuid.Data3,\r
+ (UINT32) OemHeader->OemGuid.Data4[0],\r
+ (UINT32) OemHeader->OemGuid.Data4[1],\r
+ (UINT32) OemHeader->OemGuid.Data4[2],\r
+ (UINT32) OemHeader->OemGuid.Data4[3],\r
+ (UINT32) OemHeader->OemGuid.Data4[4],\r
+ (UINT32) OemHeader->OemGuid.Data4[5],\r
+ (UINT32) OemHeader->OemGuid.Data4[6],\r
+ (UINT32) OemHeader->OemGuid.Data4[7]\r
+ );\r
+ printf (" Header size: 0x%X\n", OemHeader->HeaderSize);\r
+ printf (" OEM data");\r
+ BPtr = (UINT8 *) (OemHeader + 1);\r
+ for (ByteCount = 0; ByteCount < OemHeader->HeaderSize - sizeof (EFI_CAPSULE_OEM_HEADER); ByteCount++) {\r
+ if ((ByteCount & 0x7) == 0) {\r
+ printf ("\n ");\r
+ }\r
+\r
+ printf ("%02X ", (UINT32) *BPtr);\r
+ BPtr++;\r
+ }\r
+\r
+ printf ("\n");\r
+ }\r
+ //\r
+ // ************************************************************************\r
+ //\r
+ // Author, revision, short description, and long description information\r
+ //\r
+ // ************************************************************************\r
+ //\r
+ if (CapsuleHeader.OffsetToAuthorInformation != 0) {\r
+ if (DumpCapsuleHeaderStrings (\r
+ "Author information",\r
+ (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToAuthorInformation - CapsuleHeader.HeaderSize)\r
+ ) != STATUS_SUCCESS) {\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ if (CapsuleHeader.OffsetToRevisionInformation != 0) {\r
+ if (DumpCapsuleHeaderStrings (\r
+ "Revision information",\r
+ (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToRevisionInformation - CapsuleHeader.HeaderSize)\r
+ ) != STATUS_SUCCESS) {\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ if (CapsuleHeader.OffsetToShortDescription != 0) {\r
+ if (DumpCapsuleHeaderStrings (\r
+ "Short description",\r
+ (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToShortDescription - CapsuleHeader.HeaderSize)\r
+ ) != STATUS_SUCCESS) {\r
+ goto Done;\r
+ }\r
+ }\r
+\r
+ if (CapsuleHeader.OffsetToLongDescription != 0) {\r
+ if (DumpCapsuleHeaderStrings (\r
+ "Long description",\r
+ (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToLongDescription - CapsuleHeader.HeaderSize)\r
+ ) != STATUS_SUCCESS) {\r
+ goto Done;\r
+ }\r
+ }\r
+ }\r
+ //\r
+ // If it's not a split image, or it is a split image and this is the first in the series, then\r
+ // dump the cargo volume.\r
+ //\r
+ if ((!SplitImage) || (CapsuleHeader.SequenceNumber == 0)) {\r
+ printf (" Cargo FV dump\n");\r
+ fseek (InFptr, CapsuleHeader.OffsetToCapsuleBody, SEEK_SET);\r
+ if (fread (&FVHeader, sizeof (EFI_FIRMWARE_VOLUME_HEADER), 1, InFptr) != 1) {\r
+ Error (NULL, 0, 0, FileList->FileName, "failed to read cargo FV header");\r
+ goto Done;\r
+ }\r
+\r
+ printf (" FV length 0x%X", FVHeader.FvLength);\r
+ if (FileSize - CapsuleHeader.OffsetToCapsuleBody != FVHeader.FvLength) {\r
+ if (!SplitImage) {\r
+ printf (" ERROR: expected 0x%X to jive with file size on disk", FileSize - CapsuleHeader.OffsetToCapsuleBody);\r
+ }\r
+ }\r
+\r
+ printf ("\n");\r
+ printf (" Signature 0x%X ", FVHeader.Signature);\r
+ if (FVHeader.Signature == EFI_FVH_SIGNATURE) {\r
+ printf ("_FVH\n");\r
+ } else {\r
+ printf ("INVALID\n");\r
+ }\r
+\r
+ printf (" FV header length 0x%X\n", (UINT32) FVHeader.HeaderLength);\r
+ printf (" Revision 0x%X\n", (UINT32) FVHeader.Revision);\r
+ printf ("\n");\r
+ }\r
+\r
+ FileList = FileList->Next;\r
+ }\r
+\r
+Done:\r
+ if (InFptr != NULL) {\r
+ fclose (InFptr);\r
+ }\r
+\r
+ if (CapsuleHeaderData != NULL) {\r
+ free (CapsuleHeaderData);\r
+ }\r
+#endif\r
+}\r
+\r
+static\r
+STATUS\r
+JoinCapsule (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Join split capsule images into a single image. This is the\r
+ support function for the -j command-line option.\r
+\r
+Arguments:\r
+ None.\r
+\r
+Returns:\r
+ STATUS_SUCCESS - no problems encountered\r
+\r
+--*/\r
+{\r
+#if 0\r
+ UINT32 Size;\r
+ FILE *InFptr;\r
+ FILE *OutFptr;\r
+ INT8 *Buffer;\r
+ FILE_LIST *FileList;\r
+ STATUS Status;\r
+ EFI_CAPSULE_HEADER CapHdr;\r
+ EFI_CAPSULE_HEADER *CapHdrPtr;\r
+ UINT32 SizeLeft;\r
+ UINT32 SequenceNumber;\r
+ //\r
+ // Must have at least two files for join mode\r
+ //\r
+ if ((mOptions.FileList == NULL) || (mOptions.FileList->Next == NULL)) {\r
+ Error (NULL, 0, 0, "must specify at least two file names to join", NULL);\r
+ return STATUS_ERROR;\r
+ }\r
+ //\r
+ // Open the output file\r
+ //\r
+ if ((OutFptr = fopen (mOptions.OutputFileName, "wb")) == NULL) {\r
+ Error (NULL, 0, 0, mOptions.OutputFileName, "failed to open output file for writing");\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ FileList = mOptions.FileList;\r
+ Buffer = NULL;\r
+ SequenceNumber = 0;\r
+ InFptr = NULL;\r
+ SizeLeft = 0;\r
+ while (FileList != NULL) {\r
+ if ((InFptr = fopen (FileList->FileName, "rb")) == NULL) {\r
+ Error (NULL, 0, 0, FileList->FileName, "failed to open file for reading");\r
+ goto FailDone;\r
+ }\r
+ //\r
+ // Allocate a buffer into which we can read the file.\r
+ //\r
+ fseek (InFptr, 0, SEEK_END);\r
+ Size = ftell (InFptr);\r
+ rewind (InFptr);\r
+ Buffer = (char *) malloc (Size);\r
+ if (Buffer == NULL) {\r
+ Error (__FILE__, __LINE__, 0, FileList->FileName, "failed to allocate buffer to read file into");\r
+ goto FailDone;\r
+ }\r
+\r
+ CapHdrPtr = (EFI_CAPSULE_HEADER *) Buffer;\r
+ if (fread ((void *) Buffer, Size, 1, InFptr) != 1) {\r
+ Error (NULL, 0, 0, FileList->FileName, "failed to read file contents");\r
+ goto FailDone;\r
+ }\r
+ //\r
+ // Check the header for validity. Check size first.\r
+ //\r
+ if (Size < sizeof (EFI_CAPSULE_HEADER)) {\r
+ Error (NULL, 0, 0, FileList->FileName, "file size is insufficient for a capsule header");\r
+ goto FailDone;\r
+ }\r
+ //\r
+ // Check GUID\r
+ //\r
+ if (memcmp (&CapHdrPtr->CapsuleGuid, &mEfiCapsuleHeaderGuid, sizeof (EFI_GUID)) != 0) {\r
+ Error (NULL, 0, 0, FileList->FileName, "invalid capsule GUID");\r
+ goto FailDone;\r
+ }\r
+ //\r
+ // Check sequence number\r
+ //\r
+ if (CapHdrPtr->SequenceNumber != SequenceNumber) {\r
+ Error (\r
+ NULL,\r
+ 0,\r
+ 0,\r
+ FileList->FileName,\r
+ "invalid sequence number %d (expected %d)",\r
+ CapHdrPtr->SequenceNumber,\r
+ SequenceNumber\r
+ );\r
+ goto FailDone;\r
+ }\r
+ //\r
+ // If the first file, read save the capsule header\r
+ //\r
+ if (SequenceNumber == 0) {\r
+ memcpy (&CapHdr, CapHdrPtr, sizeof (EFI_CAPSULE_HEADER));\r
+ //\r
+ // Erase the InstanceId GUID\r
+ //\r
+ memset (&CapHdrPtr->InstanceId, 0, sizeof (EFI_GUID));\r
+ if (fwrite (Buffer, Size, 1, OutFptr) != 1) {\r
+ Error (NULL, 0, 0, FileList->FileName, "failed to write contents to output file");\r
+ goto FailDone;\r
+ }\r
+\r
+ if (CapHdr.CapsuleImageSize < Size) {\r
+ Error (NULL, 0, 0, FileList->FileName, "capsule image size in capsule header < image size");\r
+ goto FailDone;\r
+ }\r
+\r
+ SizeLeft = CapHdr.CapsuleImageSize - Size;\r
+ } else {\r
+ //\r
+ // Check the GUID against the first file's GUID\r
+ //\r
+ if (memcmp (&CapHdr.CapsuleGuid, &CapHdrPtr->CapsuleGuid, sizeof (EFI_GUID)) != 0) {\r
+ Error (NULL, 0, 0, FileList->FileName, "GUID does not match first file's GUID");\r
+ goto FailDone;\r
+ }\r
+ //\r
+ // Make sure we're not throwing out any header info\r
+ //\r
+ if (CapHdrPtr->OffsetToCapsuleBody > sizeof (EFI_CAPSULE_HEADER)) {\r
+ //\r
+ // Could be the split information, so just emit a warning\r
+ //\r
+ Warning (\r
+ NULL,\r
+ 0,\r
+ 0,\r
+ FileList->FileName,\r
+ "image appears to have additional capsule header information -- ignoring"\r
+ );\r
+ } else if (CapHdrPtr->OffsetToCapsuleBody < sizeof (EFI_CAPSULE_HEADER)) {\r
+ Error (NULL, 0, 0, FileList->FileName, "offset to capsule body in capsule header is insufficient");\r
+ goto FailDone;\r
+ }\r
+\r
+ if (fwrite (Buffer + CapHdrPtr->OffsetToCapsuleBody, Size - CapHdrPtr->OffsetToCapsuleBody, 1, OutFptr) != 1) {\r
+ Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");\r
+ goto FailDone;\r
+ }\r
+\r
+ if (SizeLeft < (Size - CapHdrPtr->OffsetToCapsuleBody)) {\r
+ Error (NULL, 0, 0, "sum of image sizes exceeds size specified in initial capsule header", NULL);\r
+ goto FailDone;\r
+ }\r
+ //\r
+ // printf ("FILE: %s OffsetToCapsuleBody=0x%X\n", FileList->FileName, CapHdrPtr->OffsetToCapsuleBody);\r
+ //\r
+ SizeLeft = SizeLeft - (Size - CapHdrPtr->OffsetToCapsuleBody);\r
+ }\r
+ //\r
+ // printf ("FILE: %s sizeleft=0x%X\n", FileList->FileName, SizeLeft);\r
+ //\r
+ fclose (InFptr);\r
+ InFptr = NULL;\r
+ free (Buffer);\r
+ Buffer = NULL;\r
+ FileList = FileList->Next;\r
+ SequenceNumber++;\r
+ }\r
+\r
+ if (SizeLeft) {\r
+ Error (NULL, 0, 0, "sum of capsule images is insufficient", "0x%X bytes missing", SizeLeft);\r
+ goto FailDone;\r
+ }\r
+\r
+ Status = STATUS_SUCCESS;\r
+ goto Done;\r
+FailDone:\r
+ Status = STATUS_ERROR;\r
+Done:\r
+ if (InFptr != NULL) {\r
+ fclose (InFptr);\r
+ }\r
+\r
+ if (OutFptr != NULL) {\r
+ fclose (OutFptr);\r
+ }\r
+\r
+ if (Buffer != NULL) {\r
+ free (Buffer);\r
+ }\r
+\r
+ return Status;\r
+\r
+#endif\r
+return STATUS_SUCCESS;\r
+}\r
+\r
+static\r
+STATUS\r
+DumpCapsuleHeaderStrings (\r
+ UINT8 *SectionName,\r
+ WCHAR *Buffer\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Given a pointer to string data from a capsule header, dump\r
+ the strings.\r
+\r
+Arguments:\r
+ SectionName - name of the capsule header section to which\r
+ the string data pertains\r
+ Buffer - pointer to string data from a capsule header\r
+\r
+Returns:\r
+ STATUS_SUCCESS - all went well\r
+\r
+--*/\r
+{\r
+ printf (" %s\n", SectionName);\r
+ while (*Buffer) {\r
+ printf (" Language: %S\n", Buffer);\r
+ while (*Buffer) {\r
+ Buffer++;\r
+ }\r
+\r
+ Buffer++;\r
+ while (*Buffer) {\r
+ if (wcslen (Buffer) > 60) {\r
+ printf (" %.60S\n", Buffer);\r
+ Buffer += 60;\r
+ } else {\r
+ printf (" %S\n", Buffer);\r
+ Buffer += wcslen (Buffer);\r
+ }\r
+ }\r
+\r
+ Buffer++;\r
+ }\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+static\r
+STATUS\r
+GetHexValue (\r
+ SOURCE_FILE *SourceFile,\r
+ UINT32 *Value,\r
+ UINT32 NumDigits\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+ Scan a hex value from the input stream.\r
+ \r
+Arguments:\r
+ SourceFile - input file contents\r
+ Value - returned value\r
+ NumDigits - number of digits to read\r
+\r
+Returns:\r
+ STATUS_SUCCESS - if NumDigits were read from the file\r
+ STATUS_ERROR - otherwise\r
+\r
+ \r
+--*/\r
+{\r
+ WCHAR *SaveFilePos;\r
+ UINT32 Digits;\r
+ WCHAR Nibble;\r
+\r
+ SaveFilePos = SourceFile->FileBufferPtr;\r
+ *Value = 0;\r
+ Digits = NumDigits;\r
+ while (Digits > 0) {\r
+ Nibble = SourceFile->FileBufferPtr[0];\r
+ if ((Nibble >= UNICODE_0) && (Nibble <= UNICODE_9)) {\r
+ *Value = (*Value << 4) | (Nibble - UNICODE_0);\r
+ } else if ((Nibble >= UNICODE_A) && (Nibble <= UNICODE_F)) {\r
+ *Value = (*Value << 4) | (Nibble - UNICODE_A + 0x10);\r
+ } else if ((Nibble >= UNICODE_a) && (Nibble <= UNICODE_f)) {\r
+ *Value = (*Value << 4) | (Nibble - UNICODE_a + 0x10);\r
+ } else {\r
+ Error (\r
+ SourceFile->FileName,\r
+ SourceFile->LineNum,\r
+ 0,\r
+ NULL,\r
+ "expected %d valid hex nibbles at %.20S",\r
+ NumDigits,\r
+ SaveFilePos\r
+ );\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ SourceFile->FileBufferPtr++;\r
+ Digits--;\r
+ }\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+static\r
+BOOLEAN\r
+EndOfFile (\r
+ SOURCE_FILE *File\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ File - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ if ((UINT32) File->FileBufferPtr - (UINT32) File->FileBuffer >= File->FileSize) {\r
+ File->EndOfFile = TRUE;\r
+ }\r
+ //\r
+ // Reposition to the end of the file if we went beyond\r
+ //\r
+ if (File->EndOfFile) {\r
+ File->FileBufferPtr = File->FileBuffer + File->FileSize / sizeof (WCHAR);\r
+ }\r
+\r
+ return File->EndOfFile;\r
+}\r
+\r
+static\r
+void\r
+SkipWhiteSpace (\r
+ SOURCE_FILE *SourceFile\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ SourceFile - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ while (!EndOfFile (SourceFile)) {\r
+ switch (*SourceFile->FileBufferPtr) {\r
+ case UNICODE_NULL:\r
+ case UNICODE_CR:\r
+ case UNICODE_SPACE:\r
+ case UNICODE_TAB:\r
+ SourceFile->FileBufferPtr++;\r
+ break;\r
+\r
+ case UNICODE_LF:\r
+ SourceFile->FileBufferPtr++;\r
+ SourceFile->LineNum++;\r
+ break;\r
+\r
+ default:\r
+ return ;\r
+ }\r
+ }\r
+}\r
+//\r
+// Parse a number. Possible format:\r
+// 1234\r
+// 1234k\r
+// 1234K\r
+// 1M\r
+// 1m\r
+// 0x100\r
+//\r
+static\r
+BOOLEAN\r
+GetNumber (\r
+ INT8 *Str,\r
+ UINT32 *Value\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ GC_TODO: Add function description\r
+\r
+Arguments:\r
+\r
+ Str - GC_TODO: add argument description\r
+ Value - GC_TODO: add argument description\r
+\r
+Returns:\r
+\r
+ GC_TODO: add return values\r
+\r
+--*/\r
+{\r
+ UINT32 LValue;\r
+\r
+ *Value = 0;\r
+ LValue = 0;\r
+ if (!isdigit (Str[0])) {\r
+ return FALSE;\r
+ }\r
+ //\r
+ // Look for hex number\r
+ //\r
+ if ((Str[0] == '0') && (tolower (Str[1]) == 'x')) {\r
+ Str += 2;\r
+ if (Str[0] == 0) {\r
+ return FALSE;\r
+ }\r
+\r
+ while (Str[0]) {\r
+ if ((Str[0] >= '0') && (Str[0] <= '9')) {\r
+ LValue = (LValue << 4) | (Str[0] - '0');\r
+ } else if ((Str[0] >= 'A') && (Str[0] <= 'F')) {\r
+ LValue = (LValue << 4) | (Str[0] - 'A' + 0x10);\r
+ } else if ((Str[0] >= 'a') && (Str[0] <= 'f')) {\r
+ LValue = (LValue << 4) | (Str[0] - 'a' + 0x10);\r
+ } else {\r
+ break;\r
+ }\r
+\r
+ Str++;\r
+ }\r
+ } else {\r
+ LValue = atoi (Str);\r
+ while (isdigit (*Str)) {\r
+ Str++;\r
+ }\r
+ }\r
+ //\r
+ // If string left over, better be one character we recognize\r
+ //\r
+ if (Str[0]) {\r
+ if (Str[1]) {\r
+ return FALSE;\r
+ }\r
+\r
+ switch (Str[0]) {\r
+ case 'k':\r
+ case 'K':\r
+ LValue *= 1024;\r
+ break;\r
+\r
+ case 'm':\r
+ case 'M':\r
+ LValue *= 1024 * 1024;\r
+ break;\r
+\r
+ default:\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ *Value = LValue;\r
+ return TRUE;\r
+}\r
+//\r
+// Process the command-line arguments\r
+//\r
+static\r
+STATUS\r
+ProcessArgs (\r
+ int Argc,\r
+ char *Argv[]\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Processes command line arguments.\r
+\r
+Arguments:\r
+\r
+ Argc - Number of command line arguments\r
+ Argv[] - Array of files input on command line \r
+\r
+Returns:\r
+\r
+ STATUS_ERROR - Function exited with an error\r
+ STATUS_SUCCESS - Function executed successfully\r
+\r
+--*/\r
+{\r
+ FILE_LIST *NewFile;\r
+\r
+ FILE_LIST *LastFile;\r
+ SIZE_LIST *NewSize;\r
+ \r
+ NewFile = NULL;\r
+ NewSize = NULL;\r
+ \r
+ //\r
+ // Clear our globals\r
+ //\r
+ memset ((char *) &mOptions, 0, sizeof (mOptions));\r
+\r
+ //\r
+ // Skip program name\r
+ //\r
+ Argc--;\r
+ Argv++;\r
+\r
+ if (Argc == 0) {\r
+ Usage ();\r
+ return STATUS_ERROR;\r
+ }\r
+ //\r
+ // Process until no more options\r
+ //\r
+ while ((Argc > 0) && (Argv[0][0] == '-')) {\r
+ if (stricmp (Argv[0], "-script") == 0) {\r
+ //\r
+ // Check for one more arg\r
+ //\r
+ if (Argc > 1) {\r
+ //\r
+ // Save the file name\r
+ //\r
+ if (strlen (Argv[1]) >= sizeof (mOptions.ScriptFileName)) {\r
+ Error (NULL, 0, 0, NULL, "input script file name length exceeds internal buffer size");\r
+ \r
+ if (NewFile != NULL) {\r
+ free (NewFile);\r
+ }\r
+ if (NewSize != NULL) {\r
+ free (NewSize);\r
+ }\r
+ \r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ strcpy (mOptions.ScriptFileName, Argv[1]);\r
+ } else {\r
+ Error (NULL, 0, 0, Argv[0], "missing script file name with option");\r
+ Usage ();\r
+ \r
+ if (NewFile != NULL) {\r
+ free (NewFile);\r
+ }\r
+ if (NewSize != NULL) {\r
+ free (NewSize);\r
+ } \r
+\r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ Argc--;\r
+ Argv++;\r
+ //\r
+ // -o outfilename -- specify output file name (required)\r
+ //\r
+ } else if (stricmp (Argv[0], "-o") == 0) {\r
+ //\r
+ // check for one more arg\r
+ //\r
+ if (Argc > 1) {\r
+ //\r
+ // Try to open the file\r
+ //\r
+ // if ((mOptions.OutFptr = fopen (Argv[1], "wb")) == NULL) {\r
+ // Error (NULL, 0, 0, Argv[1], "failed to open output file for writing");\r
+ // return STATUS_ERROR;\r
+ // }\r
+ //\r
+ strcpy (mOptions.OutputFileName, Argv[1]);\r
+ } else {\r
+ Error (NULL, 0, 0, Argv[0], "missing output filename with option");\r
+ Usage ();\r
+ \r
+ if (NewFile != NULL) {\r
+ free (NewFile);\r
+ }\r
+ if (NewSize != NULL) {\r
+ free (NewSize);\r
+ }\r
+ \r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ Argc--;\r
+ Argv++;\r
+ } else if (stricmp (Argv[0], "-j") == 0) {\r
+ mOptions.JoinMode = TRUE;\r
+ //\r
+ // -split <size> option (multiple allowed)\r
+ //\r
+ } else if (stricmp (Argv[0], "-split") == 0) {\r
+ if (Argc > 1) {\r
+ NewSize = (SIZE_LIST *) malloc (sizeof (SIZE_LIST));\r
+ if (NewSize == NULL) {\r
+ Error (NULL, 0, 0, "memory allocation failure", NULL);\r
+\r
+ if (NewFile != NULL) {\r
+ free (NewFile);\r
+ }\r
+ if (NewSize != NULL) {\r
+ free (NewSize);\r
+ }\r
+ \r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ memset (NewSize, 0, sizeof (SIZE_LIST));\r
+ //\r
+ // Get the size from the next arg, and then add this size\r
+ // to our size list\r
+ //\r
+ if (!GetNumber (Argv[1], &NewSize->Size)) {\r
+ Error (NULL, 0, 0, Argv[1], "invalid split size argument");\r
+\r
+ if (NewFile != NULL) {\r
+ free (NewFile);\r
+ }\r
+ if (NewSize != NULL) {\r
+ free (NewSize);\r
+ } \r
+ \r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ if (mOptions.SizeList == NULL) {\r
+ mOptions.SizeList = NewSize;\r
+ mOptions.CurrentSize = NewSize;\r
+ } else {\r
+ mOptions.LastSize->Next = NewSize;\r
+ }\r
+\r
+ mOptions.LastSize = NewSize;\r
+ free (NewSize);\r
+ } else {\r
+ Error (NULL, 0, 0, Argv[0], "missing size parameter with option");\r
+ Usage ();\r
+\r
+ if (NewFile != NULL) {\r
+ free (NewFile);\r
+ }\r
+ if (NewSize != NULL) {\r
+ free (NewSize);\r
+ }\r
+ \r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ Argc--;\r
+ Argv++; \r
+ } else if ((stricmp (Argv[0], "-h") == 0) || (strcmp (Argv[0], "-?") == 0)) {\r
+ Usage ();\r
+ \r
+ if (NewFile != NULL) {\r
+ free (NewFile);\r
+ }\r
+ if (NewSize != NULL) {\r
+ free (NewSize);\r
+ }\r
+ \r
+ return STATUS_ERROR;\r
+ //\r
+ // Default minimum header\r
+ //\r
+ } else if (stricmp (Argv[0], "-dump") == 0) {\r
+ mOptions.Dump = TRUE;\r
+ } else if (stricmp (Argv[0], "-v") == 0) {\r
+ mOptions.Verbose = TRUE;\r
+ } else {\r
+ Error (NULL, 0, 0, Argv[0], "unrecognized option");\r
+ Usage ();\r
+ \r
+ if (NewFile != NULL) {\r
+ free (NewFile);\r
+ }\r
+ if (NewSize != NULL) {\r
+ free (NewSize);\r
+ }\r
+ \r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ Argc--;\r
+ Argv++;\r
+ }\r
+ //\r
+ // Can't -j join files and -s split output capsule\r
+ //\r
+ if ((mOptions.SizeList != NULL) && (mOptions.JoinMode)) {\r
+ Error (NULL, 0, 0, "cannot specify both -j and -size", NULL);\r
+ \r
+ if (NewFile != NULL) {\r
+ free (NewFile);\r
+ }\r
+ if (NewSize != NULL) {\r
+ free (NewSize);\r
+ }\r
+ \r
+ return STATUS_ERROR;\r
+ }\r
+ //\r
+ // Must have specified an output file name if not -dump\r
+ //\r
+ if ((mOptions.Dump == 0) && (mOptions.OutputFileName[0] == 0)) {\r
+ Error (NULL, 0, 0, NULL, "-o OutputFileName must be specified");\r
+ Usage ();\r
+ \r
+ if (NewFile != NULL) {\r
+ free (NewFile);\r
+ }\r
+ if (NewSize != NULL) {\r
+ free (NewSize);\r
+ }\r
+ \r
+ return STATUS_ERROR;\r
+ }\r
+ //\r
+ // Rest of arguments are input files. The first one is a firmware\r
+ // volume image, and the rest are FFS files that are to be inserted\r
+ // into the firmware volume.\r
+ //\r
+ LastFile = NULL;\r
+ while (Argc > 0) {\r
+ NewFile = (FILE_LIST *) malloc (sizeof (FILE_LIST));\r
+ if (NewFile == NULL) {\r
+ Error (NULL, 0, 0, "memory allocation failure", NULL);\r
+\r
+ if (NewFile != NULL) {\r
+ free (NewFile);\r
+ }\r
+ if (NewSize != NULL) {\r
+ free (NewSize);\r
+ }\r
+ \r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ memset ((char *) NewFile, 0, sizeof (FILE_LIST));\r
+ strcpy (NewFile->FileName, Argv[0]);\r
+ if (mOptions.FileList == NULL) {\r
+ mOptions.FileList = NewFile;\r
+ } else {\r
+ if (LastFile == NULL) {\r
+ LastFile = NewFile;\r
+ } else {\r
+ LastFile->Next = NewFile;\r
+ } \r
+ }\r
+\r
+ LastFile = NewFile;\r
+ Argc--;\r
+ Argv++;\r
+ }\r
+\r
+ //\r
+ // Must have provided at least one file name\r
+ //\r
+ if (mOptions.FileList == NULL) {\r
+ Error (NULL, 0, 0, "must specify at least one file name", NULL);\r
+ Usage ();\r
+ \r
+ if (NewFile != NULL) {\r
+ free (NewFile);\r
+ }\r
+ if (NewSize != NULL) {\r
+ free (NewSize);\r
+ }\r
+ \r
+ return STATUS_ERROR;\r
+ }\r
+\r
+ return STATUS_SUCCESS;\r
+}\r
+\r
+static\r
+void\r
+Usage (\r
+ VOID\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ Print usage information for this utility.\r
+ \r
+Arguments:\r
+\r
+ None.\r
+\r
+Returns:\r
+\r
+ Nothing.\r
+ \r
+--*/\r
+{\r
+ int Index;\r
+ static const char *Str[] = {\r
+ PROGRAM_NAME " -- create a capsule header",\r
+ " Usage: "PROGRAM_NAME " {options} [CapsuleFV]",\r
+ //\r
+ // {FfsFileNames}",\r
+ //\r
+ " Options include:",\r
+ " -h or -? for this help information",\r
+ " -script fname to take capsule header info from unicode script",\r
+ " file fname",\r
+ " -o fname write output to file fname (required)",\r
+ " -split size split capsule image into multiple output files",\r
+ " -dump to dump a capsule header",\r
+ " -v for verbose output\n",\r
+ " -j to join split capsule images into a single image",\r
+ "",\r
+ " CapsuleFV is the name of an existing well-formed Tiano firmware",\r
+ " volume file.",\r
+ //\r
+ // FfsFileNames are the names of one or more Tiano FFS files to",\r
+ // " insert into the output capsule image.",\r
+ //\r
+ NULL\r
+ };\r
+ for (Index = 0; Str[Index] != NULL; Index++) {\r
+ fprintf (stdout, "%s\n", Str[Index]);\r
+ }\r
+}\r