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