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