]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/GenFfs/GenFfs.c
BaseTools: Clean up source files
[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
f7496d71
LG
4Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials\r
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
30fdf114 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 78STATIC\r
f7496d71 79VOID\r
30fdf114
LG
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
f7496d71 92\r
30fdf114
LG
93Returns:\r
94\r
95 None\r
f7496d71
LG
96\r
97--*/\r
30fdf114 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
f7496d71 127\r
30fdf114
LG
128 //\r
129 // Copyright declaration\r
f7496d71
LG
130 //\r
131 fprintf (stdout, "Copyright (c) 2007 - 2018, 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
f7496d71 239\r
30fdf114
LG
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
f7496d71 265\r
30fdf114 266Routine Description:\r
f7496d71 267\r
30fdf114
LG
268 Get the contents of all section files specified in InputFileName\r
269 into FileBuffer.\r
f7496d71 270\r
30fdf114 271Arguments:\r
f7496d71 272\r
30fdf114 273 InputFileName - Name of the input file.\r
f7496d71 274\r
30fdf114
LG
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
f7496d71 281 BufferLength - On input, this is size of the FileBuffer.\r
30fdf114
LG
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
f7496d71 285\r
30fdf114
LG
286 PeSectionNum - Calculate the number of Pe/Te Section in this FFS file.\r
287\r
288Returns:\r
f7496d71 289\r
30fdf114
LG
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
f7496d71
LG
326\r
327 //\r
30fdf114
LG
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
f7496d71
LG
339 DebugMsg (NULL, 0, 9, "Input section files",\r
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
f7496d71 374 } else if (TempSectHeader.Type == EFI_SECTION_COMPRESSION ||\r
30fdf114
LG
375 TempSectHeader.Type == EFI_SECTION_FIRMWARE_VOLUME_IMAGE) {\r
376 //\r
f7496d71 377 // for the encapsulated section, assume it contains Pe/Te section\r
30fdf114
LG
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
f7496d71 401\r
30fdf114 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 427 }\r
f7496d71 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 608 UINT32 Alignment;\r
33fc1fc4
HW
609 //\r
610 // Workaround for static code checkers.\r
611 // Ensures the size of 'AlignmentBuffer' can hold all the digits of an\r
612 // unsigned 32-bit integer plus the size unit character.\r
613 //\r
614 CHAR8 AlignmentBuffer[16];\r
f7496d71 615\r
30fdf114
LG
616 //\r
617 // Init local variables\r
618 //\r
619 LogLevel = 0;\r
620 Index = 0;\r
f7496d71 621 FfsAttrib = 0;\r
30fdf114
LG
622 FfsAlign = 0;\r
623 FfsFiletype = EFI_FV_FILETYPE_ALL;\r
624 OutputFileName = NULL;\r
625 InputFileNum = 0;\r
626 InputFileName = NULL;\r
627 InputFileAlign = NULL;\r
628 FileBuffer = NULL;\r
629 FileSize = 0;\r
630 MaxAlignment = 1;\r
631 FfsFile = NULL;\r
632 Status = EFI_SUCCESS;\r
633 PeSectionNum = 0;\r
634\r
635 SetUtilityName (UTILITY_NAME);\r
636\r
637 if (argc == 1) {\r
638 Error (NULL, 0, 1001, "Missing options", "no options input");\r
639 Usage ();\r
640 return STATUS_ERROR;\r
641 }\r
642\r
643 //\r
644 // Parse command line\r
645 //\r
646 argc --;\r
647 argv ++;\r
648\r
649 if ((stricmp (argv[0], "-h") == 0) || (stricmp (argv[0], "--help") == 0)) {\r
650 Version ();\r
651 Usage ();\r
f7496d71 652 return STATUS_SUCCESS;\r
30fdf114
LG
653 }\r
654\r
655 if (stricmp (argv[0], "--version") == 0) {\r
656 Version ();\r
f7496d71 657 return STATUS_SUCCESS;\r
30fdf114
LG
658 }\r
659\r
660 while (argc > 0) {\r
661 if ((stricmp (argv[0], "-t") == 0) || (stricmp (argv[0], "--filetype") == 0)) {\r
662 if (argv[1] == NULL || argv[1][0] == '-') {\r
663 Error (NULL, 0, 1003, "Invalid option value", "file type is missing for -t option");\r
664 goto Finish;\r
665 }\r
666 FfsFiletype = StringToType (argv[1]);\r
667 if (FfsFiletype == EFI_FV_FILETYPE_ALL) {\r
668 Error (NULL, 0, 1003, "Invalid option value", "%s is not a valid file type", argv[1]);\r
669 goto Finish;\r
670 }\r
671 argc -= 2;\r
672 argv += 2;\r
f7496d71 673 continue;\r
30fdf114
LG
674 }\r
675\r
676 if ((stricmp (argv[0], "-o") == 0) || (stricmp (argv[0], "--outputfile") == 0)) {\r
677 if (argv[1] == NULL || argv[1][0] == '-') {\r
678 Error (NULL, 0, 1003, "Invalid option value", "Output file is missing for -o option");\r
679 goto Finish;\r
680 }\r
681 OutputFileName = argv[1];\r
682 argc -= 2;\r
683 argv += 2;\r
f7496d71 684 continue;\r
30fdf114
LG
685 }\r
686\r
687 if ((stricmp (argv[0], "-g") == 0) || (stricmp (argv[0], "--fileguid") == 0)) {\r
688 Status = StringToGuid (argv[1], &FileGuid);\r
689 if (EFI_ERROR (Status)) {\r
690 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);\r
691 goto Finish;\r
692 }\r
693 argc -= 2;\r
694 argv += 2;\r
695 continue;\r
696 }\r
697\r
698 if ((stricmp (argv[0], "-x") == 0) || (stricmp (argv[0], "--fixed") == 0)) {\r
699 FfsAttrib |= FFS_ATTRIB_FIXED;\r
700 argc -= 1;\r
701 argv += 1;\r
702 continue;\r
703 }\r
704\r
705 if ((stricmp (argv[0], "-s") == 0) || (stricmp (argv[0], "--checksum") == 0)) {\r
706 FfsAttrib |= FFS_ATTRIB_CHECKSUM;\r
707 argc -= 1;\r
708 argv += 1;\r
709 continue;\r
710 }\r
711\r
712 if ((stricmp (argv[0], "-a") == 0) || (stricmp (argv[0], "--align") == 0)) {\r
713 if (argv[1] == NULL || argv[1][0] == '-') {\r
714 Error (NULL, 0, 1003, "Invalid option value", "Align value is missing for -a option");\r
715 goto Finish;\r
716 }\r
717 for (Index = 0; Index < sizeof (mFfsValidAlignName) / sizeof (CHAR8 *); Index ++) {\r
718 if (stricmp (argv[1], mFfsValidAlignName[Index]) == 0) {\r
719 break;\r
720 }\r
721 }\r
722 if (Index == sizeof (mFfsValidAlignName) / sizeof (CHAR8 *)) {\r
723 if ((stricmp (argv[1], "1") == 0) || (stricmp (argv[1], "2") == 0) || (stricmp (argv[1], "4") == 0)) {\r
724 //\r
725 // 1, 2, 4 byte alignment same to 8 byte alignment\r
726 //\r
727 Index = 0;\r
728 } else {\r
729 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);\r
730 goto Finish;\r
731 }\r
732 }\r
733 FfsAlign = Index;\r
734 argc -= 2;\r
735 argv += 2;\r
736 continue;\r
737 }\r
738\r
739 if ((stricmp (argv[0], "-i") == 0) || (stricmp (argv[0], "--sectionfile") == 0)) {\r
740 //\r
741 // Get Input file name and its alignment\r
742 //\r
743 if (argv[1] == NULL || argv[1][0] == '-') {\r
744 Error (NULL, 0, 1003, "Invalid option value", "input section file is missing for -i option");\r
745 goto Finish;\r
746 }\r
747\r
748 //\r
749 // Allocate Input file name buffer and its alignment buffer.\r
750 //\r
751 if ((InputFileNum == 0) && (InputFileName == NULL)) {\r
752 InputFileName = (CHAR8 **) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *));\r
753 if (InputFileName == NULL) {\r
754 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
755 return STATUS_ERROR;\r
756 }\r
757 memset (InputFileName, 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));\r
f7496d71 758\r
30fdf114
LG
759 InputFileAlign = (UINT32 *) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32));\r
760 if (InputFileAlign == NULL) {\r
761 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
762 free (InputFileName);\r
763 return STATUS_ERROR;\r
764 }\r
765 memset (InputFileAlign, 0, MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32));\r
766 } else if (InputFileNum % MAXIMUM_INPUT_FILE_NUM == 0) {\r
767 //\r
768 // InputFileName and alignment buffer too small, need to realloc\r
769 //\r
770 InputFileName = (CHAR8 **) realloc (\r
771 InputFileName,\r
772 (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (CHAR8 *)\r
773 );\r
f7496d71 774\r
30fdf114
LG
775 if (InputFileName == NULL) {\r
776 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
777 free (InputFileAlign);\r
778 return STATUS_ERROR;\r
779 }\r
780 memset (&(InputFileName[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));\r
781\r
782 InputFileAlign = (UINT32 *) realloc (\r
783 InputFileAlign,\r
784 (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (UINT32)\r
785 );\r
f7496d71 786\r
30fdf114
LG
787 if (InputFileAlign == NULL) {\r
788 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
789 free (InputFileName);\r
790 return STATUS_ERROR;\r
791 }\r
792 memset (&(InputFileAlign[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32)));\r
793 }\r
f7496d71 794\r
30fdf114
LG
795 InputFileName[InputFileNum] = argv[1];\r
796 argc -= 2;\r
797 argv += 2;\r
798\r
799 if (argc <= 0) {\r
f7496d71 800 InputFileNum ++;\r
30fdf114
LG
801 break;\r
802 }\r
f7496d71 803\r
30fdf114
LG
804 //\r
805 // Section File alignment requirement\r
806 //\r
807 if ((stricmp (argv[0], "-n") == 0) || (stricmp (argv[0], "--sectionalign") == 0)) {\r
f3d8e506
YZ
808 if ((argv[1] != NULL) && (stricmp("0", argv[1]) == 0)) {\r
809 Status = GetAlignmentFromFile(InputFileName[InputFileNum], &Alignment);\r
810 if (EFI_ERROR(Status)) {\r
811 Error (NULL, 0, 1003, "Fail to get Alignment from %s", InputFileName[InputFileNum]);\r
812 goto Finish;\r
813 }\r
814 if (Alignment < 0x400){\r
815 sprintf (AlignmentBuffer, "%d", Alignment);\r
816 }\r
817 else if (Alignment >= 0x400) {\r
818 if (Alignment >= 0x100000) {\r
819 sprintf (AlignmentBuffer, "%dM", Alignment/0x100000);\r
820 } else {\r
821 sprintf (AlignmentBuffer, "%dK", Alignment/0x400);\r
822 }\r
823 }\r
824 Status = StringtoAlignment (AlignmentBuffer, &(InputFileAlign[InputFileNum]));\r
825 }\r
826 else {\r
827 Status = StringtoAlignment (argv[1], &(InputFileAlign[InputFileNum]));\r
828 }\r
30fdf114
LG
829 if (EFI_ERROR (Status)) {\r
830 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);\r
831 goto Finish;\r
832 }\r
833 argc -= 2;\r
834 argv += 2;\r
835 }\r
836 InputFileNum ++;\r
f7496d71 837 continue;\r
30fdf114
LG
838 }\r
839\r
840 if ((stricmp (argv[0], "-n") == 0) || (stricmp (argv[0], "--sectionalign") == 0)) {\r
841 Error (NULL, 0, 1000, "Unknown option", "SectionAlign option must be specified with section file.");\r
842 goto Finish;\r
843 }\r
844\r
845 if ((stricmp (argv[0], "-v") == 0) || (stricmp (argv[0], "--verbose") == 0)) {\r
846 SetPrintLevel (VERBOSE_LOG_LEVEL);\r
847 VerboseMsg ("Verbose output Mode Set!");\r
848 argc --;\r
849 argv ++;\r
850 continue;\r
851 }\r
852\r
853 if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {\r
854 SetPrintLevel (KEY_LOG_LEVEL);\r
855 KeyMsg ("Quiet output Mode Set!");\r
856 argc --;\r
857 argv ++;\r
858 continue;\r
859 }\r
860\r
861 if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) {\r
862 Status = AsciiStringToUint64 (argv[1], FALSE, &LogLevel);\r
863 if (EFI_ERROR (Status)) {\r
864 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);\r
865 goto Finish;\r
866 }\r
867 if (LogLevel > 9) {\r
fd171542 868 Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, current input level is %d", (int) LogLevel);\r
30fdf114
LG
869 goto Finish;\r
870 }\r
871 SetPrintLevel (LogLevel);\r
872 DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[1]);\r
873 argc -= 2;\r
874 argv += 2;\r
875 continue;\r
876 }\r
877\r
13d79c29 878 Error (NULL, 0, 1000, "Unknown option", "%s", argv[0]);\r
30fdf114
LG
879 goto Finish;\r
880 }\r
881\r
882 VerboseMsg ("%s tool start.", UTILITY_NAME);\r
883\r
884 //\r
99e55970 885 // Check the complete input parameters.\r
30fdf114
LG
886 //\r
887 if (FfsFiletype == EFI_FV_FILETYPE_ALL) {\r
888 Error (NULL, 0, 1001, "Missing option", "filetype");\r
f7496d71 889 goto Finish;\r
30fdf114
LG
890 }\r
891\r
892 if (CompareGuid (&FileGuid, &mZeroGuid) == 0) {\r
893 Error (NULL, 0, 1001, "Missing option", "fileguid");\r
f7496d71 894 goto Finish;\r
30fdf114
LG
895 }\r
896\r
897 if (InputFileNum == 0) {\r
898 Error (NULL, 0, 1001, "Missing option", "Input files");\r
899 goto Finish;\r
900 }\r
f7496d71 901\r
30fdf114
LG
902 //\r
903 // Output input parameter information\r
904 //\r
905 VerboseMsg ("Fv File type is %s", mFfsFileType [FfsFiletype]);\r
906 VerboseMsg ("Output file name is %s", OutputFileName);\r
f7496d71 907 VerboseMsg ("FFS File Guid is %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",\r
fd171542 908 (unsigned) FileGuid.Data1,\r
30fdf114
LG
909 FileGuid.Data2,\r
910 FileGuid.Data3,\r
911 FileGuid.Data4[0],\r
912 FileGuid.Data4[1],\r
913 FileGuid.Data4[2],\r
914 FileGuid.Data4[3],\r
915 FileGuid.Data4[4],\r
916 FileGuid.Data4[5],\r
917 FileGuid.Data4[6],\r
918 FileGuid.Data4[7]);\r
919 if ((FfsAttrib & FFS_ATTRIB_FIXED) != 0) {\r
920 VerboseMsg ("FFS File has the fixed file attribute");\r
921 }\r
922 if ((FfsAttrib & FFS_ATTRIB_CHECKSUM) != 0) {\r
923 VerboseMsg ("FFS File requires the checksum of the whole file");\r
924 }\r
925 VerboseMsg ("FFS file alignment is %s", mFfsValidAlignName[FfsAlign]);\r
926 for (Index = 0; Index < InputFileNum; Index ++) {\r
927 if (InputFileAlign[Index] == 0) {\r
928 //\r
929 // Minimum alignment is 1 byte.\r
930 //\r
931 InputFileAlign[Index] = 1;\r
932 }\r
fd171542 933 VerboseMsg ("the %dth input section name is %s and section alignment is %u", Index, InputFileName[Index], (unsigned) InputFileAlign[Index]);\r
30fdf114 934 }\r
f7496d71 935\r
30fdf114
LG
936 //\r
937 // Calculate the size of all input section files.\r
f7496d71 938 //\r
30fdf114
LG
939 Status = GetSectionContents (\r
940 InputFileName,\r
941 InputFileAlign,\r
942 InputFileNum,\r
46d0f3f8 943 FfsAttrib,\r
30fdf114
LG
944 FileBuffer,\r
945 &FileSize,\r
946 &MaxAlignment,\r
947 &PeSectionNum\r
948 );\r
f7496d71
LG
949\r
950 if ((FfsFiletype == EFI_FV_FILETYPE_SECURITY_CORE ||\r
30fdf114
LG
951 FfsFiletype == EFI_FV_FILETYPE_PEI_CORE ||\r
952 FfsFiletype == EFI_FV_FILETYPE_DXE_CORE) && (PeSectionNum != 1)) {\r
fd171542 953 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
954 goto Finish;\r
955 }\r
f7496d71 956\r
30fdf114
LG
957 if ((FfsFiletype == EFI_FV_FILETYPE_PEIM ||\r
958 FfsFiletype == EFI_FV_FILETYPE_DRIVER ||\r
959 FfsFiletype == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER ||\r
960 FfsFiletype == EFI_FV_FILETYPE_APPLICATION) && (PeSectionNum < 1)) {\r
961 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
f7496d71 962 goto Finish;\r
30fdf114
LG
963 }\r
964\r
965 if (Status == EFI_BUFFER_TOO_SMALL) {\r
966 FileBuffer = (UINT8 *) malloc (FileSize);\r
967 if (FileBuffer == NULL) {\r
968 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
969 goto Finish;\r
970 }\r
971 memset (FileBuffer, 0, FileSize);\r
f7496d71 972\r
30fdf114
LG
973 //\r
974 // read all input file contents into a buffer\r
975 //\r
976 Status = GetSectionContents (\r
977 InputFileName,\r
978 InputFileAlign,\r
979 InputFileNum,\r
46d0f3f8 980 FfsAttrib,\r
30fdf114
LG
981 FileBuffer,\r
982 &FileSize,\r
983 &MaxAlignment,\r
984 &PeSectionNum\r
985 );\r
986 }\r
987\r
b390737a
HW
988 if (EFI_ERROR (Status)) {\r
989 goto Finish;\r
990 }\r
991\r
992 if (FileBuffer == NULL && FileSize != 0) {\r
993 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
30fdf114
LG
994 goto Finish;\r
995 }\r
f7496d71 996\r
30fdf114
LG
997 //\r
998 // Create Ffs file header.\r
999 //\r
e8a47801 1000 memset (&FfsFileHeader, 0, sizeof (EFI_FFS_FILE_HEADER2));\r
30fdf114
LG
1001 memcpy (&FfsFileHeader.Name, &FileGuid, sizeof (EFI_GUID));\r
1002 FfsFileHeader.Type = FfsFiletype;\r
1003 //\r
f7496d71 1004 // Update FFS Alignment based on the max alignment required by input section files\r
30fdf114 1005 //\r
f7496d71 1006 VerboseMsg ("the max alignment of all input sections is %u", (unsigned) MaxAlignment);\r
30fdf114
LG
1007 for (Index = 0; Index < sizeof (mFfsValidAlign) / sizeof (UINT32) - 1; Index ++) {\r
1008 if ((MaxAlignment > mFfsValidAlign [Index]) && (MaxAlignment <= mFfsValidAlign [Index + 1])) {\r
1009 break;\r
1010 }\r
1011 }\r
1012 if (FfsAlign < Index) {\r
1013 FfsAlign = Index;\r
1014 }\r
f7496d71
LG
1015 VerboseMsg ("the alignment of the generated FFS file is %u", (unsigned) mFfsValidAlign [FfsAlign + 1]);\r
1016\r
30fdf114
LG
1017 //\r
1018 // Now FileSize includes the EFI_FFS_FILE_HEADER\r
1019 //\r
e8a47801
LG
1020 if (FileSize + sizeof (EFI_FFS_FILE_HEADER) >= MAX_FFS_SIZE) {\r
1021 HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);\r
1022 FileSize += sizeof (EFI_FFS_FILE_HEADER2);\r
1023 FfsFileHeader.ExtendedSize = FileSize;\r
1024 memset(FfsFileHeader.Size, 0, sizeof (UINT8) * 3);\r
1025 FfsAttrib |= FFS_ATTRIB_LARGE_FILE;\r
1026 } else {\r
1027 HeaderSize = sizeof (EFI_FFS_FILE_HEADER);\r
1028 FileSize += sizeof (EFI_FFS_FILE_HEADER);\r
1029 FfsFileHeader.Size[0] = (UINT8) (FileSize & 0xFF);\r
1030 FfsFileHeader.Size[1] = (UINT8) ((FileSize & 0xFF00) >> 8);\r
1031 FfsFileHeader.Size[2] = (UINT8) ((FileSize & 0xFF0000) >> 16);\r
1032 }\r
fd171542 1033 VerboseMsg ("the size of the generated FFS file is %u bytes", (unsigned) FileSize);\r
e8a47801 1034\r
e921f58d
YZ
1035 //FfsAlign larger than 7, set FFS_ATTRIB_DATA_ALIGNMENT2\r
1036 if (FfsAlign < 8) {\r
1037 FfsFileHeader.Attributes = (EFI_FFS_FILE_ATTRIBUTES) (FfsAttrib | (FfsAlign << 3));\r
1038 } else {\r
1039 FfsFileHeader.Attributes = (EFI_FFS_FILE_ATTRIBUTES) (FfsAttrib | ((FfsAlign & 0x7) << 3) | FFS_ATTRIB_DATA_ALIGNMENT2);\r
1040 }\r
e8a47801 1041\r
30fdf114
LG
1042 //\r
1043 // Fill in checksums and state, these must be zero for checksumming\r
1044 //\r
1045 // FileHeader.IntegrityCheck.Checksum.Header = 0;\r
1046 // FileHeader.IntegrityCheck.Checksum.File = 0;\r
1047 // FileHeader.State = 0;\r
1048 //\r
1049 FfsFileHeader.IntegrityCheck.Checksum.Header = CalculateChecksum8 (\r
1050 (UINT8 *) &FfsFileHeader,\r
e8a47801 1051 HeaderSize\r
30fdf114
LG
1052 );\r
1053\r
1054 if (FfsFileHeader.Attributes & FFS_ATTRIB_CHECKSUM) {\r
1055 //\r
1056 // Ffs header checksum = zero, so only need to calculate ffs body.\r
1057 //\r
1058 FfsFileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
f7496d71 1059 FileBuffer,\r
e8a47801 1060 FileSize - HeaderSize\r
f7496d71 1061 );\r
30fdf114
LG
1062 } else {\r
1063 FfsFileHeader.IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
1064 }\r
1065\r
1066 FfsFileHeader.State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;\r
f7496d71 1067\r
30fdf114
LG
1068 //\r
1069 // Open output file to write ffs data.\r
1070 //\r
2cb87435
HW
1071 if (OutputFileName != NULL) {\r
1072 remove(OutputFileName);\r
1073 FfsFile = fopen (LongFilePath (OutputFileName), "wb");\r
1074 if (FfsFile == NULL) {\r
1075 Error (NULL, 0, 0001, "Error opening file", OutputFileName);\r
1076 goto Finish;\r
1077 }\r
1078 //\r
1079 // write header\r
1080 //\r
1081 fwrite (&FfsFileHeader, 1, HeaderSize, FfsFile);\r
1082 //\r
1083 // write data\r
1084 //\r
b390737a
HW
1085 if (FileBuffer != NULL) {\r
1086 fwrite (FileBuffer, 1, FileSize - HeaderSize, FfsFile);\r
1087 }\r
30fdf114 1088\r
2cb87435
HW
1089 fclose (FfsFile);\r
1090 }\r
30fdf114
LG
1091\r
1092Finish:\r
1093 if (InputFileName != NULL) {\r
1094 free (InputFileName);\r
1095 }\r
1096 if (InputFileAlign != NULL) {\r
1097 free (InputFileAlign);\r
1098 }\r
1099 if (FileBuffer != NULL) {\r
1100 free (FileBuffer);\r
1101 }\r
1102 //\r
1103 // If any errors were reported via the standard error reporting\r
1104 // routines, then the status has been saved. Get the value and\r
1105 // return it to the caller.\r
1106 //\r
1107 VerboseMsg ("%s tool done with return code is 0x%x.", UTILITY_NAME, GetUtilityStatus ());\r
1108\r
1109 return GetUtilityStatus ();\r
1110}\r