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"
44 #define PROGRAM_NAME "GenCapsuleHdr"
46 #define UNICODE_BACKSLASH L'\\'
47 #define UNICODE_FILE_START 0xFEFF
48 #define UNICODE_CR 0x000D
49 #define UNICODE_LF 0x000A
50 #define UNICODE_NULL 0x0000
51 #define UNICODE_SPACE L' '
52 #define UNICODE_SLASH L'/'
53 #define UNICODE_DOUBLE_QUOTE L'"'
54 #define UNICODE_A L'A'
55 #define UNICODE_F L'F'
56 #define UNICODE_Z L'Z'
57 #define UNICODE_a L'a'
58 #define UNICODE_f L'f'
59 #define UNICODE_z L'z'
60 #define UNICODE_0 L'0'
61 #define UNICODE_9 L'9'
62 #define UNICODE_TAB L'\t'
64 #define OEM_HEADER_STRING L"OemHeader"
65 #define AUTHOR_INFO_STRING L"AuthorInfo"
66 #define REVISION_INFO_STRING L"RevisionInfo"
67 #define SHORT_DESCRIPTION_STRING L"ShortDescription"
68 #define LONG_DESCRIPTION_STRING L"LongDescription"
69 #define EQUAL_STRING L"="
70 #define OPEN_BRACE_STRING L"{"
71 #define CLOSE_BRACE_STRING L"}"
72 #define GUID_STRING L"GUID"
73 #define DATA_STRING L"DATA"
75 #if (EFI_SPECIFICATION_VERSION >= 0x00020000)
76 #define UEFI_CAPSULE_HEADER_NO_FALAGS 0
77 #define UEFI_CAPSULE_HEADER_RESET_FALAGS CAPSULE_FLAGS_PERSIST_ACROSS_RESET
78 #define UEFI_CAPSULE_HEADER_ALL_FALAGS (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)
81 typedef wchar_t WCHAR
;
83 typedef struct _FILE_LIST
{
84 struct _FILE_LIST
*Next
;
85 INT8 FileName
[MAX_PATH
];
88 typedef struct _SIZE_LIST
{
89 struct _SIZE_LIST
*Next
;
94 INT8 FileName
[MAX_PATH
];
104 // Here's all our globals.
110 INT8 ScriptFileName
[MAX_PATH
];
111 INT8 OutputFileName
[MAX_PATH
];
116 SIZE_LIST
*CurrentSize
;
119 static EFI_GUID mEfiCapsuleHeaderGuid
= EFI_CAPSULE_GUID
;
136 SOURCE_FILE
*SourceFile
142 SOURCE_FILE
*SourceFile
,
152 UINT32 SequenceNumber
158 INT8
*CapsuleFileName
181 DumpCapsuleHeaderStrings (
188 CheckFirmwareVolumeHeader (
211 INT8
*ScriptFileName
,
213 EFI_CAPSULE_HEADER
*CapsuleHeader
219 SOURCE_FILE
*SourceFile
,
233 SOURCE_FILE
*SourceFile
,
257 Call the routine to process the command-line arguments, then
258 dispatch to the appropriate function.
261 Standard C main() argc and argv.
268 // GC_TODO: Argc - add argument and description to function comment
269 // GC_TODO: ] - add argument and description to function comment
274 // Specify our program name to the error printing routines.
276 SetUtilityName (PROGRAM_NAME
);
278 // Process the command-line arguments
280 Status
= ProcessArgs (Argc
, Argv
);
281 if (Status
== STATUS_SUCCESS
) {
284 } else if (mOptions
.JoinMode
) {
293 while (mOptions
.FileList
!= NULL
) {
294 NextFile
= mOptions
.FileList
->Next
;
295 free (mOptions
.FileList
);
296 mOptions
.FileList
= NextFile
;
299 while (mOptions
.SizeList
!= NULL
) {
300 mOptions
.CurrentSize
= mOptions
.SizeList
->Next
;
301 free (mOptions
.SizeList
);
302 mOptions
.SizeList
= mOptions
.CurrentSize
;
305 return GetUtilityStatus ();
317 GC_TODO: Add function description
325 GC_TODO: add return values
333 EFI_CAPSULE_HEADER CapsuleHeader
;
336 UINT32 CapsuleHeaderSize
;
337 long InsertedBlockMapEntryOffset
;
338 EFI_FV_BLOCK_MAP_ENTRY InsertedBlockMapEntry
;
339 UINT64 FirmwareVolumeSize
;
341 EFI_FIRMWARE_VOLUME_HEADER FVHeader
;
345 FirmwareVolumeSize
= 0;
346 CapsuleHeaderSize
= 0;
347 InsertedBlockMapEntryOffset
= 0;
348 memset (&InsertedBlockMapEntry
, 0, sizeof (EFI_FV_BLOCK_MAP_ENTRY
));
349 memset (&FVHeader
, 0, sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
351 if ((mOptions
.OutFptr
= fopen (mOptions
.OutputFileName
, "wb")) == NULL
) {
352 Error (NULL
, 0, 0, mOptions
.OutputFileName
, "failed to open output file for writing");
356 memset ((char *) &CapsuleHeader
, 0, sizeof (CapsuleHeader
));
357 memcpy ((void *) &CapsuleHeader
.CapsuleGuid
, (void *) &mEfiCapsuleHeaderGuid
, sizeof (EFI_GUID
));
358 CapsuleHeader
.HeaderSize
= sizeof (EFI_CAPSULE_HEADER
);
359 CapsuleHeader
.CapsuleImageSize
= sizeof (EFI_CAPSULE_HEADER
);
360 if (mOptions
.ScriptFileName
[0] != 0) {
361 if (ProcessScriptFile (mOptions
.ScriptFileName
, mOptions
.OutFptr
, &CapsuleHeader
) != STATUS_SUCCESS
) {
366 // Insert a default capsule header
367 #if (EFI_SPECIFICATION_VERSION >= 0x00020000)
368 CapsuleHeader
.HeaderSize
= sizeof (EFI_CAPSULE_HEADER
);
369 CapsuleHeader
.Flags
= UEFI_CAPSULE_HEADER_ALL_FALAGS
;
371 CapsuleHeader
.OffsetToCapsuleBody
= sizeof (EFI_CAPSULE_HEADER
);
373 if (fwrite ((void *) &CapsuleHeader
, sizeof (CapsuleHeader
), 1, mOptions
.OutFptr
) != 1) {
374 Error (NULL
, 0, 0, mOptions
.OutputFileName
, "failed to write to file");
379 CapsuleHeaderSize
= CapsuleHeader
.OffsetToCapsuleBody
;
381 // Now copy the contents of any other files specified on the command
382 // line to the output file. Files must be FFS files, which are aligned
383 // on 8-byte boundaries. Don't align the first file, since it's the start
384 // of the image once the capsule header has been removed.
386 FileList
= mOptions
.FileList
;
389 while (FileList
!= NULL
) {
390 if ((InFptr
= fopen (FileList
->FileName
, "rb")) == NULL
) {
391 Error (NULL
, 0, 0, FileList
->FileName
, "failed to open file for reading");
395 // Allocate a buffer into which we can read the file.
397 fseek (InFptr
, 0, SEEK_END
);
398 Size
= ftell (InFptr
);
400 Buffer
= (char *) malloc (Size
);
401 if (Buffer
== NULL
) {
402 Error (__FILE__
, __LINE__
, 0, FileList
->FileName
, "failed to allocate buffer to read file into");
406 if (fread ((void *) Buffer
, Size
, 1, InFptr
) != 1) {
407 Error (NULL
, 0, 0, FileList
->FileName
, "failed to read file contents");
413 // Align the write of the first bytes from the file if not the first file
417 // First file must be a firmware volume. Double-check, and then insert
418 // an additional block map entry so we can add more files from the command line
420 if (CheckFirmwareVolumeHeader (FileList
->FileName
, Buffer
, Size
) != STATUS_SUCCESS
) {
424 // Save a copy of the firmware volume header for later
426 memcpy (&FVHeader
, Buffer
, sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
427 FirmwareVolumeSize
= FVHeader
.FvLength
;
428 if (FileList
->Next
!= NULL
) {
430 // Copy the firmware volume header
432 InsertedBlockMapEntryOffset
= CapsuleHeaderSize
+ FVHeader
.HeaderLength
;
433 if (fwrite (Buffer
, FVHeader
.HeaderLength
, 1, mOptions
.OutFptr
) != 1) {
434 Error (NULL
, 0, 0, mOptions
.OutputFileName
, "failed to write to file");
438 if (fwrite (&InsertedBlockMapEntry
, sizeof (EFI_FV_BLOCK_MAP_ENTRY
), 1, mOptions
.OutFptr
) != 1) {
439 Error (NULL
, 0, 0, mOptions
.OutputFileName
, "failed to write to file");
444 Buffer
+ FVHeader
.HeaderLength
,
445 Size
- FVHeader
.HeaderLength
,
449 Error (NULL
, 0, 0, mOptions
.OutputFileName
, "failed to write to file");
454 // Copy the file contents as-is
456 if (fwrite ((void *) Buffer
, Size
, 1, mOptions
.OutFptr
) != 1) {
457 Error (NULL
, 0, 0, mOptions
.OutputFileName
, "failed to write to file");
462 while ((ftell (mOptions
.OutFptr
) - CapsuleHeaderSize
) & 0x07) {
463 if (fwrite ((void *) &Zero
, 1, 1, mOptions
.OutFptr
) != 1) {
464 Error (NULL
, 0, 0, mOptions
.OutputFileName
, "failed to write to file");
469 if (fwrite ((void *) Buffer
, Size
, 1, mOptions
.OutFptr
) != 1) {
470 Error (NULL
, 0, 0, mOptions
.OutputFileName
, "failed to write to file");
482 FileList
= FileList
->Next
;
486 if (Buffer
!= NULL
) {
490 if (InFptr
!= NULL
) {
494 // If we inserted an additional block map entry, then fix it up. Fix up the
495 // FV header as well to reflect our new size.
497 if (InsertedBlockMapEntryOffset
!= 0) {
498 FileSize
= ftell (mOptions
.OutFptr
);
499 InsertedBlockMapEntry
.NumBlocks
= 1;
500 InsertedBlockMapEntry
.BlockLength
= (UINT32
) ((UINT64
) FileSize
- (UINT64
) CapsuleHeaderSize
- FirmwareVolumeSize
- sizeof (EFI_FV_BLOCK_MAP_ENTRY
));
501 fseek (mOptions
.OutFptr
, InsertedBlockMapEntryOffset
, SEEK_SET
);
502 fwrite (&InsertedBlockMapEntry
, sizeof (EFI_FV_BLOCK_MAP_ENTRY
), 1, mOptions
.OutFptr
);
504 // Fix up the firmware volume header and write it out
506 fseek (mOptions
.OutFptr
, CapsuleHeaderSize
, SEEK_SET
);
507 FVHeader
.FvLength
= FileSize
- CapsuleHeaderSize
;
508 FVHeader
.HeaderLength
+= sizeof (EFI_FV_BLOCK_MAP_ENTRY
);
509 fwrite (&FVHeader
, sizeof (EFI_FIRMWARE_VOLUME_HEADER
) - sizeof (EFI_FV_BLOCK_MAP_ENTRY
), 1, mOptions
.OutFptr
);
511 // Reposition to the end of the file
515 // Close files and free the global string lists we allocated memory for
517 if (mOptions
.OutFptr
!= NULL
) {
519 // We should now know the full capsule image size. Update the header and write it again.
521 fseek (mOptions
.OutFptr
, 0, SEEK_END
);
522 Size
= ftell (mOptions
.OutFptr
);
523 CapsuleHeader
.CapsuleImageSize
= Size
;
524 fseek (mOptions
.OutFptr
, 0, SEEK_SET
);
525 if (fwrite ((void *) &CapsuleHeader
, sizeof (CapsuleHeader
), 1, mOptions
.OutFptr
) != 1) {
526 Error (NULL
, 0, 0, mOptions
.OutputFileName
, "failed to write to file");
529 fseek (mOptions
.OutFptr
, 0, SEEK_END
);
530 fclose (mOptions
.OutFptr
);
531 mOptions
.OutFptr
= NULL
;
534 // If they are doing split capsule output, then split it up now.
536 if ((mOptions
.Dump
== 0) && (GetUtilityStatus () == STATUS_SUCCESS
) && (mOptions
.SizeList
!= NULL
)) {
537 SplitCapsule (mOptions
.OutputFileName
);
540 return STATUS_SUCCESS
;
546 INT8
*ScriptFileName
,
548 EFI_CAPSULE_HEADER
*CapsuleHeader
553 Parse a capsule header script file.
556 ScriptFileName - name of script file to parse
557 OutFptr - output to dump binary data
558 CapsuleHeader - capsule header to update with size info
559 of parsed fields in the script file
562 STATUS_SUCCESS - if all went well
568 SOURCE_FILE SourceFile
;
569 WCHAR
*WScriptFileName
;
572 if (fwrite (CapsuleHeader
, sizeof (EFI_CAPSULE_HEADER
), 1, OutFptr
) != 1) {
573 Error (NULL
, 0, 0, "failed to write capsule header to output file", NULL
);
577 memset (&SourceFile
, 0, sizeof (SOURCE_FILE
));
578 strcpy (SourceFile
.FileName
, ScriptFileName
);
580 Status
= STATUS_ERROR
;
582 // Open the input unicode script file and read it into a buffer
584 WScriptFileName
= (WCHAR
*) malloc ((strlen (ScriptFileName
) + 1) * sizeof (WCHAR
));
585 if (WScriptFileName
== NULL
) {
586 Error (__FILE__
, __LINE__
, 0, "failed to allocate memory", NULL
);
590 swprintf (WScriptFileName
, L
"%S", ScriptFileName
);
591 if ((SourceFile
.FilePtr
= _wfopen (WScriptFileName
, L
"r")) == NULL
) {
592 free (WScriptFileName
);
593 Error (NULL
, 0, 0, ScriptFileName
, "failed to open script file for reading");
597 free (WScriptFileName
);
598 fseek (SourceFile
.FilePtr
, 0, SEEK_END
);
599 SourceFile
.FileSize
= ftell (SourceFile
.FilePtr
);
600 rewind (SourceFile
.FilePtr
);
601 SourceFile
.FileBuffer
= (WCHAR
*) malloc (SourceFile
.FileSize
+ sizeof (WCHAR
));
602 if (SourceFile
.FileBuffer
== NULL
) {
603 Error (__FILE__
, __LINE__
, 0, ScriptFileName
, "failed to allocate memory to read in file contents");
607 if (fread (SourceFile
.FileBuffer
, SourceFile
.FileSize
, 1, SourceFile
.FilePtr
) != 1) {
608 Error (NULL
, 0, 0, ScriptFileName
, "failed to read file contents");
612 SourceFile
.FileBufferPtr
= SourceFile
.FileBuffer
;
613 SourceFile
.LineNum
= 1;
614 if (SourceFile
.FileBuffer
[0] != UNICODE_FILE_START
) {
615 Error (ScriptFileName
, 1, 0, "file does not appear to be a unicode file", NULL
);
619 SourceFile
.FileBufferPtr
++;
620 SourceFile
.FileBuffer
[SourceFile
.FileSize
/ sizeof (WCHAR
)] = 0;
622 // Walk the source file buffer and replace all carriage returns with 0 so
623 // we can print from the file contents on parse errors.
626 while (!EndOfFile (&SourceFile
)) {
627 if (SourceFile
.FileBufferPtr
[0] == UNICODE_CR
) {
628 SourceFile
.FileBufferPtr
[0] = 0;
630 } else if (SourceFile
.FileBufferPtr
[0] == UNICODE_LF
) {
632 } else if (InComment
) {
633 SourceFile
.FileBufferPtr
[0] = UNICODE_SPACE
;
634 } else if ((SourceFile
.FileBufferPtr
[0] == UNICODE_SLASH
) && (SourceFile
.FileBufferPtr
[1] == UNICODE_SLASH
)) {
636 SourceFile
.FileBufferPtr
[0] = UNICODE_SPACE
;
639 SourceFile
.FileBufferPtr
++;
642 // Reposition to the start of the file, but skip over the unicode file start
644 SourceFile
.FileBufferPtr
= SourceFile
.FileBuffer
;
645 SourceFile
.FileBufferPtr
++;
646 SourceFile
.EndOfFile
= 0;
647 CapsuleHeader
->OffsetToOemDefinedHeader
= ftell (OutFptr
);
649 // Parse the OEM bytes
651 if (ParseOemInfo (&SourceFile
, OutFptr
) != STATUS_SUCCESS
) {
655 // Parse the author information
657 CapsuleHeader
->OffsetToAuthorInformation
= ftell (OutFptr
);
658 if (ParseCapsuleInfo (&SourceFile
, OutFptr
, AUTHOR_INFO_STRING
) != STATUS_SUCCESS
) {
662 // Parse the revision information
664 CapsuleHeader
->OffsetToRevisionInformation
= ftell (OutFptr
);
665 if (ParseCapsuleInfo (&SourceFile
, OutFptr
, REVISION_INFO_STRING
) != STATUS_SUCCESS
) {
669 // Parse the short description
671 CapsuleHeader
->OffsetToShortDescription
= ftell (OutFptr
);
672 if (ParseCapsuleInfo (&SourceFile
, OutFptr
, SHORT_DESCRIPTION_STRING
) != STATUS_SUCCESS
) {
676 // Parse the long description
678 CapsuleHeader
->OffsetToLongDescription
= ftell (OutFptr
);
679 if (ParseCapsuleInfo (&SourceFile
, OutFptr
, LONG_DESCRIPTION_STRING
) != STATUS_SUCCESS
) {
683 // Better be end of contents
685 SkipWhiteSpace (&SourceFile
);
686 if (!EndOfFile (&SourceFile
)) {
687 Error (ScriptFileName
, SourceFile
.LineNum
, 0, NULL
, "expected end-of-file, not %.20S", SourceFile
.FileBufferPtr
);
691 CapsuleHeader
->OffsetToCapsuleBody
= ftell (OutFptr
);
693 fwrite (CapsuleHeader
, sizeof (EFI_CAPSULE_HEADER
), 1, OutFptr
);
694 fseek (OutFptr
, 0, SEEK_END
);
695 Status
= STATUS_SUCCESS
;
697 if (SourceFile
.FilePtr
!= NULL
) {
698 fclose (SourceFile
.FilePtr
);
701 if (SourceFile
.FileBuffer
!= NULL
) {
702 free (SourceFile
.FileBuffer
);
708 return STATUS_SUCCESS
;
711 // Parse the OEM data of format:
713 // GUID = 12345676-1234-1234-123456789ABC
714 // DATA = 0x01, 0x02, 0x03...
720 SOURCE_FILE
*SourceFile
,
727 GC_TODO: Add function description
731 SourceFile - GC_TODO: add argument description
732 OutFptr - GC_TODO: add argument description
736 GC_TODO: add return values
740 long OemHeaderOffset
;
742 EFI_CAPSULE_OEM_HEADER OemHeader
;
748 Status
= STATUS_ERROR
;
749 memset (&OemHeader
, 0, sizeof (EFI_CAPSULE_OEM_HEADER
));
750 OemHeaderOffset
= ftell (OutFptr
);
751 OemHeader
.HeaderSize
= sizeof (EFI_CAPSULE_OEM_HEADER
);
752 if (fwrite (&OemHeader
, sizeof (EFI_CAPSULE_OEM_HEADER
), 1, OutFptr
) != 1) {
753 Error (NULL
, 0, 0, "failed to write OEM header to output file", NULL
);
757 if (!IsToken (SourceFile
, OEM_HEADER_STRING
)) {
759 SourceFile
->FileName
,
763 "expected %S, not %.20S",
765 SourceFile
->FileBufferPtr
770 if (!IsToken (SourceFile
, EQUAL_STRING
)) {
772 SourceFile
->FileName
,
776 "expected %S, not %.20S",
778 SourceFile
->FileBufferPtr
783 if (!IsToken (SourceFile
, OPEN_BRACE_STRING
)) {
785 SourceFile
->FileName
,
789 "expected %S, not %.20S",
791 SourceFile
->FileBufferPtr
796 // Look for: GUID = xxxxxxx-xxxx-xxxx-xxxxxxxxxxxxx
798 if (!IsToken (SourceFile
, GUID_STRING
)) {
800 SourceFile
->FileName
,
804 "expected %S, not %.20S",
806 SourceFile
->FileBufferPtr
811 if (!IsToken (SourceFile
, EQUAL_STRING
)) {
813 SourceFile
->FileName
,
817 "expected %S, not %.20S",
819 SourceFile
->FileBufferPtr
824 // Parse the xxxxxxxx-xxxx-xxxx-xxxx portion of the GUID
826 SkipWhiteSpace (SourceFile
);
827 if (GetHexValue (SourceFile
, &Data
, 8) != STATUS_SUCCESS
) {
828 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "invalid GUID", NULL
);
832 OemHeader
.OemGuid
.Data1
= Data
;
833 if (!IsToken (SourceFile
, L
"-")) {
835 SourceFile
->FileName
,
839 "expected dash in GUID, not %S",
840 SourceFile
->FileBufferPtr
847 for (DigitCount
= 0; DigitCount
< 3; DigitCount
++) {
848 if (GetHexValue (SourceFile
, &Data
, 4) != STATUS_SUCCESS
) {
849 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "invalid GUID", NULL
);
853 switch (DigitCount
) {
855 OemHeader
.OemGuid
.Data2
= (UINT16
) Data
;
859 OemHeader
.OemGuid
.Data3
= (UINT16
) Data
;
863 OemHeader
.OemGuid
.Data4
[1] = (UINT8
) Data
;
864 OemHeader
.OemGuid
.Data4
[0] = (UINT8
) (Data
>> 8);
868 if (!IsToken (SourceFile
, L
"-")) {
870 SourceFile
->FileName
,
874 "expected dash in GUID, not %S",
875 SourceFile
->FileBufferPtr
881 // Pick up the last 6 bytes of the GUID
883 SaveFilePos
= SourceFile
->FileBufferPtr
;
884 for (DigitCount
= 0; DigitCount
< 6; DigitCount
++) {
885 if (GetHexValue (SourceFile
, &Data
, 2) != STATUS_SUCCESS
) {
886 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "invalid GUID", NULL
);
890 OemHeader
.OemGuid
.Data4
[DigitCount
+ 2] = (UINT8
) Data
;
893 // Now read raw OEM data bytes. May or may not be present.
894 // DATA = 0x01, 0x02, 0x02...
896 if (IsToken (SourceFile
, CLOSE_BRACE_STRING
)) {
897 Status
= STATUS_SUCCESS
;
901 if (!IsToken (SourceFile
, DATA_STRING
)) {
903 SourceFile
->FileName
,
907 "expected %S, not %.20S",
909 SourceFile
->FileBufferPtr
914 if (!IsToken (SourceFile
, EQUAL_STRING
)) {
916 SourceFile
->FileName
,
920 "expected %S, not %.20S",
922 SourceFile
->FileBufferPtr
927 while (!EndOfFile (SourceFile
)) {
928 if (IsToken (SourceFile
, CLOSE_BRACE_STRING
)) {
929 Status
= STATUS_SUCCESS
;
933 if (IsToken (SourceFile
, L
"0x")) {
934 if (swscanf (SourceFile
->FileBufferPtr
, L
"%x", &Data
) != 1) {
936 SourceFile
->FileName
,
940 "expected hex byte value, not %.20S",
941 SourceFile
->FileBufferPtr
948 SourceFile
->FileName
,
952 "expected byte hex byte value at %.20S",
953 SourceFile
->FileBufferPtr
958 // Skip over the hex digits, then write the data
960 while (iswxdigit (SourceFile
->FileBufferPtr
[0])) {
961 SourceFile
->FileBufferPtr
++;
964 ByteData
= (UINT8
) Data
;
965 if (fwrite (&ByteData
, 1, 1, OutFptr
) != 1) {
966 Error (NULL
, 0, 0, "failed to write OEM data to output file", NULL
);
970 OemHeader
.HeaderSize
++;
974 IsToken (SourceFile
, L
",");
977 SourceFile
->FileName
,
981 "expected hex OEM data, not %.20S",
982 SourceFile
->FileBufferPtr
988 if (EndOfFile (SourceFile
)) {
990 SourceFile
->FileName
,
994 "expected %S close to OEM header data",
1000 Status
= STATUS_SUCCESS
;
1003 // re-write the oem header if no errors
1005 if (Status
== STATUS_SUCCESS
) {
1006 fseek (OutFptr
, OemHeaderOffset
, SEEK_SET
);
1007 if (fwrite (&OemHeader
, sizeof (EFI_CAPSULE_OEM_HEADER
), 1, OutFptr
) != 1) {
1008 Error (NULL
, 0, 0, "failed to write OEM header to output file", NULL
);
1012 fseek (OutFptr
, 0, SEEK_END
);
1021 SOURCE_FILE
*SourceFile
,
1025 // GC_TODO: function comment should start with '/*++'
1027 // GC_TODO: function comment is missing 'Routine Description:'
1028 // GC_TODO: function comment is missing 'Arguments:'
1029 // GC_TODO: function comment is missing 'Returns:'
1030 // GC_TODO: SourceFile - add argument and description to function comment
1031 // GC_TODO: OutFptr - add argument and description to function comment
1032 // GC_TODO: SectionName - add argument and description to function comment
1033 // Parse: eng "string " "parts"
1034 // spa "string " "parts"
1035 // Write out: "eng string parts\0spa string parts\0\0
1043 Status
= STATUS_ERROR
;
1045 Spacebar
= UNICODE_SPACE
;
1047 if (!IsToken (SourceFile
, SectionName
)) {
1049 SourceFile
->FileName
,
1050 SourceFile
->LineNum
,
1053 "expected %S, not %.20S",
1055 SourceFile
->FileBufferPtr
1060 if (!IsToken (SourceFile
, EQUAL_STRING
)) {
1062 SourceFile
->FileName
,
1063 SourceFile
->LineNum
,
1066 "expected %S, not %.20S",
1068 SourceFile
->FileBufferPtr
1073 if (!IsToken (SourceFile
, OPEN_BRACE_STRING
)) {
1075 SourceFile
->FileName
,
1076 SourceFile
->LineNum
,
1079 "expected %S, not %.20S",
1081 SourceFile
->FileBufferPtr
1086 while (!EndOfFile (SourceFile
)) {
1087 if (IsToken (SourceFile
, CLOSE_BRACE_STRING
)) {
1091 // Look for language identifier (3 lowercase chars)
1093 if ((SourceFile
->FileBufferPtr
[0] >= UNICODE_a
) &&
1094 (SourceFile
->FileBufferPtr
[0] <= UNICODE_z
) &&
1095 (SourceFile
->FileBufferPtr
[1] >= UNICODE_a
) &&
1096 (SourceFile
->FileBufferPtr
[1] <= UNICODE_z
) &&
1097 (SourceFile
->FileBufferPtr
[2] >= UNICODE_a
) &&
1098 (SourceFile
->FileBufferPtr
[2] <= UNICODE_z
) &&
1099 IsWhiteSpace (SourceFile
->FileBufferPtr
[3])
1102 // Write the 3 chars followed by a spacebar, and then look for opening quote
1104 fwrite (SourceFile
->FileBufferPtr
, sizeof (WCHAR
), 1, OutFptr
);
1105 SourceFile
->FileBufferPtr
++;
1106 fwrite (SourceFile
->FileBufferPtr
, sizeof (WCHAR
), 1, OutFptr
);
1107 SourceFile
->FileBufferPtr
++;
1108 fwrite (SourceFile
->FileBufferPtr
, sizeof (WCHAR
), 1, OutFptr
);
1109 SourceFile
->FileBufferPtr
++;
1110 fwrite (&Spacebar
, sizeof (WCHAR
), 1, OutFptr
);
1112 while (IsToken (SourceFile
, L
"\"")) {
1114 while (!EndOfFile (SourceFile
)) {
1115 if (SourceFile
->FileBufferPtr
[0] == UNICODE_DOUBLE_QUOTE
) {
1116 SourceFile
->FileBufferPtr
++;
1118 } else if ((SourceFile
->FileBufferPtr
[0] == UNICODE_LF
) || (SourceFile
->FileBufferPtr
[0] == 0)) {
1119 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "missing closing quote on string", NULL
);
1122 fwrite (SourceFile
->FileBufferPtr
, sizeof (WCHAR
), 1, OutFptr
);
1123 SourceFile
->FileBufferPtr
++;
1128 if (StringCount
== 0) {
1130 SourceFile
->FileName
,
1131 SourceFile
->LineNum
,
1134 "expected quoted string, not %.20S",
1135 SourceFile
->FileBufferPtr
1140 // This string's null terminator
1142 fwrite (&Zero
, sizeof (WCHAR
), 1, OutFptr
);
1145 SourceFile
->FileName
,
1146 SourceFile
->LineNum
,
1149 "expected valid language identifer, not %.20S",
1150 SourceFile
->FileBufferPtr
1156 // Double null terminator
1158 fwrite (&Zero
, sizeof (WCHAR
), 1, OutFptr
);
1159 Status
= STATUS_SUCCESS
;
1167 INT8
*CapsuleFileName
1171 Routine Description:
1172 We've created an entire capsule image. Now split it up into the
1173 size pieces they requested.
1176 CapsuleFileName - name of an existing capsule file on disk
1179 STATUS_SUCCESS - if no problems
1182 This implementation reads in the entire capsule image from
1183 disk, then overwrites the original file with the first
1189 EFI_CAPSULE_HEADER
*CapHdr
;
1191 EFI_CAPSULE_HEADER Hdr
;
1197 UINT32 SequenceNumber
;
1199 INT8 FileName
[MAX_PATH
];
1203 // Figure out the total size, then rewind the input file and
1204 // read the entire thing in
1206 if ((CapFptr
= fopen (CapsuleFileName
, "rb")) == NULL
) {
1207 Error (NULL
, 0, 0, CapsuleFileName
, "failed to open capsule image for reading");
1208 return STATUS_ERROR
;
1212 Status
= STATUS_SUCCESS
;
1213 fseek (CapFptr
, 0, SEEK_END
);
1214 SizeLeft
= ftell (CapFptr
);
1215 fseek (CapFptr
, 0, SEEK_SET
);
1216 CapHdr
= (EFI_CAPSULE_HEADER
*) malloc (SizeLeft
);
1217 if (CapHdr
== NULL
) {
1218 Error (NULL
, 0, 0, "memory allocation failure", NULL
);
1222 if (fread (CapHdr
, SizeLeft
, 1, CapFptr
) != 1) {
1223 Error (NULL
, 0, 0, "failed to read capsule contents", "split failed");
1230 // Get a GUID to fill in the InstanceId GUID in the header
1232 CreateGuid (&CapHdr
->InstanceId
);
1235 // If the split size is larger than the original capsule image, then
1238 if (mOptions
.SizeList
->Size
>= SizeLeft
) {
1239 mOptions
.SizeList
->Size
= SizeLeft
;
1243 // First size has to be big enough for the original header
1245 if (mOptions
.SizeList
->Size
< CapHdr
->OffsetToCapsuleBody
) {
1246 Error (NULL
, 0, 0, "first split size is insufficient for the original capsule header", NULL
);
1250 // Initialize the header we'll use on all but the first part
1252 memset (&Hdr
, 0, sizeof (Hdr
));
1253 Hdr
.CapsuleGuid
= CapHdr
->CapsuleGuid
;
1254 Hdr
.HeaderSize
= sizeof (Hdr
);
1255 Hdr
.Flags
= CapHdr
->Flags
;
1256 Hdr
.InstanceId
= CapHdr
->InstanceId
;
1257 Hdr
.CapsuleImageSize
= CapHdr
->CapsuleImageSize
;
1258 Hdr
.OffsetToCapsuleBody
= Hdr
.HeaderSize
;
1259 Hdr
.SequenceNumber
= 1;
1261 // printf ("Created %s - 0x%X bytes\n", CapsuleFileName, mOptions.SizeList->Size);
1263 Buffer
= (UINT8
*) CapHdr
;
1265 // Walk the list of sizes and write out a capsule header, and
1266 // then the raw capsule data.
1268 // SizeLeft -= mOptions.SizeList->Size;
1270 mOptions
.CurrentSize
= mOptions
.SizeList
;
1272 CurrentSize
= mOptions
.CurrentSize
->Size
;
1273 GetSplitFileName (mOptions
.OutputFileName
, FileName
, SequenceNumber
);
1274 if ((OutFptr
= fopen (FileName
, "wb")) == NULL
) {
1275 Error (NULL
, 0, 0, FileName
, "failed to open split file for writing");
1279 if (Buffer
== (UINT8
*) CapHdr
) {
1281 // First part -- write out original header and data
1283 if (fwrite (Buffer
, CurrentSize
, 1, OutFptr
) != 1) {
1284 Error (NULL
, 0, 0, FileName
, "failed to write to split image file");
1288 SizeLeft
-= CurrentSize
;
1289 Buffer
+= CurrentSize
;
1290 DataSize
= CurrentSize
;
1291 FileSize
= CurrentSize
;
1294 // Not the first part. Write the default header, and then the raw bytes from the
1297 if (CurrentSize
<= sizeof (Hdr
)) {
1298 Error (NULL
, 0, 0, "split size too small for capsule header + data", "0x%X", CurrentSize
);
1302 DataSize
= CurrentSize
- sizeof (Hdr
);
1303 if (DataSize
> SizeLeft
) {
1304 DataSize
= SizeLeft
;
1307 if (fwrite (&Hdr
, sizeof (Hdr
), 1, OutFptr
) != 1) {
1308 Error (NULL
, 0, 0, FileName
, "failed to write capsule header to output file");
1313 if (fwrite (Buffer
, DataSize
, 1, OutFptr
) != 1) {
1314 Error (NULL
, 0, 0, FileName
, "failed to write capsule data to output file");
1319 Hdr
.SequenceNumber
++;
1321 SizeLeft
-= DataSize
;
1322 FileSize
= DataSize
+ sizeof (Hdr
);
1325 // Next size in list if there is one
1327 if (mOptions
.CurrentSize
->Next
!= NULL
) {
1328 mOptions
.CurrentSize
= mOptions
.CurrentSize
->Next
;
1334 printf ("Created %s - 0x%X bytes (0x%X bytes of data)\n", FileName
, FileSize
, DataSize
);
1339 Status
= STATUS_ERROR
;
1341 if (CapHdr
!= NULL
) {
1345 if (CapFptr
!= NULL
) {
1349 if (OutFptr
!= NULL
) {
1356 return STATUS_SUCCESS
;
1364 UINT32 SequenceNumber
1368 Routine Description:
1370 GC_TODO: Add function description
1374 BaseFileName - GC_TODO: add argument description
1375 NewFileName - GC_TODO: add argument description
1376 SequenceNumber - GC_TODO: add argument description
1380 GC_TODO: add return values
1386 Routine Description:
1387 Given an initial split capsule file name and a sequence number,
1388 create an appropriate file name for this split of a capsule image.
1391 BaseFileName - name of of the first split file in the series
1392 NewFileName - output name of the split file
1393 SequenceNumber - 0-based sequence number of split images
1396 TRUE - name created successfully
1406 // Work back from the end of the file name and see if there is a number somewhere
1408 for (Ptr
= BaseFileName
+ strlen (BaseFileName
) - 1; (Ptr
> BaseFileName
) && !isdigit (*Ptr
); Ptr
--)
1410 if ((Ptr
== BaseFileName
) && (!isdigit (*Ptr
))) {
1412 // Found no number, so just add it to the end
1414 sprintf (NewFileName
, "%s%d", BaseFileName
, SequenceNumber
);
1418 // Found a number. Look back to find the first digit.
1420 Part2Start
= Ptr
+ 1;
1421 for (Digits
= 1; isdigit (*Ptr
) && (Ptr
> BaseFileName
); Ptr
--, Digits
++)
1423 if (!isdigit (*Ptr
)) {
1428 BaseOffset
= atoi (Ptr
);
1429 SequenceNumber
= SequenceNumber
+ BaseOffset
;
1432 // Copy the first part of the original file name to the new filename
1433 // This is the path for filenames with format path\name001.cap
1435 Len
= (UINT32
) Ptr
- (UINT32
) BaseFileName
;
1436 strncpy (NewFileName
, BaseFileName
, Len
);
1437 sprintf (NewFileName
+ Len
, "%0*d", Digits
, SequenceNumber
);
1438 strcat (NewFileName
, Part2Start
);
1442 // Only one digit found. This is the path for filenames with
1443 // format path\name1.cap
1445 Len
= (UINT32
) Ptr
- (UINT32
) BaseFileName
+ 1;
1446 strncpy (NewFileName
, BaseFileName
, Len
);
1447 sprintf (NewFileName
+ Len
- 1, "%d", SequenceNumber
);
1448 strcat (NewFileName
, Part2Start
);
1461 Routine Description:
1463 GC_TODO: Add function description
1467 Char - GC_TODO: add argument description
1471 GC_TODO: add return values
1496 Routine Description:
1498 GC_TODO: Add function description
1502 File - GC_TODO: add argument description
1503 Token - GC_TODO: add argument description
1507 GC_TODO: add return values
1511 SkipWhiteSpace (File
);
1512 if (EndOfFile (File
)) {
1516 if (wcsncmp (Token
, File
->FileBufferPtr
, wcslen (Token
)) == 0) {
1517 File
->FileBufferPtr
+= wcslen (Token
);
1526 CheckFirmwareVolumeHeader (
1533 Routine Description:
1535 GC_TODO: Add function description
1539 FileName - GC_TODO: add argument description
1540 Buffer - GC_TODO: add argument description
1541 BufferSize - GC_TODO: add argument description
1545 GC_TODO: add return values
1549 EFI_FIRMWARE_VOLUME_HEADER
*Hdr
;
1550 EFI_GUID FVHeaderGuid
= EFI_FIRMWARE_FILE_SYSTEM_GUID
;
1552 Hdr
= (EFI_FIRMWARE_VOLUME_HEADER
*) Buffer
;
1553 if (Hdr
->Signature
!= EFI_FVH_SIGNATURE
) {
1554 Error (NULL
, 0, 0, FileName
, "file does not appear to be a firmware volume (bad signature)");
1555 return STATUS_ERROR
;
1558 if (Hdr
->Revision
!= EFI_FVH_REVISION
) {
1559 Error (NULL
, 0, 0, FileName
, "unsupported firmware volume header version");
1560 return STATUS_ERROR
;
1563 if (Hdr
->FvLength
> BufferSize
) {
1564 Error (NULL
, 0, 0, FileName
, "malformed firmware volume -- FvLength > file size");
1565 return STATUS_ERROR
;
1568 if (memcmp (&Hdr
->FileSystemGuid
, &FVHeaderGuid
, sizeof (EFI_GUID
)) != 0) {
1569 Error (NULL
, 0, 0, FileName
, "invalid FFS GUID in firmware volume header");
1570 return STATUS_ERROR
;
1573 return STATUS_SUCCESS
;
1583 Routine Description:
1585 GC_TODO: Add function description
1593 GC_TODO: add return values
1599 FILE_LIST
*FileList
;
1600 EFI_CAPSULE_HEADER CapsuleHeader
;
1601 EFI_FIRMWARE_VOLUME_HEADER FVHeader
;
1602 EFI_CAPSULE_OEM_HEADER
*OemHeader
;
1605 UINT32 CapsuleHeaderDataSize
;
1607 UINT8
*CapsuleHeaderData
;
1611 CapsuleHeaderData
= NULL
;
1612 FileList
= mOptions
.FileList
;
1613 while (FileList
!= NULL
) {
1614 if ((InFptr
= fopen (FileList
->FileName
, "rb")) == NULL
) {
1615 Error (NULL
, 0, 0, FileList
->FileName
, "failed to open file for reading");
1619 if (fread (&CapsuleHeader
, sizeof (EFI_CAPSULE_HEADER
), 1, InFptr
) != 1) {
1620 Error (NULL
, 0, 0, FileList
->FileName
, "failed to read capsule header");
1624 fseek (InFptr
, 0, SEEK_END
);
1625 FileSize
= ftell (InFptr
);
1626 if (CapsuleHeader
.CapsuleImageSize
> FileSize
) {
1633 "Capsule %s Size=0x%X CargoSize=0x%X\n",
1636 FileSize
- CapsuleHeader
.OffsetToCapsuleBody
1639 " GUID %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
1640 CapsuleHeader
.CapsuleGuid
.Data1
,
1641 (UINT32
) CapsuleHeader
.CapsuleGuid
.Data2
,
1642 (UINT32
) CapsuleHeader
.CapsuleGuid
.Data3
,
1643 (UINT32
) CapsuleHeader
.CapsuleGuid
.Data4
[0],
1644 (UINT32
) CapsuleHeader
.CapsuleGuid
.Data4
[1],
1645 (UINT32
) CapsuleHeader
.CapsuleGuid
.Data4
[2],
1646 (UINT32
) CapsuleHeader
.CapsuleGuid
.Data4
[3],
1647 (UINT32
) CapsuleHeader
.CapsuleGuid
.Data4
[4],
1648 (UINT32
) CapsuleHeader
.CapsuleGuid
.Data4
[5],
1649 (UINT32
) CapsuleHeader
.CapsuleGuid
.Data4
[6],
1650 (UINT32
) CapsuleHeader
.CapsuleGuid
.Data4
[7]
1652 if (memcmp (&CapsuleHeader
.CapsuleGuid
, &mEfiCapsuleHeaderGuid
, sizeof (EFI_GUID
)) != 0) {
1653 printf (" INVALID GUID");
1657 printf (" Header size 0x%08X\n", CapsuleHeader
.HeaderSize
);
1658 printf (" Flags 0x%08X\n", CapsuleHeader
.Flags
);
1660 printf (" Capsule image size 0x%08X\n", CapsuleHeader
.CapsuleImageSize
);
1662 printf (" Capsule image size 0x%08X (split)\n", CapsuleHeader
.CapsuleImageSize
);
1665 printf (" Sequence number %d\n", CapsuleHeader
.SequenceNumber
);
1667 " InstanceId %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
1668 CapsuleHeader
.InstanceId
.Data1
,
1669 (UINT32
) CapsuleHeader
.InstanceId
.Data2
,
1670 (UINT32
) CapsuleHeader
.InstanceId
.Data3
,
1671 (UINT32
) CapsuleHeader
.InstanceId
.Data4
[0],
1672 (UINT32
) CapsuleHeader
.InstanceId
.Data4
[1],
1673 (UINT32
) CapsuleHeader
.InstanceId
.Data4
[2],
1674 (UINT32
) CapsuleHeader
.InstanceId
.Data4
[3],
1675 (UINT32
) CapsuleHeader
.InstanceId
.Data4
[4],
1676 (UINT32
) CapsuleHeader
.InstanceId
.Data4
[5],
1677 (UINT32
) CapsuleHeader
.InstanceId
.Data4
[6],
1678 (UINT32
) CapsuleHeader
.InstanceId
.Data4
[7]
1680 printf (" Offset to capsule 0x%X\n", CapsuleHeader
.OffsetToCapsuleBody
);
1682 // Dump header data if there
1684 CapsuleHeaderDataSize
= CapsuleHeader
.OffsetToCapsuleBody
- CapsuleHeader
.HeaderSize
;
1685 if (CapsuleHeaderDataSize
!= 0) {
1686 CapsuleHeaderData
= (UINT8
*) malloc (CapsuleHeaderDataSize
);
1687 if (CapsuleHeaderData
== NULL
) {
1692 "failed to allocate memory to read in capsule header data",
1694 CapsuleHeaderDataSize
1699 fseek (InFptr
, CapsuleHeader
.HeaderSize
, SEEK_SET
);
1700 if (fread (CapsuleHeaderData
, CapsuleHeaderDataSize
, 1, InFptr
) != 1) {
1705 "failed to read capsule header data contents from file",
1707 CapsuleHeaderDataSize
1712 // ************************************************************************
1716 // ************************************************************************
1718 if (CapsuleHeader
.OffsetToOemDefinedHeader
!= 0) {
1719 OemHeader
= (EFI_CAPSULE_OEM_HEADER
*) (CapsuleHeaderData
+ CapsuleHeader
.OffsetToOemDefinedHeader
- CapsuleHeader
.HeaderSize
);
1720 printf (" OEM Header\n");
1722 " GUID %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
1723 OemHeader
->OemGuid
.Data1
,
1724 (UINT32
) OemHeader
->OemGuid
.Data2
,
1725 (UINT32
) OemHeader
->OemGuid
.Data3
,
1726 (UINT32
) OemHeader
->OemGuid
.Data4
[0],
1727 (UINT32
) OemHeader
->OemGuid
.Data4
[1],
1728 (UINT32
) OemHeader
->OemGuid
.Data4
[2],
1729 (UINT32
) OemHeader
->OemGuid
.Data4
[3],
1730 (UINT32
) OemHeader
->OemGuid
.Data4
[4],
1731 (UINT32
) OemHeader
->OemGuid
.Data4
[5],
1732 (UINT32
) OemHeader
->OemGuid
.Data4
[6],
1733 (UINT32
) OemHeader
->OemGuid
.Data4
[7]
1735 printf (" Header size: 0x%X\n", OemHeader
->HeaderSize
);
1736 printf (" OEM data");
1737 BPtr
= (UINT8
*) (OemHeader
+ 1);
1738 for (ByteCount
= 0; ByteCount
< OemHeader
->HeaderSize
- sizeof (EFI_CAPSULE_OEM_HEADER
); ByteCount
++) {
1739 if ((ByteCount
& 0x7) == 0) {
1743 printf ("%02X ", (UINT32
) *BPtr
);
1750 // ************************************************************************
1752 // Author, revision, short description, and long description information
1754 // ************************************************************************
1756 if (CapsuleHeader
.OffsetToAuthorInformation
!= 0) {
1757 if (DumpCapsuleHeaderStrings (
1758 "Author information",
1759 (WCHAR
*) (CapsuleHeaderData
+ CapsuleHeader
.OffsetToAuthorInformation
- CapsuleHeader
.HeaderSize
)
1760 ) != STATUS_SUCCESS
) {
1765 if (CapsuleHeader
.OffsetToRevisionInformation
!= 0) {
1766 if (DumpCapsuleHeaderStrings (
1767 "Revision information",
1768 (WCHAR
*) (CapsuleHeaderData
+ CapsuleHeader
.OffsetToRevisionInformation
- CapsuleHeader
.HeaderSize
)
1769 ) != STATUS_SUCCESS
) {
1774 if (CapsuleHeader
.OffsetToShortDescription
!= 0) {
1775 if (DumpCapsuleHeaderStrings (
1776 "Short description",
1777 (WCHAR
*) (CapsuleHeaderData
+ CapsuleHeader
.OffsetToShortDescription
- CapsuleHeader
.HeaderSize
)
1778 ) != STATUS_SUCCESS
) {
1783 if (CapsuleHeader
.OffsetToLongDescription
!= 0) {
1784 if (DumpCapsuleHeaderStrings (
1786 (WCHAR
*) (CapsuleHeaderData
+ CapsuleHeader
.OffsetToLongDescription
- CapsuleHeader
.HeaderSize
)
1787 ) != STATUS_SUCCESS
) {
1793 // If it's not a split image, or it is a split image and this is the first in the series, then
1794 // dump the cargo volume.
1796 if ((!SplitImage
) || (CapsuleHeader
.SequenceNumber
== 0)) {
1797 printf (" Cargo FV dump\n");
1798 fseek (InFptr
, CapsuleHeader
.OffsetToCapsuleBody
, SEEK_SET
);
1799 if (fread (&FVHeader
, sizeof (EFI_FIRMWARE_VOLUME_HEADER
), 1, InFptr
) != 1) {
1800 Error (NULL
, 0, 0, FileList
->FileName
, "failed to read cargo FV header");
1804 printf (" FV length 0x%X", FVHeader
.FvLength
);
1805 if (FileSize
- CapsuleHeader
.OffsetToCapsuleBody
!= FVHeader
.FvLength
) {
1807 printf (" ERROR: expected 0x%X to jive with file size on disk", FileSize
- CapsuleHeader
.OffsetToCapsuleBody
);
1812 printf (" Signature 0x%X ", FVHeader
.Signature
);
1813 if (FVHeader
.Signature
== EFI_FVH_SIGNATURE
) {
1816 printf ("INVALID\n");
1819 printf (" FV header length 0x%X\n", (UINT32
) FVHeader
.HeaderLength
);
1820 printf (" Revision 0x%X\n", (UINT32
) FVHeader
.Revision
);
1824 FileList
= FileList
->Next
;
1828 if (InFptr
!= NULL
) {
1832 if (CapsuleHeaderData
!= NULL
) {
1833 free (CapsuleHeaderData
);
1845 Routine Description:
1846 Join split capsule images into a single image. This is the
1847 support function for the -j command-line option.
1853 STATUS_SUCCESS - no problems encountered
1862 FILE_LIST
*FileList
;
1864 EFI_CAPSULE_HEADER CapHdr
;
1865 EFI_CAPSULE_HEADER
*CapHdrPtr
;
1867 UINT32 SequenceNumber
;
1869 // Must have at least two files for join mode
1871 if ((mOptions
.FileList
== NULL
) || (mOptions
.FileList
->Next
== NULL
)) {
1872 Error (NULL
, 0, 0, "must specify at least two file names to join", NULL
);
1873 return STATUS_ERROR
;
1876 // Open the output file
1878 if ((OutFptr
= fopen (mOptions
.OutputFileName
, "wb")) == NULL
) {
1879 Error (NULL
, 0, 0, mOptions
.OutputFileName
, "failed to open output file for writing");
1880 return STATUS_ERROR
;
1883 FileList
= mOptions
.FileList
;
1888 while (FileList
!= NULL
) {
1889 if ((InFptr
= fopen (FileList
->FileName
, "rb")) == NULL
) {
1890 Error (NULL
, 0, 0, FileList
->FileName
, "failed to open file for reading");
1894 // Allocate a buffer into which we can read the file.
1896 fseek (InFptr
, 0, SEEK_END
);
1897 Size
= ftell (InFptr
);
1899 Buffer
= (char *) malloc (Size
);
1900 if (Buffer
== NULL
) {
1901 Error (__FILE__
, __LINE__
, 0, FileList
->FileName
, "failed to allocate buffer to read file into");
1905 CapHdrPtr
= (EFI_CAPSULE_HEADER
*) Buffer
;
1906 if (fread ((void *) Buffer
, Size
, 1, InFptr
) != 1) {
1907 Error (NULL
, 0, 0, FileList
->FileName
, "failed to read file contents");
1911 // Check the header for validity. Check size first.
1913 if (Size
< sizeof (EFI_CAPSULE_HEADER
)) {
1914 Error (NULL
, 0, 0, FileList
->FileName
, "file size is insufficient for a capsule header");
1920 if (memcmp (&CapHdrPtr
->CapsuleGuid
, &mEfiCapsuleHeaderGuid
, sizeof (EFI_GUID
)) != 0) {
1921 Error (NULL
, 0, 0, FileList
->FileName
, "invalid capsule GUID");
1925 // Check sequence number
1927 if (CapHdrPtr
->SequenceNumber
!= SequenceNumber
) {
1933 "invalid sequence number %d (expected %d)",
1934 CapHdrPtr
->SequenceNumber
,
1940 // If the first file, read save the capsule header
1942 if (SequenceNumber
== 0) {
1943 memcpy (&CapHdr
, CapHdrPtr
, sizeof (EFI_CAPSULE_HEADER
));
1945 // Erase the InstanceId GUID
1947 memset (&CapHdrPtr
->InstanceId
, 0, sizeof (EFI_GUID
));
1948 if (fwrite (Buffer
, Size
, 1, OutFptr
) != 1) {
1949 Error (NULL
, 0, 0, FileList
->FileName
, "failed to write contents to output file");
1953 if (CapHdr
.CapsuleImageSize
< Size
) {
1954 Error (NULL
, 0, 0, FileList
->FileName
, "capsule image size in capsule header < image size");
1958 SizeLeft
= CapHdr
.CapsuleImageSize
- Size
;
1961 // Check the GUID against the first file's GUID
1963 if (memcmp (&CapHdr
.CapsuleGuid
, &CapHdrPtr
->CapsuleGuid
, sizeof (EFI_GUID
)) != 0) {
1964 Error (NULL
, 0, 0, FileList
->FileName
, "GUID does not match first file's GUID");
1968 // Make sure we're not throwing out any header info
1970 if (CapHdrPtr
->OffsetToCapsuleBody
> sizeof (EFI_CAPSULE_HEADER
)) {
1972 // Could be the split information, so just emit a warning
1979 "image appears to have additional capsule header information -- ignoring"
1981 } else if (CapHdrPtr
->OffsetToCapsuleBody
< sizeof (EFI_CAPSULE_HEADER
)) {
1982 Error (NULL
, 0, 0, FileList
->FileName
, "offset to capsule body in capsule header is insufficient");
1986 if (fwrite (Buffer
+ CapHdrPtr
->OffsetToCapsuleBody
, Size
- CapHdrPtr
->OffsetToCapsuleBody
, 1, OutFptr
) != 1) {
1987 Error (NULL
, 0, 0, mOptions
.OutputFileName
, "failed to write to file");
1991 if (SizeLeft
< (Size
- CapHdrPtr
->OffsetToCapsuleBody
)) {
1992 Error (NULL
, 0, 0, "sum of image sizes exceeds size specified in initial capsule header", NULL
);
1996 // printf ("FILE: %s OffsetToCapsuleBody=0x%X\n", FileList->FileName, CapHdrPtr->OffsetToCapsuleBody);
1998 SizeLeft
= SizeLeft
- (Size
- CapHdrPtr
->OffsetToCapsuleBody
);
2001 // printf ("FILE: %s sizeleft=0x%X\n", FileList->FileName, SizeLeft);
2007 FileList
= FileList
->Next
;
2012 Error (NULL
, 0, 0, "sum of capsule images is insufficient", "0x%X bytes missing", SizeLeft
);
2016 Status
= STATUS_SUCCESS
;
2019 Status
= STATUS_ERROR
;
2021 if (InFptr
!= NULL
) {
2025 if (OutFptr
!= NULL
) {
2029 if (Buffer
!= NULL
) {
2036 return STATUS_SUCCESS
;
2041 DumpCapsuleHeaderStrings (
2047 Routine Description:
2048 Given a pointer to string data from a capsule header, dump
2052 SectionName - name of the capsule header section to which
2053 the string data pertains
2054 Buffer - pointer to string data from a capsule header
2057 STATUS_SUCCESS - all went well
2061 printf (" %s\n", SectionName
);
2063 printf (" Language: %S\n", Buffer
);
2070 if (wcslen (Buffer
) > 60) {
2071 printf (" %.60S\n", Buffer
);
2074 printf (" %S\n", Buffer
);
2075 Buffer
+= wcslen (Buffer
);
2082 return STATUS_SUCCESS
;
2088 SOURCE_FILE
*SourceFile
,
2094 Routine Description:
2095 Scan a hex value from the input stream.
2098 SourceFile - input file contents
2099 Value - returned value
2100 NumDigits - number of digits to read
2103 STATUS_SUCCESS - if NumDigits were read from the file
2104 STATUS_ERROR - otherwise
2113 SaveFilePos
= SourceFile
->FileBufferPtr
;
2116 while (Digits
> 0) {
2117 Nibble
= SourceFile
->FileBufferPtr
[0];
2118 if ((Nibble
>= UNICODE_0
) && (Nibble
<= UNICODE_9
)) {
2119 *Value
= (*Value
<< 4) | (Nibble
- UNICODE_0
);
2120 } else if ((Nibble
>= UNICODE_A
) && (Nibble
<= UNICODE_F
)) {
2121 *Value
= (*Value
<< 4) | (Nibble
- UNICODE_A
+ 0x10);
2122 } else if ((Nibble
>= UNICODE_a
) && (Nibble
<= UNICODE_f
)) {
2123 *Value
= (*Value
<< 4) | (Nibble
- UNICODE_a
+ 0x10);
2126 SourceFile
->FileName
,
2127 SourceFile
->LineNum
,
2130 "expected %d valid hex nibbles at %.20S",
2134 return STATUS_ERROR
;
2137 SourceFile
->FileBufferPtr
++;
2141 return STATUS_SUCCESS
;
2151 Routine Description:
2153 GC_TODO: Add function description
2157 File - GC_TODO: add argument description
2161 GC_TODO: add return values
2165 if ((UINT32
) File
->FileBufferPtr
- (UINT32
) File
->FileBuffer
>= File
->FileSize
) {
2166 File
->EndOfFile
= TRUE
;
2169 // Reposition to the end of the file if we went beyond
2171 if (File
->EndOfFile
) {
2172 File
->FileBufferPtr
= File
->FileBuffer
+ File
->FileSize
/ sizeof (WCHAR
);
2175 return File
->EndOfFile
;
2181 SOURCE_FILE
*SourceFile
2185 Routine Description:
2187 GC_TODO: Add function description
2191 SourceFile - GC_TODO: add argument description
2195 GC_TODO: add return values
2199 while (!EndOfFile (SourceFile
)) {
2200 switch (*SourceFile
->FileBufferPtr
) {
2205 SourceFile
->FileBufferPtr
++;
2209 SourceFile
->FileBufferPtr
++;
2210 SourceFile
->LineNum
++;
2219 // Parse a number. Possible format:
2235 Routine Description:
2237 GC_TODO: Add function description
2241 Str - GC_TODO: add argument description
2242 Value - GC_TODO: add argument description
2246 GC_TODO: add return values
2254 if (!isdigit (Str
[0])) {
2258 // Look for hex number
2260 if ((Str
[0] == '0') && (tolower (Str
[1]) == 'x')) {
2267 if ((Str
[0] >= '0') && (Str
[0] <= '9')) {
2268 LValue
= (LValue
<< 4) | (Str
[0] - '0');
2269 } else if ((Str
[0] >= 'A') && (Str
[0] <= 'F')) {
2270 LValue
= (LValue
<< 4) | (Str
[0] - 'A' + 0x10);
2271 } else if ((Str
[0] >= 'a') && (Str
[0] <= 'f')) {
2272 LValue
= (LValue
<< 4) | (Str
[0] - 'a' + 0x10);
2280 LValue
= atoi (Str
);
2281 while (isdigit (*Str
)) {
2286 // If string left over, better be one character we recognize
2301 LValue
*= 1024 * 1024;
2313 // Process the command-line arguments
2323 Routine Description:
2325 Processes command line arguments.
2329 Argc - Number of command line arguments
2330 Argv[] - Array of files input on command line
2334 STATUS_ERROR - Function exited with an error
2335 STATUS_SUCCESS - Function executed successfully
2341 FILE_LIST
*LastFile
;
2348 // Clear our globals
2350 memset ((char *) &mOptions
, 0, sizeof (mOptions
));
2353 // Skip program name
2360 return STATUS_ERROR
;
2363 // Process until no more options
2365 while ((Argc
> 0) && (Argv
[0][0] == '-')) {
2366 if (stricmp (Argv
[0], "-script") == 0) {
2368 // Check for one more arg
2372 // Save the file name
2374 if (strlen (Argv
[1]) >= sizeof (mOptions
.ScriptFileName
)) {
2375 Error (NULL
, 0, 0, NULL
, "input script file name length exceeds internal buffer size");
2377 if (NewFile
!= NULL
) {
2380 if (NewSize
!= NULL
) {
2384 return STATUS_ERROR
;
2387 strcpy (mOptions
.ScriptFileName
, Argv
[1]);
2389 Error (NULL
, 0, 0, Argv
[0], "missing script file name with option");
2392 if (NewFile
!= NULL
) {
2395 if (NewSize
!= NULL
) {
2399 return STATUS_ERROR
;
2405 // -o outfilename -- specify output file name (required)
2407 } else if (stricmp (Argv
[0], "-o") == 0) {
2409 // check for one more arg
2413 // Try to open the file
2415 // if ((mOptions.OutFptr = fopen (Argv[1], "wb")) == NULL) {
2416 // Error (NULL, 0, 0, Argv[1], "failed to open output file for writing");
2417 // return STATUS_ERROR;
2420 strcpy (mOptions
.OutputFileName
, Argv
[1]);
2422 Error (NULL
, 0, 0, Argv
[0], "missing output filename with option");
2425 if (NewFile
!= NULL
) {
2428 if (NewSize
!= NULL
) {
2432 return STATUS_ERROR
;
2437 } else if (stricmp (Argv
[0], "-j") == 0) {
2438 mOptions
.JoinMode
= TRUE
;
2440 // -split <size> option (multiple allowed)
2442 } else if (stricmp (Argv
[0], "-split") == 0) {
2444 NewSize
= (SIZE_LIST
*) malloc (sizeof (SIZE_LIST
));
2445 if (NewSize
== NULL
) {
2446 Error (NULL
, 0, 0, "memory allocation failure", NULL
);
2448 if (NewFile
!= NULL
) {
2451 if (NewSize
!= NULL
) {
2455 return STATUS_ERROR
;
2458 memset (NewSize
, 0, sizeof (SIZE_LIST
));
2460 // Get the size from the next arg, and then add this size
2463 if (!GetNumber (Argv
[1], &NewSize
->Size
)) {
2464 Error (NULL
, 0, 0, Argv
[1], "invalid split size argument");
2466 if (NewFile
!= NULL
) {
2469 if (NewSize
!= NULL
) {
2473 return STATUS_ERROR
;
2476 if (mOptions
.SizeList
== NULL
) {
2477 mOptions
.SizeList
= NewSize
;
2478 mOptions
.CurrentSize
= NewSize
;
2480 mOptions
.LastSize
->Next
= NewSize
;
2483 mOptions
.LastSize
= NewSize
;
2486 Error (NULL
, 0, 0, Argv
[0], "missing size parameter with option");
2489 if (NewFile
!= NULL
) {
2492 if (NewSize
!= NULL
) {
2496 return STATUS_ERROR
;
2501 } else if ((stricmp (Argv
[0], "-h") == 0) || (strcmp (Argv
[0], "-?") == 0)) {
2504 if (NewFile
!= NULL
) {
2507 if (NewSize
!= NULL
) {
2511 return STATUS_ERROR
;
2513 // Default minimum header
2515 } else if (stricmp (Argv
[0], "-dump") == 0) {
2516 mOptions
.Dump
= TRUE
;
2517 } else if (stricmp (Argv
[0], "-v") == 0) {
2518 mOptions
.Verbose
= TRUE
;
2520 Error (NULL
, 0, 0, Argv
[0], "unrecognized option");
2523 if (NewFile
!= NULL
) {
2526 if (NewSize
!= NULL
) {
2530 return STATUS_ERROR
;
2537 // Can't -j join files and -s split output capsule
2539 if ((mOptions
.SizeList
!= NULL
) && (mOptions
.JoinMode
)) {
2540 Error (NULL
, 0, 0, "cannot specify both -j and -size", NULL
);
2542 if (NewFile
!= NULL
) {
2545 if (NewSize
!= NULL
) {
2549 return STATUS_ERROR
;
2552 // Must have specified an output file name if not -dump
2554 if ((mOptions
.Dump
== 0) && (mOptions
.OutputFileName
[0] == 0)) {
2555 Error (NULL
, 0, 0, NULL
, "-o OutputFileName must be specified");
2558 if (NewFile
!= NULL
) {
2561 if (NewSize
!= NULL
) {
2565 return STATUS_ERROR
;
2568 // Rest of arguments are input files. The first one is a firmware
2569 // volume image, and the rest are FFS files that are to be inserted
2570 // into the firmware volume.
2574 NewFile
= (FILE_LIST
*) malloc (sizeof (FILE_LIST
));
2575 if (NewFile
== NULL
) {
2576 Error (NULL
, 0, 0, "memory allocation failure", NULL
);
2578 if (NewFile
!= NULL
) {
2581 if (NewSize
!= NULL
) {
2585 return STATUS_ERROR
;
2588 memset ((char *) NewFile
, 0, sizeof (FILE_LIST
));
2589 strcpy (NewFile
->FileName
, Argv
[0]);
2590 if (mOptions
.FileList
== NULL
) {
2591 mOptions
.FileList
= NewFile
;
2593 if (LastFile
== NULL
) {
2596 LastFile
->Next
= NewFile
;
2606 // Must have provided at least one file name
2608 if (mOptions
.FileList
== NULL
) {
2609 Error (NULL
, 0, 0, "must specify at least one file name", NULL
);
2612 if (NewFile
!= NULL
) {
2615 if (NewSize
!= NULL
) {
2619 return STATUS_ERROR
;
2622 return STATUS_SUCCESS
;
2632 Routine Description:
2634 Print usage information for this utility.
2647 static const char *Str
[] = {
2648 PROGRAM_NAME
" -- create a capsule header",
2649 " Usage: "PROGRAM_NAME
" {options} [CapsuleFV]",
2653 " Options include:",
2654 " -h or -? for this help information",
2655 " -script fname to take capsule header info from unicode script",
2657 " -o fname write output to file fname (required)",
2658 " -split size split capsule image into multiple output files",
2659 " -dump to dump a capsule header",
2660 " -v for verbose output\n",
2661 " -j to join split capsule images into a single image",
2663 " CapsuleFV is the name of an existing well-formed Tiano firmware",
2666 // FfsFileNames are the names of one or more Tiano FFS files to",
2667 // " insert into the output capsule image.",
2671 for (Index
= 0; Str
[Index
] != NULL
; Index
++) {
2672 fprintf (stdout
, "%s\n", Str
[Index
]);