]> git.proxmox.com Git - mirror_edk2.git/blob - Tools/CodeTools/TianoTools/GenCapsuleHdr/GenCapsuleHdr.c
Restructuring for better separation of Tool packages.
[mirror_edk2.git] / Tools / CodeTools / TianoTools / GenCapsuleHdr / GenCapsuleHdr.c
1 /*++
2
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
8
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.
11
12
13 Module Name:
14
15 GenCapsuleHdr.c
16
17 Abstract:
18
19 Generate a capsule header for a file, and optionally prepend the
20 header to a file or list of files.
21
22 --*/
23
24 #define _UNICODE
25
26 #include <stdio.h>
27 #include <string.h>
28 #include <stdlib.h>
29 #include <ctype.h>
30
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
39
40 #include "CommonLib.h"
41 #include "EfiUtilityMsgs.h"
42
43 #define MAX_PATH 256
44 #define PROGRAM_NAME "GenCapsuleHdr"
45
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'
63
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"
74
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)
79 #endif
80
81 typedef wchar_t WCHAR;
82
83 typedef struct _FILE_LIST {
84 struct _FILE_LIST *Next;
85 INT8 FileName[MAX_PATH];
86 } FILE_LIST;
87
88 typedef struct _SIZE_LIST {
89 struct _SIZE_LIST *Next;
90 UINT32 Size;
91 } SIZE_LIST;
92
93 typedef struct {
94 INT8 FileName[MAX_PATH];
95 WCHAR *FileBuffer;
96 WCHAR *FileBufferPtr;
97 UINT32 FileSize;
98 FILE *FilePtr;
99 BOOLEAN EndOfFile;
100 UINT32 LineNum;
101 } SOURCE_FILE;
102
103 //
104 // Here's all our globals.
105 //
106 static struct {
107 BOOLEAN Dump;
108 BOOLEAN Verbose;
109 BOOLEAN JoinMode;
110 INT8 ScriptFileName[MAX_PATH];
111 INT8 OutputFileName[MAX_PATH];
112 FILE_LIST *FileList;
113 FILE *OutFptr;
114 SIZE_LIST *SizeList;
115 SIZE_LIST *LastSize;
116 SIZE_LIST *CurrentSize;
117 } mOptions;
118
119 static EFI_GUID mEfiCapsuleHeaderGuid = EFI_CAPSULE_GUID;
120
121 void
122 CreateGuid (
123 EFI_GUID *Guid
124 );
125
126 static
127 STATUS
128 ProcessArgs (
129 int Argc,
130 char *Argv[]
131 );
132
133 static
134 void
135 SkipWhiteSpace (
136 SOURCE_FILE *SourceFile
137 );
138
139 static
140 STATUS
141 GetHexValue (
142 SOURCE_FILE *SourceFile,
143 UINT32 *Value,
144 UINT32 NumDigits
145 );
146
147 static
148 BOOLEAN
149 GetSplitFileName (
150 INT8 *BaseFileName,
151 INT8 *NewFileName,
152 UINT32 SequenceNumber
153 );
154
155 static
156 STATUS
157 SplitCapsule (
158 INT8 *CapsuleFileName
159 );
160
161 static
162 void
163 Usage (
164 VOID
165 );
166
167 static
168 void
169 DumpCapsule (
170 VOID
171 );
172
173 static
174 STATUS
175 JoinCapsule (
176 VOID
177 );
178
179 static
180 STATUS
181 DumpCapsuleHeaderStrings (
182 UINT8 *SectionName,
183 WCHAR *Buffer
184 );
185
186 static
187 STATUS
188 CheckFirmwareVolumeHeader (
189 INT8 *FileName,
190 INT8 *Buffer,
191 UINT32 BufferSize
192 );
193
194 static
195 BOOLEAN
196 IsToken (
197 SOURCE_FILE *File,
198 WCHAR *Token
199 );
200
201 static
202 BOOLEAN
203 GetNumber (
204 INT8 *Str,
205 UINT32 *Value
206 );
207
208 static
209 STATUS
210 ProcessScriptFile (
211 INT8 *ScriptFileName,
212 FILE *OutFptr,
213 EFI_CAPSULE_HEADER *CapsuleHeader
214 );
215
216 static
217 STATUS
218 ParseCapsuleInfo (
219 SOURCE_FILE *SourceFile,
220 FILE *OutFptr,
221 WCHAR *SectionName
222 );
223
224 static
225 STATUS
226 CreateCapsule (
227 VOID
228 );
229
230 static
231 STATUS
232 ParseOemInfo (
233 SOURCE_FILE *SourceFile,
234 FILE *OutFptr
235 );
236
237 static
238 BOOLEAN
239 IsWhiteSpace (
240 WCHAR Char
241 );
242
243 static
244 BOOLEAN
245 EndOfFile (
246 SOURCE_FILE *File
247 );
248
249 int
250 main (
251 int Argc,
252 char *Argv[]
253 )
254 /*++
255
256 Routine Description:
257 Call the routine to process the command-line arguments, then
258 dispatch to the appropriate function.
259
260 Arguments:
261 Standard C main() argc and argv.
262
263 Returns:
264 0 if successful
265 nonzero otherwise
266
267 --*/
268 // GC_TODO: Argc - add argument and description to function comment
269 // GC_TODO: ] - add argument and description to function comment
270 {
271 STATUS Status;
272 FILE_LIST *NextFile;
273 //
274 // Specify our program name to the error printing routines.
275 //
276 SetUtilityName (PROGRAM_NAME);
277 //
278 // Process the command-line arguments
279 //
280 Status = ProcessArgs (Argc, Argv);
281 if (Status == STATUS_SUCCESS) {
282 if (mOptions.Dump) {
283 DumpCapsule ();
284 } else if (mOptions.JoinMode) {
285 JoinCapsule ();
286 } else {
287 CreateCapsule ();
288 }
289 }
290 //
291 // Cleanup
292 //
293 while (mOptions.FileList != NULL) {
294 NextFile = mOptions.FileList->Next;
295 free (mOptions.FileList);
296 mOptions.FileList = NextFile;
297 }
298
299 while (mOptions.SizeList != NULL) {
300 mOptions.CurrentSize = mOptions.SizeList->Next;
301 free (mOptions.SizeList);
302 mOptions.SizeList = mOptions.CurrentSize;
303 }
304
305 return GetUtilityStatus ();
306 }
307
308 static
309 STATUS
310 CreateCapsule (
311 VOID
312 )
313 /*++
314
315 Routine Description:
316
317 GC_TODO: Add function description
318
319 Arguments:
320
321 None
322
323 Returns:
324
325 GC_TODO: add return values
326
327 --*/
328 {
329 FILE *InFptr;
330 FILE_LIST *FileList;
331 INT8 *Buffer;
332 UINT32 Size;
333 EFI_CAPSULE_HEADER CapsuleHeader;
334 UINT8 Zero;
335 UINT8 FirstFile;
336 UINT32 CapsuleHeaderSize;
337 long InsertedBlockMapEntryOffset;
338 EFI_FV_BLOCK_MAP_ENTRY InsertedBlockMapEntry;
339 UINT64 FirmwareVolumeSize;
340 long FileSize;
341 EFI_FIRMWARE_VOLUME_HEADER FVHeader;
342
343 Buffer = NULL;
344 InFptr = NULL;
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));
350
351 if ((mOptions.OutFptr = fopen (mOptions.OutputFileName, "wb")) == NULL) {
352 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to open output file for writing");
353 return STATUS_ERROR;
354 }
355
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) {
362 goto Done;
363 }
364 } else {
365 //
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;
370 #endif
371 CapsuleHeader.OffsetToCapsuleBody = sizeof (EFI_CAPSULE_HEADER);
372
373 if (fwrite ((void *) &CapsuleHeader, sizeof (CapsuleHeader), 1, mOptions.OutFptr) != 1) {
374 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");
375 goto Done;
376 }
377 }
378
379 CapsuleHeaderSize = CapsuleHeader.OffsetToCapsuleBody;
380 //
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.
385 //
386 FileList = mOptions.FileList;
387 FirstFile = 1;
388 Zero = 0;
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");
392 goto Done;
393 }
394 //
395 // Allocate a buffer into which we can read the file.
396 //
397 fseek (InFptr, 0, SEEK_END);
398 Size = ftell (InFptr);
399 rewind (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");
403 goto Done;
404 }
405
406 if (fread ((void *) Buffer, Size, 1, InFptr) != 1) {
407 Error (NULL, 0, 0, FileList->FileName, "failed to read file contents");
408 goto Done;
409 }
410
411 if (Size > 0) {
412 //
413 // Align the write of the first bytes from the file if not the first file
414 //
415 if (FirstFile) {
416 //
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
419 //
420 if (CheckFirmwareVolumeHeader (FileList->FileName, Buffer, Size) != STATUS_SUCCESS) {
421 goto Done;
422 }
423 //
424 // Save a copy of the firmware volume header for later
425 //
426 memcpy (&FVHeader, Buffer, sizeof (EFI_FIRMWARE_VOLUME_HEADER));
427 FirmwareVolumeSize = FVHeader.FvLength;
428 if (FileList->Next != NULL) {
429 //
430 // Copy the firmware volume header
431 //
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");
435 goto Done;
436 }
437
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");
440 goto Done;
441 }
442
443 if (fwrite (
444 Buffer + FVHeader.HeaderLength,
445 Size - FVHeader.HeaderLength,
446 1,
447 mOptions.OutFptr
448 ) != 1) {
449 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");
450 goto Done;
451 }
452 } else {
453 //
454 // Copy the file contents as-is
455 //
456 if (fwrite ((void *) Buffer, Size, 1, mOptions.OutFptr) != 1) {
457 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");
458 goto Done;
459 }
460 }
461 } else {
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");
465 goto Done;
466 }
467 }
468
469 if (fwrite ((void *) Buffer, Size, 1, mOptions.OutFptr) != 1) {
470 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");
471 goto Done;
472 }
473 }
474
475 FirstFile = 0;
476 }
477
478 free (Buffer);
479 Buffer = NULL;
480 fclose (InFptr);
481 InFptr = NULL;
482 FileList = FileList->Next;
483 }
484
485 Done:
486 if (Buffer != NULL) {
487 free (Buffer);
488 }
489
490 if (InFptr != NULL) {
491 fclose (InFptr);
492 }
493 //
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.
496 //
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);
503 //
504 // Fix up the firmware volume header and write it out
505 //
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);
510 //
511 // Reposition to the end of the file
512 //
513 }
514 //
515 // Close files and free the global string lists we allocated memory for
516 //
517 if (mOptions.OutFptr != NULL) {
518 //
519 // We should now know the full capsule image size. Update the header and write it again.
520 //
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");
527 }
528
529 fseek (mOptions.OutFptr, 0, SEEK_END);
530 fclose (mOptions.OutFptr);
531 mOptions.OutFptr = NULL;
532 }
533 //
534 // If they are doing split capsule output, then split it up now.
535 //
536 if ((mOptions.Dump == 0) && (GetUtilityStatus () == STATUS_SUCCESS) && (mOptions.SizeList != NULL)) {
537 SplitCapsule (mOptions.OutputFileName);
538 }
539
540 return STATUS_SUCCESS;
541 }
542
543 static
544 STATUS
545 ProcessScriptFile (
546 INT8 *ScriptFileName,
547 FILE *OutFptr,
548 EFI_CAPSULE_HEADER *CapsuleHeader
549 )
550 /*++
551
552 Routine Description:
553 Parse a capsule header script file.
554
555 Arguments:
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
560
561 Returns:
562 STATUS_SUCCESS - if all went well
563
564 --*/
565 {
566 #if 0
567 STATUS Status;
568 SOURCE_FILE SourceFile;
569 WCHAR *WScriptFileName;
570 BOOLEAN InComment;
571
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);
574 return STATUS_ERROR;
575 }
576
577 memset (&SourceFile, 0, sizeof (SOURCE_FILE));
578 strcpy (SourceFile.FileName, ScriptFileName);
579
580 Status = STATUS_ERROR;
581 //
582 // Open the input unicode script file and read it into a buffer
583 //
584 WScriptFileName = (WCHAR *) malloc ((strlen (ScriptFileName) + 1) * sizeof (WCHAR));
585 if (WScriptFileName == NULL) {
586 Error (__FILE__, __LINE__, 0, "failed to allocate memory", NULL);
587 return STATUS_ERROR;
588 }
589
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");
594 goto Done;
595 }
596
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");
604 goto Done;
605 }
606
607 if (fread (SourceFile.FileBuffer, SourceFile.FileSize, 1, SourceFile.FilePtr) != 1) {
608 Error (NULL, 0, 0, ScriptFileName, "failed to read file contents");
609 goto Done;
610 }
611
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);
616 goto Done;
617 }
618
619 SourceFile.FileBufferPtr++;
620 SourceFile.FileBuffer[SourceFile.FileSize / sizeof (WCHAR)] = 0;
621 //
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.
624 //
625 InComment = 0;
626 while (!EndOfFile (&SourceFile)) {
627 if (SourceFile.FileBufferPtr[0] == UNICODE_CR) {
628 SourceFile.FileBufferPtr[0] = 0;
629 InComment = 0;
630 } else if (SourceFile.FileBufferPtr[0] == UNICODE_LF) {
631 InComment = 0;
632 } else if (InComment) {
633 SourceFile.FileBufferPtr[0] = UNICODE_SPACE;
634 } else if ((SourceFile.FileBufferPtr[0] == UNICODE_SLASH) && (SourceFile.FileBufferPtr[1] == UNICODE_SLASH)) {
635 InComment = 1;
636 SourceFile.FileBufferPtr[0] = UNICODE_SPACE;
637 }
638
639 SourceFile.FileBufferPtr++;
640 }
641 //
642 // Reposition to the start of the file, but skip over the unicode file start
643 //
644 SourceFile.FileBufferPtr = SourceFile.FileBuffer;
645 SourceFile.FileBufferPtr++;
646 SourceFile.EndOfFile = 0;
647 CapsuleHeader->OffsetToOemDefinedHeader = ftell (OutFptr);
648 //
649 // Parse the OEM bytes
650 //
651 if (ParseOemInfo (&SourceFile, OutFptr) != STATUS_SUCCESS) {
652 goto Done;
653 }
654 //
655 // Parse the author information
656 //
657 CapsuleHeader->OffsetToAuthorInformation = ftell (OutFptr);
658 if (ParseCapsuleInfo (&SourceFile, OutFptr, AUTHOR_INFO_STRING) != STATUS_SUCCESS) {
659 goto Done;
660 }
661 //
662 // Parse the revision information
663 //
664 CapsuleHeader->OffsetToRevisionInformation = ftell (OutFptr);
665 if (ParseCapsuleInfo (&SourceFile, OutFptr, REVISION_INFO_STRING) != STATUS_SUCCESS) {
666 goto Done;
667 }
668 //
669 // Parse the short description
670 //
671 CapsuleHeader->OffsetToShortDescription = ftell (OutFptr);
672 if (ParseCapsuleInfo (&SourceFile, OutFptr, SHORT_DESCRIPTION_STRING) != STATUS_SUCCESS) {
673 goto Done;
674 }
675 //
676 // Parse the long description
677 //
678 CapsuleHeader->OffsetToLongDescription = ftell (OutFptr);
679 if (ParseCapsuleInfo (&SourceFile, OutFptr, LONG_DESCRIPTION_STRING) != STATUS_SUCCESS) {
680 goto Done;
681 }
682 //
683 // Better be end of contents
684 //
685 SkipWhiteSpace (&SourceFile);
686 if (!EndOfFile (&SourceFile)) {
687 Error (ScriptFileName, SourceFile.LineNum, 0, NULL, "expected end-of-file, not %.20S", SourceFile.FileBufferPtr);
688 goto Done;
689 }
690
691 CapsuleHeader->OffsetToCapsuleBody = ftell (OutFptr);
692 rewind (OutFptr);
693 fwrite (CapsuleHeader, sizeof (EFI_CAPSULE_HEADER), 1, OutFptr);
694 fseek (OutFptr, 0, SEEK_END);
695 Status = STATUS_SUCCESS;
696 Done:
697 if (SourceFile.FilePtr != NULL) {
698 fclose (SourceFile.FilePtr);
699 }
700
701 if (SourceFile.FileBuffer != NULL) {
702 free (SourceFile.FileBuffer);
703 }
704
705 return Status;
706
707 #endif
708 return STATUS_SUCCESS;
709 }
710 //
711 // Parse the OEM data of format:
712 // OemInfo {
713 // GUID = 12345676-1234-1234-123456789ABC
714 // DATA = 0x01, 0x02, 0x03...
715 // }
716 //
717 static
718 STATUS
719 ParseOemInfo (
720 SOURCE_FILE *SourceFile,
721 FILE *OutFptr
722 )
723 /*++
724
725 Routine Description:
726
727 GC_TODO: Add function description
728
729 Arguments:
730
731 SourceFile - GC_TODO: add argument description
732 OutFptr - GC_TODO: add argument description
733
734 Returns:
735
736 GC_TODO: add return values
737
738 --*/
739 {
740 long OemHeaderOffset;
741 UINT32 Data;
742 EFI_CAPSULE_OEM_HEADER OemHeader;
743 STATUS Status;
744 UINT32 DigitCount;
745 WCHAR *SaveFilePos;
746 UINT8 ByteData;
747
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);
754 goto Done;
755 }
756
757 if (!IsToken (SourceFile, OEM_HEADER_STRING)) {
758 Error (
759 SourceFile->FileName,
760 SourceFile->LineNum,
761 0,
762 NULL,
763 "expected %S, not %.20S",
764 OEM_HEADER_STRING,
765 SourceFile->FileBufferPtr
766 );
767 goto Done;
768 }
769
770 if (!IsToken (SourceFile, EQUAL_STRING)) {
771 Error (
772 SourceFile->FileName,
773 SourceFile->LineNum,
774 0,
775 NULL,
776 "expected %S, not %.20S",
777 EQUAL_STRING,
778 SourceFile->FileBufferPtr
779 );
780 goto Done;
781 }
782
783 if (!IsToken (SourceFile, OPEN_BRACE_STRING)) {
784 Error (
785 SourceFile->FileName,
786 SourceFile->LineNum,
787 0,
788 NULL,
789 "expected %S, not %.20S",
790 OPEN_BRACE_STRING,
791 SourceFile->FileBufferPtr
792 );
793 goto Done;
794 }
795 //
796 // Look for: GUID = xxxxxxx-xxxx-xxxx-xxxxxxxxxxxxx
797 //
798 if (!IsToken (SourceFile, GUID_STRING)) {
799 Error (
800 SourceFile->FileName,
801 SourceFile->LineNum,
802 0,
803 NULL,
804 "expected %S, not %.20S",
805 GUID_STRING,
806 SourceFile->FileBufferPtr
807 );
808 goto Done;
809 }
810
811 if (!IsToken (SourceFile, EQUAL_STRING)) {
812 Error (
813 SourceFile->FileName,
814 SourceFile->LineNum,
815 0,
816 NULL,
817 "expected %S, not %.20S",
818 EQUAL_STRING,
819 SourceFile->FileBufferPtr
820 );
821 goto Done;
822 }
823 //
824 // Parse the xxxxxxxx-xxxx-xxxx-xxxx portion of the GUID
825 //
826 SkipWhiteSpace (SourceFile);
827 if (GetHexValue (SourceFile, &Data, 8) != STATUS_SUCCESS) {
828 Error (SourceFile->FileName, SourceFile->LineNum, 0, "invalid GUID", NULL);
829 goto Done;
830 }
831
832 OemHeader.OemGuid.Data1 = Data;
833 if (!IsToken (SourceFile, L"-")) {
834 Error (
835 SourceFile->FileName,
836 SourceFile->LineNum,
837 0,
838 NULL,
839 "expected dash in GUID, not %S",
840 SourceFile->FileBufferPtr
841 );
842 goto Done;
843 }
844 //
845 // Get 3 word values
846 //
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);
850 goto Done;
851 }
852
853 switch (DigitCount) {
854 case 0:
855 OemHeader.OemGuid.Data2 = (UINT16) Data;
856 break;
857
858 case 1:
859 OemHeader.OemGuid.Data3 = (UINT16) Data;
860 break;
861
862 case 2:
863 OemHeader.OemGuid.Data4[1] = (UINT8) Data;
864 OemHeader.OemGuid.Data4[0] = (UINT8) (Data >> 8);
865 break;
866 }
867
868 if (!IsToken (SourceFile, L"-")) {
869 Error (
870 SourceFile->FileName,
871 SourceFile->LineNum,
872 0,
873 NULL,
874 "expected dash in GUID, not %S",
875 SourceFile->FileBufferPtr
876 );
877 goto Done;
878 }
879 }
880 //
881 // Pick up the last 6 bytes of the GUID
882 //
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);
887 goto Done;
888 }
889
890 OemHeader.OemGuid.Data4[DigitCount + 2] = (UINT8) Data;
891 }
892 //
893 // Now read raw OEM data bytes. May or may not be present.
894 // DATA = 0x01, 0x02, 0x02...
895 //
896 if (IsToken (SourceFile, CLOSE_BRACE_STRING)) {
897 Status = STATUS_SUCCESS;
898 goto Done;
899 }
900
901 if (!IsToken (SourceFile, DATA_STRING)) {
902 Error (
903 SourceFile->FileName,
904 SourceFile->LineNum,
905 0,
906 NULL,
907 "expected %S, not %.20S",
908 DATA_STRING,
909 SourceFile->FileBufferPtr
910 );
911 goto Done;
912 }
913
914 if (!IsToken (SourceFile, EQUAL_STRING)) {
915 Error (
916 SourceFile->FileName,
917 SourceFile->LineNum,
918 0,
919 NULL,
920 "expected %S, not %.20S",
921 EQUAL_STRING,
922 SourceFile->FileBufferPtr
923 );
924 goto Done;
925 }
926
927 while (!EndOfFile (SourceFile)) {
928 if (IsToken (SourceFile, CLOSE_BRACE_STRING)) {
929 Status = STATUS_SUCCESS;
930 goto Done;
931 }
932
933 if (IsToken (SourceFile, L"0x")) {
934 if (swscanf (SourceFile->FileBufferPtr, L"%x", &Data) != 1) {
935 Error (
936 SourceFile->FileName,
937 SourceFile->LineNum,
938 0,
939 NULL,
940 "expected hex byte value, not %.20S",
941 SourceFile->FileBufferPtr
942 );
943 goto Done;
944 }
945
946 if (Data &~0xFF) {
947 Error (
948 SourceFile->FileName,
949 SourceFile->LineNum,
950 0,
951 NULL,
952 "expected byte hex byte value at %.20S",
953 SourceFile->FileBufferPtr
954 );
955 goto Done;
956 }
957 //
958 // Skip over the hex digits, then write the data
959 //
960 while (iswxdigit (SourceFile->FileBufferPtr[0])) {
961 SourceFile->FileBufferPtr++;
962 }
963
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);
967 goto Done;
968 }
969
970 OemHeader.HeaderSize++;
971 //
972 // Optional comma
973 //
974 IsToken (SourceFile, L",");
975 } else {
976 Error (
977 SourceFile->FileName,
978 SourceFile->LineNum,
979 0,
980 NULL,
981 "expected hex OEM data, not %.20S",
982 SourceFile->FileBufferPtr
983 );
984 goto Done;
985 }
986 }
987
988 if (EndOfFile (SourceFile)) {
989 Error (
990 SourceFile->FileName,
991 SourceFile->LineNum,
992 0,
993 NULL,
994 "expected %S close to OEM header data",
995 CLOSE_BRACE_STRING
996 );
997 goto Done;
998 }
999
1000 Status = STATUS_SUCCESS;
1001 Done:
1002 //
1003 // re-write the oem header if no errors
1004 //
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);
1009 goto Done;
1010 }
1011
1012 fseek (OutFptr, 0, SEEK_END);
1013 }
1014
1015 return Status;
1016 }
1017
1018 static
1019 STATUS
1020 ParseCapsuleInfo (
1021 SOURCE_FILE *SourceFile,
1022 FILE *OutFptr,
1023 WCHAR *SectionName
1024 )
1025 // GC_TODO: function comment should start with '/*++'
1026 //
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
1036 //
1037 {
1038 STATUS Status;
1039 int StringCount;
1040 WCHAR Zero;
1041 WCHAR Spacebar;
1042
1043 Status = STATUS_ERROR;
1044 Zero = 0;
1045 Spacebar = UNICODE_SPACE;
1046
1047 if (!IsToken (SourceFile, SectionName)) {
1048 Error (
1049 SourceFile->FileName,
1050 SourceFile->LineNum,
1051 0,
1052 NULL,
1053 "expected %S, not %.20S",
1054 SectionName,
1055 SourceFile->FileBufferPtr
1056 );
1057 goto Done;
1058 }
1059
1060 if (!IsToken (SourceFile, EQUAL_STRING)) {
1061 Error (
1062 SourceFile->FileName,
1063 SourceFile->LineNum,
1064 0,
1065 NULL,
1066 "expected %S, not %.20S",
1067 EQUAL_STRING,
1068 SourceFile->FileBufferPtr
1069 );
1070 goto Done;
1071 }
1072
1073 if (!IsToken (SourceFile, OPEN_BRACE_STRING)) {
1074 Error (
1075 SourceFile->FileName,
1076 SourceFile->LineNum,
1077 0,
1078 NULL,
1079 "expected %S, not %.20S",
1080 OPEN_BRACE_STRING,
1081 SourceFile->FileBufferPtr
1082 );
1083 goto Done;
1084 }
1085
1086 while (!EndOfFile (SourceFile)) {
1087 if (IsToken (SourceFile, CLOSE_BRACE_STRING)) {
1088 break;
1089 }
1090 //
1091 // Look for language identifier (3 lowercase chars)
1092 //
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])
1100 ) {
1101 //
1102 // Write the 3 chars followed by a spacebar, and then look for opening quote
1103 //
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);
1111 StringCount = 0;
1112 while (IsToken (SourceFile, L"\"")) {
1113 StringCount++;
1114 while (!EndOfFile (SourceFile)) {
1115 if (SourceFile->FileBufferPtr[0] == UNICODE_DOUBLE_QUOTE) {
1116 SourceFile->FileBufferPtr++;
1117 break;
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);
1120 goto Done;
1121 } else {
1122 fwrite (SourceFile->FileBufferPtr, sizeof (WCHAR), 1, OutFptr);
1123 SourceFile->FileBufferPtr++;
1124 }
1125 }
1126 }
1127
1128 if (StringCount == 0) {
1129 Error (
1130 SourceFile->FileName,
1131 SourceFile->LineNum,
1132 0,
1133 NULL,
1134 "expected quoted string, not %.20S",
1135 SourceFile->FileBufferPtr
1136 );
1137 goto Done;
1138 }
1139 //
1140 // This string's null terminator
1141 //
1142 fwrite (&Zero, sizeof (WCHAR), 1, OutFptr);
1143 } else {
1144 Error (
1145 SourceFile->FileName,
1146 SourceFile->LineNum,
1147 0,
1148 NULL,
1149 "expected valid language identifer, not %.20S",
1150 SourceFile->FileBufferPtr
1151 );
1152 goto Done;
1153 }
1154 }
1155 //
1156 // Double null terminator
1157 //
1158 fwrite (&Zero, sizeof (WCHAR), 1, OutFptr);
1159 Status = STATUS_SUCCESS;
1160 Done:
1161 return Status;
1162 }
1163
1164 static
1165 STATUS
1166 SplitCapsule (
1167 INT8 *CapsuleFileName
1168 )
1169 /*++
1170
1171 Routine Description:
1172 We've created an entire capsule image. Now split it up into the
1173 size pieces they requested.
1174
1175 Arguments:
1176 CapsuleFileName - name of an existing capsule file on disk
1177
1178 Returns:
1179 STATUS_SUCCESS - if no problems
1180
1181 Notes:
1182 This implementation reads in the entire capsule image from
1183 disk, then overwrites the original file with the first
1184 in the series.
1185
1186 --*/
1187 {
1188 #if 0
1189 EFI_CAPSULE_HEADER *CapHdr;
1190
1191 EFI_CAPSULE_HEADER Hdr;
1192 FILE *CapFptr;
1193 FILE *OutFptr;
1194 UINT32 SizeLeft;
1195 UINT32 CurrentSize;
1196 UINT32 DataSize;
1197 UINT32 SequenceNumber;
1198 INT8 *Buffer;
1199 INT8 FileName[MAX_PATH];
1200 STATUS Status;
1201 UINT32 FileSize;
1202 //
1203 // Figure out the total size, then rewind the input file and
1204 // read the entire thing in
1205 //
1206 if ((CapFptr = fopen (CapsuleFileName, "rb")) == NULL) {
1207 Error (NULL, 0, 0, CapsuleFileName, "failed to open capsule image for reading");
1208 return STATUS_ERROR;
1209 }
1210
1211 OutFptr = NULL;
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);
1219 goto FailDone;
1220 }
1221
1222 if (fread (CapHdr, SizeLeft, 1, CapFptr) != 1) {
1223 Error (NULL, 0, 0, "failed to read capsule contents", "split failed");
1224 goto FailDone;
1225 }
1226
1227 fclose (CapFptr);
1228 CapFptr = NULL;
1229 //
1230 // Get a GUID to fill in the InstanceId GUID in the header
1231 //
1232 CreateGuid (&CapHdr->InstanceId);
1233 SequenceNumber = 0;
1234 //
1235 // If the split size is larger than the original capsule image, then
1236 // we're done.
1237 //
1238 if (mOptions.SizeList->Size >= SizeLeft) {
1239 mOptions.SizeList->Size = SizeLeft;
1240 goto Done;
1241 }
1242 //
1243 // First size has to be big enough for the original header
1244 //
1245 if (mOptions.SizeList->Size < CapHdr->OffsetToCapsuleBody) {
1246 Error (NULL, 0, 0, "first split size is insufficient for the original capsule header", NULL);
1247 goto FailDone;
1248 }
1249 //
1250 // Initialize the header we'll use on all but the first part
1251 //
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;
1260 //
1261 // printf ("Created %s - 0x%X bytes\n", CapsuleFileName, mOptions.SizeList->Size);
1262 //
1263 Buffer = (UINT8 *) CapHdr;
1264 //
1265 // Walk the list of sizes and write out a capsule header, and
1266 // then the raw capsule data.
1267 //
1268 // SizeLeft -= mOptions.SizeList->Size;
1269 //
1270 mOptions.CurrentSize = mOptions.SizeList;
1271 while (SizeLeft) {
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");
1276 goto FailDone;
1277 }
1278
1279 if (Buffer == (UINT8 *) CapHdr) {
1280 //
1281 // First part -- write out original header and data
1282 //
1283 if (fwrite (Buffer, CurrentSize, 1, OutFptr) != 1) {
1284 Error (NULL, 0, 0, FileName, "failed to write to split image file");
1285 goto FailDone;
1286 }
1287
1288 SizeLeft -= CurrentSize;
1289 Buffer += CurrentSize;
1290 DataSize = CurrentSize;
1291 FileSize = CurrentSize;
1292 } else {
1293 //
1294 // Not the first part. Write the default header, and then the raw bytes from the
1295 // original image.
1296 //
1297 if (CurrentSize <= sizeof (Hdr)) {
1298 Error (NULL, 0, 0, "split size too small for capsule header + data", "0x%X", CurrentSize);
1299 goto FailDone;
1300 }
1301
1302 DataSize = CurrentSize - sizeof (Hdr);
1303 if (DataSize > SizeLeft) {
1304 DataSize = SizeLeft;
1305 }
1306
1307 if (fwrite (&Hdr, sizeof (Hdr), 1, OutFptr) != 1) {
1308 Error (NULL, 0, 0, FileName, "failed to write capsule header to output file");
1309 fclose (OutFptr);
1310 goto FailDone;
1311 }
1312
1313 if (fwrite (Buffer, DataSize, 1, OutFptr) != 1) {
1314 Error (NULL, 0, 0, FileName, "failed to write capsule data to output file");
1315 fclose (OutFptr);
1316 goto FailDone;
1317 }
1318
1319 Hdr.SequenceNumber++;
1320 Buffer += DataSize;
1321 SizeLeft -= DataSize;
1322 FileSize = DataSize + sizeof (Hdr);
1323 }
1324 //
1325 // Next size in list if there is one
1326 //
1327 if (mOptions.CurrentSize->Next != NULL) {
1328 mOptions.CurrentSize = mOptions.CurrentSize->Next;
1329 }
1330
1331 SequenceNumber++;
1332 fclose (OutFptr);
1333 OutFptr = NULL;
1334 printf ("Created %s - 0x%X bytes (0x%X bytes of data)\n", FileName, FileSize, DataSize);
1335 }
1336
1337 goto Done;
1338 FailDone:
1339 Status = STATUS_ERROR;
1340 Done:
1341 if (CapHdr != NULL) {
1342 free (CapHdr);
1343 }
1344
1345 if (CapFptr != NULL) {
1346 fclose (CapFptr);
1347 }
1348
1349 if (OutFptr != NULL) {
1350 fclose (OutFptr);
1351 }
1352
1353 return Status;
1354
1355 #endif
1356 return STATUS_SUCCESS;
1357 }
1358
1359 static
1360 BOOLEAN
1361 GetSplitFileName (
1362 INT8 *BaseFileName,
1363 INT8 *NewFileName,
1364 UINT32 SequenceNumber
1365 )
1366 /*++
1367
1368 Routine Description:
1369
1370 GC_TODO: Add function description
1371
1372 Arguments:
1373
1374 BaseFileName - GC_TODO: add argument description
1375 NewFileName - GC_TODO: add argument description
1376 SequenceNumber - GC_TODO: add argument description
1377
1378 Returns:
1379
1380 GC_TODO: add return values
1381
1382 --*/
1383 {
1384 /*++
1385
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.
1389
1390 Arguments:
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
1394
1395 Returns:
1396 TRUE - name created successfully
1397 FALSE - otherwise
1398
1399 --*/
1400 INT8 *Ptr;
1401 INT8 *Part2Start;
1402 UINT32 Digits;
1403 UINT32 Len;
1404 UINT32 BaseOffset;
1405 //
1406 // Work back from the end of the file name and see if there is a number somewhere
1407 //
1408 for (Ptr = BaseFileName + strlen (BaseFileName) - 1; (Ptr > BaseFileName) && !isdigit (*Ptr); Ptr--)
1409 ;
1410 if ((Ptr == BaseFileName) && (!isdigit (*Ptr))) {
1411 //
1412 // Found no number, so just add it to the end
1413 //
1414 sprintf (NewFileName, "%s%d", BaseFileName, SequenceNumber);
1415 return TRUE;
1416 } else {
1417 //
1418 // Found a number. Look back to find the first digit.
1419 //
1420 Part2Start = Ptr + 1;
1421 for (Digits = 1; isdigit (*Ptr) && (Ptr > BaseFileName); Ptr--, Digits++)
1422 ;
1423 if (!isdigit (*Ptr)) {
1424 Ptr++;
1425 Digits--;
1426 }
1427
1428 BaseOffset = atoi (Ptr);
1429 SequenceNumber = SequenceNumber + BaseOffset;
1430 if (Digits > 1) {
1431 //
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
1434 //
1435 Len = (UINT32) Ptr - (UINT32) BaseFileName;
1436 strncpy (NewFileName, BaseFileName, Len);
1437 sprintf (NewFileName + Len, "%0*d", Digits, SequenceNumber);
1438 strcat (NewFileName, Part2Start);
1439 return TRUE;
1440 } else {
1441 //
1442 // Only one digit found. This is the path for filenames with
1443 // format path\name1.cap
1444 //
1445 Len = (UINT32) Ptr - (UINT32) BaseFileName + 1;
1446 strncpy (NewFileName, BaseFileName, Len);
1447 sprintf (NewFileName + Len - 1, "%d", SequenceNumber);
1448 strcat (NewFileName, Part2Start);
1449 return TRUE;
1450 }
1451 }
1452 }
1453
1454 static
1455 BOOLEAN
1456 IsWhiteSpace (
1457 WCHAR Char
1458 )
1459 /*++
1460
1461 Routine Description:
1462
1463 GC_TODO: Add function description
1464
1465 Arguments:
1466
1467 Char - GC_TODO: add argument description
1468
1469 Returns:
1470
1471 GC_TODO: add return values
1472
1473 --*/
1474 {
1475 switch (Char) {
1476 case UNICODE_SPACE:
1477 case UNICODE_TAB:
1478 case UNICODE_NULL:
1479 case UNICODE_CR:
1480 case UNICODE_LF:
1481 return TRUE;
1482
1483 default:
1484 return FALSE;
1485 }
1486 }
1487
1488 static
1489 BOOLEAN
1490 IsToken (
1491 SOURCE_FILE *File,
1492 WCHAR *Token
1493 )
1494 /*++
1495
1496 Routine Description:
1497
1498 GC_TODO: Add function description
1499
1500 Arguments:
1501
1502 File - GC_TODO: add argument description
1503 Token - GC_TODO: add argument description
1504
1505 Returns:
1506
1507 GC_TODO: add return values
1508
1509 --*/
1510 {
1511 SkipWhiteSpace (File);
1512 if (EndOfFile (File)) {
1513 return FALSE;
1514 }
1515
1516 if (wcsncmp (Token, File->FileBufferPtr, wcslen (Token)) == 0) {
1517 File->FileBufferPtr += wcslen (Token);
1518 return TRUE;
1519 }
1520
1521 return FALSE;
1522 }
1523
1524 static
1525 STATUS
1526 CheckFirmwareVolumeHeader (
1527 INT8 *FileName,
1528 INT8 *Buffer,
1529 UINT32 BufferSize
1530 )
1531 /*++
1532
1533 Routine Description:
1534
1535 GC_TODO: Add function description
1536
1537 Arguments:
1538
1539 FileName - GC_TODO: add argument description
1540 Buffer - GC_TODO: add argument description
1541 BufferSize - GC_TODO: add argument description
1542
1543 Returns:
1544
1545 GC_TODO: add return values
1546
1547 --*/
1548 {
1549 EFI_FIRMWARE_VOLUME_HEADER *Hdr;
1550 EFI_GUID FVHeaderGuid = EFI_FIRMWARE_FILE_SYSTEM_GUID;
1551
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;
1556 }
1557
1558 if (Hdr->Revision != EFI_FVH_REVISION) {
1559 Error (NULL, 0, 0, FileName, "unsupported firmware volume header version");
1560 return STATUS_ERROR;
1561 }
1562
1563 if (Hdr->FvLength > BufferSize) {
1564 Error (NULL, 0, 0, FileName, "malformed firmware volume -- FvLength > file size");
1565 return STATUS_ERROR;
1566 }
1567
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;
1571 }
1572
1573 return STATUS_SUCCESS;
1574 }
1575
1576 static
1577 void
1578 DumpCapsule (
1579 VOID
1580 )
1581 /*++
1582
1583 Routine Description:
1584
1585 GC_TODO: Add function description
1586
1587 Arguments:
1588
1589 None
1590
1591 Returns:
1592
1593 GC_TODO: add return values
1594
1595 --*/
1596 {
1597 #if 0
1598 FILE *InFptr;
1599 FILE_LIST *FileList;
1600 EFI_CAPSULE_HEADER CapsuleHeader;
1601 EFI_FIRMWARE_VOLUME_HEADER FVHeader;
1602 EFI_CAPSULE_OEM_HEADER *OemHeader;
1603 UINT8 *BPtr;
1604 UINT32 FileSize;
1605 UINT32 CapsuleHeaderDataSize;
1606 UINT8 ByteCount;
1607 UINT8 *CapsuleHeaderData;
1608 BOOLEAN SplitImage;
1609
1610 InFptr = NULL;
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");
1616 goto Done;
1617 }
1618
1619 if (fread (&CapsuleHeader, sizeof (EFI_CAPSULE_HEADER), 1, InFptr) != 1) {
1620 Error (NULL, 0, 0, FileList->FileName, "failed to read capsule header");
1621 goto Done;
1622 }
1623
1624 fseek (InFptr, 0, SEEK_END);
1625 FileSize = ftell (InFptr);
1626 if (CapsuleHeader.CapsuleImageSize > FileSize) {
1627 SplitImage = TRUE;
1628 } else {
1629 SplitImage = FALSE;
1630 }
1631
1632 printf (
1633 "Capsule %s Size=0x%X CargoSize=0x%X\n",
1634 FileList->FileName,
1635 FileSize,
1636 FileSize - CapsuleHeader.OffsetToCapsuleBody
1637 );
1638 printf (
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]
1651 );
1652 if (memcmp (&CapsuleHeader.CapsuleGuid, &mEfiCapsuleHeaderGuid, sizeof (EFI_GUID)) != 0) {
1653 printf (" INVALID GUID");
1654 }
1655
1656 printf ("\n");
1657 printf (" Header size 0x%08X\n", CapsuleHeader.HeaderSize);
1658 printf (" Flags 0x%08X\n", CapsuleHeader.Flags);
1659 if (!SplitImage) {
1660 printf (" Capsule image size 0x%08X\n", CapsuleHeader.CapsuleImageSize);
1661 } else {
1662 printf (" Capsule image size 0x%08X (split)\n", CapsuleHeader.CapsuleImageSize);
1663 }
1664
1665 printf (" Sequence number %d\n", CapsuleHeader.SequenceNumber);
1666 printf (
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]
1679 );
1680 printf (" Offset to capsule 0x%X\n", CapsuleHeader.OffsetToCapsuleBody);
1681 //
1682 // Dump header data if there
1683 //
1684 CapsuleHeaderDataSize = CapsuleHeader.OffsetToCapsuleBody - CapsuleHeader.HeaderSize;
1685 if (CapsuleHeaderDataSize != 0) {
1686 CapsuleHeaderData = (UINT8 *) malloc (CapsuleHeaderDataSize);
1687 if (CapsuleHeaderData == NULL) {
1688 Error (
1689 NULL,
1690 0,
1691 0,
1692 "failed to allocate memory to read in capsule header data",
1693 "0x%X bytes",
1694 CapsuleHeaderDataSize
1695 );
1696 goto Done;
1697 }
1698
1699 fseek (InFptr, CapsuleHeader.HeaderSize, SEEK_SET);
1700 if (fread (CapsuleHeaderData, CapsuleHeaderDataSize, 1, InFptr) != 1) {
1701 Error (
1702 NULL,
1703 0,
1704 0,
1705 "failed to read capsule header data contents from file",
1706 "0x%X bytes",
1707 CapsuleHeaderDataSize
1708 );
1709 goto Done;
1710 }
1711 //
1712 // ************************************************************************
1713 //
1714 // OEM HEADER
1715 //
1716 // ************************************************************************
1717 //
1718 if (CapsuleHeader.OffsetToOemDefinedHeader != 0) {
1719 OemHeader = (EFI_CAPSULE_OEM_HEADER *) (CapsuleHeaderData + CapsuleHeader.OffsetToOemDefinedHeader - CapsuleHeader.HeaderSize);
1720 printf (" OEM Header\n");
1721 printf (
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]
1734 );
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) {
1740 printf ("\n ");
1741 }
1742
1743 printf ("%02X ", (UINT32) *BPtr);
1744 BPtr++;
1745 }
1746
1747 printf ("\n");
1748 }
1749 //
1750 // ************************************************************************
1751 //
1752 // Author, revision, short description, and long description information
1753 //
1754 // ************************************************************************
1755 //
1756 if (CapsuleHeader.OffsetToAuthorInformation != 0) {
1757 if (DumpCapsuleHeaderStrings (
1758 "Author information",
1759 (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToAuthorInformation - CapsuleHeader.HeaderSize)
1760 ) != STATUS_SUCCESS) {
1761 goto Done;
1762 }
1763 }
1764
1765 if (CapsuleHeader.OffsetToRevisionInformation != 0) {
1766 if (DumpCapsuleHeaderStrings (
1767 "Revision information",
1768 (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToRevisionInformation - CapsuleHeader.HeaderSize)
1769 ) != STATUS_SUCCESS) {
1770 goto Done;
1771 }
1772 }
1773
1774 if (CapsuleHeader.OffsetToShortDescription != 0) {
1775 if (DumpCapsuleHeaderStrings (
1776 "Short description",
1777 (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToShortDescription - CapsuleHeader.HeaderSize)
1778 ) != STATUS_SUCCESS) {
1779 goto Done;
1780 }
1781 }
1782
1783 if (CapsuleHeader.OffsetToLongDescription != 0) {
1784 if (DumpCapsuleHeaderStrings (
1785 "Long description",
1786 (WCHAR *) (CapsuleHeaderData + CapsuleHeader.OffsetToLongDescription - CapsuleHeader.HeaderSize)
1787 ) != STATUS_SUCCESS) {
1788 goto Done;
1789 }
1790 }
1791 }
1792 //
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.
1795 //
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");
1801 goto Done;
1802 }
1803
1804 printf (" FV length 0x%X", FVHeader.FvLength);
1805 if (FileSize - CapsuleHeader.OffsetToCapsuleBody != FVHeader.FvLength) {
1806 if (!SplitImage) {
1807 printf (" ERROR: expected 0x%X to jive with file size on disk", FileSize - CapsuleHeader.OffsetToCapsuleBody);
1808 }
1809 }
1810
1811 printf ("\n");
1812 printf (" Signature 0x%X ", FVHeader.Signature);
1813 if (FVHeader.Signature == EFI_FVH_SIGNATURE) {
1814 printf ("_FVH\n");
1815 } else {
1816 printf ("INVALID\n");
1817 }
1818
1819 printf (" FV header length 0x%X\n", (UINT32) FVHeader.HeaderLength);
1820 printf (" Revision 0x%X\n", (UINT32) FVHeader.Revision);
1821 printf ("\n");
1822 }
1823
1824 FileList = FileList->Next;
1825 }
1826
1827 Done:
1828 if (InFptr != NULL) {
1829 fclose (InFptr);
1830 }
1831
1832 if (CapsuleHeaderData != NULL) {
1833 free (CapsuleHeaderData);
1834 }
1835 #endif
1836 }
1837
1838 static
1839 STATUS
1840 JoinCapsule (
1841 VOID
1842 )
1843 /*++
1844
1845 Routine Description:
1846 Join split capsule images into a single image. This is the
1847 support function for the -j command-line option.
1848
1849 Arguments:
1850 None.
1851
1852 Returns:
1853 STATUS_SUCCESS - no problems encountered
1854
1855 --*/
1856 {
1857 #if 0
1858 UINT32 Size;
1859 FILE *InFptr;
1860 FILE *OutFptr;
1861 INT8 *Buffer;
1862 FILE_LIST *FileList;
1863 STATUS Status;
1864 EFI_CAPSULE_HEADER CapHdr;
1865 EFI_CAPSULE_HEADER *CapHdrPtr;
1866 UINT32 SizeLeft;
1867 UINT32 SequenceNumber;
1868 //
1869 // Must have at least two files for join mode
1870 //
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;
1874 }
1875 //
1876 // Open the output file
1877 //
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;
1881 }
1882
1883 FileList = mOptions.FileList;
1884 Buffer = NULL;
1885 SequenceNumber = 0;
1886 InFptr = NULL;
1887 SizeLeft = 0;
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");
1891 goto FailDone;
1892 }
1893 //
1894 // Allocate a buffer into which we can read the file.
1895 //
1896 fseek (InFptr, 0, SEEK_END);
1897 Size = ftell (InFptr);
1898 rewind (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");
1902 goto FailDone;
1903 }
1904
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");
1908 goto FailDone;
1909 }
1910 //
1911 // Check the header for validity. Check size first.
1912 //
1913 if (Size < sizeof (EFI_CAPSULE_HEADER)) {
1914 Error (NULL, 0, 0, FileList->FileName, "file size is insufficient for a capsule header");
1915 goto FailDone;
1916 }
1917 //
1918 // Check GUID
1919 //
1920 if (memcmp (&CapHdrPtr->CapsuleGuid, &mEfiCapsuleHeaderGuid, sizeof (EFI_GUID)) != 0) {
1921 Error (NULL, 0, 0, FileList->FileName, "invalid capsule GUID");
1922 goto FailDone;
1923 }
1924 //
1925 // Check sequence number
1926 //
1927 if (CapHdrPtr->SequenceNumber != SequenceNumber) {
1928 Error (
1929 NULL,
1930 0,
1931 0,
1932 FileList->FileName,
1933 "invalid sequence number %d (expected %d)",
1934 CapHdrPtr->SequenceNumber,
1935 SequenceNumber
1936 );
1937 goto FailDone;
1938 }
1939 //
1940 // If the first file, read save the capsule header
1941 //
1942 if (SequenceNumber == 0) {
1943 memcpy (&CapHdr, CapHdrPtr, sizeof (EFI_CAPSULE_HEADER));
1944 //
1945 // Erase the InstanceId GUID
1946 //
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");
1950 goto FailDone;
1951 }
1952
1953 if (CapHdr.CapsuleImageSize < Size) {
1954 Error (NULL, 0, 0, FileList->FileName, "capsule image size in capsule header < image size");
1955 goto FailDone;
1956 }
1957
1958 SizeLeft = CapHdr.CapsuleImageSize - Size;
1959 } else {
1960 //
1961 // Check the GUID against the first file's GUID
1962 //
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");
1965 goto FailDone;
1966 }
1967 //
1968 // Make sure we're not throwing out any header info
1969 //
1970 if (CapHdrPtr->OffsetToCapsuleBody > sizeof (EFI_CAPSULE_HEADER)) {
1971 //
1972 // Could be the split information, so just emit a warning
1973 //
1974 Warning (
1975 NULL,
1976 0,
1977 0,
1978 FileList->FileName,
1979 "image appears to have additional capsule header information -- ignoring"
1980 );
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");
1983 goto FailDone;
1984 }
1985
1986 if (fwrite (Buffer + CapHdrPtr->OffsetToCapsuleBody, Size - CapHdrPtr->OffsetToCapsuleBody, 1, OutFptr) != 1) {
1987 Error (NULL, 0, 0, mOptions.OutputFileName, "failed to write to file");
1988 goto FailDone;
1989 }
1990
1991 if (SizeLeft < (Size - CapHdrPtr->OffsetToCapsuleBody)) {
1992 Error (NULL, 0, 0, "sum of image sizes exceeds size specified in initial capsule header", NULL);
1993 goto FailDone;
1994 }
1995 //
1996 // printf ("FILE: %s OffsetToCapsuleBody=0x%X\n", FileList->FileName, CapHdrPtr->OffsetToCapsuleBody);
1997 //
1998 SizeLeft = SizeLeft - (Size - CapHdrPtr->OffsetToCapsuleBody);
1999 }
2000 //
2001 // printf ("FILE: %s sizeleft=0x%X\n", FileList->FileName, SizeLeft);
2002 //
2003 fclose (InFptr);
2004 InFptr = NULL;
2005 free (Buffer);
2006 Buffer = NULL;
2007 FileList = FileList->Next;
2008 SequenceNumber++;
2009 }
2010
2011 if (SizeLeft) {
2012 Error (NULL, 0, 0, "sum of capsule images is insufficient", "0x%X bytes missing", SizeLeft);
2013 goto FailDone;
2014 }
2015
2016 Status = STATUS_SUCCESS;
2017 goto Done;
2018 FailDone:
2019 Status = STATUS_ERROR;
2020 Done:
2021 if (InFptr != NULL) {
2022 fclose (InFptr);
2023 }
2024
2025 if (OutFptr != NULL) {
2026 fclose (OutFptr);
2027 }
2028
2029 if (Buffer != NULL) {
2030 free (Buffer);
2031 }
2032
2033 return Status;
2034
2035 #endif
2036 return STATUS_SUCCESS;
2037 }
2038
2039 static
2040 STATUS
2041 DumpCapsuleHeaderStrings (
2042 UINT8 *SectionName,
2043 WCHAR *Buffer
2044 )
2045 /*++
2046
2047 Routine Description:
2048 Given a pointer to string data from a capsule header, dump
2049 the strings.
2050
2051 Arguments:
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
2055
2056 Returns:
2057 STATUS_SUCCESS - all went well
2058
2059 --*/
2060 {
2061 printf (" %s\n", SectionName);
2062 while (*Buffer) {
2063 printf (" Language: %S\n", Buffer);
2064 while (*Buffer) {
2065 Buffer++;
2066 }
2067
2068 Buffer++;
2069 while (*Buffer) {
2070 if (wcslen (Buffer) > 60) {
2071 printf (" %.60S\n", Buffer);
2072 Buffer += 60;
2073 } else {
2074 printf (" %S\n", Buffer);
2075 Buffer += wcslen (Buffer);
2076 }
2077 }
2078
2079 Buffer++;
2080 }
2081
2082 return STATUS_SUCCESS;
2083 }
2084
2085 static
2086 STATUS
2087 GetHexValue (
2088 SOURCE_FILE *SourceFile,
2089 UINT32 *Value,
2090 UINT32 NumDigits
2091 )
2092 /*++
2093
2094 Routine Description:
2095 Scan a hex value from the input stream.
2096
2097 Arguments:
2098 SourceFile - input file contents
2099 Value - returned value
2100 NumDigits - number of digits to read
2101
2102 Returns:
2103 STATUS_SUCCESS - if NumDigits were read from the file
2104 STATUS_ERROR - otherwise
2105
2106
2107 --*/
2108 {
2109 WCHAR *SaveFilePos;
2110 UINT32 Digits;
2111 WCHAR Nibble;
2112
2113 SaveFilePos = SourceFile->FileBufferPtr;
2114 *Value = 0;
2115 Digits = NumDigits;
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);
2124 } else {
2125 Error (
2126 SourceFile->FileName,
2127 SourceFile->LineNum,
2128 0,
2129 NULL,
2130 "expected %d valid hex nibbles at %.20S",
2131 NumDigits,
2132 SaveFilePos
2133 );
2134 return STATUS_ERROR;
2135 }
2136
2137 SourceFile->FileBufferPtr++;
2138 Digits--;
2139 }
2140
2141 return STATUS_SUCCESS;
2142 }
2143
2144 static
2145 BOOLEAN
2146 EndOfFile (
2147 SOURCE_FILE *File
2148 )
2149 /*++
2150
2151 Routine Description:
2152
2153 GC_TODO: Add function description
2154
2155 Arguments:
2156
2157 File - GC_TODO: add argument description
2158
2159 Returns:
2160
2161 GC_TODO: add return values
2162
2163 --*/
2164 {
2165 if ((UINT32) File->FileBufferPtr - (UINT32) File->FileBuffer >= File->FileSize) {
2166 File->EndOfFile = TRUE;
2167 }
2168 //
2169 // Reposition to the end of the file if we went beyond
2170 //
2171 if (File->EndOfFile) {
2172 File->FileBufferPtr = File->FileBuffer + File->FileSize / sizeof (WCHAR);
2173 }
2174
2175 return File->EndOfFile;
2176 }
2177
2178 static
2179 void
2180 SkipWhiteSpace (
2181 SOURCE_FILE *SourceFile
2182 )
2183 /*++
2184
2185 Routine Description:
2186
2187 GC_TODO: Add function description
2188
2189 Arguments:
2190
2191 SourceFile - GC_TODO: add argument description
2192
2193 Returns:
2194
2195 GC_TODO: add return values
2196
2197 --*/
2198 {
2199 while (!EndOfFile (SourceFile)) {
2200 switch (*SourceFile->FileBufferPtr) {
2201 case UNICODE_NULL:
2202 case UNICODE_CR:
2203 case UNICODE_SPACE:
2204 case UNICODE_TAB:
2205 SourceFile->FileBufferPtr++;
2206 break;
2207
2208 case UNICODE_LF:
2209 SourceFile->FileBufferPtr++;
2210 SourceFile->LineNum++;
2211 break;
2212
2213 default:
2214 return ;
2215 }
2216 }
2217 }
2218 //
2219 // Parse a number. Possible format:
2220 // 1234
2221 // 1234k
2222 // 1234K
2223 // 1M
2224 // 1m
2225 // 0x100
2226 //
2227 static
2228 BOOLEAN
2229 GetNumber (
2230 INT8 *Str,
2231 UINT32 *Value
2232 )
2233 /*++
2234
2235 Routine Description:
2236
2237 GC_TODO: Add function description
2238
2239 Arguments:
2240
2241 Str - GC_TODO: add argument description
2242 Value - GC_TODO: add argument description
2243
2244 Returns:
2245
2246 GC_TODO: add return values
2247
2248 --*/
2249 {
2250 UINT32 LValue;
2251
2252 *Value = 0;
2253 LValue = 0;
2254 if (!isdigit (Str[0])) {
2255 return FALSE;
2256 }
2257 //
2258 // Look for hex number
2259 //
2260 if ((Str[0] == '0') && (tolower (Str[1]) == 'x')) {
2261 Str += 2;
2262 if (Str[0] == 0) {
2263 return FALSE;
2264 }
2265
2266 while (Str[0]) {
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);
2273 } else {
2274 break;
2275 }
2276
2277 Str++;
2278 }
2279 } else {
2280 LValue = atoi (Str);
2281 while (isdigit (*Str)) {
2282 Str++;
2283 }
2284 }
2285 //
2286 // If string left over, better be one character we recognize
2287 //
2288 if (Str[0]) {
2289 if (Str[1]) {
2290 return FALSE;
2291 }
2292
2293 switch (Str[0]) {
2294 case 'k':
2295 case 'K':
2296 LValue *= 1024;
2297 break;
2298
2299 case 'm':
2300 case 'M':
2301 LValue *= 1024 * 1024;
2302 break;
2303
2304 default:
2305 return FALSE;
2306 }
2307 }
2308
2309 *Value = LValue;
2310 return TRUE;
2311 }
2312 //
2313 // Process the command-line arguments
2314 //
2315 static
2316 STATUS
2317 ProcessArgs (
2318 int Argc,
2319 char *Argv[]
2320 )
2321 /*++
2322
2323 Routine Description:
2324
2325 Processes command line arguments.
2326
2327 Arguments:
2328
2329 Argc - Number of command line arguments
2330 Argv[] - Array of files input on command line
2331
2332 Returns:
2333
2334 STATUS_ERROR - Function exited with an error
2335 STATUS_SUCCESS - Function executed successfully
2336
2337 --*/
2338 {
2339 FILE_LIST *NewFile;
2340
2341 FILE_LIST *LastFile;
2342 SIZE_LIST *NewSize;
2343
2344 NewFile = NULL;
2345 NewSize = NULL;
2346
2347 //
2348 // Clear our globals
2349 //
2350 memset ((char *) &mOptions, 0, sizeof (mOptions));
2351
2352 //
2353 // Skip program name
2354 //
2355 Argc--;
2356 Argv++;
2357
2358 if (Argc == 0) {
2359 Usage ();
2360 return STATUS_ERROR;
2361 }
2362 //
2363 // Process until no more options
2364 //
2365 while ((Argc > 0) && (Argv[0][0] == '-')) {
2366 if (stricmp (Argv[0], "-script") == 0) {
2367 //
2368 // Check for one more arg
2369 //
2370 if (Argc > 1) {
2371 //
2372 // Save the file name
2373 //
2374 if (strlen (Argv[1]) >= sizeof (mOptions.ScriptFileName)) {
2375 Error (NULL, 0, 0, NULL, "input script file name length exceeds internal buffer size");
2376
2377 if (NewFile != NULL) {
2378 free (NewFile);
2379 }
2380 if (NewSize != NULL) {
2381 free (NewSize);
2382 }
2383
2384 return STATUS_ERROR;
2385 }
2386
2387 strcpy (mOptions.ScriptFileName, Argv[1]);
2388 } else {
2389 Error (NULL, 0, 0, Argv[0], "missing script file name with option");
2390 Usage ();
2391
2392 if (NewFile != NULL) {
2393 free (NewFile);
2394 }
2395 if (NewSize != NULL) {
2396 free (NewSize);
2397 }
2398
2399 return STATUS_ERROR;
2400 }
2401
2402 Argc--;
2403 Argv++;
2404 //
2405 // -o outfilename -- specify output file name (required)
2406 //
2407 } else if (stricmp (Argv[0], "-o") == 0) {
2408 //
2409 // check for one more arg
2410 //
2411 if (Argc > 1) {
2412 //
2413 // Try to open the file
2414 //
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;
2418 // }
2419 //
2420 strcpy (mOptions.OutputFileName, Argv[1]);
2421 } else {
2422 Error (NULL, 0, 0, Argv[0], "missing output filename with option");
2423 Usage ();
2424
2425 if (NewFile != NULL) {
2426 free (NewFile);
2427 }
2428 if (NewSize != NULL) {
2429 free (NewSize);
2430 }
2431
2432 return STATUS_ERROR;
2433 }
2434
2435 Argc--;
2436 Argv++;
2437 } else if (stricmp (Argv[0], "-j") == 0) {
2438 mOptions.JoinMode = TRUE;
2439 //
2440 // -split <size> option (multiple allowed)
2441 //
2442 } else if (stricmp (Argv[0], "-split") == 0) {
2443 if (Argc > 1) {
2444 NewSize = (SIZE_LIST *) malloc (sizeof (SIZE_LIST));
2445 if (NewSize == NULL) {
2446 Error (NULL, 0, 0, "memory allocation failure", NULL);
2447
2448 if (NewFile != NULL) {
2449 free (NewFile);
2450 }
2451 if (NewSize != NULL) {
2452 free (NewSize);
2453 }
2454
2455 return STATUS_ERROR;
2456 }
2457
2458 memset (NewSize, 0, sizeof (SIZE_LIST));
2459 //
2460 // Get the size from the next arg, and then add this size
2461 // to our size list
2462 //
2463 if (!GetNumber (Argv[1], &NewSize->Size)) {
2464 Error (NULL, 0, 0, Argv[1], "invalid split size argument");
2465
2466 if (NewFile != NULL) {
2467 free (NewFile);
2468 }
2469 if (NewSize != NULL) {
2470 free (NewSize);
2471 }
2472
2473 return STATUS_ERROR;
2474 }
2475
2476 if (mOptions.SizeList == NULL) {
2477 mOptions.SizeList = NewSize;
2478 mOptions.CurrentSize = NewSize;
2479 } else {
2480 mOptions.LastSize->Next = NewSize;
2481 }
2482
2483 mOptions.LastSize = NewSize;
2484 free (NewSize);
2485 } else {
2486 Error (NULL, 0, 0, Argv[0], "missing size parameter with option");
2487 Usage ();
2488
2489 if (NewFile != NULL) {
2490 free (NewFile);
2491 }
2492 if (NewSize != NULL) {
2493 free (NewSize);
2494 }
2495
2496 return STATUS_ERROR;
2497 }
2498
2499 Argc--;
2500 Argv++;
2501 } else if ((stricmp (Argv[0], "-h") == 0) || (strcmp (Argv[0], "-?") == 0)) {
2502 Usage ();
2503
2504 if (NewFile != NULL) {
2505 free (NewFile);
2506 }
2507 if (NewSize != NULL) {
2508 free (NewSize);
2509 }
2510
2511 return STATUS_ERROR;
2512 //
2513 // Default minimum header
2514 //
2515 } else if (stricmp (Argv[0], "-dump") == 0) {
2516 mOptions.Dump = TRUE;
2517 } else if (stricmp (Argv[0], "-v") == 0) {
2518 mOptions.Verbose = TRUE;
2519 } else {
2520 Error (NULL, 0, 0, Argv[0], "unrecognized option");
2521 Usage ();
2522
2523 if (NewFile != NULL) {
2524 free (NewFile);
2525 }
2526 if (NewSize != NULL) {
2527 free (NewSize);
2528 }
2529
2530 return STATUS_ERROR;
2531 }
2532
2533 Argc--;
2534 Argv++;
2535 }
2536 //
2537 // Can't -j join files and -s split output capsule
2538 //
2539 if ((mOptions.SizeList != NULL) && (mOptions.JoinMode)) {
2540 Error (NULL, 0, 0, "cannot specify both -j and -size", NULL);
2541
2542 if (NewFile != NULL) {
2543 free (NewFile);
2544 }
2545 if (NewSize != NULL) {
2546 free (NewSize);
2547 }
2548
2549 return STATUS_ERROR;
2550 }
2551 //
2552 // Must have specified an output file name if not -dump
2553 //
2554 if ((mOptions.Dump == 0) && (mOptions.OutputFileName[0] == 0)) {
2555 Error (NULL, 0, 0, NULL, "-o OutputFileName must be specified");
2556 Usage ();
2557
2558 if (NewFile != NULL) {
2559 free (NewFile);
2560 }
2561 if (NewSize != NULL) {
2562 free (NewSize);
2563 }
2564
2565 return STATUS_ERROR;
2566 }
2567 //
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.
2571 //
2572 LastFile = NULL;
2573 while (Argc > 0) {
2574 NewFile = (FILE_LIST *) malloc (sizeof (FILE_LIST));
2575 if (NewFile == NULL) {
2576 Error (NULL, 0, 0, "memory allocation failure", NULL);
2577
2578 if (NewFile != NULL) {
2579 free (NewFile);
2580 }
2581 if (NewSize != NULL) {
2582 free (NewSize);
2583 }
2584
2585 return STATUS_ERROR;
2586 }
2587
2588 memset ((char *) NewFile, 0, sizeof (FILE_LIST));
2589 strcpy (NewFile->FileName, Argv[0]);
2590 if (mOptions.FileList == NULL) {
2591 mOptions.FileList = NewFile;
2592 } else {
2593 if (LastFile == NULL) {
2594 LastFile = NewFile;
2595 } else {
2596 LastFile->Next = NewFile;
2597 }
2598 }
2599
2600 LastFile = NewFile;
2601 Argc--;
2602 Argv++;
2603 }
2604
2605 //
2606 // Must have provided at least one file name
2607 //
2608 if (mOptions.FileList == NULL) {
2609 Error (NULL, 0, 0, "must specify at least one file name", NULL);
2610 Usage ();
2611
2612 if (NewFile != NULL) {
2613 free (NewFile);
2614 }
2615 if (NewSize != NULL) {
2616 free (NewSize);
2617 }
2618
2619 return STATUS_ERROR;
2620 }
2621
2622 return STATUS_SUCCESS;
2623 }
2624
2625 static
2626 void
2627 Usage (
2628 VOID
2629 )
2630 /*++
2631
2632 Routine Description:
2633
2634 Print usage information for this utility.
2635
2636 Arguments:
2637
2638 None.
2639
2640 Returns:
2641
2642 Nothing.
2643
2644 --*/
2645 {
2646 int Index;
2647 static const char *Str[] = {
2648 PROGRAM_NAME " -- create a capsule header",
2649 " Usage: "PROGRAM_NAME " {options} [CapsuleFV]",
2650 //
2651 // {FfsFileNames}",
2652 //
2653 " Options include:",
2654 " -h or -? for this help information",
2655 " -script fname to take capsule header info from unicode script",
2656 " file fname",
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",
2662 "",
2663 " CapsuleFV is the name of an existing well-formed Tiano firmware",
2664 " volume file.",
2665 //
2666 // FfsFileNames are the names of one or more Tiano FFS files to",
2667 // " insert into the output capsule image.",
2668 //
2669 NULL
2670 };
2671 for (Index = 0; Str[Index] != NULL; Index++) {
2672 fprintf (stdout, "%s\n", Str[Index]);
2673 }
2674 }