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