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