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