• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
Version(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
Usage(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
StringtoAlignment(IN CHAR8 * AlignBuffer,OUT UINT32 * AlignNumber)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
StringToType(IN CHAR8 * String)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
GetSectionContents(IN CHAR8 ** InputFileName,IN UINT32 * InputFileAlign,IN UINT32 InputFileNum,IN EFI_FFS_FILE_ATTRIBUTES FfsAttrib,OUT UINT8 * FileBuffer,OUT UINT32 * BufferLength,OUT UINT32 * MaxAlignment,OUT UINT8 * PESectionNum)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
main(int argc,CHAR8 * argv[])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