Home | History | Annotate | Download | only in GenFv
      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
    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
    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
    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
    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
    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
    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
    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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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
   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