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