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