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