3 Copyright (c) 2002 - 2005, Intel Corporation. All rights reserved
4 This software and associated documentation (if any) is furnished
5 under a license and may only be used or copied in accordance
6 with the terms of the license. Except as permitted by such
7 license, no part of this software or documentation may be
8 reproduced, stored in a retrieval system, or transmitted in any
9 form or by any means without the express written consent of
19 Generate a capsule header for a file, and optionally prepend the
20 header to a file or list of files.
31 #include "Tiano.h" // need a guid definition
32 #include "EfiUtilityMsgs.h"
33 #include "EfiCapsule.h"
34 #include "EfiFirmwareVolumeHeader.h"
35 #include "EfiFirmwareFileSystem.h" // for FV header GUID
37 #define PROGRAM_NAME "GenCapsuleHdr"
39 #define UNICODE_BACKSLASH L'\\'
40 #define UNICODE_FILE_START 0xFEFF
41 #define UNICODE_CR 0x000D
42 #define UNICODE_LF 0x000A
43 #define UNICODE_NULL 0x0000
44 #define UNICODE_SPACE L' '
45 #define UNICODE_SLASH L'/'
46 #define UNICODE_DOUBLE_QUOTE L'"'
47 #define UNICODE_A L'A'
48 #define UNICODE_F L'F'
49 #define UNICODE_Z L'Z'
50 #define UNICODE_a L'a'
51 #define UNICODE_f L'f'
52 #define UNICODE_z L'z'
53 #define UNICODE_0 L'0'
54 #define UNICODE_9 L'9'
55 #define UNICODE_TAB L'\t'
57 #define OEM_HEADER_STRING L"OemHeader"
58 #define AUTHOR_INFO_STRING L"AuthorInfo"
59 #define REVISION_INFO_STRING L"RevisionInfo"
60 #define SHORT_DESCRIPTION_STRING L"ShortDescription"
61 #define LONG_DESCRIPTION_STRING L"LongDescription"
62 #define EQUAL_STRING L"="
63 #define OPEN_BRACE_STRING L"{"
64 #define CLOSE_BRACE_STRING L"}"
65 #define GUID_STRING L"GUID"
66 #define DATA_STRING L"DATA"
68 #if (EFI_SPECIFICATION_VERSION >= 0x00020000)
69 #define UEFI_CAPSULE_HEADER_NO_FALAGS 0
70 #define UEFI_CAPSULE_HEADER_RESET_FALAGS CAPSULE_FLAGS_PERSIST_ACROSS_RESET
71 #define UEFI_CAPSULE_HEADER_ALL_FALAGS (CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE)
74 typedef wchar_t WCHAR
;
76 typedef struct _FILE_LIST
{
77 struct _FILE_LIST
*Next
;
78 INT8 FileName
[MAX_PATH
];
81 typedef struct _SIZE_LIST
{
82 struct _SIZE_LIST
*Next
;
87 INT8 FileName
[MAX_PATH
];
97 // Here's all our globals.
103 INT8 ScriptFileName
[MAX_PATH
];
104 INT8 OutputFileName
[MAX_PATH
];
109 SIZE_LIST
*CurrentSize
;
112 static EFI_GUID mEfiCapsuleHeaderGuid
= EFI_CAPSULE_GUID
;
129 SOURCE_FILE
*SourceFile
135 SOURCE_FILE
*SourceFile
,
145 UINT32 SequenceNumber
151 INT8
*CapsuleFileName
174 DumpCapsuleHeaderStrings (
181 CheckFirmwareVolumeHeader (
204 INT8
*ScriptFileName
,
206 EFI_CAPSULE_HEADER
*CapsuleHeader
212 SOURCE_FILE
*SourceFile
,
226 SOURCE_FILE
*SourceFile
,
250 Call the routine to process the command-line arguments, then
251 dispatch to the appropriate function.
254 Standard C main() argc and argv.
261 // GC_TODO: Argc - add argument and description to function comment
262 // GC_TODO: ] - add argument and description to function comment
267 // Specify our program name to the error printing routines.
269 SetUtilityName (PROGRAM_NAME
);
271 // Process the command-line arguments
273 Status
= ProcessArgs (Argc
, Argv
);
274 if (Status
== STATUS_SUCCESS
) {
277 } else if (mOptions
.JoinMode
) {
286 while (mOptions
.FileList
!= NULL
) {
287 NextFile
= mOptions
.FileList
->Next
;
288 free (mOptions
.FileList
);
289 mOptions
.FileList
= NextFile
;
292 while (mOptions
.SizeList
!= NULL
) {
293 mOptions
.CurrentSize
= mOptions
.SizeList
->Next
;
294 free (mOptions
.SizeList
);
295 mOptions
.SizeList
= mOptions
.CurrentSize
;
298 return GetUtilityStatus ();
310 GC_TODO: Add function description
318 GC_TODO: add return values
326 EFI_CAPSULE_HEADER CapsuleHeader
;
329 UINT32 CapsuleHeaderSize
;
330 long InsertedBlockMapEntryOffset
;
331 EFI_FV_BLOCK_MAP_ENTRY InsertedBlockMapEntry
;
332 UINT64 FirmwareVolumeSize
;
334 EFI_FIRMWARE_VOLUME_HEADER FVHeader
;
338 FirmwareVolumeSize
= 0;
339 CapsuleHeaderSize
= 0;
340 InsertedBlockMapEntryOffset
= 0;
341 memset (&InsertedBlockMapEntry
, 0, sizeof (EFI_FV_BLOCK_MAP_ENTRY
));
342 memset (&FVHeader
, 0, sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
344 if ((mOptions
.OutFptr
= fopen (mOptions
.OutputFileName
, "wb")) == NULL
) {
345 Error (NULL
, 0, 0, mOptions
.OutputFileName
, "failed to open output file for writing");
349 memset ((char *) &CapsuleHeader
, 0, sizeof (CapsuleHeader
));
350 memcpy ((void *) &CapsuleHeader
.CapsuleGuid
, (void *) &mEfiCapsuleHeaderGuid
, sizeof (EFI_GUID
));
351 CapsuleHeader
.HeaderSize
= sizeof (EFI_CAPSULE_HEADER
);
352 CapsuleHeader
.CapsuleImageSize
= sizeof (EFI_CAPSULE_HEADER
);
353 if (mOptions
.ScriptFileName
[0] != 0) {
354 if (ProcessScriptFile (mOptions
.ScriptFileName
, mOptions
.OutFptr
, &CapsuleHeader
) != STATUS_SUCCESS
) {
359 // Insert a default capsule header
360 #if (EFI_SPECIFICATION_VERSION >= 0x00020000)
361 CapsuleHeader
.HeaderSize
= sizeof (EFI_CAPSULE_HEADER
);
362 CapsuleHeader
.Flags
= UEFI_CAPSULE_HEADER_ALL_FALAGS
;
364 CapsuleHeader
.OffsetToCapsuleBody
= sizeof (EFI_CAPSULE_HEADER
);
366 if (fwrite ((void *) &CapsuleHeader
, sizeof (CapsuleHeader
), 1, mOptions
.OutFptr
) != 1) {
367 Error (NULL
, 0, 0, mOptions
.OutputFileName
, "failed to write to file");
372 CapsuleHeaderSize
= CapsuleHeader
.OffsetToCapsuleBody
;
374 // Now copy the contents of any other files specified on the command
375 // line to the output file. Files must be FFS files, which are aligned
376 // on 8-byte boundaries. Don't align the first file, since it's the start
377 // of the image once the capsule header has been removed.
379 FileList
= mOptions
.FileList
;
382 while (FileList
!= NULL
) {
383 if ((InFptr
= fopen (FileList
->FileName
, "rb")) == NULL
) {
384 Error (NULL
, 0, 0, FileList
->FileName
, "failed to open file for reading");
388 // Allocate a buffer into which we can read the file.
390 fseek (InFptr
, 0, SEEK_END
);
391 Size
= ftell (InFptr
);
393 Buffer
= (char *) malloc (Size
);
394 if (Buffer
== NULL
) {
395 Error (__FILE__
, __LINE__
, 0, FileList
->FileName
, "failed to allocate buffer to read file into");
399 if (fread ((void *) Buffer
, Size
, 1, InFptr
) != 1) {
400 Error (NULL
, 0, 0, FileList
->FileName
, "failed to read file contents");
406 // Align the write of the first bytes from the file if not the first file
410 // First file must be a firmware volume. Double-check, and then insert
411 // an additional block map entry so we can add more files from the command line
413 if (CheckFirmwareVolumeHeader (FileList
->FileName
, Buffer
, Size
) != STATUS_SUCCESS
) {
417 // Save a copy of the firmware volume header for later
419 memcpy (&FVHeader
, Buffer
, sizeof (EFI_FIRMWARE_VOLUME_HEADER
));
420 FirmwareVolumeSize
= FVHeader
.FvLength
;
421 if (FileList
->Next
!= NULL
) {
423 // Copy the firmware volume header
425 InsertedBlockMapEntryOffset
= CapsuleHeaderSize
+ FVHeader
.HeaderLength
;
426 if (fwrite (Buffer
, FVHeader
.HeaderLength
, 1, mOptions
.OutFptr
) != 1) {
427 Error (NULL
, 0, 0, mOptions
.OutputFileName
, "failed to write to file");
431 if (fwrite (&InsertedBlockMapEntry
, sizeof (EFI_FV_BLOCK_MAP_ENTRY
), 1, mOptions
.OutFptr
) != 1) {
432 Error (NULL
, 0, 0, mOptions
.OutputFileName
, "failed to write to file");
437 Buffer
+ FVHeader
.HeaderLength
,
438 Size
- FVHeader
.HeaderLength
,
442 Error (NULL
, 0, 0, mOptions
.OutputFileName
, "failed to write to file");
447 // Copy the file contents as-is
449 if (fwrite ((void *) Buffer
, Size
, 1, mOptions
.OutFptr
) != 1) {
450 Error (NULL
, 0, 0, mOptions
.OutputFileName
, "failed to write to file");
455 while ((ftell (mOptions
.OutFptr
) - CapsuleHeaderSize
) & 0x07) {
456 if (fwrite ((void *) &Zero
, 1, 1, mOptions
.OutFptr
) != 1) {
457 Error (NULL
, 0, 0, mOptions
.OutputFileName
, "failed to write to file");
462 if (fwrite ((void *) Buffer
, Size
, 1, mOptions
.OutFptr
) != 1) {
463 Error (NULL
, 0, 0, mOptions
.OutputFileName
, "failed to write to file");
475 FileList
= FileList
->Next
;
479 if (Buffer
!= NULL
) {
483 if (InFptr
!= NULL
) {
487 // If we inserted an additional block map entry, then fix it up. Fix up the
488 // FV header as well to reflect our new size.
490 if (InsertedBlockMapEntryOffset
!= 0) {
491 FileSize
= ftell (mOptions
.OutFptr
);
492 InsertedBlockMapEntry
.NumBlocks
= 1;
493 InsertedBlockMapEntry
.BlockLength
= (UINT32
) ((UINT64
) FileSize
- (UINT64
) CapsuleHeaderSize
- FirmwareVolumeSize
- sizeof (EFI_FV_BLOCK_MAP_ENTRY
));
494 fseek (mOptions
.OutFptr
, InsertedBlockMapEntryOffset
, SEEK_SET
);
495 fwrite (&InsertedBlockMapEntry
, sizeof (EFI_FV_BLOCK_MAP_ENTRY
), 1, mOptions
.OutFptr
);
497 // Fix up the firmware volume header and write it out
499 fseek (mOptions
.OutFptr
, CapsuleHeaderSize
, SEEK_SET
);
500 FVHeader
.FvLength
= FileSize
- CapsuleHeaderSize
;
501 FVHeader
.HeaderLength
+= sizeof (EFI_FV_BLOCK_MAP_ENTRY
);
502 fwrite (&FVHeader
, sizeof (EFI_FIRMWARE_VOLUME_HEADER
) - sizeof (EFI_FV_BLOCK_MAP_ENTRY
), 1, mOptions
.OutFptr
);
504 // Reposition to the end of the file
508 // Close files and free the global string lists we allocated memory for
510 if (mOptions
.OutFptr
!= NULL
) {
512 // We should now know the full capsule image size. Update the header and write it again.
514 fseek (mOptions
.OutFptr
, 0, SEEK_END
);
515 Size
= ftell (mOptions
.OutFptr
);
516 CapsuleHeader
.CapsuleImageSize
= Size
;
517 fseek (mOptions
.OutFptr
, 0, SEEK_SET
);
518 if (fwrite ((void *) &CapsuleHeader
, sizeof (CapsuleHeader
), 1, mOptions
.OutFptr
) != 1) {
519 Error (NULL
, 0, 0, mOptions
.OutputFileName
, "failed to write to file");
522 fseek (mOptions
.OutFptr
, 0, SEEK_END
);
523 fclose (mOptions
.OutFptr
);
524 mOptions
.OutFptr
= NULL
;
527 // If they are doing split capsule output, then split it up now.
529 if ((mOptions
.Dump
== 0) && (GetUtilityStatus () == STATUS_SUCCESS
) && (mOptions
.SizeList
!= NULL
)) {
530 SplitCapsule (mOptions
.OutputFileName
);
533 return STATUS_SUCCESS
;
539 INT8
*ScriptFileName
,
541 EFI_CAPSULE_HEADER
*CapsuleHeader
546 Parse a capsule header script file.
549 ScriptFileName - name of script file to parse
550 OutFptr - output to dump binary data
551 CapsuleHeader - capsule header to update with size info
552 of parsed fields in the script file
555 STATUS_SUCCESS - if all went well
561 SOURCE_FILE SourceFile
;
562 WCHAR
*WScriptFileName
;
565 if (fwrite (CapsuleHeader
, sizeof (EFI_CAPSULE_HEADER
), 1, OutFptr
) != 1) {
566 Error (NULL
, 0, 0, "failed to write capsule header to output file", NULL
);
570 memset (&SourceFile
, 0, sizeof (SOURCE_FILE
));
571 strcpy (SourceFile
.FileName
, ScriptFileName
);
573 Status
= STATUS_ERROR
;
575 // Open the input unicode script file and read it into a buffer
577 WScriptFileName
= (WCHAR
*) malloc ((strlen (ScriptFileName
) + 1) * sizeof (WCHAR
));
578 if (WScriptFileName
== NULL
) {
579 Error (__FILE__
, __LINE__
, 0, "failed to allocate memory", NULL
);
583 swprintf (WScriptFileName
, L
"%S", ScriptFileName
);
584 if ((SourceFile
.FilePtr
= _wfopen (WScriptFileName
, L
"r")) == NULL
) {
585 free (WScriptFileName
);
586 Error (NULL
, 0, 0, ScriptFileName
, "failed to open script file for reading");
590 free (WScriptFileName
);
591 fseek (SourceFile
.FilePtr
, 0, SEEK_END
);
592 SourceFile
.FileSize
= ftell (SourceFile
.FilePtr
);
593 rewind (SourceFile
.FilePtr
);
594 SourceFile
.FileBuffer
= (WCHAR
*) malloc (SourceFile
.FileSize
+ sizeof (WCHAR
));
595 if (SourceFile
.FileBuffer
== NULL
) {
596 Error (__FILE__
, __LINE__
, 0, ScriptFileName
, "failed to allocate memory to read in file contents");
600 if (fread (SourceFile
.FileBuffer
, SourceFile
.FileSize
, 1, SourceFile
.FilePtr
) != 1) {
601 Error (NULL
, 0, 0, ScriptFileName
, "failed to read file contents");
605 SourceFile
.FileBufferPtr
= SourceFile
.FileBuffer
;
606 SourceFile
.LineNum
= 1;
607 if (SourceFile
.FileBuffer
[0] != UNICODE_FILE_START
) {
608 Error (ScriptFileName
, 1, 0, "file does not appear to be a unicode file", NULL
);
612 SourceFile
.FileBufferPtr
++;
613 SourceFile
.FileBuffer
[SourceFile
.FileSize
/ sizeof (WCHAR
)] = 0;
615 // Walk the source file buffer and replace all carriage returns with 0 so
616 // we can print from the file contents on parse errors.
619 while (!EndOfFile (&SourceFile
)) {
620 if (SourceFile
.FileBufferPtr
[0] == UNICODE_CR
) {
621 SourceFile
.FileBufferPtr
[0] = 0;
623 } else if (SourceFile
.FileBufferPtr
[0] == UNICODE_LF
) {
625 } else if (InComment
) {
626 SourceFile
.FileBufferPtr
[0] = UNICODE_SPACE
;
627 } else if ((SourceFile
.FileBufferPtr
[0] == UNICODE_SLASH
) && (SourceFile
.FileBufferPtr
[1] == UNICODE_SLASH
)) {
629 SourceFile
.FileBufferPtr
[0] = UNICODE_SPACE
;
632 SourceFile
.FileBufferPtr
++;
635 // Reposition to the start of the file, but skip over the unicode file start
637 SourceFile
.FileBufferPtr
= SourceFile
.FileBuffer
;
638 SourceFile
.FileBufferPtr
++;
639 SourceFile
.EndOfFile
= 0;
640 CapsuleHeader
->OffsetToOemDefinedHeader
= ftell (OutFptr
);
642 // Parse the OEM bytes
644 if (ParseOemInfo (&SourceFile
, OutFptr
) != STATUS_SUCCESS
) {
648 // Parse the author information
650 CapsuleHeader
->OffsetToAuthorInformation
= ftell (OutFptr
);
651 if (ParseCapsuleInfo (&SourceFile
, OutFptr
, AUTHOR_INFO_STRING
) != STATUS_SUCCESS
) {
655 // Parse the revision information
657 CapsuleHeader
->OffsetToRevisionInformation
= ftell (OutFptr
);
658 if (ParseCapsuleInfo (&SourceFile
, OutFptr
, REVISION_INFO_STRING
) != STATUS_SUCCESS
) {
662 // Parse the short description
664 CapsuleHeader
->OffsetToShortDescription
= ftell (OutFptr
);
665 if (ParseCapsuleInfo (&SourceFile
, OutFptr
, SHORT_DESCRIPTION_STRING
) != STATUS_SUCCESS
) {
669 // Parse the long description
671 CapsuleHeader
->OffsetToLongDescription
= ftell (OutFptr
);
672 if (ParseCapsuleInfo (&SourceFile
, OutFptr
, LONG_DESCRIPTION_STRING
) != STATUS_SUCCESS
) {
676 // Better be end of contents
678 SkipWhiteSpace (&SourceFile
);
679 if (!EndOfFile (&SourceFile
)) {
680 Error (ScriptFileName
, SourceFile
.LineNum
, 0, NULL
, "expected end-of-file, not %.20S", SourceFile
.FileBufferPtr
);
684 CapsuleHeader
->OffsetToCapsuleBody
= ftell (OutFptr
);
686 fwrite (CapsuleHeader
, sizeof (EFI_CAPSULE_HEADER
), 1, OutFptr
);
687 fseek (OutFptr
, 0, SEEK_END
);
688 Status
= STATUS_SUCCESS
;
690 if (SourceFile
.FilePtr
!= NULL
) {
691 fclose (SourceFile
.FilePtr
);
694 if (SourceFile
.FileBuffer
!= NULL
) {
695 free (SourceFile
.FileBuffer
);
701 return STATUS_SUCCESS
;
704 // Parse the OEM data of format:
706 // GUID = 12345676-1234-1234-123456789ABC
707 // DATA = 0x01, 0x02, 0x03...
713 SOURCE_FILE
*SourceFile
,
720 GC_TODO: Add function description
724 SourceFile - GC_TODO: add argument description
725 OutFptr - GC_TODO: add argument description
729 GC_TODO: add return values
733 long OemHeaderOffset
;
735 EFI_CAPSULE_OEM_HEADER OemHeader
;
741 Status
= STATUS_ERROR
;
742 memset (&OemHeader
, 0, sizeof (EFI_CAPSULE_OEM_HEADER
));
743 OemHeaderOffset
= ftell (OutFptr
);
744 OemHeader
.HeaderSize
= sizeof (EFI_CAPSULE_OEM_HEADER
);
745 if (fwrite (&OemHeader
, sizeof (EFI_CAPSULE_OEM_HEADER
), 1, OutFptr
) != 1) {
746 Error (NULL
, 0, 0, "failed to write OEM header to output file", NULL
);
750 if (!IsToken (SourceFile
, OEM_HEADER_STRING
)) {
752 SourceFile
->FileName
,
756 "expected %S, not %.20S",
758 SourceFile
->FileBufferPtr
763 if (!IsToken (SourceFile
, EQUAL_STRING
)) {
765 SourceFile
->FileName
,
769 "expected %S, not %.20S",
771 SourceFile
->FileBufferPtr
776 if (!IsToken (SourceFile
, OPEN_BRACE_STRING
)) {
778 SourceFile
->FileName
,
782 "expected %S, not %.20S",
784 SourceFile
->FileBufferPtr
789 // Look for: GUID = xxxxxxx-xxxx-xxxx-xxxxxxxxxxxxx
791 if (!IsToken (SourceFile
, GUID_STRING
)) {
793 SourceFile
->FileName
,
797 "expected %S, not %.20S",
799 SourceFile
->FileBufferPtr
804 if (!IsToken (SourceFile
, EQUAL_STRING
)) {
806 SourceFile
->FileName
,
810 "expected %S, not %.20S",
812 SourceFile
->FileBufferPtr
817 // Parse the xxxxxxxx-xxxx-xxxx-xxxx portion of the GUID
819 SkipWhiteSpace (SourceFile
);
820 if (GetHexValue (SourceFile
, &Data
, 8) != STATUS_SUCCESS
) {
821 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "invalid GUID", NULL
);
825 OemHeader
.OemGuid
.Data1
= Data
;
826 if (!IsToken (SourceFile
, L
"-")) {
828 SourceFile
->FileName
,
832 "expected dash in GUID, not %S",
833 SourceFile
->FileBufferPtr
840 for (DigitCount
= 0; DigitCount
< 3; DigitCount
++) {
841 if (GetHexValue (SourceFile
, &Data
, 4) != STATUS_SUCCESS
) {
842 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "invalid GUID", NULL
);
846 switch (DigitCount
) {
848 OemHeader
.OemGuid
.Data2
= (UINT16
) Data
;
852 OemHeader
.OemGuid
.Data3
= (UINT16
) Data
;
856 OemHeader
.OemGuid
.Data4
[1] = (UINT8
) Data
;
857 OemHeader
.OemGuid
.Data4
[0] = (UINT8
) (Data
>> 8);
861 if (!IsToken (SourceFile
, L
"-")) {
863 SourceFile
->FileName
,
867 "expected dash in GUID, not %S",
868 SourceFile
->FileBufferPtr
874 // Pick up the last 6 bytes of the GUID
876 SaveFilePos
= SourceFile
->FileBufferPtr
;
877 for (DigitCount
= 0; DigitCount
< 6; DigitCount
++) {
878 if (GetHexValue (SourceFile
, &Data
, 2) != STATUS_SUCCESS
) {
879 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "invalid GUID", NULL
);
883 OemHeader
.OemGuid
.Data4
[DigitCount
+ 2] = (UINT8
) Data
;
886 // Now read raw OEM data bytes. May or may not be present.
887 // DATA = 0x01, 0x02, 0x02...
889 if (IsToken (SourceFile
, CLOSE_BRACE_STRING
)) {
890 Status
= STATUS_SUCCESS
;
894 if (!IsToken (SourceFile
, DATA_STRING
)) {
896 SourceFile
->FileName
,
900 "expected %S, not %.20S",
902 SourceFile
->FileBufferPtr
907 if (!IsToken (SourceFile
, EQUAL_STRING
)) {
909 SourceFile
->FileName
,
913 "expected %S, not %.20S",
915 SourceFile
->FileBufferPtr
920 while (!EndOfFile (SourceFile
)) {
921 if (IsToken (SourceFile
, CLOSE_BRACE_STRING
)) {
922 Status
= STATUS_SUCCESS
;
926 if (IsToken (SourceFile
, L
"0x")) {
927 if (swscanf (SourceFile
->FileBufferPtr
, L
"%x", &Data
) != 1) {
929 SourceFile
->FileName
,
933 "expected hex byte value, not %.20S",
934 SourceFile
->FileBufferPtr
941 SourceFile
->FileName
,
945 "expected byte hex byte value at %.20S",
946 SourceFile
->FileBufferPtr
951 // Skip over the hex digits, then write the data
953 while (iswxdigit (SourceFile
->FileBufferPtr
[0])) {
954 SourceFile
->FileBufferPtr
++;
957 ByteData
= (UINT8
) Data
;
958 if (fwrite (&ByteData
, 1, 1, OutFptr
) != 1) {
959 Error (NULL
, 0, 0, "failed to write OEM data to output file", NULL
);
963 OemHeader
.HeaderSize
++;
967 IsToken (SourceFile
, L
",");
970 SourceFile
->FileName
,
974 "expected hex OEM data, not %.20S",
975 SourceFile
->FileBufferPtr
981 if (EndOfFile (SourceFile
)) {
983 SourceFile
->FileName
,
987 "expected %S close to OEM header data",
993 Status
= STATUS_SUCCESS
;
996 // re-write the oem header if no errors
998 if (Status
== STATUS_SUCCESS
) {
999 fseek (OutFptr
, OemHeaderOffset
, SEEK_SET
);
1000 if (fwrite (&OemHeader
, sizeof (EFI_CAPSULE_OEM_HEADER
), 1, OutFptr
) != 1) {
1001 Error (NULL
, 0, 0, "failed to write OEM header to output file", NULL
);
1005 fseek (OutFptr
, 0, SEEK_END
);
1014 SOURCE_FILE
*SourceFile
,
1018 // GC_TODO: function comment should start with '/*++'
1020 // GC_TODO: function comment is missing 'Routine Description:'
1021 // GC_TODO: function comment is missing 'Arguments:'
1022 // GC_TODO: function comment is missing 'Returns:'
1023 // GC_TODO: SourceFile - add argument and description to function comment
1024 // GC_TODO: OutFptr - add argument and description to function comment
1025 // GC_TODO: SectionName - add argument and description to function comment
1026 // Parse: eng "string " "parts"
1027 // spa "string " "parts"
1028 // Write out: "eng string parts\0spa string parts\0\0
1036 Status
= STATUS_ERROR
;
1038 Spacebar
= UNICODE_SPACE
;
1040 if (!IsToken (SourceFile
, SectionName
)) {
1042 SourceFile
->FileName
,
1043 SourceFile
->LineNum
,
1046 "expected %S, not %.20S",
1048 SourceFile
->FileBufferPtr
1053 if (!IsToken (SourceFile
, EQUAL_STRING
)) {
1055 SourceFile
->FileName
,
1056 SourceFile
->LineNum
,
1059 "expected %S, not %.20S",
1061 SourceFile
->FileBufferPtr
1066 if (!IsToken (SourceFile
, OPEN_BRACE_STRING
)) {
1068 SourceFile
->FileName
,
1069 SourceFile
->LineNum
,
1072 "expected %S, not %.20S",
1074 SourceFile
->FileBufferPtr
1079 while (!EndOfFile (SourceFile
)) {
1080 if (IsToken (SourceFile
, CLOSE_BRACE_STRING
)) {
1084 // Look for language identifier (3 lowercase chars)
1086 if ((SourceFile
->FileBufferPtr
[0] >= UNICODE_a
) &&
1087 (SourceFile
->FileBufferPtr
[0] <= UNICODE_z
) &&
1088 (SourceFile
->FileBufferPtr
[1] >= UNICODE_a
) &&
1089 (SourceFile
->FileBufferPtr
[1] <= UNICODE_z
) &&
1090 (SourceFile
->FileBufferPtr
[2] >= UNICODE_a
) &&
1091 (SourceFile
->FileBufferPtr
[2] <= UNICODE_z
) &&
1092 IsWhiteSpace (SourceFile
->FileBufferPtr
[3])
1095 // Write the 3 chars followed by a spacebar, and then look for opening quote
1097 fwrite (SourceFile
->FileBufferPtr
, sizeof (WCHAR
), 1, OutFptr
);
1098 SourceFile
->FileBufferPtr
++;
1099 fwrite (SourceFile
->FileBufferPtr
, sizeof (WCHAR
), 1, OutFptr
);
1100 SourceFile
->FileBufferPtr
++;
1101 fwrite (SourceFile
->FileBufferPtr
, sizeof (WCHAR
), 1, OutFptr
);
1102 SourceFile
->FileBufferPtr
++;
1103 fwrite (&Spacebar
, sizeof (WCHAR
), 1, OutFptr
);
1105 while (IsToken (SourceFile
, L
"\"")) {
1107 while (!EndOfFile (SourceFile
)) {
1108 if (SourceFile
->FileBufferPtr
[0] == UNICODE_DOUBLE_QUOTE
) {
1109 SourceFile
->FileBufferPtr
++;
1111 } else if ((SourceFile
->FileBufferPtr
[0] == UNICODE_LF
) || (SourceFile
->FileBufferPtr
[0] == 0)) {
1112 Error (SourceFile
->FileName
, SourceFile
->LineNum
, 0, "missing closing quote on string", NULL
);
1115 fwrite (SourceFile
->FileBufferPtr
, sizeof (WCHAR
), 1, OutFptr
);
1116 SourceFile
->FileBufferPtr
++;
1121 if (StringCount
== 0) {
1123 SourceFile
->FileName
,
1124 SourceFile
->LineNum
,
1127 "expected quoted string, not %.20S",
1128 SourceFile
->FileBufferPtr
1133 // This string's null terminator
1135 fwrite (&Zero
, sizeof (WCHAR
), 1, OutFptr
);
1138 SourceFile
->FileName
,
1139 SourceFile
->LineNum
,
1142 "expected valid language identifer, not %.20S",
1143 SourceFile
->FileBufferPtr
1149 // Double null terminator
1151 fwrite (&Zero
, sizeof (WCHAR
), 1, OutFptr
);
1152 Status
= STATUS_SUCCESS
;
1160 INT8
*CapsuleFileName
1164 Routine Description:
1165 We've created an entire capsule image. Now split it up into the
1166 size pieces they requested.
1169 CapsuleFileName - name of an existing capsule file on disk
1172 STATUS_SUCCESS - if no problems
1175 This implementation reads in the entire capsule image from
1176 disk, then overwrites the original file with the first
1182 EFI_CAPSULE_HEADER
*CapHdr
;
1184 EFI_CAPSULE_HEADER Hdr
;
1190 UINT32 SequenceNumber
;
1192 INT8 FileName
[MAX_PATH
];
1196 // Figure out the total size, then rewind the input file and
1197 // read the entire thing in
1199 if ((CapFptr
= fopen (CapsuleFileName
, "rb")) == NULL
) {
1200 Error (NULL
, 0, 0, CapsuleFileName
, "failed to open capsule image for reading");
1201 return STATUS_ERROR
;
1205 Status
= STATUS_SUCCESS
;
1206 fseek (CapFptr
, 0, SEEK_END
);
1207 SizeLeft
= ftell (CapFptr
);
1208 fseek (CapFptr
, 0, SEEK_SET
);
1209 CapHdr
= (EFI_CAPSULE_HEADER
*) malloc (SizeLeft
);
1210 if (CapHdr
== NULL
) {
1211 Error (NULL
, 0, 0, "memory allocation failure", NULL
);
1215 if (fread (CapHdr
, SizeLeft
, 1, CapFptr
) != 1) {
1216 Error (NULL
, 0, 0, "failed to read capsule contents", "split failed");
1223 // Get a GUID to fill in the InstanceId GUID in the header
1225 CreateGuid (&CapHdr
->InstanceId
);
1228 // If the split size is larger than the original capsule image, then
1231 if (mOptions
.SizeList
->Size
>= SizeLeft
) {
1232 mOptions
.SizeList
->Size
= SizeLeft
;
1236 // First size has to be big enough for the original header
1238 if (mOptions
.SizeList
->Size
< CapHdr
->OffsetToCapsuleBody
) {
1239 Error (NULL
, 0, 0, "first split size is insufficient for the original capsule header", NULL
);
1243 // Initialize the header we'll use on all but the first part
1245 memset (&Hdr
, 0, sizeof (Hdr
));
1246 Hdr
.CapsuleGuid
= CapHdr
->CapsuleGuid
;
1247 Hdr
.HeaderSize
= sizeof (Hdr
);
1248 Hdr
.Flags
= CapHdr
->Flags
;
1249 Hdr
.InstanceId
= CapHdr
->InstanceId
;
1250 Hdr
.CapsuleImageSize
= CapHdr
->CapsuleImageSize
;
1251 Hdr
.OffsetToCapsuleBody
= Hdr
.HeaderSize
;
1252 Hdr
.SequenceNumber
= 1;
1254 // printf ("Created %s - 0x%X bytes\n", CapsuleFileName, mOptions.SizeList->Size);
1256 Buffer
= (UINT8
*) CapHdr
;
1258 // Walk the list of sizes and write out a capsule header, and
1259 // then the raw capsule data.
1261 // SizeLeft -= mOptions.SizeList->Size;
1263 mOptions
.CurrentSize
= mOptions
.SizeList
;
1265 CurrentSize
= mOptions
.CurrentSize
->Size
;
1266 GetSplitFileName (mOptions
.OutputFileName
, FileName
, SequenceNumber
);
1267 if ((OutFptr
= fopen (FileName
, "wb")) == NULL
) {
1268 Error (NULL
, 0, 0, FileName
, "failed to open split file for writing");
1272 if (Buffer
== (UINT8
*) CapHdr
) {
1274 // First part -- write out original header and data
1276 if (fwrite (Buffer
, CurrentSize
, 1, OutFptr
) != 1) {
1277 Error (NULL
, 0, 0, FileName
, "failed to write to split image file");
1281 SizeLeft
-= CurrentSize
;
1282 Buffer
+= CurrentSize
;
1283 DataSize
= CurrentSize
;
1284 FileSize
= CurrentSize
;
1287 // Not the first part. Write the default header, and then the raw bytes from the
1290 if (CurrentSize
<= sizeof (Hdr
)) {
1291 Error (NULL
, 0, 0, "split size too small for capsule header + data", "0x%X", CurrentSize
);
1295 DataSize
= CurrentSize
- sizeof (Hdr
);
1296 if (DataSize
> SizeLeft
) {
1297 DataSize
= SizeLeft
;
1300 if (fwrite (&Hdr
, sizeof (Hdr
), 1, OutFptr
) != 1) {
1301 Error (NULL
, 0, 0, FileName
, "failed to write capsule header to output file");
1306 if (fwrite (Buffer
, DataSize
, 1, OutFptr
) != 1) {
1307 Error (NULL
, 0, 0, FileName
, "failed to write capsule data to output file");
1312 Hdr
.SequenceNumber
++;
1314 SizeLeft
-= DataSize
;
1315 FileSize
= DataSize
+ sizeof (Hdr
);
1318 // Next size in list if there is one
1320 if (mOptions
.CurrentSize
->Next
!= NULL
) {
1321 mOptions
.CurrentSize
= mOptions
.CurrentSize
->Next
;
1327 printf ("Created %s - 0x%X bytes (0x%X bytes of data)\n", FileName
, FileSize
, DataSize
);
1332 Status
= STATUS_ERROR
;
1334 if (CapHdr
!= NULL
) {
1338 if (CapFptr
!= NULL
) {
1342 if (OutFptr
!= NULL
) {
1349 return STATUS_SUCCESS
;
1357 UINT32 SequenceNumber
1361 Routine Description:
1363 GC_TODO: Add function description
1367 BaseFileName - GC_TODO: add argument description
1368 NewFileName - GC_TODO: add argument description
1369 SequenceNumber - GC_TODO: add argument description
1373 GC_TODO: add return values
1379 Routine Description:
1380 Given an initial split capsule file name and a sequence number,
1381 create an appropriate file name for this split of a capsule image.
1384 BaseFileName - name of of the first split file in the series
1385 NewFileName - output name of the split file
1386 SequenceNumber - 0-based sequence number of split images
1389 TRUE - name created successfully
1399 // Work back from the end of the file name and see if there is a number somewhere
1401 for (Ptr
= BaseFileName
+ strlen (BaseFileName
) - 1; (Ptr
> BaseFileName
) && !isdigit (*Ptr
); Ptr
--)
1403 if ((Ptr
== BaseFileName
) && (!isdigit (*Ptr
))) {
1405 // Found no number, so just add it to the end
1407 sprintf (NewFileName
, "%s%d", BaseFileName
, SequenceNumber
);
1411 // Found a number. Look back to find the first digit.
1413 Part2Start
= Ptr
+ 1;
1414 for (Digits
= 1; isdigit (*Ptr
) && (Ptr
> BaseFileName
); Ptr
--, Digits
++)
1416 if (!isdigit (*Ptr
)) {
1421 BaseOffset
= atoi (Ptr
);
1422 SequenceNumber
= SequenceNumber
+ BaseOffset
;
1425 // Copy the first part of the original file name to the new filename
1426 // This is the path for filenames with format path\name001.cap
1428 Len
= (UINT32
) Ptr
- (UINT32
) BaseFileName
;
1429 strncpy (NewFileName
, BaseFileName
, Len
);
1430 sprintf (NewFileName
+ Len
, "%0*d", Digits
, SequenceNumber
);
1431 strcat (NewFileName
, Part2Start
);
1435 // Only one digit found. This is the path for filenames with
1436 // format path\name1.cap
1438 Len
= (UINT32
) Ptr
- (UINT32
) BaseFileName
+ 1;
1439 strncpy (NewFileName
, BaseFileName
, Len
);
1440 sprintf (NewFileName
+ Len
- 1, "%d", SequenceNumber
);
1441 strcat (NewFileName
, Part2Start
);
1454 Routine Description:
1456 GC_TODO: Add function description
1460 Char - GC_TODO: add argument description
1464 GC_TODO: add return values
1489 Routine Description:
1491 GC_TODO: Add function description
1495 File - GC_TODO: add argument description
1496 Token - GC_TODO: add argument description
1500 GC_TODO: add return values
1504 SkipWhiteSpace (File
);
1505 if (EndOfFile (File
)) {
1509 if (wcsncmp (Token
, File
->FileBufferPtr
, wcslen (Token
)) == 0) {
1510 File
->FileBufferPtr
+= wcslen (Token
);
1519 CheckFirmwareVolumeHeader (
1526 Routine Description:
1528 GC_TODO: Add function description
1532 FileName - GC_TODO: add argument description
1533 Buffer - GC_TODO: add argument description
1534 BufferSize - GC_TODO: add argument description
1538 GC_TODO: add return values
1542 EFI_FIRMWARE_VOLUME_HEADER
*Hdr
;
1543 EFI_GUID FVHeaderGuid
= EFI_FIRMWARE_FILE_SYSTEM_GUID
;
1545 Hdr
= (EFI_FIRMWARE_VOLUME_HEADER
*) Buffer
;
1546 if (Hdr
->Signature
!= EFI_FVH_SIGNATURE
) {
1547 Error (NULL
, 0, 0, FileName
, "file does not appear to be a firmware volume (bad signature)");
1548 return STATUS_ERROR
;
1551 if (Hdr
->Revision
!= EFI_FVH_REVISION
) {
1552 Error (NULL
, 0, 0, FileName
, "unsupported firmware volume header version");
1553 return STATUS_ERROR
;
1556 if (Hdr
->FvLength
> BufferSize
) {
1557 Error (NULL
, 0, 0, FileName
, "malformed firmware volume -- FvLength > file size");
1558 return STATUS_ERROR
;
1561 if (memcmp (&Hdr
->FileSystemGuid
, &FVHeaderGuid
, sizeof (EFI_GUID
)) != 0) {
1562 Error (NULL
, 0, 0, FileName
, "invalid FFS GUID in firmware volume header");
1563 return STATUS_ERROR
;
1566 return STATUS_SUCCESS
;
1576 Routine Description:
1578 GC_TODO: Add function description
1586 GC_TODO: add return values
1592 FILE_LIST
*FileList
;
1593 EFI_CAPSULE_HEADER CapsuleHeader
;
1594 EFI_FIRMWARE_VOLUME_HEADER FVHeader
;
1595 EFI_CAPSULE_OEM_HEADER
*OemHeader
;
1598 UINT32 CapsuleHeaderDataSize
;
1600 UINT8
*CapsuleHeaderData
;
1604 CapsuleHeaderData
= NULL
;
1605 FileList
= mOptions
.FileList
;
1606 while (FileList
!= NULL
) {
1607 if ((InFptr
= fopen (FileList
->FileName
, "rb")) == NULL
) {
1608 Error (NULL
, 0, 0, FileList
->FileName
, "failed to open file for reading");
1612 if (fread (&CapsuleHeader
, sizeof (EFI_CAPSULE_HEADER
), 1, InFptr
) != 1) {
1613 Error (NULL
, 0, 0, FileList
->FileName
, "failed to read capsule header");
1617 fseek (InFptr
, 0, SEEK_END
);
1618 FileSize
= ftell (InFptr
);
1619 if (CapsuleHeader
.CapsuleImageSize
> FileSize
) {
1626 "Capsule %s Size=0x%X CargoSize=0x%X\n",
1629 FileSize
- CapsuleHeader
.OffsetToCapsuleBody
1632 " GUID %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
1633 CapsuleHeader
.CapsuleGuid
.Data1
,
1634 (UINT32
) CapsuleHeader
.CapsuleGuid
.Data2
,
1635 (UINT32
) CapsuleHeader
.CapsuleGuid
.Data3
,
1636 (UINT32
) CapsuleHeader
.CapsuleGuid
.Data4
[0],
1637 (UINT32
) CapsuleHeader
.CapsuleGuid
.Data4
[1],
1638 (UINT32
) CapsuleHeader
.CapsuleGuid
.Data4
[2],
1639 (UINT32
) CapsuleHeader
.CapsuleGuid
.Data4
[3],
1640 (UINT32
) CapsuleHeader
.CapsuleGuid
.Data4
[4],
1641 (UINT32
) CapsuleHeader
.CapsuleGuid
.Data4
[5],
1642 (UINT32
) CapsuleHeader
.CapsuleGuid
.Data4
[6],
1643 (UINT32
) CapsuleHeader
.CapsuleGuid
.Data4
[7]
1645 if (memcmp (&CapsuleHeader
.CapsuleGuid
, &mEfiCapsuleHeaderGuid
, sizeof (EFI_GUID
)) != 0) {
1646 printf (" INVALID GUID");
1650 printf (" Header size 0x%08X\n", CapsuleHeader
.HeaderSize
);
1651 printf (" Flags 0x%08X\n", CapsuleHeader
.Flags
);
1653 printf (" Capsule image size 0x%08X\n", CapsuleHeader
.CapsuleImageSize
);
1655 printf (" Capsule image size 0x%08X (split)\n", CapsuleHeader
.CapsuleImageSize
);
1658 printf (" Sequence number %d\n", CapsuleHeader
.SequenceNumber
);
1660 " InstanceId %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
1661 CapsuleHeader
.InstanceId
.Data1
,
1662 (UINT32
) CapsuleHeader
.InstanceId
.Data2
,
1663 (UINT32
) CapsuleHeader
.InstanceId
.Data3
,
1664 (UINT32
) CapsuleHeader
.InstanceId
.Data4
[0],
1665 (UINT32
) CapsuleHeader
.InstanceId
.Data4
[1],
1666 (UINT32
) CapsuleHeader
.InstanceId
.Data4
[2],
1667 (UINT32
) CapsuleHeader
.InstanceId
.Data4
[3],
1668 (UINT32
) CapsuleHeader
.InstanceId
.Data4
[4],
1669 (UINT32
) CapsuleHeader
.InstanceId
.Data4
[5],
1670 (UINT32
) CapsuleHeader
.InstanceId
.Data4
[6],
1671 (UINT32
) CapsuleHeader
.InstanceId
.Data4
[7]
1673 printf (" Offset to capsule 0x%X\n", CapsuleHeader
.OffsetToCapsuleBody
);
1675 // Dump header data if there
1677 CapsuleHeaderDataSize
= CapsuleHeader
.OffsetToCapsuleBody
- CapsuleHeader
.HeaderSize
;
1678 if (CapsuleHeaderDataSize
!= 0) {
1679 CapsuleHeaderData
= (UINT8
*) malloc (CapsuleHeaderDataSize
);
1680 if (CapsuleHeaderData
== NULL
) {
1685 "failed to allocate memory to read in capsule header data",
1687 CapsuleHeaderDataSize
1692 fseek (InFptr
, CapsuleHeader
.HeaderSize
, SEEK_SET
);
1693 if (fread (CapsuleHeaderData
, CapsuleHeaderDataSize
, 1, InFptr
) != 1) {
1698 "failed to read capsule header data contents from file",
1700 CapsuleHeaderDataSize
1705 // ************************************************************************
1709 // ************************************************************************
1711 if (CapsuleHeader
.OffsetToOemDefinedHeader
!= 0) {
1712 OemHeader
= (EFI_CAPSULE_OEM_HEADER
*) (CapsuleHeaderData
+ CapsuleHeader
.OffsetToOemDefinedHeader
- CapsuleHeader
.HeaderSize
);
1713 printf (" OEM Header\n");
1715 " GUID %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X\n",
1716 OemHeader
->OemGuid
.Data1
,
1717 (UINT32
) OemHeader
->OemGuid
.Data2
,
1718 (UINT32
) OemHeader
->OemGuid
.Data3
,
1719 (UINT32
) OemHeader
->OemGuid
.Data4
[0],
1720 (UINT32
) OemHeader
->OemGuid
.Data4
[1],
1721 (UINT32
) OemHeader
->OemGuid
.Data4
[2],
1722 (UINT32
) OemHeader
->OemGuid
.Data4
[3],
1723 (UINT32
) OemHeader
->OemGuid
.Data4
[4],
1724 (UINT32
) OemHeader
->OemGuid
.Data4
[5],
1725 (UINT32
) OemHeader
->OemGuid
.Data4
[6],
1726 (UINT32
) OemHeader
->OemGuid
.Data4
[7]
1728 printf (" Header size: 0x%X\n", OemHeader
->HeaderSize
);
1729 printf (" OEM data");
1730 BPtr
= (UINT8
*) (OemHeader
+ 1);
1731 for (ByteCount
= 0; ByteCount
< OemHeader
->HeaderSize
- sizeof (EFI_CAPSULE_OEM_HEADER
); ByteCount
++) {
1732 if ((ByteCount
& 0x7) == 0) {
1736 printf ("%02X ", (UINT32
) *BPtr
);
1743 // ************************************************************************
1745 // Author, revision, short description, and long description information
1747 // ************************************************************************
1749 if (CapsuleHeader
.OffsetToAuthorInformation
!= 0) {
1750 if (DumpCapsuleHeaderStrings (
1751 "Author information",
1752 (WCHAR
*) (CapsuleHeaderData
+ CapsuleHeader
.OffsetToAuthorInformation
- CapsuleHeader
.HeaderSize
)
1753 ) != STATUS_SUCCESS
) {
1758 if (CapsuleHeader
.OffsetToRevisionInformation
!= 0) {
1759 if (DumpCapsuleHeaderStrings (
1760 "Revision information",
1761 (WCHAR
*) (CapsuleHeaderData
+ CapsuleHeader
.OffsetToRevisionInformation
- CapsuleHeader
.HeaderSize
)
1762 ) != STATUS_SUCCESS
) {
1767 if (CapsuleHeader
.OffsetToShortDescription
!= 0) {
1768 if (DumpCapsuleHeaderStrings (
1769 "Short description",
1770 (WCHAR
*) (CapsuleHeaderData
+ CapsuleHeader
.OffsetToShortDescription
- CapsuleHeader
.HeaderSize
)
1771 ) != STATUS_SUCCESS
) {
1776 if (CapsuleHeader
.OffsetToLongDescription
!= 0) {
1777 if (DumpCapsuleHeaderStrings (
1779 (WCHAR
*) (CapsuleHeaderData
+ CapsuleHeader
.OffsetToLongDescription
- CapsuleHeader
.HeaderSize
)
1780 ) != STATUS_SUCCESS
) {
1786 // If it's not a split image, or it is a split image and this is the first in the series, then
1787 // dump the cargo volume.
1789 if ((!SplitImage
) || (CapsuleHeader
.SequenceNumber
== 0)) {
1790 printf (" Cargo FV dump\n");
1791 fseek (InFptr
, CapsuleHeader
.OffsetToCapsuleBody
, SEEK_SET
);
1792 if (fread (&FVHeader
, sizeof (EFI_FIRMWARE_VOLUME_HEADER
), 1, InFptr
) != 1) {
1793 Error (NULL
, 0, 0, FileList
->FileName
, "failed to read cargo FV header");
1797 printf (" FV length 0x%X", FVHeader
.FvLength
);
1798 if (FileSize
- CapsuleHeader
.OffsetToCapsuleBody
!= FVHeader
.FvLength
) {
1800 printf (" ERROR: expected 0x%X to jive with file size on disk", FileSize
- CapsuleHeader
.OffsetToCapsuleBody
);
1805 printf (" Signature 0x%X ", FVHeader
.Signature
);
1806 if (FVHeader
.Signature
== EFI_FVH_SIGNATURE
) {
1809 printf ("INVALID\n");
1812 printf (" FV header length 0x%X\n", (UINT32
) FVHeader
.HeaderLength
);
1813 printf (" Revision 0x%X\n", (UINT32
) FVHeader
.Revision
);
1817 FileList
= FileList
->Next
;
1821 if (InFptr
!= NULL
) {
1825 if (CapsuleHeaderData
!= NULL
) {
1826 free (CapsuleHeaderData
);
1838 Routine Description:
1839 Join split capsule images into a single image. This is the
1840 support function for the -j command-line option.
1846 STATUS_SUCCESS - no problems encountered
1855 FILE_LIST
*FileList
;
1857 EFI_CAPSULE_HEADER CapHdr
;
1858 EFI_CAPSULE_HEADER
*CapHdrPtr
;
1860 UINT32 SequenceNumber
;
1862 // Must have at least two files for join mode
1864 if ((mOptions
.FileList
== NULL
) || (mOptions
.FileList
->Next
== NULL
)) {
1865 Error (NULL
, 0, 0, "must specify at least two file names to join", NULL
);
1866 return STATUS_ERROR
;
1869 // Open the output file
1871 if ((OutFptr
= fopen (mOptions
.OutputFileName
, "wb")) == NULL
) {
1872 Error (NULL
, 0, 0, mOptions
.OutputFileName
, "failed to open output file for writing");
1873 return STATUS_ERROR
;
1876 FileList
= mOptions
.FileList
;
1881 while (FileList
!= NULL
) {
1882 if ((InFptr
= fopen (FileList
->FileName
, "rb")) == NULL
) {
1883 Error (NULL
, 0, 0, FileList
->FileName
, "failed to open file for reading");
1887 // Allocate a buffer into which we can read the file.
1889 fseek (InFptr
, 0, SEEK_END
);
1890 Size
= ftell (InFptr
);
1892 Buffer
= (char *) malloc (Size
);
1893 if (Buffer
== NULL
) {
1894 Error (__FILE__
, __LINE__
, 0, FileList
->FileName
, "failed to allocate buffer to read file into");
1898 CapHdrPtr
= (EFI_CAPSULE_HEADER
*) Buffer
;
1899 if (fread ((void *) Buffer
, Size
, 1, InFptr
) != 1) {
1900 Error (NULL
, 0, 0, FileList
->FileName
, "failed to read file contents");
1904 // Check the header for validity. Check size first.
1906 if (Size
< sizeof (EFI_CAPSULE_HEADER
)) {
1907 Error (NULL
, 0, 0, FileList
->FileName
, "file size is insufficient for a capsule header");
1913 if (memcmp (&CapHdrPtr
->CapsuleGuid
, &mEfiCapsuleHeaderGuid
, sizeof (EFI_GUID
)) != 0) {
1914 Error (NULL
, 0, 0, FileList
->FileName
, "invalid capsule GUID");
1918 // Check sequence number
1920 if (CapHdrPtr
->SequenceNumber
!= SequenceNumber
) {
1926 "invalid sequence number %d (expected %d)",
1927 CapHdrPtr
->SequenceNumber
,
1933 // If the first file, read save the capsule header
1935 if (SequenceNumber
== 0) {
1936 memcpy (&CapHdr
, CapHdrPtr
, sizeof (EFI_CAPSULE_HEADER
));
1938 // Erase the InstanceId GUID
1940 memset (&CapHdrPtr
->InstanceId
, 0, sizeof (EFI_GUID
));
1941 if (fwrite (Buffer
, Size
, 1, OutFptr
) != 1) {
1942 Error (NULL
, 0, 0, FileList
->FileName
, "failed to write contents to output file");
1946 if (CapHdr
.CapsuleImageSize
< Size
) {
1947 Error (NULL
, 0, 0, FileList
->FileName
, "capsule image size in capsule header < image size");
1951 SizeLeft
= CapHdr
.CapsuleImageSize
- Size
;
1954 // Check the GUID against the first file's GUID
1956 if (memcmp (&CapHdr
.CapsuleGuid
, &CapHdrPtr
->CapsuleGuid
, sizeof (EFI_GUID
)) != 0) {
1957 Error (NULL
, 0, 0, FileList
->FileName
, "GUID does not match first file's GUID");
1961 // Make sure we're not throwing out any header info
1963 if (CapHdrPtr
->OffsetToCapsuleBody
> sizeof (EFI_CAPSULE_HEADER
)) {
1965 // Could be the split information, so just emit a warning
1972 "image appears to have additional capsule header information -- ignoring"
1974 } else if (CapHdrPtr
->OffsetToCapsuleBody
< sizeof (EFI_CAPSULE_HEADER
)) {
1975 Error (NULL
, 0, 0, FileList
->FileName
, "offset to capsule body in capsule header is insufficient");
1979 if (fwrite (Buffer
+ CapHdrPtr
->OffsetToCapsuleBody
, Size
- CapHdrPtr
->OffsetToCapsuleBody
, 1, OutFptr
) != 1) {
1980 Error (NULL
, 0, 0, mOptions
.OutputFileName
, "failed to write to file");
1984 if (SizeLeft
< (Size
- CapHdrPtr
->OffsetToCapsuleBody
)) {
1985 Error (NULL
, 0, 0, "sum of image sizes exceeds size specified in initial capsule header", NULL
);
1989 // printf ("FILE: %s OffsetToCapsuleBody=0x%X\n", FileList->FileName, CapHdrPtr->OffsetToCapsuleBody);
1991 SizeLeft
= SizeLeft
- (Size
- CapHdrPtr
->OffsetToCapsuleBody
);
1994 // printf ("FILE: %s sizeleft=0x%X\n", FileList->FileName, SizeLeft);
2000 FileList
= FileList
->Next
;
2005 Error (NULL
, 0, 0, "sum of capsule images is insufficient", "0x%X bytes missing", SizeLeft
);
2009 Status
= STATUS_SUCCESS
;
2012 Status
= STATUS_ERROR
;
2014 if (InFptr
!= NULL
) {
2018 if (OutFptr
!= NULL
) {
2022 if (Buffer
!= NULL
) {
2029 return STATUS_SUCCESS
;
2034 DumpCapsuleHeaderStrings (
2040 Routine Description:
2041 Given a pointer to string data from a capsule header, dump
2045 SectionName - name of the capsule header section to which
2046 the string data pertains
2047 Buffer - pointer to string data from a capsule header
2050 STATUS_SUCCESS - all went well
2054 printf (" %s\n", SectionName
);
2056 printf (" Language: %S\n", Buffer
);
2063 if (wcslen (Buffer
) > 60) {
2064 printf (" %.60S\n", Buffer
);
2067 printf (" %S\n", Buffer
);
2068 Buffer
+= wcslen (Buffer
);
2075 return STATUS_SUCCESS
;
2081 SOURCE_FILE
*SourceFile
,
2087 Routine Description:
2088 Scan a hex value from the input stream.
2091 SourceFile - input file contents
2092 Value - returned value
2093 NumDigits - number of digits to read
2096 STATUS_SUCCESS - if NumDigits were read from the file
2097 STATUS_ERROR - otherwise
2106 SaveFilePos
= SourceFile
->FileBufferPtr
;
2109 while (Digits
> 0) {
2110 Nibble
= SourceFile
->FileBufferPtr
[0];
2111 if ((Nibble
>= UNICODE_0
) && (Nibble
<= UNICODE_9
)) {
2112 *Value
= (*Value
<< 4) | (Nibble
- UNICODE_0
);
2113 } else if ((Nibble
>= UNICODE_A
) && (Nibble
<= UNICODE_F
)) {
2114 *Value
= (*Value
<< 4) | (Nibble
- UNICODE_A
+ 0x10);
2115 } else if ((Nibble
>= UNICODE_a
) && (Nibble
<= UNICODE_f
)) {
2116 *Value
= (*Value
<< 4) | (Nibble
- UNICODE_a
+ 0x10);
2119 SourceFile
->FileName
,
2120 SourceFile
->LineNum
,
2123 "expected %d valid hex nibbles at %.20S",
2127 return STATUS_ERROR
;
2130 SourceFile
->FileBufferPtr
++;
2134 return STATUS_SUCCESS
;
2144 Routine Description:
2146 GC_TODO: Add function description
2150 File - GC_TODO: add argument description
2154 GC_TODO: add return values
2158 if ((UINT32
) File
->FileBufferPtr
- (UINT32
) File
->FileBuffer
>= File
->FileSize
) {
2159 File
->EndOfFile
= TRUE
;
2162 // Reposition to the end of the file if we went beyond
2164 if (File
->EndOfFile
) {
2165 File
->FileBufferPtr
= File
->FileBuffer
+ File
->FileSize
/ sizeof (WCHAR
);
2168 return File
->EndOfFile
;
2174 SOURCE_FILE
*SourceFile
2178 Routine Description:
2180 GC_TODO: Add function description
2184 SourceFile - GC_TODO: add argument description
2188 GC_TODO: add return values
2192 while (!EndOfFile (SourceFile
)) {
2193 switch (*SourceFile
->FileBufferPtr
) {
2198 SourceFile
->FileBufferPtr
++;
2202 SourceFile
->FileBufferPtr
++;
2203 SourceFile
->LineNum
++;
2212 // Parse a number. Possible format:
2228 Routine Description:
2230 GC_TODO: Add function description
2234 Str - GC_TODO: add argument description
2235 Value - GC_TODO: add argument description
2239 GC_TODO: add return values
2247 if (!isdigit (Str
[0])) {
2251 // Look for hex number
2253 if ((Str
[0] == '0') && (tolower (Str
[1]) == 'x')) {
2260 if ((Str
[0] >= '0') && (Str
[0] <= '9')) {
2261 LValue
= (LValue
<< 4) | (Str
[0] - '0');
2262 } else if ((Str
[0] >= 'A') && (Str
[0] <= 'F')) {
2263 LValue
= (LValue
<< 4) | (Str
[0] - 'A' + 0x10);
2264 } else if ((Str
[0] >= 'a') && (Str
[0] <= 'f')) {
2265 LValue
= (LValue
<< 4) | (Str
[0] - 'a' + 0x10);
2273 LValue
= atoi (Str
);
2274 while (isdigit (*Str
)) {
2279 // If string left over, better be one character we recognize
2294 LValue
*= 1024 * 1024;
2306 // Process the command-line arguments
2316 Routine Description:
2318 Processes command line arguments.
2322 Argc - Number of command line arguments
2323 Argv[] - Array of files input on command line
2327 STATUS_ERROR - Function exited with an error
2328 STATUS_SUCCESS - Function executed successfully
2334 FILE_LIST
*LastFile
;
2341 // Clear our globals
2343 memset ((char *) &mOptions
, 0, sizeof (mOptions
));
2346 // Skip program name
2353 return STATUS_ERROR
;
2356 // Process until no more options
2358 while ((Argc
> 0) && (Argv
[0][0] == '-')) {
2359 if (stricmp (Argv
[0], "-script") == 0) {
2361 // Check for one more arg
2365 // Save the file name
2367 if (strlen (Argv
[1]) >= sizeof (mOptions
.ScriptFileName
)) {
2368 Error (NULL
, 0, 0, NULL
, "input script file name length exceeds internal buffer size");
2370 if (NewFile
!= NULL
) {
2373 if (NewSize
!= NULL
) {
2377 return STATUS_ERROR
;
2380 strcpy (mOptions
.ScriptFileName
, Argv
[1]);
2382 Error (NULL
, 0, 0, Argv
[0], "missing script file name with option");
2385 if (NewFile
!= NULL
) {
2388 if (NewSize
!= NULL
) {
2392 return STATUS_ERROR
;
2398 // -o outfilename -- specify output file name (required)
2400 } else if (stricmp (Argv
[0], "-o") == 0) {
2402 // check for one more arg
2406 // Try to open the file
2408 // if ((mOptions.OutFptr = fopen (Argv[1], "wb")) == NULL) {
2409 // Error (NULL, 0, 0, Argv[1], "failed to open output file for writing");
2410 // return STATUS_ERROR;
2413 strcpy (mOptions
.OutputFileName
, Argv
[1]);
2415 Error (NULL
, 0, 0, Argv
[0], "missing output filename with option");
2418 if (NewFile
!= NULL
) {
2421 if (NewSize
!= NULL
) {
2425 return STATUS_ERROR
;
2430 } else if (stricmp (Argv
[0], "-j") == 0) {
2431 mOptions
.JoinMode
= TRUE
;
2433 // -split <size> option (multiple allowed)
2435 } else if (stricmp (Argv
[0], "-split") == 0) {
2437 NewSize
= (SIZE_LIST
*) malloc (sizeof (SIZE_LIST
));
2438 if (NewSize
== NULL
) {
2439 Error (NULL
, 0, 0, "memory allocation failure", NULL
);
2441 if (NewFile
!= NULL
) {
2444 if (NewSize
!= NULL
) {
2448 return STATUS_ERROR
;
2451 memset (NewSize
, 0, sizeof (SIZE_LIST
));
2453 // Get the size from the next arg, and then add this size
2456 if (!GetNumber (Argv
[1], &NewSize
->Size
)) {
2457 Error (NULL
, 0, 0, Argv
[1], "invalid split size argument");
2459 if (NewFile
!= NULL
) {
2462 if (NewSize
!= NULL
) {
2466 return STATUS_ERROR
;
2469 if (mOptions
.SizeList
== NULL
) {
2470 mOptions
.SizeList
= NewSize
;
2471 mOptions
.CurrentSize
= NewSize
;
2473 mOptions
.LastSize
->Next
= NewSize
;
2476 mOptions
.LastSize
= NewSize
;
2479 Error (NULL
, 0, 0, Argv
[0], "missing size parameter with option");
2482 if (NewFile
!= NULL
) {
2485 if (NewSize
!= NULL
) {
2489 return STATUS_ERROR
;
2494 } else if ((stricmp (Argv
[0], "-h") == 0) || (strcmp (Argv
[0], "-?") == 0)) {
2497 if (NewFile
!= NULL
) {
2500 if (NewSize
!= NULL
) {
2504 return STATUS_ERROR
;
2506 // Default minimum header
2508 } else if (stricmp (Argv
[0], "-dump") == 0) {
2509 mOptions
.Dump
= TRUE
;
2510 } else if (stricmp (Argv
[0], "-v") == 0) {
2511 mOptions
.Verbose
= TRUE
;
2513 Error (NULL
, 0, 0, Argv
[0], "unrecognized option");
2516 if (NewFile
!= NULL
) {
2519 if (NewSize
!= NULL
) {
2523 return STATUS_ERROR
;
2530 // Can't -j join files and -s split output capsule
2532 if ((mOptions
.SizeList
!= NULL
) && (mOptions
.JoinMode
)) {
2533 Error (NULL
, 0, 0, "cannot specify both -j and -size", NULL
);
2535 if (NewFile
!= NULL
) {
2538 if (NewSize
!= NULL
) {
2542 return STATUS_ERROR
;
2545 // Must have specified an output file name if not -dump
2547 if ((mOptions
.Dump
== 0) && (mOptions
.OutputFileName
[0] == 0)) {
2548 Error (NULL
, 0, 0, NULL
, "-o OutputFileName must be specified");
2551 if (NewFile
!= NULL
) {
2554 if (NewSize
!= NULL
) {
2558 return STATUS_ERROR
;
2561 // Rest of arguments are input files. The first one is a firmware
2562 // volume image, and the rest are FFS files that are to be inserted
2563 // into the firmware volume.
2567 NewFile
= (FILE_LIST
*) malloc (sizeof (FILE_LIST
));
2568 if (NewFile
== NULL
) {
2569 Error (NULL
, 0, 0, "memory allocation failure", NULL
);
2571 if (NewFile
!= NULL
) {
2574 if (NewSize
!= NULL
) {
2578 return STATUS_ERROR
;
2581 memset ((char *) NewFile
, 0, sizeof (FILE_LIST
));
2582 strcpy (NewFile
->FileName
, Argv
[0]);
2583 if (mOptions
.FileList
== NULL
) {
2584 mOptions
.FileList
= NewFile
;
2586 if (LastFile
== NULL
) {
2589 LastFile
->Next
= NewFile
;
2599 // Must have provided at least one file name
2601 if (mOptions
.FileList
== NULL
) {
2602 Error (NULL
, 0, 0, "must specify at least one file name", NULL
);
2605 if (NewFile
!= NULL
) {
2608 if (NewSize
!= NULL
) {
2612 return STATUS_ERROR
;
2615 return STATUS_SUCCESS
;
2625 Routine Description:
2627 Print usage information for this utility.
2640 static const char *Str
[] = {
2641 PROGRAM_NAME
" -- create a capsule header",
2642 " Usage: "PROGRAM_NAME
" {options} [CapsuleFV]",
2646 " Options include:",
2647 " -h or -? for this help information",
2648 " -script fname to take capsule header info from unicode script",
2650 " -o fname write output to file fname (required)",
2651 " -split size split capsule image into multiple output files",
2652 " -dump to dump a capsule header",
2653 " -v for verbose output\n",
2654 " -j to join split capsule images into a single image",
2656 " CapsuleFV is the name of an existing well-formed Tiano firmware",
2659 // FfsFileNames are the names of one or more Tiano FFS files to",
2660 // " insert into the output capsule image.",
2664 for (Index
= 0; Str
[Index
] != NULL
; Index
++) {
2665 fprintf (stdout
, "%s\n", Str
[Index
]);