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