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