3 Copyright (c) 2002-2006 Intel Corporation. All rights reserved
\r
4 This program and the accompanying materials are licensed and made available
\r
5 under the terms and conditions of the BSD License which accompanies this
\r
6 distribution. The full text of the license may be found at
\r
7 http://opensource.org/licenses/bsd-license.php
\r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
\r
19 Generate a capsule header for a file, and optionally prepend the
\r
20 header to a file or list of files.
\r
31 #include <Common/UefiBaseTypes.h>
\r
32 #include <Common/MultiPhase.h>
\r
33 #include <Common/Capsule.h>
\r
34 #include <Common/FirmwareVolumeImageFormat.h>
\r
35 #include <Common/FirmwareVolumeHeader.h>
\r
36 #include <Common/FirmwareFileSystem.h> // for FV header GUID
\r
37 #include <Guid/Capsule.h>
\r
38 #include <Guid/FirmwareFileSystem.h> // for FV header GUID
\r
40 #include "CommonLib.h"
\r
41 #include "EfiUtilityMsgs.h"
\r
43 #define MAX_PATH 256
\r
45 #define UTILITY_NAME "GenCapsuleHdr"
\r
46 #define UTILITY_MAJOR_VERSION 1
\r
47 #define UTILITY_MINOR_VERSION 0
\r
49 #define UNICODE_BACKSLASH L'\\'
\r
50 #define UNICODE_FILE_START 0xFEFF
\r
51 #define UNICODE_CR 0x000D
\r
52 #define UNICODE_LF 0x000A
\r
53 #define UNICODE_NULL 0x0000
\r
54 #define UNICODE_SPACE L' '
\r
55 #define UNICODE_SLASH L'/'
\r
56 #define UNICODE_DOUBLE_QUOTE L'"'
\r
57 #define UNICODE_A L'A'
\r
58 #define UNICODE_F L'F'
\r
59 #define UNICODE_Z L'Z'
\r
60 #define UNICODE_a L'a'
\r
61 #define UNICODE_f L'f'
\r
62 #define UNICODE_z L'z'
\r
63 #define UNICODE_0 L'0'
\r
64 #define UNICODE_9 L'9'
\r
65 #define UNICODE_TAB L'\t'
\r
67 #define OEM_HEADER_STRING L"OemHeader"
\r
68 #define AUTHOR_INFO_STRING L"AuthorInfo"
\r
69 #define REVISION_INFO_STRING L"RevisionInfo"
\r
70 #define SHORT_DESCRIPTION_STRING L"ShortDescription"
\r
71 #define LONG_DESCRIPTION_STRING L"LongDescription"
\r
72 #define EQUAL_STRING L"="
\r
73 #define OPEN_BRACE_STRING L"{"
\r
74 #define CLOSE_BRACE_STRING L"}"
\r
75 #define GUID_STRING L"GUID"
\r
76 #define DATA_STRING L"DATA"
\r
78 #if (EFI_SPECIFICATION_VERSION >= 0x00020000)
\r
79 #define UEFI_CAPSULE_HEADER_NO_FALAGS 0
\r
80 #define UEFI_CAPSULE_HEADER_RESET_FALAGS CAPSULE_FLAGS_PERSIST_ACROSS_RESET
\r
81 #define UEFI_CAPSULE_HEADER_ALL_FALAGS (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)
\r
84 typedef wchar_t WCHAR;
\r
86 typedef struct _FILE_LIST {
\r
87 struct _FILE_LIST *Next;
\r
88 INT8 FileName[MAX_PATH];
\r
91 typedef struct _SIZE_LIST {
\r
92 struct _SIZE_LIST *Next;
\r
97 INT8 FileName[MAX_PATH];
\r
99 WCHAR *FileBufferPtr;
\r
107 // Here's all our globals.
\r
113 INT8 ScriptFileName[MAX_PATH];
\r
114 INT8 OutputFileName[MAX_PATH];
\r
115 FILE_LIST *FileList;
\r
117 SIZE_LIST *SizeList;
\r
118 SIZE_LIST *LastSize;
\r
119 SIZE_LIST *CurrentSize;
\r
122 static EFI_GUID mEfiCapsuleHeaderGuid = EFI_CAPSULE_GUID;
\r
139 SOURCE_FILE *SourceFile
\r
145 SOURCE_FILE *SourceFile,
\r
153 INT8 *BaseFileName,
\r
155 UINT32 SequenceNumber
\r
161 INT8 *CapsuleFileName
\r
190 DumpCapsuleHeaderStrings (
\r
191 UINT8 *SectionName,
\r
197 CheckFirmwareVolumeHeader (
\r
219 ProcessScriptFile (
\r
220 INT8 *ScriptFileName,
\r
222 EFI_CAPSULE_HEADER *CapsuleHeader
\r
228 SOURCE_FILE *SourceFile,
\r
242 SOURCE_FILE *SourceFile,
\r
265 Routine Description:
\r
266 Call the routine to process the command-line arguments, then
\r
267 dispatch to the appropriate function.
\r
270 Standard C main() argc and argv.
\r
277 // GC_TODO: Argc - add argument and description to function comment
\r
278 // GC_TODO: ] - add argument and description to function comment
\r
281 FILE_LIST *NextFile;
\r
283 // Specify our program name to the error printing routines.
\r
285 SetUtilityName (UTILITY_NAME);
\r
287 // Process the command-line arguments
\r
289 Status = ProcessArgs (Argc, Argv);
\r
290 if (Status == STATUS_SUCCESS) {
\r
291 if (mOptions.Dump) {
\r
293 } else if (mOptions.JoinMode) {
\r
302 while (mOptions.FileList != NULL) {
\r
303 NextFile = mOptions.FileList->Next;
\r
304 free (mOptions.FileList);
\r
305 mOptions.FileList = NextFile;
\r
308 while (mOptions.SizeList != NULL) {
\r
309 mOptions.CurrentSize = mOptions.SizeList->Next;
\r
310 free (mOptions.SizeList);
\r
311 mOptions.SizeList = mOptions.CurrentSize;
\r
314 return GetUtilityStatus ();
\r
324 Routine Description:
\r
326 GC_TODO: Add function description
\r
334 GC_TODO: add return values
\r
339 FILE_LIST *FileList;
\r
342 EFI_CAPSULE_HEADER CapsuleHeader;
\r
345 UINT32 CapsuleHeaderSize;
\r
346 long InsertedBlockMapEntryOffset;
\r
347 EFI_FV_BLOCK_MAP_ENTRY InsertedBlockMapEntry;
\r
348 UINT64 FirmwareVolumeSize;
\r
350 EFI_FIRMWARE_VOLUME_HEADER FVHeader;
\r
354 FirmwareVolumeSize = 0;
\r
355 CapsuleHeaderSize = 0;
\r
356 InsertedBlockMapEntryOffset = 0;
\r
357 memset (&InsertedBlockMapEntry, 0, sizeof (EFI_FV_BLOCK_MAP_ENTRY));
\r
358 memset (&FVHeader, 0, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
\r
360 if ((mOptions.OutFptr = fopen (mOptions.OutputFileName, "wb")) == NULL) {
\r
361 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to open output file for writing");
\r
362 return STATUS_ERROR;
\r
365 memset ((char *) &CapsuleHeader, 0, sizeof (CapsuleHeader));
\r
366 memcpy ((void *) &CapsuleHeader.CapsuleGuid, (void *) &mEfiCapsuleHeaderGuid, sizeof (EFI_GUID));
\r
367 CapsuleHeader.HeaderSize = sizeof (EFI_CAPSULE_HEADER);
\r
368 CapsuleHeader.CapsuleImageSize = sizeof (EFI_CAPSULE_HEADER);
\r
369 if (mOptions.ScriptFileName[0] != 0) {
\r
370 if (ProcessScriptFile (mOptions.ScriptFileName, mOptions.OutFptr, &CapsuleHeader) != STATUS_SUCCESS) {
\r
375 // Insert a default capsule header
\r
376 #if (EFI_SPECIFICATION_VERSION >= 0x00020000)
\r
377 CapsuleHeader.HeaderSize = sizeof (EFI_CAPSULE_HEADER);
\r
378 CapsuleHeader.Flags = UEFI_CAPSULE_HEADER_ALL_FALAGS;
\r
380 CapsuleHeader.OffsetToCapsuleBody = sizeof (EFI_CAPSULE_HEADER);
\r
382 if (fwrite ((void *) &CapsuleHeader, sizeof (CapsuleHeader), 1, mOptions.OutFptr) != 1) {
\r
383 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");
\r
388 CapsuleHeaderSize = CapsuleHeader.OffsetToCapsuleBody;
\r
390 // Now copy the contents of any other files specified on the command
\r
391 // line to the output file. Files must be FFS files, which are aligned
\r
392 // on 8-byte boundaries. Don't align the first file, since it's the start
\r
393 // of the image once the capsule header has been removed.
\r
395 FileList = mOptions.FileList;
\r
398 while (FileList != NULL) {
\r
399 if ((InFptr = fopen (FileList->FileName, "rb")) == NULL) {
\r
400 Error (NULL, 0, 0, FileList->FileName, "failed to open file for reading");
\r
404 // Allocate a buffer into which we can read the file.
\r
406 fseek (InFptr, 0, SEEK_END);
\r
407 Size = ftell (InFptr);
\r
409 Buffer = (char *) malloc (Size);
\r
410 if (Buffer == NULL) {
\r
411 Error (__FILE__, __LINE__, 0, FileList->FileName, "failed to allocate buffer to read file into");
\r
415 if (fread ((void *) Buffer, Size, 1, InFptr) != 1) {
\r
416 Error (NULL, 0, 0, FileList->FileName, "failed to read file contents");
\r
422 // Align the write of the first bytes from the file if not the first file
\r
426 // First file must be a firmware volume. Double-check, and then insert
\r
427 // an additional block map entry so we can add more files from the command line
\r
429 if (CheckFirmwareVolumeHeader (FileList->FileName, Buffer, Size) != STATUS_SUCCESS) {
\r
433 // Save a copy of the firmware volume header for later
\r
435 memcpy (&FVHeader, Buffer, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
\r
436 FirmwareVolumeSize = FVHeader.FvLength;
\r
437 if (FileList->Next != NULL) {
\r
439 // Copy the firmware volume header
\r
441 InsertedBlockMapEntryOffset = CapsuleHeaderSize + FVHeader.HeaderLength;
\r
442 if (fwrite (Buffer, FVHeader.HeaderLength, 1, mOptions.OutFptr) != 1) {
\r
443 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");
\r
447 if (fwrite (&InsertedBlockMapEntry, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, mOptions.OutFptr) != 1) {
\r
448 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");
\r
453 Buffer + FVHeader.HeaderLength,
\r
454 Size - FVHeader.HeaderLength,
\r
458 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");
\r
463 // Copy the file contents as-is
\r
465 if (fwrite ((void *) Buffer, Size, 1, mOptions.OutFptr) != 1) {
\r
466 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");
\r
471 while ((ftell (mOptions.OutFptr) - CapsuleHeaderSize) & 0x07) {
\r
472 if (fwrite ((void *) &Zero, 1, 1, mOptions.OutFptr) != 1) {
\r
473 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");
\r
478 if (fwrite ((void *) Buffer, Size, 1, mOptions.OutFptr) != 1) {
\r
479 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");
\r
491 FileList = FileList->Next;
\r
495 if (Buffer != NULL) {
\r
499 if (InFptr != NULL) {
\r
503 // If we inserted an additional block map entry, then fix it up. Fix up the
\r
504 // FV header as well to reflect our new size.
\r
506 if (InsertedBlockMapEntryOffset != 0) {
\r
507 FileSize = ftell (mOptions.OutFptr);
\r
508 InsertedBlockMapEntry.NumBlocks = 1;
\r
509 InsertedBlockMapEntry.BlockLength = (UINT32) ((UINT64) FileSize - (UINT64) CapsuleHeaderSize - FirmwareVolumeSize - sizeof (EFI_FV_BLOCK_MAP_ENTRY));
\r
510 fseek (mOptions.OutFptr, InsertedBlockMapEntryOffset, SEEK_SET);
\r
511 fwrite (&InsertedBlockMapEntry, sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, mOptions.OutFptr);
\r
513 // Fix up the firmware volume header and write it out
\r
515 fseek (mOptions.OutFptr, CapsuleHeaderSize, SEEK_SET);
\r
516 FVHeader.FvLength = FileSize - CapsuleHeaderSize;
\r
517 FVHeader.HeaderLength += sizeof (EFI_FV_BLOCK_MAP_ENTRY);
\r
518 fwrite (&FVHeader, sizeof (EFI_FIRMWARE_VOLUME_HEADER) - sizeof (EFI_FV_BLOCK_MAP_ENTRY), 1, mOptions.OutFptr);
\r
520 // Reposition to the end of the file
\r
524 // Close files and free the global string lists we allocated memory for
\r
526 if (mOptions.OutFptr != NULL) {
\r
528 // We should now know the full capsule image size. Update the header and write it again.
\r
530 fseek (mOptions.OutFptr, 0, SEEK_END);
\r
531 Size = ftell (mOptions.OutFptr);
\r
532 CapsuleHeader.CapsuleImageSize = Size;
\r
533 fseek (mOptions.OutFptr, 0, SEEK_SET);
\r
534 if (fwrite ((void *) &CapsuleHeader, sizeof (CapsuleHeader), 1, mOptions.OutFptr) != 1) {
\r
535 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");
\r
538 fseek (mOptions.OutFptr, 0, SEEK_END);
\r
539 fclose (mOptions.OutFptr);
\r
540 mOptions.OutFptr = NULL;
\r
543 // If they are doing split capsule output, then split it up now.
\r
545 if ((mOptions.Dump == 0) && (GetUtilityStatus () == STATUS_SUCCESS) && (mOptions.SizeList != NULL)) {
\r
546 SplitCapsule (mOptions.OutputFileName);
\r
549 return STATUS_SUCCESS;
\r
554 ProcessScriptFile (
\r
555 INT8 *ScriptFileName,
\r
557 EFI_CAPSULE_HEADER *CapsuleHeader
\r
561 Routine Description:
\r
562 Parse a capsule header script file.
\r
565 ScriptFileName - name of script file to parse
\r
566 OutFptr - output to dump binary data
\r
567 CapsuleHeader - capsule header to update with size info
\r
568 of parsed fields in the script file
\r
571 STATUS_SUCCESS - if all went well
\r
577 SOURCE_FILE SourceFile;
\r
578 WCHAR *WScriptFileName;
\r
581 if (fwrite (CapsuleHeader, sizeof (EFI_CAPSULE_HEADER), 1, OutFptr) != 1) {
\r
582 Error (NULL, 0, 0, "failed to write capsule header to output file", NULL);
\r
583 return STATUS_ERROR;
\r
586 memset (&SourceFile, 0, sizeof (SOURCE_FILE));
\r
587 strcpy (SourceFile.FileName, ScriptFileName);
\r
589 Status = STATUS_ERROR;
\r
591 // Open the input unicode script file and read it into a buffer
\r
593 WScriptFileName = (WCHAR *) malloc ((strlen (ScriptFileName) + 1) * sizeof (WCHAR));
\r
594 if (WScriptFileName == NULL) {
\r
595 Error (__FILE__, __LINE__, 0, "failed to allocate memory", NULL);
\r
596 return STATUS_ERROR;
\r
599 swprintf (WScriptFileName, L"%S", ScriptFileName);
\r
600 if ((SourceFile.FilePtr = _wfopen (WScriptFileName, L"r")) == NULL) {
\r
601 free (WScriptFileName);
\r
602 Error (NULL, 0, 0, ScriptFileName, "failed to open script file for reading");
\r
606 free (WScriptFileName);
\r
607 fseek (SourceFile.FilePtr, 0, SEEK_END);
\r
608 SourceFile.FileSize = ftell (SourceFile.FilePtr);
\r
609 rewind (SourceFile.FilePtr);
\r
610 SourceFile.FileBuffer = (WCHAR *) malloc (SourceFile.FileSize + sizeof (WCHAR));
\r
611 if (SourceFile.FileBuffer == NULL) {
\r
612 Error (__FILE__, __LINE__, 0, ScriptFileName, "failed to allocate memory to read in file contents");
\r
616 if (fread (SourceFile.FileBuffer, SourceFile.FileSize, 1, SourceFile.FilePtr) != 1) {
\r
617 Error (NULL, 0, 0, ScriptFileName, "failed to read file contents");
\r
621 SourceFile.FileBufferPtr = SourceFile.FileBuffer;
\r
622 SourceFile.LineNum = 1;
\r
623 if (SourceFile.FileBuffer[0] != UNICODE_FILE_START) {
\r
624 Error (ScriptFileName, 1, 0, "file does not appear to be a unicode file", NULL);
\r
628 SourceFile.FileBufferPtr++;
\r
629 SourceFile.FileBuffer[SourceFile.FileSize / sizeof (WCHAR)] = 0;
\r
631 // Walk the source file buffer and replace all carriage returns with 0 so
\r
632 // we can print from the file contents on parse errors.
\r
635 while (!EndOfFile (&SourceFile)) {
\r
636 if (SourceFile.FileBufferPtr[0] == UNICODE_CR) {
\r
637 SourceFile.FileBufferPtr[0] = 0;
\r
639 } else if (SourceFile.FileBufferPtr[0] == UNICODE_LF) {
\r
641 } else if (InComment) {
\r
642 SourceFile.FileBufferPtr[0] = UNICODE_SPACE;
\r
643 } else if ((SourceFile.FileBufferPtr[0] == UNICODE_SLASH) && (SourceFile.FileBufferPtr[1] == UNICODE_SLASH)) {
\r
645 SourceFile.FileBufferPtr[0] = UNICODE_SPACE;
\r
648 SourceFile.FileBufferPtr++;
\r
651 // Reposition to the start of the file, but skip over the unicode file start
\r
653 SourceFile.FileBufferPtr = SourceFile.FileBuffer;
\r
654 SourceFile.FileBufferPtr++;
\r
655 SourceFile.EndOfFile = 0;
\r
656 CapsuleHeader->OffsetToOemDefinedHeader = ftell (OutFptr);
\r
658 // Parse the OEM bytes
\r
660 if (ParseOemInfo (&SourceFile, OutFptr) != STATUS_SUCCESS) {
\r
664 // Parse the author information
\r
666 CapsuleHeader->OffsetToAuthorInformation = ftell (OutFptr);
\r
667 if (ParseCapsuleInfo (&SourceFile, OutFptr, AUTHOR_INFO_STRING) != STATUS_SUCCESS) {
\r
671 // Parse the revision information
\r
673 CapsuleHeader->OffsetToRevisionInformation = ftell (OutFptr);
\r
674 if (ParseCapsuleInfo (&SourceFile, OutFptr, REVISION_INFO_STRING) != STATUS_SUCCESS) {
\r
678 // Parse the short description
\r
680 CapsuleHeader->OffsetToShortDescription = ftell (OutFptr);
\r
681 if (ParseCapsuleInfo (&SourceFile, OutFptr, SHORT_DESCRIPTION_STRING) != STATUS_SUCCESS) {
\r
685 // Parse the long description
\r
687 CapsuleHeader->OffsetToLongDescription = ftell (OutFptr);
\r
688 if (ParseCapsuleInfo (&SourceFile, OutFptr, LONG_DESCRIPTION_STRING) != STATUS_SUCCESS) {
\r
692 // Better be end of contents
\r
694 SkipWhiteSpace (&SourceFile);
\r
695 if (!EndOfFile (&SourceFile)) {
\r
696 Error (ScriptFileName, SourceFile.LineNum, 0, NULL, "expected end-of-file, not %.20S", SourceFile.FileBufferPtr);
\r
700 CapsuleHeader->OffsetToCapsuleBody = ftell (OutFptr);
\r
702 fwrite (CapsuleHeader, sizeof (EFI_CAPSULE_HEADER), 1, OutFptr);
\r
703 fseek (OutFptr, 0, SEEK_END);
\r
704 Status = STATUS_SUCCESS;
\r
706 if (SourceFile.FilePtr != NULL) {
\r
707 fclose (SourceFile.FilePtr);
\r
710 if (SourceFile.FileBuffer != NULL) {
\r
711 free (SourceFile.FileBuffer);
\r
717 return STATUS_SUCCESS;
\r
720 // Parse the OEM data of format:
\r
722 // GUID = 12345676-1234-1234-123456789ABC
\r
723 // DATA = 0x01, 0x02, 0x03...
\r
729 SOURCE_FILE *SourceFile,
\r
734 Routine Description:
\r
736 GC_TODO: Add function description
\r
740 SourceFile - GC_TODO: add argument description
\r
741 OutFptr - GC_TODO: add argument description
\r
745 GC_TODO: add return values
\r
749 long OemHeaderOffset;
\r
751 EFI_CAPSULE_OEM_HEADER OemHeader;
\r
754 WCHAR *SaveFilePos;
\r
757 Status = STATUS_ERROR;
\r
758 memset (&OemHeader, 0, sizeof (EFI_CAPSULE_OEM_HEADER));
\r
759 OemHeaderOffset = ftell (OutFptr);
\r
760 OemHeader.HeaderSize = sizeof (EFI_CAPSULE_OEM_HEADER);
\r
761 if (fwrite (&OemHeader, sizeof (EFI_CAPSULE_OEM_HEADER), 1, OutFptr) != 1) {
\r
762 Error (NULL, 0, 0, "failed to write OEM header to output file", NULL);
\r
766 if (!IsToken (SourceFile, OEM_HEADER_STRING)) {
\r
768 SourceFile->FileName,
\r
769 SourceFile->LineNum,
\r
772 "expected %S, not %.20S",
\r
774 SourceFile->FileBufferPtr
\r
779 if (!IsToken (SourceFile, EQUAL_STRING)) {
\r
781 SourceFile->FileName,
\r
782 SourceFile->LineNum,
\r
785 "expected %S, not %.20S",
\r
787 SourceFile->FileBufferPtr
\r
792 if (!IsToken (SourceFile, OPEN_BRACE_STRING)) {
\r
794 SourceFile->FileName,
\r
795 SourceFile->LineNum,
\r
798 "expected %S, not %.20S",
\r
800 SourceFile->FileBufferPtr
\r
805 // Look for: GUID = xxxxxxx-xxxx-xxxx-xxxxxxxxxxxxx
\r
807 if (!IsToken (SourceFile, GUID_STRING)) {
\r
809 SourceFile->FileName,
\r
810 SourceFile->LineNum,
\r
813 "expected %S, not %.20S",
\r
815 SourceFile->FileBufferPtr
\r
820 if (!IsToken (SourceFile, EQUAL_STRING)) {
\r
822 SourceFile->FileName,
\r
823 SourceFile->LineNum,
\r
826 "expected %S, not %.20S",
\r
828 SourceFile->FileBufferPtr
\r
833 // Parse the xxxxxxxx-xxxx-xxxx-xxxx portion of the GUID
\r
835 SkipWhiteSpace (SourceFile);
\r
836 if (GetHexValue (SourceFile, &Data, 8) != STATUS_SUCCESS) {
\r
837 Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid GUID", NULL);
\r
841 OemHeader.OemGuid.Data1 = Data;
\r
842 if (!IsToken (SourceFile, L"-")) {
\r
844 SourceFile->FileName,
\r
845 SourceFile->LineNum,
\r
848 "expected dash in GUID, not %S",
\r
849 SourceFile->FileBufferPtr
\r
854 // Get 3 word values
\r
856 for (DigitCount = 0; DigitCount < 3; DigitCount++) {
\r
857 if (GetHexValue (SourceFile, &Data, 4) != STATUS_SUCCESS) {
\r
858 Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid GUID", NULL);
\r
862 switch (DigitCount) {
\r
864 OemHeader.OemGuid.Data2 = (UINT16) Data;
\r
868 OemHeader.OemGuid.Data3 = (UINT16) Data;
\r
872 OemHeader.OemGuid.Data4[1] = (UINT8) Data;
\r
873 OemHeader.OemGuid.Data4[0] = (UINT8) (Data >> 8);
\r
877 if (!IsToken (SourceFile, L"-")) {
\r
879 SourceFile->FileName,
\r
880 SourceFile->LineNum,
\r
883 "expected dash in GUID, not %S",
\r
884 SourceFile->FileBufferPtr
\r
890 // Pick up the last 6 bytes of the GUID
\r
892 SaveFilePos = SourceFile->FileBufferPtr;
\r
893 for (DigitCount = 0; DigitCount < 6; DigitCount++) {
\r
894 if (GetHexValue (SourceFile, &Data, 2) != STATUS_SUCCESS) {
\r
895 Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid GUID", NULL);
\r
899 OemHeader.OemGuid.Data4[DigitCount + 2] = (UINT8) Data;
\r
902 // Now read raw OEM data bytes. May or may not be present.
\r
903 // DATA = 0x01, 0x02, 0x02...
\r
905 if (IsToken (SourceFile, CLOSE_BRACE_STRING)) {
\r
906 Status = STATUS_SUCCESS;
\r
910 if (!IsToken (SourceFile, DATA_STRING)) {
\r
912 SourceFile->FileName,
\r
913 SourceFile->LineNum,
\r
916 "expected %S, not %.20S",
\r
918 SourceFile->FileBufferPtr
\r
923 if (!IsToken (SourceFile, EQUAL_STRING)) {
\r
925 SourceFile->FileName,
\r
926 SourceFile->LineNum,
\r
929 "expected %S, not %.20S",
\r
931 SourceFile->FileBufferPtr
\r
936 while (!EndOfFile (SourceFile)) {
\r
937 if (IsToken (SourceFile, CLOSE_BRACE_STRING)) {
\r
938 Status = STATUS_SUCCESS;
\r
942 if (IsToken (SourceFile, L"0x")) {
\r
943 if (swscanf (SourceFile->FileBufferPtr, L"%x", &Data) != 1) {
\r
945 SourceFile->FileName,
\r
946 SourceFile->LineNum,
\r
949 "expected hex byte value, not %.20S",
\r
950 SourceFile->FileBufferPtr
\r
957 SourceFile->FileName,
\r
958 SourceFile->LineNum,
\r
961 "expected byte hex byte value at %.20S",
\r
962 SourceFile->FileBufferPtr
\r
967 // Skip over the hex digits, then write the data
\r
969 while (iswxdigit (SourceFile->FileBufferPtr[0])) {
\r
970 SourceFile->FileBufferPtr++;
\r
973 ByteData = (UINT8) Data;
\r
974 if (fwrite (&ByteData, 1, 1, OutFptr) != 1) {
\r
975 Error (NULL, 0, 0, "failed to write OEM data to output file", NULL);
\r
979 OemHeader.HeaderSize++;
\r
983 IsToken (SourceFile, L",");
\r
986 SourceFile->FileName,
\r
987 SourceFile->LineNum,
\r
990 "expected hex OEM data, not %.20S",
\r
991 SourceFile->FileBufferPtr
\r
997 if (EndOfFile (SourceFile)) {
\r
999 SourceFile->FileName,
\r
1000 SourceFile->LineNum,
\r
1003 "expected %S close to OEM header data",
\r
1004 CLOSE_BRACE_STRING
\r
1009 Status = STATUS_SUCCESS;
\r
1012 // re-write the oem header if no errors
\r
1014 if (Status == STATUS_SUCCESS) {
\r
1015 fseek (OutFptr, OemHeaderOffset, SEEK_SET);
\r
1016 if (fwrite (&OemHeader, sizeof (EFI_CAPSULE_OEM_HEADER), 1, OutFptr) != 1) {
\r
1017 Error (NULL, 0, 0, "failed to write OEM header to output file", NULL);
\r
1021 fseek (OutFptr, 0, SEEK_END);
\r
1029 ParseCapsuleInfo (
\r
1030 SOURCE_FILE *SourceFile,
\r
1032 WCHAR *SectionName
\r
1034 // GC_TODO: function comment should start with '/*++'
\r
1036 // GC_TODO: function comment is missing 'Routine Description:'
\r
1037 // GC_TODO: function comment is missing 'Arguments:'
\r
1038 // GC_TODO: function comment is missing 'Returns:'
\r
1039 // GC_TODO: SourceFile - add argument and description to function comment
\r
1040 // GC_TODO: OutFptr - add argument and description to function comment
\r
1041 // GC_TODO: SectionName - add argument and description to function comment
\r
1042 // Parse: eng "string " "parts"
\r
1043 // spa "string " "parts"
\r
1044 // Write out: "eng string parts\0spa string parts\0\0
\r
1052 Status = STATUS_ERROR;
\r
1054 Spacebar = UNICODE_SPACE;
\r
1056 if (!IsToken (SourceFile, SectionName)) {
\r
1058 SourceFile->FileName,
\r
1059 SourceFile->LineNum,
\r
1062 "expected %S, not %.20S",
\r
1064 SourceFile->FileBufferPtr
\r
1069 if (!IsToken (SourceFile, EQUAL_STRING)) {
\r
1071 SourceFile->FileName,
\r
1072 SourceFile->LineNum,
\r
1075 "expected %S, not %.20S",
\r
1077 SourceFile->FileBufferPtr
\r
1082 if (!IsToken (SourceFile, OPEN_BRACE_STRING)) {
\r
1084 SourceFile->FileName,
\r
1085 SourceFile->LineNum,
\r
1088 "expected %S, not %.20S",
\r
1089 OPEN_BRACE_STRING,
\r
1090 SourceFile->FileBufferPtr
\r
1095 while (!EndOfFile (SourceFile)) {
\r
1096 if (IsToken (SourceFile, CLOSE_BRACE_STRING)) {
\r
1100 // Look for language identifier (3 lowercase chars)
\r
1102 if ((SourceFile->FileBufferPtr[0] >= UNICODE_a) &&
\r
1103 (SourceFile->FileBufferPtr[0] <= UNICODE_z) &&
\r
1104 (SourceFile->FileBufferPtr[1] >= UNICODE_a) &&
\r
1105 (SourceFile->FileBufferPtr[1] <= UNICODE_z) &&
\r
1106 (SourceFile->FileBufferPtr[2] >= UNICODE_a) &&
\r
1107 (SourceFile->FileBufferPtr[2] <= UNICODE_z) &&
\r
1108 IsWhiteSpace (SourceFile->FileBufferPtr[3])
\r
1111 // Write the 3 chars followed by a spacebar, and then look for opening quote
\r
1113 fwrite (SourceFile->FileBufferPtr, sizeof (WCHAR), 1, OutFptr);
\r
1114 SourceFile->FileBufferPtr++;
\r
1115 fwrite (SourceFile->FileBufferPtr, sizeof (WCHAR), 1, OutFptr);
\r
1116 SourceFile->FileBufferPtr++;
\r
1117 fwrite (SourceFile->FileBufferPtr, sizeof (WCHAR), 1, OutFptr);
\r
1118 SourceFile->FileBufferPtr++;
\r
1119 fwrite (&Spacebar, sizeof (WCHAR), 1, OutFptr);
\r
1121 while (IsToken (SourceFile, L"\"")) {
\r
1123 while (!EndOfFile (SourceFile)) {
\r
1124 if (SourceFile->FileBufferPtr[0] == UNICODE_DOUBLE_QUOTE) {
\r
1125 SourceFile->FileBufferPtr++;
\r
1127 } else if ((SourceFile->FileBufferPtr[0] == UNICODE_LF) || (SourceFile->FileBufferPtr[0] == 0)) {
\r
1128 Error (SourceFile->FileName, SourceFile->LineNum, 0, "missing closing quote on string", NULL);
\r
1131 fwrite (SourceFile->FileBufferPtr, sizeof (WCHAR), 1, OutFptr);
\r
1132 SourceFile->FileBufferPtr++;
\r
1137 if (StringCount == 0) {
\r
1139 SourceFile->FileName,
\r
1140 SourceFile->LineNum,
\r
1143 "expected quoted string, not %.20S",
\r
1144 SourceFile->FileBufferPtr
\r
1149 // This string's null terminator
\r
1151 fwrite (&Zero, sizeof (WCHAR), 1, OutFptr);
\r
1154 SourceFile->FileName,
\r
1155 SourceFile->LineNum,
\r
1158 "expected valid language identifer, not %.20S",
\r
1159 SourceFile->FileBufferPtr
\r
1165 // Double null terminator
\r
1167 fwrite (&Zero, sizeof (WCHAR), 1, OutFptr);
\r
1168 Status = STATUS_SUCCESS;
\r
1176 INT8 *CapsuleFileName
\r
1180 Routine Description:
\r
1181 We've created an entire capsule image. Now split it up into the
\r
1182 size pieces they requested.
\r
1185 CapsuleFileName - name of an existing capsule file on disk
\r
1188 STATUS_SUCCESS - if no problems
\r
1191 This implementation reads in the entire capsule image from
\r
1192 disk, then overwrites the original file with the first
\r
1198 EFI_CAPSULE_HEADER *CapHdr;
\r
1200 EFI_CAPSULE_HEADER Hdr;
\r
1204 UINT32 CurrentSize;
\r
1206 UINT32 SequenceNumber;
\r
1208 INT8 FileName[MAX_PATH];
\r
1212 // Figure out the total size, then rewind the input file and
\r
1213 // read the entire thing in
\r
1215 if ((CapFptr = fopen (CapsuleFileName, "rb")) == NULL) {
\r
1216 Error (NULL, 0, 0, CapsuleFileName, "failed to open capsule image for reading");
\r
1217 return STATUS_ERROR;
\r
1221 Status = STATUS_SUCCESS;
\r
1222 fseek (CapFptr, 0, SEEK_END);
\r
1223 SizeLeft = ftell (CapFptr);
\r
1224 fseek (CapFptr, 0, SEEK_SET);
\r
1225 CapHdr = (EFI_CAPSULE_HEADER *) malloc (SizeLeft);
\r
1226 if (CapHdr == NULL) {
\r
1227 Error (NULL, 0, 0, "memory allocation failure", NULL);
\r
1231 if (fread (CapHdr, SizeLeft, 1, CapFptr) != 1) {
\r
1232 Error (NULL, 0, 0, "failed to read capsule contents", "split failed");
\r
1239 // Get a GUID to fill in the InstanceId GUID in the header
\r
1241 CreateGuid (&CapHdr->InstanceId);
\r
1242 SequenceNumber = 0;
\r
1244 // If the split size is larger than the original capsule image, then
\r
1247 if (mOptions.SizeList->Size >= SizeLeft) {
\r
1248 mOptions.SizeList->Size = SizeLeft;
\r
1252 // First size has to be big enough for the original header
\r
1254 if (mOptions.SizeList->Size < CapHdr->OffsetToCapsuleBody) {
\r
1255 Error (NULL, 0, 0, "first split size is insufficient for the original capsule header", NULL);
\r
1259 // Initialize the header we'll use on all but the first part
\r
1261 memset (&Hdr, 0, sizeof (Hdr));
\r
1262 Hdr.CapsuleGuid = CapHdr->CapsuleGuid;
\r
1263 Hdr.HeaderSize = sizeof (Hdr);
\r
1264 Hdr.Flags = CapHdr->Flags;
\r
1265 Hdr.InstanceId = CapHdr->InstanceId;
\r
1266 Hdr.CapsuleImageSize = CapHdr->CapsuleImageSize;
\r
1267 Hdr.OffsetToCapsuleBody = Hdr.HeaderSize;
\r
1268 Hdr.SequenceNumber = 1;
\r
1270 // printf ("Created %s - 0x%X bytes\n", CapsuleFileName, mOptions.SizeList->Size);
\r
1272 Buffer = (UINT8 *) CapHdr;
\r
1274 // Walk the list of sizes and write out a capsule header, and
\r
1275 // then the raw capsule data.
\r
1277 // SizeLeft -= mOptions.SizeList->Size;
\r
1279 mOptions.CurrentSize = mOptions.SizeList;
\r
1280 while (SizeLeft) {
\r
1281 CurrentSize = mOptions.CurrentSize->Size;
\r
1282 GetSplitFileName (mOptions.OutputFileName, FileName, SequenceNumber);
\r
1283 if ((OutFptr = fopen (FileName, "wb")) == NULL) {
\r
1284 Error (NULL, 0, 0, FileName, "failed to open split file for writing");
\r
1288 if (Buffer == (UINT8 *) CapHdr) {
\r
1290 // First part -- write out original header and data
\r
1292 if (fwrite (Buffer, CurrentSize, 1, OutFptr) != 1) {
\r
1293 Error (NULL, 0, 0, FileName, "failed to write to split image file");
\r
1297 SizeLeft -= CurrentSize;
\r
1298 Buffer += CurrentSize;
\r
1299 DataSize = CurrentSize;
\r
1300 FileSize = CurrentSize;
\r
1303 // Not the first part. Write the default header, and then the raw bytes from the
\r
1304 // original image.
\r
1306 if (CurrentSize <= sizeof (Hdr)) {
\r
1307 Error (NULL, 0, 0, "split size too small for capsule header + data", "0x%X", CurrentSize);
\r
1311 DataSize = CurrentSize - sizeof (Hdr);
\r
1312 if (DataSize > SizeLeft) {
\r
1313 DataSize = SizeLeft;
\r
1316 if (fwrite (&Hdr, sizeof (Hdr), 1, OutFptr) != 1) {
\r
1317 Error (NULL, 0, 0, FileName, "failed to write capsule header to output file");
\r
1322 if (fwrite (Buffer, DataSize, 1, OutFptr) != 1) {
\r
1323 Error (NULL, 0, 0, FileName, "failed to write capsule data to output file");
\r
1328 Hdr.SequenceNumber++;
\r
1329 Buffer += DataSize;
\r
1330 SizeLeft -= DataSize;
\r
1331 FileSize = DataSize + sizeof (Hdr);
\r
1334 // Next size in list if there is one
\r
1336 if (mOptions.CurrentSize->Next != NULL) {
\r
1337 mOptions.CurrentSize = mOptions.CurrentSize->Next;
\r
1343 printf ("Created %s - 0x%X bytes (0x%X bytes of data)\n", FileName, FileSize, DataSize);
\r
1348 Status = STATUS_ERROR;
\r
1350 if (CapHdr != NULL) {
\r
1354 if (CapFptr != NULL) {
\r
1358 if (OutFptr != NULL) {
\r
1365 return STATUS_SUCCESS;
\r
1370 GetSplitFileName (
\r
1371 INT8 *BaseFileName,
\r
1372 INT8 *NewFileName,
\r
1373 UINT32 SequenceNumber
\r
1377 Routine Description:
\r
1379 GC_TODO: Add function description
\r
1383 BaseFileName - GC_TODO: add argument description
\r
1384 NewFileName - GC_TODO: add argument description
\r
1385 SequenceNumber - GC_TODO: add argument description
\r
1389 GC_TODO: add return values
\r
1395 Routine Description:
\r
1396 Given an initial split capsule file name and a sequence number,
\r
1397 create an appropriate file name for this split of a capsule image.
\r
1400 BaseFileName - name of of the first split file in the series
\r
1401 NewFileName - output name of the split file
\r
1402 SequenceNumber - 0-based sequence number of split images
\r
1405 TRUE - name created successfully
\r
1413 UINT32 BaseOffset;
\r
1415 // Work back from the end of the file name and see if there is a number somewhere
\r
1417 for (Ptr = BaseFileName + strlen (BaseFileName) - 1; (Ptr > BaseFileName) && !isdigit (*Ptr); Ptr--)
\r
1419 if ((Ptr == BaseFileName) && (!isdigit (*Ptr))) {
\r
1421 // Found no number, so just add it to the end
\r
1423 sprintf (NewFileName, "%s%d", BaseFileName, SequenceNumber);
\r
1427 // Found a number. Look back to find the first digit.
\r
1429 Part2Start = Ptr + 1;
\r
1430 for (Digits = 1; isdigit (*Ptr) && (Ptr > BaseFileName); Ptr--, Digits++)
\r
1432 if (!isdigit (*Ptr)) {
\r
1437 BaseOffset = atoi (Ptr);
\r
1438 SequenceNumber = SequenceNumber + BaseOffset;
\r
1441 // Copy the first part of the original file name to the new filename
\r
1442 // This is the path for filenames with format path\name001.cap
\r
1444 Len = (UINT32) Ptr - (UINT32) BaseFileName;
\r
1445 strncpy (NewFileName, BaseFileName, Len);
\r
1446 sprintf (NewFileName + Len, "%0*d", Digits, SequenceNumber);
\r
1447 strcat (NewFileName, Part2Start);
\r
1451 // Only one digit found. This is the path for filenames with
\r
1452 // format path\name1.cap
\r
1454 Len = (UINT32) Ptr - (UINT32) BaseFileName + 1;
\r
1455 strncpy (NewFileName, BaseFileName, Len);
\r
1456 sprintf (NewFileName + Len - 1, "%d", SequenceNumber);
\r
1457 strcat (NewFileName, Part2Start);
\r
1470 Routine Description:
\r
1472 GC_TODO: Add function description
\r
1476 Char - GC_TODO: add argument description
\r
1480 GC_TODO: add return values
\r
1485 case UNICODE_SPACE:
\r
1487 case UNICODE_NULL:
\r
1500 SOURCE_FILE *File,
\r
1505 Routine Description:
\r
1507 GC_TODO: Add function description
\r
1511 File - GC_TODO: add argument description
\r
1512 Token - GC_TODO: add argument description
\r
1516 GC_TODO: add return values
\r
1520 SkipWhiteSpace (File);
\r
1521 if (EndOfFile (File)) {
\r
1525 if (wcsncmp (Token, File->FileBufferPtr, wcslen (Token)) == 0) {
\r
1526 File->FileBufferPtr += wcslen (Token);
\r
1535 CheckFirmwareVolumeHeader (
\r
1542 Routine Description:
\r
1544 GC_TODO: Add function description
\r
1548 FileName - GC_TODO: add argument description
\r
1549 Buffer - GC_TODO: add argument description
\r
1550 BufferSize - GC_TODO: add argument description
\r
1554 GC_TODO: add return values
\r
1558 EFI_FIRMWARE_VOLUME_HEADER *Hdr;
\r
1559 EFI_GUID FVHeaderGuid = EFI_FIRMWARE_FILE_SYSTEM_GUID;
\r
1561 Hdr = (EFI_FIRMWARE_VOLUME_HEADER *) Buffer;
\r
1562 if (Hdr->Signature != EFI_FVH_SIGNATURE) {
\r
1563 Error (NULL, 0, 0, FileName, "file does not appear to be a firmware volume (bad signature)");
\r
1564 return STATUS_ERROR;
\r
1567 if (Hdr->Revision != EFI_FVH_REVISION) {
\r
1568 Error (NULL, 0, 0, FileName, "unsupported firmware volume header version");
\r
1569 return STATUS_ERROR;
\r
1572 if (Hdr->FvLength > BufferSize) {
\r
1573 Error (NULL, 0, 0, FileName, "malformed firmware volume -- FvLength > file size");
\r
1574 return STATUS_ERROR;
\r
1577 if (memcmp (&Hdr->FileSystemGuid, &FVHeaderGuid, sizeof (EFI_GUID)) != 0) {
\r
1578 Error (NULL, 0, 0, FileName, "invalid FFS GUID in firmware volume header");
\r
1579 return STATUS_ERROR;
\r
1582 return STATUS_SUCCESS;
\r
1592 Routine Description:
\r
1594 GC_TODO: Add function description
\r
1602 GC_TODO: add return values
\r
1608 FILE_LIST *FileList;
\r
1609 EFI_CAPSULE_HEADER CapsuleHeader;
\r
1610 EFI_FIRMWARE_VOLUME_HEADER FVHeader;
\r
1611 EFI_CAPSULE_OEM_HEADER *OemHeader;
\r
1614 UINT32 CapsuleHeaderDataSize;
\r
1616 UINT8 *CapsuleHeaderData;
\r
1617 BOOLEAN SplitImage;
\r
1620 CapsuleHeaderData = NULL;
\r
1621 FileList = mOptions.FileList;
\r
1622 while (FileList != NULL) {
\r
1623 if ((InFptr = fopen (FileList->FileName, "rb")) == NULL) {
\r
1624 Error (NULL, 0, 0, FileList->FileName, "failed to open file for reading");
\r
1628 if (fread (&CapsuleHeader, sizeof (EFI_CAPSULE_HEADER), 1, InFptr) != 1) {
\r
1629 Error (NULL, 0, 0, FileList->FileName, "failed to read capsule header");
\r
1633 fseek (InFptr, 0, SEEK_END);
\r
1634 FileSize = ftell (InFptr);
\r
1635 if (CapsuleHeader.CapsuleImageSize > FileSize) {
\r
1636 SplitImage = TRUE;
\r
1638 SplitImage = FALSE;
\r
1642 "Capsule %s Size=0x%X CargoSize=0x%X\n",
\r
1643 FileList->FileName,
\r
1645 FileSize - CapsuleHeader.OffsetToCapsuleBody
\r
1648 " GUID %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
\r
1649 CapsuleHeader.CapsuleGuid.Data1,
\r
1650 (UINT32) CapsuleHeader.CapsuleGuid.Data2,
\r
1651 (UINT32) CapsuleHeader.CapsuleGuid.Data3,
\r
1652 (UINT32) CapsuleHeader.CapsuleGuid.Data4[0],
\r
1653 (UINT32) CapsuleHeader.CapsuleGuid.Data4[1],
\r
1654 (UINT32) CapsuleHeader.CapsuleGuid.Data4[2],
\r
1655 (UINT32) CapsuleHeader.CapsuleGuid.Data4[3],
\r
1656 (UINT32) CapsuleHeader.CapsuleGuid.Data4[4],
\r
1657 (UINT32) CapsuleHeader.CapsuleGuid.Data4[5],
\r
1658 (UINT32) CapsuleHeader.CapsuleGuid.Data4[6],
\r
1659 (UINT32) CapsuleHeader.CapsuleGuid.Data4[7]
\r
1661 if (memcmp (&CapsuleHeader.CapsuleGuid, &mEfiCapsuleHeaderGuid, sizeof (EFI_GUID)) != 0) {
\r
1662 printf (" INVALID GUID");
\r
1666 printf (" Header size 0x%08X\n", CapsuleHeader.HeaderSize);
\r
1667 printf (" Flags 0x%08X\n", CapsuleHeader.Flags);
\r
1668 if (!SplitImage) {
\r
1669 printf (" Capsule image size 0x%08X\n", CapsuleHeader.CapsuleImageSize);
\r
1671 printf (" Capsule image size 0x%08X (split)\n", CapsuleHeader.CapsuleImageSize);
\r
1674 printf (" Sequence number %d\n", CapsuleHeader.SequenceNumber);
\r
1676 " InstanceId %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
\r
1677 CapsuleHeader.InstanceId.Data1,
\r
1678 (UINT32) CapsuleHeader.InstanceId.Data2,
\r
1679 (UINT32) CapsuleHeader.InstanceId.Data3,
\r
1680 (UINT32) CapsuleHeader.InstanceId.Data4[0],
\r
1681 (UINT32) CapsuleHeader.InstanceId.Data4[1],
\r
1682 (UINT32) CapsuleHeader.InstanceId.Data4[2],
\r
1683 (UINT32) CapsuleHeader.InstanceId.Data4[3],
\r
1684 (UINT32) CapsuleHeader.InstanceId.Data4[4],
\r
1685 (UINT32) CapsuleHeader.InstanceId.Data4[5],
\r
1686 (UINT32) CapsuleHeader.InstanceId.Data4[6],
\r
1687 (UINT32) CapsuleHeader.InstanceId.Data4[7]
\r
1689 printf (" Offset to capsule 0x%X\n", CapsuleHeader.OffsetToCapsuleBody);
\r
1691 // Dump header data if there
\r
1693 CapsuleHeaderDataSize = CapsuleHeader.OffsetToCapsuleBody - CapsuleHeader.HeaderSize;
\r
1694 if (CapsuleHeaderDataSize != 0) {
\r
1695 CapsuleHeaderData = (UINT8 *) malloc (CapsuleHeaderDataSize);
\r
1696 if (CapsuleHeaderData == NULL) {
\r
1701 "failed to allocate memory to read in capsule header data",
\r
1703 CapsuleHeaderDataSize
\r
1708 fseek (InFptr, CapsuleHeader.HeaderSize, SEEK_SET);
\r
1709 if (fread (CapsuleHeaderData, CapsuleHeaderDataSize, 1, InFptr) != 1) {
\r
1714 "failed to read capsule header data contents from file",
\r
1716 CapsuleHeaderDataSize
\r
1721 // ************************************************************************
\r
1725 // ************************************************************************
\r
1727 if (CapsuleHeader.OffsetToOemDefinedHeader != 0) {
\r
1728 OemHeader = (EFI_CAPSULE_OEM_HEADER *) (CapsuleHeaderData + CapsuleHeader.OffsetToOemDefinedHeader - CapsuleHeader.HeaderSize);
\r
1729 printf (" OEM Header\n");
\r
1731 " GUID %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
\r
1732 OemHeader->OemGuid.Data1,
\r
1733 (UINT32) OemHeader->OemGuid.Data2,
\r
1734 (UINT32) OemHeader->OemGuid.Data3,
\r
1735 (UINT32) OemHeader->OemGuid.Data4[0],
\r
1736 (UINT32) OemHeader->OemGuid.Data4[1],
\r
1737 (UINT32) OemHeader->OemGuid.Data4[2],
\r
1738 (UINT32) OemHeader->OemGuid.Data4[3],
\r
1739 (UINT32) OemHeader->OemGuid.Data4[4],
\r
1740 (UINT32) OemHeader->OemGuid.Data4[5],
\r
1741 (UINT32) OemHeader->OemGuid.Data4[6],
\r
1742 (UINT32) OemHeader->OemGuid.Data4[7]
\r
1744 printf (" Header size: 0x%X\n", OemHeader->HeaderSize);
\r
1745 printf (" OEM data");
\r
1746 BPtr = (UINT8 *) (OemHeader + 1);
\r
1747 for (ByteCount = 0; ByteCount < OemHeader->HeaderSize - sizeof (EFI_CAPSULE_OEM_HEADER); ByteCount++) {
\r
1748 if ((ByteCount & 0x7) == 0) {
\r
1752 printf ("%02X ", (UINT32) *BPtr);
\r
1759 // ************************************************************************
\r
1761 // Author, revision, short description, and long description information
\r
1763 // ************************************************************************
\r
1765 if (CapsuleHeader.OffsetToAuthorInformation != 0) {
\r
1766 if (DumpCapsuleHeaderStrings (
\r
1767 "Author information",
\r
1768 (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToAuthorInformation - CapsuleHeader.HeaderSize)
\r
1769 ) != STATUS_SUCCESS) {
\r
1774 if (CapsuleHeader.OffsetToRevisionInformation != 0) {
\r
1775 if (DumpCapsuleHeaderStrings (
\r
1776 "Revision information",
\r
1777 (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToRevisionInformation - CapsuleHeader.HeaderSize)
\r
1778 ) != STATUS_SUCCESS) {
\r
1783 if (CapsuleHeader.OffsetToShortDescription != 0) {
\r
1784 if (DumpCapsuleHeaderStrings (
\r
1785 "Short description",
\r
1786 (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToShortDescription - CapsuleHeader.HeaderSize)
\r
1787 ) != STATUS_SUCCESS) {
\r
1792 if (CapsuleHeader.OffsetToLongDescription != 0) {
\r
1793 if (DumpCapsuleHeaderStrings (
\r
1794 "Long description",
\r
1795 (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToLongDescription - CapsuleHeader.HeaderSize)
\r
1796 ) != STATUS_SUCCESS) {
\r
1802 // If it's not a split image, or it is a split image and this is the first in the series, then
\r
1803 // dump the cargo volume.
\r
1805 if ((!SplitImage) || (CapsuleHeader.SequenceNumber == 0)) {
\r
1806 printf (" Cargo FV dump\n");
\r
1807 fseek (InFptr, CapsuleHeader.OffsetToCapsuleBody, SEEK_SET);
\r
1808 if (fread (&FVHeader, sizeof (EFI_FIRMWARE_VOLUME_HEADER), 1, InFptr) != 1) {
\r
1809 Error (NULL, 0, 0, FileList->FileName, "failed to read cargo FV header");
\r
1813 printf (" FV length 0x%X", FVHeader.FvLength);
\r
1814 if (FileSize - CapsuleHeader.OffsetToCapsuleBody != FVHeader.FvLength) {
\r
1815 if (!SplitImage) {
\r
1816 printf (" ERROR: expected 0x%X to jive with file size on disk", FileSize - CapsuleHeader.OffsetToCapsuleBody);
\r
1821 printf (" Signature 0x%X ", FVHeader.Signature);
\r
1822 if (FVHeader.Signature == EFI_FVH_SIGNATURE) {
\r
1823 printf ("_FVH\n");
\r
1825 printf ("INVALID\n");
\r
1828 printf (" FV header length 0x%X\n", (UINT32) FVHeader.HeaderLength);
\r
1829 printf (" Revision 0x%X\n", (UINT32) FVHeader.Revision);
\r
1833 FileList = FileList->Next;
\r
1837 if (InFptr != NULL) {
\r
1841 if (CapsuleHeaderData != NULL) {
\r
1842 free (CapsuleHeaderData);
\r
1854 Routine Description:
\r
1855 Join split capsule images into a single image. This is the
\r
1856 support function for the -j command-line option.
\r
1862 STATUS_SUCCESS - no problems encountered
\r
1871 FILE_LIST *FileList;
\r
1873 EFI_CAPSULE_HEADER CapHdr;
\r
1874 EFI_CAPSULE_HEADER *CapHdrPtr;
\r
1876 UINT32 SequenceNumber;
\r
1878 // Must have at least two files for join mode
\r
1880 if ((mOptions.FileList == NULL) || (mOptions.FileList->Next == NULL)) {
\r
1881 Error (NULL, 0, 0, "must specify at least two file names to join", NULL);
\r
1882 return STATUS_ERROR;
\r
1885 // Open the output file
\r
1887 if ((OutFptr = fopen (mOptions.OutputFileName, "wb")) == NULL) {
\r
1888 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to open output file for writing");
\r
1889 return STATUS_ERROR;
\r
1892 FileList = mOptions.FileList;
\r
1894 SequenceNumber = 0;
\r
1897 while (FileList != NULL) {
\r
1898 if ((InFptr = fopen (FileList->FileName, "rb")) == NULL) {
\r
1899 Error (NULL, 0, 0, FileList->FileName, "failed to open file for reading");
\r
1903 // Allocate a buffer into which we can read the file.
\r
1905 fseek (InFptr, 0, SEEK_END);
\r
1906 Size = ftell (InFptr);
\r
1908 Buffer = (char *) malloc (Size);
\r
1909 if (Buffer == NULL) {
\r
1910 Error (__FILE__, __LINE__, 0, FileList->FileName, "failed to allocate buffer to read file into");
\r
1914 CapHdrPtr = (EFI_CAPSULE_HEADER *) Buffer;
\r
1915 if (fread ((void *) Buffer, Size, 1, InFptr) != 1) {
\r
1916 Error (NULL, 0, 0, FileList->FileName, "failed to read file contents");
\r
1920 // Check the header for validity. Check size first.
\r
1922 if (Size < sizeof (EFI_CAPSULE_HEADER)) {
\r
1923 Error (NULL, 0, 0, FileList->FileName, "file size is insufficient for a capsule header");
\r
1929 if (memcmp (&CapHdrPtr->CapsuleGuid, &mEfiCapsuleHeaderGuid, sizeof (EFI_GUID)) != 0) {
\r
1930 Error (NULL, 0, 0, FileList->FileName, "invalid capsule GUID");
\r
1934 // Check sequence number
\r
1936 if (CapHdrPtr->SequenceNumber != SequenceNumber) {
\r
1941 FileList->FileName,
\r
1942 "invalid sequence number %d (expected %d)",
\r
1943 CapHdrPtr->SequenceNumber,
\r
1949 // If the first file, read save the capsule header
\r
1951 if (SequenceNumber == 0) {
\r
1952 memcpy (&CapHdr, CapHdrPtr, sizeof (EFI_CAPSULE_HEADER));
\r
1954 // Erase the InstanceId GUID
\r
1956 memset (&CapHdrPtr->InstanceId, 0, sizeof (EFI_GUID));
\r
1957 if (fwrite (Buffer, Size, 1, OutFptr) != 1) {
\r
1958 Error (NULL, 0, 0, FileList->FileName, "failed to write contents to output file");
\r
1962 if (CapHdr.CapsuleImageSize < Size) {
\r
1963 Error (NULL, 0, 0, FileList->FileName, "capsule image size in capsule header < image size");
\r
1967 SizeLeft = CapHdr.CapsuleImageSize - Size;
\r
1970 // Check the GUID against the first file's GUID
\r
1972 if (memcmp (&CapHdr.CapsuleGuid, &CapHdrPtr->CapsuleGuid, sizeof (EFI_GUID)) != 0) {
\r
1973 Error (NULL, 0, 0, FileList->FileName, "GUID does not match first file's GUID");
\r
1977 // Make sure we're not throwing out any header info
\r
1979 if (CapHdrPtr->OffsetToCapsuleBody > sizeof (EFI_CAPSULE_HEADER)) {
\r
1981 // Could be the split information, so just emit a warning
\r
1987 FileList->FileName,
\r
1988 "image appears to have additional capsule header information -- ignoring"
\r
1990 } else if (CapHdrPtr->OffsetToCapsuleBody < sizeof (EFI_CAPSULE_HEADER)) {
\r
1991 Error (NULL, 0, 0, FileList->FileName, "offset to capsule body in capsule header is insufficient");
\r
1995 if (fwrite (Buffer + CapHdrPtr->OffsetToCapsuleBody, Size - CapHdrPtr->OffsetToCapsuleBody, 1, OutFptr) != 1) {
\r
1996 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");
\r
2000 if (SizeLeft < (Size - CapHdrPtr->OffsetToCapsuleBody)) {
\r
2001 Error (NULL, 0, 0, "sum of image sizes exceeds size specified in initial capsule header", NULL);
\r
2005 // printf ("FILE: %s OffsetToCapsuleBody=0x%X\n", FileList->FileName, CapHdrPtr->OffsetToCapsuleBody);
\r
2007 SizeLeft = SizeLeft - (Size - CapHdrPtr->OffsetToCapsuleBody);
\r
2010 // printf ("FILE: %s sizeleft=0x%X\n", FileList->FileName, SizeLeft);
\r
2016 FileList = FileList->Next;
\r
2021 Error (NULL, 0, 0, "sum of capsule images is insufficient", "0x%X bytes missing", SizeLeft);
\r
2025 Status = STATUS_SUCCESS;
\r
2028 Status = STATUS_ERROR;
\r
2030 if (InFptr != NULL) {
\r
2034 if (OutFptr != NULL) {
\r
2038 if (Buffer != NULL) {
\r
2045 return STATUS_SUCCESS;
\r
2050 DumpCapsuleHeaderStrings (
\r
2051 UINT8 *SectionName,
\r
2056 Routine Description:
\r
2057 Given a pointer to string data from a capsule header, dump
\r
2061 SectionName - name of the capsule header section to which
\r
2062 the string data pertains
\r
2063 Buffer - pointer to string data from a capsule header
\r
2066 STATUS_SUCCESS - all went well
\r
2070 printf (" %s\n", SectionName);
\r
2072 printf (" Language: %S\n", Buffer);
\r
2079 if (wcslen (Buffer) > 60) {
\r
2080 printf (" %.60S\n", Buffer);
\r
2083 printf (" %S\n", Buffer);
\r
2084 Buffer += wcslen (Buffer);
\r
2091 return STATUS_SUCCESS;
\r
2097 SOURCE_FILE *SourceFile,
\r
2103 Routine Description:
\r
2104 Scan a hex value from the input stream.
\r
2107 SourceFile - input file contents
\r
2108 Value - returned value
\r
2109 NumDigits - number of digits to read
\r
2112 STATUS_SUCCESS - if NumDigits were read from the file
\r
2113 STATUS_ERROR - otherwise
\r
2118 WCHAR *SaveFilePos;
\r
2122 SaveFilePos = SourceFile->FileBufferPtr;
\r
2124 Digits = NumDigits;
\r
2125 while (Digits > 0) {
\r
2126 Nibble = SourceFile->FileBufferPtr[0];
\r
2127 if ((Nibble >= UNICODE_0) && (Nibble <= UNICODE_9)) {
\r
2128 *Value = (*Value << 4) | (Nibble - UNICODE_0);
\r
2129 } else if ((Nibble >= UNICODE_A) && (Nibble <= UNICODE_F)) {
\r
2130 *Value = (*Value << 4) | (Nibble - UNICODE_A + 0x10);
\r
2131 } else if ((Nibble >= UNICODE_a) && (Nibble <= UNICODE_f)) {
\r
2132 *Value = (*Value << 4) | (Nibble - UNICODE_a + 0x10);
\r
2135 SourceFile->FileName,
\r
2136 SourceFile->LineNum,
\r
2139 "expected %d valid hex nibbles at %.20S",
\r
2143 return STATUS_ERROR;
\r
2146 SourceFile->FileBufferPtr++;
\r
2150 return STATUS_SUCCESS;
\r
2160 Routine Description:
\r
2162 GC_TODO: Add function description
\r
2166 File - GC_TODO: add argument description
\r
2170 GC_TODO: add return values
\r
2174 if ((UINT32) File->FileBufferPtr - (UINT32) File->FileBuffer >= File->FileSize) {
\r
2175 File->EndOfFile = TRUE;
\r
2178 // Reposition to the end of the file if we went beyond
\r
2180 if (File->EndOfFile) {
\r
2181 File->FileBufferPtr = File->FileBuffer + File->FileSize / sizeof (WCHAR);
\r
2184 return File->EndOfFile;
\r
2190 SOURCE_FILE *SourceFile
\r
2194 Routine Description:
\r
2196 GC_TODO: Add function description
\r
2200 SourceFile - GC_TODO: add argument description
\r
2204 GC_TODO: add return values
\r
2208 while (!EndOfFile (SourceFile)) {
\r
2209 switch (*SourceFile->FileBufferPtr) {
\r
2210 case UNICODE_NULL:
\r
2212 case UNICODE_SPACE:
\r
2214 SourceFile->FileBufferPtr++;
\r
2218 SourceFile->FileBufferPtr++;
\r
2219 SourceFile->LineNum++;
\r
2228 // Parse a number. Possible format:
\r
2244 Routine Description:
\r
2246 GC_TODO: Add function description
\r
2250 Str - GC_TODO: add argument description
\r
2251 Value - GC_TODO: add argument description
\r
2255 GC_TODO: add return values
\r
2263 if (!isdigit (Str[0])) {
\r
2267 // Look for hex number
\r
2269 if ((Str[0] == '0') && (tolower (Str[1]) == 'x')) {
\r
2271 if (Str[0] == 0) {
\r
2276 if ((Str[0] >= '0') && (Str[0] <= '9')) {
\r
2277 LValue = (LValue << 4) | (Str[0] - '0');
\r
2278 } else if ((Str[0] >= 'A') && (Str[0] <= 'F')) {
\r
2279 LValue = (LValue << 4) | (Str[0] - 'A' + 0x10);
\r
2280 } else if ((Str[0] >= 'a') && (Str[0] <= 'f')) {
\r
2281 LValue = (LValue << 4) | (Str[0] - 'a' + 0x10);
\r
2289 LValue = atoi (Str);
\r
2290 while (isdigit (*Str)) {
\r
2295 // If string left over, better be one character we recognize
\r
2310 LValue *= 1024 * 1024;
\r
2322 // Process the command-line arguments
\r
2332 Routine Description:
\r
2334 Processes command line arguments.
\r
2338 Argc - Number of command line arguments
\r
2339 Argv[] - Array of files input on command line
\r
2343 STATUS_ERROR - Function exited with an error
\r
2344 STATUS_SUCCESS - Function executed successfully
\r
2348 FILE_LIST *NewFile;
\r
2350 FILE_LIST *LastFile;
\r
2351 SIZE_LIST *NewSize;
\r
2357 // Clear our globals
\r
2359 memset ((char *) &mOptions, 0, sizeof (mOptions));
\r
2362 // Skip program name
\r
2369 return STATUS_ERROR;
\r
2372 if ((strcmp(Argv[0], "-h") == 0) || (strcmp(Argv[0], "--help") == 0) ||
\r
2373 (strcmp(Argv[0], "-?") == 0) || (strcmp(Argv[0], "/?") == 0)) {
\r
2375 return STATUS_ERROR;
\r
2378 if ((strcmp(Argv[0], "-V") == 0) || (strcmp(Argv[0], "--version") == 0)) {
\r
2380 return STATUS_ERROR;
\r
2384 // Process until no more options
\r
2386 while ((Argc > 0) && (Argv[0][0] == '-')) {
\r
2387 if (stricmp (Argv[0], "-script") == 0) {
\r
2389 // Check for one more arg
\r
2393 // Save the file name
\r
2395 if (strlen (Argv[1]) >= sizeof (mOptions.ScriptFileName)) {
\r
2396 Error (NULL, 0, 0, NULL, "input script file name length exceeds internal buffer size");
\r
2398 if (NewFile != NULL) {
\r
2401 if (NewSize != NULL) {
\r
2405 return STATUS_ERROR;
\r
2408 strcpy (mOptions.ScriptFileName, Argv[1]);
\r
2410 Error (NULL, 0, 0, Argv[0], "missing script file name with option");
\r
2413 if (NewFile != NULL) {
\r
2416 if (NewSize != NULL) {
\r
2420 return STATUS_ERROR;
\r
2426 // -o outfilename -- specify output file name (required)
\r
2428 } else if (stricmp (Argv[0], "-o") == 0) {
\r
2430 // check for one more arg
\r
2434 // Try to open the file
\r
2436 // if ((mOptions.OutFptr = fopen (Argv[1], "wb")) == NULL) {
\r
2437 // Error (NULL, 0, 0, Argv[1], "failed to open output file for writing");
\r
2438 // return STATUS_ERROR;
\r
2441 strcpy (mOptions.OutputFileName, Argv[1]);
\r
2443 Error (NULL, 0, 0, Argv[0], "missing output filename with option");
\r
2446 if (NewFile != NULL) {
\r
2449 if (NewSize != NULL) {
\r
2453 return STATUS_ERROR;
\r
2458 } else if (stricmp (Argv[0], "-j") == 0) {
\r
2459 mOptions.JoinMode = TRUE;
\r
2461 // -split <size> option (multiple allowed)
\r
2463 } else if (stricmp (Argv[0], "-split") == 0) {
\r
2465 NewSize = (SIZE_LIST *) malloc (sizeof (SIZE_LIST));
\r
2466 if (NewSize == NULL) {
\r
2467 Error (NULL, 0, 0, "memory allocation failure", NULL);
\r
2469 if (NewFile != NULL) {
\r
2472 if (NewSize != NULL) {
\r
2476 return STATUS_ERROR;
\r
2479 memset (NewSize, 0, sizeof (SIZE_LIST));
\r
2481 // Get the size from the next arg, and then add this size
\r
2482 // to our size list
\r
2484 if (!GetNumber (Argv[1], &NewSize->Size)) {
\r
2485 Error (NULL, 0, 0, Argv[1], "invalid split size argument");
\r
2487 if (NewFile != NULL) {
\r
2490 if (NewSize != NULL) {
\r
2494 return STATUS_ERROR;
\r
2497 if (mOptions.SizeList == NULL) {
\r
2498 mOptions.SizeList = NewSize;
\r
2499 mOptions.CurrentSize = NewSize;
\r
2501 mOptions.LastSize->Next = NewSize;
\r
2504 mOptions.LastSize = NewSize;
\r
2507 Error (NULL, 0, 0, Argv[0], "missing size parameter with option");
\r
2510 if (NewFile != NULL) {
\r
2513 if (NewSize != NULL) {
\r
2517 return STATUS_ERROR;
\r
2522 } else if ((stricmp (Argv[0], "-h") == 0) || (strcmp (Argv[0], "-?") == 0)) {
\r
2525 if (NewFile != NULL) {
\r
2528 if (NewSize != NULL) {
\r
2532 return STATUS_ERROR;
\r
2534 // Default minimum header
\r
2536 } else if (stricmp (Argv[0], "-dump") == 0) {
\r
2537 mOptions.Dump = TRUE;
\r
2538 } else if (stricmp (Argv[0], "-v") == 0) {
\r
2539 mOptions.Verbose = TRUE;
\r
2541 Error (NULL, 0, 0, Argv[0], "unrecognized option");
\r
2544 if (NewFile != NULL) {
\r
2547 if (NewSize != NULL) {
\r
2551 return STATUS_ERROR;
\r
2558 // Can't -j join files and -s split output capsule
\r
2560 if ((mOptions.SizeList != NULL) && (mOptions.JoinMode)) {
\r
2561 Error (NULL, 0, 0, "cannot specify both -j and -size", NULL);
\r
2563 if (NewFile != NULL) {
\r
2566 if (NewSize != NULL) {
\r
2570 return STATUS_ERROR;
\r
2573 // Must have specified an output file name if not -dump
\r
2575 if ((mOptions.Dump == 0) && (mOptions.OutputFileName[0] == 0)) {
\r
2576 Error (NULL, 0, 0, NULL, "-o OutputFileName must be specified");
\r
2579 if (NewFile != NULL) {
\r
2582 if (NewSize != NULL) {
\r
2586 return STATUS_ERROR;
\r
2589 // Rest of arguments are input files. The first one is a firmware
\r
2590 // volume image, and the rest are FFS files that are to be inserted
\r
2591 // into the firmware volume.
\r
2594 while (Argc > 0) {
\r
2595 NewFile = (FILE_LIST *) malloc (sizeof (FILE_LIST));
\r
2596 if (NewFile == NULL) {
\r
2597 Error (NULL, 0, 0, "memory allocation failure", NULL);
\r
2599 if (NewFile != NULL) {
\r
2602 if (NewSize != NULL) {
\r
2606 return STATUS_ERROR;
\r
2609 memset ((char *) NewFile, 0, sizeof (FILE_LIST));
\r
2610 strcpy (NewFile->FileName, Argv[0]);
\r
2611 if (mOptions.FileList == NULL) {
\r
2612 mOptions.FileList = NewFile;
\r
2614 if (LastFile == NULL) {
\r
2615 LastFile = NewFile;
\r
2617 LastFile->Next = NewFile;
\r
2621 LastFile = NewFile;
\r
2627 // Must have provided at least one file name
\r
2629 if (mOptions.FileList == NULL) {
\r
2630 Error (NULL, 0, 0, "must specify at least one file name", NULL);
\r
2633 if (NewFile != NULL) {
\r
2636 if (NewSize != NULL) {
\r
2640 return STATUS_ERROR;
\r
2643 return STATUS_SUCCESS;
\r
2653 Routine Description:
\r
2655 Print out version information for this utility.
\r
2667 printf ("%s v%d.%d -EDK utility to create a capsule header.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);
\r
2668 printf ("Copyright (c) 1999-2006 Intel Corporation. All rights reserved.\n");
\r
2678 Routine Description:
\r
2680 Print usage information for this utility.
\r
2693 static const char *Str[] = {
\r
2694 "\nUsage: "UTILITY_NAME " {options} [CapsuleFV]",
\r
2696 // {FfsFileNames}",
\r
2698 " Options include:",
\r
2699 " -h,--help,-?,/? to display help messages",
\r
2700 " -V,--version to display version information",
\r
2701 " -script fname to take capsule header info from unicode script",
\r
2703 " -o fname write output to file fname (required)",
\r
2704 " -split size split capsule image into multiple output files",
\r
2705 " -dump to dump a capsule header",
\r
2706 " -v for verbose output\n",
\r
2707 " -j to join split capsule images into a single image",
\r
2709 " CapsuleFV is the name of an existing well-formed Tiano firmware",
\r
2712 // FfsFileNames are the names of one or more Tiano FFS files to",
\r
2713 // " insert into the output capsule image.",
\r
2720 for (Index = 0; Str[Index] != NULL; Index++) {
\r
2721 fprintf (stdout, "%s\n", Str[Index]);
\r