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