]> git.proxmox.com Git - mirror_edk2.git/blame - BaseTools/Source/C/GenFfs/GenFfs.c
BaseTools: Fixed issue in MultiThread Genfds function
[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 4Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
2e351cbe 5SPDX-License-Identifier: BSD-2-Clause-Patent\r
30fdf114 6\r
30fdf114
LG
7**/\r
8\r
f3d8e506
YZ
9#ifndef __GNUC__\r
10#include <windows.h>\r
11#include <io.h>\r
12#include <sys/types.h>\r
13#include <sys/stat.h>\r
14#endif\r
15\r
b1e27d17
FB
16#ifdef __GNUC__\r
17#include <unistd.h>\r
18#endif\r
19\r
30fdf114
LG
20#include <stdio.h>\r
21#include <stdlib.h>\r
22#include <string.h>\r
23\r
24#include <Common/UefiBaseTypes.h>\r
25#include <Common/PiFirmwareFile.h>\r
26#include <IndustryStandard/PeImage.h>\r
46d0f3f8 27#include <Guid/FfsSectionAlignmentPadding.h>\r
30fdf114
LG
28\r
29#include "CommonLib.h"\r
30#include "ParseInf.h"\r
31#include "EfiUtilityMsgs.h"\r
f3d8e506
YZ
32#include "FvLib.h"\r
33#include "PeCoffLib.h"\r
30fdf114
LG
34\r
35#define UTILITY_NAME "GenFfs"\r
36#define UTILITY_MAJOR_VERSION 0\r
37#define UTILITY_MINOR_VERSION 1\r
38\r
39STATIC CHAR8 *mFfsFileType[] = {\r
40 NULL, // 0x00\r
41 "EFI_FV_FILETYPE_RAW", // 0x01\r
42 "EFI_FV_FILETYPE_FREEFORM", // 0x02\r
43 "EFI_FV_FILETYPE_SECURITY_CORE", // 0x03\r
44 "EFI_FV_FILETYPE_PEI_CORE", // 0x04\r
45 "EFI_FV_FILETYPE_DXE_CORE", // 0x05\r
46 "EFI_FV_FILETYPE_PEIM", // 0x06\r
47 "EFI_FV_FILETYPE_DRIVER", // 0x07\r
48 "EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER", // 0x08\r
49 "EFI_FV_FILETYPE_APPLICATION", // 0x09\r
50 "EFI_FV_FILETYPE_SMM", // 0x0A\r
51 "EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE",// 0x0B\r
52 "EFI_FV_FILETYPE_COMBINED_SMM_DXE", // 0x0C\r
116f23e8
SV
53 "EFI_FV_FILETYPE_SMM_CORE", // 0x0D\r
54 "EFI_FV_FILETYPE_MM_STANDALONE", // 0x0E\r
55 "EFI_FV_FILETYPE_MM_CORE_STANDALONE" // 0x0F\r
56};\r
30fdf114
LG
57\r
58STATIC CHAR8 *mAlignName[] = {\r
59 "1", "2", "4", "8", "16", "32", "64", "128", "256", "512",\r
e921f58d
YZ
60 "1K", "2K", "4K", "8K", "16K", "32K", "64K", "128K", "256K",\r
61 "512K", "1M", "2M", "4M", "8M", "16M"\r
30fdf114
LG
62 };\r
63\r
64STATIC CHAR8 *mFfsValidAlignName[] = {\r
e921f58d
YZ
65 "8", "16", "128", "512", "1K", "4K", "32K", "64K", "128K","256K",\r
66 "512K", "1M", "2M", "4M", "8M", "16M"\r
30fdf114
LG
67 };\r
68\r
e921f58d
YZ
69STATIC UINT32 mFfsValidAlign[] = {0, 8, 16, 128, 512, 1024, 4096, 32768, 65536, 131072, 262144,\r
70 524288, 1048576, 2097152, 4194304, 8388608, 16777216};\r
30fdf114
LG
71\r
72STATIC EFI_GUID mZeroGuid = {0};\r
73\r
46d0f3f8
AB
74STATIC EFI_GUID mEfiFfsSectionAlignmentPaddingGuid = EFI_FFS_SECTION_ALIGNMENT_PADDING_GUID;\r
75\r
30fdf114 76STATIC\r
f7496d71 77VOID\r
30fdf114
LG
78Version (\r
79 VOID\r
80 )\r
81/*++\r
82\r
83Routine Description:\r
84\r
85 Print out version information for this utility.\r
86\r
87Arguments:\r
88\r
89 None\r
f7496d71 90\r
30fdf114
LG
91Returns:\r
92\r
93 None\r
f7496d71
LG
94\r
95--*/\r
30fdf114 96{\r
b36d134f 97 fprintf (stdout, "%s Version %d.%d %s \n", UTILITY_NAME, UTILITY_MAJOR_VERSION, UTILITY_MINOR_VERSION, __BUILD_VERSION);\r
30fdf114
LG
98}\r
99\r
100STATIC\r
101VOID\r
102Usage (\r
103 VOID\r
104 )\r
105/*++\r
106\r
107Routine Description:\r
108\r
109 Print Error / Help message.\r
110\r
111Arguments:\r
112\r
113 VOID\r
114\r
115Returns:\r
116\r
117 None\r
118\r
119--*/\r
120{\r
121 //\r
122 // Summary usage\r
123 //\r
124 fprintf (stdout, "\nUsage: %s [options]\n\n", UTILITY_NAME);\r
f7496d71 125\r
30fdf114
LG
126 //\r
127 // Copyright declaration\r
f7496d71
LG
128 //\r
129 fprintf (stdout, "Copyright (c) 2007 - 2018, Intel Corporation. All rights reserved.\n\n");\r
30fdf114
LG
130\r
131 //\r
132 // Details Option\r
133 //\r
134 fprintf (stdout, "Options:\n");\r
135 fprintf (stdout, " -o FileName, --outputfile FileName\n\\r
136 File is FFS file to be created.\n");\r
137 fprintf (stdout, " -t Type, --filetype Type\n\\r
138 Type is one FV file type defined in PI spec, which is\n\\r
139 EFI_FV_FILETYPE_RAW, EFI_FV_FILETYPE_FREEFORM,\n\\r
140 EFI_FV_FILETYPE_SECURITY_CORE, EFI_FV_FILETYPE_PEIM,\n\\r
141 EFI_FV_FILETYPE_PEI_CORE, EFI_FV_FILETYPE_DXE_CORE,\n\\r
142 EFI_FV_FILETYPE_DRIVER, EFI_FV_FILETYPE_APPLICATION,\n\\r
143 EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,\n\\r
b303ea72 144 EFI_FV_FILETYPE_SMM, EFI_FV_FILETYPE_SMM_CORE,\n\\r
116f23e8
SV
145 EFI_FV_FILETYPE_MM_STANDALONE,\n\\r
146 EFI_FV_FILETYPE_MM_CORE_STANDALONE,\n\\r
b303ea72 147 EFI_FV_FILETYPE_COMBINED_SMM_DXE, \n\\r
30fdf114
LG
148 EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE.\n");\r
149 fprintf (stdout, " -g FileGuid, --fileguid FileGuid\n\\r
150 FileGuid is one module guid.\n\\r
151 Its format is xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\n");\r
152 fprintf (stdout, " -x, --fixed Indicates that the file may not be moved\n\\r
153 from its present location.\n");\r
154 fprintf (stdout, " -s, --checksum Indicates to calculate file checksum.\n");\r
155 fprintf (stdout, " -a FileAlign, --align FileAlign\n\\r
156 FileAlign points to file alignment, which only support\n\\r
e921f58d
YZ
157 the following align: 1,2,4,8,16,128,512,1K,4K,32K,64K\n\\r
158 128K,256K,512K,1M,2M,4M,8M,16M\n");\r
30fdf114
LG
159 fprintf (stdout, " -i SectionFile, --sectionfile SectionFile\n\\r
160 Section file will be contained in this FFS file.\n");\r
b1e27d17
FB
161 fprintf (stdout, " -oi SectionFile, --optionalsectionfile SectionFile\n\\r
162 If the Section file exists, it will be contained in this FFS file, otherwise, it will be ignored.\n");\r
30fdf114
LG
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
b1e27d17 739 if ((stricmp (argv[0], "-oi") == 0) || (stricmp (argv[0], "--optionalsectionfile") == 0) || (stricmp (argv[0], "-i") == 0) || (stricmp (argv[0], "--sectionfile") == 0)) {\r
30fdf114
LG
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
b1e27d17
FB
747 if ((stricmp (argv[0], "-oi") == 0) || (stricmp (argv[0], "--optionalsectionfile") == 0) ){\r
748 if (-1 == access(argv[1] , 0)){\r
749 Warning(NULL, 0, 0001, "File is not found.", argv[1]);\r
750 argc -= 2;\r
751 argv += 2;\r
752 continue;\r
753 }\r
754 }\r
30fdf114
LG
755 //\r
756 // Allocate Input file name buffer and its alignment buffer.\r
757 //\r
758 if ((InputFileNum == 0) && (InputFileName == NULL)) {\r
759 InputFileName = (CHAR8 **) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *));\r
760 if (InputFileName == NULL) {\r
761 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
762 return STATUS_ERROR;\r
763 }\r
764 memset (InputFileName, 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));\r
f7496d71 765\r
30fdf114
LG
766 InputFileAlign = (UINT32 *) malloc (MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32));\r
767 if (InputFileAlign == NULL) {\r
768 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
769 free (InputFileName);\r
770 return STATUS_ERROR;\r
771 }\r
772 memset (InputFileAlign, 0, MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32));\r
773 } else if (InputFileNum % MAXIMUM_INPUT_FILE_NUM == 0) {\r
774 //\r
775 // InputFileName and alignment buffer too small, need to realloc\r
776 //\r
777 InputFileName = (CHAR8 **) realloc (\r
778 InputFileName,\r
779 (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (CHAR8 *)\r
780 );\r
f7496d71 781\r
30fdf114
LG
782 if (InputFileName == NULL) {\r
783 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
784 free (InputFileAlign);\r
785 return STATUS_ERROR;\r
786 }\r
787 memset (&(InputFileName[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (CHAR8 *)));\r
788\r
789 InputFileAlign = (UINT32 *) realloc (\r
790 InputFileAlign,\r
791 (InputFileNum + MAXIMUM_INPUT_FILE_NUM) * sizeof (UINT32)\r
792 );\r
f7496d71 793\r
30fdf114
LG
794 if (InputFileAlign == NULL) {\r
795 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
796 free (InputFileName);\r
797 return STATUS_ERROR;\r
798 }\r
799 memset (&(InputFileAlign[InputFileNum]), 0, (MAXIMUM_INPUT_FILE_NUM * sizeof (UINT32)));\r
800 }\r
f7496d71 801\r
30fdf114
LG
802 InputFileName[InputFileNum] = argv[1];\r
803 argc -= 2;\r
804 argv += 2;\r
805\r
806 if (argc <= 0) {\r
f7496d71 807 InputFileNum ++;\r
30fdf114
LG
808 break;\r
809 }\r
f7496d71 810\r
30fdf114
LG
811 //\r
812 // Section File alignment requirement\r
813 //\r
814 if ((stricmp (argv[0], "-n") == 0) || (stricmp (argv[0], "--sectionalign") == 0)) {\r
f3d8e506
YZ
815 if ((argv[1] != NULL) && (stricmp("0", argv[1]) == 0)) {\r
816 Status = GetAlignmentFromFile(InputFileName[InputFileNum], &Alignment);\r
817 if (EFI_ERROR(Status)) {\r
818 Error (NULL, 0, 1003, "Fail to get Alignment from %s", InputFileName[InputFileNum]);\r
819 goto Finish;\r
820 }\r
821 if (Alignment < 0x400){\r
822 sprintf (AlignmentBuffer, "%d", Alignment);\r
823 }\r
824 else if (Alignment >= 0x400) {\r
825 if (Alignment >= 0x100000) {\r
826 sprintf (AlignmentBuffer, "%dM", Alignment/0x100000);\r
827 } else {\r
828 sprintf (AlignmentBuffer, "%dK", Alignment/0x400);\r
829 }\r
830 }\r
831 Status = StringtoAlignment (AlignmentBuffer, &(InputFileAlign[InputFileNum]));\r
832 }\r
833 else {\r
834 Status = StringtoAlignment (argv[1], &(InputFileAlign[InputFileNum]));\r
835 }\r
30fdf114
LG
836 if (EFI_ERROR (Status)) {\r
837 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);\r
838 goto Finish;\r
839 }\r
840 argc -= 2;\r
841 argv += 2;\r
842 }\r
843 InputFileNum ++;\r
f7496d71 844 continue;\r
30fdf114
LG
845 }\r
846\r
847 if ((stricmp (argv[0], "-n") == 0) || (stricmp (argv[0], "--sectionalign") == 0)) {\r
848 Error (NULL, 0, 1000, "Unknown option", "SectionAlign option must be specified with section file.");\r
849 goto Finish;\r
850 }\r
851\r
852 if ((stricmp (argv[0], "-v") == 0) || (stricmp (argv[0], "--verbose") == 0)) {\r
853 SetPrintLevel (VERBOSE_LOG_LEVEL);\r
854 VerboseMsg ("Verbose output Mode Set!");\r
855 argc --;\r
856 argv ++;\r
857 continue;\r
858 }\r
859\r
860 if ((stricmp (argv[0], "-q") == 0) || (stricmp (argv[0], "--quiet") == 0)) {\r
861 SetPrintLevel (KEY_LOG_LEVEL);\r
862 KeyMsg ("Quiet output Mode Set!");\r
863 argc --;\r
864 argv ++;\r
865 continue;\r
866 }\r
867\r
868 if ((stricmp (argv[0], "-d") == 0) || (stricmp (argv[0], "--debug") == 0)) {\r
869 Status = AsciiStringToUint64 (argv[1], FALSE, &LogLevel);\r
870 if (EFI_ERROR (Status)) {\r
871 Error (NULL, 0, 1003, "Invalid option value", "%s = %s", argv[0], argv[1]);\r
872 goto Finish;\r
873 }\r
874 if (LogLevel > 9) {\r
fd171542 875 Error (NULL, 0, 1003, "Invalid option value", "Debug Level range is 0-9, current input level is %d", (int) LogLevel);\r
30fdf114
LG
876 goto Finish;\r
877 }\r
878 SetPrintLevel (LogLevel);\r
879 DebugMsg (NULL, 0, 9, "Debug Mode Set", "Debug Output Mode Level %s is set!", argv[1]);\r
880 argc -= 2;\r
881 argv += 2;\r
882 continue;\r
883 }\r
884\r
13d79c29 885 Error (NULL, 0, 1000, "Unknown option", "%s", argv[0]);\r
30fdf114
LG
886 goto Finish;\r
887 }\r
888\r
889 VerboseMsg ("%s tool start.", UTILITY_NAME);\r
890\r
891 //\r
99e55970 892 // Check the complete input parameters.\r
30fdf114
LG
893 //\r
894 if (FfsFiletype == EFI_FV_FILETYPE_ALL) {\r
895 Error (NULL, 0, 1001, "Missing option", "filetype");\r
f7496d71 896 goto Finish;\r
30fdf114
LG
897 }\r
898\r
899 if (CompareGuid (&FileGuid, &mZeroGuid) == 0) {\r
900 Error (NULL, 0, 1001, "Missing option", "fileguid");\r
f7496d71 901 goto Finish;\r
30fdf114
LG
902 }\r
903\r
904 if (InputFileNum == 0) {\r
905 Error (NULL, 0, 1001, "Missing option", "Input files");\r
906 goto Finish;\r
907 }\r
f7496d71 908\r
30fdf114
LG
909 //\r
910 // Output input parameter information\r
911 //\r
912 VerboseMsg ("Fv File type is %s", mFfsFileType [FfsFiletype]);\r
913 VerboseMsg ("Output file name is %s", OutputFileName);\r
f7496d71 914 VerboseMsg ("FFS File Guid is %08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",\r
fd171542 915 (unsigned) FileGuid.Data1,\r
30fdf114
LG
916 FileGuid.Data2,\r
917 FileGuid.Data3,\r
918 FileGuid.Data4[0],\r
919 FileGuid.Data4[1],\r
920 FileGuid.Data4[2],\r
921 FileGuid.Data4[3],\r
922 FileGuid.Data4[4],\r
923 FileGuid.Data4[5],\r
924 FileGuid.Data4[6],\r
925 FileGuid.Data4[7]);\r
926 if ((FfsAttrib & FFS_ATTRIB_FIXED) != 0) {\r
927 VerboseMsg ("FFS File has the fixed file attribute");\r
928 }\r
929 if ((FfsAttrib & FFS_ATTRIB_CHECKSUM) != 0) {\r
930 VerboseMsg ("FFS File requires the checksum of the whole file");\r
931 }\r
932 VerboseMsg ("FFS file alignment is %s", mFfsValidAlignName[FfsAlign]);\r
933 for (Index = 0; Index < InputFileNum; Index ++) {\r
934 if (InputFileAlign[Index] == 0) {\r
935 //\r
936 // Minimum alignment is 1 byte.\r
937 //\r
938 InputFileAlign[Index] = 1;\r
939 }\r
fd171542 940 VerboseMsg ("the %dth input section name is %s and section alignment is %u", Index, InputFileName[Index], (unsigned) InputFileAlign[Index]);\r
30fdf114 941 }\r
f7496d71 942\r
30fdf114
LG
943 //\r
944 // Calculate the size of all input section files.\r
f7496d71 945 //\r
30fdf114
LG
946 Status = GetSectionContents (\r
947 InputFileName,\r
948 InputFileAlign,\r
949 InputFileNum,\r
46d0f3f8 950 FfsAttrib,\r
30fdf114
LG
951 FileBuffer,\r
952 &FileSize,\r
953 &MaxAlignment,\r
954 &PeSectionNum\r
955 );\r
f7496d71
LG
956\r
957 if ((FfsFiletype == EFI_FV_FILETYPE_SECURITY_CORE ||\r
30fdf114
LG
958 FfsFiletype == EFI_FV_FILETYPE_PEI_CORE ||\r
959 FfsFiletype == EFI_FV_FILETYPE_DXE_CORE) && (PeSectionNum != 1)) {\r
fd171542 960 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
961 goto Finish;\r
962 }\r
f7496d71 963\r
30fdf114
LG
964 if ((FfsFiletype == EFI_FV_FILETYPE_PEIM ||\r
965 FfsFiletype == EFI_FV_FILETYPE_DRIVER ||\r
966 FfsFiletype == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER ||\r
967 FfsFiletype == EFI_FV_FILETYPE_APPLICATION) && (PeSectionNum < 1)) {\r
968 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 969 goto Finish;\r
30fdf114
LG
970 }\r
971\r
972 if (Status == EFI_BUFFER_TOO_SMALL) {\r
973 FileBuffer = (UINT8 *) malloc (FileSize);\r
974 if (FileBuffer == NULL) {\r
975 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
976 goto Finish;\r
977 }\r
978 memset (FileBuffer, 0, FileSize);\r
f7496d71 979\r
30fdf114
LG
980 //\r
981 // read all input file contents into a buffer\r
982 //\r
983 Status = GetSectionContents (\r
984 InputFileName,\r
985 InputFileAlign,\r
986 InputFileNum,\r
46d0f3f8 987 FfsAttrib,\r
30fdf114
LG
988 FileBuffer,\r
989 &FileSize,\r
990 &MaxAlignment,\r
991 &PeSectionNum\r
992 );\r
993 }\r
994\r
b390737a
HW
995 if (EFI_ERROR (Status)) {\r
996 goto Finish;\r
997 }\r
998\r
999 if (FileBuffer == NULL && FileSize != 0) {\r
1000 Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!");\r
30fdf114
LG
1001 goto Finish;\r
1002 }\r
f7496d71 1003\r
30fdf114
LG
1004 //\r
1005 // Create Ffs file header.\r
1006 //\r
e8a47801 1007 memset (&FfsFileHeader, 0, sizeof (EFI_FFS_FILE_HEADER2));\r
30fdf114
LG
1008 memcpy (&FfsFileHeader.Name, &FileGuid, sizeof (EFI_GUID));\r
1009 FfsFileHeader.Type = FfsFiletype;\r
1010 //\r
f7496d71 1011 // Update FFS Alignment based on the max alignment required by input section files\r
30fdf114 1012 //\r
f7496d71 1013 VerboseMsg ("the max alignment of all input sections is %u", (unsigned) MaxAlignment);\r
30fdf114
LG
1014 for (Index = 0; Index < sizeof (mFfsValidAlign) / sizeof (UINT32) - 1; Index ++) {\r
1015 if ((MaxAlignment > mFfsValidAlign [Index]) && (MaxAlignment <= mFfsValidAlign [Index + 1])) {\r
1016 break;\r
1017 }\r
1018 }\r
1019 if (FfsAlign < Index) {\r
1020 FfsAlign = Index;\r
1021 }\r
f7496d71
LG
1022 VerboseMsg ("the alignment of the generated FFS file is %u", (unsigned) mFfsValidAlign [FfsAlign + 1]);\r
1023\r
30fdf114
LG
1024 //\r
1025 // Now FileSize includes the EFI_FFS_FILE_HEADER\r
1026 //\r
e8a47801
LG
1027 if (FileSize + sizeof (EFI_FFS_FILE_HEADER) >= MAX_FFS_SIZE) {\r
1028 HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);\r
1029 FileSize += sizeof (EFI_FFS_FILE_HEADER2);\r
1030 FfsFileHeader.ExtendedSize = FileSize;\r
1031 memset(FfsFileHeader.Size, 0, sizeof (UINT8) * 3);\r
1032 FfsAttrib |= FFS_ATTRIB_LARGE_FILE;\r
1033 } else {\r
1034 HeaderSize = sizeof (EFI_FFS_FILE_HEADER);\r
1035 FileSize += sizeof (EFI_FFS_FILE_HEADER);\r
1036 FfsFileHeader.Size[0] = (UINT8) (FileSize & 0xFF);\r
1037 FfsFileHeader.Size[1] = (UINT8) ((FileSize & 0xFF00) >> 8);\r
1038 FfsFileHeader.Size[2] = (UINT8) ((FileSize & 0xFF0000) >> 16);\r
1039 }\r
fd171542 1040 VerboseMsg ("the size of the generated FFS file is %u bytes", (unsigned) FileSize);\r
e8a47801 1041\r
e921f58d
YZ
1042 //FfsAlign larger than 7, set FFS_ATTRIB_DATA_ALIGNMENT2\r
1043 if (FfsAlign < 8) {\r
1044 FfsFileHeader.Attributes = (EFI_FFS_FILE_ATTRIBUTES) (FfsAttrib | (FfsAlign << 3));\r
1045 } else {\r
1046 FfsFileHeader.Attributes = (EFI_FFS_FILE_ATTRIBUTES) (FfsAttrib | ((FfsAlign & 0x7) << 3) | FFS_ATTRIB_DATA_ALIGNMENT2);\r
1047 }\r
e8a47801 1048\r
30fdf114
LG
1049 //\r
1050 // Fill in checksums and state, these must be zero for checksumming\r
1051 //\r
1052 // FileHeader.IntegrityCheck.Checksum.Header = 0;\r
1053 // FileHeader.IntegrityCheck.Checksum.File = 0;\r
1054 // FileHeader.State = 0;\r
1055 //\r
1056 FfsFileHeader.IntegrityCheck.Checksum.Header = CalculateChecksum8 (\r
1057 (UINT8 *) &FfsFileHeader,\r
e8a47801 1058 HeaderSize\r
30fdf114
LG
1059 );\r
1060\r
1061 if (FfsFileHeader.Attributes & FFS_ATTRIB_CHECKSUM) {\r
1062 //\r
1063 // Ffs header checksum = zero, so only need to calculate ffs body.\r
1064 //\r
1065 FfsFileHeader.IntegrityCheck.Checksum.File = CalculateChecksum8 (\r
f7496d71 1066 FileBuffer,\r
e8a47801 1067 FileSize - HeaderSize\r
f7496d71 1068 );\r
30fdf114
LG
1069 } else {\r
1070 FfsFileHeader.IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;\r
1071 }\r
1072\r
1073 FfsFileHeader.State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;\r
f7496d71 1074\r
30fdf114
LG
1075 //\r
1076 // Open output file to write ffs data.\r
1077 //\r
2cb87435
HW
1078 if (OutputFileName != NULL) {\r
1079 remove(OutputFileName);\r
1080 FfsFile = fopen (LongFilePath (OutputFileName), "wb");\r
1081 if (FfsFile == NULL) {\r
1082 Error (NULL, 0, 0001, "Error opening file", OutputFileName);\r
1083 goto Finish;\r
1084 }\r
1085 //\r
1086 // write header\r
1087 //\r
1088 fwrite (&FfsFileHeader, 1, HeaderSize, FfsFile);\r
1089 //\r
1090 // write data\r
1091 //\r
b390737a
HW
1092 if (FileBuffer != NULL) {\r
1093 fwrite (FileBuffer, 1, FileSize - HeaderSize, FfsFile);\r
1094 }\r
30fdf114 1095\r
2cb87435
HW
1096 fclose (FfsFile);\r
1097 }\r
30fdf114
LG
1098\r
1099Finish:\r
1100 if (InputFileName != NULL) {\r
1101 free (InputFileName);\r
1102 }\r
1103 if (InputFileAlign != NULL) {\r
1104 free (InputFileAlign);\r
1105 }\r
1106 if (FileBuffer != NULL) {\r
1107 free (FileBuffer);\r
1108 }\r
1109 //\r
1110 // If any errors were reported via the standard error reporting\r
1111 // routines, then the status has been saved. Get the value and\r
1112 // return it to the caller.\r
1113 //\r
1114 VerboseMsg ("%s tool done with return code is 0x%x.", UTILITY_NAME, GetUtilityStatus ());\r
1115\r
1116 return GetUtilityStatus ();\r
1117}\r