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