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