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