1 /** @file
2 This file contains the internal functions required to generate a Firmware Volume.
3 
4 Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
5 Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution.  The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10 
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 //
17 // Include files
18 //
19 
20 #if defined(__FreeBSD__)
21 #include <uuid.h>
22 #elif defined(__GNUC__)
23 #include <uuid/uuid.h>
24 #endif
25 #ifdef __GNUC__
26 #include <sys/stat.h>
27 #endif
28 #include <string.h>
29 #ifndef __GNUC__
30 #include <io.h>
31 #endif
32 #include <assert.h>
33 
34 #include <Guid/FfsSectionAlignmentPadding.h>
35 
36 #include "GenFvInternalLib.h"
37 #include "FvLib.h"
38 #include "PeCoffLib.h"
39 #include "WinNtInclude.h"
40 
41 BOOLEAN mArm = FALSE;
42 STATIC UINT32   MaxFfsAlignment = 0;
43 
44 EFI_GUID  mEfiFirmwareVolumeTopFileGuid       = EFI_FFS_VOLUME_TOP_FILE_GUID;
45 EFI_GUID  mFileGuidArray [MAX_NUMBER_OF_FILES_IN_FV];
46 EFI_GUID  mZeroGuid                           = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};
47 EFI_GUID  mDefaultCapsuleGuid                 = {0x3B6686BD, 0x0D76, 0x4030, { 0xB7, 0x0E, 0xB5, 0x51, 0x9E, 0x2F, 0xC5, 0xA0 }};
48 EFI_GUID  mEfiFfsSectionAlignmentPaddingGuid  = EFI_FFS_SECTION_ALIGNMENT_PADDING_GUID;
49 
50 CHAR8      *mFvbAttributeName[] = {
51   EFI_FVB2_READ_DISABLED_CAP_STRING,
52   EFI_FVB2_READ_ENABLED_CAP_STRING,
53   EFI_FVB2_READ_STATUS_STRING,
54   EFI_FVB2_WRITE_DISABLED_CAP_STRING,
55   EFI_FVB2_WRITE_ENABLED_CAP_STRING,
56   EFI_FVB2_WRITE_STATUS_STRING,
57   EFI_FVB2_LOCK_CAP_STRING,
58   EFI_FVB2_LOCK_STATUS_STRING,
59   NULL,
60   EFI_FVB2_STICKY_WRITE_STRING,
61   EFI_FVB2_MEMORY_MAPPED_STRING,
62   EFI_FVB2_ERASE_POLARITY_STRING,
63   EFI_FVB2_READ_LOCK_CAP_STRING,
64   EFI_FVB2_READ_LOCK_STATUS_STRING,
65   EFI_FVB2_WRITE_LOCK_CAP_STRING,
66   EFI_FVB2_WRITE_LOCK_STATUS_STRING
67 };
68 
69 CHAR8      *mFvbAlignmentName[] = {
70   EFI_FVB2_ALIGNMENT_1_STRING,
71   EFI_FVB2_ALIGNMENT_2_STRING,
72   EFI_FVB2_ALIGNMENT_4_STRING,
73   EFI_FVB2_ALIGNMENT_8_STRING,
74   EFI_FVB2_ALIGNMENT_16_STRING,
75   EFI_FVB2_ALIGNMENT_32_STRING,
76   EFI_FVB2_ALIGNMENT_64_STRING,
77   EFI_FVB2_ALIGNMENT_128_STRING,
78   EFI_FVB2_ALIGNMENT_256_STRING,
79   EFI_FVB2_ALIGNMENT_512_STRING,
80   EFI_FVB2_ALIGNMENT_1K_STRING,
81   EFI_FVB2_ALIGNMENT_2K_STRING,
82   EFI_FVB2_ALIGNMENT_4K_STRING,
83   EFI_FVB2_ALIGNMENT_8K_STRING,
84   EFI_FVB2_ALIGNMENT_16K_STRING,
85   EFI_FVB2_ALIGNMENT_32K_STRING,
86   EFI_FVB2_ALIGNMENT_64K_STRING,
87   EFI_FVB2_ALIGNMENT_128K_STRING,
88   EFI_FVB2_ALIGNMENT_256K_STRING,
89   EFI_FVB2_ALIGNMENT_512K_STRING,
90   EFI_FVB2_ALIGNMENT_1M_STRING,
91   EFI_FVB2_ALIGNMENT_2M_STRING,
92   EFI_FVB2_ALIGNMENT_4M_STRING,
93   EFI_FVB2_ALIGNMENT_8M_STRING,
94   EFI_FVB2_ALIGNMENT_16M_STRING,
95   EFI_FVB2_ALIGNMENT_32M_STRING,
96   EFI_FVB2_ALIGNMENT_64M_STRING,
97   EFI_FVB2_ALIGNMENT_128M_STRING,
98   EFI_FVB2_ALIGNMENT_256M_STRING,
99   EFI_FVB2_ALIGNMENT_512M_STRING,
100   EFI_FVB2_ALIGNMENT_1G_STRING,
101   EFI_FVB2_ALIGNMENT_2G_STRING
102 };
103 
104 //
105 // This data array will be located at the base of the Firmware Volume Header (FVH)
106 // in the boot block.  It must not exceed 14 bytes of code.  The last 2 bytes
107 // will be used to keep the FVH checksum consistent.
108 // This code will be run in response to a starutp IPI for HT-enabled systems.
109 //
110 #define SIZEOF_STARTUP_DATA_ARRAY 0x10
111 
112 UINT8                                   m128kRecoveryStartupApDataArray[SIZEOF_STARTUP_DATA_ARRAY] = {
113   //
114   // EA D0 FF 00 F0               ; far jmp F000:FFD0
115   // 0, 0, 0, 0, 0, 0, 0, 0, 0,   ; Reserved bytes
116   // 0, 0                         ; Checksum Padding
117   //
118   0xEA,
119   0xD0,
120   0xFF,
121   0x0,
122   0xF0,
123   0x00,
124   0x00,
125   0x00,
126   0x00,
127   0x00,
128   0x00,
129   0x00,
130   0x00,
131   0x00,
132   0x00,
133   0x00
134 };
135 
136 UINT8                                   m64kRecoveryStartupApDataArray[SIZEOF_STARTUP_DATA_ARRAY] = {
137   //
138   // EB CE                               ; jmp short ($-0x30)
139   // ; (from offset 0x0 to offset 0xFFD0)
140   // 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ; Reserved bytes
141   // 0, 0                                ; Checksum Padding
142   //
143   0xEB,
144   0xCE,
145   0x00,
146   0x00,
147   0x00,
148   0x00,
149   0x00,
150   0x00,
151   0x00,
152   0x00,
153   0x00,
154   0x00,
155   0x00,
156   0x00,
157   0x00,
158   0x00
159 };
160 
161 FV_INFO                     mFvDataInfo;
162 CAP_INFO                    mCapDataInfo;
163 BOOLEAN                     mIsLargeFfs = FALSE;
164 
165 EFI_PHYSICAL_ADDRESS mFvBaseAddress[0x10];
166 UINT32               mFvBaseAddressNumber = 0;
167 
168 EFI_STATUS
ParseFvInf(IN MEMORY_FILE * InfFile,OUT FV_INFO * FvInfo)169 ParseFvInf (
170   IN  MEMORY_FILE  *InfFile,
171   OUT FV_INFO      *FvInfo
172   )
173 /*++
174 
175 Routine Description:
176 
177   This function parses a FV.INF file and copies info into a FV_INFO structure.
178 
179 Arguments:
180 
181   InfFile         Memory file image.
182   FvInfo          Information read from INF file.
183 
184 Returns:
185 
186   EFI_SUCCESS       INF file information successfully retrieved.
187   EFI_ABORTED       INF file has an invalid format.
188   EFI_NOT_FOUND     A required string was not found in the INF file.
189 --*/
190 {
191   CHAR8       Value[MAX_LONG_FILE_PATH];
192   UINT64      Value64;
193   UINTN       Index;
194   UINTN       Number;
195   EFI_STATUS  Status;
196   EFI_GUID    GuidValue;
197 
198   //
199   // Read the FV base address
200   //
201   if (!mFvDataInfo.BaseAddressSet) {
202     Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_BASE_ADDRESS_STRING, 0, Value);
203     if (Status == EFI_SUCCESS) {
204       //
205       // Get the base address
206       //
207       Status = AsciiStringToUint64 (Value, FALSE, &Value64);
208       if (EFI_ERROR (Status)) {
209         Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_FV_BASE_ADDRESS_STRING, Value);
210         return EFI_ABORTED;
211       }
212       DebugMsg (NULL, 0, 9, "rebase address", "%s = %s", EFI_FV_BASE_ADDRESS_STRING, Value);
213 
214       FvInfo->BaseAddress = Value64;
215       FvInfo->BaseAddressSet = TRUE;
216     }
217   }
218 
219   //
220   // Read the FV File System Guid
221   //
222   if (!FvInfo->FvFileSystemGuidSet) {
223     Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_FILESYSTEMGUID_STRING, 0, Value);
224     if (Status == EFI_SUCCESS) {
225       //
226       // Get the guid value
227       //
228       Status = StringToGuid (Value, &GuidValue);
229       if (EFI_ERROR (Status)) {
230         Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_FV_FILESYSTEMGUID_STRING, Value);
231         return EFI_ABORTED;
232       }
233       memcpy (&FvInfo->FvFileSystemGuid, &GuidValue, sizeof (EFI_GUID));
234       FvInfo->FvFileSystemGuidSet = TRUE;
235     }
236   }
237 
238   //
239   // Read the FV Extension Header File Name
240   //
241   Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FV_EXT_HEADER_FILE_NAME, 0, Value);
242   if (Status == EFI_SUCCESS) {
243     strcpy (FvInfo->FvExtHeaderFile, Value);
244   }
245 
246   //
247   // Read the FV file name
248   //
249   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FV_FILE_NAME_STRING, 0, Value);
250   if (Status == EFI_SUCCESS) {
251     //
252     // copy the file name
253     //
254     strcpy (FvInfo->FvName, Value);
255   }
256 
257   //
258   // Read Fv Attribute
259   //
260   for (Index = 0; Index < sizeof (mFvbAttributeName)/sizeof (CHAR8 *); Index ++) {
261     if ((mFvbAttributeName [Index] != NULL) && \
262         (FindToken (InfFile, ATTRIBUTES_SECTION_STRING, mFvbAttributeName [Index], 0, Value) == EFI_SUCCESS)) {
263       if ((strcmp (Value, TRUE_STRING) == 0) || (strcmp (Value, ONE_STRING) == 0)) {
264         FvInfo->FvAttributes |= 1 << Index;
265       } else if ((strcmp (Value, FALSE_STRING) != 0) && (strcmp (Value, ZERO_STRING) != 0)) {
266         Error (NULL, 0, 2000, "Invalid parameter", "%s expected %s | %s", mFvbAttributeName [Index], TRUE_STRING, FALSE_STRING);
267         return EFI_ABORTED;
268       }
269     }
270   }
271 
272   //
273   // Read Fv Alignment
274   //
275   for (Index = 0; Index < sizeof (mFvbAlignmentName)/sizeof (CHAR8 *); Index ++) {
276     if (FindToken (InfFile, ATTRIBUTES_SECTION_STRING, mFvbAlignmentName [Index], 0, Value) == EFI_SUCCESS) {
277       if (strcmp (Value, TRUE_STRING) == 0) {
278         FvInfo->FvAttributes |= Index << 16;
279         DebugMsg (NULL, 0, 9, "FV file alignment", "Align = %s", mFvbAlignmentName [Index]);
280         break;
281       }
282     }
283   }
284 
285   //
286   // Read weak alignment flag
287   //
288   Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FV_WEAK_ALIGNMENT_STRING, 0, Value);
289   if (Status == EFI_SUCCESS) {
290     if ((strcmp (Value, TRUE_STRING) == 0) || (strcmp (Value, ONE_STRING) == 0)) {
291       FvInfo->FvAttributes |= EFI_FVB2_WEAK_ALIGNMENT;
292     } else if ((strcmp (Value, FALSE_STRING) != 0) && (strcmp (Value, ZERO_STRING) != 0)) {
293       Error (NULL, 0, 2000, "Invalid parameter", "Weak alignment value expected one of TRUE, FALSE, 1 or 0.");
294       return EFI_ABORTED;
295     }
296   }
297 
298   //
299   // Read block maps
300   //
301   for (Index = 0; Index < MAX_NUMBER_OF_FV_BLOCKS; Index++) {
302     if (FvInfo->FvBlocks[Index].Length == 0) {
303       //
304       // Read block size
305       //
306       Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_BLOCK_SIZE_STRING, Index, Value);
307 
308       if (Status == EFI_SUCCESS) {
309         //
310         // Update the size of block
311         //
312         Status = AsciiStringToUint64 (Value, FALSE, &Value64);
313         if (EFI_ERROR (Status)) {
314           Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_BLOCK_SIZE_STRING, Value);
315           return EFI_ABORTED;
316         }
317 
318         FvInfo->FvBlocks[Index].Length = (UINT32) Value64;
319         DebugMsg (NULL, 0, 9, "FV Block Size", "%s = %s", EFI_BLOCK_SIZE_STRING, Value);
320       } else {
321         //
322         // If there is no blocks size, but there is the number of block, then we have a mismatched pair
323         // and should return an error.
324         //
325         Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_NUM_BLOCKS_STRING, Index, Value);
326         if (!EFI_ERROR (Status)) {
327           Error (NULL, 0, 2000, "Invalid parameter", "both %s and %s must be specified.", EFI_NUM_BLOCKS_STRING, EFI_BLOCK_SIZE_STRING);
328           return EFI_ABORTED;
329         } else {
330           //
331           // We are done
332           //
333           break;
334         }
335       }
336 
337       //
338       // Read blocks number
339       //
340       Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_NUM_BLOCKS_STRING, Index, Value);
341 
342       if (Status == EFI_SUCCESS) {
343         //
344         // Update the number of blocks
345         //
346         Status = AsciiStringToUint64 (Value, FALSE, &Value64);
347         if (EFI_ERROR (Status)) {
348           Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_NUM_BLOCKS_STRING, Value);
349           return EFI_ABORTED;
350         }
351 
352         FvInfo->FvBlocks[Index].NumBlocks = (UINT32) Value64;
353         DebugMsg (NULL, 0, 9, "FV Block Number", "%s = %s", EFI_NUM_BLOCKS_STRING, Value);
354       }
355     }
356   }
357 
358   if (Index == 0) {
359     Error (NULL, 0, 2001, "Missing required argument", "block size.");
360     return EFI_ABORTED;
361   }
362 
363   //
364   // Read files
365   //
366   Number = 0;
367   for (Number = 0; Number < MAX_NUMBER_OF_FILES_IN_FV; Number ++) {
368     if (FvInfo->FvFiles[Number][0] == '\0') {
369       break;
370     }
371   }
372 
373   for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_FV; Index++) {
374     //
375     // Read the FFS file list
376     //
377     Status = FindToken (InfFile, FILES_SECTION_STRING, EFI_FILE_NAME_STRING, Index, Value);
378 
379     if (Status == EFI_SUCCESS) {
380       //
381       // Add the file
382       //
383       strcpy (FvInfo->FvFiles[Number + Index], Value);
384       DebugMsg (NULL, 0, 9, "FV component file", "the %uth name is %s", (unsigned) Index, Value);
385     } else {
386       break;
387     }
388   }
389 
390   if ((Index + Number) == 0) {
391     Warning (NULL, 0, 0, "FV components are not specified.", NULL);
392   }
393 
394   return EFI_SUCCESS;
395 }
396 
397 VOID
UpdateFfsFileState(IN EFI_FFS_FILE_HEADER * FfsFile,IN EFI_FIRMWARE_VOLUME_HEADER * FvHeader)398 UpdateFfsFileState (
399   IN EFI_FFS_FILE_HEADER          *FfsFile,
400   IN EFI_FIRMWARE_VOLUME_HEADER   *FvHeader
401   )
402 /*++
403 
404 Routine Description:
405 
406   This function changes the FFS file attributes based on the erase polarity
407   of the FV. Update the reserved bits of State to EFI_FVB2_ERASE_POLARITY.
408 
409 Arguments:
410 
411   FfsFile   File header.
412   FvHeader  FV header.
413 
414 Returns:
415 
416   None
417 
418 --*/
419 {
420   if (FvHeader->Attributes & EFI_FVB2_ERASE_POLARITY) {
421     FfsFile->State = (UINT8)~(FfsFile->State);
422     // FfsFile->State |= ~(UINT8) EFI_FILE_ALL_STATE_BITS;
423   }
424 }
425 
426 EFI_STATUS
ReadFfsAlignment(IN EFI_FFS_FILE_HEADER * FfsFile,IN OUT UINT32 * Alignment)427 ReadFfsAlignment (
428   IN EFI_FFS_FILE_HEADER    *FfsFile,
429   IN OUT UINT32             *Alignment
430   )
431 /*++
432 
433 Routine Description:
434 
435   This function determines the alignment of the FFS input file from the file
436   attributes.
437 
438 Arguments:
439 
440   FfsFile       FFS file to parse
441   Alignment     The minimum required alignment offset of the FFS file
442 
443 Returns:
444 
445   EFI_SUCCESS              The function completed successfully.
446   EFI_INVALID_PARAMETER    One of the input parameters was invalid.
447   EFI_ABORTED              An error occurred.
448 
449 --*/
450 {
451   //
452   // Verify input parameters.
453   //
454   if (FfsFile == NULL || Alignment == NULL) {
455     return EFI_INVALID_PARAMETER;
456   }
457 
458   switch ((FfsFile->Attributes >> 3) & 0x07) {
459 
460   case 0:
461     //
462     // 1 byte alignment
463     //
464     *Alignment = 0;
465     break;
466 
467   case 1:
468     //
469     // 16 byte alignment
470     //
471     *Alignment = 4;
472     break;
473 
474   case 2:
475     //
476     // 128 byte alignment
477     //
478     *Alignment = 7;
479     break;
480 
481   case 3:
482     //
483     // 512 byte alignment
484     //
485     *Alignment = 9;
486     break;
487 
488   case 4:
489     //
490     // 1K byte alignment
491     //
492     *Alignment = 10;
493     break;
494 
495   case 5:
496     //
497     // 4K byte alignment
498     //
499     *Alignment = 12;
500     break;
501 
502   case 6:
503     //
504     // 32K byte alignment
505     //
506     *Alignment = 15;
507     break;
508 
509   case 7:
510     //
511     // 64K byte alignment
512     //
513     *Alignment = 16;
514     break;
515 
516   default:
517     break;
518   }
519 
520   return EFI_SUCCESS;
521 }
522 
523 EFI_STATUS
AddPadFile(IN OUT MEMORY_FILE * FvImage,IN UINT32 DataAlignment,IN VOID * FvEnd,IN EFI_FIRMWARE_VOLUME_EXT_HEADER * ExtHeader,IN UINT32 NextFfsSize)524 AddPadFile (
525   IN OUT MEMORY_FILE  *FvImage,
526   IN UINT32           DataAlignment,
527   IN VOID             *FvEnd,
528   IN EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtHeader,
529   IN UINT32           NextFfsSize
530   )
531 /*++
532 
533 Routine Description:
534 
535   This function adds a pad file to the FV image if it required to align the
536   data of the next file.
537 
538 Arguments:
539 
540   FvImage         The memory image of the FV to add it to.
541                   The current offset must be valid.
542   DataAlignment   The data alignment of the next FFS file.
543   FvEnd           End of the empty data in FvImage.
544   ExtHeader       PI FvExtHeader Optional
545 
546 Returns:
547 
548   EFI_SUCCESS              The function completed successfully.
549   EFI_INVALID_PARAMETER    One of the input parameters was invalid.
550   EFI_OUT_OF_RESOURCES     Insufficient resources exist in the FV to complete
551                            the pad file add.
552 
553 --*/
554 {
555   EFI_FFS_FILE_HEADER *PadFile;
556   UINTN               PadFileSize;
557   UINT32              NextFfsHeaderSize;
558   UINT32              CurFfsHeaderSize;
559 
560   CurFfsHeaderSize = sizeof (EFI_FFS_FILE_HEADER);
561   //
562   // Verify input parameters.
563   //
564   if (FvImage == NULL) {
565     return EFI_INVALID_PARAMETER;
566   }
567 
568   //
569   // Calculate the pad file size
570   //
571 
572   //
573   // Append extension header size
574   //
575   if (ExtHeader != NULL) {
576     PadFileSize = ExtHeader->ExtHeaderSize;
577     if (PadFileSize + sizeof (EFI_FFS_FILE_HEADER) >= MAX_FFS_SIZE) {
578       CurFfsHeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
579     }
580     PadFileSize += CurFfsHeaderSize;
581   } else {
582     NextFfsHeaderSize = sizeof (EFI_FFS_FILE_HEADER);
583     if (NextFfsSize >= MAX_FFS_SIZE) {
584       NextFfsHeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
585     }
586     //
587     // Check if a pad file is necessary
588     //
589     if (((UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + NextFfsHeaderSize) % DataAlignment == 0) {
590       return EFI_SUCCESS;
591     }
592     PadFileSize = (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + sizeof (EFI_FFS_FILE_HEADER) + NextFfsHeaderSize;
593     //
594     // Add whatever it takes to get to the next aligned address
595     //
596     while ((PadFileSize % DataAlignment) != 0) {
597       PadFileSize++;
598     }
599     //
600     // Subtract the next file header size
601     //
602     PadFileSize -= NextFfsHeaderSize;
603     //
604     // Subtract the starting offset to get size
605     //
606     PadFileSize -= (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage;
607   }
608 
609   //
610   // Verify that we have enough space for the file header
611   //
612   if (((UINTN) FvImage->CurrentFilePointer + PadFileSize) > (UINTN) FvEnd) {
613     return EFI_OUT_OF_RESOURCES;
614   }
615 
616   //
617   // Write pad file header
618   //
619   PadFile = (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer;
620 
621   //
622   // Write PadFile FFS header with PadType, don't need to set PAD file guid in its header.
623   //
624   PadFile->Type       = EFI_FV_FILETYPE_FFS_PAD;
625   PadFile->Attributes = 0;
626 
627   //
628   // Write pad file size (calculated size minus next file header size)
629   //
630   if (PadFileSize >= MAX_FFS_SIZE) {
631     memset(PadFile->Size, 0, sizeof(UINT8) * 3);
632     ((EFI_FFS_FILE_HEADER2 *)PadFile)->ExtendedSize = PadFileSize;
633     PadFile->Attributes |= FFS_ATTRIB_LARGE_FILE;
634   } else {
635     PadFile->Size[0]  = (UINT8) (PadFileSize & 0xFF);
636     PadFile->Size[1]  = (UINT8) ((PadFileSize >> 8) & 0xFF);
637     PadFile->Size[2]  = (UINT8) ((PadFileSize >> 16) & 0xFF);
638   }
639 
640   //
641   // Fill in checksums and state, they must be 0 for checksumming.
642   //
643   PadFile->IntegrityCheck.Checksum.Header = 0;
644   PadFile->IntegrityCheck.Checksum.File   = 0;
645   PadFile->State                          = 0;
646   PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, CurFfsHeaderSize);
647   PadFile->IntegrityCheck.Checksum.File   = FFS_FIXED_CHECKSUM;
648 
649   PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
650   UpdateFfsFileState (
651     (EFI_FFS_FILE_HEADER *) PadFile,
652     (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage
653     );
654 
655   //
656   // Update the current FV pointer
657   //
658   FvImage->CurrentFilePointer += PadFileSize;
659 
660   if (ExtHeader != NULL) {
661     //
662     // Copy Fv Extension Header and Set Fv Extension header offset
663     //
664     memcpy ((UINT8 *)PadFile + CurFfsHeaderSize, ExtHeader, ExtHeader->ExtHeaderSize);
665     ((EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage)->ExtHeaderOffset = (UINT16) ((UINTN) ((UINT8 *)PadFile + CurFfsHeaderSize) - (UINTN) FvImage->FileImage);
666 	  //
667 	  // Make next file start at QWord Boundry
668 	  //
669 	  while (((UINTN) FvImage->CurrentFilePointer & (EFI_FFS_FILE_HEADER_ALIGNMENT - 1)) != 0) {
670 	    FvImage->CurrentFilePointer++;
671 	  }
672   }
673 
674   return EFI_SUCCESS;
675 }
676 
677 BOOLEAN
IsVtfFile(IN EFI_FFS_FILE_HEADER * FileBuffer)678 IsVtfFile (
679   IN EFI_FFS_FILE_HEADER    *FileBuffer
680   )
681 /*++
682 
683 Routine Description:
684 
685   This function checks the header to validate if it is a VTF file
686 
687 Arguments:
688 
689   FileBuffer     Buffer in which content of a file has been read.
690 
691 Returns:
692 
693   TRUE    If this is a VTF file
694   FALSE   If this is not a VTF file
695 
696 --*/
697 {
698   if (!memcmp (&FileBuffer->Name, &mEfiFirmwareVolumeTopFileGuid, sizeof (EFI_GUID))) {
699     return TRUE;
700   } else {
701     return FALSE;
702   }
703 }
704 
705 EFI_STATUS
WriteMapFile(IN OUT FILE * FvMapFile,IN CHAR8 * FileName,IN EFI_FFS_FILE_HEADER * FfsFile,IN EFI_PHYSICAL_ADDRESS ImageBaseAddress,IN PE_COFF_LOADER_IMAGE_CONTEXT * pImageContext)706 WriteMapFile (
707   IN OUT FILE                  *FvMapFile,
708   IN     CHAR8                 *FileName,
709   IN     EFI_FFS_FILE_HEADER   *FfsFile,
710   IN     EFI_PHYSICAL_ADDRESS  ImageBaseAddress,
711   IN     PE_COFF_LOADER_IMAGE_CONTEXT *pImageContext
712   )
713 /*++
714 
715 Routine Description:
716 
717   This function gets the basic debug information (entrypoint, baseaddress, .text, .data section base address)
718   from PE/COFF image and abstracts Pe Map file information and add them into FvMap file for Debug.
719 
720 Arguments:
721 
722   FvMapFile             A pointer to FvMap File
723   FileName              Ffs File PathName
724   FfsFile               A pointer to Ffs file image.
725   ImageBaseAddress      PeImage Base Address.
726   pImageContext         Image Context Information.
727 
728 Returns:
729 
730   EFI_SUCCESS           Added required map information.
731 
732 --*/
733 {
734   CHAR8                               PeMapFileName [MAX_LONG_FILE_PATH];
735   CHAR8                               *Cptr, *Cptr2;
736   CHAR8                               FileGuidName [MAX_LINE_LEN];
737   FILE                                *PeMapFile;
738   CHAR8                               Line [MAX_LINE_LEN];
739   CHAR8                               KeyWord [MAX_LINE_LEN];
740   CHAR8                               FunctionName [MAX_LINE_LEN];
741   EFI_PHYSICAL_ADDRESS                FunctionAddress;
742   UINT32                              FunctionType;
743   CHAR8                               FunctionTypeName [MAX_LINE_LEN];
744   UINT32                              Index;
745   UINT32                              AddressOfEntryPoint;
746   UINT32                              Offset;
747   EFI_IMAGE_OPTIONAL_HEADER_UNION     *ImgHdr;
748   EFI_TE_IMAGE_HEADER                 *TEImageHeader;
749   EFI_IMAGE_SECTION_HEADER            *SectionHeader;
750   unsigned long long                  TempLongAddress;
751   UINT32                              TextVirtualAddress;
752   UINT32                              DataVirtualAddress;
753   EFI_PHYSICAL_ADDRESS                LinkTimeBaseAddress;
754 
755   //
756   // Init local variable
757   //
758   FunctionType = 0;
759   //
760   // Print FileGuid to string buffer.
761   //
762   PrintGuidToBuffer (&FfsFile->Name, (UINT8 *)FileGuidName, MAX_LINE_LEN, TRUE);
763 
764   //
765   // Construct Map file Name
766   //
767   strcpy (PeMapFileName, FileName);
768 
769   //
770   // Change '\\' to '/', unified path format.
771   //
772   Cptr = PeMapFileName;
773   while (*Cptr != '\0') {
774     if (*Cptr == '\\') {
775       *Cptr = FILE_SEP_CHAR;
776     }
777     Cptr ++;
778   }
779 
780   //
781   // Get Map file
782   //
783   Cptr = PeMapFileName + strlen (PeMapFileName);
784   while ((*Cptr != '.') && (Cptr >= PeMapFileName)) {
785     Cptr --;
786   }
787   if (Cptr < PeMapFileName) {
788     return EFI_NOT_FOUND;
789   } else {
790     *(Cptr + 1) = 'm';
791     *(Cptr + 2) = 'a';
792     *(Cptr + 3) = 'p';
793     *(Cptr + 4) = '\0';
794   }
795 
796   //
797   // Get module Name
798   //
799   Cptr2 = Cptr;
800   while ((*Cptr != FILE_SEP_CHAR) && (Cptr >= PeMapFileName)) {
801     Cptr --;
802   }
803 	*Cptr2 = '\0';
804 	strcpy (KeyWord, Cptr + 1);
805 	*Cptr2 = '.';
806 
807   //
808   // AddressOfEntryPoint and Offset in Image
809   //
810   if (!pImageContext->IsTeImage) {
811   	ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) pImageContext->Handle + pImageContext->PeCoffHeaderOffset);
812   	AddressOfEntryPoint = ImgHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
813   	Offset = 0;
814     SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (
815                        (UINT8 *) ImgHdr +
816                        sizeof (UINT32) +
817                        sizeof (EFI_IMAGE_FILE_HEADER) +
818                        ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
819                        );
820     Index = ImgHdr->Pe32.FileHeader.NumberOfSections;
821   } else {
822   	TEImageHeader = (EFI_TE_IMAGE_HEADER *) pImageContext->Handle;
823     AddressOfEntryPoint = TEImageHeader->AddressOfEntryPoint;
824     Offset = TEImageHeader->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER);
825     SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (TEImageHeader + 1);
826     Index = TEImageHeader->NumberOfSections;
827   }
828 
829   //
830   // module information output
831   //
832   if (ImageBaseAddress == 0) {
833     fprintf (FvMapFile, "%s (dummy) (", KeyWord);
834     fprintf (FvMapFile, "BaseAddress=%010llx, ", (unsigned long long) ImageBaseAddress);
835   } else {
836     fprintf (FvMapFile, "%s (Fixed Flash Address, ", KeyWord);
837     fprintf (FvMapFile, "BaseAddress=0x%010llx, ", (unsigned long long) (ImageBaseAddress + Offset));
838   }
839 
840   if (FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE && pImageContext->Machine == EFI_IMAGE_MACHINE_IA64) {
841     //
842     // Process IPF PLABEL to get the real address after the image has been rebased.
843     // PLABEL structure is got by AddressOfEntryPoint offset to ImageBuffer stored in pImageContext->Handle.
844     //
845     fprintf (FvMapFile, "EntryPoint=0x%010llx", (unsigned long long) (*(UINT64 *)((UINTN) pImageContext->Handle + (UINTN) AddressOfEntryPoint)));
846   } else {
847     fprintf (FvMapFile, "EntryPoint=0x%010llx", (unsigned long long) (ImageBaseAddress + AddressOfEntryPoint));
848   }
849   fprintf (FvMapFile, ")\n");
850 
851   fprintf (FvMapFile, "(GUID=%s", FileGuidName);
852   TextVirtualAddress = 0;
853   DataVirtualAddress = 0;
854   for (; Index > 0; Index --, SectionHeader ++) {
855     if (stricmp ((CHAR8 *)SectionHeader->Name, ".text") == 0) {
856   		TextVirtualAddress = SectionHeader->VirtualAddress;
857   	} else if (stricmp ((CHAR8 *)SectionHeader->Name, ".data") == 0) {
858   	  DataVirtualAddress = SectionHeader->VirtualAddress;
859   	} else if (stricmp ((CHAR8 *)SectionHeader->Name, ".sdata") == 0) {
860   	  DataVirtualAddress = SectionHeader->VirtualAddress;
861   	}
862   }
863   fprintf (FvMapFile, " .textbaseaddress=0x%010llx", (unsigned long long) (ImageBaseAddress + TextVirtualAddress));
864   fprintf (FvMapFile, " .databaseaddress=0x%010llx", (unsigned long long) (ImageBaseAddress + DataVirtualAddress));
865   fprintf (FvMapFile, ")\n\n");
866 
867   //
868   // Open PeMapFile
869   //
870   PeMapFile = fopen (LongFilePath (PeMapFileName), "r");
871   if (PeMapFile == NULL) {
872     // fprintf (stdout, "can't open %s file to reading\n", PeMapFileName);
873     return EFI_ABORTED;
874   }
875   VerboseMsg ("The map file is %s", PeMapFileName);
876 
877   //
878   // Output Functions information into Fv Map file
879   //
880   LinkTimeBaseAddress = 0;
881   while (fgets (Line, MAX_LINE_LEN, PeMapFile) != NULL) {
882     //
883     // Skip blank line
884     //
885     if (Line[0] == 0x0a) {
886       FunctionType = 0;
887       continue;
888     }
889     //
890     // By Address and Static keyword
891     //
892     if (FunctionType == 0) {
893       sscanf (Line, "%s", KeyWord);
894       if (stricmp (KeyWord, "Address") == 0) {
895         //
896         // function list
897         //
898         FunctionType = 1;
899         fgets (Line, MAX_LINE_LEN, PeMapFile);
900       } else if (stricmp (KeyWord, "Static") == 0) {
901         //
902         // static function list
903         //
904         FunctionType = 2;
905         fgets (Line, MAX_LINE_LEN, PeMapFile);
906       } else if (stricmp (KeyWord, "Preferred") ==0) {
907         sscanf (Line + strlen (" Preferred load address is"), "%llx", &TempLongAddress);
908         LinkTimeBaseAddress = (UINT64) TempLongAddress;
909       }
910       continue;
911     }
912     //
913     // Printf Function Information
914     //
915     if (FunctionType == 1) {
916       sscanf (Line, "%s %s %llx %s", KeyWord, FunctionName, &TempLongAddress, FunctionTypeName);
917       FunctionAddress = (UINT64) TempLongAddress;
918       if (FunctionTypeName [1] == '\0' && (FunctionTypeName [0] == 'f' || FunctionTypeName [0] == 'F')) {
919         fprintf (FvMapFile, "  0x%010llx    ", (unsigned long long) (ImageBaseAddress + FunctionAddress - LinkTimeBaseAddress));
920         fprintf (FvMapFile, "%s\n", FunctionName);
921       }
922     } else if (FunctionType == 2) {
923       sscanf (Line, "%s %s %llx %s", KeyWord, FunctionName, &TempLongAddress, FunctionTypeName);
924       FunctionAddress = (UINT64) TempLongAddress;
925       if (FunctionTypeName [1] == '\0' && (FunctionTypeName [0] == 'f' || FunctionTypeName [0] == 'F')) {
926         fprintf (FvMapFile, "  0x%010llx    ", (unsigned long long) (ImageBaseAddress + FunctionAddress - LinkTimeBaseAddress));
927         fprintf (FvMapFile, "%s\n", FunctionName);
928       }
929     }
930   }
931   //
932   // Close PeMap file
933   //
934   fprintf (FvMapFile, "\n\n");
935   fclose (PeMapFile);
936 
937   return EFI_SUCCESS;
938 }
939 
940 STATIC
941 BOOLEAN
AdjustInternalFfsPadding(IN OUT EFI_FFS_FILE_HEADER * FfsFile,IN OUT MEMORY_FILE * FvImage,IN UINTN Alignment,IN OUT UINTN * FileSize)942 AdjustInternalFfsPadding (
943   IN OUT  EFI_FFS_FILE_HEADER   *FfsFile,
944   IN OUT  MEMORY_FILE           *FvImage,
945   IN      UINTN                 Alignment,
946   IN OUT  UINTN                 *FileSize
947   )
948 /*++
949 
950 Routine Description:
951 
952   This function looks for a dedicated alignment padding section in the FFS, and
953   shrinks it to the size required to line up subsequent sections correctly.
954 
955 Arguments:
956 
957   FfsFile               A pointer to Ffs file image.
958   FvImage               The memory image of the FV to adjust it to.
959   Alignment             Current file alignment
960   FileSize              Reference to a variable holding the size of the FFS file
961 
962 Returns:
963 
964   TRUE                  Padding section was found and updated successfully
965   FALSE                 Otherwise
966 
967 --*/
968 {
969   EFI_FILE_SECTION_POINTER  PadSection;
970   UINT8                     *Remainder;
971   EFI_STATUS                Status;
972   UINT32                    FfsHeaderLength;
973   UINT32                    FfsFileLength;
974   UINT32                    PadSize;
975   UINTN                     Misalignment;
976   EFI_FFS_INTEGRITY_CHECK   *IntegrityCheck;
977 
978   //
979   // Figure out the misalignment: all FFS sections are aligned relative to the
980   // start of the FFS payload, so use that as the base of the misalignment
981   // computation.
982   //
983   FfsHeaderLength = GetFfsHeaderLength(FfsFile);
984   Misalignment = (UINTN) FvImage->CurrentFilePointer -
985                  (UINTN) FvImage->FileImage + FfsHeaderLength;
986   Misalignment &= Alignment - 1;
987   if (Misalignment == 0) {
988     // Nothing to do, return success
989     return TRUE;
990   }
991 
992   //
993   // We only apply this optimization to FFS files with the FIXED attribute set,
994   // since the FFS will not be loadable at arbitrary offsets anymore after
995   // we adjust the size of the padding section.
996   //
997   if ((FfsFile->Attributes & FFS_ATTRIB_FIXED) == 0) {
998     return FALSE;
999   }
1000 
1001   //
1002   // Look for a dedicated padding section that we can adjust to compensate
1003   // for the misalignment. If such a padding section exists, it precedes all
1004   // sections with alignment requirements, and so the adjustment will correct
1005   // all of them.
1006   //
1007   Status = GetSectionByType (FfsFile, EFI_SECTION_FREEFORM_SUBTYPE_GUID, 1,
1008              &PadSection);
1009   if (EFI_ERROR (Status) ||
1010       CompareGuid (&PadSection.FreeformSubtypeSection->SubTypeGuid,
1011         &mEfiFfsSectionAlignmentPaddingGuid) != 0) {
1012     return FALSE;
1013   }
1014 
1015   //
1016   // Find out if the size of the padding section is sufficient to compensate
1017   // for the misalignment.
1018   //
1019   PadSize = GetSectionFileLength (PadSection.CommonHeader);
1020   if (Misalignment > PadSize - sizeof (EFI_FREEFORM_SUBTYPE_GUID_SECTION)) {
1021     return FALSE;
1022   }
1023 
1024   //
1025   // Move the remainder of the FFS file towards the front, and adjust the
1026   // file size output parameter.
1027   //
1028   Remainder = (UINT8 *) PadSection.CommonHeader + PadSize;
1029   memmove (Remainder - Misalignment, Remainder,
1030            *FileSize - (UINTN) (Remainder - (UINTN) FfsFile));
1031   *FileSize -= Misalignment;
1032 
1033   //
1034   // Update the padding section's length with the new values. Note that the
1035   // padding is always < 64 KB, so we can ignore EFI_COMMON_SECTION_HEADER2
1036   // ExtendedSize.
1037   //
1038   PadSize -= Misalignment;
1039   PadSection.CommonHeader->Size[0] = (UINT8) (PadSize & 0xff);
1040   PadSection.CommonHeader->Size[1] = (UINT8) ((PadSize & 0xff00) >> 8);
1041   PadSection.CommonHeader->Size[2] = (UINT8) ((PadSize & 0xff0000) >> 16);
1042 
1043   //
1044   // Update the FFS header with the new overall length
1045   //
1046   FfsFileLength = GetFfsFileLength (FfsFile) - Misalignment;
1047   if (FfsHeaderLength > sizeof(EFI_FFS_FILE_HEADER)) {
1048     ((EFI_FFS_FILE_HEADER2 *)FfsFile)->ExtendedSize = FfsFileLength;
1049   } else {
1050     FfsFile->Size[0] = (UINT8) (FfsFileLength & 0x000000FF);
1051     FfsFile->Size[1] = (UINT8) ((FfsFileLength & 0x0000FF00) >> 8);
1052     FfsFile->Size[2] = (UINT8) ((FfsFileLength & 0x00FF0000) >> 16);
1053   }
1054 
1055   //
1056   // Clear the alignment bits: these have become meaningless now that we have
1057   // adjusted the padding section.
1058   //
1059   FfsFile->Attributes &= ~FFS_ATTRIB_DATA_ALIGNMENT;
1060 
1061   //
1062   // Recalculate the FFS header checksum. Instead of setting Header and State
1063   // both to zero, set Header to (UINT8)(-State) so State preserves its original
1064   // value
1065   //
1066   IntegrityCheck = &FfsFile->IntegrityCheck;
1067   IntegrityCheck->Checksum.Header = (UINT8) (0x100 - FfsFile->State);
1068   IntegrityCheck->Checksum.File = 0;
1069 
1070   IntegrityCheck->Checksum.Header = CalculateChecksum8 (
1071                                       (UINT8 *) FfsFile, FfsHeaderLength);
1072 
1073   if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
1074     //
1075     // Ffs header checksum = zero, so only need to calculate ffs body.
1076     //
1077     IntegrityCheck->Checksum.File = CalculateChecksum8 (
1078                                       (UINT8 *) FfsFile + FfsHeaderLength,
1079                                       FfsFileLength - FfsHeaderLength);
1080   } else {
1081     IntegrityCheck->Checksum.File = FFS_FIXED_CHECKSUM;
1082   }
1083 
1084   return TRUE;
1085 }
1086 
1087 EFI_STATUS
AddFile(IN OUT MEMORY_FILE * FvImage,IN FV_INFO * FvInfo,IN UINTN Index,IN OUT EFI_FFS_FILE_HEADER ** VtfFileImage,IN FILE * FvMapFile,IN FILE * FvReportFile)1088 AddFile (
1089   IN OUT MEMORY_FILE          *FvImage,
1090   IN FV_INFO                  *FvInfo,
1091   IN UINTN                    Index,
1092   IN OUT EFI_FFS_FILE_HEADER  **VtfFileImage,
1093   IN FILE                     *FvMapFile,
1094   IN FILE                     *FvReportFile
1095   )
1096 /*++
1097 
1098 Routine Description:
1099 
1100   This function adds a file to the FV image.  The file will pad to the
1101   appropriate alignment if required.
1102 
1103 Arguments:
1104 
1105   FvImage       The memory image of the FV to add it to.  The current offset
1106                 must be valid.
1107   FvInfo        Pointer to information about the FV.
1108   Index         The file in the FvInfo file list to add.
1109   VtfFileImage  A pointer to the VTF file within the FvImage.  If this is equal
1110                 to the end of the FvImage then no VTF previously found.
1111   FvMapFile     Pointer to FvMap File
1112   FvReportFile  Pointer to FvReport File
1113 
1114 Returns:
1115 
1116   EFI_SUCCESS              The function completed successfully.
1117   EFI_INVALID_PARAMETER    One of the input parameters was invalid.
1118   EFI_ABORTED              An error occurred.
1119   EFI_OUT_OF_RESOURCES     Insufficient resources exist to complete the add.
1120 
1121 --*/
1122 {
1123   FILE                  *NewFile;
1124   UINTN                 FileSize;
1125   UINT8                 *FileBuffer;
1126   UINTN                 NumBytesRead;
1127   UINT32                CurrentFileAlignment;
1128   EFI_STATUS            Status;
1129   UINTN                 Index1;
1130   UINT8                 FileGuidString[PRINTED_GUID_BUFFER_SIZE];
1131 
1132   Index1 = 0;
1133   //
1134   // Verify input parameters.
1135   //
1136   if (FvImage == NULL || FvInfo == NULL || FvInfo->FvFiles[Index][0] == 0 || VtfFileImage == NULL) {
1137     return EFI_INVALID_PARAMETER;
1138   }
1139 
1140   //
1141   // Read the file to add
1142   //
1143   NewFile = fopen (LongFilePath (FvInfo->FvFiles[Index]), "rb");
1144 
1145   if (NewFile == NULL) {
1146     Error (NULL, 0, 0001, "Error opening file", FvInfo->FvFiles[Index]);
1147     return EFI_ABORTED;
1148   }
1149 
1150   //
1151   // Get the file size
1152   //
1153   FileSize = _filelength (fileno (NewFile));
1154 
1155   //
1156   // Read the file into a buffer
1157   //
1158   FileBuffer = malloc (FileSize);
1159   if (FileBuffer == NULL) {
1160     Error (NULL, 0, 4001, "Resouce", "memory cannot be allocated!");
1161     return EFI_OUT_OF_RESOURCES;
1162   }
1163 
1164   NumBytesRead = fread (FileBuffer, sizeof (UINT8), FileSize, NewFile);
1165 
1166   //
1167   // Done with the file, from this point on we will just use the buffer read.
1168   //
1169   fclose (NewFile);
1170 
1171   //
1172   // Verify read successful
1173   //
1174   if (NumBytesRead != sizeof (UINT8) * FileSize) {
1175     free  (FileBuffer);
1176     Error (NULL, 0, 0004, "Error reading file", FvInfo->FvFiles[Index]);
1177     return EFI_ABORTED;
1178   }
1179 
1180   //
1181   // For None PI Ffs file, directly add them into FvImage.
1182   //
1183   if (!FvInfo->IsPiFvImage) {
1184     memcpy (FvImage->CurrentFilePointer, FileBuffer, FileSize);
1185     if (FvInfo->SizeofFvFiles[Index] > FileSize) {
1186     	FvImage->CurrentFilePointer += FvInfo->SizeofFvFiles[Index];
1187     } else {
1188     	FvImage->CurrentFilePointer += FileSize;
1189     }
1190     goto Done;
1191   }
1192 
1193   //
1194   // Verify Ffs file
1195   //
1196   Status = VerifyFfsFile ((EFI_FFS_FILE_HEADER *)FileBuffer);
1197   if (EFI_ERROR (Status)) {
1198     free (FileBuffer);
1199     Error (NULL, 0, 3000, "Invalid", "%s is not a valid FFS file.", FvInfo->FvFiles[Index]);
1200     return EFI_INVALID_PARAMETER;
1201   }
1202 
1203   //
1204   // Verify space exists to add the file
1205   //
1206   if (FileSize > (UINTN) ((UINTN) *VtfFileImage - (UINTN) FvImage->CurrentFilePointer)) {
1207     free (FileBuffer);
1208     Error (NULL, 0, 4002, "Resource", "FV space is full, not enough room to add file %s.", FvInfo->FvFiles[Index]);
1209     return EFI_OUT_OF_RESOURCES;
1210   }
1211 
1212   //
1213   // Verify the input file is the duplicated file in this Fv image
1214   //
1215   for (Index1 = 0; Index1 < Index; Index1 ++) {
1216     if (CompareGuid ((EFI_GUID *) FileBuffer, &mFileGuidArray [Index1]) == 0) {
1217       Error (NULL, 0, 2000, "Invalid parameter", "the %dth file and %uth file have the same file GUID.", (unsigned) Index1 + 1, (unsigned) Index + 1);
1218       PrintGuid ((EFI_GUID *) FileBuffer);
1219       return EFI_INVALID_PARAMETER;
1220     }
1221   }
1222   CopyMem (&mFileGuidArray [Index], FileBuffer, sizeof (EFI_GUID));
1223 
1224   //
1225   // Update the file state based on polarity of the FV.
1226   //
1227   UpdateFfsFileState (
1228     (EFI_FFS_FILE_HEADER *) FileBuffer,
1229     (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage
1230     );
1231 
1232   //
1233   // Check if alignment is required
1234   //
1235   ReadFfsAlignment ((EFI_FFS_FILE_HEADER *) FileBuffer, &CurrentFileAlignment);
1236 
1237   //
1238   // Find the largest alignment of all the FFS files in the FV
1239   //
1240   if (CurrentFileAlignment > MaxFfsAlignment) {
1241     MaxFfsAlignment = CurrentFileAlignment;
1242   }
1243   //
1244   // If we have a VTF file, add it at the top.
1245   //
1246   if (IsVtfFile ((EFI_FFS_FILE_HEADER *) FileBuffer)) {
1247     if ((UINTN) *VtfFileImage == (UINTN) FvImage->Eof) {
1248       //
1249       // No previous VTF, add this one.
1250       //
1251       *VtfFileImage = (EFI_FFS_FILE_HEADER *) (UINTN) ((UINTN) FvImage->FileImage + FvInfo->Size - FileSize);
1252       //
1253       // Sanity check. The file MUST align appropriately
1254       //
1255       if (((UINTN) *VtfFileImage + GetFfsHeaderLength((EFI_FFS_FILE_HEADER *)FileBuffer) - (UINTN) FvImage->FileImage) % (1 << CurrentFileAlignment)) {
1256         Error (NULL, 0, 3000, "Invalid", "VTF file cannot be aligned on a %u-byte boundary.", (unsigned) (1 << CurrentFileAlignment));
1257         free (FileBuffer);
1258         return EFI_ABORTED;
1259       }
1260       //
1261       // Rebase the PE or TE image in FileBuffer of FFS file for XIP
1262       // Rebase for the debug genfvmap tool
1263       //
1264       Status = FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) *VtfFileImage - (UINTN) FvImage->FileImage, FvMapFile);
1265       if (EFI_ERROR (Status)) {
1266         Error (NULL, 0, 3000, "Invalid", "Could not rebase %s.", FvInfo->FvFiles[Index]);
1267         return Status;
1268       }
1269       //
1270       // copy VTF File
1271       //
1272       memcpy (*VtfFileImage, FileBuffer, FileSize);
1273 
1274       PrintGuidToBuffer ((EFI_GUID *) FileBuffer, FileGuidString, sizeof (FileGuidString), TRUE);
1275       fprintf (FvReportFile, "0x%08X %s\n", (unsigned)(UINTN) (((UINT8 *)*VtfFileImage) - (UINTN)FvImage->FileImage), FileGuidString);
1276 
1277       free (FileBuffer);
1278       DebugMsg (NULL, 0, 9, "Add VTF FFS file in FV image", NULL);
1279       return EFI_SUCCESS;
1280     } else {
1281       //
1282       // Already found a VTF file.
1283       //
1284       Error (NULL, 0, 3000, "Invalid", "multiple VTF files are not permitted within a single FV.");
1285       free (FileBuffer);
1286       return EFI_ABORTED;
1287     }
1288   }
1289 
1290   //
1291   // Add pad file if necessary
1292   //
1293   if (!AdjustInternalFfsPadding ((EFI_FFS_FILE_HEADER *) FileBuffer, FvImage,
1294          1 << CurrentFileAlignment, &FileSize)) {
1295     Status = AddPadFile (FvImage, 1 << CurrentFileAlignment, *VtfFileImage, NULL, FileSize);
1296     if (EFI_ERROR (Status)) {
1297       Error (NULL, 0, 4002, "Resource", "FV space is full, could not add pad file for data alignment property.");
1298       free (FileBuffer);
1299       return EFI_ABORTED;
1300     }
1301   }
1302   //
1303   // Add file
1304   //
1305   if ((UINTN) (FvImage->CurrentFilePointer + FileSize) <= (UINTN) (*VtfFileImage)) {
1306     //
1307     // Rebase the PE or TE image in FileBuffer of FFS file for XIP.
1308     // Rebase Bs and Rt drivers for the debug genfvmap tool.
1309     //
1310     Status = FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage, FvMapFile);
1311 	if (EFI_ERROR (Status)) {
1312 	  Error (NULL, 0, 3000, "Invalid", "Could not rebase %s.", FvInfo->FvFiles[Index]);
1313 	  return Status;
1314 	}
1315     //
1316     // Copy the file
1317     //
1318     memcpy (FvImage->CurrentFilePointer, FileBuffer, FileSize);
1319     PrintGuidToBuffer ((EFI_GUID *) FileBuffer, FileGuidString, sizeof (FileGuidString), TRUE);
1320     fprintf (FvReportFile, "0x%08X %s\n", (unsigned) (FvImage->CurrentFilePointer - FvImage->FileImage), FileGuidString);
1321     FvImage->CurrentFilePointer += FileSize;
1322   } else {
1323     Error (NULL, 0, 4002, "Resource", "FV space is full, cannot add file %s.", FvInfo->FvFiles[Index]);
1324     free (FileBuffer);
1325     return EFI_ABORTED;
1326   }
1327   //
1328   // Make next file start at QWord Boundry
1329   //
1330   while (((UINTN) FvImage->CurrentFilePointer & (EFI_FFS_FILE_HEADER_ALIGNMENT - 1)) != 0) {
1331     FvImage->CurrentFilePointer++;
1332   }
1333 
1334 Done:
1335   //
1336   // Free allocated memory.
1337   //
1338   free (FileBuffer);
1339 
1340   return EFI_SUCCESS;
1341 }
1342 
1343 EFI_STATUS
PadFvImage(IN MEMORY_FILE * FvImage,IN EFI_FFS_FILE_HEADER * VtfFileImage)1344 PadFvImage (
1345   IN MEMORY_FILE          *FvImage,
1346   IN EFI_FFS_FILE_HEADER  *VtfFileImage
1347   )
1348 /*++
1349 
1350 Routine Description:
1351 
1352   This function places a pad file between the last file in the FV and the VTF
1353   file if the VTF file exists.
1354 
1355 Arguments:
1356 
1357   FvImage       Memory file for the FV memory image
1358   VtfFileImage  The address of the VTF file.  If this is the end of the FV
1359                 image, no VTF exists and no pad file is needed.
1360 
1361 Returns:
1362 
1363   EFI_SUCCESS             Completed successfully.
1364   EFI_INVALID_PARAMETER   One of the input parameters was NULL.
1365 
1366 --*/
1367 {
1368   EFI_FFS_FILE_HEADER *PadFile;
1369   UINTN               FileSize;
1370   UINT32              FfsHeaderSize;
1371 
1372   //
1373   // If there is no VTF or the VTF naturally follows the previous file without a
1374   // pad file, then there's nothing to do
1375   //
1376   if ((UINTN) VtfFileImage == (UINTN) FvImage->Eof || \
1377       ((UINTN) VtfFileImage == (UINTN) FvImage->CurrentFilePointer)) {
1378     return EFI_SUCCESS;
1379   }
1380 
1381   if ((UINTN) VtfFileImage < (UINTN) FvImage->CurrentFilePointer) {
1382     return EFI_INVALID_PARAMETER;
1383   }
1384 
1385   //
1386   // Pad file starts at beginning of free space
1387   //
1388   PadFile = (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer;
1389 
1390   //
1391   // write PadFile FFS header with PadType, don't need to set PAD file guid in its header.
1392   //
1393   PadFile->Type       = EFI_FV_FILETYPE_FFS_PAD;
1394   PadFile->Attributes = 0;
1395 
1396   //
1397   // FileSize includes the EFI_FFS_FILE_HEADER
1398   //
1399   FileSize          = (UINTN) VtfFileImage - (UINTN) FvImage->CurrentFilePointer;
1400   if (FileSize >= MAX_FFS_SIZE) {
1401     PadFile->Attributes |= FFS_ATTRIB_LARGE_FILE;
1402     memset(PadFile->Size, 0, sizeof(UINT8) * 3);
1403     ((EFI_FFS_FILE_HEADER2 *)PadFile)->ExtendedSize = FileSize;
1404     FfsHeaderSize = sizeof(EFI_FFS_FILE_HEADER2);
1405     mIsLargeFfs = TRUE;
1406   } else {
1407     PadFile->Size[0]  = (UINT8) (FileSize & 0x000000FF);
1408     PadFile->Size[1]  = (UINT8) ((FileSize & 0x0000FF00) >> 8);
1409     PadFile->Size[2]  = (UINT8) ((FileSize & 0x00FF0000) >> 16);
1410     FfsHeaderSize = sizeof(EFI_FFS_FILE_HEADER);
1411   }
1412 
1413   //
1414   // Fill in checksums and state, must be zero during checksum calculation.
1415   //
1416   PadFile->IntegrityCheck.Checksum.Header = 0;
1417   PadFile->IntegrityCheck.Checksum.File   = 0;
1418   PadFile->State                          = 0;
1419   PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, FfsHeaderSize);
1420   PadFile->IntegrityCheck.Checksum.File   = FFS_FIXED_CHECKSUM;
1421 
1422   PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID;
1423 
1424   UpdateFfsFileState (
1425     (EFI_FFS_FILE_HEADER *) PadFile,
1426     (EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage
1427     );
1428   //
1429   // Update the current FV pointer
1430   //
1431   FvImage->CurrentFilePointer = FvImage->Eof;
1432 
1433   return EFI_SUCCESS;
1434 }
1435 
1436 EFI_STATUS
UpdateResetVector(IN MEMORY_FILE * FvImage,IN FV_INFO * FvInfo,IN EFI_FFS_FILE_HEADER * VtfFile)1437 UpdateResetVector (
1438   IN MEMORY_FILE            *FvImage,
1439   IN FV_INFO                *FvInfo,
1440   IN EFI_FFS_FILE_HEADER    *VtfFile
1441   )
1442 /*++
1443 
1444 Routine Description:
1445 
1446   This parses the FV looking for the PEI core and then plugs the address into
1447   the SALE_ENTRY point of the BSF/VTF for IPF and does BUGBUG TBD action to
1448   complete an IA32 Bootstrap FV.
1449 
1450 Arguments:
1451 
1452   FvImage       Memory file for the FV memory image
1453   FvInfo        Information read from INF file.
1454   VtfFile       Pointer to the VTF file in the FV image.
1455 
1456 Returns:
1457 
1458   EFI_SUCCESS             Function Completed successfully.
1459   EFI_ABORTED             Error encountered.
1460   EFI_INVALID_PARAMETER   A required parameter was NULL.
1461   EFI_NOT_FOUND           PEI Core file not found.
1462 
1463 --*/
1464 {
1465   EFI_FFS_FILE_HEADER       *PeiCoreFile;
1466   EFI_FFS_FILE_HEADER       *SecCoreFile;
1467   EFI_STATUS                Status;
1468   EFI_FILE_SECTION_POINTER  Pe32Section;
1469   UINT32                    EntryPoint;
1470   UINT32                    BaseOfCode;
1471   UINT16                    MachineType;
1472   EFI_PHYSICAL_ADDRESS      PeiCorePhysicalAddress;
1473   EFI_PHYSICAL_ADDRESS      SecCorePhysicalAddress;
1474   EFI_PHYSICAL_ADDRESS      *SecCoreEntryAddressPtr;
1475   INT32                     Ia32SecEntryOffset;
1476   UINT32                    *Ia32ResetAddressPtr;
1477   UINT8                     *BytePointer;
1478   UINT8                     *BytePointer2;
1479   UINT16                    *WordPointer;
1480   UINT16                    CheckSum;
1481   UINT32                    IpiVector;
1482   UINTN                     Index;
1483   EFI_FFS_FILE_STATE        SavedState;
1484   UINT64                    FitAddress;
1485   FIT_TABLE                 *FitTablePtr;
1486   BOOLEAN                   Vtf0Detected;
1487   UINT32                    FfsHeaderSize;
1488   UINT32                    SecHeaderSize;
1489 
1490   //
1491   // Verify input parameters
1492   //
1493   if (FvImage == NULL || FvInfo == NULL || VtfFile == NULL) {
1494     return EFI_INVALID_PARAMETER;
1495   }
1496   //
1497   // Initialize FV library
1498   //
1499   InitializeFvLib (FvImage->FileImage, FvInfo->Size);
1500 
1501   //
1502   // Verify VTF file
1503   //
1504   Status = VerifyFfsFile (VtfFile);
1505   if (EFI_ERROR (Status)) {
1506     return EFI_INVALID_PARAMETER;
1507   }
1508 
1509   if (
1510       (((UINTN)FvImage->Eof - (UINTN)FvImage->FileImage) >=
1511         IA32_X64_VTF_SIGNATURE_OFFSET) &&
1512       (*(UINT32 *)(VOID*)((UINTN) FvImage->Eof -
1513                                   IA32_X64_VTF_SIGNATURE_OFFSET) ==
1514         IA32_X64_VTF0_SIGNATURE)
1515      ) {
1516     Vtf0Detected = TRUE;
1517   } else {
1518     Vtf0Detected = FALSE;
1519   }
1520 
1521   //
1522   // Find the Sec Core
1523   //
1524   Status = GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE, 1, &SecCoreFile);
1525   if (EFI_ERROR (Status) || SecCoreFile == NULL) {
1526     if (Vtf0Detected) {
1527       //
1528       // If the SEC core file is not found, but the VTF-0 signature
1529       // is found, we'll treat it as a VTF-0 'Volume Top File'.
1530       // This means no modifications are required to the VTF.
1531       //
1532       return EFI_SUCCESS;
1533     }
1534 
1535     Error (NULL, 0, 3000, "Invalid", "could not find the SEC core file in the FV.");
1536     return EFI_ABORTED;
1537   }
1538   //
1539   // Sec Core found, now find PE32 section
1540   //
1541   Status = GetSectionByType (SecCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);
1542   if (Status == EFI_NOT_FOUND) {
1543     Status = GetSectionByType (SecCoreFile, EFI_SECTION_TE, 1, &Pe32Section);
1544   }
1545 
1546   if (EFI_ERROR (Status)) {
1547     Error (NULL, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");
1548     return EFI_ABORTED;
1549   }
1550 
1551   SecHeaderSize = GetSectionHeaderLength(Pe32Section.CommonHeader);
1552   Status = GetPe32Info (
1553             (VOID *) ((UINTN) Pe32Section.Pe32Section + SecHeaderSize),
1554             &EntryPoint,
1555             &BaseOfCode,
1556             &MachineType
1557             );
1558 
1559   if (EFI_ERROR (Status)) {
1560     Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");
1561     return EFI_ABORTED;
1562   }
1563 
1564   if (
1565        Vtf0Detected &&
1566        (MachineType == EFI_IMAGE_MACHINE_IA32 ||
1567         MachineType == EFI_IMAGE_MACHINE_X64)
1568      ) {
1569     //
1570     // If the SEC core code is IA32 or X64 and the VTF-0 signature
1571     // is found, we'll treat it as a VTF-0 'Volume Top File'.
1572     // This means no modifications are required to the VTF.
1573     //
1574     return EFI_SUCCESS;
1575   }
1576 
1577   //
1578   // Physical address is FV base + offset of PE32 + offset of the entry point
1579   //
1580   SecCorePhysicalAddress = FvInfo->BaseAddress;
1581   SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + SecHeaderSize - (UINTN) FvImage->FileImage;
1582   SecCorePhysicalAddress += EntryPoint;
1583   DebugMsg (NULL, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress);
1584 
1585   //
1586   // Find the PEI Core
1587   //
1588   Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile);
1589   if (EFI_ERROR (Status) || PeiCoreFile == NULL) {
1590     Error (NULL, 0, 3000, "Invalid", "could not find the PEI core in the FV.");
1591     return EFI_ABORTED;
1592   }
1593   //
1594   // PEI Core found, now find PE32 or TE section
1595   //
1596   Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);
1597   if (Status == EFI_NOT_FOUND) {
1598     Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section);
1599   }
1600 
1601   if (EFI_ERROR (Status)) {
1602     Error (NULL, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file.");
1603     return EFI_ABORTED;
1604   }
1605 
1606   SecHeaderSize = GetSectionHeaderLength(Pe32Section.CommonHeader);
1607   Status = GetPe32Info (
1608             (VOID *) ((UINTN) Pe32Section.Pe32Section + SecHeaderSize),
1609             &EntryPoint,
1610             &BaseOfCode,
1611             &MachineType
1612             );
1613 
1614   if (EFI_ERROR (Status)) {
1615     Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core.");
1616     return EFI_ABORTED;
1617   }
1618   //
1619   // Physical address is FV base + offset of PE32 + offset of the entry point
1620   //
1621   PeiCorePhysicalAddress = FvInfo->BaseAddress;
1622   PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + SecHeaderSize - (UINTN) FvImage->FileImage;
1623   PeiCorePhysicalAddress += EntryPoint;
1624   DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress);
1625 
1626   if (MachineType == EFI_IMAGE_MACHINE_IA64) {
1627     //
1628     // Update PEI_CORE address
1629     //
1630     //
1631     // Set the uncached attribute bit in the physical address
1632     //
1633     PeiCorePhysicalAddress |= 0x8000000000000000ULL;
1634 
1635     //
1636     // Check if address is aligned on a 16 byte boundary
1637     //
1638     if (PeiCorePhysicalAddress & 0xF) {
1639       Error (NULL, 0, 3000, "Invalid",
1640         "PEI_CORE entry point is not aligned on a 16 byte boundary, address specified is %llXh.",
1641         (unsigned long long) PeiCorePhysicalAddress
1642         );
1643       return EFI_ABORTED;
1644     }
1645     //
1646     // First Get the FIT table address
1647     //
1648     FitAddress  = (*(UINT64 *) (FvImage->Eof - IPF_FIT_ADDRESS_OFFSET)) & 0xFFFFFFFF;
1649 
1650     FitTablePtr = (FIT_TABLE *) (FvImage->FileImage + (FitAddress - FvInfo->BaseAddress));
1651 
1652     Status      = UpdatePeiCoreEntryInFit (FitTablePtr, PeiCorePhysicalAddress);
1653 
1654     if (!EFI_ERROR (Status)) {
1655       UpdateFitCheckSum (FitTablePtr);
1656     }
1657 
1658     //
1659     // Update SEC_CORE address
1660     //
1661     //
1662     // Set the uncached attribute bit in the physical address
1663     //
1664     SecCorePhysicalAddress |= 0x8000000000000000ULL;
1665     //
1666     // Check if address is aligned on a 16 byte boundary
1667     //
1668     if (SecCorePhysicalAddress & 0xF) {
1669       Error (NULL, 0, 3000, "Invalid",
1670         "SALE_ENTRY entry point is not aligned on a 16 byte boundary, address specified is %llXh.",
1671         (unsigned long long) SecCorePhysicalAddress
1672         );
1673       return EFI_ABORTED;
1674     }
1675     //
1676     // Update the address
1677     //
1678     SecCoreEntryAddressPtr  = (EFI_PHYSICAL_ADDRESS *) ((UINTN) FvImage->Eof - IPF_SALE_ENTRY_ADDRESS_OFFSET);
1679     *SecCoreEntryAddressPtr = SecCorePhysicalAddress;
1680 
1681   } else if (MachineType == EFI_IMAGE_MACHINE_IA32 || MachineType == EFI_IMAGE_MACHINE_X64) {
1682     //
1683     // Get the location to update
1684     //
1685     Ia32ResetAddressPtr  = (UINT32 *) ((UINTN) FvImage->Eof - IA32_PEI_CORE_ENTRY_OFFSET);
1686 
1687     //
1688     // Write lower 32 bits of physical address for Pei Core entry
1689     //
1690     *Ia32ResetAddressPtr = (UINT32) PeiCorePhysicalAddress;
1691 
1692     //
1693     // Write SecCore Entry point relative address into the jmp instruction in reset vector.
1694     //
1695     Ia32ResetAddressPtr  = (UINT32 *) ((UINTN) FvImage->Eof - IA32_SEC_CORE_ENTRY_OFFSET);
1696 
1697     Ia32SecEntryOffset   = (INT32) (SecCorePhysicalAddress - (FV_IMAGES_TOP_ADDRESS - IA32_SEC_CORE_ENTRY_OFFSET + 2));
1698     if (Ia32SecEntryOffset <= -65536) {
1699       Error (NULL, 0, 3000, "Invalid", "The SEC EXE file size is too large, it must be less than 64K.");
1700       return STATUS_ERROR;
1701     }
1702 
1703     *(UINT16 *) Ia32ResetAddressPtr = (UINT16) Ia32SecEntryOffset;
1704 
1705     //
1706     // Update the BFV base address
1707     //
1708     Ia32ResetAddressPtr   = (UINT32 *) ((UINTN) FvImage->Eof - 4);
1709     *Ia32ResetAddressPtr  = (UINT32) (FvInfo->BaseAddress);
1710     DebugMsg (NULL, 0, 9, "update BFV base address in the top FV image", "BFV base address = 0x%llX.", (unsigned long long) FvInfo->BaseAddress);
1711 
1712     //
1713     // Update the Startup AP in the FVH header block ZeroVector region.
1714     //
1715     BytePointer   = (UINT8 *) ((UINTN) FvImage->FileImage);
1716     if (FvInfo->Size <= 0x10000) {
1717       BytePointer2 = m64kRecoveryStartupApDataArray;
1718     } else if (FvInfo->Size <= 0x20000) {
1719       BytePointer2 = m128kRecoveryStartupApDataArray;
1720     } else {
1721       BytePointer2 = m128kRecoveryStartupApDataArray;
1722       //
1723       // Find the position to place Ap reset vector, the offset
1724       // between the position and the end of Fvrecovery.fv file
1725       // should not exceed 128kB to prevent Ap reset vector from
1726       // outside legacy E and F segment
1727       //
1728       Status = FindApResetVectorPosition (FvImage, &BytePointer);
1729       if (EFI_ERROR (Status)) {
1730         Error (NULL, 0, 3000, "Invalid", "FV image does not have enough space to place AP reset vector. The FV image needs to reserve at least 4KB of unused space.");
1731         return EFI_ABORTED;
1732       }
1733     }
1734 
1735     for (Index = 0; Index < SIZEOF_STARTUP_DATA_ARRAY; Index++) {
1736       BytePointer[Index] = BytePointer2[Index];
1737     }
1738     //
1739     // Calculate the checksum
1740     //
1741     CheckSum              = 0x0000;
1742     WordPointer = (UINT16 *) (BytePointer);
1743     for (Index = 0; Index < SIZEOF_STARTUP_DATA_ARRAY / 2; Index++) {
1744       CheckSum = (UINT16) (CheckSum + ((UINT16) *WordPointer));
1745       WordPointer++;
1746     }
1747     //
1748     // Update the checksum field
1749     //
1750     WordPointer   = (UINT16 *) (BytePointer + SIZEOF_STARTUP_DATA_ARRAY - 2);
1751     *WordPointer  = (UINT16) (0x10000 - (UINT32) CheckSum);
1752 
1753     //
1754     // IpiVector at the 4k aligned address in the top 2 blocks in the PEI FV.
1755     //
1756     IpiVector  = (UINT32) (FV_IMAGES_TOP_ADDRESS - ((UINTN) FvImage->Eof - (UINTN) BytePointer));
1757     DebugMsg (NULL, 0, 9, "Startup AP Vector address", "IpiVector at 0x%X", (unsigned) IpiVector);
1758     if ((IpiVector & 0xFFF) != 0) {
1759       Error (NULL, 0, 3000, "Invalid", "Startup AP Vector address are not 4K aligned, because the FV size is not 4K aligned");
1760       return EFI_ABORTED;
1761     }
1762     IpiVector  = IpiVector >> 12;
1763     IpiVector  = IpiVector & 0xFF;
1764 
1765     //
1766     // Write IPI Vector at Offset FvrecoveryFileSize - 8
1767     //
1768     Ia32ResetAddressPtr   = (UINT32 *) ((UINTN) FvImage->Eof - 8);
1769     *Ia32ResetAddressPtr  = IpiVector;
1770   } else if (MachineType == EFI_IMAGE_MACHINE_ARMT) {
1771     //
1772     // Since the ARM reset vector is in the FV Header you really don't need a
1773     // Volume Top File, but if you have one for some reason don't crash...
1774     //
1775   } else if (MachineType == EFI_IMAGE_MACHINE_AARCH64) {
1776     //
1777     // Since the AArch64 reset vector is in the FV Header you really don't need a
1778     // Volume Top File, but if you have one for some reason don't crash...
1779     //
1780   } else {
1781     Error (NULL, 0, 3000, "Invalid", "machine type=0x%X in PEI core.", MachineType);
1782     return EFI_ABORTED;
1783   }
1784 
1785   //
1786   // Now update file checksum
1787   //
1788   SavedState  = VtfFile->State;
1789   VtfFile->IntegrityCheck.Checksum.File = 0;
1790   VtfFile->State                        = 0;
1791   if (VtfFile->Attributes & FFS_ATTRIB_CHECKSUM) {
1792     FfsHeaderSize = GetFfsHeaderLength(VtfFile);
1793     VtfFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (
1794                                               (UINT8 *) ((UINT8 *)VtfFile + FfsHeaderSize),
1795                                               GetFfsFileLength (VtfFile) - FfsHeaderSize
1796                                               );
1797   } else {
1798     VtfFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
1799   }
1800 
1801   VtfFile->State = SavedState;
1802 
1803   return EFI_SUCCESS;
1804 }
1805 
1806 
1807 EFI_STATUS
UpdateArmResetVectorIfNeeded(IN MEMORY_FILE * FvImage,IN FV_INFO * FvInfo)1808 UpdateArmResetVectorIfNeeded (
1809   IN MEMORY_FILE            *FvImage,
1810   IN FV_INFO                *FvInfo
1811   )
1812 /*++
1813 
1814 Routine Description:
1815   This parses the FV looking for SEC and patches that address into the
1816   beginning of the FV header.
1817 
1818   For ARM32 the reset vector is at 0x00000000 or 0xFFFF0000.
1819   For AArch64 the reset vector is at 0x00000000.
1820 
1821   This would commonly map to the first entry in the ROM.
1822   ARM32 Exceptions:
1823   Reset            +0
1824   Undefined        +4
1825   SWI              +8
1826   Prefetch Abort   +12
1827   Data Abort       +16
1828   IRQ              +20
1829   FIQ              +24
1830 
1831   We support two schemes on ARM.
1832   1) Beginning of the FV is the reset vector
1833   2) Reset vector is data bytes FDF file and that code branches to reset vector
1834     in the beginning of the FV (fixed size offset).
1835 
1836   Need to have the jump for the reset vector at location zero.
1837   We also need to store the address or PEI (if it exists).
1838   We stub out a return from interrupt in case the debugger
1839    is using SWI (not done for AArch64, not enough space in struct).
1840   The optional entry to the common exception handler is
1841    to support full featured exception handling from ROM and is currently
1842     not support by this tool.
1843 
1844 Arguments:
1845   FvImage       Memory file for the FV memory image
1846   FvInfo        Information read from INF file.
1847 
1848 Returns:
1849 
1850   EFI_SUCCESS             Function Completed successfully.
1851   EFI_ABORTED             Error encountered.
1852   EFI_INVALID_PARAMETER   A required parameter was NULL.
1853   EFI_NOT_FOUND           PEI Core file not found.
1854 
1855 --*/
1856 {
1857   EFI_FFS_FILE_HEADER       *PeiCoreFile;
1858   EFI_FFS_FILE_HEADER       *SecCoreFile;
1859   EFI_STATUS                Status;
1860   EFI_FILE_SECTION_POINTER  Pe32Section;
1861   UINT32                    EntryPoint;
1862   UINT32                    BaseOfCode;
1863   UINT16                    MachineType;
1864   EFI_PHYSICAL_ADDRESS      PeiCorePhysicalAddress;
1865   EFI_PHYSICAL_ADDRESS      SecCorePhysicalAddress;
1866   INT32                     ResetVector[4]; // ARM32:
1867                                             // 0 - is branch relative to SEC entry point
1868                                             // 1 - PEI Entry Point
1869                                             // 2 - movs pc,lr for a SWI handler
1870                                             // 3 - Place holder for Common Exception Handler
1871                                             // AArch64: Used as UINT64 ResetVector[2]
1872                                             // 0 - is branch relative to SEC entry point
1873                                             // 1 - PEI Entry Point
1874 
1875   //
1876   // Verify input parameters
1877   //
1878   if (FvImage == NULL || FvInfo == NULL) {
1879     return EFI_INVALID_PARAMETER;
1880   }
1881   //
1882   // Initialize FV library
1883   //
1884   InitializeFvLib (FvImage->FileImage, FvInfo->Size);
1885 
1886   //
1887   // Find the Sec Core
1888   //
1889   Status = GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE, 1, &SecCoreFile);
1890   if (EFI_ERROR (Status) || SecCoreFile == NULL) {
1891     //
1892     // Maybe hardware does SEC job and we only have PEI Core?
1893     //
1894 
1895     //
1896     // Find the PEI Core. It may not exist if SEC loads DXE core directly
1897     //
1898     PeiCorePhysicalAddress = 0;
1899     Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile);
1900     if (!EFI_ERROR (Status) && PeiCoreFile != NULL) {
1901       //
1902       // PEI Core found, now find PE32 or TE section
1903       //
1904       Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);
1905       if (Status == EFI_NOT_FOUND) {
1906         Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section);
1907       }
1908 
1909       if (EFI_ERROR (Status)) {
1910         Error (NULL, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file!");
1911         return EFI_ABORTED;
1912       }
1913 
1914       Status = GetPe32Info (
1915                 (VOID *) ((UINTN) Pe32Section.Pe32Section + GetSectionHeaderLength(Pe32Section.CommonHeader)),
1916                 &EntryPoint,
1917                 &BaseOfCode,
1918                 &MachineType
1919                 );
1920 
1921       if (EFI_ERROR (Status)) {
1922         Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core!");
1923         return EFI_ABORTED;
1924       }
1925       //
1926       // Physical address is FV base + offset of PE32 + offset of the entry point
1927       //
1928       PeiCorePhysicalAddress = FvInfo->BaseAddress;
1929       PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + GetSectionHeaderLength(Pe32Section.CommonHeader) - (UINTN) FvImage->FileImage;
1930       PeiCorePhysicalAddress += EntryPoint;
1931       DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress);
1932 
1933       if (MachineType == EFI_IMAGE_MACHINE_ARMT || MachineType == EFI_IMAGE_MACHINE_AARCH64) {
1934         memset (ResetVector, 0, sizeof (ResetVector));
1935         // Address of PEI Core, if we have one
1936         ResetVector[1] = (UINT32)PeiCorePhysicalAddress;
1937       }
1938 
1939       //
1940       // Copy to the beginning of the FV
1941       //
1942       memcpy ((UINT8 *) ((UINTN) FvImage->FileImage), ResetVector, sizeof (ResetVector));
1943 
1944     }
1945 
1946     return EFI_SUCCESS;
1947   }
1948 
1949   //
1950   // Sec Core found, now find PE32 section
1951   //
1952   Status = GetSectionByType (SecCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);
1953   if (Status == EFI_NOT_FOUND) {
1954     Status = GetSectionByType (SecCoreFile, EFI_SECTION_TE, 1, &Pe32Section);
1955   }
1956 
1957   if (EFI_ERROR (Status)) {
1958     Error (NULL, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file.");
1959     return EFI_ABORTED;
1960   }
1961 
1962   Status = GetPe32Info (
1963             (VOID *) ((UINTN) Pe32Section.Pe32Section + GetSectionHeaderLength(Pe32Section.CommonHeader)),
1964             &EntryPoint,
1965             &BaseOfCode,
1966             &MachineType
1967             );
1968   if (EFI_ERROR (Status)) {
1969     Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core.");
1970     return EFI_ABORTED;
1971   }
1972 
1973   if ((MachineType != EFI_IMAGE_MACHINE_ARMT) && (MachineType != EFI_IMAGE_MACHINE_AARCH64)) {
1974     //
1975     // If SEC is not ARM we have nothing to do
1976     //
1977     return EFI_SUCCESS;
1978   }
1979 
1980   //
1981   // Physical address is FV base + offset of PE32 + offset of the entry point
1982   //
1983   SecCorePhysicalAddress = FvInfo->BaseAddress;
1984   SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + GetSectionHeaderLength(Pe32Section.CommonHeader) - (UINTN) FvImage->FileImage;
1985   SecCorePhysicalAddress += EntryPoint;
1986   DebugMsg (NULL, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress);
1987 
1988   //
1989   // Find the PEI Core. It may not exist if SEC loads DXE core directly
1990   //
1991   PeiCorePhysicalAddress = 0;
1992   Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile);
1993   if (!EFI_ERROR (Status) && PeiCoreFile != NULL) {
1994     //
1995     // PEI Core found, now find PE32 or TE section
1996     //
1997     Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section);
1998     if (Status == EFI_NOT_FOUND) {
1999       Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section);
2000     }
2001 
2002     if (EFI_ERROR (Status)) {
2003       Error (NULL, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file!");
2004       return EFI_ABORTED;
2005     }
2006 
2007     Status = GetPe32Info (
2008               (VOID *) ((UINTN) Pe32Section.Pe32Section + GetSectionHeaderLength(Pe32Section.CommonHeader)),
2009               &EntryPoint,
2010               &BaseOfCode,
2011               &MachineType
2012               );
2013 
2014     if (EFI_ERROR (Status)) {
2015       Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core!");
2016       return EFI_ABORTED;
2017     }
2018     //
2019     // Physical address is FV base + offset of PE32 + offset of the entry point
2020     //
2021     PeiCorePhysicalAddress = FvInfo->BaseAddress;
2022     PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + GetSectionHeaderLength(Pe32Section.CommonHeader) - (UINTN) FvImage->FileImage;
2023     PeiCorePhysicalAddress += EntryPoint;
2024     DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress);
2025   }
2026 
2027   if (MachineType == EFI_IMAGE_MACHINE_ARMT) {
2028     // B SecEntryPoint - signed_immed_24 part +/-32MB offset
2029     // on ARM, the PC is always 8 ahead, so we're not really jumping from the base address, but from base address + 8
2030     ResetVector[0] = (INT32)(SecCorePhysicalAddress - FvInfo->BaseAddress - 8) >> 2;
2031 
2032     if (ResetVector[0] > 0x00FFFFFF) {
2033       Error (NULL, 0, 3000, "Invalid", "SEC Entry point must be within 32MB of the start of the FV");
2034       return EFI_ABORTED;
2035     }
2036 
2037     // Add opcode for an uncondional branch with no link. AKA B SecEntryPoint
2038     ResetVector[0] |= 0xEB000000;
2039 
2040 
2041     // Address of PEI Core, if we have one
2042     ResetVector[1] = (UINT32)PeiCorePhysicalAddress;
2043 
2044     // SWI handler movs   pc,lr. Just in case a debugger uses SWI
2045     ResetVector[2] = 0xE1B0F07E;
2046 
2047     // Place holder to support a common interrupt handler from ROM.
2048     // Currently not suppprted. For this to be used the reset vector would not be in this FV
2049     // and the exception vectors would be hard coded in the ROM and just through this address
2050     // to find a common handler in the a module in the FV.
2051     ResetVector[3] = 0;
2052   } else if (MachineType == EFI_IMAGE_MACHINE_AARCH64) {
2053 
2054   /* NOTE:
2055     ARMT above has an entry in ResetVector[2] for SWI. The way we are using the ResetVector
2056     array at the moment, for AArch64, does not allow us space for this as the header only
2057     allows for a fixed amount of bytes at the start. If we are sure that UEFI will live
2058     within the first 4GB of addressable RAM we could potensioally adopt the same ResetVector
2059     layout as above. But for the moment we replace the four 32bit vectors with two 64bit
2060     vectors in the same area of the Image heasder. This allows UEFI to start from a 64bit
2061     base.
2062   */
2063 
2064     ((UINT64*)ResetVector)[0] = (UINT64)(SecCorePhysicalAddress - FvInfo->BaseAddress) >> 2;
2065 
2066     // B SecEntryPoint - signed_immed_26 part +/-128MB offset
2067     if ( ((UINT64*)ResetVector)[0] > 0x03FFFFFF) {
2068       Error (NULL, 0, 3000, "Invalid", "SEC Entry point must be within 128MB of the start of the FV");
2069       return EFI_ABORTED;
2070     }
2071     // Add opcode for an uncondional branch with no link. AKA B SecEntryPoint
2072     ((UINT64*)ResetVector)[0] |= 0x14000000;
2073 
2074     // Address of PEI Core, if we have one
2075     ((UINT64*)ResetVector)[1] = (UINT64)PeiCorePhysicalAddress;
2076 
2077   } else {
2078     Error (NULL, 0, 3000, "Invalid", "Unknown ARM machine type");
2079     return EFI_ABORTED;
2080   }
2081 
2082   //
2083   // Copy to the beginning of the FV
2084   //
2085   memcpy ((UINT8 *) ((UINTN) FvImage->FileImage), ResetVector, sizeof (ResetVector));
2086 
2087   DebugMsg (NULL, 0, 9, "Update Reset vector in FV Header", NULL);
2088 
2089   return EFI_SUCCESS;
2090 }
2091 
2092 EFI_STATUS
GetPe32Info(IN UINT8 * Pe32,OUT UINT32 * EntryPoint,OUT UINT32 * BaseOfCode,OUT UINT16 * MachineType)2093 GetPe32Info (
2094   IN UINT8                  *Pe32,
2095   OUT UINT32                *EntryPoint,
2096   OUT UINT32                *BaseOfCode,
2097   OUT UINT16                *MachineType
2098   )
2099 /*++
2100 
2101 Routine Description:
2102 
2103   Retrieves the PE32 entry point offset and machine type from PE image or TeImage.
2104   See EfiImage.h for machine types.  The entry point offset is from the beginning
2105   of the PE32 buffer passed in.
2106 
2107 Arguments:
2108 
2109   Pe32          Beginning of the PE32.
2110   EntryPoint    Offset from the beginning of the PE32 to the image entry point.
2111   BaseOfCode    Base address of code.
2112   MachineType   Magic number for the machine type.
2113 
2114 Returns:
2115 
2116   EFI_SUCCESS             Function completed successfully.
2117   EFI_ABORTED             Error encountered.
2118   EFI_INVALID_PARAMETER   A required parameter was NULL.
2119   EFI_UNSUPPORTED         The operation is unsupported.
2120 
2121 --*/
2122 {
2123   EFI_IMAGE_DOS_HEADER             *DosHeader;
2124   EFI_IMAGE_OPTIONAL_HEADER_UNION  *ImgHdr;
2125   EFI_TE_IMAGE_HEADER              *TeHeader;
2126 
2127   //
2128   // Verify input parameters
2129   //
2130   if (Pe32 == NULL) {
2131     return EFI_INVALID_PARAMETER;
2132   }
2133 
2134   //
2135   // First check whether it is one TE Image.
2136   //
2137   TeHeader = (EFI_TE_IMAGE_HEADER *) Pe32;
2138   if (TeHeader->Signature == EFI_TE_IMAGE_HEADER_SIGNATURE) {
2139     //
2140     // By TeImage Header to get output
2141     //
2142     *EntryPoint   = TeHeader->AddressOfEntryPoint + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;
2143     *BaseOfCode   = TeHeader->BaseOfCode + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize;
2144     *MachineType  = TeHeader->Machine;
2145   } else {
2146 
2147     //
2148     // Then check whether
2149     // First is the DOS header
2150     //
2151     DosHeader = (EFI_IMAGE_DOS_HEADER *) Pe32;
2152 
2153     //
2154     // Verify DOS header is expected
2155     //
2156     if (DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
2157       Error (NULL, 0, 3000, "Invalid", "Unknown magic number in the DOS header, 0x%04X.", DosHeader->e_magic);
2158       return EFI_UNSUPPORTED;
2159     }
2160     //
2161     // Immediately following is the NT header.
2162     //
2163     ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN) Pe32 + DosHeader->e_lfanew);
2164 
2165     //
2166     // Verify NT header is expected
2167     //
2168     if (ImgHdr->Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
2169       Error (NULL, 0, 3000, "Invalid", "Unrecognized image signature 0x%08X.", (unsigned) ImgHdr->Pe32.Signature);
2170       return EFI_UNSUPPORTED;
2171     }
2172     //
2173     // Get output
2174     //
2175     *EntryPoint   = ImgHdr->Pe32.OptionalHeader.AddressOfEntryPoint;
2176     *BaseOfCode   = ImgHdr->Pe32.OptionalHeader.BaseOfCode;
2177     *MachineType  = ImgHdr->Pe32.FileHeader.Machine;
2178   }
2179 
2180   //
2181   // Verify machine type is supported
2182   //
2183   if ((*MachineType != EFI_IMAGE_MACHINE_IA32) && (*MachineType != EFI_IMAGE_MACHINE_IA64) && (*MachineType != EFI_IMAGE_MACHINE_X64) && (*MachineType != EFI_IMAGE_MACHINE_EBC) &&
2184       (*MachineType != EFI_IMAGE_MACHINE_ARMT) && (*MachineType != EFI_IMAGE_MACHINE_AARCH64)) {
2185     Error (NULL, 0, 3000, "Invalid", "Unrecognized machine type in the PE32 file.");
2186     return EFI_UNSUPPORTED;
2187   }
2188 
2189   return EFI_SUCCESS;
2190 }
2191 
2192 EFI_STATUS
GenerateFvImage(IN CHAR8 * InfFileImage,IN UINTN InfFileSize,IN CHAR8 * FvFileName,IN CHAR8 * MapFileName)2193 GenerateFvImage (
2194   IN CHAR8                *InfFileImage,
2195   IN UINTN                InfFileSize,
2196   IN CHAR8                *FvFileName,
2197   IN CHAR8                *MapFileName
2198   )
2199 /*++
2200 
2201 Routine Description:
2202 
2203   This is the main function which will be called from application.
2204 
2205 Arguments:
2206 
2207   InfFileImage   Buffer containing the INF file contents.
2208   InfFileSize    Size of the contents of the InfFileImage buffer.
2209   FvFileName     Requested name for the FV file.
2210   MapFileName    Fv map file to log fv driver information.
2211 
2212 Returns:
2213 
2214   EFI_SUCCESS             Function completed successfully.
2215   EFI_OUT_OF_RESOURCES    Could not allocate required resources.
2216   EFI_ABORTED             Error encountered.
2217   EFI_INVALID_PARAMETER   A required parameter was NULL.
2218 
2219 --*/
2220 {
2221   EFI_STATUS                      Status;
2222   MEMORY_FILE                     InfMemoryFile;
2223   MEMORY_FILE                     FvImageMemoryFile;
2224   UINTN                           Index;
2225   EFI_FIRMWARE_VOLUME_HEADER      *FvHeader;
2226   EFI_FFS_FILE_HEADER             *VtfFileImage;
2227   UINT8                           *FvBufferHeader; // to make sure fvimage header 8 type alignment.
2228   UINT8                           *FvImage;
2229   UINTN                           FvImageSize;
2230   FILE                            *FvFile;
2231   CHAR8                           FvMapName [MAX_LONG_FILE_PATH];
2232   FILE                            *FvMapFile;
2233   EFI_FIRMWARE_VOLUME_EXT_HEADER  *FvExtHeader;
2234   FILE                            *FvExtHeaderFile;
2235   UINTN                           FileSize;
2236   CHAR8                           FvReportName[MAX_LONG_FILE_PATH];
2237   FILE                            *FvReportFile;
2238 
2239   FvBufferHeader = NULL;
2240   FvFile         = NULL;
2241   FvMapFile      = NULL;
2242   FvReportFile   = NULL;
2243 
2244   if (InfFileImage != NULL) {
2245     //
2246     // Initialize file structures
2247     //
2248     InfMemoryFile.FileImage           = InfFileImage;
2249     InfMemoryFile.CurrentFilePointer  = InfFileImage;
2250     InfMemoryFile.Eof                 = InfFileImage + InfFileSize;
2251 
2252     //
2253     // Parse the FV inf file for header information
2254     //
2255     Status = ParseFvInf (&InfMemoryFile, &mFvDataInfo);
2256     if (EFI_ERROR (Status)) {
2257       Error (NULL, 0, 0003, "Error parsing file", "the input FV INF file.");
2258       return Status;
2259     }
2260   }
2261 
2262   //
2263   // Update the file name return values
2264   //
2265   if (FvFileName == NULL && mFvDataInfo.FvName[0] != '\0') {
2266     FvFileName = mFvDataInfo.FvName;
2267   }
2268 
2269   if (FvFileName == NULL) {
2270     Error (NULL, 0, 1001, "Missing option", "Output file name");
2271     return EFI_ABORTED;
2272   }
2273 
2274   if (mFvDataInfo.FvBlocks[0].Length == 0) {
2275     Error (NULL, 0, 1001, "Missing required argument", "Block Size");
2276     return EFI_ABORTED;
2277   }
2278 
2279   //
2280   // Debug message Fv File System Guid
2281   //
2282   if (mFvDataInfo.FvFileSystemGuidSet) {
2283     DebugMsg (NULL, 0, 9, "FV File System Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
2284                   (unsigned) mFvDataInfo.FvFileSystemGuid.Data1,
2285                   mFvDataInfo.FvFileSystemGuid.Data2,
2286                   mFvDataInfo.FvFileSystemGuid.Data3,
2287                   mFvDataInfo.FvFileSystemGuid.Data4[0],
2288                   mFvDataInfo.FvFileSystemGuid.Data4[1],
2289                   mFvDataInfo.FvFileSystemGuid.Data4[2],
2290                   mFvDataInfo.FvFileSystemGuid.Data4[3],
2291                   mFvDataInfo.FvFileSystemGuid.Data4[4],
2292                   mFvDataInfo.FvFileSystemGuid.Data4[5],
2293                   mFvDataInfo.FvFileSystemGuid.Data4[6],
2294                   mFvDataInfo.FvFileSystemGuid.Data4[7]);
2295   }
2296 
2297   //
2298   // Add PI FV extension header
2299   //
2300   FvExtHeader = NULL;
2301   FvExtHeaderFile = NULL;
2302   if (mFvDataInfo.FvExtHeaderFile[0] != 0) {
2303     //
2304     // Open the FV Extension Header file
2305     //
2306     FvExtHeaderFile = fopen (LongFilePath (mFvDataInfo.FvExtHeaderFile), "rb");
2307 
2308     //
2309     // Get the file size
2310     //
2311     FileSize = _filelength (fileno (FvExtHeaderFile));
2312 
2313     //
2314     // Allocate a buffer for the FV Extension Header
2315     //
2316     FvExtHeader = malloc(FileSize);
2317     if (FvExtHeader == NULL) {
2318       fclose (FvExtHeaderFile);
2319       return EFI_OUT_OF_RESOURCES;
2320     }
2321 
2322     //
2323     // Read the FV Extension Header
2324     //
2325     fread (FvExtHeader, sizeof (UINT8), FileSize, FvExtHeaderFile);
2326     fclose (FvExtHeaderFile);
2327 
2328     //
2329     // See if there is an override for the FV Name GUID
2330     //
2331     if (mFvDataInfo.FvNameGuidSet) {
2332       memcpy (&FvExtHeader->FvName, &mFvDataInfo.FvNameGuid, sizeof (EFI_GUID));
2333     }
2334     memcpy (&mFvDataInfo.FvNameGuid, &FvExtHeader->FvName, sizeof (EFI_GUID));
2335     mFvDataInfo.FvNameGuidSet = TRUE;
2336   } else if (mFvDataInfo.FvNameGuidSet) {
2337     //
2338     // Allocate a buffer for the FV Extension Header
2339     //
2340     FvExtHeader = malloc(sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER));
2341     if (FvExtHeader == NULL) {
2342       return EFI_OUT_OF_RESOURCES;
2343     }
2344     memcpy (&FvExtHeader->FvName, &mFvDataInfo.FvNameGuid, sizeof (EFI_GUID));
2345     FvExtHeader->ExtHeaderSize = sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER);
2346   }
2347 
2348   //
2349   // Debug message Fv Name Guid
2350   //
2351   if (mFvDataInfo.FvNameGuidSet) {
2352       DebugMsg (NULL, 0, 9, "FV Name Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X",
2353                   (unsigned) mFvDataInfo.FvNameGuid.Data1,
2354                   mFvDataInfo.FvNameGuid.Data2,
2355                   mFvDataInfo.FvNameGuid.Data3,
2356                   mFvDataInfo.FvNameGuid.Data4[0],
2357                   mFvDataInfo.FvNameGuid.Data4[1],
2358                   mFvDataInfo.FvNameGuid.Data4[2],
2359                   mFvDataInfo.FvNameGuid.Data4[3],
2360                   mFvDataInfo.FvNameGuid.Data4[4],
2361                   mFvDataInfo.FvNameGuid.Data4[5],
2362                   mFvDataInfo.FvNameGuid.Data4[6],
2363                   mFvDataInfo.FvNameGuid.Data4[7]);
2364   }
2365 
2366   if (CompareGuid (&mFvDataInfo.FvFileSystemGuid, &mEfiFirmwareFileSystem2Guid) == 0 ||
2367     CompareGuid (&mFvDataInfo.FvFileSystemGuid, &mEfiFirmwareFileSystem3Guid) == 0) {
2368     mFvDataInfo.IsPiFvImage = TRUE;
2369   }
2370 
2371   //
2372   // FvMap file to log the function address of all modules in one Fvimage
2373   //
2374   if (MapFileName != NULL) {
2375     strcpy (FvMapName, MapFileName);
2376   } else {
2377     strcpy (FvMapName, FvFileName);
2378     strcat (FvMapName, ".map");
2379   }
2380   VerboseMsg ("FV Map file name is %s", FvMapName);
2381 
2382   //
2383   // FvReport file to log the FV information in one Fvimage
2384   //
2385   strcpy (FvReportName, FvFileName);
2386   strcat (FvReportName, ".txt");
2387 
2388   //
2389   // Calculate the FV size and Update Fv Size based on the actual FFS files.
2390   // And Update mFvDataInfo data.
2391   //
2392   Status = CalculateFvSize (&mFvDataInfo);
2393   if (EFI_ERROR (Status)) {
2394     return Status;
2395   }
2396   VerboseMsg ("the generated FV image size is %u bytes", (unsigned) mFvDataInfo.Size);
2397 
2398   //
2399   // support fv image and empty fv image
2400   //
2401   FvImageSize = mFvDataInfo.Size;
2402 
2403   //
2404   // Allocate the FV, assure FvImage Header 8 byte alignment
2405   //
2406   FvBufferHeader = malloc (FvImageSize + sizeof (UINT64));
2407   if (FvBufferHeader == NULL) {
2408     return EFI_OUT_OF_RESOURCES;
2409   }
2410   FvImage = (UINT8 *) (((UINTN) FvBufferHeader + 7) & ~7);
2411 
2412   //
2413   // Initialize the FV to the erase polarity
2414   //
2415   if (mFvDataInfo.FvAttributes == 0) {
2416     //
2417     // Set Default Fv Attribute
2418     //
2419     mFvDataInfo.FvAttributes = FV_DEFAULT_ATTRIBUTE;
2420   }
2421   if (mFvDataInfo.FvAttributes & EFI_FVB2_ERASE_POLARITY) {
2422     memset (FvImage, -1, FvImageSize);
2423   } else {
2424     memset (FvImage, 0, FvImageSize);
2425   }
2426 
2427   //
2428   // Initialize FV header
2429   //
2430   FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FvImage;
2431 
2432   //
2433   // Initialize the zero vector to all zeros.
2434   //
2435   memset (FvHeader->ZeroVector, 0, 16);
2436 
2437   //
2438   // Copy the Fv file system GUID
2439   //
2440   memcpy (&FvHeader->FileSystemGuid, &mFvDataInfo.FvFileSystemGuid, sizeof (EFI_GUID));
2441 
2442   FvHeader->FvLength        = FvImageSize;
2443   FvHeader->Signature       = EFI_FVH_SIGNATURE;
2444   FvHeader->Attributes      = mFvDataInfo.FvAttributes;
2445   FvHeader->Revision        = EFI_FVH_REVISION;
2446   FvHeader->ExtHeaderOffset = 0;
2447   FvHeader->Reserved[0]     = 0;
2448 
2449   //
2450   // Copy firmware block map
2451   //
2452   for (Index = 0; mFvDataInfo.FvBlocks[Index].Length != 0; Index++) {
2453     FvHeader->BlockMap[Index].NumBlocks   = mFvDataInfo.FvBlocks[Index].NumBlocks;
2454     FvHeader->BlockMap[Index].Length      = mFvDataInfo.FvBlocks[Index].Length;
2455   }
2456 
2457   //
2458   // Add block map terminator
2459   //
2460   FvHeader->BlockMap[Index].NumBlocks   = 0;
2461   FvHeader->BlockMap[Index].Length      = 0;
2462 
2463   //
2464   // Complete the header
2465   //
2466   FvHeader->HeaderLength  = (UINT16) (((UINTN) &(FvHeader->BlockMap[Index + 1])) - (UINTN) FvImage);
2467   FvHeader->Checksum      = 0;
2468   FvHeader->Checksum      = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
2469 
2470   //
2471   // If there is no FFS file, generate one empty FV
2472   //
2473   if (mFvDataInfo.FvFiles[0][0] == 0 && !mFvDataInfo.FvNameGuidSet) {
2474     goto WriteFile;
2475   }
2476 
2477   //
2478   // Initialize our "file" view of the buffer
2479   //
2480   FvImageMemoryFile.FileImage           = (CHAR8 *)FvImage;
2481   FvImageMemoryFile.CurrentFilePointer  = (CHAR8 *)FvImage + FvHeader->HeaderLength;
2482   FvImageMemoryFile.Eof                 = (CHAR8 *)FvImage + FvImageSize;
2483 
2484   //
2485   // Initialize the FV library.
2486   //
2487   InitializeFvLib (FvImageMemoryFile.FileImage, FvImageSize);
2488 
2489   //
2490   // Initialize the VTF file address.
2491   //
2492   VtfFileImage = (EFI_FFS_FILE_HEADER *) FvImageMemoryFile.Eof;
2493 
2494   //
2495   // Open FvMap file
2496   //
2497   FvMapFile = fopen (LongFilePath (FvMapName), "w");
2498   if (FvMapFile == NULL) {
2499     Error (NULL, 0, 0001, "Error opening file", FvMapName);
2500     return EFI_ABORTED;
2501   }
2502 
2503   //
2504   // Open FvReport file
2505   //
2506   FvReportFile = fopen (LongFilePath (FvReportName), "w");
2507   if (FvReportFile == NULL) {
2508     Error (NULL, 0, 0001, "Error opening file", FvReportName);
2509     return EFI_ABORTED;
2510   }
2511   //
2512   // record FV size information into FvMap file.
2513   //
2514   if (mFvTotalSize != 0) {
2515     fprintf (FvMapFile, EFI_FV_TOTAL_SIZE_STRING);
2516     fprintf (FvMapFile, " = 0x%x\n", (unsigned) mFvTotalSize);
2517   }
2518   if (mFvTakenSize != 0) {
2519     fprintf (FvMapFile, EFI_FV_TAKEN_SIZE_STRING);
2520     fprintf (FvMapFile, " = 0x%x\n", (unsigned) mFvTakenSize);
2521   }
2522   if (mFvTotalSize != 0 && mFvTakenSize != 0) {
2523     fprintf (FvMapFile, EFI_FV_SPACE_SIZE_STRING);
2524     fprintf (FvMapFile, " = 0x%x\n\n", (unsigned) (mFvTotalSize - mFvTakenSize));
2525   }
2526 
2527   //
2528   // record FV size information to FvReportFile.
2529   //
2530   fprintf (FvReportFile, "%s = 0x%x\n", EFI_FV_TOTAL_SIZE_STRING, (unsigned) mFvTotalSize);
2531   fprintf (FvReportFile, "%s = 0x%x\n", EFI_FV_TAKEN_SIZE_STRING, (unsigned) mFvTakenSize);
2532 
2533   //
2534   // Add PI FV extension header
2535   //
2536   if (FvExtHeader != NULL) {
2537     //
2538     // Add FV Extended Header contents to the FV as a PAD file
2539     //
2540     AddPadFile (&FvImageMemoryFile, 4, VtfFileImage, FvExtHeader, 0);
2541 
2542     //
2543     // Fv Extension header change update Fv Header Check sum
2544     //
2545     FvHeader->Checksum      = 0;
2546     FvHeader->Checksum      = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
2547   }
2548 
2549   //
2550   // Add files to FV
2551   //
2552   for (Index = 0; mFvDataInfo.FvFiles[Index][0] != 0; Index++) {
2553     //
2554     // Add the file
2555     //
2556     Status = AddFile (&FvImageMemoryFile, &mFvDataInfo, Index, &VtfFileImage, FvMapFile, FvReportFile);
2557 
2558     //
2559     // Exit if error detected while adding the file
2560     //
2561     if (EFI_ERROR (Status)) {
2562       goto Finish;
2563     }
2564   }
2565 
2566   //
2567   // If there is a VTF file, some special actions need to occur.
2568   //
2569   if ((UINTN) VtfFileImage != (UINTN) FvImageMemoryFile.Eof) {
2570     //
2571     // Pad from the end of the last file to the beginning of the VTF file.
2572     // If the left space is less than sizeof (EFI_FFS_FILE_HEADER)?
2573     //
2574     Status = PadFvImage (&FvImageMemoryFile, VtfFileImage);
2575     if (EFI_ERROR (Status)) {
2576       Error (NULL, 0, 4002, "Resource", "FV space is full, cannot add pad file between the last file and the VTF file.");
2577       goto Finish;
2578     }
2579     if (!mArm) {
2580       //
2581       // Update reset vector (SALE_ENTRY for IPF)
2582       // Now for IA32 and IA64 platform, the fv which has bsf file must have the
2583       // EndAddress of 0xFFFFFFFF. Thus, only this type fv needs to update the
2584       // reset vector. If the PEI Core is found, the VTF file will probably get
2585       // corrupted by updating the entry point.
2586       //
2587       if ((mFvDataInfo.BaseAddress + mFvDataInfo.Size) == FV_IMAGES_TOP_ADDRESS) {
2588         Status = UpdateResetVector (&FvImageMemoryFile, &mFvDataInfo, VtfFileImage);
2589         if (EFI_ERROR(Status)) {
2590           Error (NULL, 0, 3000, "Invalid", "Could not update the reset vector.");
2591           goto Finish;
2592         }
2593         DebugMsg (NULL, 0, 9, "Update Reset vector in VTF file", NULL);
2594       }
2595     }
2596   }
2597 
2598   if (mArm) {
2599     Status = UpdateArmResetVectorIfNeeded (&FvImageMemoryFile, &mFvDataInfo);
2600     if (EFI_ERROR (Status)) {
2601       Error (NULL, 0, 3000, "Invalid", "Could not update the reset vector.");
2602       goto Finish;
2603     }
2604 
2605     //
2606     // Update Checksum for FvHeader
2607     //
2608     FvHeader->Checksum = 0;
2609     FvHeader->Checksum = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
2610   }
2611 
2612   //
2613   // Update FV Alignment attribute to the largest alignment of all the FFS files in the FV
2614   //
2615   if (((FvHeader->Attributes & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) &&
2616       (((FvHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16)) < MaxFfsAlignment) {
2617     FvHeader->Attributes = ((MaxFfsAlignment << 16) | (FvHeader->Attributes & 0xFFFF));
2618     //
2619     // Update Checksum for FvHeader
2620     //
2621     FvHeader->Checksum      = 0;
2622     FvHeader->Checksum      = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
2623   }
2624 
2625   //
2626   // If there are large FFS in FV, the file system GUID should set to system 3 GUID.
2627   //
2628   if (mIsLargeFfs && CompareGuid (&FvHeader->FileSystemGuid, &mEfiFirmwareFileSystem2Guid) == 0) {
2629     memcpy (&FvHeader->FileSystemGuid, &mEfiFirmwareFileSystem3Guid, sizeof (EFI_GUID));
2630     FvHeader->Checksum      = 0;
2631     FvHeader->Checksum      = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16));
2632   }
2633 
2634 WriteFile:
2635   //
2636   // Write fv file
2637   //
2638   FvFile = fopen (LongFilePath (FvFileName), "wb");
2639   if (FvFile == NULL) {
2640     Error (NULL, 0, 0001, "Error opening file", FvFileName);
2641     Status = EFI_ABORTED;
2642     goto Finish;
2643   }
2644 
2645   if (fwrite (FvImage, 1, FvImageSize, FvFile) != FvImageSize) {
2646     Error (NULL, 0, 0002, "Error writing file", FvFileName);
2647     Status = EFI_ABORTED;
2648     goto Finish;
2649   }
2650 
2651 Finish:
2652   if (FvBufferHeader != NULL) {
2653     free (FvBufferHeader);
2654   }
2655 
2656   if (FvExtHeader != NULL) {
2657     free (FvExtHeader);
2658   }
2659 
2660   if (FvFile != NULL) {
2661     fflush (FvFile);
2662     fclose (FvFile);
2663   }
2664 
2665   if (FvMapFile != NULL) {
2666     fflush (FvMapFile);
2667     fclose (FvMapFile);
2668   }
2669 
2670   if (FvReportFile != NULL) {
2671     fflush (FvReportFile);
2672     fclose (FvReportFile);
2673   }
2674   return Status;
2675 }
2676 
2677 EFI_STATUS
UpdatePeiCoreEntryInFit(IN FIT_TABLE * FitTablePtr,IN UINT64 PeiCorePhysicalAddress)2678 UpdatePeiCoreEntryInFit (
2679   IN FIT_TABLE     *FitTablePtr,
2680   IN UINT64        PeiCorePhysicalAddress
2681   )
2682 /*++
2683 
2684 Routine Description:
2685 
2686   This function is used to update the Pei Core address in FIT, this can be used by Sec core to pass control from
2687   Sec to Pei Core
2688 
2689 Arguments:
2690 
2691   FitTablePtr             - The pointer of FIT_TABLE.
2692   PeiCorePhysicalAddress  - The address of Pei Core entry.
2693 
2694 Returns:
2695 
2696   EFI_SUCCESS             - The PEI_CORE FIT entry was updated successfully.
2697   EFI_NOT_FOUND           - Not found the PEI_CORE FIT entry.
2698 
2699 --*/
2700 {
2701   FIT_TABLE *TmpFitPtr;
2702   UINTN     Index;
2703   UINTN     NumFitComponents;
2704 
2705   TmpFitPtr         = FitTablePtr;
2706   NumFitComponents  = TmpFitPtr->CompSize;
2707 
2708   for (Index = 0; Index < NumFitComponents; Index++) {
2709     if ((TmpFitPtr->CvAndType & FIT_TYPE_MASK) == COMP_TYPE_FIT_PEICORE) {
2710       TmpFitPtr->CompAddress = PeiCorePhysicalAddress;
2711       return EFI_SUCCESS;
2712     }
2713 
2714     TmpFitPtr++;
2715   }
2716 
2717   return EFI_NOT_FOUND;
2718 }
2719 
2720 VOID
UpdateFitCheckSum(IN FIT_TABLE * FitTablePtr)2721 UpdateFitCheckSum (
2722   IN FIT_TABLE   *FitTablePtr
2723   )
2724 /*++
2725 
2726 Routine Description:
2727 
2728   This function is used to update the checksum for FIT.
2729 
2730 
2731 Arguments:
2732 
2733   FitTablePtr             - The pointer of FIT_TABLE.
2734 
2735 Returns:
2736 
2737   None.
2738 
2739 --*/
2740 {
2741   if ((FitTablePtr->CvAndType & CHECKSUM_BIT_MASK) >> 7) {
2742     FitTablePtr->CheckSum = 0;
2743     FitTablePtr->CheckSum = CalculateChecksum8 ((UINT8 *) FitTablePtr, FitTablePtr->CompSize * 16);
2744   }
2745 }
2746 
2747 EFI_STATUS
CalculateFvSize(FV_INFO * FvInfoPtr)2748 CalculateFvSize (
2749   FV_INFO *FvInfoPtr
2750   )
2751 /*++
2752 Routine Description:
2753   Calculate the FV size and Update Fv Size based on the actual FFS files.
2754   And Update FvInfo data.
2755 
2756 Arguments:
2757   FvInfoPtr     - The pointer to FV_INFO structure.
2758 
2759 Returns:
2760   EFI_ABORTED   - Ffs Image Error
2761   EFI_SUCCESS   - Successfully update FvSize
2762 --*/
2763 {
2764   UINTN               CurrentOffset;
2765   UINTN               Index;
2766   FILE                *fpin;
2767   UINTN               FfsFileSize;
2768   UINTN               FvExtendHeaderSize;
2769   UINT32              FfsAlignment;
2770   UINT32              FfsHeaderSize;
2771   EFI_FFS_FILE_HEADER FfsHeader;
2772   BOOLEAN             VtfFileFlag;
2773   UINTN               VtfFileSize;
2774 
2775   FvExtendHeaderSize = 0;
2776   VtfFileSize = 0;
2777   VtfFileFlag = FALSE;
2778   fpin  = NULL;
2779   Index = 0;
2780 
2781   //
2782   // Compute size for easy access later
2783   //
2784   FvInfoPtr->Size = 0;
2785   for (Index = 0; FvInfoPtr->FvBlocks[Index].NumBlocks > 0 && FvInfoPtr->FvBlocks[Index].Length > 0; Index++) {
2786     FvInfoPtr->Size += FvInfoPtr->FvBlocks[Index].NumBlocks * FvInfoPtr->FvBlocks[Index].Length;
2787   }
2788 
2789   //
2790   // Calculate the required sizes for all FFS files.
2791   //
2792   CurrentOffset = sizeof (EFI_FIRMWARE_VOLUME_HEADER);
2793 
2794   for (Index = 1;; Index ++) {
2795     CurrentOffset += sizeof (EFI_FV_BLOCK_MAP_ENTRY);
2796     if (FvInfoPtr->FvBlocks[Index].NumBlocks == 0 || FvInfoPtr->FvBlocks[Index].Length == 0) {
2797       break;
2798     }
2799   }
2800 
2801   //
2802   // Calculate PI extension header
2803   //
2804   if (mFvDataInfo.FvExtHeaderFile[0] != '\0') {
2805     fpin = fopen (LongFilePath (mFvDataInfo.FvExtHeaderFile), "rb");
2806     if (fpin == NULL) {
2807       Error (NULL, 0, 0001, "Error opening file", mFvDataInfo.FvExtHeaderFile);
2808       return EFI_ABORTED;
2809     }
2810     FvExtendHeaderSize = _filelength (fileno (fpin));
2811     fclose (fpin);
2812     if (sizeof (EFI_FFS_FILE_HEADER) + FvExtendHeaderSize >= MAX_FFS_SIZE) {
2813       CurrentOffset += sizeof (EFI_FFS_FILE_HEADER2) + FvExtendHeaderSize;
2814       mIsLargeFfs = TRUE;
2815     } else {
2816       CurrentOffset += sizeof (EFI_FFS_FILE_HEADER) + FvExtendHeaderSize;
2817     }
2818     CurrentOffset = (CurrentOffset + 7) & (~7);
2819   } else if (mFvDataInfo.FvNameGuidSet) {
2820     CurrentOffset += sizeof (EFI_FFS_FILE_HEADER) + sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER);
2821     CurrentOffset = (CurrentOffset + 7) & (~7);
2822   }
2823 
2824   //
2825   // Accumlate every FFS file size.
2826   //
2827   for (Index = 0; FvInfoPtr->FvFiles[Index][0] != 0; Index++) {
2828     //
2829     // Open FFS file
2830     //
2831     fpin = NULL;
2832     fpin = fopen (LongFilePath (FvInfoPtr->FvFiles[Index]), "rb");
2833     if (fpin == NULL) {
2834       Error (NULL, 0, 0001, "Error opening file", FvInfoPtr->FvFiles[Index]);
2835       return EFI_ABORTED;
2836     }
2837     //
2838     // Get the file size
2839     //
2840     FfsFileSize = _filelength (fileno (fpin));
2841     if (FfsFileSize >= MAX_FFS_SIZE) {
2842       FfsHeaderSize = sizeof(EFI_FFS_FILE_HEADER2);
2843       mIsLargeFfs = TRUE;
2844     } else {
2845       FfsHeaderSize = sizeof(EFI_FFS_FILE_HEADER);
2846     }
2847     //
2848     // Read Ffs File header
2849     //
2850     fread (&FfsHeader, sizeof (UINT8), sizeof (EFI_FFS_FILE_HEADER), fpin);
2851     //
2852     // close file
2853     //
2854     fclose (fpin);
2855 
2856     if (FvInfoPtr->IsPiFvImage) {
2857         //
2858         // Check whether this ffs file is vtf file
2859         //
2860         if (IsVtfFile (&FfsHeader)) {
2861           if (VtfFileFlag) {
2862             //
2863             // One Fv image can't have two vtf files.
2864             //
2865             Error (NULL, 0, 3000,"Invalid", "One Fv image can't have two vtf files.");
2866             return EFI_ABORTED;
2867           }
2868           VtfFileFlag = TRUE;
2869         VtfFileSize = FfsFileSize;
2870         continue;
2871       }
2872 
2873       //
2874       // Get the alignment of FFS file
2875       //
2876       ReadFfsAlignment (&FfsHeader, &FfsAlignment);
2877       FfsAlignment = 1 << FfsAlignment;
2878       //
2879       // Add Pad file
2880       //
2881       if (((CurrentOffset + FfsHeaderSize) % FfsAlignment) != 0) {
2882         //
2883         // Only EFI_FFS_FILE_HEADER is needed for a pad section.
2884         //
2885         CurrentOffset = (CurrentOffset + FfsHeaderSize + sizeof(EFI_FFS_FILE_HEADER) + FfsAlignment - 1) & ~(FfsAlignment - 1);
2886         CurrentOffset -= FfsHeaderSize;
2887       }
2888 	  }
2889 
2890     //
2891     // Add ffs file size
2892     //
2893     if (FvInfoPtr->SizeofFvFiles[Index] > FfsFileSize) {
2894     	CurrentOffset += FvInfoPtr->SizeofFvFiles[Index];
2895     } else {
2896     	CurrentOffset += FfsFileSize;
2897     }
2898 
2899     //
2900     // Make next ffs file start at QWord Boundry
2901     //
2902     if (FvInfoPtr->IsPiFvImage) {
2903     	CurrentOffset = (CurrentOffset + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1);
2904     }
2905   }
2906   CurrentOffset += VtfFileSize;
2907   DebugMsg (NULL, 0, 9, "FvImage size", "The calculated fv image size is 0x%x and the current set fv image size is 0x%x", (unsigned) CurrentOffset, (unsigned) FvInfoPtr->Size);
2908 
2909   if (FvInfoPtr->Size == 0) {
2910     //
2911     // Update FvInfo data
2912     //
2913     FvInfoPtr->FvBlocks[0].NumBlocks = CurrentOffset / FvInfoPtr->FvBlocks[0].Length + ((CurrentOffset % FvInfoPtr->FvBlocks[0].Length)?1:0);
2914     FvInfoPtr->Size = FvInfoPtr->FvBlocks[0].NumBlocks * FvInfoPtr->FvBlocks[0].Length;
2915     FvInfoPtr->FvBlocks[1].NumBlocks = 0;
2916     FvInfoPtr->FvBlocks[1].Length = 0;
2917   } else if (FvInfoPtr->Size < CurrentOffset) {
2918     //
2919     // Not invalid
2920     //
2921     Error (NULL, 0, 3000, "Invalid", "the required fv image size 0x%x exceeds the set fv image size 0x%x", (unsigned) CurrentOffset, (unsigned) FvInfoPtr->Size);
2922     return EFI_INVALID_PARAMETER;
2923   }
2924 
2925   //
2926   // Set Fv Size Information
2927   //
2928   mFvTotalSize = FvInfoPtr->Size;
2929   mFvTakenSize = CurrentOffset;
2930 
2931   return EFI_SUCCESS;
2932 }
2933 
2934 EFI_STATUS
FfsRebaseImageRead(IN VOID * FileHandle,IN UINTN FileOffset,IN OUT UINT32 * ReadSize,OUT VOID * Buffer)2935 FfsRebaseImageRead (
2936   IN     VOID    *FileHandle,
2937   IN     UINTN   FileOffset,
2938   IN OUT UINT32  *ReadSize,
2939   OUT    VOID    *Buffer
2940   )
2941 /*++
2942 
2943 Routine Description:
2944 
2945   Support routine for the PE/COFF Loader that reads a buffer from a PE/COFF file
2946 
2947 Arguments:
2948 
2949   FileHandle - The handle to the PE/COFF file
2950 
2951   FileOffset - The offset, in bytes, into the file to read
2952 
2953   ReadSize   - The number of bytes to read from the file starting at FileOffset
2954 
2955   Buffer     - A pointer to the buffer to read the data into.
2956 
2957 Returns:
2958 
2959   EFI_SUCCESS - ReadSize bytes of data were read into Buffer from the PE/COFF file starting at FileOffset
2960 
2961 --*/
2962 {
2963   CHAR8   *Destination8;
2964   CHAR8   *Source8;
2965   UINT32  Length;
2966 
2967   Destination8  = Buffer;
2968   Source8       = (CHAR8 *) ((UINTN) FileHandle + FileOffset);
2969   Length        = *ReadSize;
2970   while (Length--) {
2971     *(Destination8++) = *(Source8++);
2972   }
2973 
2974   return EFI_SUCCESS;
2975 }
2976 
2977 EFI_STATUS
GetChildFvFromFfs(IN FV_INFO * FvInfo,IN EFI_FFS_FILE_HEADER * FfsFile,IN UINTN XipOffset)2978 GetChildFvFromFfs (
2979   IN      FV_INFO               *FvInfo,
2980   IN      EFI_FFS_FILE_HEADER   *FfsFile,
2981   IN      UINTN                 XipOffset
2982   )
2983 /*++
2984 
2985 Routine Description:
2986 
2987   This function gets all child FvImages in the input FfsFile, and records
2988   their base address to the parent image.
2989 
2990 Arguments:
2991   FvInfo            A pointer to FV_INFO struture.
2992   FfsFile           A pointer to Ffs file image that may contain FvImage.
2993   XipOffset         The offset address to the parent FvImage base.
2994 
2995 Returns:
2996 
2997   EFI_SUCCESS        Base address of child Fv image is recorded.
2998 --*/
2999 {
3000   EFI_STATUS                          Status;
3001   UINTN                               Index;
3002   EFI_FILE_SECTION_POINTER            SubFvSection;
3003   EFI_FIRMWARE_VOLUME_HEADER          *SubFvImageHeader;
3004   EFI_PHYSICAL_ADDRESS                SubFvBaseAddress;
3005 
3006   for (Index = 1;; Index++) {
3007     //
3008     // Find FV section
3009     //
3010     Status = GetSectionByType (FfsFile, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, Index, &SubFvSection);
3011     if (EFI_ERROR (Status)) {
3012       break;
3013     }
3014     SubFvImageHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) SubFvSection.FVImageSection + GetSectionHeaderLength(SubFvSection.FVImageSection));
3015     //
3016     // Rebase on Flash
3017     //
3018     SubFvBaseAddress = FvInfo->BaseAddress + (UINTN) SubFvImageHeader - (UINTN) FfsFile + XipOffset;
3019     mFvBaseAddress[mFvBaseAddressNumber ++ ] = SubFvBaseAddress;
3020   }
3021 
3022   return EFI_SUCCESS;
3023 }
3024 
3025 EFI_STATUS
FfsRebase(IN OUT FV_INFO * FvInfo,IN CHAR8 * FileName,IN OUT EFI_FFS_FILE_HEADER * FfsFile,IN UINTN XipOffset,IN FILE * FvMapFile)3026 FfsRebase (
3027   IN OUT  FV_INFO               *FvInfo,
3028   IN      CHAR8                 *FileName,
3029   IN OUT  EFI_FFS_FILE_HEADER   *FfsFile,
3030   IN      UINTN                 XipOffset,
3031   IN      FILE                  *FvMapFile
3032   )
3033 /*++
3034 
3035 Routine Description:
3036 
3037   This function determines if a file is XIP and should be rebased.  It will
3038   rebase any PE32 sections found in the file using the base address.
3039 
3040 Arguments:
3041 
3042   FvInfo            A pointer to FV_INFO struture.
3043   FileName          Ffs File PathName
3044   FfsFile           A pointer to Ffs file image.
3045   XipOffset         The offset address to use for rebasing the XIP file image.
3046   FvMapFile         FvMapFile to record the function address in one Fvimage
3047 
3048 Returns:
3049 
3050   EFI_SUCCESS             The image was properly rebased.
3051   EFI_INVALID_PARAMETER   An input parameter is invalid.
3052   EFI_ABORTED             An error occurred while rebasing the input file image.
3053   EFI_OUT_OF_RESOURCES    Could not allocate a required resource.
3054   EFI_NOT_FOUND           No compressed sections could be found.
3055 
3056 --*/
3057 {
3058   EFI_STATUS                            Status;
3059   PE_COFF_LOADER_IMAGE_CONTEXT          ImageContext;
3060   PE_COFF_LOADER_IMAGE_CONTEXT          OrigImageContext;
3061   EFI_PHYSICAL_ADDRESS                  XipBase;
3062   EFI_PHYSICAL_ADDRESS                  NewPe32BaseAddress;
3063   UINTN                                 Index;
3064   EFI_FILE_SECTION_POINTER              CurrentPe32Section;
3065   EFI_FFS_FILE_STATE                    SavedState;
3066   EFI_IMAGE_OPTIONAL_HEADER_UNION       *ImgHdr;
3067   EFI_TE_IMAGE_HEADER                   *TEImageHeader;
3068   UINT8                                 *MemoryImagePointer;
3069   EFI_IMAGE_SECTION_HEADER              *SectionHeader;
3070   CHAR8                                 PeFileName [MAX_LONG_FILE_PATH];
3071   CHAR8                                 *Cptr;
3072   FILE                                  *PeFile;
3073   UINT8                                 *PeFileBuffer;
3074   UINT32                                PeFileSize;
3075   CHAR8                                 *PdbPointer;
3076   UINT32                                FfsHeaderSize;
3077   UINT32                                CurSecHdrSize;
3078 
3079   Index              = 0;
3080   MemoryImagePointer = NULL;
3081   TEImageHeader      = NULL;
3082   ImgHdr             = NULL;
3083   SectionHeader      = NULL;
3084   Cptr               = NULL;
3085   PeFile             = NULL;
3086   PeFileBuffer       = NULL;
3087 
3088   //
3089   // Don't need to relocate image when BaseAddress is zero and no ForceRebase Flag specified.
3090   //
3091   if ((FvInfo->BaseAddress == 0) && (FvInfo->ForceRebase == -1)) {
3092     return EFI_SUCCESS;
3093   }
3094 
3095   //
3096   // If ForceRebase Flag specified to FALSE, will always not take rebase action.
3097   //
3098   if (FvInfo->ForceRebase == 0) {
3099     return EFI_SUCCESS;
3100   }
3101 
3102 
3103   XipBase = FvInfo->BaseAddress + XipOffset;
3104 
3105   //
3106   // We only process files potentially containing PE32 sections.
3107   //
3108   switch (FfsFile->Type) {
3109     case EFI_FV_FILETYPE_SECURITY_CORE:
3110     case EFI_FV_FILETYPE_PEI_CORE:
3111     case EFI_FV_FILETYPE_PEIM:
3112     case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
3113     case EFI_FV_FILETYPE_DRIVER:
3114     case EFI_FV_FILETYPE_DXE_CORE:
3115       break;
3116     case EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE:
3117       //
3118       // Rebase the inside FvImage.
3119       //
3120       GetChildFvFromFfs (FvInfo, FfsFile, XipOffset);
3121 
3122       //
3123       // Search PE/TE section in FV sectin.
3124       //
3125       break;
3126     default:
3127       return EFI_SUCCESS;
3128   }
3129 
3130   FfsHeaderSize = GetFfsHeaderLength(FfsFile);
3131   //
3132   // Rebase each PE32 section
3133   //
3134   Status      = EFI_SUCCESS;
3135   for (Index = 1;; Index++) {
3136     //
3137     // Init Value
3138     //
3139     NewPe32BaseAddress = 0;
3140 
3141     //
3142     // Find Pe Image
3143     //
3144     Status = GetSectionByType (FfsFile, EFI_SECTION_PE32, Index, &CurrentPe32Section);
3145     if (EFI_ERROR (Status)) {
3146       break;
3147     }
3148     CurSecHdrSize = GetSectionHeaderLength(CurrentPe32Section.CommonHeader);
3149 
3150     //
3151     // Initialize context
3152     //
3153     memset (&ImageContext, 0, sizeof (ImageContext));
3154     ImageContext.Handle     = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize);
3155     ImageContext.ImageRead  = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;
3156     Status                  = PeCoffLoaderGetImageInfo (&ImageContext);
3157     if (EFI_ERROR (Status)) {
3158       Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int) Status);
3159       return Status;
3160     }
3161 
3162     if ( (ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) ||
3163          (ImageContext.Machine == EFI_IMAGE_MACHINE_AARCH64) ) {
3164       mArm = TRUE;
3165     }
3166 
3167     //
3168     // Keep Image Context for PE image in FV
3169     //
3170     memcpy (&OrigImageContext, &ImageContext, sizeof (ImageContext));
3171 
3172     //
3173     // Get File PdbPointer
3174     //
3175     PdbPointer = PeCoffLoaderGetPdbPointer (ImageContext.Handle);
3176 
3177     //
3178     // Get PeHeader pointer
3179     //
3180     ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize + ImageContext.PeCoffHeaderOffset);
3181 
3182     //
3183     // Calculate the PE32 base address, based on file type
3184     //
3185     switch (FfsFile->Type) {
3186       case EFI_FV_FILETYPE_SECURITY_CORE:
3187       case EFI_FV_FILETYPE_PEI_CORE:
3188       case EFI_FV_FILETYPE_PEIM:
3189       case EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER:
3190         //
3191         // Check if section-alignment and file-alignment match or not
3192         //
3193         if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {
3194           //
3195           // Xip module has the same section alignment and file alignment.
3196           //
3197           Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);
3198           return EFI_ABORTED;
3199         }
3200         //
3201         // PeImage has no reloc section. It will try to get reloc data from the original EFI image.
3202         //
3203         if (ImageContext.RelocationsStripped) {
3204           //
3205           // Construct the original efi file Name
3206           //
3207           strcpy (PeFileName, FileName);
3208           Cptr = PeFileName + strlen (PeFileName);
3209           while (*Cptr != '.') {
3210             Cptr --;
3211           }
3212           if (*Cptr != '.') {
3213             Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
3214             return EFI_ABORTED;
3215           } else {
3216             *(Cptr + 1) = 'e';
3217             *(Cptr + 2) = 'f';
3218             *(Cptr + 3) = 'i';
3219             *(Cptr + 4) = '\0';
3220           }
3221           PeFile = fopen (LongFilePath (PeFileName), "rb");
3222           if (PeFile == NULL) {
3223             Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
3224             //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
3225             //return EFI_ABORTED;
3226             break;
3227           }
3228           //
3229           // Get the file size
3230           //
3231           PeFileSize = _filelength (fileno (PeFile));
3232           PeFileBuffer = (UINT8 *) malloc (PeFileSize);
3233           if (PeFileBuffer == NULL) {
3234             Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
3235             return EFI_OUT_OF_RESOURCES;
3236           }
3237           //
3238           // Read Pe File
3239           //
3240           fread (PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);
3241           //
3242           // close file
3243           //
3244           fclose (PeFile);
3245           //
3246           // Handle pointer to the original efi image.
3247           //
3248           ImageContext.Handle = PeFileBuffer;
3249           Status              = PeCoffLoaderGetImageInfo (&ImageContext);
3250           if (EFI_ERROR (Status)) {
3251             Error (NULL, 0, 3000, "Invalid PeImage", "The input file is %s and the return status is %x", FileName, (int) Status);
3252             return Status;
3253           }
3254           ImageContext.RelocationsStripped = FALSE;
3255         }
3256 
3257         NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile;
3258         break;
3259 
3260       case EFI_FV_FILETYPE_DRIVER:
3261       case EFI_FV_FILETYPE_DXE_CORE:
3262         //
3263         // Check if section-alignment and file-alignment match or not
3264         //
3265         if ((ImgHdr->Pe32.OptionalHeader.SectionAlignment != ImgHdr->Pe32.OptionalHeader.FileAlignment)) {
3266           //
3267           // Xip module has the same section alignment and file alignment.
3268           //
3269           Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName);
3270           return EFI_ABORTED;
3271         }
3272         NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile;
3273         break;
3274 
3275       default:
3276         //
3277         // Not supported file type
3278         //
3279         return EFI_SUCCESS;
3280     }
3281 
3282     //
3283     // Relocation doesn't exist
3284     //
3285     if (ImageContext.RelocationsStripped) {
3286       Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
3287       continue;
3288     }
3289 
3290     //
3291     // Relocation exist and rebase
3292     //
3293     //
3294     // Load and Relocate Image Data
3295     //
3296     MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);
3297     if (MemoryImagePointer == NULL) {
3298       Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
3299       return EFI_OUT_OF_RESOURCES;
3300     }
3301     memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);
3302     ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((UINTN) ImageContext.SectionAlignment - 1));
3303 
3304     Status =  PeCoffLoaderLoadImage (&ImageContext);
3305     if (EFI_ERROR (Status)) {
3306       Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);
3307       free ((VOID *) MemoryImagePointer);
3308       return Status;
3309     }
3310 
3311     ImageContext.DestinationAddress = NewPe32BaseAddress;
3312     Status                          = PeCoffLoaderRelocateImage (&ImageContext);
3313     if (EFI_ERROR (Status)) {
3314       Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of %s", FileName);
3315       free ((VOID *) MemoryImagePointer);
3316       return Status;
3317     }
3318 
3319     //
3320     // Copy Relocated data to raw image file.
3321     //
3322     SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (
3323                        (UINTN) ImgHdr +
3324                        sizeof (UINT32) +
3325                        sizeof (EFI_IMAGE_FILE_HEADER) +
3326                        ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader
3327                        );
3328 
3329     for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) {
3330       CopyMem (
3331         (UINT8 *) CurrentPe32Section.Pe32Section + CurSecHdrSize + SectionHeader->PointerToRawData,
3332         (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress),
3333         SectionHeader->SizeOfRawData
3334         );
3335     }
3336 
3337     free ((VOID *) MemoryImagePointer);
3338     MemoryImagePointer = NULL;
3339     if (PeFileBuffer != NULL) {
3340       free (PeFileBuffer);
3341       PeFileBuffer = NULL;
3342     }
3343 
3344     //
3345     // Update Image Base Address
3346     //
3347     if (ImgHdr->Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
3348       ImgHdr->Pe32.OptionalHeader.ImageBase = (UINT32) NewPe32BaseAddress;
3349     } else if (ImgHdr->Pe32Plus.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
3350       ImgHdr->Pe32Plus.OptionalHeader.ImageBase = NewPe32BaseAddress;
3351     } else {
3352       Error (NULL, 0, 3000, "Invalid", "unknown PE magic signature %X in PE32 image %s",
3353         ImgHdr->Pe32.OptionalHeader.Magic,
3354         FileName
3355         );
3356       return EFI_ABORTED;
3357     }
3358 
3359     //
3360     // Now update file checksum
3361     //
3362     if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
3363       SavedState  = FfsFile->State;
3364       FfsFile->IntegrityCheck.Checksum.File = 0;
3365       FfsFile->State                        = 0;
3366       FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (
3367                                                 (UINT8 *) ((UINT8 *)FfsFile + FfsHeaderSize),
3368                                                 GetFfsFileLength (FfsFile) - FfsHeaderSize
3369                                                 );
3370       FfsFile->State = SavedState;
3371     }
3372 
3373     //
3374     // Get this module function address from ModulePeMapFile and add them into FvMap file
3375     //
3376 
3377     //
3378     // Default use FileName as map file path
3379     //
3380     if (PdbPointer == NULL) {
3381       PdbPointer = FileName;
3382     }
3383 
3384     WriteMapFile (FvMapFile, PdbPointer, FfsFile, NewPe32BaseAddress, &OrigImageContext);
3385   }
3386 
3387   if (FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE &&
3388       FfsFile->Type != EFI_FV_FILETYPE_PEI_CORE &&
3389       FfsFile->Type != EFI_FV_FILETYPE_PEIM &&
3390       FfsFile->Type != EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER &&
3391       FfsFile->Type != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
3392       ) {
3393     //
3394     // Only Peim code may have a TE section
3395     //
3396     return EFI_SUCCESS;
3397   }
3398 
3399   //
3400   // Now process TE sections
3401   //
3402   for (Index = 1;; Index++) {
3403     NewPe32BaseAddress = 0;
3404 
3405     //
3406     // Find Te Image
3407     //
3408     Status = GetSectionByType (FfsFile, EFI_SECTION_TE, Index, &CurrentPe32Section);
3409     if (EFI_ERROR (Status)) {
3410       break;
3411     }
3412 
3413     CurSecHdrSize = GetSectionHeaderLength(CurrentPe32Section.CommonHeader);
3414 
3415     //
3416     // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off
3417     // by GenTEImage
3418     //
3419     TEImageHeader = (EFI_TE_IMAGE_HEADER *) ((UINT8 *) CurrentPe32Section.Pe32Section + CurSecHdrSize);
3420 
3421     //
3422     // Initialize context, load image info.
3423     //
3424     memset (&ImageContext, 0, sizeof (ImageContext));
3425     ImageContext.Handle     = (VOID *) TEImageHeader;
3426     ImageContext.ImageRead  = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead;
3427     Status                  = PeCoffLoaderGetImageInfo (&ImageContext);
3428     if (EFI_ERROR (Status)) {
3429       Error (NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int) Status);
3430       return Status;
3431     }
3432 
3433     if ( (ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) ||
3434          (ImageContext.Machine == EFI_IMAGE_MACHINE_AARCH64) ) {
3435       mArm = TRUE;
3436     }
3437 
3438     //
3439     // Keep Image Context for TE image in FV
3440     //
3441     memcpy (&OrigImageContext, &ImageContext, sizeof (ImageContext));
3442 
3443     //
3444     // Get File PdbPointer
3445     //
3446     PdbPointer = PeCoffLoaderGetPdbPointer (ImageContext.Handle);
3447 
3448     //
3449     // Set new rebased address.
3450     //
3451     NewPe32BaseAddress = XipBase + (UINTN) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) \
3452                          - TEImageHeader->StrippedSize - (UINTN) FfsFile;
3453 
3454     //
3455     // if reloc is stripped, try to get the original efi image to get reloc info.
3456     //
3457     if (ImageContext.RelocationsStripped) {
3458       //
3459       // Construct the original efi file name
3460       //
3461       strcpy (PeFileName, FileName);
3462       Cptr = PeFileName + strlen (PeFileName);
3463       while (*Cptr != '.') {
3464         Cptr --;
3465       }
3466 
3467       if (*Cptr != '.') {
3468         Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
3469         return EFI_ABORTED;
3470       } else {
3471         *(Cptr + 1) = 'e';
3472         *(Cptr + 2) = 'f';
3473         *(Cptr + 3) = 'i';
3474         *(Cptr + 4) = '\0';
3475       }
3476 
3477       PeFile = fopen (LongFilePath (PeFileName), "rb");
3478       if (PeFile == NULL) {
3479         Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
3480         //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName);
3481         //return EFI_ABORTED;
3482       } else {
3483         //
3484         // Get the file size
3485         //
3486         PeFileSize = _filelength (fileno (PeFile));
3487         PeFileBuffer = (UINT8 *) malloc (PeFileSize);
3488         if (PeFileBuffer == NULL) {
3489           Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
3490           return EFI_OUT_OF_RESOURCES;
3491         }
3492         //
3493         // Read Pe File
3494         //
3495         fread (PeFileBuffer, sizeof (UINT8), PeFileSize, PeFile);
3496         //
3497         // close file
3498         //
3499         fclose (PeFile);
3500         //
3501         // Append reloc section into TeImage
3502         //
3503         ImageContext.Handle = PeFileBuffer;
3504         Status              = PeCoffLoaderGetImageInfo (&ImageContext);
3505         if (EFI_ERROR (Status)) {
3506           Error (NULL, 0, 3000, "Invalid TeImage", "The input file is %s and the return status is %x", FileName, (int) Status);
3507           return Status;
3508         }
3509         ImageContext.RelocationsStripped = FALSE;
3510       }
3511     }
3512     //
3513     // Relocation doesn't exist
3514     //
3515     if (ImageContext.RelocationsStripped) {
3516       Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName);
3517       continue;
3518     }
3519 
3520     //
3521     // Relocation exist and rebase
3522     //
3523     //
3524     // Load and Relocate Image Data
3525     //
3526     MemoryImagePointer = (UINT8 *) malloc ((UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);
3527     if (MemoryImagePointer == NULL) {
3528       Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName);
3529       return EFI_OUT_OF_RESOURCES;
3530     }
3531     memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment);
3532     ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((UINTN) ImageContext.SectionAlignment - 1));
3533 
3534     Status =  PeCoffLoaderLoadImage (&ImageContext);
3535     if (EFI_ERROR (Status)) {
3536       Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName);
3537       free ((VOID *) MemoryImagePointer);
3538       return Status;
3539     }
3540     //
3541     // Reloacate TeImage
3542     //
3543     ImageContext.DestinationAddress = NewPe32BaseAddress;
3544     Status                          = PeCoffLoaderRelocateImage (&ImageContext);
3545     if (EFI_ERROR (Status)) {
3546       Error (NULL, 0, 3000, "Invalid", "RelocateImage() call failed on rebase of TE image %s", FileName);
3547       free ((VOID *) MemoryImagePointer);
3548       return Status;
3549     }
3550 
3551     //
3552     // Copy the relocated image into raw image file.
3553     //
3554     SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (TEImageHeader + 1);
3555     for (Index = 0; Index < TEImageHeader->NumberOfSections; Index ++, SectionHeader ++) {
3556       if (!ImageContext.IsTeImage) {
3557         CopyMem (
3558           (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData,
3559           (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress),
3560           SectionHeader->SizeOfRawData
3561           );
3562       } else {
3563         CopyMem (
3564           (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData,
3565           (VOID*) (UINTN) (ImageContext.ImageAddress + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->VirtualAddress),
3566           SectionHeader->SizeOfRawData
3567           );
3568       }
3569     }
3570 
3571     //
3572     // Free the allocated memory resource
3573     //
3574     free ((VOID *) MemoryImagePointer);
3575     MemoryImagePointer = NULL;
3576     if (PeFileBuffer != NULL) {
3577       free (PeFileBuffer);
3578       PeFileBuffer = NULL;
3579     }
3580 
3581     //
3582     // Update Image Base Address
3583     //
3584     TEImageHeader->ImageBase = NewPe32BaseAddress;
3585 
3586     //
3587     // Now update file checksum
3588     //
3589     if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {
3590       SavedState  = FfsFile->State;
3591       FfsFile->IntegrityCheck.Checksum.File = 0;
3592       FfsFile->State                        = 0;
3593       FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 (
3594                                                 (UINT8 *)((UINT8 *)FfsFile + FfsHeaderSize),
3595                                                 GetFfsFileLength (FfsFile) - FfsHeaderSize
3596                                                 );
3597       FfsFile->State = SavedState;
3598     }
3599     //
3600     // Get this module function address from ModulePeMapFile and add them into FvMap file
3601     //
3602 
3603     //
3604     // Default use FileName as map file path
3605     //
3606     if (PdbPointer == NULL) {
3607       PdbPointer = FileName;
3608     }
3609 
3610     WriteMapFile (
3611       FvMapFile,
3612       PdbPointer,
3613       FfsFile,
3614       NewPe32BaseAddress,
3615       &OrigImageContext
3616       );
3617   }
3618 
3619   return EFI_SUCCESS;
3620 }
3621 
3622 EFI_STATUS
FindApResetVectorPosition(IN MEMORY_FILE * FvImage,OUT UINT8 ** Pointer)3623 FindApResetVectorPosition (
3624   IN  MEMORY_FILE  *FvImage,
3625   OUT UINT8        **Pointer
3626   )
3627 /*++
3628 
3629 Routine Description:
3630 
3631   Find the position in this FvImage to place Ap reset vector.
3632 
3633 Arguments:
3634 
3635   FvImage       Memory file for the FV memory image.
3636   Pointer       Pointer to pointer to position.
3637 
3638 Returns:
3639 
3640   EFI_NOT_FOUND   - No satisfied position is found.
3641   EFI_SUCCESS     - The suitable position is return.
3642 
3643 --*/
3644 {
3645   EFI_FFS_FILE_HEADER   *PadFile;
3646   UINT32                Index;
3647   EFI_STATUS            Status;
3648   UINT8                 *FixPoint;
3649   UINT32                FileLength;
3650 
3651   for (Index = 1; ;Index ++) {
3652     //
3653     // Find Pad File to add ApResetVector info
3654     //
3655     Status = GetFileByType (EFI_FV_FILETYPE_FFS_PAD, Index, &PadFile);
3656     if (EFI_ERROR (Status) || (PadFile == NULL)) {
3657       //
3658       // No Pad file to be found.
3659       //
3660       break;
3661     }
3662     //
3663     // Get Pad file size.
3664     //
3665     FileLength = GetFfsFileLength(PadFile);
3666     FileLength = (FileLength + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1);
3667     //
3668     // FixPoint must be align on 0x1000 relative to FvImage Header
3669     //
3670     FixPoint = (UINT8*) PadFile + GetFfsHeaderLength(PadFile);
3671     FixPoint = FixPoint + 0x1000 - (((UINTN) FixPoint - (UINTN) FvImage->FileImage) & 0xFFF);
3672     //
3673     // FixPoint be larger at the last place of one fv image.
3674     //
3675     while (((UINTN) FixPoint + SIZEOF_STARTUP_DATA_ARRAY - (UINTN) PadFile) <= FileLength) {
3676       FixPoint += 0x1000;
3677     }
3678     FixPoint -= 0x1000;
3679 
3680     if ((UINTN) FixPoint < ((UINTN) PadFile + GetFfsHeaderLength(PadFile))) {
3681       //
3682       // No alignment FixPoint in this Pad File.
3683       //
3684       continue;
3685     }
3686 
3687     if ((UINTN) FvImage->Eof - (UINTN)FixPoint <= 0x20000) {
3688       //
3689       // Find the position to place ApResetVector
3690       //
3691       *Pointer = FixPoint;
3692       return EFI_SUCCESS;
3693     }
3694   }
3695 
3696   return EFI_NOT_FOUND;
3697 }
3698 
3699 EFI_STATUS
ParseCapInf(IN MEMORY_FILE * InfFile,OUT CAP_INFO * CapInfo)3700 ParseCapInf (
3701   IN  MEMORY_FILE  *InfFile,
3702   OUT CAP_INFO     *CapInfo
3703   )
3704 /*++
3705 
3706 Routine Description:
3707 
3708   This function parses a Cap.INF file and copies info into a CAP_INFO structure.
3709 
3710 Arguments:
3711 
3712   InfFile        Memory file image.
3713   CapInfo        Information read from INF file.
3714 
3715 Returns:
3716 
3717   EFI_SUCCESS       INF file information successfully retrieved.
3718   EFI_ABORTED       INF file has an invalid format.
3719   EFI_NOT_FOUND     A required string was not found in the INF file.
3720 --*/
3721 {
3722   CHAR8       Value[MAX_LONG_FILE_PATH];
3723   UINT64      Value64;
3724   UINTN       Index, Number;
3725   EFI_STATUS  Status;
3726 
3727   //
3728   // Initialize Cap info
3729   //
3730   // memset (CapInfo, 0, sizeof (CAP_INFO));
3731   //
3732 
3733   //
3734   // Read the Capsule Guid
3735   //
3736   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_GUID_STRING, 0, Value);
3737   if (Status == EFI_SUCCESS) {
3738     //
3739     // Get the Capsule Guid
3740     //
3741     Status = StringToGuid (Value, &CapInfo->CapGuid);
3742     if (EFI_ERROR (Status)) {
3743       Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_GUID_STRING, Value);
3744       return EFI_ABORTED;
3745     }
3746     DebugMsg (NULL, 0, 9, "Capsule Guid", "%s = %s", EFI_CAPSULE_GUID_STRING, Value);
3747   }
3748 
3749   //
3750   // Read the Capsule Header Size
3751   //
3752   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_HEADER_SIZE_STRING, 0, Value);
3753   if (Status == EFI_SUCCESS) {
3754     Status = AsciiStringToUint64 (Value, FALSE, &Value64);
3755     if (EFI_ERROR (Status)) {
3756       Error (NULL, 0, 2000, "Invalid parameter", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING, Value);
3757       return EFI_ABORTED;
3758     }
3759     CapInfo->HeaderSize = (UINT32) Value64;
3760     DebugMsg (NULL, 0, 9, "Capsule Header size", "%s = %s", EFI_CAPSULE_HEADER_SIZE_STRING, Value);
3761   }
3762 
3763   //
3764   // Read the Capsule Flag
3765   //
3766   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_CAPSULE_FLAGS_STRING, 0, Value);
3767   if (Status == EFI_SUCCESS) {
3768     if (strstr (Value, "PopulateSystemTable") != NULL) {
3769       CapInfo->Flags |= CAPSULE_FLAGS_PERSIST_ACROSS_RESET | CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE;
3770       if (strstr (Value, "InitiateReset") != NULL) {
3771         CapInfo->Flags |= CAPSULE_FLAGS_INITIATE_RESET;
3772       }
3773     } else if (strstr (Value, "PersistAcrossReset") != NULL) {
3774       CapInfo->Flags |= CAPSULE_FLAGS_PERSIST_ACROSS_RESET;
3775       if (strstr (Value, "InitiateReset") != NULL) {
3776         CapInfo->Flags |= CAPSULE_FLAGS_INITIATE_RESET;
3777       }
3778     } else {
3779       Error (NULL, 0, 2000, "Invalid parameter", "invalid Flag setting for %s.", EFI_CAPSULE_FLAGS_STRING);
3780       return EFI_ABORTED;
3781     }
3782     DebugMsg (NULL, 0, 9, "Capsule Flag", Value);
3783   }
3784 
3785   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_OEM_CAPSULE_FLAGS_STRING, 0, Value);
3786   if (Status == EFI_SUCCESS) {
3787     Status = AsciiStringToUint64 (Value, FALSE, &Value64);
3788     if (EFI_ERROR (Status) || Value64 > 0xffff) {
3789       Error (NULL, 0, 2000, "Invalid parameter",
3790         "invalid Flag setting for %s. Must be integer value between 0x0000 and 0xffff.",
3791         EFI_OEM_CAPSULE_FLAGS_STRING);
3792       return EFI_ABORTED;
3793     }
3794     CapInfo->Flags |= Value64;
3795     DebugMsg (NULL, 0, 9, "Capsule Extend Flag", Value);
3796   }
3797 
3798   //
3799   // Read Capsule File name
3800   //
3801   Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_FILE_NAME_STRING, 0, Value);
3802   if (Status == EFI_SUCCESS) {
3803     //
3804     // Get output file name
3805     //
3806     strcpy (CapInfo->CapName, Value);
3807   }
3808 
3809   //
3810   // Read the Capsule FileImage
3811   //
3812   Number = 0;
3813   for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_CAP; Index++) {
3814     if (CapInfo->CapFiles[Index][0] != '\0') {
3815       continue;
3816     }
3817     //
3818     // Read the capsule file name
3819     //
3820     Status = FindToken (InfFile, FILES_SECTION_STRING, EFI_FILE_NAME_STRING, Number++, Value);
3821 
3822     if (Status == EFI_SUCCESS) {
3823       //
3824       // Add the file
3825       //
3826       strcpy (CapInfo->CapFiles[Index], Value);
3827       DebugMsg (NULL, 0, 9, "Capsule component file", "the %uth file name is %s", (unsigned) Index, CapInfo->CapFiles[Index]);
3828     } else {
3829       break;
3830     }
3831   }
3832 
3833   if (Index == 0) {
3834     Warning (NULL, 0, 0, "Capsule components are not specified.", NULL);
3835   }
3836 
3837   return EFI_SUCCESS;
3838 }
3839 
3840 EFI_STATUS
GenerateCapImage(IN CHAR8 * InfFileImage,IN UINTN InfFileSize,IN CHAR8 * CapFileName)3841 GenerateCapImage (
3842   IN CHAR8                *InfFileImage,
3843   IN UINTN                InfFileSize,
3844   IN CHAR8                *CapFileName
3845   )
3846 /*++
3847 
3848 Routine Description:
3849 
3850   This is the main function which will be called from application to create UEFI Capsule image.
3851 
3852 Arguments:
3853 
3854   InfFileImage   Buffer containing the INF file contents.
3855   InfFileSize    Size of the contents of the InfFileImage buffer.
3856   CapFileName    Requested name for the Cap file.
3857 
3858 Returns:
3859 
3860   EFI_SUCCESS             Function completed successfully.
3861   EFI_OUT_OF_RESOURCES    Could not allocate required resources.
3862   EFI_ABORTED             Error encountered.
3863   EFI_INVALID_PARAMETER   A required parameter was NULL.
3864 
3865 --*/
3866 {
3867   UINT32                CapSize;
3868   UINT8                 *CapBuffer;
3869   EFI_CAPSULE_HEADER    *CapsuleHeader;
3870   MEMORY_FILE           InfMemoryFile;
3871   UINT32                FileSize;
3872   UINT32                Index;
3873   FILE                  *fpin, *fpout;
3874   EFI_STATUS            Status;
3875 
3876   if (InfFileImage != NULL) {
3877     //
3878     // Initialize file structures
3879     //
3880     InfMemoryFile.FileImage           = InfFileImage;
3881     InfMemoryFile.CurrentFilePointer  = InfFileImage;
3882     InfMemoryFile.Eof                 = InfFileImage + InfFileSize;
3883 
3884     //
3885     // Parse the Cap inf file for header information
3886     //
3887     Status = ParseCapInf (&InfMemoryFile, &mCapDataInfo);
3888     if (Status != EFI_SUCCESS) {
3889       return Status;
3890     }
3891   }
3892 
3893   if (mCapDataInfo.HeaderSize == 0) {
3894     //
3895     // make header size align 16 bytes.
3896     //
3897     mCapDataInfo.HeaderSize = sizeof (EFI_CAPSULE_HEADER);
3898     mCapDataInfo.HeaderSize = (mCapDataInfo.HeaderSize + 0xF) & ~0xF;
3899   }
3900 
3901   if (mCapDataInfo.HeaderSize < sizeof (EFI_CAPSULE_HEADER)) {
3902     Error (NULL, 0, 2000, "Invalid parameter", "The specified HeaderSize cannot be less than the size of EFI_CAPSULE_HEADER.");
3903     return EFI_INVALID_PARAMETER;
3904   }
3905 
3906   if (CapFileName == NULL && mCapDataInfo.CapName[0] != '\0') {
3907     CapFileName = mCapDataInfo.CapName;
3908   }
3909 
3910   if (CapFileName == NULL) {
3911     Error (NULL, 0, 2001, "Missing required argument", "Output Capsule file name");
3912     return EFI_INVALID_PARAMETER;
3913   }
3914 
3915   //
3916   // Set Default Capsule Guid value
3917   //
3918   if (CompareGuid (&mCapDataInfo.CapGuid, &mZeroGuid) == 0) {
3919     memcpy (&mCapDataInfo.CapGuid, &mDefaultCapsuleGuid, sizeof (EFI_GUID));
3920   }
3921   //
3922   // Calculate the size of capsule image.
3923   //
3924   Index    = 0;
3925   FileSize = 0;
3926   CapSize  = mCapDataInfo.HeaderSize;
3927   while (mCapDataInfo.CapFiles [Index][0] != '\0') {
3928     fpin = fopen (LongFilePath (mCapDataInfo.CapFiles[Index]), "rb");
3929     if (fpin == NULL) {
3930       Error (NULL, 0, 0001, "Error opening file", mCapDataInfo.CapFiles[Index]);
3931       return EFI_ABORTED;
3932     }
3933     FileSize  = _filelength (fileno (fpin));
3934     CapSize  += FileSize;
3935     fclose (fpin);
3936     Index ++;
3937   }
3938 
3939   //
3940   // Allocate buffer for capsule image.
3941   //
3942   CapBuffer = (UINT8 *) malloc (CapSize);
3943   if (CapBuffer == NULL) {
3944     Error (NULL, 0, 4001, "Resource", "memory cannot be allocated for creating the capsule.");
3945     return EFI_OUT_OF_RESOURCES;
3946   }
3947 
3948   //
3949   // Initialize the capsule header to zero
3950   //
3951   memset (CapBuffer, 0, mCapDataInfo.HeaderSize);
3952 
3953   //
3954   // create capsule header and get capsule body
3955   //
3956   CapsuleHeader = (EFI_CAPSULE_HEADER *) CapBuffer;
3957   memcpy (&CapsuleHeader->CapsuleGuid, &mCapDataInfo.CapGuid, sizeof (EFI_GUID));
3958   CapsuleHeader->HeaderSize       = mCapDataInfo.HeaderSize;
3959   CapsuleHeader->Flags            = mCapDataInfo.Flags;
3960   CapsuleHeader->CapsuleImageSize = CapSize;
3961 
3962   Index    = 0;
3963   FileSize = 0;
3964   CapSize  = CapsuleHeader->HeaderSize;
3965   while (mCapDataInfo.CapFiles [Index][0] != '\0') {
3966     fpin = fopen (LongFilePath (mCapDataInfo.CapFiles[Index]), "rb");
3967     if (fpin == NULL) {
3968       Error (NULL, 0, 0001, "Error opening file", mCapDataInfo.CapFiles[Index]);
3969       free (CapBuffer);
3970       return EFI_ABORTED;
3971     }
3972     FileSize = _filelength (fileno (fpin));
3973     fread (CapBuffer + CapSize, 1, FileSize, fpin);
3974     fclose (fpin);
3975     Index ++;
3976     CapSize += FileSize;
3977   }
3978 
3979   //
3980   // write capsule data into the output file
3981   //
3982   fpout = fopen (LongFilePath (CapFileName), "wb");
3983   if (fpout == NULL) {
3984     Error (NULL, 0, 0001, "Error opening file", CapFileName);
3985     free (CapBuffer);
3986     return EFI_ABORTED;
3987   }
3988 
3989   fwrite (CapBuffer, 1, CapSize, fpout);
3990   fclose (fpout);
3991 
3992   VerboseMsg ("The size of the generated capsule image is %u bytes", (unsigned) CapSize);
3993 
3994   return EFI_SUCCESS;
3995 }
3996