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