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