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