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