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