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