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