]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/GenFfs/GenFfs.c
Sync EDKII BaseTools to BaseTools project r1903.
[mirror_edk2.git] / BaseTools / Source / C / GenFfs / GenFfs.c
CommitLineData
30fdf114
LG
1/**\r
2\r
52302d4d 3Copyright (c) 2004-2010, Intel Corporation \r
30fdf114
LG
4All rights reserved. This program and the accompanying materials \r
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
90 fprintf (stdout, "%s Version %d.%d\n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION);\r
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
52302d4d 122 fprintf (stdout, "Copyright (c) 2007 - 2010, 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
287 EFI_COMMON_SECTION_HEADER TempSectHeader;\r
288 EFI_TE_IMAGE_HEADER TeHeader;\r
289 UINT32 TeOffset;\r
52302d4d
LG
290 EFI_GUID_DEFINED_SECTION GuidSectHeader;\r
291 UINT32 HeaderSize;\r
30fdf114
LG
292\r
293 Size = 0;\r
294 Offset = 0;\r
295 TeOffset = 0;\r
296\r
297 //\r
298 // Go through our array of file names and copy their contents\r
299 // to the output buffer.\r
300 //\r
301 for (Index = 0; Index < InputFileNum; Index++) {\r
302 //\r
303 // make sure section ends on a DWORD boundary\r
304 //\r
305 while ((Size & 0x03) != 0) {\r
306 Size++;\r
307 }\r
308 \r
309 //\r
310 // Get the Max alignment of all input file datas\r
311 //\r
312 if (*MaxAlignment < InputFileAlign [Index]) {\r
313 *MaxAlignment = InputFileAlign [Index];\r
314 }\r
315\r
316 // \r
317 // Open file and read contents\r
318 //\r
319 InFile = fopen (InputFileName[Index], "rb");\r
320 if (InFile == NULL) {\r
321 Error (NULL, 0, 0001, "Error opening file", InputFileName[Index]);\r
322 return EFI_ABORTED;\r
323 }\r
324\r
325 fseek (InFile, 0, SEEK_END);\r
326 FileSize = ftell (InFile);\r
327 fseek (InFile, 0, SEEK_SET);\r
328 DebugMsg (NULL, 0, 9, "Input section files", \r
fd171542 329 "the input section name is %s and the size is %u bytes", InputFileName[Index], (unsigned) FileSize); \r
30fdf114
LG
330\r
331 //\r
332 // Check this section is Te/Pe section, and Calculate the numbers of Te/Pe section.\r
333 //\r
334 TeOffset = 0;\r
52302d4d 335 HeaderSize = sizeof (EFI_COMMON_SECTION_HEADER);\r
30fdf114
LG
336 fread (&TempSectHeader, 1, sizeof (TempSectHeader), InFile);\r
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
347 fread (&GuidSectHeader, 1, sizeof (GuidSectHeader), InFile);\r
348 if ((GuidSectHeader.Attributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == 0) {\r
349 HeaderSize = GuidSectHeader.DataOffset;\r
350 }\r
351 (*PESectionNum) ++;\r
30fdf114 352 } else if (TempSectHeader.Type == EFI_SECTION_COMPRESSION || \r
30fdf114
LG
353 TempSectHeader.Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE) {\r
354 //\r
355 // for the encapsulated section, assume it contains Pe/Te section \r
356 //\r
357 (*PESectionNum) ++;\r
358 }\r
359\r
360 fseek (InFile, 0, SEEK_SET);\r
361\r
362 //\r
363 // Revert TeOffset to the converse value relative to Alignment\r
364 // This is to assure the original PeImage Header at Alignment.\r
365 //\r
366 if ((TeOffset != 0) && (InputFileAlign [Index] != 0)) {\r
367 TeOffset = InputFileAlign [Index] - (TeOffset % InputFileAlign [Index]);\r
368 TeOffset = TeOffset % InputFileAlign [Index];\r
369 }\r
52302d4d 370\r
30fdf114
LG
371 //\r
372 // make sure section data meet its alignment requirement by adding one raw pad section.\r
373 // But the different sections have the different section header. Necessary or not?\r
374 // Based on section type to adjust offset? Todo\r
375 //\r
52302d4d
LG
376 if ((InputFileAlign [Index] != 0) && (((Size + HeaderSize + TeOffset) % InputFileAlign [Index]) != 0)) {\r
377 Offset = (Size + sizeof (EFI_COMMON_SECTION_HEADER) + HeaderSize + TeOffset + InputFileAlign [Index] - 1) & ~(InputFileAlign [Index] - 1);\r
378 Offset = Offset - Size - HeaderSize - TeOffset;\r
30fdf114
LG
379 \r
380 if (FileBuffer != NULL && ((Size + Offset) < *BufferLength)) {\r
52302d4d 381 memset (FileBuffer + Size, 0, Offset);\r
30fdf114
LG
382 SectHeader = (EFI_COMMON_SECTION_HEADER *) (FileBuffer + Size);\r
383 SectHeader->Type = EFI_SECTION_RAW;\r
384 SectHeader->Size[0] = (UINT8) (Offset & 0xff);\r
385 SectHeader->Size[1] = (UINT8) ((Offset & 0xff00) >> 8);\r
386 SectHeader->Size[2] = (UINT8) ((Offset & 0xff0000) >> 16);\r
387 }\r
388 DebugMsg (NULL, 0, 9, "Pad raw section for section data alignment", \r
fd171542 389 "Pad Raw section size is %u", (unsigned) Offset);\r
30fdf114
LG
390\r
391 Size = Size + Offset;\r
392 }\r
393\r
394 //\r
395 // Now read the contents of the file into the buffer\r
396 // Buffer must be enough to contain the file content.\r
397 //\r
398 if ((FileSize > 0) && (FileBuffer != NULL) && ((Size + FileSize) <= *BufferLength)) {\r
399 if (fread (FileBuffer + Size, (size_t) FileSize, 1, InFile) != 1) {\r
400 Error (NULL, 0, 0004, "Error reading file", InputFileName[Index]);\r
401 fclose (InFile);\r
402 return EFI_ABORTED;\r
403 }\r
404 }\r
405\r
406 fclose (InFile);\r
407 Size += FileSize;\r
408 }\r
409 \r
410 //\r
411 // Set the actual length of the data.\r
412 //\r
413 if (Size > *BufferLength) {\r
414 *BufferLength = Size;\r
415 return EFI_BUFFER_TOO_SMALL;\r
416 } else {\r
417 *BufferLength = Size;\r
418 return EFI_SUCCESS;\r
419 }\r
420}\r
421\r
422int\r
423main (\r
fd171542 424 int argc,\r
30fdf114
LG
425 CHAR8 *argv[]\r
426 )\r
427/*++\r
428\r
429Routine Description:\r
430\r
431 Main function.\r
432\r
433Arguments:\r
434\r
435 argc - Number of command line parameters.\r
436 argv - Array of pointers to parameter strings.\r
437\r
438Returns:\r
439 STATUS_SUCCESS - Utility exits successfully.\r
440 STATUS_ERROR - Some error occurred during execution.\r
441\r
442--*/\r
443{\r
444 EFI_STATUS Status;\r
445 EFI_FFS_FILE_ATTRIBUTES FfsAttrib;\r
446 UINT32 FfsAlign;\r
447 EFI_FV_FILETYPE FfsFiletype;\r
448 CHAR8 *OutputFileName;\r
449 EFI_GUID FileGuid = {0};\r
450 UINT32 InputFileNum;\r
451 UINT32 *InputFileAlign;\r
452 CHAR8 **InputFileName;\r
453 UINT8 *FileBuffer;\r
454 UINT32 FileSize;\r
455 UINT32 MaxAlignment;\r
456 EFI_FFS_FILE_HEADER FfsFileHeader;\r
457 FILE *FfsFile;\r
458 UINT32 Index;\r
459 UINT64 LogLevel;\r
460 UINT8 PeSectionNum;\r
461 \r
462 //\r
463 // Init local variables\r
464 //\r
465 LogLevel = 0;\r
466 Index = 0;\r
467 FfsAttrib = 0; \r
468 FfsAlign = 0;\r
469 FfsFiletype = EFI_FV_FILETYPE_ALL;\r
470 OutputFileName = NULL;\r
471 InputFileNum = 0;\r
472 InputFileName = NULL;\r
473 InputFileAlign = NULL;\r
474 FileBuffer = NULL;\r
475 FileSize = 0;\r
476 MaxAlignment = 1;\r
477 FfsFile = NULL;\r
478 Status = EFI_SUCCESS;\r
479 PeSectionNum = 0;\r
480\r
481 SetUtilityName (UTILITY_NAME);\r
482\r
483 if (argc == 1) {\r
484 Error (NULL, 0, 1001, "Missing options", "no options input");\r
485 Usage ();\r
486 return STATUS_ERROR;\r
487 }\r
488\r
489 //\r
490 // Parse command line\r
491 //\r
492 argc --;\r
493 argv ++;\r
494\r
495 if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {\r
496 Version ();\r
497 Usage ();\r
498 return STATUS_SUCCESS; \r
499 }\r
500\r
501 if (stricmp (argv[0], "--version") == 0) {\r
502 Version ();\r
503 return STATUS_SUCCESS; \r
504 }\r
505\r
506 while (argc > 0) {\r
507 if ((stricmp (argv[0], "-t") == 0) || (stricmp (argv[0], "--filetype") == 0)) {\r
508 if (argv[1] == NULL || argv[1][0] == '-') {\r
509 Error (NULL, 0, 1003, "Invalid option value", "file type is missing for -t option");\r
510 goto Finish;\r
511 }\r
512 FfsFiletype = StringToType (argv[1]);\r
513 if (FfsFiletype == EFI_FV_FILETYPE_ALL) {\r
514 Error (NULL, 0, 1003, "Invalid option value", "%s is not a valid file type", argv[1]);\r
515 goto Finish;\r
516 }\r
517 argc -= 2;\r
518 argv += 2;\r
519 continue; \r
520 }\r
521\r
522 if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--outputfile") == 0)) {\r
523 if (argv[1] == NULL || argv[1][0] == '-') {\r
524 Error (NULL, 0, 1003, "Invalid option value", "Output file is missing for -o option");\r
525 goto Finish;\r
526 }\r
527 OutputFileName = argv[1];\r
528 argc -= 2;\r
529 argv += 2;\r
530 continue; \r
531 }\r
532\r
533 if ((stricmp (argv[0], "-g") == 0) || (stricmp (argv[0], "--fileguid") == 0)) {\r
534 Status = StringToGuid (argv[1], &FileGuid);\r
535 if (EFI_ERROR (Status)) {\r
536 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);\r
537 goto Finish;\r
538 }\r
539 argc -= 2;\r
540 argv += 2;\r
541 continue;\r
542 }\r
543\r
544 if ((stricmp (argv[0], "-x") == 0) || (stricmp (argv[0], "--fixed") == 0)) {\r
545 FfsAttrib |= FFS_ATTRIB_FIXED;\r
546 argc -= 1;\r
547 argv += 1;\r
548 continue;\r
549 }\r
550\r
551 if ((stricmp (argv[0], "-s") == 0) || (stricmp (argv[0], "--checksum") == 0)) {\r
552 FfsAttrib |= FFS_ATTRIB_CHECKSUM;\r
553 argc -= 1;\r
554 argv += 1;\r
555 continue;\r
556 }\r
557\r
558 if ((stricmp (argv[0], "-a") == 0) || (stricmp (argv[0], "--align") == 0)) {\r
559 if (argv[1] == NULL || argv[1][0] == '-') {\r
560 Error (NULL, 0, 1003, "Invalid option value", "Align value is missing for -a option");\r
561 goto Finish;\r
562 }\r
563 for (Index = 0; Index < sizeof (mFfsValidAlignName) / sizeof (CHAR8 *); Index ++) {\r
564 if (stricmp (argv[1], mFfsValidAlignName[Index]) == 0) {\r
565 break;\r
566 }\r
567 }\r
568 if (Index == sizeof (mFfsValidAlignName) / sizeof (CHAR8 *)) {\r
569 if ((stricmp (argv[1], "1") == 0) || (stricmp (argv[1], "2") == 0) || (stricmp (argv[1], "4") == 0)) {\r
570 //\r
571 // 1, 2, 4 byte alignment same to 8 byte alignment\r
572 //\r
573 Index = 0;\r
574 } else {\r
575 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);\r
576 goto Finish;\r
577 }\r
578 }\r
579 FfsAlign = Index;\r
580 argc -= 2;\r
581 argv += 2;\r
582 continue;\r
583 }\r
584\r
585 if ((stricmp (argv[0], "-i") == 0) || (stricmp (argv[0], "--sectionfile") == 0)) {\r
586 //\r
587 // Get Input file name and its alignment\r
588 //\r
589 if (argv[1] == NULL || argv[1][0] == '-') {\r
590 Error (NULL, 0, 1003, "Invalid option value", "input section file is missing for -i option");\r
591 goto Finish;\r
592 }\r
593\r
594 //\r
595 // Allocate Input file name buffer and its alignment buffer.\r
596 //\r
597 if ((InputFileNum == 0) && (InputFileName == NULL)) {\r
598 InputFileName = (CHAR8 **) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *));\r
599 if (InputFileName == NULL) {\r
600 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
601 return STATUS_ERROR;\r
602 }\r
603 memset (InputFileName, 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));\r
604 \r
605 InputFileAlign = (UINT32 *) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32));\r
606 if (InputFileAlign == NULL) {\r
607 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
608 free (InputFileName);\r
609 return STATUS_ERROR;\r
610 }\r
611 memset (InputFileAlign, 0, MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32));\r
612 } else if (InputFileNum % MAXIMUM_INPUT_FILE_NUM == 0) {\r
613 //\r
614 // InputFileName and alignment buffer too small, need to realloc\r
615 //\r
616 InputFileName = (CHAR8 **) realloc (\r
617 InputFileName,\r
618 (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (CHAR8 *)\r
619 );\r
620 \r
621 if (InputFileName == NULL) {\r
622 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
623 free (InputFileAlign);\r
624 return STATUS_ERROR;\r
625 }\r
626 memset (&(InputFileName[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));\r
627\r
628 InputFileAlign = (UINT32 *) realloc (\r
629 InputFileAlign,\r
630 (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (UINT32)\r
631 );\r
632 \r
633 if (InputFileAlign == NULL) {\r
634 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
635 free (InputFileName);\r
636 return STATUS_ERROR;\r
637 }\r
638 memset (&(InputFileAlign[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32)));\r
639 }\r
640 \r
641 InputFileName[InputFileNum] = argv[1];\r
642 argc -= 2;\r
643 argv += 2;\r
644\r
645 if (argc <= 0) {\r
646 InputFileNum ++;\r
647 break;\r
648 }\r
649 \r
650 //\r
651 // Section File alignment requirement\r
652 //\r
653 if ((stricmp (argv[0], "-n") == 0) || (stricmp (argv[0], "--sectionalign") == 0)) {\r
654 Status = StringtoAlignment (argv[1], &(InputFileAlign[InputFileNum]));\r
655 if (EFI_ERROR (Status)) {\r
656 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);\r
657 goto Finish;\r
658 }\r
659 argc -= 2;\r
660 argv += 2;\r
661 }\r
662 InputFileNum ++;\r
663 continue; \r
664 }\r
665\r
666 if ((stricmp (argv[0], "-n") == 0) || (stricmp (argv[0], "--sectionalign") == 0)) {\r
667 Error (NULL, 0, 1000, "Unknown option", "SectionAlign option must be specified with section file.");\r
668 goto Finish;\r
669 }\r
670\r
671 if ((stricmp (argv[0], "-v") == 0) || (stricmp (argv[0], "--verbose") == 0)) {\r
672 SetPrintLevel (VERBOSE_LOG_LEVEL);\r
673 VerboseMsg ("Verbose output Mode Set!");\r
674 argc --;\r
675 argv ++;\r
676 continue;\r
677 }\r
678\r
679 if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {\r
680 SetPrintLevel (KEY_LOG_LEVEL);\r
681 KeyMsg ("Quiet output Mode Set!");\r
682 argc --;\r
683 argv ++;\r
684 continue;\r
685 }\r
686\r
687 if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) {\r
688 Status = AsciiStringToUint64 (argv[1], FALSE, &LogLevel);\r
689 if (EFI_ERROR (Status)) {\r
690 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);\r
691 goto Finish;\r
692 }\r
693 if (LogLevel > 9) {\r
fd171542 694 Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, current input level is %d", (int) LogLevel);\r
30fdf114
LG
695 goto Finish;\r
696 }\r
697 SetPrintLevel (LogLevel);\r
698 DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[1]);\r
699 argc -= 2;\r
700 argv += 2;\r
701 continue;\r
702 }\r
703\r
704 Error (NULL, 0, 1000, "Unknown option", argv[0]);\r
705 goto Finish;\r
706 }\r
707\r
708 VerboseMsg ("%s tool start.", UTILITY_NAME);\r
709\r
710 //\r
711 // Check the complete input paramters.\r
712 //\r
713 if (FfsFiletype == EFI_FV_FILETYPE_ALL) {\r
714 Error (NULL, 0, 1001, "Missing option", "filetype");\r
715 goto Finish; \r
716 }\r
717\r
718 if (CompareGuid (&FileGuid, &mZeroGuid) == 0) {\r
719 Error (NULL, 0, 1001, "Missing option", "fileguid");\r
720 goto Finish; \r
721 }\r
722\r
723 if (InputFileNum == 0) {\r
724 Error (NULL, 0, 1001, "Missing option", "Input files");\r
725 goto Finish;\r
726 }\r
727 \r
728 //\r
729 // Output input parameter information\r
730 //\r
731 VerboseMsg ("Fv File type is %s", mFfsFileType [FfsFiletype]);\r
732 VerboseMsg ("Output file name is %s", OutputFileName);\r
733 VerboseMsg ("FFS File Guid is %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", \r
fd171542 734 (unsigned) FileGuid.Data1,\r
30fdf114
LG
735 FileGuid.Data2,\r
736 FileGuid.Data3,\r
737 FileGuid.Data4[0],\r
738 FileGuid.Data4[1],\r
739 FileGuid.Data4[2],\r
740 FileGuid.Data4[3],\r
741 FileGuid.Data4[4],\r
742 FileGuid.Data4[5],\r
743 FileGuid.Data4[6],\r
744 FileGuid.Data4[7]);\r
745 if ((FfsAttrib & FFS_ATTRIB_FIXED) != 0) {\r
746 VerboseMsg ("FFS File has the fixed file attribute");\r
747 }\r
748 if ((FfsAttrib & FFS_ATTRIB_CHECKSUM) != 0) {\r
749 VerboseMsg ("FFS File requires the checksum of the whole file");\r
750 }\r
751 VerboseMsg ("FFS file alignment is %s", mFfsValidAlignName[FfsAlign]);\r
752 for (Index = 0; Index < InputFileNum; Index ++) {\r
753 if (InputFileAlign[Index] == 0) {\r
754 //\r
755 // Minimum alignment is 1 byte.\r
756 //\r
757 InputFileAlign[Index] = 1;\r
758 }\r
fd171542 759 VerboseMsg ("the %dth input section name is %s and section alignment is %u", Index, InputFileName[Index], (unsigned) InputFileAlign[Index]);\r
30fdf114
LG
760 }\r
761 \r
762 //\r
763 // Calculate the size of all input section files.\r
764 // \r
765 Status = GetSectionContents (\r
766 InputFileName,\r
767 InputFileAlign,\r
768 InputFileNum,\r
769 FileBuffer,\r
770 &FileSize,\r
771 &MaxAlignment,\r
772 &PeSectionNum\r
773 );\r
774 \r
775 if ((FfsFiletype == EFI_FV_FILETYPE_SECURITY_CORE || \r
776 FfsFiletype == EFI_FV_FILETYPE_PEI_CORE ||\r
777 FfsFiletype == EFI_FV_FILETYPE_DXE_CORE) && (PeSectionNum != 1)) {\r
fd171542 778 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
779 goto Finish;\r
780 }\r
781 \r
782 if ((FfsFiletype == EFI_FV_FILETYPE_PEIM ||\r
783 FfsFiletype == EFI_FV_FILETYPE_DRIVER ||\r
784 FfsFiletype == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER ||\r
785 FfsFiletype == EFI_FV_FILETYPE_APPLICATION) && (PeSectionNum < 1)) {\r
786 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
787 goto Finish; \r
788 }\r
789\r
790 if (Status == EFI_BUFFER_TOO_SMALL) {\r
791 FileBuffer = (UINT8 *) malloc (FileSize);\r
792 if (FileBuffer == NULL) {\r
793 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
794 goto Finish;\r
795 }\r
796 memset (FileBuffer, 0, FileSize);\r
797 \r
798 //\r
799 // read all input file contents into a buffer\r
800 //\r
801 Status = GetSectionContents (\r
802 InputFileName,\r
803 InputFileAlign,\r
804 InputFileNum,\r
805 FileBuffer,\r
806 &FileSize,\r
807 &MaxAlignment,\r
808 &PeSectionNum\r
809 );\r
810 }\r
811\r
812 if (EFI_ERROR (Status)) {\r
813 goto Finish;\r
814 }\r
815 \r
816 //\r
817 // Create Ffs file header.\r
818 //\r
819 memset (&FfsFileHeader, 0, sizeof (EFI_FFS_FILE_HEADER));\r
820 memcpy (&FfsFileHeader.Name, &FileGuid, sizeof (EFI_GUID));\r
821 FfsFileHeader.Type = FfsFiletype;\r
822 //\r
823 // Update FFS Alignment based on the max alignment required by input section files \r
824 //\r
fd171542 825 VerboseMsg ("the max alignment of all input sections is %u", (unsigned) MaxAlignment); \r
30fdf114
LG
826 for (Index = 0; Index < sizeof (mFfsValidAlign) / sizeof (UINT32) - 1; Index ++) {\r
827 if ((MaxAlignment > mFfsValidAlign [Index]) && (MaxAlignment <= mFfsValidAlign [Index + 1])) {\r
828 break;\r
829 }\r
830 }\r
831 if (FfsAlign < Index) {\r
832 FfsAlign = Index;\r
833 }\r
fd171542 834 VerboseMsg ("the alignment of the generated FFS file is %u", (unsigned) mFfsValidAlign [FfsAlign + 1]); \r
835 FfsFileHeader.Attributes = (EFI_FFS_FILE_ATTRIBUTES) (FfsAttrib | (FfsAlign << 3));\r
30fdf114
LG
836 \r
837 //\r
838 // Now FileSize includes the EFI_FFS_FILE_HEADER\r
839 //\r
840 FileSize += sizeof (EFI_FFS_FILE_HEADER);\r
fd171542 841 VerboseMsg ("the size of the generated FFS file is %u bytes", (unsigned) FileSize);\r
30fdf114
LG
842 FfsFileHeader.Size[0] = (UINT8) (FileSize & 0xFF);\r
843 FfsFileHeader.Size[1] = (UINT8) ((FileSize & 0xFF00) >> 8);\r
844 FfsFileHeader.Size[2] = (UINT8) ((FileSize & 0xFF0000) >> 16);\r
845 //\r
846 // Fill in checksums and state, these must be zero for checksumming\r
847 //\r
848 // FileHeader.IntegrityCheck.Checksum.Header = 0;\r
849 // FileHeader.IntegrityCheck.Checksum.File = 0;\r
850 // FileHeader.State = 0;\r
851 //\r
852 FfsFileHeader.IntegrityCheck.Checksum.Header = CalculateChecksum8 (\r
853 (UINT8 *) &FfsFileHeader,\r
854 sizeof (EFI_FFS_FILE_HEADER)\r
855 );\r
856\r
857 if (FfsFileHeader.Attributes & FFS_ATTRIB_CHECKSUM) {\r
858 //\r
859 // Ffs header checksum = zero, so only need to calculate ffs body.\r
860 //\r
861 FfsFileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
862 FileBuffer, \r
863 FileSize - sizeof (EFI_FFS_FILE_HEADER)\r
864 ); \r
865 } else {\r
866 FfsFileHeader.IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
867 }\r
868\r
869 FfsFileHeader.State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;\r
870 \r
871 //\r
872 // Open output file to write ffs data.\r
873 //\r
874 remove(OutputFileName);\r
875 FfsFile = fopen (OutputFileName, "wb");\r
876 if (FfsFile == NULL) {\r
877 Error (NULL, 0, 0001, "Error opening file", OutputFileName);\r
878 goto Finish;\r
879 }\r
880 //\r
881 // write header\r
882 //\r
883 fwrite (&FfsFileHeader, 1, sizeof (FfsFileHeader), FfsFile);\r
884 //\r
885 // write data\r
886 //\r
887 fwrite (FileBuffer, 1, FileSize - sizeof (EFI_FFS_FILE_HEADER), FfsFile);\r
888\r
889 fclose (FfsFile);\r
890\r
891Finish:\r
892 if (InputFileName != NULL) {\r
893 free (InputFileName);\r
894 }\r
895 if (InputFileAlign != NULL) {\r
896 free (InputFileAlign);\r
897 }\r
898 if (FileBuffer != NULL) {\r
899 free (FileBuffer);\r
900 }\r
901 //\r
902 // If any errors were reported via the standard error reporting\r
903 // routines, then the status has been saved. Get the value and\r
904 // return it to the caller.\r
905 //\r
906 VerboseMsg ("%s tool done with return code is 0x%x.", UTILITY_NAME, GetUtilityStatus ());\r
907\r
908 return GetUtilityStatus ();\r
909}\r