]> git.proxmox.com Git - mirror_edk2.git/blob - Tools/CCode/Source/GenFfsFile/GenFfsFile.c
remove unnecessary check for NULL pointer.
[mirror_edk2.git] / Tools / CCode / Source / GenFfsFile / GenFfsFile.c
1 /*++
2
3 Copyright (c) 2004-2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this 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 Module Name:
13
14 GenFfsFile.c
15
16 Abstract:
17
18 This file contains functions required to generate a Firmware File System
19 file.
20
21 --*/
22
23 #include <stdio.h>
24 #include <ctype.h> // for isalpha()
25 //
26 // include file for _spawnv
27 //
28 #ifndef __GNUC__
29 #include <process.h>
30 #endif
31 #include <stdlib.h>
32 #include <string.h>
33
34 #include <Common/UefiBaseTypes.h>
35 #include <Common/FirmwareVolumeImageFormat.h>
36 #include <Common/FirmwareFileSystem.h>
37 #include <Common/FirmwareVolumeHeader.h>
38 #include <Common/FirmwareVolumeImageFormat.h>
39
40 #include "ParseInf.h"
41 #include "Compress.h"
42 #include "EfiCustomizedCompress.h"
43 #include "Crc32.h"
44 #include "GenFfsFile.h"
45 #include "CommonLib.h"
46 #include "EfiUtilityMsgs.h"
47 #include "SimpleFileParsing.h"
48
49 #define UTILITY_NAME "GenFfsFile"
50 #define UTILITY_MAJOR_VERSION 0
51 #define UTILITY_MINOR_VERSION 32
52
53 #define MAX_ARRAY_SIZE 100
54
55 static
56 INT32
57 GetNextLine (
58 OUT CHAR8 *Destination,
59 IN FILE *Package,
60 IN OUT UINT32 *LineNumber
61 );
62
63 static
64 void
65 CheckSlash (
66 IN OUT CHAR8 *String,
67 IN FILE *In,
68 IN OUT UINT32 *LineNumber
69 );
70
71 static
72 INT32
73 FindSectionInPackage (
74 IN CHAR8 *BuildDirectory,
75 IN FILE *OverridePackage,
76 IN OUT UINT32 *LineNumber
77 );
78
79 static
80 STATUS
81 ProcessCommandLineArgs (
82 int Argc,
83 char *Argv[]
84 );
85
86 static
87 void
88 Version (
89 void
90 );
91
92 static
93 void
94 Usage (
95 void
96 );
97
98 //
99 // Keep globals in this structure
100 //
101 static struct {
102 UINT8 BuildDirectory[_MAX_PATH];
103 UINT8 PrimaryPackagePath[_MAX_PATH];
104 UINT8 OverridePackagePath[_MAX_PATH];
105 BOOLEAN Verbose;
106 } mGlobals;
107
108 static EFI_GUID mZeroGuid = { 0 };
109
110 static
111 void
112 StripQuotes (
113 IN OUT CHAR8 *String
114 )
115 /*++
116
117 Routine Description:
118
119 Removes quotes and/or whitespace from around a string
120
121 Arguments:
122
123 String - String to remove quotes from
124
125 Returns:
126
127 None
128
129 --*/
130 {
131 UINTN Index;
132 UINTN Index2;
133 UINTN StrLen;
134
135 Index2 = strspn (String, "\" \t\n");
136 StrLen = strlen (String);
137
138 for (Index = Index2; String[Index] != '\"', Index < StrLen; Index++) {
139 String[Index - Index2] = String[Index];
140 }
141
142 String[Index - Index2] = 0;
143 }
144
145 static
146 void
147 Version(
148 void
149 )
150 /*++
151
152 Routine Description:
153
154 Print out version information for this utility.
155
156 Arguments:
157
158 None
159
160 Returns:
161
162 None
163
164 --*/
165 {
166 printf ("%s v%d.%d -EDK utility to generate a Firmware File System files.\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);
167 printf ("Copyright (c) 1999-2007 Intel Corporation. All rights reserved.\n");
168 }
169
170 static
171 void
172 Usage (
173 void
174 )
175 /*++
176
177 Routine Description:
178
179 Print Error / Help message.
180
181 Arguments:
182
183 void
184
185 Returns:
186
187 None
188
189 --*/
190 {
191 Version();
192
193 printf ("\nUsage:\n");
194 printf (UTILITY_NAME " -b \"build directory\" -p1 \"package1.inf\" -p2 \"package2.inf\" -v\n");
195 printf (" -b \"build directory\":\n ");
196 printf (" specifies the full path to the component build directory.\n");
197 printf (" -p1 \"P1_path\":\n");
198 printf (" specifies fully qualified file name to the primary package file.\n");
199 printf (" This file will normally exist in the same directory as the makefile\n");
200 printf (" for the component. Required.\n");
201 printf (" -p2 \"P2_path\":\n");
202 printf (" specifies fully qualified file name to the override package file.\n");
203 printf (" This file will normally exist in the build tip. Optional.\n");
204 }
205
206 static
207 INT32
208 TestComment (
209 IN CHAR8 *String,
210 IN FILE *In
211 )
212 /*++
213
214 Routine Description:
215
216 Tests input string to see if it is a comment, and if so goes to the next line in the file that is not a comment
217
218 Arguments:
219
220 String - String to test
221
222 In - Open file to move pointer within
223
224 Returns:
225
226 -1 - End of file reached
227 0 - Not a comment
228 1 - Comment bypassed
229
230 --*/
231 {
232 CHAR8 CharBuffer;
233
234 CharBuffer = 0;
235 if ((String[0] == '/') && (String[1] == '/')) {
236 while (CharBuffer != '\n') {
237 fscanf (In, "%c", &CharBuffer);
238 if (feof (In)) {
239 return -1;
240 }
241 }
242 } else {
243 return 0;
244 }
245
246 return 1;
247 }
248
249 static
250 void
251 BreakString (
252 IN CONST CHAR8 *Source,
253 OUT CHAR8 *Destination,
254 IN INTN Direction
255 )
256 /*++
257
258 Routine Description:
259
260 Takes an input string and returns either the part before the =, or the part after the =, depending on direction
261
262 Arguments:
263
264 Source - String to break
265
266 Destination - Buffer to place new string in
267
268 Direction - 0 to return all of source string before =
269 1 to return all of source string after =
270
271 Returns:
272
273 None
274
275 --*/
276 {
277 UINTN Index;
278 UINTN Index2;
279
280 Index = 0;
281 Index2 = 0;
282
283 if (strchr (Source, '=') == NULL) {
284 strcpy (Destination, Source);
285
286 return ;
287 }
288
289 if (Direction == 0) {
290 //
291 // return part of string before =
292 //
293 while (Source[Index] != '=') {
294 Destination[Index] = Source[Index++];
295 }
296
297 Destination[Index] = 0;
298 } else {
299 //
300 // return part of string after =
301 //
302 strcpy (Destination, strchr (Source, '=') + 1);
303 }
304 }
305
306 static
307 INT32
308 GetNextLine (
309 OUT CHAR8 *Destination,
310 IN FILE *Package,
311 IN OUT UINT32 *LineNumber
312 )
313 /*++
314
315 Routine Description:
316
317 Gets the next non-commented line from the file
318
319 Arguments:
320
321 Destination - Where to put string
322
323 Package - Package to get string from
324
325 LineNumber - The actual line number.
326
327 Returns:
328
329 -1 - End of file reached
330 0 - Success
331
332 --*/
333 {
334 CHAR8 String[_MAX_PATH];
335 fscanf (Package, "%s", &String);
336 if (feof (Package)) {
337 return -1;
338 }
339
340 while (TestComment (String, Package) == 1) {
341 fscanf (Package, "%s", &String);
342 if (feof (Package)) {
343 return -1;
344 }
345 }
346
347 strcpy (Destination, String);
348 return 0;
349 }
350
351 static
352 VOID
353 CheckSlash (
354 IN OUT CHAR8 *String,
355 IN FILE *In,
356 IN OUT UINT32 *LineNumber
357 )
358 /*++
359
360 Routine Description:
361
362 Checks to see if string is line continuation character, if so goes to next valid line
363
364 Arguments:
365
366 String - String to test
367
368 In - Open file to move pointer within
369
370 LineNumber - The line number.
371
372 Returns:
373
374 None
375
376 --*/
377 {
378 CHAR8 ByteBuffer;
379 ByteBuffer = 0;
380
381 switch (String[0]) {
382
383 case '\\':
384 while (String[0] == '\\') {
385 while (ByteBuffer != '\n') {
386 fscanf (In, "%c", &ByteBuffer);
387 }
388 (*LineNumber)++;
389 if (GetNextLine (String, In, LineNumber) == -1) {
390 return ;
391 }
392 }
393 break;
394
395 case '\n':
396 (*LineNumber)++;
397 while (String[0] == '\n') {
398 if (GetNextLine (String, In, LineNumber) == -1) {
399 return ;
400 }
401 }
402 break;
403
404 default:
405 break;
406
407 }
408
409 }
410
411 static
412 INT32
413 FindSectionInPackage (
414 IN CHAR8 *BuildDirectory,
415 IN FILE *OverridePackage,
416 IN OUT UINT32 *LineNumber
417 )
418 /*++
419
420 Routine Description:
421
422 Finds the matching section within the package
423
424 Arguments:
425
426 BuildDirectory - name of section to find
427
428 OverridePackage - Package file to search within
429
430 LineNumber - The line number.
431
432 Returns:
433
434 -1 - End of file reached
435 0 - Success
436
437 --*/
438 {
439 CHAR8 String[_MAX_PATH];
440 CHAR8 NewString[_MAX_PATH];
441 String[0] = 0;
442
443 while (strcmp (BuildDirectory, String) != 0) {
444 if (GetNextLine (NewString, OverridePackage, LineNumber) != 0) {
445 return -1;
446 }
447
448 if (NewString[0] == '[') {
449 if (NewString[strlen (NewString) - 1] != ']') {
450 //
451 // have to construct string.
452 //
453 strcpy (String, NewString + 1);
454
455 while (1) {
456 fscanf (OverridePackage, "%s", &NewString);
457 if (feof (OverridePackage)) {
458 return -1;
459 }
460
461 if (NewString[0] != ']') {
462 if (strlen (String) != 0) {
463 strcat (String, " ");
464 }
465
466 strcat (String, NewString);
467 if (String[strlen (String) - 1] == ']') {
468 String[strlen (String) - 1] = 0;
469 break;
470 }
471 } else {
472 break;
473 }
474 }
475 } else {
476 NewString[strlen (NewString) - 1] = 0;
477 strcpy (String, NewString + 1);
478 }
479 }
480 }
481
482 return 0;
483 }
484
485 static
486 EFI_STATUS
487 GenSimpleGuidSection (
488 IN OUT UINT8 *FileBuffer,
489 IN OUT UINT32 *BufferSize,
490 IN UINT32 DataSize,
491 IN EFI_GUID SignGuid,
492 IN UINT16 GuidedSectionAttributes
493 )
494 /*++
495
496 Routine Description:
497
498 add GUIDed section header for the data buffer.
499 data stays in same location (overwrites source data).
500
501 Arguments:
502
503 FileBuffer - Buffer containing data to sign
504
505 BufferSize - On input, the size of FileBuffer. On output, the size of
506 actual section data (including added section header).
507
508 DataSize - Length of data to Sign
509
510 SignGuid - Guid to be add.
511
512 GuidedSectionAttributes - The section attribute.
513
514 Returns:
515
516 EFI_SUCCESS - Successful
517 EFI_OUT_OF_RESOURCES - Not enough resource.
518
519 --*/
520 {
521 UINT32 TotalSize;
522
523 EFI_GUID_DEFINED_SECTION GuidSectionHeader;
524 UINT8 *SwapBuffer;
525
526 SwapBuffer = NULL;
527
528 if (DataSize == 0) {
529 *BufferSize = 0;
530
531 return EFI_SUCCESS;
532 }
533
534 TotalSize = DataSize + sizeof (EFI_GUID_DEFINED_SECTION);
535 GuidSectionHeader.CommonHeader.Type = EFI_SECTION_GUID_DEFINED;
536 GuidSectionHeader.CommonHeader.Size[0] = (UINT8) (TotalSize & 0xff);
537 GuidSectionHeader.CommonHeader.Size[1] = (UINT8) ((TotalSize & 0xff00) >> 8);
538 GuidSectionHeader.CommonHeader.Size[2] = (UINT8) ((TotalSize & 0xff0000) >> 16);
539 memcpy (&(GuidSectionHeader.SectionDefinitionGuid), &SignGuid, sizeof (EFI_GUID));
540 GuidSectionHeader.Attributes = GuidedSectionAttributes;
541 GuidSectionHeader.DataOffset = sizeof (EFI_GUID_DEFINED_SECTION);
542
543 SwapBuffer = (UINT8 *) malloc (DataSize);
544 if (SwapBuffer == NULL) {
545 return EFI_OUT_OF_RESOURCES;
546 }
547
548 memcpy (SwapBuffer, FileBuffer, DataSize);
549 memcpy (FileBuffer, &GuidSectionHeader, sizeof (EFI_GUID_DEFINED_SECTION));
550 memcpy (FileBuffer + sizeof (EFI_GUID_DEFINED_SECTION), SwapBuffer, DataSize);
551
552 //
553 // Make sure section ends on a DWORD boundary
554 //
555 while ((TotalSize & 0x03) != 0) {
556 FileBuffer[TotalSize] = 0;
557 TotalSize++;
558 }
559
560 *BufferSize = TotalSize;
561
562 if (SwapBuffer != NULL) {
563 free (SwapBuffer);
564 }
565
566 return EFI_SUCCESS;
567 }
568
569 static
570 EFI_STATUS
571 CompressSection (
572 UINT8 *FileBuffer,
573 UINT32 *BufferSize,
574 UINT32 DataSize,
575 CHAR8 *Type
576 )
577 /*++
578
579 Routine Description:
580
581 Compress the data and add section header for the compressed data.
582 Compressed data (with section header) stays in same location as the source
583 (overwrites source data).
584
585 Arguments:
586
587 FileBuffer - Buffer containing data to Compress
588
589 BufferSize - On input, the size of FileBuffer. On output, the size of
590 actual compressed data (including added section header).
591 When buffer is too small, this value indicates the size needed.
592
593 DataSize - The size of data to compress
594
595 Type - The compression type (not used currently).
596 Assume EFI_HEAVY_COMPRESSION.
597
598 Returns:
599
600 EFI_BUFFER_TOO_SMALL - Buffer size is too small.
601 EFI_UNSUPPORTED - Compress type can not be supported.
602 EFI_SUCCESS - Successful
603 EFI_OUT_OF_RESOURCES - Not enough resource.
604
605 --*/
606 {
607 EFI_STATUS Status;
608 UINT8 *CompData;
609 UINT32 CompSize;
610 UINT32 TotalSize;
611 EFI_COMPRESSION_SECTION CompressionSet;
612 UINT8 CompressionType;
613 COMPRESS_FUNCTION CompressFunction;
614
615 Status = EFI_SUCCESS;
616 CompData = NULL;
617 CompSize = 0;
618 TotalSize = 0;
619 CompressFunction = NULL;
620
621 //
622 // Get the compress type
623 //
624 if (strcmpi (Type, "Dummy") == 0) {
625 //
626 // Added "Dummy" to keep backward compatibility.
627 //
628 CompressionType = EFI_STANDARD_COMPRESSION;
629 CompressFunction = (COMPRESS_FUNCTION) EfiCompress;
630
631 } else if (strcmpi (Type, "LZH") == 0) {
632 //
633 // EFI stardard compression (LZH)
634 //
635 CompressionType = EFI_STANDARD_COMPRESSION;
636 CompressFunction = (COMPRESS_FUNCTION) EfiCompress;
637
638 } else {
639 //
640 // Customized compression
641 //
642 Status = SetCustomizedCompressionType (Type);
643 if (EFI_ERROR (Status)) {
644 return Status;
645 }
646
647 CompressionType = EFI_CUSTOMIZED_COMPRESSION;
648 CompressFunction = (COMPRESS_FUNCTION) CustomizedCompress;
649 }
650 //
651 // Compress the raw data
652 //
653 Status = CompressFunction (FileBuffer, DataSize, CompData, &CompSize);
654 if (Status == EFI_BUFFER_TOO_SMALL) {
655 CompData = malloc (CompSize);
656 if (!CompData) {
657 return EFI_OUT_OF_RESOURCES;
658 }
659
660 Status = CompressFunction (FileBuffer, DataSize, CompData, &CompSize);
661 }
662
663 if (EFI_ERROR (Status)) {
664 if (CompData != NULL) {
665 free (CompData);
666 }
667
668 return Status;
669 }
670
671 TotalSize = CompSize + sizeof (EFI_COMPRESSION_SECTION);
672
673 //
674 // Buffer too small?
675 //
676 if (TotalSize > *BufferSize) {
677 *BufferSize = TotalSize;
678 if (CompData != NULL) {
679 free (CompData);
680 }
681
682 return EFI_BUFFER_TOO_SMALL;
683 }
684 //
685 // Add the section header for the compressed data
686 //
687 CompressionSet.CommonHeader.Type = EFI_SECTION_COMPRESSION;
688 CompressionSet.CommonHeader.Size[0] = (UINT8) (TotalSize & 0xff);
689 CompressionSet.CommonHeader.Size[1] = (UINT8) ((TotalSize & 0xff00) >> 8);
690 CompressionSet.CommonHeader.Size[2] = (UINT8) ((TotalSize & 0xff0000) >> 16);
691 CompressionSet.CompressionType = CompressionType;
692 CompressionSet.UncompressedLength = DataSize;
693
694 //
695 // Copy header and data to the buffer
696 //
697 memcpy (FileBuffer, &CompressionSet, sizeof (EFI_COMPRESSION_SECTION));
698 memcpy (FileBuffer + sizeof (CompressionSet), CompData, CompSize);
699
700 //
701 // Make sure section ends on a DWORD boundary
702 //
703 while ((TotalSize & 0x03) != 0) {
704 FileBuffer[TotalSize] = 0;
705 TotalSize++;
706 }
707
708 *BufferSize = TotalSize;
709
710 if (CompData != NULL) {
711 free (CompData);
712 }
713
714 return EFI_SUCCESS;
715 }
716
717 static
718 void
719 StripParens (
720 IN OUT CHAR8 *String
721 )
722 /*++
723
724 Routine Description:
725
726 Removes Parenthesis from around a string
727
728 Arguments:
729
730 String - String to remove parens from
731
732 Returns:
733
734 None
735
736 --*/
737 {
738 INT32 Index;
739
740 if (String[0] != '(') {
741 return ;
742 }
743
744 for (Index = 1; String[Index] != ')'; Index++) {
745 String[Index - 1] = String[Index];
746 if (String[Index] == 0) {
747 return ;
748 }
749 }
750
751 String[Index - 1] = 0;
752
753 return ;
754 }
755
756 static
757 void
758 StripEqualMark (
759 IN OUT CHAR8 *String
760 )
761 /*++
762
763 Routine Description:
764
765 Removes Equal Mark from around a string
766
767 Arguments:
768
769 String - String to remove equal mark from
770
771 Returns:
772
773 None
774
775 --*/
776 {
777 INT32 Index;
778
779 if (String[0] != '=' && String[strlen (String) - 1] != '=') {
780 return ;
781 }
782
783 if (String[0] == '=') {
784
785 for (Index = 1; String[Index] != 0; Index++) {
786 String[Index - 1] = String[Index];
787 }
788
789 String[Index - 1] = 0;
790 }
791
792 if (String[strlen (String) - 1] == '=') {
793 String[strlen (String) - 1] = 0;
794 }
795
796 return ;
797 }
798
799 static
800 INT32
801 ProcessEnvironmentVariable (
802 IN CHAR8 *Buffer,
803 OUT CHAR8 *NewBuffer
804 )
805 /*++
806
807 Routine Description:
808
809 Converts environment variables to values
810
811 Arguments:
812
813 Buffer - Buffer containing Environment Variable String
814
815 NewBuffer - Buffer containing value of environment variable
816
817
818 Returns:
819
820 Number of characters from Buffer used
821
822 --*/
823 {
824 INT32 Index;
825 INT32 Index2;
826 CHAR8 VariableBuffer[_MAX_PATH];
827
828 Index = 2;
829 Index2 = 0;
830
831 while (Buffer[Index] != ')') {
832 VariableBuffer[Index - 2] = Buffer[Index++];
833 }
834
835 VariableBuffer[Index - 2] = 0;
836 Index++;
837
838 if (getenv (VariableBuffer) != NULL) {
839 strcpy (NewBuffer, getenv (VariableBuffer));
840 } else {
841 printf ("Environment variable %s not found!\n", VariableBuffer);
842 }
843
844 return Index;
845 }
846
847 static
848 void
849 SplitAttributesField (
850 IN CHAR8 *Buffer,
851 IN CHAR8 *AttributesArray[],
852 IN OUT UINT32 *NumberOfAttributes
853 )
854 /*
855 NumberOfAttributes: on input, it specifies the current number of attributes
856 stored in AttributeArray.
857 on output, it is updated to the latest number of attributes
858 stored in AttributesArray.
859 */
860 {
861 UINT32 Index;
862 UINT32 Index2;
863 UINT32 z;
864 CHAR8 *CharBuffer;
865
866 CharBuffer = NULL;
867 CharBuffer = (CHAR8 *) malloc (_MAX_PATH);
868 ZeroMem (CharBuffer, _MAX_PATH);
869
870 for (Index = 0, z = 0, Index2 = 0; Index < strlen (Buffer); Index++) {
871
872 if (Buffer[Index] != '|') {
873 CharBuffer[z] = Buffer[Index];
874 z++;
875 } else {
876
877 CharBuffer[z] = 0;
878 AttributesArray[*NumberOfAttributes + Index2] = CharBuffer;
879 Index2++;
880
881 //
882 // allocate new char buffer for the next attributes string
883 //
884 CharBuffer = (CHAR8 *) malloc (_MAX_PATH);
885 ZeroMem (CharBuffer, _MAX_PATH);
886 z = 0;
887 }
888 }
889
890 CharBuffer[z] = 0;
891 //
892 // record the last attributes string in the Buffer
893 //
894 AttributesArray[*NumberOfAttributes + Index2] = CharBuffer;
895 Index2++;
896
897 *NumberOfAttributes += Index2;
898
899 return ;
900 }
901
902 static
903 INT32
904 GetToolArguments (
905 CHAR8 *ToolArgumentsArray[],
906 FILE *Package,
907 CHAR8 **PtrInputFileName,
908 CHAR8 **PtrOutputFileName,
909 EFI_GUID *Guid,
910 UINT16 *GuidedSectionAttributes
911 )
912 {
913 CHAR8 Buffer[_MAX_PATH];
914 BOOLEAN ArgumentsFlag;
915 BOOLEAN InputFlag;
916 BOOLEAN OutputFlag;
917 BOOLEAN GuidFlag;
918 BOOLEAN AttributesFlag;
919 UINT32 argc;
920 UINT32 Index2;
921 UINT32 z;
922 CHAR8 *CharBuffer;
923 INT32 Index;
924 INT32 ReturnValue;
925 EFI_STATUS Status;
926
927 CHAR8 *AttributesArray[MAX_ARRAY_SIZE];
928 UINT32 NumberOfAttributes;
929 CHAR8 *InputFileName;
930 CHAR8 *OutputFileName;
931 UINT32 LineNumber;
932 Buffer[_MAX_PATH];
933
934 ArgumentsFlag = FALSE;
935 InputFlag = FALSE;
936 OutputFlag = FALSE;
937 GuidFlag = FALSE;
938 AttributesFlag = FALSE;
939 //
940 // Start at 1, since ToolArgumentsArray[0]
941 // is the program name.
942 //
943 argc = 1;
944 Index2 = 0;
945
946 z = 0;
947 ReturnValue = 0;
948 NumberOfAttributes = 0;
949 InputFileName = NULL;
950 OutputFileName = NULL;
951
952 ZeroMem (Buffer, _MAX_PATH);
953 ZeroMem (AttributesArray, sizeof (CHAR8 *) * MAX_ARRAY_SIZE);
954 LineNumber = 0;
955 while (Buffer[0] != ')') {
956
957 if (GetNextLine (Buffer, Package, &LineNumber) != -1) {
958 CheckSlash (Buffer, Package, &LineNumber);
959 StripEqualMark (Buffer);
960 } else {
961 Error (NULL, 0, 0, "failed to get next line from package file", NULL);
962 return -1;
963 }
964
965 if (Buffer[0] == ')') {
966 break;
967 } else if (strcmpi (Buffer, "ARGS") == 0) {
968
969 ArgumentsFlag = TRUE;
970 AttributesFlag = FALSE;
971 continue;
972
973 } else if (strcmpi (Buffer, "INPUT") == 0) {
974
975 InputFlag = TRUE;
976 ArgumentsFlag = FALSE;
977 AttributesFlag = FALSE;
978 continue;
979
980 } else if (strcmpi (Buffer, "OUTPUT") == 0) {
981
982 OutputFlag = TRUE;
983 ArgumentsFlag = FALSE;
984 AttributesFlag = FALSE;
985 continue;
986
987 } else if (strcmpi (Buffer, "GUID") == 0) {
988
989 GuidFlag = TRUE;
990 ArgumentsFlag = FALSE;
991 AttributesFlag = FALSE;
992 //
993 // fetch the GUID for the section
994 //
995 continue;
996
997 } else if (strcmpi (Buffer, "ATTRIBUTES") == 0) {
998
999 AttributesFlag = TRUE;
1000 ArgumentsFlag = FALSE;
1001 //
1002 // fetch the GUIDed Section's Attributes
1003 //
1004 continue;
1005
1006 } else if (strcmpi (Buffer, "") == 0) {
1007 continue;
1008 }
1009 //
1010 // get all command arguments into ToolArgumentsArray
1011 //
1012 if (ArgumentsFlag) {
1013
1014 StripEqualMark (Buffer);
1015
1016 CharBuffer = (CHAR8 *) malloc (_MAX_PATH);
1017 if (CharBuffer == NULL) {
1018 goto ErrorExit;
1019 }
1020
1021 ZeroMem (CharBuffer, sizeof (_MAX_PATH));
1022
1023 ToolArgumentsArray[argc] = CharBuffer;
1024
1025 if (Buffer[0] == '$') {
1026 Index = ProcessEnvironmentVariable (&Buffer[0], ToolArgumentsArray[argc]);
1027 //
1028 // if there is string after the environment variable, cat it.
1029 //
1030 if ((UINT32) Index < strlen (Buffer)) {
1031 strcat (ToolArgumentsArray[argc], &Buffer[Index]);
1032 }
1033 } else {
1034 strcpy (ToolArgumentsArray[argc], Buffer);
1035 }
1036
1037 argc += 1;
1038 ToolArgumentsArray[argc] = NULL;
1039 continue;
1040 }
1041
1042 if (InputFlag) {
1043
1044 StripEqualMark (Buffer);
1045
1046 InputFileName = (CHAR8 *) malloc (_MAX_PATH);
1047 if (InputFileName == NULL) {
1048 goto ErrorExit;
1049 }
1050
1051 ZeroMem (InputFileName, sizeof (_MAX_PATH));
1052
1053 if (Buffer[0] == '$') {
1054 Index = ProcessEnvironmentVariable (&Buffer[0], InputFileName);
1055 //
1056 // if there is string after the environment variable, cat it.
1057 //
1058 if ((UINT32) Index < strlen (Buffer)) {
1059 strcat (InputFileName, &Buffer[Index]);
1060 }
1061 } else {
1062 strcpy (InputFileName, Buffer);
1063 }
1064
1065 InputFlag = FALSE;
1066 continue;
1067 }
1068
1069 if (OutputFlag) {
1070
1071 StripEqualMark (Buffer);
1072
1073 OutputFileName = (CHAR8 *) malloc (_MAX_PATH);
1074 if (OutputFileName == NULL) {
1075 goto ErrorExit;
1076 }
1077
1078 ZeroMem (OutputFileName, sizeof (_MAX_PATH));
1079
1080 if (Buffer[0] == '$') {
1081 Index = ProcessEnvironmentVariable (&Buffer[0], OutputFileName);
1082 //
1083 // if there is string after the environment variable, cat it.
1084 //
1085 if ((UINT32) Index < strlen (Buffer)) {
1086 strcat (OutputFileName, &Buffer[Index]);
1087 }
1088 } else {
1089 strcpy (OutputFileName, Buffer);
1090 }
1091
1092 OutputFlag = FALSE;
1093 continue;
1094 }
1095
1096 if (GuidFlag) {
1097
1098 StripEqualMark (Buffer);
1099
1100 Status = StringToGuid (Buffer, Guid);
1101 if (EFI_ERROR (Status)) {
1102 ReturnValue = -1;
1103 goto ErrorExit;
1104 }
1105
1106 GuidFlag = FALSE;
1107 }
1108
1109 if (AttributesFlag) {
1110
1111 StripEqualMark (Buffer);
1112
1113 //
1114 // there might be no space between each attribute in the statement,
1115 // split them aside and return each attribute string
1116 // in the AttributesArray
1117 //
1118 SplitAttributesField (Buffer, AttributesArray, &NumberOfAttributes);
1119 }
1120 }
1121 //
1122 // ReplaceVariableInBuffer (ToolArgumentsArray,&i,"INPUT",InputVariable,j);
1123 // ReplaceVariableInBuffer (ToolArgumentsArray,&i,"OUTPUT",&TargetFileName,1);
1124 //
1125 for (z = 0; z < NumberOfAttributes; z++) {
1126 if (strcmpi (AttributesArray[z], "PROCESSING_REQUIRED") == 0) {
1127 *GuidedSectionAttributes |= EFI_GUIDED_SECTION_PROCESSING_REQUIRED;
1128 } else if (strcmpi (AttributesArray[z], "AUTH_STATUS_VALID") == 0) {
1129 *GuidedSectionAttributes |= EFI_GUIDED_SECTION_AUTH_STATUS_VALID;
1130 }
1131 }
1132
1133 ErrorExit:
1134
1135 for (Index2 = 0; Index2 < MAX_ARRAY_SIZE; Index2++) {
1136 if (AttributesArray[Index2] == NULL) {
1137 break;
1138 }
1139
1140 free (AttributesArray[Index2]);
1141 }
1142
1143 *PtrInputFileName = InputFileName;
1144 *PtrOutputFileName = OutputFileName;
1145
1146 return ReturnValue;
1147 }
1148
1149 static
1150 INT32
1151 ProcessScript (
1152 IN OUT UINT8 *FileBuffer,
1153 IN FILE *Package,
1154 IN CHAR8 *BuildDirectory,
1155 IN BOOLEAN ForceUncompress
1156 )
1157 /*++
1158
1159 Routine Description:
1160
1161 Signs the section, data stays in same location
1162
1163 Arguments:
1164
1165 FileBuffer - Data Buffer
1166
1167 Package - Points to curly brace in Image Script
1168
1169 BuildDirectory - Name of the source directory parameter
1170
1171 ForceUncompress - Whether to force uncompress.
1172
1173 Returns:
1174
1175 Number of bytes added to file buffer
1176 -1 on error
1177
1178 --*/
1179 {
1180 EFI_STATUS Status;
1181 UINT32 Size;
1182 CHAR8 Buffer[_MAX_PATH];
1183 CHAR8 Type[_MAX_PATH];
1184 CHAR8 FileName[_MAX_PATH];
1185 CHAR8 NewBuffer[_MAX_PATH];
1186 INT32 Index3;
1187 INT32 Index2;
1188 UINT32 ReturnValue;
1189 UINT8 ByteBuffer;
1190 FILE *InFile;
1191 UINT32 SourceDataSize;
1192 CHAR8 *ToolArgumentsArray[MAX_ARRAY_SIZE];
1193 CHAR8 *OutputFileName;
1194 CHAR8 *InputFileName;
1195 CHAR8 ToolName[_MAX_PATH];
1196 FILE *OutputFile;
1197 FILE *InputFile;
1198 UINT8 Temp;
1199 int returnint;
1200 INT32 Index;
1201 UINT32 LineNumber;
1202 BOOLEAN IsError;
1203 EFI_GUID SignGuid;
1204 UINT16 GuidedSectionAttributes;
1205 UINT8 *TargetFileBuffer;
1206
1207 OutputFileName = NULL;
1208 InputFileName = NULL;
1209 OutputFile = NULL;
1210 InputFile = NULL;
1211 IsError = FALSE;
1212 GuidedSectionAttributes = 0;
1213 TargetFileBuffer = NULL;
1214
1215 Size = 0;
1216 LineNumber = 0;
1217 Buffer[0] = 0;
1218 for (Index3 = 0; Index3 < MAX_ARRAY_SIZE; ++Index3) {
1219 ToolArgumentsArray[Index3] = NULL;
1220 }
1221
1222 while (Buffer[0] != '}') {
1223 if (GetNextLine (Buffer, Package, &LineNumber) != -1) {
1224 CheckSlash (Buffer, Package, &LineNumber);
1225 } else {
1226 printf ("ERROR in IMAGE SCRIPT!\n");
1227 IsError = TRUE;
1228 goto Done;
1229 }
1230
1231 if (strcmpi (Buffer, "Compress") == 0) {
1232 //
1233 // Handle compress
1234 //
1235 //
1236 // read compression type
1237 //
1238 if (GetNextLine (Buffer, Package, &LineNumber) != -1) {
1239 CheckSlash (Buffer, Package, &LineNumber);
1240 }
1241
1242 StripParens (Buffer);
1243 if (Buffer[0] == '$') {
1244 ProcessEnvironmentVariable (&Buffer[0], Type);
1245 } else {
1246 strcpy (Type, Buffer);
1247 }
1248 //
1249 // build buffer
1250 //
1251 while (Buffer[0] != '{') {
1252 if (GetNextLine (Buffer, Package, &LineNumber) != -1) {
1253 CheckSlash (Buffer, Package, &LineNumber);
1254 }
1255 }
1256
1257 ReturnValue = ProcessScript (&FileBuffer[Size], Package, BuildDirectory, ForceUncompress);
1258 if (ReturnValue == -1) {
1259 IsError = TRUE;
1260 goto Done;
1261 }
1262 //
1263 // Call compress routine on buffer.
1264 // Occasionally, compressed data + section header would
1265 // be largere than the source and EFI_BUFFER_TOO_SMALL is
1266 // returned from CompressSection()
1267 //
1268 SourceDataSize = ReturnValue;
1269
1270 if (!ForceUncompress) {
1271
1272 Status = CompressSection (
1273 &FileBuffer[Size],
1274 &ReturnValue,
1275 SourceDataSize,
1276 Type
1277 );
1278
1279 if (Status == EFI_BUFFER_TOO_SMALL) {
1280 Status = CompressSection (
1281 &FileBuffer[Size],
1282 &ReturnValue,
1283 SourceDataSize,
1284 Type
1285 );
1286 }
1287
1288 if (EFI_ERROR (Status)) {
1289 IsError = TRUE;
1290 goto Done;
1291 }
1292 }
1293
1294 Size += ReturnValue;
1295
1296 } else if (strcmpi (Buffer, "Tool") == 0) {
1297
1298 ZeroMem (ToolName, _MAX_PATH);
1299 ZeroMem (ToolArgumentsArray, sizeof (CHAR8 *) * MAX_ARRAY_SIZE);
1300 ZeroMem (&SignGuid, sizeof (EFI_GUID));
1301
1302 //
1303 // handle signing Tool
1304 //
1305 while (Buffer[0] != '(') {
1306 if (GetNextLine (Buffer, Package, &LineNumber) != -1) {
1307 CheckSlash (Buffer, Package, &LineNumber);
1308 }
1309 }
1310
1311 if (strcmpi (Buffer, "(") == 0) {
1312 if (GetNextLine (Buffer, Package, &LineNumber) != -1) {
1313 CheckSlash (Buffer, Package, &LineNumber);
1314 }
1315 }
1316
1317 StripParens (Buffer);
1318
1319 if (Buffer[0] == '$') {
1320 Index = ProcessEnvironmentVariable (&Buffer[0], ToolName);
1321 //
1322 // if there is string after the environment variable, cat it.
1323 //
1324 if ((UINT32) Index < strlen (Buffer)) {
1325 strcat (ToolName, &Buffer[Index]);
1326 }
1327 } else {
1328 strcpy (ToolName, Buffer);
1329 }
1330
1331 ToolArgumentsArray[0] = ToolName;
1332
1333 //
1334 // read ARGS
1335 //
1336 if (GetToolArguments (
1337 ToolArgumentsArray,
1338 Package,
1339 &InputFileName,
1340 &OutputFileName,
1341 &SignGuid,
1342 &GuidedSectionAttributes
1343 ) == -1) {
1344 IsError = TRUE;
1345 goto Done;
1346 }
1347 //
1348 // if the tool need input file,
1349 // dump the file buffer to the specified input file.
1350 //
1351 if (InputFileName != NULL) {
1352 InputFile = fopen (InputFileName, "wb");
1353 if (InputFile == NULL) {
1354 Error (NULL, 0, 0, InputFileName, "failed to open output file for writing");
1355 IsError = TRUE;
1356 goto Done;
1357 }
1358
1359 fwrite (FileBuffer, sizeof (UINT8), Size, InputFile);
1360 fclose (InputFile);
1361 InputFile = NULL;
1362 free (InputFileName);
1363 InputFileName = NULL;
1364 }
1365 //
1366 // dispatch signing tool
1367 //
1368 #ifdef __GNUC__
1369 {
1370 char CommandLine[1000];
1371 sprintf(CommandLine, "%s %s", ToolName, ToolArgumentsArray);
1372 returnint = system(CommandLine);
1373 }
1374 #else
1375 returnint = _spawnv (_P_WAIT, ToolName, ToolArgumentsArray);
1376 #endif
1377 if (returnint != 0) {
1378 Error (NULL, 0, 0, ToolName, "external tool failed");
1379 IsError = TRUE;
1380 goto Done;
1381 }
1382 //
1383 // if the tool has output file,
1384 // dump the output file to the file buffer
1385 //
1386 if (OutputFileName != NULL) {
1387
1388 OutputFile = fopen (OutputFileName, "rb");
1389 if (OutputFile == NULL) {
1390 Error (NULL, 0, 0, OutputFileName, "failed to open output file for writing");
1391 IsError = TRUE;
1392 goto Done;
1393 }
1394
1395 TargetFileBuffer = &FileBuffer[Size];
1396 SourceDataSize = Size;
1397
1398 fread (&Temp, sizeof (UINT8), 1, OutputFile);
1399 while (!feof (OutputFile)) {
1400 FileBuffer[Size++] = Temp;
1401 fread (&Temp, sizeof (UINT8), 1, OutputFile);
1402 }
1403
1404 while ((Size & 0x03) != 0) {
1405 FileBuffer[Size] = 0;
1406 Size++;
1407 }
1408
1409 SourceDataSize = Size - SourceDataSize;
1410
1411 fclose (OutputFile);
1412 OutputFile = NULL;
1413 free (OutputFileName);
1414 OutputFileName = NULL;
1415
1416 if (CompareGuid (&SignGuid, &mZeroGuid) != 0) {
1417 ReturnValue = SourceDataSize;
1418 Status = GenSimpleGuidSection (
1419 TargetFileBuffer,
1420 &ReturnValue,
1421 SourceDataSize,
1422 SignGuid,
1423 GuidedSectionAttributes
1424 );
1425 if (EFI_ERROR (Status)) {
1426 IsError = TRUE;
1427 goto Done;
1428 }
1429
1430 Size = ReturnValue;
1431 }
1432 }
1433
1434 } else if (Buffer[0] != '}') {
1435 //
1436 // if we are here, we should see either a file name,
1437 // or a }.
1438 //
1439 Index3 = 0;
1440 FileName[0] = 0;
1441 //
1442 // Prepend the build directory to the file name if the
1443 // file name does not already contain a full path.
1444 //
1445 if (!isalpha (Buffer[0]) || (Buffer[1] != ':')) {
1446 sprintf (FileName, "%s\\", BuildDirectory);
1447 }
1448
1449 while (Buffer[Index3] != '\n') {
1450 if (Buffer[Index3] == '$') {
1451 Index3 += ProcessEnvironmentVariable (&Buffer[Index3], NewBuffer);
1452 strcat (FileName, NewBuffer);
1453 }
1454
1455 if (Buffer[Index3] == 0) {
1456 break;
1457 } else {
1458 Index2 = strlen (FileName);
1459 FileName[Index2++] = Buffer[Index3++];
1460 FileName[Index2] = 0;
1461 }
1462 }
1463
1464 InFile = fopen (FileName, "rb");
1465 if (InFile == NULL) {
1466 Error (NULL, 0, 0, FileName, "failed to open file for reading");
1467 IsError = TRUE;
1468 goto Done;
1469 }
1470
1471 fread (&ByteBuffer, sizeof (UINT8), 1, InFile);
1472 while (!feof (InFile)) {
1473 FileBuffer[Size++] = ByteBuffer;
1474 fread (&ByteBuffer, sizeof (UINT8), 1, InFile);
1475 }
1476
1477 fclose (InFile);
1478 InFile = NULL;
1479
1480 //
1481 // Make sure section ends on a DWORD boundary
1482 //
1483 while ((Size & 0x03) != 0) {
1484 FileBuffer[Size] = 0;
1485 Size++;
1486 }
1487
1488 }
1489 }
1490
1491 Done:
1492 for (Index3 = 1; Index3 < MAX_ARRAY_SIZE; Index3++) {
1493 if (ToolArgumentsArray[Index3] == NULL) {
1494 break;
1495 }
1496
1497 free (ToolArgumentsArray[Index3]);
1498 }
1499
1500 if (IsError) {
1501 return -1;
1502 }
1503
1504 return Size;
1505
1506 }
1507
1508 static
1509 UINT8
1510 StringToType (
1511 IN CHAR8 *String
1512 )
1513 /*++
1514
1515 Routine Description:
1516
1517 Converts File Type String to value. EFI_FV_FILETYPE_ALL indicates that an
1518 unrecognized file type was specified.
1519
1520 Arguments:
1521
1522 String - File type string
1523
1524 Returns:
1525
1526 File Type Value
1527
1528 --*/
1529 {
1530 if (strcmpi (String, "EFI_FV_FILETYPE_RAW") == 0) {
1531 return EFI_FV_FILETYPE_RAW;
1532 }
1533
1534 if (strcmpi (String, "EFI_FV_FILETYPE_FREEFORM") == 0) {
1535 return EFI_FV_FILETYPE_FREEFORM;
1536 }
1537
1538 if (strcmpi (String, "EFI_FV_FILETYPE_SECURITY_CORE") == 0) {
1539 return EFI_FV_FILETYPE_SECURITY_CORE;
1540 }
1541
1542 if (strcmpi (String, "EFI_FV_FILETYPE_PEI_CORE") == 0) {
1543 return EFI_FV_FILETYPE_PEI_CORE;
1544 }
1545
1546 if (strcmpi (String, "EFI_FV_FILETYPE_DXE_CORE") == 0) {
1547 return EFI_FV_FILETYPE_DXE_CORE;
1548 }
1549
1550 if (strcmpi (String, "EFI_FV_FILETYPE_PEIM") == 0) {
1551 return EFI_FV_FILETYPE_PEIM;
1552 }
1553
1554 if (strcmpi (String, "EFI_FV_FILETYPE_DRIVER") == 0) {
1555 return EFI_FV_FILETYPE_DRIVER;
1556 }
1557
1558 if (strcmpi (String, "EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER") == 0) {
1559 return EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER;
1560 }
1561
1562 if (strcmpi (String, "EFI_FV_FILETYPE_APPLICATION") == 0) {
1563 return EFI_FV_FILETYPE_APPLICATION;
1564 }
1565
1566 if (strcmpi (String, "EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE") == 0) {
1567 return EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE;
1568 }
1569
1570 return EFI_FV_FILETYPE_ALL;
1571 }
1572
1573 static
1574 UINT32
1575 AdjustFileSize (
1576 IN UINT8 *FileBuffer,
1577 IN UINT32 FileSize
1578 )
1579 /*++
1580
1581 Routine Description:
1582 Adjusts file size to insure sectioned file is exactly the right length such
1583 that it ends on exactly the last byte of the last section. ProcessScript()
1584 may have padded beyond the end of the last section out to a 4 byte boundary.
1585 This padding is stripped.
1586
1587 Arguments:
1588 FileBuffer - Data Buffer - contains a section stream
1589 FileSize - Size of FileBuffer as returned from ProcessScript()
1590
1591 Returns:
1592 Corrected size of file.
1593
1594 --*/
1595 {
1596 UINT32 TotalLength;
1597 UINT32 CurrentLength;
1598 UINT32 SectionLength;
1599 UINT32 SectionStreamLength;
1600 EFI_COMMON_SECTION_HEADER *SectionHeader;
1601 EFI_COMMON_SECTION_HEADER *NextSectionHeader;
1602
1603 TotalLength = 0;
1604 CurrentLength = 0;
1605 SectionStreamLength = FileSize;
1606
1607 SectionHeader = (EFI_COMMON_SECTION_HEADER *) FileBuffer;
1608
1609 while (TotalLength < SectionStreamLength) {
1610 SectionLength = *((UINT32 *) SectionHeader->Size) & 0x00ffffff;
1611 TotalLength += SectionLength;
1612
1613 if (TotalLength == SectionStreamLength) {
1614 return TotalLength;
1615 }
1616 //
1617 // Move to the next byte following the section...
1618 //
1619 SectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) SectionHeader + SectionLength);
1620 CurrentLength = (UINTN) SectionHeader - (UINTN) FileBuffer;
1621
1622 //
1623 // Figure out where the next section begins
1624 //
1625 NextSectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) SectionHeader + 3);
1626 NextSectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINTN) NextSectionHeader &~ (UINTN) 3);
1627 TotalLength += (UINTN) NextSectionHeader - (UINTN) SectionHeader;
1628 SectionHeader = NextSectionHeader;
1629 }
1630
1631 return CurrentLength;
1632 }
1633
1634 static
1635 INT32
1636 MainEntry (
1637 INT32 argc,
1638 CHAR8 *argv[],
1639 BOOLEAN ForceUncompress
1640 )
1641 /*++
1642
1643 Routine Description:
1644
1645 MainEntry function.
1646
1647 Arguments:
1648
1649 argc - Number of command line parameters.
1650 argv - Array of pointers to command line parameter strings.
1651 ForceUncompress - If TRUE, force to do not compress the sections even if compression
1652 is specified in the script. Otherwise, FALSE.
1653
1654 Returns:
1655 STATUS_SUCCESS - Function exits successfully.
1656 STATUS_ERROR - Some error occurred during execution.
1657
1658 --*/
1659 {
1660 FILE *PrimaryPackage;
1661 FILE *OverridePackage;
1662 FILE *Out;
1663 CHAR8 BaseName[_MAX_PATH];
1664 EFI_GUID FfsGuid;
1665 CHAR8 GuidString[_MAX_PATH];
1666 EFI_FFS_FILE_HEADER FileHeader;
1667 CHAR8 FileType[_MAX_PATH];
1668 EFI_FFS_FILE_ATTRIBUTES FfsAttrib;
1669 EFI_FFS_FILE_ATTRIBUTES FfsAttribDefined;
1670 UINT64 FfsAlignment;
1671 UINT32 FfsAlignment32;
1672 CHAR8 InputString[_MAX_PATH];
1673 BOOLEAN ImageScriptInOveride;
1674 UINT32 FileSize;
1675 UINT8 *FileBuffer;
1676 EFI_STATUS Status;
1677 UINT32 LineNumber;
1678 EFI_FFS_FILE_TAIL TailValue;
1679
1680 BaseName[0] = 0;
1681 FileType[0] = 0;
1682 FfsAttrib = 0;
1683 FfsAttribDefined = 0;
1684 FfsAlignment = 0;
1685 FfsAlignment32 = 0;
1686 PrimaryPackage = NULL;
1687 Out = NULL;
1688 OverridePackage = NULL;
1689 FileBuffer = NULL;
1690
1691 strcpy (GuidString, "00000000-0000-0000-0000-000000000000");
1692 Status = StringToGuid (GuidString, &FfsGuid);
1693 if (Status != 0) {
1694 Error (NULL, 0, 0, GuidString, "error parsing GUID string");
1695 return STATUS_ERROR;
1696 }
1697
1698 GuidString[0] = 0;
1699 ImageScriptInOveride = FALSE;
1700 //
1701 // Initialize the simple file parsing routines. Then open
1702 // the primary package file for parsing.
1703 //
1704 SFPInit ();
1705 if (SFPOpenFile (mGlobals.PrimaryPackagePath) != STATUS_SUCCESS) {
1706 Error (NULL, 0, 0, mGlobals.PrimaryPackagePath, "unable to open primary package file");
1707 goto Done;
1708 }
1709 //
1710 // First token in the file must be "PACKAGE.INF"
1711 //
1712 if (!SFPIsToken ("PACKAGE.INF")) {
1713 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'PACKAGE.INF'", NULL);
1714 goto Done;
1715 }
1716 //
1717 // Find the [.] section
1718 //
1719 if (!SFPSkipToToken ("[.]")) {
1720 Error (mGlobals.PrimaryPackagePath, 1, 0, "could not locate [.] section in package file", NULL);
1721 goto Done;
1722 }
1723 //
1724 // Start parsing the data. The algorithm is essentially the same for each keyword:
1725 // 1. Identify the keyword
1726 // 2. Verify that the keyword/value pair has not already been defined
1727 // 3. Set some flag indicating that the keyword/value pair has been defined
1728 // 4. Skip over the "="
1729 // 5. Get the value, which may be a number, TRUE, FALSE, or a string.
1730 //
1731 while (1) {
1732 if (SFPIsToken ("BASE_NAME")) {
1733 //
1734 // Found BASE_NAME, format:
1735 // BASE_NAME = MyBaseName
1736 //
1737 if (BaseName[0] != 0) {
1738 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "BASE_NAME already defined", NULL);
1739 goto Done;
1740 }
1741
1742 if (!SFPIsToken ("=")) {
1743 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
1744 goto Done;
1745 }
1746
1747 if (!SFPGetNextToken (BaseName, sizeof (BaseName))) {
1748 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected valid base name", NULL);
1749 goto Done;
1750 }
1751 } else if (SFPIsToken ("IMAGE_SCRIPT")) {
1752 //
1753 // Found IMAGE_SCRIPT. Break out and process below.
1754 //
1755 break;
1756 } else if (SFPIsToken ("FFS_FILEGUID")) {
1757 //
1758 // found FILEGUID, format:
1759 // FFS_FILEGUID = F7845C4F-EDF5-42C5-BD8F-A02AF63DD93A
1760 //
1761 if (GuidString[0] != 0) {
1762 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_FILEGUID already defined", NULL);
1763 goto Done;
1764 }
1765
1766 if (!SFPIsToken ("=")) {
1767 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
1768 goto Done;
1769 }
1770
1771 if (SFPGetGuidToken (GuidString, sizeof (GuidString)) != TRUE) {
1772 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected file GUID", NULL);
1773 goto Done;
1774 }
1775
1776 Status = StringToGuid (GuidString, &FfsGuid);
1777 if (Status != 0) {
1778 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected valid file GUID", NULL);
1779 goto Done;
1780 }
1781 } else if (SFPIsToken ("FFS_FILETYPE")) {
1782 //
1783 // ***********************************************************************
1784 //
1785 // Found FFS_FILETYPE, format:
1786 // FFS_FILETYPE = EFI_FV_FILETYPE_APPLICATION
1787 //
1788 if (FileType[0] != 0) {
1789 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_FILETYPE previously defined", NULL);
1790 goto Done;
1791 }
1792
1793 if (!SFPIsToken ("=")) {
1794 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
1795 goto Done;
1796 }
1797
1798 if (!SFPGetNextToken (FileType, sizeof (FileType))) {
1799 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected valid FFS_FILETYPE", NULL);
1800 goto Done;
1801 }
1802 } else if (SFPIsToken ("FFS_ATTRIB_HEADER_EXTENSION")) {
1803 //
1804 // ***********************************************************************
1805 //
1806 // Found: FFS_ATTRIB_HEADER_EXTENSION = FALSE
1807 // Spec says the bit is for future expansion, and must be false.
1808 //
1809 if (FfsAttribDefined & FFS_ATTRIB_HEADER_EXTENSION) {
1810 Error (
1811 mGlobals.PrimaryPackagePath,
1812 SFPGetLineNumber (),
1813 0,
1814 "FFS_ATTRIB_HEADER_EXTENSION previously defined",
1815 NULL
1816 );
1817 goto Done;
1818 }
1819
1820 FfsAttribDefined |= FFS_ATTRIB_HEADER_EXTENSION;
1821 if (!SFPIsToken ("=")) {
1822 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
1823 goto Done;
1824 }
1825
1826 if (SFPIsToken ("TRUE")) {
1827 Error (
1828 mGlobals.PrimaryPackagePath,
1829 SFPGetLineNumber (),
1830 0,
1831 "only FFS_ATTRIB_HEADER_EXTENSION = FALSE is supported",
1832 NULL
1833 );
1834 goto Done;
1835 } else if (SFPIsToken ("FALSE")) {
1836 //
1837 // Default is FALSE
1838 //
1839 } else {
1840 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'FALSE'", NULL);
1841 goto Done;
1842 }
1843 } else if (SFPIsToken ("FFS_ATTRIB_TAIL_PRESENT")) {
1844 //
1845 // ***********************************************************************
1846 //
1847 // Found: FFS_ATTRIB_TAIL_PRESENT = TRUE | FALSE
1848 //
1849 if (FfsAttribDefined & FFS_ATTRIB_TAIL_PRESENT) {
1850 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_TAIL_PRESENT previously defined", NULL);
1851 goto Done;
1852 }
1853
1854 FfsAttribDefined |= FFS_ATTRIB_TAIL_PRESENT;
1855 if (!SFPIsToken ("=")) {
1856 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
1857 goto Done;
1858 }
1859
1860 if (SFPIsToken ("TRUE")) {
1861 FfsAttrib |= FFS_ATTRIB_TAIL_PRESENT;
1862 } else if (SFPIsToken ("FALSE")) {
1863 //
1864 // Default is FALSE
1865 //
1866 } else {
1867 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL);
1868 goto Done;
1869 }
1870 } else if (SFPIsToken ("FFS_ATTRIB_RECOVERY")) {
1871 //
1872 // ***********************************************************************
1873 //
1874 // Found: FFS_ATTRIB_RECOVERY = TRUE | FALSE
1875 //
1876 if (FfsAttribDefined & FFS_ATTRIB_RECOVERY) {
1877 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_RECOVERY previously defined", NULL);
1878 goto Done;
1879 }
1880
1881 FfsAttribDefined |= FFS_ATTRIB_RECOVERY;
1882 if (!SFPIsToken ("=")) {
1883 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
1884 goto Done;
1885 }
1886
1887 if (SFPIsToken ("TRUE")) {
1888 FfsAttrib |= FFS_ATTRIB_RECOVERY;
1889 } else if (SFPIsToken ("FALSE")) {
1890 //
1891 // Default is FALSE
1892 //
1893 } else {
1894 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL);
1895 goto Done;
1896 }
1897 } else if (SFPIsToken ("FFS_ATTRIB_CHECKSUM")) {
1898 //
1899 // ***********************************************************************
1900 //
1901 // Found: FFS_ATTRIB_CHECKSUM = TRUE | FALSE
1902 //
1903 if (FfsAttribDefined & FFS_ATTRIB_CHECKSUM) {
1904 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "FFS_ATTRIB_CHECKSUM previously defined", NULL);
1905 goto Done;
1906 }
1907
1908 FfsAttribDefined |= FFS_ATTRIB_CHECKSUM;
1909 if (!SFPIsToken ("=")) {
1910 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
1911 goto Done;
1912 }
1913
1914 if (SFPIsToken ("TRUE")) {
1915 FfsAttrib |= FFS_ATTRIB_CHECKSUM;
1916 } else if (SFPIsToken ("FALSE")) {
1917 //
1918 // Default is FALSE
1919 //
1920 } else {
1921 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 'TRUE' or 'FALSE'", NULL);
1922 goto Done;
1923 }
1924 } else if (SFPIsToken ("FFS_ALIGNMENT") || SFPIsToken ("FFS_ATTRIB_DATA_ALIGNMENT")) {
1925 //
1926 // ***********************************************************************
1927 //
1928 // Found FFS_ALIGNMENT, formats:
1929 // FFS_ALIGNMENT = 0-7
1930 // FFS_ATTRIB_DATA_ALIGNMENT = 0-7
1931 //
1932 if (FfsAttribDefined & FFS_ATTRIB_DATA_ALIGNMENT) {
1933 Error (
1934 mGlobals.PrimaryPackagePath,
1935 SFPGetLineNumber (),
1936 0,
1937 "FFS_ALIGNMENT/FFS_ATTRIB_DATA_ALIGNMENT previously defined",
1938 NULL
1939 );
1940 goto Done;
1941 }
1942
1943 FfsAttribDefined |= FFS_ATTRIB_DATA_ALIGNMENT;
1944 if (!SFPIsToken ("=")) {
1945 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected '='", NULL);
1946 goto Done;
1947 }
1948
1949 if (!SFPGetNumber (&FfsAlignment32)) {
1950 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected numeric value for alignment", NULL);
1951 goto Done;
1952 }
1953
1954 if (FfsAlignment32 > 7) {
1955 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, "expected 0 <= alignment <= 7", NULL);
1956 goto Done;
1957 }
1958
1959 FfsAttrib |= (((EFI_FFS_FILE_ATTRIBUTES) FfsAlignment32) << 3);
1960 } else {
1961 SFPGetNextToken (InputString, sizeof (InputString));
1962 Error (mGlobals.PrimaryPackagePath, SFPGetLineNumber (), 0, InputString, "unrecognized/unexpected token");
1963 goto Done;
1964 }
1965 }
1966 //
1967 // Close the primary package file
1968 //
1969 SFPCloseFile ();
1970 //
1971 // TODO: replace code below with basically a copy of the code above. Don't
1972 // forget to reset the FfsAttribDefined variable first. Also, you'll need
1973 // to somehow keep track of whether or not the basename is defined multiple
1974 // times in the override package. Ditto on the file GUID.
1975 //
1976 if (mGlobals.OverridePackagePath[0] != 0) {
1977 OverridePackage = fopen (mGlobals.OverridePackagePath, "r");
1978 //
1979 // NOTE: For package override to work correctly, the code below must be modified to
1980 // SET or CLEAR bits properly. For example, if the primary package set
1981 // FFS_ATTRIB_CHECKSUM = TRUE, and the override set FFS_ATTRIB_CHECKSUM = FALSE, then
1982 // we'd need to clear the bit below. Since this is not happening, I'm guessing that
1983 // the override functionality is not being used, so should be made obsolete. If I'm
1984 // wrong, and it is being used, then it needs to be fixed. Thus emit an error if it is
1985 // used, and we'll address it then. 4/10/2003
1986 //
1987 Error (__FILE__, __LINE__, 0, "package override functionality is not implemented correctly", NULL);
1988 goto Done;
1989 } else {
1990 OverridePackage = NULL;
1991 }
1992
1993 #ifdef OVERRIDE_SUPPORTED
1994 if (OverridePackage != NULL) {
1995 //
1996 // Parse override package file
1997 //
1998 fscanf (OverridePackage, "%s", &InputString);
1999 if (strcmpi (InputString, "PACKAGE.INF") != 0) {
2000 Error (mGlobals.OverridePackagePath, 1, 0, "invalid package file", "expected 'PACKAGE.INF'");
2001 goto Done;
2002 }
2003 //
2004 // Match [dir] to Build Directory
2005 //
2006 if (FindSectionInPackage (mGlobals.BuildDirectory, OverridePackage, &LineNumber) != 0) {
2007 Error (mGlobals.OverridePackagePath, 1, 0, mGlobals.BuildDirectory, "section not found in package file");
2008 goto Done;
2009 }
2010
2011 InputString[0] = 0;
2012 while ((InputString[0] != '[') && (!feof (OverridePackage))) {
2013 if (GetNextLine (InputString, OverridePackage, &LineNumber) != -1) {
2014 if (InputString[0] != '[') {
2015 here:
2016 if (strcmpi (InputString, "BASE_NAME") == 0) {
2017 //
2018 // found BASE_NAME, next is = and string.
2019 //
2020 fscanf (OverridePackage, "%s", &InputString);
2021 CheckSlash (InputString, OverridePackage, &LineNumber);
2022 if (strlen (InputString) == 1) {
2023 //
2024 // string is just =
2025 //
2026 fscanf (OverridePackage, "%s", &InputString);
2027 CheckSlash (InputString, OverridePackage, &LineNumber);
2028 strcpy (BaseName, InputString);
2029 } else {
2030 BreakString (InputString, InputString, 1);
2031 strcpy (BaseName, InputString);
2032 }
2033 } else if (strcmpi (InputString, "IMAGE_SCRIPT") == 0) {
2034 //
2035 // found IMAGE_SCRIPT, come back later to process it
2036 //
2037 ImageScriptInOveride = TRUE;
2038 fscanf (OverridePackage, "%s", &InputString);
2039 } else if (strcmpi (InputString, "FFS_FILEGUID") == 0) {
2040 //
2041 // found FILEGUID, next is = and string.
2042 //
2043 fscanf (OverridePackage, "%s", &InputString);
2044 CheckSlash (InputString, OverridePackage, &LineNumber);
2045 if (strlen (InputString) == 1) {
2046 //
2047 // string is just =
2048 //
2049 fscanf (OverridePackage, "%s", &InputString);
2050 CheckSlash (InputString, OverridePackage, &LineNumber);
2051 Status = StringToGuid (InputString, &FfsGuid);
2052 if (Status != 0) {
2053 Error (mGlobals.OverridePackagePath, 1, 0, InputString, "bad FFS_FILEGUID format");
2054 goto Done;
2055 }
2056 } else {
2057 BreakString (InputString, InputString, 1);
2058 Status = StringToGuid (InputString, &FfsGuid);
2059 if (Status != 0) {
2060 Error (mGlobals.OverridePackagePath, 1, 0, InputString, "bad FFS_FILEGUID format");
2061 goto Done;
2062 }
2063 }
2064 } else if (strcmpi (InputString, "FFS_FILETYPE") == 0) {
2065 //
2066 // found FILETYPE, next is = and string.
2067 //
2068 fscanf (OverridePackage, "%s", &InputString);
2069 CheckSlash (InputString, OverridePackage, &LineNumber);
2070 if (strlen (InputString) == 1) {
2071 //
2072 // string is just =
2073 //
2074 fscanf (OverridePackage, "%s", &InputString);
2075 CheckSlash (InputString, OverridePackage, &LineNumber);
2076 strcpy (FileType, InputString);
2077 } else {
2078 BreakString (InputString, InputString, 1);
2079 strcpy (FileType, InputString);
2080 }
2081
2082 } else if (strcmpi (InputString, "FFS_ATTRIB_RECOVERY") == 0) {
2083 //
2084 // found FFS_ATTRIB_RECOVERY, next is = and string.
2085 //
2086 fscanf (OverridePackage, "%s", &InputString);
2087 CheckSlash (InputString, OverridePackage, &LineNumber);
2088 if (strlen (InputString) == 1) {
2089 //
2090 // string is just =
2091 //
2092 fscanf (OverridePackage, "%s", &InputString);
2093 CheckSlash (InputString, OverridePackage, &LineNumber);
2094 if (strcmpi (InputString, "TRUE") == 0) {
2095 FfsAttrib |= FFS_ATTRIB_RECOVERY;
2096 }
2097 } else {
2098 BreakString (InputString, InputString, 1);
2099 if (strcmpi (InputString, "TRUE") == 0) {
2100 FfsAttrib |= FFS_ATTRIB_RECOVERY;
2101 }
2102 }
2103 } else if (strcmpi (InputString, "FFS_ATTRIB_CHECKSUM") == 0) {
2104 //
2105 // found FFS_ATTRIB_CHECKSUM, next is = and string.
2106 //
2107 fscanf (OverridePackage, "%s", &InputString);
2108 CheckSlash (InputString, OverridePackage, &LineNumber);
2109 if (strlen (InputString) == 1) {
2110 //
2111 // string is just =
2112 //
2113 fscanf (OverridePackage, "%s", &InputString);
2114 CheckSlash (InputString, OverridePackage, &LineNumber);
2115 if (strcmpi (InputString, "TRUE") == 0) {
2116 FfsAttrib |= FFS_ATTRIB_CHECKSUM;
2117 }
2118 } else {
2119 BreakString (InputString, InputString, 1);
2120 if (strcmpi (InputString, "TRUE") == 0) {
2121 FfsAttrib |= FFS_ATTRIB_CHECKSUM;
2122 }
2123 }
2124 } else if (strcmpi (InputString, "FFS_ALIGNMENT") == 0) {
2125 //
2126 // found FFS_ALIGNMENT, next is = and string.
2127 //
2128 fscanf (OverridePackage, "%s", &InputString);
2129 CheckSlash (InputString, OverridePackage, &LineNumber);
2130 if (strlen (InputString) == 1) {
2131 //
2132 // string is just =
2133 //
2134 fscanf (OverridePackage, "%s", &InputString);
2135 CheckSlash (InputString, OverridePackage, &LineNumber);
2136 } else {
2137 BreakString (InputString, InputString, 1);
2138 }
2139
2140 AsciiStringToUint64 (InputString, FALSE, &FfsAlignment);
2141 if (FfsAlignment > 7) {
2142 Error (mGlobals.OverridePackagePath, 1, 0, InputString, "invalid FFS_ALIGNMENT value");
2143 goto Done;
2144 }
2145
2146 FfsAttrib |= (((EFI_FFS_FILE_ATTRIBUTES) FfsAlignment) << 3);
2147 } else if (strchr (InputString, '=') != NULL) {
2148 BreakString (InputString, String, 1);
2149 fseek (OverridePackage, (-1 * (strlen (String) + 1)), SEEK_CUR);
2150 BreakString (InputString, InputString, 0);
2151 goto here;
2152 }
2153 }
2154 }
2155 }
2156 }
2157 #endif // #ifdef OVERRIDE_SUPPORTED
2158 //
2159 // Require that they specified a file GUID at least, since that's how we're
2160 // naming the file.
2161 //
2162 if (GuidString[0] == 0) {
2163 Error (mGlobals.PrimaryPackagePath, 1, 0, "FFS_FILEGUID must be specified", NULL);
2164 return STATUS_ERROR;
2165 }
2166 //
2167 // Build Header and process image script
2168 //
2169 FileBuffer = (UINT8 *) malloc ((1024 * 1024 * 16) * sizeof (UINT8));
2170 if (FileBuffer == NULL) {
2171 Error (__FILE__, __LINE__, 0, "memory allocation failed", NULL);
2172 goto Done;
2173 }
2174
2175 FileSize = 0;
2176 if (ImageScriptInOveride) {
2177 #ifdef OVERRIDE_SUPORTED
2178 rewind (OverridePackage);
2179 LineNumber = 0;
2180 FindSectionInPackage (mGlobals.BuildDirectory, OverridePackage, &LineNumber);
2181 while (strcmpi (InputString, "IMAGE_SCRIPT") != 0) {
2182 GetNextLine (InputString, OverridePackage, &LineNumber);
2183 CheckSlash (InputString, OverridePackage, &LineNumber);
2184 if (strchr (InputString, '=') != NULL) {
2185 BreakString (InputString, InputString, 0);
2186 }
2187 }
2188
2189 while (InputString[0] != '{') {
2190 GetNextLine (InputString, OverridePackage, &LineNumber);
2191 CheckSlash (InputString, OverridePackage, &LineNumber);
2192 }
2193 //
2194 // Found start of image script, process it
2195 //
2196 FileSize += ProcessScript (FileBuffer, OverridePackage, mGlobals.BuildDirectory, ForceUncompress);
2197 if (FileSize == -1) {
2198 return -1;
2199 }
2200
2201 if (StringToType (FileType) != EFI_FV_FILETYPE_RAW) {
2202 FileSize = AdjustFileSize (FileBuffer, FileSize);
2203 }
2204
2205 if (BaseName[0] == '\"') {
2206 StripQuotes (BaseName);
2207 }
2208
2209 if (BaseName[0] != 0) {
2210 sprintf (InputString, "%s-%s", GuidString, BaseName);
2211 } else {
2212 strcpy (InputString, GuidString);
2213 }
2214
2215 switch (StringToType (FileType)) {
2216
2217 case EFI_FV_FILETYPE_SECURITY_CORE:
2218 strcat (InputString, ".SEC");
2219 break;
2220
2221 case EFI_FV_FILETYPE_PEIM:
2222 case EFI_FV_FILETYPE_PEI_CORE:
2223 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
2224 strcat (InputString, ".PEI");
2225 break;
2226
2227 case EFI_FV_FILETYPE_DRIVER:
2228 case EFI_FV_FILETYPE_DXE_CORE:
2229 strcat (InputString, ".DXE");
2230 break;
2231
2232 case EFI_FV_FILETYPE_APPLICATION:
2233 strcat (InputString, ".APP");
2234 break;
2235
2236 case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE:
2237 strcat (InputString, ".FVI");
2238 break;
2239
2240 case EFI_FV_FILETYPE_ALL:
2241 Error (mGlobals.OverridePackagePath, 1, 0, "invalid FFS file type for this utility", NULL);
2242 goto Done;
2243
2244 default:
2245 strcat (InputString, ".FFS");
2246 break;
2247 }
2248
2249 if (ForceUncompress) {
2250 strcat (InputString, ".ORG");
2251 }
2252
2253 Out = fopen (InputString, "wb");
2254 if (Out == NULL) {
2255 Error (NULL, 0, 0, InputString, "could not open output file for writing");
2256 goto Done;
2257 }
2258 //
2259 // create ffs header
2260 //
2261 memset (&FileHeader, 0, sizeof (EFI_FFS_FILE_HEADER));
2262 memcpy (&FileHeader.Name, &FfsGuid, sizeof (EFI_GUID));
2263 FileHeader.Type = StringToType (FileType);
2264 FileHeader.Attributes = FfsAttrib;
2265 //
2266 // Now FileSize includes the EFI_FFS_FILE_HEADER
2267 //
2268 FileSize += sizeof (EFI_FFS_FILE_HEADER);
2269 FileHeader.Size[0] = (UINT8) (FileSize & 0xFF);
2270 FileHeader.Size[1] = (UINT8) ((FileSize & 0xFF00) >> 8);
2271 FileHeader.Size[2] = (UINT8) ((FileSize & 0xFF0000) >> 16);
2272 //
2273 // Fill in checksums and state, these must be zero for checksumming
2274 //
2275 // FileHeader.IntegrityCheck.Checksum.Header = 0;
2276 // FileHeader.IntegrityCheck.Checksum.File = 0;
2277 // FileHeader.State = 0;
2278 //
2279 FileHeader.IntegrityCheck.Checksum.Header = CalculateChecksum8 (
2280 (UINT8 *) &FileHeader,
2281 sizeof (EFI_FFS_FILE_HEADER)
2282 );
2283 if (FileHeader.Attributes & FFS_ATTRIB_CHECKSUM) {
2284 FileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 ((UINT8 *) &FileHeader, FileSize);
2285 } else {
2286 FileHeader.IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
2287 }
2288
2289 FileHeader.State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
2290 //
2291 // write header
2292 //
2293 if (fwrite (&FileHeader, sizeof (FileHeader), 1, Out) != 1) {
2294 Error (NULL, 0, 0, "failed to write file header to output file", NULL);
2295 goto Done;
2296 }
2297 //
2298 // write data
2299 //
2300 if (fwrite (FileBuffer, FileSize - sizeof (EFI_FFS_FILE_HEADER), 1, Out) != 1) {
2301 Error (NULL, 0, 0, "failed to write all bytes to output file", NULL);
2302 goto Done;
2303 }
2304
2305 fclose (Out);
2306 Out = NULL;
2307 #endif // #ifdef OVERRIDE_SUPPORTED
2308 } else {
2309 //
2310 // Open primary package file and process the IMAGE_SCRIPT section
2311 //
2312 PrimaryPackage = fopen (mGlobals.PrimaryPackagePath, "r");
2313 if (PrimaryPackage == NULL) {
2314 Error (NULL, 0, 0, mGlobals.PrimaryPackagePath, "unable to open primary package file");
2315 goto Done;
2316 }
2317
2318 LineNumber = 1;
2319 FindSectionInPackage (".", PrimaryPackage, &LineNumber);
2320 while (strcmpi (InputString, "IMAGE_SCRIPT") != 0) {
2321 GetNextLine (InputString, PrimaryPackage, &LineNumber);
2322 CheckSlash (InputString, PrimaryPackage, &LineNumber);
2323 if (strchr (InputString, '=') != NULL) {
2324 BreakString (InputString, InputString, 0);
2325 }
2326 }
2327
2328 while (InputString[0] != '{') {
2329 GetNextLine (InputString, PrimaryPackage, &LineNumber);
2330 CheckSlash (InputString, PrimaryPackage, &LineNumber);
2331 }
2332 //
2333 // Found start of image script, process it
2334 //
2335 FileSize += ProcessScript (FileBuffer, PrimaryPackage, mGlobals.BuildDirectory, ForceUncompress);
2336 if (FileSize == -1) {
2337 goto Done;
2338 }
2339
2340 if (StringToType (FileType) != EFI_FV_FILETYPE_RAW) {
2341 FileSize = AdjustFileSize (FileBuffer, FileSize);
2342 }
2343
2344 if (BaseName[0] == '\"') {
2345 StripQuotes (BaseName);
2346 }
2347
2348 if (BaseName[0] != 0) {
2349 sprintf (InputString, "%s-%s", GuidString, BaseName);
2350 } else {
2351 strcpy (InputString, GuidString);
2352 }
2353
2354 switch (StringToType (FileType)) {
2355
2356 case EFI_FV_FILETYPE_SECURITY_CORE:
2357 strcat (InputString, ".SEC");
2358 break;
2359
2360 case EFI_FV_FILETYPE_PEIM:
2361 case EFI_FV_FILETYPE_PEI_CORE:
2362 case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
2363 strcat (InputString, ".PEI");
2364 break;
2365
2366 case EFI_FV_FILETYPE_DRIVER:
2367 case EFI_FV_FILETYPE_DXE_CORE:
2368 strcat (InputString, ".DXE");
2369 break;
2370
2371 case EFI_FV_FILETYPE_APPLICATION:
2372 strcat (InputString, ".APP");
2373 break;
2374
2375 case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE:
2376 strcat (InputString, ".FVI");
2377 break;
2378
2379 case EFI_FV_FILETYPE_ALL:
2380 Error (mGlobals.PrimaryPackagePath, 1, 0, "invalid FFS file type for this utility", NULL);
2381 goto Done;
2382
2383 default:
2384 strcat (InputString, ".FFS");
2385 break;
2386 }
2387
2388 if (ForceUncompress) {
2389 strcat (InputString, ".ORG");
2390 }
2391
2392 Out = fopen (InputString, "wb");
2393 if (Out == NULL) {
2394 Error (NULL, 0, 0, InputString, "failed to open output file for writing");
2395 goto Done;
2396 }
2397 //
2398 // Initialize the FFS file header
2399 //
2400 memset (&FileHeader, 0, sizeof (EFI_FFS_FILE_HEADER));
2401 memcpy (&FileHeader.Name, &FfsGuid, sizeof (EFI_GUID));
2402 FileHeader.Type = StringToType (FileType);
2403 FileHeader.Attributes = FfsAttrib;
2404 //
2405 // From this point on FileSize includes the size of the EFI_FFS_FILE_HEADER
2406 //
2407 FileSize += sizeof (EFI_FFS_FILE_HEADER);
2408 //
2409 // If using a tail, then it adds two bytes
2410 //
2411 if (FileHeader.Attributes & FFS_ATTRIB_TAIL_PRESENT) {
2412 //
2413 // Tail is not allowed for pad and 0-length files
2414 //
2415 if ((FileHeader.Type == EFI_FV_FILETYPE_FFS_PAD) || (FileSize == sizeof (EFI_FFS_FILE_HEADER))) {
2416 Error (
2417 mGlobals.PrimaryPackagePath,
2418 1,
2419 0,
2420 "FFS_ATTRIB_TAIL_PRESENT=TRUE is invalid for PAD or 0-length files",
2421 NULL
2422 );
2423 goto Done;
2424 }
2425
2426 FileSize += sizeof (EFI_FFS_FILE_TAIL);
2427 }
2428
2429 FileHeader.Size[0] = (UINT8) (FileSize & 0xFF);
2430 FileHeader.Size[1] = (UINT8) ((FileSize & 0xFF00) >> 8);
2431 FileHeader.Size[2] = (UINT8) ((FileSize & 0xFF0000) >> 16);
2432 //
2433 // Fill in checksums and state, they must be 0 for checksumming.
2434 //
2435 // FileHeader.IntegrityCheck.Checksum.Header = 0;
2436 // FileHeader.IntegrityCheck.Checksum.File = 0;
2437 // FileHeader.State = 0;
2438 //
2439 FileHeader.IntegrityCheck.Checksum.Header = CalculateChecksum8 (
2440 (UINT8 *) &FileHeader,
2441 sizeof (EFI_FFS_FILE_HEADER)
2442 );
2443 if (FileHeader.Attributes & FFS_ATTRIB_CHECKSUM) {
2444 //
2445 // Cheating here. Since the header checksums, just calculate the checksum of the body.
2446 // Checksum does not include the tail
2447 //
2448 if (FileHeader.Attributes & FFS_ATTRIB_TAIL_PRESENT) {
2449 FileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 (
2450 FileBuffer,
2451 FileSize - sizeof (EFI_FFS_FILE_HEADER) - sizeof (EFI_FFS_FILE_TAIL)
2452 );
2453 } else {
2454 FileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 (
2455 FileBuffer,
2456 FileSize - sizeof (EFI_FFS_FILE_HEADER)
2457 );
2458 }
2459 } else {
2460 FileHeader.IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
2461 }
2462 //
2463 // Set the state now. Spec says the checksum assumes the state is 0
2464 //
2465 FileHeader.State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
2466 //
2467 // If there is a tail, then set it
2468 //
2469 if (FileHeader.Attributes & FFS_ATTRIB_TAIL_PRESENT) {
2470 TailValue = FileHeader.IntegrityCheck.TailReference;
2471 TailValue = (UINT16) (~TailValue);
2472 memcpy (
2473 (UINT8 *) FileBuffer + FileSize - sizeof (EFI_FFS_FILE_HEADER) - sizeof (EFI_FFS_FILE_TAIL),
2474 &TailValue,
2475 sizeof (TailValue)
2476 );
2477 }
2478 //
2479 // Write the FFS file header
2480 //
2481 if (fwrite (&FileHeader, sizeof (FileHeader), 1, Out) != 1) {
2482 Error (NULL, 0, 0, "failed to write file header contents", NULL);
2483 goto Done;
2484 }
2485 //
2486 // Write data
2487 //
2488 if (fwrite (FileBuffer, FileSize - sizeof (EFI_FFS_FILE_HEADER), 1, Out) != 1) {
2489 Error (NULL, 0, 0, "failed to write file contents", NULL);
2490 goto Done;
2491 }
2492 }
2493
2494 Done:
2495 SFPCloseFile ();
2496 if (Out != NULL) {
2497 fclose (Out);
2498 }
2499
2500 if (PrimaryPackage != NULL) {
2501 fclose (PrimaryPackage);
2502 }
2503
2504 if (FileBuffer != NULL) {
2505 free (FileBuffer);
2506 }
2507
2508 if (OverridePackage != NULL) {
2509 fclose (OverridePackage);
2510 }
2511
2512 return GetUtilityStatus ();
2513 }
2514
2515 int
2516 main (
2517 INT32 argc,
2518 CHAR8 *argv[]
2519 )
2520 /*++
2521
2522 Routine Description:
2523
2524 Main function.
2525
2526 Arguments:
2527
2528 argc - Number of command line parameters.
2529 argv - Array of pointers to parameter strings.
2530
2531 Returns:
2532 STATUS_SUCCESS - Utility exits successfully.
2533 STATUS_ERROR - Some error occurred during execution.
2534
2535 --*/
2536 {
2537 STATUS Status;
2538 //
2539 // Set the name of our utility for error reporting purposes.
2540 //
2541 SetUtilityName (UTILITY_NAME);
2542 Status = ProcessCommandLineArgs (argc, argv);
2543 if (Status != STATUS_SUCCESS) {
2544 return Status;
2545 }
2546
2547 Status = MainEntry (argc, argv, TRUE);
2548 if (Status == STATUS_SUCCESS) {
2549 MainEntry (argc, argv, FALSE);
2550 }
2551 //
2552 // If any errors were reported via the standard error reporting
2553 // routines, then the status has been saved. Get the value and
2554 // return it to the caller.
2555 //
2556 return GetUtilityStatus ();
2557 }
2558
2559 static
2560 STATUS
2561 ProcessCommandLineArgs (
2562 int Argc,
2563 char *Argv[]
2564 )
2565 /*++
2566
2567 Routine Description:
2568 Process the command line arguments.
2569
2570 Arguments:
2571 Argc - as passed in to main()
2572 Argv - as passed in to main()
2573
2574 Returns:
2575 STATUS_SUCCESS - arguments all ok
2576 STATUS_ERROR - problem with args, so caller should exit
2577
2578 --*/
2579 {
2580 //
2581 // If no args, then print usage instructions and return an error
2582 //
2583 Argc--;
2584 Argv++;
2585
2586 if (Argc < 1) {
2587 Usage ();
2588 return STATUS_ERROR;
2589 }
2590
2591 if ((strcmp(Argv[0], "-h") == 0) || (strcmp(Argv[0], "--help") == 0) ||
2592 (strcmp(Argv[0], "-?") == 0) || (strcmp(Argv[0], "/?") == 0)) {
2593 Usage();
2594 return STATUS_ERROR;
2595 }
2596
2597 if ((strcmp(Argv[0], "-V") == 0) || (strcmp(Argv[0], "--version") == 0)) {
2598 Version();
2599 return STATUS_ERROR;
2600 }
2601
2602 memset (&mGlobals, 0, sizeof (mGlobals));
2603
2604 while (Argc > 0) {
2605 if (strcmpi (Argv[0], "-b") == 0) {
2606 //
2607 // OPTION: -b BuildDirectory
2608 // Make sure there is another argument, then save it to our globals.
2609 //
2610 if (Argc < 2) {
2611 Error (NULL, 0, 0, "-b option requires the build directory name", NULL);
2612 return STATUS_ERROR;
2613 }
2614
2615 if (mGlobals.BuildDirectory[0]) {
2616 Error (NULL, 0, 0, Argv[0], "option can only be specified once");
2617 return STATUS_ERROR;
2618 }
2619
2620 strcpy (mGlobals.BuildDirectory, Argv[1]);
2621 Argc--;
2622 Argv++;
2623 } else if (strcmpi (Argv[0], "-p1") == 0) {
2624 //
2625 // OPTION: -p1 PrimaryPackageFile
2626 // Make sure there is another argument, then save it to our globals.
2627 //
2628 if (Argc < 2) {
2629 Error (NULL, 0, 0, Argv[0], "option requires the primary package file name");
2630 return STATUS_ERROR;
2631 }
2632
2633 if (mGlobals.PrimaryPackagePath[0]) {
2634 Error (NULL, 0, 0, Argv[0], "option can only be specified once");
2635 return STATUS_ERROR;
2636 }
2637
2638 strcpy (mGlobals.PrimaryPackagePath, Argv[1]);
2639 Argc--;
2640 Argv++;
2641 } else if (strcmpi (Argv[0], "-p2") == 0) {
2642 //
2643 // OPTION: -p2 OverridePackageFile
2644 // Make sure there is another argument, then save it to our globals.
2645 //
2646 if (Argc < 2) {
2647 Error (NULL, 0, 0, Argv[0], "option requires the override package file name");
2648 return STATUS_ERROR;
2649 }
2650
2651 if (mGlobals.OverridePackagePath[0]) {
2652 Error (NULL, 0, 0, Argv[0], "option can only be specified once");
2653 return STATUS_ERROR;
2654 }
2655
2656 strcpy (mGlobals.OverridePackagePath, Argv[1]);
2657 Argc--;
2658 Argv++;
2659 } else if (strcmpi (Argv[0], "-v") == 0) {
2660 //
2661 // OPTION: -v verbose
2662 //
2663 mGlobals.Verbose = TRUE;
2664 } else if (strcmpi (Argv[0], "-h") == 0) {
2665 //
2666 // OPTION: -h help
2667 //
2668 Usage ();
2669 return STATUS_ERROR;
2670 } else if (strcmpi (Argv[0], "-?") == 0) {
2671 //
2672 // OPTION: -? help
2673 //
2674 Usage ();
2675 return STATUS_ERROR;
2676 } else {
2677 Error (NULL, 0, 0, Argv[0], "unrecognized option");
2678 Usage ();
2679 return STATUS_ERROR;
2680 }
2681
2682 Argv++;
2683 Argc--;
2684 }
2685 //
2686 // Must have at least specified the package file name
2687 //
2688 if (mGlobals.PrimaryPackagePath[0] == 0) {
2689 Error (NULL, 0, 0, "must specify primary package file", NULL);
2690 return STATUS_ERROR;
2691 }
2692
2693 return STATUS_SUCCESS;
2694 }