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