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