1 /** @file 2 This file contains functions required to generate a Firmware File System file. 3 4 Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR> 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13 **/ 14 15 #include <stdio.h> 16 #include <stdlib.h> 17 #include <string.h> 18 19 #include <Common/UefiBaseTypes.h> 20 #include <Common/PiFirmwareFile.h> 21 #include <IndustryStandard/PeImage.h> 22 #include <Guid/FfsSectionAlignmentPadding.h> 23 24 #include "CommonLib.h" 25 #include "ParseInf.h" 26 #include "EfiUtilityMsgs.h" 27 28 #define UTILITY_NAME "GenFfs" 29 #define UTILITY_MAJOR_VERSION 0 30 #define UTILITY_MINOR_VERSION 1 31 32 STATIC CHAR8 *mFfsFileType[] = { 33 NULL, // 0x00 34 "EFI_FV_FILETYPE_RAW", // 0x01 35 "EFI_FV_FILETYPE_FREEFORM", // 0x02 36 "EFI_FV_FILETYPE_SECURITY_CORE", // 0x03 37 "EFI_FV_FILETYPE_PEI_CORE", // 0x04 38 "EFI_FV_FILETYPE_DXE_CORE", // 0x05 39 "EFI_FV_FILETYPE_PEIM", // 0x06 40 "EFI_FV_FILETYPE_DRIVER", // 0x07 41 "EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER", // 0x08 42 "EFI_FV_FILETYPE_APPLICATION", // 0x09 43 "EFI_FV_FILETYPE_SMM", // 0x0A 44 "EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE",// 0x0B 45 "EFI_FV_FILETYPE_COMBINED_SMM_DXE", // 0x0C 46 "EFI_FV_FILETYPE_SMM_CORE" // 0x0D 47 }; 48 49 STATIC CHAR8 *mAlignName[] = { 50 "1", "2", "4", "8", "16", "32", "64", "128", "256", "512", 51 "1K", "2K", "4K", "8K", "16K", "32K", "64K" 52 }; 53 54 STATIC CHAR8 *mFfsValidAlignName[] = { 55 "8", "16", "128", "512", "1K", "4K", "32K", "64K" 56 }; 57 58 STATIC UINT32 mFfsValidAlign[] = {0, 8, 16, 128, 512, 1024, 4096, 32768, 65536}; 59 60 STATIC EFI_GUID mZeroGuid = {0}; 61 62 STATIC EFI_GUID mEfiFfsSectionAlignmentPaddingGuid = EFI_FFS_SECTION_ALIGNMENT_PADDING_GUID; 63 64 STATIC 65 VOID 66 Version ( 67 VOID 68 ) 69 /*++ 70 71 Routine Description: 72 73 Print out version information for this utility. 74 75 Arguments: 76 77 None 78 79 Returns: 80 81 None 82 83 --*/ 84 { 85 fprintf (stdout, "%s Version %d.%d %s \n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION); 86 } 87 88 STATIC 89 VOID 90 Usage ( 91 VOID 92 ) 93 /*++ 94 95 Routine Description: 96 97 Print Error / Help message. 98 99 Arguments: 100 101 VOID 102 103 Returns: 104 105 None 106 107 --*/ 108 { 109 // 110 // Summary usage 111 // 112 fprintf (stdout, "\nUsage: %s [options]\n\n", UTILITY_NAME); 113 114 // 115 // Copyright declaration 116 // 117 fprintf (stdout, "Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.\n\n"); 118 119 // 120 // Details Option 121 // 122 fprintf (stdout, "Options:\n"); 123 fprintf (stdout, " -o FileName, --outputfile FileName\n\ 124 File is FFS file to be created.\n"); 125 fprintf (stdout, " -t Type, --filetype Type\n\ 126 Type is one FV file type defined in PI spec, which is\n\ 127 EFI_FV_FILETYPE_RAW, EFI_FV_FILETYPE_FREEFORM,\n\ 128 EFI_FV_FILETYPE_SECURITY_CORE, EFI_FV_FILETYPE_PEIM,\n\ 129 EFI_FV_FILETYPE_PEI_CORE, EFI_FV_FILETYPE_DXE_CORE,\n\ 130 EFI_FV_FILETYPE_DRIVER, EFI_FV_FILETYPE_APPLICATION,\n\ 131 EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,\n\ 132 EFI_FV_FILETYPE_SMM, EFI_FV_FILETYPE_SMM_CORE,\n\ 133 EFI_FV_FILETYPE_COMBINED_SMM_DXE, \n\ 134 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE.\n"); 135 fprintf (stdout, " -g FileGuid, --fileguid FileGuid\n\ 136 FileGuid is one module guid.\n\ 137 Its format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n"); 138 fprintf (stdout, " -x, --fixed Indicates that the file may not be moved\n\ 139 from its present location.\n"); 140 fprintf (stdout, " -s, --checksum Indicates to calculate file checksum.\n"); 141 fprintf (stdout, " -a FileAlign, --align FileAlign\n\ 142 FileAlign points to file alignment, which only support\n\ 143 the following align: 1,2,4,8,16,128,512,1K,4K,32K,64K\n"); 144 fprintf (stdout, " -i SectionFile, --sectionfile SectionFile\n\ 145 Section file will be contained in this FFS file.\n"); 146 fprintf (stdout, " -n SectionAlign, --sectionalign SectionAlign\n\ 147 SectionAlign points to section alignment, which support\n\ 148 the alignment scope 1~64K. It is specified together\n\ 149 with sectionfile to point its alignment in FFS file.\n"); 150 fprintf (stdout, " -v, --verbose Turn on verbose output with informational messages.\n"); 151 fprintf (stdout, " -q, --quiet Disable all messages except key message and fatal error\n"); 152 fprintf (stdout, " -d, --debug level Enable debug messages, at input debug level.\n"); 153 fprintf (stdout, " --version Show program's version number and exit.\n"); 154 fprintf (stdout, " -h, --help Show this help message and exit.\n"); 155 } 156 157 STATIC 158 EFI_STATUS 159 StringtoAlignment ( 160 IN CHAR8 *AlignBuffer, 161 OUT UINT32 *AlignNumber 162 ) 163 /*++ 164 165 Routine Description: 166 167 Converts Align String to align value (1~64K). 168 169 Arguments: 170 171 AlignBuffer - Pointer to Align string. 172 AlignNumber - Pointer to Align value. 173 174 Returns: 175 176 EFI_SUCCESS Successfully convert align string to align value. 177 EFI_INVALID_PARAMETER Align string is invalid or align value is not in scope. 178 179 --*/ 180 { 181 UINT32 Index = 0; 182 // 183 // Check AlignBuffer 184 // 185 if (AlignBuffer == NULL) { 186 return EFI_INVALID_PARAMETER; 187 } 188 for (Index = 0; Index < sizeof (mAlignName) / sizeof (CHAR8 *); Index ++) { 189 if (stricmp (AlignBuffer, mAlignName [Index]) == 0) { 190 *AlignNumber = 1 << Index; 191 return EFI_SUCCESS; 192 } 193 } 194 return EFI_INVALID_PARAMETER; 195 } 196 197 STATIC 198 UINT8 199 StringToType ( 200 IN CHAR8 *String 201 ) 202 /*++ 203 204 Routine Description: 205 206 Converts File Type String to value. EFI_FV_FILETYPE_ALL indicates that an 207 unrecognized file type was specified. 208 209 Arguments: 210 211 String - File type string 212 213 Returns: 214 215 File Type Value 216 217 --*/ 218 { 219 UINT8 Index = 0; 220 221 if (String == NULL) { 222 return EFI_FV_FILETYPE_ALL; 223 } 224 225 for (Index = 0; Index < sizeof (mFfsFileType) / sizeof (CHAR8 *); Index ++) { 226 if (mFfsFileType [Index] != NULL && (stricmp (String, mFfsFileType [Index]) == 0)) { 227 return Index; 228 } 229 } 230 return EFI_FV_FILETYPE_ALL; 231 } 232 233 STATIC 234 EFI_STATUS 235 GetSectionContents ( 236 IN CHAR8 **InputFileName, 237 IN UINT32 *InputFileAlign, 238 IN UINT32 InputFileNum, 239 IN EFI_FFS_FILE_ATTRIBUTES FfsAttrib, 240 OUT UINT8 *FileBuffer, 241 OUT UINT32 *BufferLength, 242 OUT UINT32 *MaxAlignment, 243 OUT UINT8 *PESectionNum 244 ) 245 /*++ 246 247 Routine Description: 248 249 Get the contents of all section files specified in InputFileName 250 into FileBuffer. 251 252 Arguments: 253 254 InputFileName - Name of the input file. 255 256 InputFileAlign - Alignment required by the input file data. 257 258 InputFileNum - Number of input files. Should be at least 1. 259 260 FileBuffer - Output buffer to contain data 261 262 BufferLength - On input, this is size of the FileBuffer. 263 On output, this is the actual length of the data. 264 265 MaxAlignment - The max alignment required by all the input file datas. 266 267 PeSectionNum - Calculate the number of Pe/Te Section in this FFS file. 268 269 Returns: 270 271 EFI_SUCCESS on successful return 272 EFI_INVALID_PARAMETER if InputFileNum is less than 1 or BufferLength point is NULL. 273 EFI_ABORTED if unable to open input file. 274 EFI_BUFFER_TOO_SMALL FileBuffer is not enough to contain all file data. 275 --*/ 276 { 277 UINT32 Size; 278 UINT32 Offset; 279 UINT32 FileSize; 280 UINT32 Index; 281 FILE *InFile; 282 EFI_FREEFORM_SUBTYPE_GUID_SECTION *SectHeader; 283 EFI_COMMON_SECTION_HEADER2 TempSectHeader; 284 EFI_TE_IMAGE_HEADER TeHeader; 285 UINT32 TeOffset; 286 EFI_GUID_DEFINED_SECTION GuidSectHeader; 287 EFI_GUID_DEFINED_SECTION2 GuidSectHeader2; 288 UINT32 HeaderSize; 289 UINT32 MaxEncounteredAlignment; 290 291 Size = 0; 292 Offset = 0; 293 TeOffset = 0; 294 MaxEncounteredAlignment = 1; 295 296 // 297 // Go through our array of file names and copy their contents 298 // to the output buffer. 299 // 300 for (Index = 0; Index < InputFileNum; Index++) { 301 // 302 // make sure section ends on a DWORD boundary 303 // 304 while ((Size & 0x03) != 0) { 305 Size++; 306 } 307 308 // 309 // Open file and read contents 310 // 311 InFile = fopen (LongFilePath (InputFileName[Index]), "rb"); 312 if (InFile == NULL) { 313 Error (NULL, 0, 0001, "Error opening file", InputFileName[Index]); 314 return EFI_ABORTED; 315 } 316 317 fseek (InFile, 0, SEEK_END); 318 FileSize = ftell (InFile); 319 fseek (InFile, 0, SEEK_SET); 320 DebugMsg (NULL, 0, 9, "Input section files", 321 "the input section name is %s and the size is %u bytes", InputFileName[Index], (unsigned) FileSize); 322 323 // 324 // Check this section is Te/Pe section, and Calculate the numbers of Te/Pe section. 325 // 326 TeOffset = 0; 327 if (FileSize >= MAX_FFS_SIZE) { 328 HeaderSize = sizeof (EFI_COMMON_SECTION_HEADER2); 329 } else { 330 HeaderSize = sizeof (EFI_COMMON_SECTION_HEADER); 331 } 332 fread (&TempSectHeader, 1, HeaderSize, InFile); 333 if (TempSectHeader.Type == EFI_SECTION_TE) { 334 (*PESectionNum) ++; 335 fread (&TeHeader, 1, sizeof (TeHeader), InFile); 336 if (TeHeader.Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) { 337 TeOffset = TeHeader.StrippedSize - sizeof (TeHeader); 338 } 339 } else if (TempSectHeader.Type == EFI_SECTION_PE32) { 340 (*PESectionNum) ++; 341 } else if (TempSectHeader.Type == EFI_SECTION_GUID_DEFINED) { 342 fseek (InFile, 0, SEEK_SET); 343 if (FileSize >= MAX_SECTION_SIZE) { 344 fread (&GuidSectHeader2, 1, sizeof (GuidSectHeader2), InFile); 345 if ((GuidSectHeader2.Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) { 346 HeaderSize = GuidSectHeader2.DataOffset; 347 } 348 } else { 349 fread (&GuidSectHeader, 1, sizeof (GuidSectHeader), InFile); 350 if ((GuidSectHeader.Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) { 351 HeaderSize = GuidSectHeader.DataOffset; 352 } 353 } 354 (*PESectionNum) ++; 355 } else if (TempSectHeader.Type == EFI_SECTION_COMPRESSION || 356 TempSectHeader.Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE) { 357 // 358 // for the encapsulated section, assume it contains Pe/Te section 359 // 360 (*PESectionNum) ++; 361 } 362 363 fseek (InFile, 0, SEEK_SET); 364 365 // 366 // Revert TeOffset to the converse value relative to Alignment 367 // This is to assure the original PeImage Header at Alignment. 368 // 369 if ((TeOffset != 0) && (InputFileAlign [Index] != 0)) { 370 TeOffset = InputFileAlign [Index] - (TeOffset % InputFileAlign [Index]); 371 TeOffset = TeOffset % InputFileAlign [Index]; 372 } 373 374 // 375 // make sure section data meet its alignment requirement by adding one pad section. 376 // But the different sections have the different section header. Necessary or not? 377 // Based on section type to adjust offset? Todo 378 // 379 if ((InputFileAlign [Index] != 0) && (((Size + HeaderSize + TeOffset) % InputFileAlign [Index]) != 0)) { 380 Offset = (Size + sizeof (EFI_COMMON_SECTION_HEADER) + HeaderSize + TeOffset + InputFileAlign [Index] - 1) & ~(InputFileAlign [Index] - 1); 381 Offset = Offset - Size - HeaderSize - TeOffset; 382 383 if (FileBuffer != NULL && ((Size + Offset) < *BufferLength)) { 384 // 385 // The maximal alignment is 64K, the raw section size must be less than 0xffffff 386 // 387 memset (FileBuffer + Size, 0, Offset); 388 SectHeader = (EFI_FREEFORM_SUBTYPE_GUID_SECTION *) (FileBuffer + Size); 389 SectHeader->CommonHeader.Size[0] = (UINT8) (Offset & 0xff); 390 SectHeader->CommonHeader.Size[1] = (UINT8) ((Offset & 0xff00) >> 8); 391 SectHeader->CommonHeader.Size[2] = (UINT8) ((Offset & 0xff0000) >> 16); 392 393 // 394 // Only add a special reducible padding section if 395 // - this FFS has the FFS_ATTRIB_FIXED attribute, 396 // - none of the preceding sections have alignment requirements, 397 // - the size of the padding is sufficient for the 398 // EFI_SECTION_FREEFORM_SUBTYPE_GUID header. 399 // 400 if ((FfsAttrib & FFS_ATTRIB_FIXED) != 0 && 401 MaxEncounteredAlignment <= 1 && 402 Offset >= sizeof (EFI_FREEFORM_SUBTYPE_GUID_SECTION)) { 403 SectHeader->CommonHeader.Type = EFI_SECTION_FREEFORM_SUBTYPE_GUID; 404 SectHeader->SubTypeGuid = mEfiFfsSectionAlignmentPaddingGuid; 405 } else { 406 SectHeader->CommonHeader.Type = EFI_SECTION_RAW; 407 } 408 } 409 DebugMsg (NULL, 0, 9, "Pad raw section for section data alignment", 410 "Pad Raw section size is %u", (unsigned) Offset); 411 412 Size = Size + Offset; 413 } 414 415 // 416 // Get the Max alignment of all input file datas 417 // 418 if (MaxEncounteredAlignment < InputFileAlign [Index]) { 419 MaxEncounteredAlignment = InputFileAlign [Index]; 420 } 421 422 // 423 // Now read the contents of the file into the buffer 424 // Buffer must be enough to contain the file content. 425 // 426 if ((FileSize > 0) && (FileBuffer != NULL) && ((Size + FileSize) <= *BufferLength)) { 427 if (fread (FileBuffer + Size, (size_t) FileSize, 1, InFile) != 1) { 428 Error (NULL, 0, 0004, "Error reading file", InputFileName[Index]); 429 fclose (InFile); 430 return EFI_ABORTED; 431 } 432 } 433 434 fclose (InFile); 435 Size += FileSize; 436 } 437 438 *MaxAlignment = MaxEncounteredAlignment; 439 440 // 441 // Set the actual length of the data. 442 // 443 if (Size > *BufferLength) { 444 *BufferLength = Size; 445 return EFI_BUFFER_TOO_SMALL; 446 } else { 447 *BufferLength = Size; 448 return EFI_SUCCESS; 449 } 450 } 451 452 int 453 main ( 454 int argc, 455 CHAR8 *argv[] 456 ) 457 /*++ 458 459 Routine Description: 460 461 Main function. 462 463 Arguments: 464 465 argc - Number of command line parameters. 466 argv - Array of pointers to parameter strings. 467 468 Returns: 469 STATUS_SUCCESS - Utility exits successfully. 470 STATUS_ERROR - Some error occurred during execution. 471 472 --*/ 473 { 474 EFI_STATUS Status; 475 EFI_FFS_FILE_ATTRIBUTES FfsAttrib; 476 UINT32 FfsAlign; 477 EFI_FV_FILETYPE FfsFiletype; 478 CHAR8 *OutputFileName; 479 EFI_GUID FileGuid = {0}; 480 UINT32 InputFileNum; 481 UINT32 *InputFileAlign; 482 CHAR8 **InputFileName; 483 UINT8 *FileBuffer; 484 UINT32 FileSize; 485 UINT32 MaxAlignment; 486 EFI_FFS_FILE_HEADER2 FfsFileHeader; 487 FILE *FfsFile; 488 UINT32 Index; 489 UINT64 LogLevel; 490 UINT8 PeSectionNum; 491 UINT32 HeaderSize; 492 493 // 494 // Init local variables 495 // 496 LogLevel = 0; 497 Index = 0; 498 FfsAttrib = 0; 499 FfsAlign = 0; 500 FfsFiletype = EFI_FV_FILETYPE_ALL; 501 OutputFileName = NULL; 502 InputFileNum = 0; 503 InputFileName = NULL; 504 InputFileAlign = NULL; 505 FileBuffer = NULL; 506 FileSize = 0; 507 MaxAlignment = 1; 508 FfsFile = NULL; 509 Status = EFI_SUCCESS; 510 PeSectionNum = 0; 511 512 SetUtilityName (UTILITY_NAME); 513 514 if (argc == 1) { 515 Error (NULL, 0, 1001, "Missing options", "no options input"); 516 Usage (); 517 return STATUS_ERROR; 518 } 519 520 // 521 // Parse command line 522 // 523 argc --; 524 argv ++; 525 526 if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) { 527 Version (); 528 Usage (); 529 return STATUS_SUCCESS; 530 } 531 532 if (stricmp (argv[0], "--version") == 0) { 533 Version (); 534 return STATUS_SUCCESS; 535 } 536 537 while (argc > 0) { 538 if ((stricmp (argv[0], "-t") == 0) || (stricmp (argv[0], "--filetype") == 0)) { 539 if (argv[1] == NULL || argv[1][0] == '-') { 540 Error (NULL, 0, 1003, "Invalid option value", "file type is missing for -t option"); 541 goto Finish; 542 } 543 FfsFiletype = StringToType (argv[1]); 544 if (FfsFiletype == EFI_FV_FILETYPE_ALL) { 545 Error (NULL, 0, 1003, "Invalid option value", "%s is not a valid file type", argv[1]); 546 goto Finish; 547 } 548 argc -= 2; 549 argv += 2; 550 continue; 551 } 552 553 if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--outputfile") == 0)) { 554 if (argv[1] == NULL || argv[1][0] == '-') { 555 Error (NULL, 0, 1003, "Invalid option value", "Output file is missing for -o option"); 556 goto Finish; 557 } 558 OutputFileName = argv[1]; 559 argc -= 2; 560 argv += 2; 561 continue; 562 } 563 564 if ((stricmp (argv[0], "-g") == 0) || (stricmp (argv[0], "--fileguid") == 0)) { 565 Status = StringToGuid (argv[1], &FileGuid); 566 if (EFI_ERROR (Status)) { 567 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]); 568 goto Finish; 569 } 570 argc -= 2; 571 argv += 2; 572 continue; 573 } 574 575 if ((stricmp (argv[0], "-x") == 0) || (stricmp (argv[0], "--fixed") == 0)) { 576 FfsAttrib |= FFS_ATTRIB_FIXED; 577 argc -= 1; 578 argv += 1; 579 continue; 580 } 581 582 if ((stricmp (argv[0], "-s") == 0) || (stricmp (argv[0], "--checksum") == 0)) { 583 FfsAttrib |= FFS_ATTRIB_CHECKSUM; 584 argc -= 1; 585 argv += 1; 586 continue; 587 } 588 589 if ((stricmp (argv[0], "-a") == 0) || (stricmp (argv[0], "--align") == 0)) { 590 if (argv[1] == NULL || argv[1][0] == '-') { 591 Error (NULL, 0, 1003, "Invalid option value", "Align value is missing for -a option"); 592 goto Finish; 593 } 594 for (Index = 0; Index < sizeof (mFfsValidAlignName) / sizeof (CHAR8 *); Index ++) { 595 if (stricmp (argv[1], mFfsValidAlignName[Index]) == 0) { 596 break; 597 } 598 } 599 if (Index == sizeof (mFfsValidAlignName) / sizeof (CHAR8 *)) { 600 if ((stricmp (argv[1], "1") == 0) || (stricmp (argv[1], "2") == 0) || (stricmp (argv[1], "4") == 0)) { 601 // 602 // 1, 2, 4 byte alignment same to 8 byte alignment 603 // 604 Index = 0; 605 } else { 606 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]); 607 goto Finish; 608 } 609 } 610 FfsAlign = Index; 611 argc -= 2; 612 argv += 2; 613 continue; 614 } 615 616 if ((stricmp (argv[0], "-i") == 0) || (stricmp (argv[0], "--sectionfile") == 0)) { 617 // 618 // Get Input file name and its alignment 619 // 620 if (argv[1] == NULL || argv[1][0] == '-') { 621 Error (NULL, 0, 1003, "Invalid option value", "input section file is missing for -i option"); 622 goto Finish; 623 } 624 625 // 626 // Allocate Input file name buffer and its alignment buffer. 627 // 628 if ((InputFileNum == 0) && (InputFileName == NULL)) { 629 InputFileName = (CHAR8 **) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)); 630 if (InputFileName == NULL) { 631 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); 632 return STATUS_ERROR; 633 } 634 memset (InputFileName, 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *))); 635 636 InputFileAlign = (UINT32 *) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32)); 637 if (InputFileAlign == NULL) { 638 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); 639 free (InputFileName); 640 return STATUS_ERROR; 641 } 642 memset (InputFileAlign, 0, MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32)); 643 } else if (InputFileNum % MAXIMUM_INPUT_FILE_NUM == 0) { 644 // 645 // InputFileName and alignment buffer too small, need to realloc 646 // 647 InputFileName = (CHAR8 **) realloc ( 648 InputFileName, 649 (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (CHAR8 *) 650 ); 651 652 if (InputFileName == NULL) { 653 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); 654 free (InputFileAlign); 655 return STATUS_ERROR; 656 } 657 memset (&(InputFileName[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *))); 658 659 InputFileAlign = (UINT32 *) realloc ( 660 InputFileAlign, 661 (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (UINT32) 662 ); 663 664 if (InputFileAlign == NULL) { 665 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); 666 free (InputFileName); 667 return STATUS_ERROR; 668 } 669 memset (&(InputFileAlign[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32))); 670 } 671 672 InputFileName[InputFileNum] = argv[1]; 673 argc -= 2; 674 argv += 2; 675 676 if (argc <= 0) { 677 InputFileNum ++; 678 break; 679 } 680 681 // 682 // Section File alignment requirement 683 // 684 if ((stricmp (argv[0], "-n") == 0) || (stricmp (argv[0], "--sectionalign") == 0)) { 685 Status = StringtoAlignment (argv[1], &(InputFileAlign[InputFileNum])); 686 if (EFI_ERROR (Status)) { 687 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]); 688 goto Finish; 689 } 690 argc -= 2; 691 argv += 2; 692 } 693 InputFileNum ++; 694 continue; 695 } 696 697 if ((stricmp (argv[0], "-n") == 0) || (stricmp (argv[0], "--sectionalign") == 0)) { 698 Error (NULL, 0, 1000, "Unknown option", "SectionAlign option must be specified with section file."); 699 goto Finish; 700 } 701 702 if ((stricmp (argv[0], "-v") == 0) || (stricmp (argv[0], "--verbose") == 0)) { 703 SetPrintLevel (VERBOSE_LOG_LEVEL); 704 VerboseMsg ("Verbose output Mode Set!"); 705 argc --; 706 argv ++; 707 continue; 708 } 709 710 if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) { 711 SetPrintLevel (KEY_LOG_LEVEL); 712 KeyMsg ("Quiet output Mode Set!"); 713 argc --; 714 argv ++; 715 continue; 716 } 717 718 if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) { 719 Status = AsciiStringToUint64 (argv[1], FALSE, &LogLevel); 720 if (EFI_ERROR (Status)) { 721 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]); 722 goto Finish; 723 } 724 if (LogLevel > 9) { 725 Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, current input level is %d", (int) LogLevel); 726 goto Finish; 727 } 728 SetPrintLevel (LogLevel); 729 DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[1]); 730 argc -= 2; 731 argv += 2; 732 continue; 733 } 734 735 Error (NULL, 0, 1000, "Unknown option", argv[0]); 736 goto Finish; 737 } 738 739 VerboseMsg ("%s tool start.", UTILITY_NAME); 740 741 // 742 // Check the complete input parameters. 743 // 744 if (FfsFiletype == EFI_FV_FILETYPE_ALL) { 745 Error (NULL, 0, 1001, "Missing option", "filetype"); 746 goto Finish; 747 } 748 749 if (CompareGuid (&FileGuid, &mZeroGuid) == 0) { 750 Error (NULL, 0, 1001, "Missing option", "fileguid"); 751 goto Finish; 752 } 753 754 if (InputFileNum == 0) { 755 Error (NULL, 0, 1001, "Missing option", "Input files"); 756 goto Finish; 757 } 758 759 // 760 // Output input parameter information 761 // 762 VerboseMsg ("Fv File type is %s", mFfsFileType [FfsFiletype]); 763 VerboseMsg ("Output file name is %s", OutputFileName); 764 VerboseMsg ("FFS File Guid is %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", 765 (unsigned) FileGuid.Data1, 766 FileGuid.Data2, 767 FileGuid.Data3, 768 FileGuid.Data4[0], 769 FileGuid.Data4[1], 770 FileGuid.Data4[2], 771 FileGuid.Data4[3], 772 FileGuid.Data4[4], 773 FileGuid.Data4[5], 774 FileGuid.Data4[6], 775 FileGuid.Data4[7]); 776 if ((FfsAttrib & FFS_ATTRIB_FIXED) != 0) { 777 VerboseMsg ("FFS File has the fixed file attribute"); 778 } 779 if ((FfsAttrib & FFS_ATTRIB_CHECKSUM) != 0) { 780 VerboseMsg ("FFS File requires the checksum of the whole file"); 781 } 782 VerboseMsg ("FFS file alignment is %s", mFfsValidAlignName[FfsAlign]); 783 for (Index = 0; Index < InputFileNum; Index ++) { 784 if (InputFileAlign[Index] == 0) { 785 // 786 // Minimum alignment is 1 byte. 787 // 788 InputFileAlign[Index] = 1; 789 } 790 VerboseMsg ("the %dth input section name is %s and section alignment is %u", Index, InputFileName[Index], (unsigned) InputFileAlign[Index]); 791 } 792 793 // 794 // Calculate the size of all input section files. 795 // 796 Status = GetSectionContents ( 797 InputFileName, 798 InputFileAlign, 799 InputFileNum, 800 FfsAttrib, 801 FileBuffer, 802 &FileSize, 803 &MaxAlignment, 804 &PeSectionNum 805 ); 806 807 if ((FfsFiletype == EFI_FV_FILETYPE_SECURITY_CORE || 808 FfsFiletype == EFI_FV_FILETYPE_PEI_CORE || 809 FfsFiletype == EFI_FV_FILETYPE_DXE_CORE) && (PeSectionNum != 1)) { 810 Error (NULL, 0, 2000, "Invalid parameter", "Fv File type %s must have one and only one Pe or Te section, but %u Pe/Te section are input", mFfsFileType [FfsFiletype], PeSectionNum); 811 goto Finish; 812 } 813 814 if ((FfsFiletype == EFI_FV_FILETYPE_PEIM || 815 FfsFiletype == EFI_FV_FILETYPE_DRIVER || 816 FfsFiletype == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER || 817 FfsFiletype == EFI_FV_FILETYPE_APPLICATION) && (PeSectionNum < 1)) { 818 Error (NULL, 0, 2000, "Invalid parameter", "Fv File type %s must have at least one Pe or Te section, but no Pe/Te section is input", mFfsFileType [FfsFiletype]); 819 goto Finish; 820 } 821 822 if (Status == EFI_BUFFER_TOO_SMALL) { 823 FileBuffer = (UINT8 *) malloc (FileSize); 824 if (FileBuffer == NULL) { 825 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); 826 goto Finish; 827 } 828 memset (FileBuffer, 0, FileSize); 829 830 // 831 // read all input file contents into a buffer 832 // 833 Status = GetSectionContents ( 834 InputFileName, 835 InputFileAlign, 836 InputFileNum, 837 FfsAttrib, 838 FileBuffer, 839 &FileSize, 840 &MaxAlignment, 841 &PeSectionNum 842 ); 843 } 844 845 if (EFI_ERROR (Status)) { 846 goto Finish; 847 } 848 849 if (FileBuffer == NULL && FileSize != 0) { 850 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); 851 goto Finish; 852 } 853 854 // 855 // Create Ffs file header. 856 // 857 memset (&FfsFileHeader, 0, sizeof (EFI_FFS_FILE_HEADER2)); 858 memcpy (&FfsFileHeader.Name, &FileGuid, sizeof (EFI_GUID)); 859 FfsFileHeader.Type = FfsFiletype; 860 // 861 // Update FFS Alignment based on the max alignment required by input section files 862 // 863 VerboseMsg ("the max alignment of all input sections is %u", (unsigned) MaxAlignment); 864 for (Index = 0; Index < sizeof (mFfsValidAlign) / sizeof (UINT32) - 1; Index ++) { 865 if ((MaxAlignment > mFfsValidAlign [Index]) && (MaxAlignment <= mFfsValidAlign [Index + 1])) { 866 break; 867 } 868 } 869 if (FfsAlign < Index) { 870 FfsAlign = Index; 871 } 872 VerboseMsg ("the alignment of the generated FFS file is %u", (unsigned) mFfsValidAlign [FfsAlign + 1]); 873 874 // 875 // Now FileSize includes the EFI_FFS_FILE_HEADER 876 // 877 if (FileSize + sizeof (EFI_FFS_FILE_HEADER) >= MAX_FFS_SIZE) { 878 HeaderSize = sizeof (EFI_FFS_FILE_HEADER2); 879 FileSize += sizeof (EFI_FFS_FILE_HEADER2); 880 FfsFileHeader.ExtendedSize = FileSize; 881 memset(FfsFileHeader.Size, 0, sizeof (UINT8) * 3); 882 FfsAttrib |= FFS_ATTRIB_LARGE_FILE; 883 } else { 884 HeaderSize = sizeof (EFI_FFS_FILE_HEADER); 885 FileSize += sizeof (EFI_FFS_FILE_HEADER); 886 FfsFileHeader.Size[0] = (UINT8) (FileSize & 0xFF); 887 FfsFileHeader.Size[1] = (UINT8) ((FileSize & 0xFF00) >> 8); 888 FfsFileHeader.Size[2] = (UINT8) ((FileSize & 0xFF0000) >> 16); 889 } 890 VerboseMsg ("the size of the generated FFS file is %u bytes", (unsigned) FileSize); 891 892 FfsFileHeader.Attributes = (EFI_FFS_FILE_ATTRIBUTES) (FfsAttrib | (FfsAlign << 3)); 893 894 // 895 // Fill in checksums and state, these must be zero for checksumming 896 // 897 // FileHeader.IntegrityCheck.Checksum.Header = 0; 898 // FileHeader.IntegrityCheck.Checksum.File = 0; 899 // FileHeader.State = 0; 900 // 901 FfsFileHeader.IntegrityCheck.Checksum.Header = CalculateChecksum8 ( 902 (UINT8 *) &FfsFileHeader, 903 HeaderSize 904 ); 905 906 if (FfsFileHeader.Attributes & FFS_ATTRIB_CHECKSUM) { 907 // 908 // Ffs header checksum = zero, so only need to calculate ffs body. 909 // 910 FfsFileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 ( 911 FileBuffer, 912 FileSize - HeaderSize 913 ); 914 } else { 915 FfsFileHeader.IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; 916 } 917 918 FfsFileHeader.State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID; 919 920 // 921 // Open output file to write ffs data. 922 // 923 if (OutputFileName != NULL) { 924 remove(OutputFileName); 925 FfsFile = fopen (LongFilePath (OutputFileName), "wb"); 926 if (FfsFile == NULL) { 927 Error (NULL, 0, 0001, "Error opening file", OutputFileName); 928 goto Finish; 929 } 930 // 931 // write header 932 // 933 fwrite (&FfsFileHeader, 1, HeaderSize, FfsFile); 934 // 935 // write data 936 // 937 if (FileBuffer != NULL) { 938 fwrite (FileBuffer, 1, FileSize - HeaderSize, FfsFile); 939 } 940 941 fclose (FfsFile); 942 } 943 944 Finish: 945 if (InputFileName != NULL) { 946 free (InputFileName); 947 } 948 if (InputFileAlign != NULL) { 949 free (InputFileAlign); 950 } 951 if (FileBuffer != NULL) { 952 free (FileBuffer); 953 } 954 // 955 // If any errors were reported via the standard error reporting 956 // routines, then the status has been saved. Get the value and 957 // return it to the caller. 958 // 959 VerboseMsg ("%s tool done with return code is 0x%x.", UTILITY_NAME, GetUtilityStatus ()); 960 961 return GetUtilityStatus (); 962 } 963