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