X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=BaseTools%2FSource%2FC%2FGenFv%2FGenFvInternalLib.c;h=6a874f4e944fd56f6f286f1b91bfbaa78b8b6b02;hb=ecbaa856da0c94b7054f795d001ee3f5aaee033e;hp=d86909b4df63e15df65eeabec1a4de3a35a0c9ba;hpb=b36d134faf4305247830522b8e2bb255e98c5699;p=mirror_edk2.git diff --git a/BaseTools/Source/C/GenFv/GenFvInternalLib.c b/BaseTools/Source/C/GenFv/GenFvInternalLib.c index d86909b4df..6a874f4e94 100644 --- a/BaseTools/Source/C/GenFv/GenFvInternalLib.c +++ b/BaseTools/Source/C/GenFv/GenFvInternalLib.c @@ -1,29 +1,29 @@ /** @file +This file contains the internal functions required to generate a Firmware Volume. -Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.
-This program and the accompanying materials -are licensed and made available under the terms and conditions of the BSD License -which accompanies this distribution. The full text of the license may be found at -http://opensource.org/licenses/bsd-license.php - -THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, -WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. +Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.
+Portions Copyright (c) 2011 - 2013, ARM Ltd. All rights reserved.
+Portions Copyright (c) 2016 HP Development Company, L.P.
+This program and the accompanying materials +are licensed and made available under the terms and conditions of the BSD License +which accompanies this distribution. The full text of the license may be found at +http://opensource.org/licenses/bsd-license.php -Module Name: - - GenFvInternalLib.c - -Abstract: - - This file contains the internal functions required to generate a Firmware Volume. +THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, +WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. **/ // // Include files // -#ifdef __GNUC__ + +#if defined(__FreeBSD__) +#include +#elif defined(__GNUC__) #include +#endif +#ifdef __GNUC__ #include #endif #include @@ -32,70 +32,77 @@ Abstract: #endif #include +#include + +#include "WinNtInclude.h" #include "GenFvInternalLib.h" #include "FvLib.h" #include "PeCoffLib.h" -#include "WinNtInclude.h" + +#define ARMT_UNCONDITIONAL_JUMP_INSTRUCTION 0xEB000000 +#define ARM64_UNCONDITIONAL_JUMP_INSTRUCTION 0x14000000 BOOLEAN mArm = FALSE; STATIC UINT32 MaxFfsAlignment = 0; +BOOLEAN VtfFileFlag = FALSE; -EFI_GUID mEfiFirmwareVolumeTopFileGuid = EFI_FFS_VOLUME_TOP_FILE_GUID; +EFI_GUID mEfiFirmwareVolumeTopFileGuid = EFI_FFS_VOLUME_TOP_FILE_GUID; EFI_GUID mFileGuidArray [MAX_NUMBER_OF_FILES_IN_FV]; -EFI_GUID mZeroGuid = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; -EFI_GUID mDefaultCapsuleGuid = {0x3B6686BD, 0x0D76, 0x4030, { 0xB7, 0x0E, 0xB5, 0x51, 0x9E, 0x2F, 0xC5, 0xA0 }}; +EFI_GUID mZeroGuid = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; +EFI_GUID mDefaultCapsuleGuid = {0x3B6686BD, 0x0D76, 0x4030, { 0xB7, 0x0E, 0xB5, 0x51, 0x9E, 0x2F, 0xC5, 0xA0 }}; +EFI_GUID mEfiFfsSectionAlignmentPaddingGuid = EFI_FFS_SECTION_ALIGNMENT_PADDING_GUID; CHAR8 *mFvbAttributeName[] = { - EFI_FVB2_READ_DISABLED_CAP_STRING, - EFI_FVB2_READ_ENABLED_CAP_STRING, - EFI_FVB2_READ_STATUS_STRING, + EFI_FVB2_READ_DISABLED_CAP_STRING, + EFI_FVB2_READ_ENABLED_CAP_STRING, + EFI_FVB2_READ_STATUS_STRING, EFI_FVB2_WRITE_DISABLED_CAP_STRING, - EFI_FVB2_WRITE_ENABLED_CAP_STRING, - EFI_FVB2_WRITE_STATUS_STRING, - EFI_FVB2_LOCK_CAP_STRING, - EFI_FVB2_LOCK_STATUS_STRING, + EFI_FVB2_WRITE_ENABLED_CAP_STRING, + EFI_FVB2_WRITE_STATUS_STRING, + EFI_FVB2_LOCK_CAP_STRING, + EFI_FVB2_LOCK_STATUS_STRING, NULL, - EFI_FVB2_STICKY_WRITE_STRING, - EFI_FVB2_MEMORY_MAPPED_STRING, - EFI_FVB2_ERASE_POLARITY_STRING, - EFI_FVB2_READ_LOCK_CAP_STRING, - EFI_FVB2_READ_LOCK_STATUS_STRING, - EFI_FVB2_WRITE_LOCK_CAP_STRING, - EFI_FVB2_WRITE_LOCK_STATUS_STRING + EFI_FVB2_STICKY_WRITE_STRING, + EFI_FVB2_MEMORY_MAPPED_STRING, + EFI_FVB2_ERASE_POLARITY_STRING, + EFI_FVB2_READ_LOCK_CAP_STRING, + EFI_FVB2_READ_LOCK_STATUS_STRING, + EFI_FVB2_WRITE_LOCK_CAP_STRING, + EFI_FVB2_WRITE_LOCK_STATUS_STRING }; CHAR8 *mFvbAlignmentName[] = { - EFI_FVB2_ALIGNMENT_1_STRING, - EFI_FVB2_ALIGNMENT_2_STRING, - EFI_FVB2_ALIGNMENT_4_STRING, - EFI_FVB2_ALIGNMENT_8_STRING, - EFI_FVB2_ALIGNMENT_16_STRING, - EFI_FVB2_ALIGNMENT_32_STRING, - EFI_FVB2_ALIGNMENT_64_STRING, - EFI_FVB2_ALIGNMENT_128_STRING, - EFI_FVB2_ALIGNMENT_256_STRING, - EFI_FVB2_ALIGNMENT_512_STRING, - EFI_FVB2_ALIGNMENT_1K_STRING, - EFI_FVB2_ALIGNMENT_2K_STRING, - EFI_FVB2_ALIGNMENT_4K_STRING, - EFI_FVB2_ALIGNMENT_8K_STRING, - EFI_FVB2_ALIGNMENT_16K_STRING, - EFI_FVB2_ALIGNMENT_32K_STRING, - EFI_FVB2_ALIGNMENT_64K_STRING, + EFI_FVB2_ALIGNMENT_1_STRING, + EFI_FVB2_ALIGNMENT_2_STRING, + EFI_FVB2_ALIGNMENT_4_STRING, + EFI_FVB2_ALIGNMENT_8_STRING, + EFI_FVB2_ALIGNMENT_16_STRING, + EFI_FVB2_ALIGNMENT_32_STRING, + EFI_FVB2_ALIGNMENT_64_STRING, + EFI_FVB2_ALIGNMENT_128_STRING, + EFI_FVB2_ALIGNMENT_256_STRING, + EFI_FVB2_ALIGNMENT_512_STRING, + EFI_FVB2_ALIGNMENT_1K_STRING, + EFI_FVB2_ALIGNMENT_2K_STRING, + EFI_FVB2_ALIGNMENT_4K_STRING, + EFI_FVB2_ALIGNMENT_8K_STRING, + EFI_FVB2_ALIGNMENT_16K_STRING, + EFI_FVB2_ALIGNMENT_32K_STRING, + EFI_FVB2_ALIGNMENT_64K_STRING, EFI_FVB2_ALIGNMENT_128K_STRING, EFI_FVB2_ALIGNMENT_256K_STRING, - EFI_FVB2_ALIGNMNET_512K_STRING, - EFI_FVB2_ALIGNMENT_1M_STRING, - EFI_FVB2_ALIGNMENT_2M_STRING, - EFI_FVB2_ALIGNMENT_4M_STRING, - EFI_FVB2_ALIGNMENT_8M_STRING, - EFI_FVB2_ALIGNMENT_16M_STRING, - EFI_FVB2_ALIGNMENT_32M_STRING, - EFI_FVB2_ALIGNMENT_64M_STRING, + EFI_FVB2_ALIGNMENT_512K_STRING, + EFI_FVB2_ALIGNMENT_1M_STRING, + EFI_FVB2_ALIGNMENT_2M_STRING, + EFI_FVB2_ALIGNMENT_4M_STRING, + EFI_FVB2_ALIGNMENT_8M_STRING, + EFI_FVB2_ALIGNMENT_16M_STRING, + EFI_FVB2_ALIGNMENT_32M_STRING, + EFI_FVB2_ALIGNMENT_64M_STRING, EFI_FVB2_ALIGNMENT_128M_STRING, EFI_FVB2_ALIGNMENT_256M_STRING, EFI_FVB2_ALIGNMENT_512M_STRING, - EFI_FVB2_ALIGNMENT_1G_STRING, + EFI_FVB2_ALIGNMENT_1G_STRING, EFI_FVB2_ALIGNMENT_2G_STRING }; @@ -158,6 +165,7 @@ UINT8 m64kRecoveryStartupApDataArray[SIZEOF_ST FV_INFO mFvDataInfo; CAP_INFO mCapDataInfo; +BOOLEAN mIsLargeFfs = FALSE; EFI_PHYSICAL_ADDRESS mFvBaseAddress[0x10]; UINT32 mFvBaseAddressNumber = 0; @@ -185,7 +193,7 @@ Returns: EFI_NOT_FOUND A required string was not found in the INF file. --*/ { - CHAR8 Value[_MAX_PATH]; + CHAR8 Value[MAX_LONG_FILE_PATH]; UINT64 Value64; UINTN Index; UINTN Number; @@ -209,6 +217,7 @@ Returns: DebugMsg (NULL, 0, 9, "rebase address", "%s = %s", EFI_FV_BASE_ADDRESS_STRING, Value); FvInfo->BaseAddress = Value64; + FvInfo->BaseAddressSet = TRUE; } } @@ -249,7 +258,7 @@ Returns: // strcpy (FvInfo->FvName, Value); } - + // // Read Fv Attribute // @@ -278,6 +287,19 @@ Returns: } } + // + // Read weak alignment flag + // + Status = FindToken (InfFile, ATTRIBUTES_SECTION_STRING, EFI_FV_WEAK_ALIGNMENT_STRING, 0, Value); + if (Status == EFI_SUCCESS) { + if ((strcmp (Value, TRUE_STRING) == 0) || (strcmp (Value, ONE_STRING) == 0)) { + FvInfo->FvAttributes |= EFI_FVB2_WEAK_ALIGNMENT; + } else if ((strcmp (Value, FALSE_STRING) != 0) && (strcmp (Value, ZERO_STRING) != 0)) { + Error (NULL, 0, 2000, "Invalid parameter", "Weak alignment value expected one of TRUE, FALSE, 1 or 0."); + return EFI_ABORTED; + } + } + // // Read block maps // @@ -353,7 +375,7 @@ Returns: } } - for (Index = 0; Index < MAX_NUMBER_OF_FILES_IN_FV; Index++) { + for (Index = 0; Number + Index < MAX_NUMBER_OF_FILES_IN_FV; Index++) { // // Read the FFS file list // @@ -387,7 +409,7 @@ UpdateFfsFileState ( Routine Description: This function changes the FFS file attributes based on the erase polarity - of the FV. Update the reserved bits of State to EFI_FVB2_ERASE_POLARITY. + of the FV. Update the reserved bits of State to EFI_FVB2_ERASE_POLARITY. Arguments: @@ -442,58 +464,98 @@ Returns: case 0: // - // 8 byte alignment, mini alignment requirement for FFS file. + // 1 byte alignment + //if bit 1 have set, 128K byte alignmnet // - *Alignment = 3; + if (FfsFile->Attributes & FFS_ATTRIB_DATA_ALIGNMENT2) { + *Alignment = 17; + } else { + *Alignment = 0; + } break; case 1: // // 16 byte alignment + //if bit 1 have set, 256K byte alignment // - *Alignment = 4; + if (FfsFile->Attributes & FFS_ATTRIB_DATA_ALIGNMENT2) { + *Alignment = 18; + } else { + *Alignment = 4; + } break; case 2: // // 128 byte alignment + //if bit 1 have set, 512K byte alignment // - *Alignment = 7; + if (FfsFile->Attributes & FFS_ATTRIB_DATA_ALIGNMENT2) { + *Alignment = 19; + } else { + *Alignment = 7; + } break; case 3: // // 512 byte alignment + //if bit 1 have set, 1M byte alignment // - *Alignment = 9; + if (FfsFile->Attributes & FFS_ATTRIB_DATA_ALIGNMENT2) { + *Alignment = 20; + } else { + *Alignment = 9; + } break; case 4: // // 1K byte alignment + //if bit 1 have set, 2M byte alignment // - *Alignment = 10; + if (FfsFile->Attributes & FFS_ATTRIB_DATA_ALIGNMENT2) { + *Alignment = 21; + } else { + *Alignment = 10; + } break; case 5: // // 4K byte alignment + //if bit 1 have set, 4M byte alignment // - *Alignment = 12; + if (FfsFile->Attributes & FFS_ATTRIB_DATA_ALIGNMENT2) { + *Alignment = 22; + } else { + *Alignment = 12; + } break; case 6: // // 32K byte alignment + //if bit 1 have set , 8M byte alignment // - *Alignment = 15; + if (FfsFile->Attributes & FFS_ATTRIB_DATA_ALIGNMENT2) { + *Alignment = 23; + } else { + *Alignment = 15; + } break; case 7: // // 64K byte alignment + //if bit 1 have set, 16M alignment // - *Alignment = 16; + if (FfsFile->Attributes & FFS_ATTRIB_DATA_ALIGNMENT2) { + *Alignment = 24; + } else { + *Alignment = 16; + } break; default: @@ -508,7 +570,8 @@ AddPadFile ( IN OUT MEMORY_FILE *FvImage, IN UINT32 DataAlignment, IN VOID *FvEnd, - IN EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtHeader + IN EFI_FIRMWARE_VOLUME_EXT_HEADER *ExtHeader, + IN UINT32 NextFfsSize ) /*++ @@ -523,7 +586,7 @@ Arguments: The current offset must be valid. DataAlignment The data alignment of the next FFS file. FvEnd End of the empty data in FvImage. - ExtHeader PI FvExtHeader Optional + ExtHeader PI FvExtHeader Optional Returns: @@ -536,7 +599,12 @@ Returns: { EFI_FFS_FILE_HEADER *PadFile; UINTN PadFileSize; + UINT32 NextFfsHeaderSize; + UINT32 CurFfsHeaderSize; + UINT32 Index; + Index = 0; + CurFfsHeaderSize = sizeof (EFI_FFS_FILE_HEADER); // // Verify input parameters. // @@ -544,43 +612,45 @@ Returns: return EFI_INVALID_PARAMETER; } - // - // Check if a pad file is necessary - // - if ((ExtHeader == NULL) && (((UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + sizeof (EFI_FFS_FILE_HEADER)) % DataAlignment == 0)) { - return EFI_SUCCESS; - } - // // Calculate the pad file size // - // - // This is the earliest possible valid offset (current plus pad file header - // plus the next file header) - // - PadFileSize = (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + (sizeof (EFI_FFS_FILE_HEADER) * 2); - // - // Add whatever it takes to get to the next aligned address - // - while ((PadFileSize % DataAlignment) != 0) { - PadFileSize++; - } - // - // Subtract the next file header size - // - PadFileSize -= sizeof (EFI_FFS_FILE_HEADER); - - // - // Subtract the starting offset to get size - // - PadFileSize -= (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage; - // // Append extension header size // if (ExtHeader != NULL) { - PadFileSize = PadFileSize + ExtHeader->ExtHeaderSize; + PadFileSize = ExtHeader->ExtHeaderSize; + if (PadFileSize + sizeof (EFI_FFS_FILE_HEADER) >= MAX_FFS_SIZE) { + CurFfsHeaderSize = sizeof (EFI_FFS_FILE_HEADER2); + } + PadFileSize += CurFfsHeaderSize; + } else { + NextFfsHeaderSize = sizeof (EFI_FFS_FILE_HEADER); + if (NextFfsSize >= MAX_FFS_SIZE) { + NextFfsHeaderSize = sizeof (EFI_FFS_FILE_HEADER2); + } + // + // Check if a pad file is necessary + // + if (((UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + NextFfsHeaderSize) % DataAlignment == 0) { + return EFI_SUCCESS; + } + PadFileSize = (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage + sizeof (EFI_FFS_FILE_HEADER) + NextFfsHeaderSize; + // + // Add whatever it takes to get to the next aligned address + // + while ((PadFileSize % DataAlignment) != 0) { + PadFileSize++; + } + // + // Subtract the next file header size + // + PadFileSize -= NextFfsHeaderSize; + // + // Subtract the starting offset to get size + // + PadFileSize -= (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage; } // @@ -604,9 +674,15 @@ Returns: // // Write pad file size (calculated size minus next file header size) // - PadFile->Size[0] = (UINT8) (PadFileSize & 0xFF); - PadFile->Size[1] = (UINT8) ((PadFileSize >> 8) & 0xFF); - PadFile->Size[2] = (UINT8) ((PadFileSize >> 16) & 0xFF); + if (PadFileSize >= MAX_FFS_SIZE) { + memset(PadFile->Size, 0, sizeof(UINT8) * 3); + ((EFI_FFS_FILE_HEADER2 *)PadFile)->ExtendedSize = PadFileSize; + PadFile->Attributes |= FFS_ATTRIB_LARGE_FILE; + } else { + PadFile->Size[0] = (UINT8) (PadFileSize & 0xFF); + PadFile->Size[1] = (UINT8) ((PadFileSize >> 8) & 0xFF); + PadFile->Size[2] = (UINT8) ((PadFileSize >> 16) & 0xFF); + } // // Fill in checksums and state, they must be 0 for checksumming. @@ -614,7 +690,7 @@ Returns: PadFile->IntegrityCheck.Checksum.Header = 0; PadFile->IntegrityCheck.Checksum.File = 0; PadFile->State = 0; - PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, sizeof (EFI_FFS_FILE_HEADER)); + PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, CurFfsHeaderSize); PadFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID; @@ -632,14 +708,27 @@ Returns: // // Copy Fv Extension Header and Set Fv Extension header offset // - memcpy (PadFile + 1, ExtHeader, ExtHeader->ExtHeaderSize); - ((EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage)->ExtHeaderOffset = (UINT16) ((UINTN) (PadFile + 1) - (UINTN) FvImage->FileImage); - // - // Make next file start at QWord Boundry - // - while (((UINTN) FvImage->CurrentFilePointer & (EFI_FFS_FILE_HEADER_ALIGNMENT - 1)) != 0) { - FvImage->CurrentFilePointer++; - } + if (ExtHeader->ExtHeaderSize > sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER)) { + for (Index = sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER); Index < ExtHeader->ExtHeaderSize;) { + if (((EFI_FIRMWARE_VOLUME_EXT_ENTRY *)((UINT8 *)ExtHeader + Index))-> ExtEntryType == EFI_FV_EXT_TYPE_USED_SIZE_TYPE) { + if (VtfFileFlag) { + ((EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE *)((UINT8 *)ExtHeader + Index))->UsedSize = mFvTotalSize; + } else { + ((EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE *)((UINT8 *)ExtHeader + Index))->UsedSize = mFvTakenSize; + } + break; + } + Index += ((EFI_FIRMWARE_VOLUME_EXT_ENTRY *)((UINT8 *)ExtHeader + Index))-> ExtEntrySize; + } + } + memcpy ((UINT8 *)PadFile + CurFfsHeaderSize, ExtHeader, ExtHeader->ExtHeaderSize); + ((EFI_FIRMWARE_VOLUME_HEADER *) FvImage->FileImage)->ExtHeaderOffset = (UINT16) ((UINTN) ((UINT8 *)PadFile + CurFfsHeaderSize) - (UINTN) FvImage->FileImage); + // + // Make next file start at QWord Boundry + // + while (((UINTN) FvImage->CurrentFilePointer & (EFI_FFS_FILE_HEADER_ALIGNMENT - 1)) != 0) { + FvImage->CurrentFilePointer++; + } } return EFI_SUCCESS; @@ -677,7 +766,7 @@ EFI_STATUS WriteMapFile ( IN OUT FILE *FvMapFile, IN CHAR8 *FileName, - IN EFI_FFS_FILE_HEADER *FfsFile, + IN EFI_FFS_FILE_HEADER *FfsFile, IN EFI_PHYSICAL_ADDRESS ImageBaseAddress, IN PE_COFF_LOADER_IMAGE_CONTEXT *pImageContext ) @@ -702,7 +791,7 @@ Returns: --*/ { - CHAR8 PeMapFileName [_MAX_PATH]; + CHAR8 PeMapFileName [MAX_LONG_FILE_PATH]; CHAR8 *Cptr, *Cptr2; CHAR8 FileGuidName [MAX_LINE_LEN]; FILE *PeMapFile; @@ -718,7 +807,7 @@ Returns: EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr; EFI_TE_IMAGE_HEADER *TEImageHeader; EFI_IMAGE_SECTION_HEADER *SectionHeader; - unsigned long long TempLongAddress; + long long TempLongAddress; UINT32 TextVirtualAddress; UINT32 DataVirtualAddress; EFI_PHYSICAL_ADDRESS LinkTimeBaseAddress; @@ -728,15 +817,19 @@ Returns: // FunctionType = 0; // - // Print FileGuid to string buffer. + // Print FileGuid to string buffer. // PrintGuidToBuffer (&FfsFile->Name, (UINT8 *)FileGuidName, MAX_LINE_LEN, TRUE); - + // - // Construct Map file Name + // Construct Map file Name // - strcpy (PeMapFileName, FileName); - + if (strlen (FileName) >= MAX_LONG_FILE_PATH) { + return EFI_ABORTED; + } + strncpy (PeMapFileName, FileName, MAX_LONG_FILE_PATH - 1); + PeMapFileName[MAX_LONG_FILE_PATH - 1] = 0; + // // Change '\\' to '/', unified path format. // @@ -747,10 +840,10 @@ Returns: } Cptr ++; } - + // // Get Map file - // + // Cptr = PeMapFileName + strlen (PeMapFileName); while ((*Cptr != '.') && (Cptr >= PeMapFileName)) { Cptr --; @@ -771,26 +864,30 @@ Returns: while ((*Cptr != FILE_SEP_CHAR) && (Cptr >= PeMapFileName)) { Cptr --; } - *Cptr2 = '\0'; - strcpy (KeyWord, Cptr + 1); - *Cptr2 = '.'; + *Cptr2 = '\0'; + if (strlen (Cptr + 1) >= MAX_LINE_LEN) { + return EFI_ABORTED; + } + strncpy (KeyWord, Cptr + 1, MAX_LINE_LEN - 1); + KeyWord[MAX_LINE_LEN - 1] = 0; + *Cptr2 = '.'; // // AddressOfEntryPoint and Offset in Image // if (!pImageContext->IsTeImage) { - ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) pImageContext->Handle + pImageContext->PeCoffHeaderOffset); - AddressOfEntryPoint = ImgHdr->Pe32.OptionalHeader.AddressOfEntryPoint; - Offset = 0; + ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINT8 *) pImageContext->Handle + pImageContext->PeCoffHeaderOffset); + AddressOfEntryPoint = ImgHdr->Pe32.OptionalHeader.AddressOfEntryPoint; + Offset = 0; SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ( (UINT8 *) ImgHdr + - sizeof (UINT32) + - sizeof (EFI_IMAGE_FILE_HEADER) + + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER) + ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader ); Index = ImgHdr->Pe32.FileHeader.NumberOfSections; } else { - TEImageHeader = (EFI_TE_IMAGE_HEADER *) pImageContext->Handle; + TEImageHeader = (EFI_TE_IMAGE_HEADER *) pImageContext->Handle; AddressOfEntryPoint = TEImageHeader->AddressOfEntryPoint; Offset = TEImageHeader->StrippedSize - sizeof (EFI_TE_IMAGE_HEADER); SectionHeader = (EFI_IMAGE_SECTION_HEADER *) (TEImageHeader + 1); @@ -810,41 +907,41 @@ Returns: if (FfsFile->Type != EFI_FV_FILETYPE_SECURITY_CORE && pImageContext->Machine == EFI_IMAGE_MACHINE_IA64) { // - // Process IPF PLABEL to get the real address after the image has been rebased. + // Process IPF PLABEL to get the real address after the image has been rebased. // PLABEL structure is got by AddressOfEntryPoint offset to ImageBuffer stored in pImageContext->Handle. // fprintf (FvMapFile, "EntryPoint=0x%010llx", (unsigned long long) (*(UINT64 *)((UINTN) pImageContext->Handle + (UINTN) AddressOfEntryPoint))); } else { fprintf (FvMapFile, "EntryPoint=0x%010llx", (unsigned long long) (ImageBaseAddress + AddressOfEntryPoint)); } - fprintf (FvMapFile, ")\n"); - + fprintf (FvMapFile, ")\n"); + fprintf (FvMapFile, "(GUID=%s", FileGuidName); TextVirtualAddress = 0; DataVirtualAddress = 0; for (; Index > 0; Index --, SectionHeader ++) { if (stricmp ((CHAR8 *)SectionHeader->Name, ".text") == 0) { - TextVirtualAddress = SectionHeader->VirtualAddress; - } else if (stricmp ((CHAR8 *)SectionHeader->Name, ".data") == 0) { - DataVirtualAddress = SectionHeader->VirtualAddress; - } else if (stricmp ((CHAR8 *)SectionHeader->Name, ".sdata") == 0) { - DataVirtualAddress = SectionHeader->VirtualAddress; - } + TextVirtualAddress = SectionHeader->VirtualAddress; + } else if (stricmp ((CHAR8 *)SectionHeader->Name, ".data") == 0) { + DataVirtualAddress = SectionHeader->VirtualAddress; + } else if (stricmp ((CHAR8 *)SectionHeader->Name, ".sdata") == 0) { + DataVirtualAddress = SectionHeader->VirtualAddress; + } } fprintf (FvMapFile, " .textbaseaddress=0x%010llx", (unsigned long long) (ImageBaseAddress + TextVirtualAddress)); fprintf (FvMapFile, " .databaseaddress=0x%010llx", (unsigned long long) (ImageBaseAddress + DataVirtualAddress)); fprintf (FvMapFile, ")\n\n"); - + // // Open PeMapFile // - PeMapFile = fopen (PeMapFileName, "r"); + PeMapFile = fopen (LongFilePath (PeMapFileName), "r"); if (PeMapFile == NULL) { // fprintf (stdout, "can't open %s file to reading\n", PeMapFileName); return EFI_ABORTED; } VerboseMsg ("The map file is %s", PeMapFileName); - + // // Output Functions information into Fv Map file // @@ -859,7 +956,7 @@ Returns: } // // By Address and Static keyword - // + // if (FunctionType == 0) { sscanf (Line, "%s", KeyWord); if (stricmp (KeyWord, "Address") == 0) { @@ -904,10 +1001,157 @@ Returns: // fprintf (FvMapFile, "\n\n"); fclose (PeMapFile); - + return EFI_SUCCESS; } +STATIC +BOOLEAN +AdjustInternalFfsPadding ( + IN OUT EFI_FFS_FILE_HEADER *FfsFile, + IN OUT MEMORY_FILE *FvImage, + IN UINTN Alignment, + IN OUT UINTN *FileSize + ) +/*++ + +Routine Description: + + This function looks for a dedicated alignment padding section in the FFS, and + shrinks it to the size required to line up subsequent sections correctly. + +Arguments: + + FfsFile A pointer to Ffs file image. + FvImage The memory image of the FV to adjust it to. + Alignment Current file alignment + FileSize Reference to a variable holding the size of the FFS file + +Returns: + + TRUE Padding section was found and updated successfully + FALSE Otherwise + +--*/ +{ + EFI_FILE_SECTION_POINTER PadSection; + UINT8 *Remainder; + EFI_STATUS Status; + UINT32 FfsHeaderLength; + UINT32 FfsFileLength; + UINT32 PadSize; + UINTN Misalignment; + EFI_FFS_INTEGRITY_CHECK *IntegrityCheck; + + // + // Figure out the misalignment: all FFS sections are aligned relative to the + // start of the FFS payload, so use that as the base of the misalignment + // computation. + // + FfsHeaderLength = GetFfsHeaderLength(FfsFile); + Misalignment = (UINTN) FvImage->CurrentFilePointer - + (UINTN) FvImage->FileImage + FfsHeaderLength; + Misalignment &= Alignment - 1; + if (Misalignment == 0) { + // Nothing to do, return success + return TRUE; + } + + // + // We only apply this optimization to FFS files with the FIXED attribute set, + // since the FFS will not be loadable at arbitrary offsets anymore after + // we adjust the size of the padding section. + // + if ((FfsFile->Attributes & FFS_ATTRIB_FIXED) == 0) { + return FALSE; + } + + // + // Look for a dedicated padding section that we can adjust to compensate + // for the misalignment. If such a padding section exists, it precedes all + // sections with alignment requirements, and so the adjustment will correct + // all of them. + // + Status = GetSectionByType (FfsFile, EFI_SECTION_FREEFORM_SUBTYPE_GUID, 1, + &PadSection); + if (EFI_ERROR (Status) || + CompareGuid (&PadSection.FreeformSubtypeSection->SubTypeGuid, + &mEfiFfsSectionAlignmentPaddingGuid) != 0) { + return FALSE; + } + + // + // Find out if the size of the padding section is sufficient to compensate + // for the misalignment. + // + PadSize = GetSectionFileLength (PadSection.CommonHeader); + if (Misalignment > PadSize - sizeof (EFI_FREEFORM_SUBTYPE_GUID_SECTION)) { + return FALSE; + } + + // + // Move the remainder of the FFS file towards the front, and adjust the + // file size output parameter. + // + Remainder = (UINT8 *) PadSection.CommonHeader + PadSize; + memmove (Remainder - Misalignment, Remainder, + *FileSize - (UINTN) (Remainder - (UINTN) FfsFile)); + *FileSize -= Misalignment; + + // + // Update the padding section's length with the new values. Note that the + // padding is always < 64 KB, so we can ignore EFI_COMMON_SECTION_HEADER2 + // ExtendedSize. + // + PadSize -= Misalignment; + PadSection.CommonHeader->Size[0] = (UINT8) (PadSize & 0xff); + PadSection.CommonHeader->Size[1] = (UINT8) ((PadSize & 0xff00) >> 8); + PadSection.CommonHeader->Size[2] = (UINT8) ((PadSize & 0xff0000) >> 16); + + // + // Update the FFS header with the new overall length + // + FfsFileLength = GetFfsFileLength (FfsFile) - Misalignment; + if (FfsHeaderLength > sizeof(EFI_FFS_FILE_HEADER)) { + ((EFI_FFS_FILE_HEADER2 *)FfsFile)->ExtendedSize = FfsFileLength; + } else { + FfsFile->Size[0] = (UINT8) (FfsFileLength & 0x000000FF); + FfsFile->Size[1] = (UINT8) ((FfsFileLength & 0x0000FF00) >> 8); + FfsFile->Size[2] = (UINT8) ((FfsFileLength & 0x00FF0000) >> 16); + } + + // + // Clear the alignment bits: these have become meaningless now that we have + // adjusted the padding section. + // + FfsFile->Attributes &= ~(FFS_ATTRIB_DATA_ALIGNMENT | FFS_ATTRIB_DATA_ALIGNMENT2); + + // + // Recalculate the FFS header checksum. Instead of setting Header and State + // both to zero, set Header to (UINT8)(-State) so State preserves its original + // value + // + IntegrityCheck = &FfsFile->IntegrityCheck; + IntegrityCheck->Checksum.Header = (UINT8) (0x100 - FfsFile->State); + IntegrityCheck->Checksum.File = 0; + + IntegrityCheck->Checksum.Header = CalculateChecksum8 ( + (UINT8 *) FfsFile, FfsHeaderLength); + + if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) { + // + // Ffs header checksum = zero, so only need to calculate ffs body. + // + IntegrityCheck->Checksum.File = CalculateChecksum8 ( + (UINT8 *) FfsFile + FfsHeaderLength, + FfsFileLength - FfsHeaderLength); + } else { + IntegrityCheck->Checksum.File = FFS_FIXED_CHECKSUM; + } + + return TRUE; +} + EFI_STATUS AddFile ( IN OUT MEMORY_FILE *FvImage, @@ -952,7 +1196,7 @@ Returns: EFI_STATUS Status; UINTN Index1; UINT8 FileGuidString[PRINTED_GUID_BUFFER_SIZE]; - + Index1 = 0; // // Verify input parameters. @@ -964,7 +1208,7 @@ Returns: // // Read the file to add // - NewFile = fopen (FvInfo->FvFiles[Index], "rb"); + NewFile = fopen (LongFilePath (FvInfo->FvFiles[Index]), "rb"); if (NewFile == NULL) { Error (NULL, 0, 0001, "Error opening file", FvInfo->FvFiles[Index]); @@ -981,6 +1225,7 @@ Returns: // FileBuffer = malloc (FileSize); if (FileBuffer == NULL) { + fclose (NewFile); Error (NULL, 0, 4001, "Resouce", "memory cannot be allocated!"); return EFI_OUT_OF_RESOURCES; } @@ -991,7 +1236,7 @@ Returns: // Done with the file, from this point on we will just use the buffer read. // fclose (NewFile); - + // // Verify read successful // @@ -1000,27 +1245,27 @@ Returns: Error (NULL, 0, 0004, "Error reading file", FvInfo->FvFiles[Index]); return EFI_ABORTED; } - + // // For None PI Ffs file, directly add them into FvImage. // if (!FvInfo->IsPiFvImage) { memcpy (FvImage->CurrentFilePointer, FileBuffer, FileSize); if (FvInfo->SizeofFvFiles[Index] > FileSize) { - FvImage->CurrentFilePointer += FvInfo->SizeofFvFiles[Index]; + FvImage->CurrentFilePointer += FvInfo->SizeofFvFiles[Index]; } else { - FvImage->CurrentFilePointer += FileSize; + FvImage->CurrentFilePointer += FileSize; } goto Done; } - + // // Verify Ffs file // Status = VerifyFfsFile ((EFI_FFS_FILE_HEADER *)FileBuffer); if (EFI_ERROR (Status)) { free (FileBuffer); - Error (NULL, 0, 3000, "Invalid", "%s is a FFS file.", FvInfo->FvFiles[Index]); + Error (NULL, 0, 3000, "Invalid", "%s is not a valid FFS file.", FvInfo->FvFiles[Index]); return EFI_INVALID_PARAMETER; } @@ -1040,6 +1285,7 @@ Returns: if (CompareGuid ((EFI_GUID *) FileBuffer, &mFileGuidArray [Index1]) == 0) { Error (NULL, 0, 2000, "Invalid parameter", "the %dth file and %uth file have the same file GUID.", (unsigned) Index1 + 1, (unsigned) Index + 1); PrintGuid ((EFI_GUID *) FileBuffer); + free (FileBuffer); return EFI_INVALID_PARAMETER; } } @@ -1057,7 +1303,7 @@ Returns: // Check if alignment is required // ReadFfsAlignment ((EFI_FFS_FILE_HEADER *) FileBuffer, &CurrentFileAlignment); - + // // Find the largest alignment of all the FFS files in the FV // @@ -1076,26 +1322,26 @@ Returns: // // Sanity check. The file MUST align appropriately // - if (((UINTN) *VtfFileImage + sizeof (EFI_FFS_FILE_HEADER) - (UINTN) FvImage->FileImage) % (1 << CurrentFileAlignment)) { + if (((UINTN) *VtfFileImage + GetFfsHeaderLength((EFI_FFS_FILE_HEADER *)FileBuffer) - (UINTN) FvImage->FileImage) % (1 << CurrentFileAlignment)) { Error (NULL, 0, 3000, "Invalid", "VTF file cannot be aligned on a %u-byte boundary.", (unsigned) (1 << CurrentFileAlignment)); free (FileBuffer); return EFI_ABORTED; } // - // Rebase the PE or TE image in FileBuffer of FFS file for XIP + // Rebase the PE or TE image in FileBuffer of FFS file for XIP // Rebase for the debug genfvmap tool // Status = FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) *VtfFileImage - (UINTN) FvImage->FileImage, FvMapFile); if (EFI_ERROR (Status)) { Error (NULL, 0, 3000, "Invalid", "Could not rebase %s.", FvInfo->FvFiles[Index]); return Status; - } + } // // copy VTF File // memcpy (*VtfFileImage, FileBuffer, FileSize); - - PrintGuidToBuffer ((EFI_GUID *) FileBuffer, FileGuidString, sizeof (FileGuidString), TRUE); + + PrintGuidToBuffer ((EFI_GUID *) FileBuffer, FileGuidString, sizeof (FileGuidString), TRUE); fprintf (FvReportFile, "0x%08X %s\n", (unsigned)(UINTN) (((UINT8 *)*VtfFileImage) - (UINTN)FvImage->FileImage), FileGuidString); free (FileBuffer); @@ -1114,30 +1360,33 @@ Returns: // // Add pad file if necessary // - Status = AddPadFile (FvImage, 1 << CurrentFileAlignment, *VtfFileImage, NULL); - if (EFI_ERROR (Status)) { - Error (NULL, 0, 4002, "Resource", "FV space is full, could not add pad file for data alignment property."); - free (FileBuffer); - return EFI_ABORTED; + if (!AdjustInternalFfsPadding ((EFI_FFS_FILE_HEADER *) FileBuffer, FvImage, + 1 << CurrentFileAlignment, &FileSize)) { + Status = AddPadFile (FvImage, 1 << CurrentFileAlignment, *VtfFileImage, NULL, FileSize); + if (EFI_ERROR (Status)) { + Error (NULL, 0, 4002, "Resource", "FV space is full, could not add pad file for data alignment property."); + free (FileBuffer); + return EFI_ABORTED; + } } // // Add file // if ((UINTN) (FvImage->CurrentFilePointer + FileSize) <= (UINTN) (*VtfFileImage)) { // - // Rebase the PE or TE image in FileBuffer of FFS file for XIP. + // Rebase the PE or TE image in FileBuffer of FFS file for XIP. // Rebase Bs and Rt drivers for the debug genfvmap tool. // Status = FfsRebase (FvInfo, FvInfo->FvFiles[Index], (EFI_FFS_FILE_HEADER *) FileBuffer, (UINTN) FvImage->CurrentFilePointer - (UINTN) FvImage->FileImage, FvMapFile); - if (EFI_ERROR (Status)) { - Error (NULL, 0, 3000, "Invalid", "Could not rebase %s.", FvInfo->FvFiles[Index]); - return Status; - } + if (EFI_ERROR (Status)) { + Error (NULL, 0, 3000, "Invalid", "Could not rebase %s.", FvInfo->FvFiles[Index]); + return Status; + } // // Copy the file // memcpy (FvImage->CurrentFilePointer, FileBuffer, FileSize); - PrintGuidToBuffer ((EFI_GUID *) FileBuffer, FileGuidString, sizeof (FileGuidString), TRUE); + PrintGuidToBuffer ((EFI_GUID *) FileBuffer, FileGuidString, sizeof (FileGuidString), TRUE); fprintf (FvReportFile, "0x%08X %s\n", (unsigned) (FvImage->CurrentFilePointer - FvImage->FileImage), FileGuidString); FvImage->CurrentFilePointer += FileSize; } else { @@ -1152,7 +1401,7 @@ Returns: FvImage->CurrentFilePointer++; } -Done: +Done: // // Free allocated memory. // @@ -1188,6 +1437,7 @@ Returns: { EFI_FFS_FILE_HEADER *PadFile; UINTN FileSize; + UINT32 FfsHeaderSize; // // If there is no VTF or the VTF naturally follows the previous file without a @@ -1208,7 +1458,7 @@ Returns: PadFile = (EFI_FFS_FILE_HEADER *) FvImage->CurrentFilePointer; // - // write PadFile FFS header with PadType, don't need to set PAD file guid in its header. + // write PadFile FFS header with PadType, don't need to set PAD file guid in its header. // PadFile->Type = EFI_FV_FILETYPE_FFS_PAD; PadFile->Attributes = 0; @@ -1217,9 +1467,18 @@ Returns: // FileSize includes the EFI_FFS_FILE_HEADER // FileSize = (UINTN) VtfFileImage - (UINTN) FvImage->CurrentFilePointer; - PadFile->Size[0] = (UINT8) (FileSize & 0x000000FF); - PadFile->Size[1] = (UINT8) ((FileSize & 0x0000FF00) >> 8); - PadFile->Size[2] = (UINT8) ((FileSize & 0x00FF0000) >> 16); + if (FileSize >= MAX_FFS_SIZE) { + PadFile->Attributes |= FFS_ATTRIB_LARGE_FILE; + memset(PadFile->Size, 0, sizeof(UINT8) * 3); + ((EFI_FFS_FILE_HEADER2 *)PadFile)->ExtendedSize = FileSize; + FfsHeaderSize = sizeof(EFI_FFS_FILE_HEADER2); + mIsLargeFfs = TRUE; + } else { + PadFile->Size[0] = (UINT8) (FileSize & 0x000000FF); + PadFile->Size[1] = (UINT8) ((FileSize & 0x0000FF00) >> 8); + PadFile->Size[2] = (UINT8) ((FileSize & 0x00FF0000) >> 16); + FfsHeaderSize = sizeof(EFI_FFS_FILE_HEADER); + } // // Fill in checksums and state, must be zero during checksum calculation. @@ -1227,7 +1486,7 @@ Returns: PadFile->IntegrityCheck.Checksum.Header = 0; PadFile->IntegrityCheck.Checksum.File = 0; PadFile->State = 0; - PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, sizeof (EFI_FFS_FILE_HEADER)); + PadFile->IntegrityCheck.Checksum.Header = CalculateChecksum8 ((UINT8 *) PadFile, FfsHeaderSize); PadFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; PadFile->State = EFI_FILE_HEADER_CONSTRUCTION | EFI_FILE_HEADER_VALID | EFI_FILE_DATA_VALID; @@ -1295,6 +1554,8 @@ Returns: UINT64 FitAddress; FIT_TABLE *FitTablePtr; BOOLEAN Vtf0Detected; + UINT32 FfsHeaderSize; + UINT32 SecHeaderSize; // // Verify input parameters @@ -1357,8 +1618,9 @@ Returns: return EFI_ABORTED; } + SecHeaderSize = GetSectionHeaderLength(Pe32Section.CommonHeader); Status = GetPe32Info ( - (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)), + (VOID *) ((UINTN) Pe32Section.Pe32Section + SecHeaderSize), &EntryPoint, &BaseOfCode, &MachineType @@ -1367,7 +1629,7 @@ Returns: if (EFI_ERROR (Status)) { Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core."); return EFI_ABORTED; - } + } if ( Vtf0Detected && @@ -1386,9 +1648,9 @@ Returns: // Physical address is FV base + offset of PE32 + offset of the entry point // SecCorePhysicalAddress = FvInfo->BaseAddress; - SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage; + SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + SecHeaderSize - (UINTN) FvImage->FileImage; SecCorePhysicalAddress += EntryPoint; - DebugMsg (NULL, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress); + DebugMsg (NULL, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress); // // Find the PEI Core @@ -1411,8 +1673,9 @@ Returns: return EFI_ABORTED; } + SecHeaderSize = GetSectionHeaderLength(Pe32Section.CommonHeader); Status = GetPe32Info ( - (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)), + (VOID *) ((UINTN) Pe32Section.Pe32Section + SecHeaderSize), &EntryPoint, &BaseOfCode, &MachineType @@ -1426,7 +1689,7 @@ Returns: // Physical address is FV base + offset of PE32 + offset of the entry point // PeiCorePhysicalAddress = FvInfo->BaseAddress; - PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage; + PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + SecHeaderSize - (UINTN) FvImage->FileImage; PeiCorePhysicalAddress += EntryPoint; DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress); @@ -1495,18 +1758,18 @@ Returns: // Write lower 32 bits of physical address for Pei Core entry // *Ia32ResetAddressPtr = (UINT32) PeiCorePhysicalAddress; - + // // Write SecCore Entry point relative address into the jmp instruction in reset vector. - // + // Ia32ResetAddressPtr = (UINT32 *) ((UINTN) FvImage->Eof - IA32_SEC_CORE_ENTRY_OFFSET); - + Ia32SecEntryOffset = (INT32) (SecCorePhysicalAddress - (FV_IMAGES_TOP_ADDRESS - IA32_SEC_CORE_ENTRY_OFFSET + 2)); if (Ia32SecEntryOffset <= -65536) { Error (NULL, 0, 3000, "Invalid", "The SEC EXE file size is too large, it must be less than 64K."); return STATUS_ERROR; } - + *(UINT16 *) Ia32ResetAddressPtr = (UINT16) Ia32SecEntryOffset; // @@ -1534,7 +1797,7 @@ Returns: // Status = FindApResetVectorPosition (FvImage, &BytePointer); if (EFI_ERROR (Status)) { - Error (NULL, 0, 3000, "Invalid", "Cannot find the appropriate location in FvImage to add Ap reset vector!"); + 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."); return EFI_ABORTED; } } @@ -1556,9 +1819,9 @@ Returns: // WordPointer = (UINT16 *) (BytePointer + SIZEOF_STARTUP_DATA_ARRAY - 2); *WordPointer = (UINT16) (0x10000 - (UINT32) CheckSum); - + // - // IpiVector at the 4k aligned address in the top 2 blocks in the PEI FV. + // IpiVector at the 4k aligned address in the top 2 blocks in the PEI FV. // IpiVector = (UINT32) (FV_IMAGES_TOP_ADDRESS - ((UINTN) FvImage->Eof - (UINTN) BytePointer)); DebugMsg (NULL, 0, 9, "Startup AP Vector address", "IpiVector at 0x%X", (unsigned) IpiVector); @@ -1579,6 +1842,11 @@ Returns: // Since the ARM reset vector is in the FV Header you really don't need a // Volume Top File, but if you have one for some reason don't crash... // + } else if (MachineType == EFI_IMAGE_MACHINE_AARCH64) { + // + // Since the AArch64 reset vector is in the FV Header you really don't need a + // Volume Top File, but if you have one for some reason don't crash... + // } else { Error (NULL, 0, 3000, "Invalid", "machine type=0x%X in PEI core.", MachineType); return EFI_ABORTED; @@ -1591,9 +1859,10 @@ Returns: VtfFile->IntegrityCheck.Checksum.File = 0; VtfFile->State = 0; if (VtfFile->Attributes & FFS_ATTRIB_CHECKSUM) { + FfsHeaderSize = GetFfsHeaderLength(VtfFile); VtfFile->IntegrityCheck.Checksum.File = CalculateChecksum8 ( - (UINT8 *) (VtfFile + 1), - GetLength (VtfFile->Size) - sizeof (EFI_FFS_FILE_HEADER) + (UINT8 *) ((UINT8 *)VtfFile + FfsHeaderSize), + GetFfsFileLength (VtfFile) - FfsHeaderSize ); } else { VtfFile->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM; @@ -1604,6 +1873,244 @@ Returns: return EFI_SUCCESS; } +EFI_STATUS +FindCorePeSection( + IN VOID *FvImageBuffer, + IN UINT64 FvSize, + IN EFI_FV_FILETYPE FileType, + OUT EFI_FILE_SECTION_POINTER *Pe32Section + ) +/*++ + +Routine Description: + + Recursively searches the FV for the FFS file of specified type (typically + SEC or PEI core) and extracts the PE32 section for further processing. + +Arguments: + + FvImageBuffer Buffer containing FV data + FvSize Size of the FV + FileType Type of FFS file to search for + Pe32Section PE32 section pointer when FFS file is found. + +Returns: + + EFI_SUCCESS Function Completed successfully. + EFI_ABORTED Error encountered. + EFI_INVALID_PARAMETER A required parameter was NULL. + EFI_NOT_FOUND Core file not found. + +--*/ +{ + EFI_STATUS Status; + EFI_FIRMWARE_VOLUME_HEADER *OrigFvHeader; + UINT32 OrigFvLength; + EFI_FFS_FILE_HEADER *CoreFfsFile; + UINTN FvImageFileCount; + EFI_FFS_FILE_HEADER *FvImageFile; + UINTN EncapFvSectionCount; + EFI_FILE_SECTION_POINTER EncapFvSection; + EFI_FIRMWARE_VOLUME_HEADER *EncapsulatedFvHeader; + + if (Pe32Section == NULL) { + return EFI_INVALID_PARAMETER; + } + + // + // Initialize FV library, saving previous values + // + OrigFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)NULL; + GetFvHeader (&OrigFvHeader, &OrigFvLength); + InitializeFvLib(FvImageBuffer, (UINT32)FvSize); + + // + // First see if we can obtain the file directly in outer FV + // + Status = GetFileByType(FileType, 1, &CoreFfsFile); + if (!EFI_ERROR(Status) && (CoreFfsFile != NULL) ) { + + // + // Core found, now find PE32 or TE section + // + Status = GetSectionByType(CoreFfsFile, EFI_SECTION_PE32, 1, Pe32Section); + if (EFI_ERROR(Status)) { + Status = GetSectionByType(CoreFfsFile, EFI_SECTION_TE, 1, Pe32Section); + } + + if (EFI_ERROR(Status)) { + Error(NULL, 0, 3000, "Invalid", "could not find a PE32 section in the core file."); + return EFI_ABORTED; + } + + // + // Core PE/TE section, found, return + // + Status = EFI_SUCCESS; + goto EarlyExit; + } + + // + // File was not found, look for FV Image file + // + + // iterate through all FV image files in outer FV + for (FvImageFileCount = 1;; FvImageFileCount++) { + + Status = GetFileByType(EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE, FvImageFileCount, &FvImageFile); + + if (EFI_ERROR(Status) || (FvImageFile == NULL) ) { + // exit FV image file loop, no more found + break; + } + + // Found an fv image file, look for an FV image section. The PI spec does not + // preclude multiple FV image sections so we loop accordingly. + for (EncapFvSectionCount = 1;; EncapFvSectionCount++) { + + // Look for the next FV image section. The section search code will + // iterate into encapsulation sections. For example, it will iterate + // into an EFI_SECTION_GUID_DEFINED encapsulation section to find the + // EFI_SECTION_FIRMWARE_VOLUME_IMAGE sections contained therein. + Status = GetSectionByType(FvImageFile, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, EncapFvSectionCount, &EncapFvSection); + + if (EFI_ERROR(Status)) { + // exit section inner loop, no more found + break; + } + + EncapsulatedFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *)((UINT8 *)EncapFvSection.FVImageSection + GetSectionHeaderLength(EncapFvSection.FVImageSection)); + + // recurse to search the encapsulated FV for this core file type + Status = FindCorePeSection(EncapsulatedFvHeader, EncapsulatedFvHeader->FvLength, FileType, Pe32Section); + + if (!EFI_ERROR(Status)) { + // we found the core in the capsulated image, success + goto EarlyExit; + } + + } // end encapsulated fv image section loop + } // end fv image file loop + + // core was not found + Status = EFI_NOT_FOUND; + +EarlyExit: + + // restore FV lib values + if(OrigFvHeader != NULL) { + InitializeFvLib(OrigFvHeader, OrigFvLength); + } + + return Status; +} + +EFI_STATUS +GetCoreMachineType( + IN EFI_FILE_SECTION_POINTER Pe32Section, + OUT UINT16 *CoreMachineType + ) +/*++ + +Routine Description: + + Returns the machine type of a P32 image, typically SEC or PEI core. + +Arguments: + + Pe32Section PE32 section data + CoreMachineType The extracted machine type + +Returns: + + EFI_SUCCESS Function Completed successfully. + EFI_ABORTED Error encountered. + EFI_INVALID_PARAMETER A required parameter was NULL. + +--*/ +{ + EFI_STATUS Status; + UINT32 EntryPoint; + UINT32 BaseOfCode; + + if (CoreMachineType == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = GetPe32Info( + (VOID *)((UINTN)Pe32Section.Pe32Section + GetSectionHeaderLength(Pe32Section.CommonHeader)), + &EntryPoint, + &BaseOfCode, + CoreMachineType + ); + if (EFI_ERROR(Status)) { + Error(NULL, 0, 3000, "Invalid", "could not get the PE32 machine type for the core."); + return EFI_ABORTED; + } + + return EFI_SUCCESS; +} + +EFI_STATUS +GetCoreEntryPointAddress( + IN VOID *FvImageBuffer, + IN FV_INFO *FvInfo, + IN EFI_FILE_SECTION_POINTER Pe32Section, + OUT EFI_PHYSICAL_ADDRESS *CoreEntryAddress +) +/*++ + +Routine Description: + + Returns the physical address of the core (SEC or PEI) entry point. + +Arguments: + + FvImageBuffer Pointer to buffer containing FV data + FvInfo Info for the parent FV + Pe32Section PE32 section data + CoreEntryAddress The extracted core entry physical address + +Returns: + + EFI_SUCCESS Function Completed successfully. + EFI_ABORTED Error encountered. + EFI_INVALID_PARAMETER A required parameter was NULL. + +--*/ +{ + EFI_STATUS Status; + UINT32 EntryPoint; + UINT32 BaseOfCode; + UINT16 MachineType; + EFI_PHYSICAL_ADDRESS EntryPhysicalAddress; + + if (CoreEntryAddress == NULL) { + return EFI_INVALID_PARAMETER; + } + + Status = GetPe32Info( + (VOID *)((UINTN)Pe32Section.Pe32Section + GetSectionHeaderLength(Pe32Section.CommonHeader)), + &EntryPoint, + &BaseOfCode, + &MachineType + ); + if (EFI_ERROR(Status)) { + Error(NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the core."); + return EFI_ABORTED; + } + + // + // Physical address is FV base + offset of PE32 + offset of the entry point + // + EntryPhysicalAddress = FvInfo->BaseAddress; + EntryPhysicalAddress += (UINTN)Pe32Section.Pe32Section + GetSectionHeaderLength(Pe32Section.CommonHeader) - (UINTN)FvImageBuffer; + EntryPhysicalAddress += EntryPoint; + + *CoreEntryAddress = EntryPhysicalAddress; + + return EFI_SUCCESS; +} EFI_STATUS UpdateArmResetVectorIfNeeded ( @@ -1613,13 +2120,15 @@ UpdateArmResetVectorIfNeeded ( /*++ Routine Description: - This parses the FV looking for SEC and patches that address into the + This parses the FV looking for SEC and patches that address into the beginning of the FV header. - For ARM the reset vector is at 0x00000000 or 0xFFFF0000. - This would commonly map to the first entry in the ROM. - ARM Exceptions: - Reset +0 + For ARM32 the reset vector is at 0x00000000 or 0xFFFF0000. + For AArch64 the reset vector is at 0x00000000. + + This would commonly map to the first entry in the ROM. + ARM32 Exceptions: + Reset +0 Undefined +4 SWI +8 Prefetch Abort +12 @@ -1629,16 +2138,15 @@ Routine Description: We support two schemes on ARM. 1) Beginning of the FV is the reset vector - 2) Reset vector is data bytes FDF file and that code branches to reset vector + 2) Reset vector is data bytes FDF file and that code branches to reset vector in the beginning of the FV (fixed size offset). - Need to have the jump for the reset vector at location zero. We also need to store the address or PEI (if it exists). - We stub out a return from interrupt in case the debugger - is using SWI. - The optional entry to the common exception handler is - to support full featured exception handling from ROM and is currently + We stub out a return from interrupt in case the debugger + is using SWI (not done for AArch64, not enough space in struct). + The optional entry to the common exception handler is + to support full featured exception handling from ROM and is currently not support by this tool. Arguments: @@ -1654,19 +2162,15 @@ Returns: --*/ { - EFI_FFS_FILE_HEADER *PeiCoreFile; - EFI_FFS_FILE_HEADER *SecCoreFile; - EFI_STATUS Status; - EFI_FILE_SECTION_POINTER Pe32Section; - UINT32 EntryPoint; - UINT32 BaseOfCode; - UINT16 MachineType; - EFI_PHYSICAL_ADDRESS PeiCorePhysicalAddress; - EFI_PHYSICAL_ADDRESS SecCorePhysicalAddress; - INT32 ResetVector[4]; // 0 - is branch relative to SEC entry point - // 1 - PEI Entry Point - // 2 - movs pc,lr for a SWI handler - // 3 - Place holder for Common Exception Handler + EFI_STATUS Status; + EFI_FILE_SECTION_POINTER SecPe32; + EFI_FILE_SECTION_POINTER PeiPe32; + BOOLEAN UpdateVectorSec = FALSE; + BOOLEAN UpdateVectorPei = FALSE; + UINT16 MachineType = 0; + EFI_PHYSICAL_ADDRESS SecCoreEntryAddress = 0; + UINT16 PeiMachineType = 0; + EFI_PHYSICAL_ADDRESS PeiCoreEntryAddress = 0; // // Verify input parameters @@ -1674,184 +2178,169 @@ Returns: if (FvImage == NULL || FvInfo == NULL) { return EFI_INVALID_PARAMETER; } - // - // Initialize FV library - // - InitializeFvLib (FvImage->FileImage, FvInfo->Size); // - // Find the Sec Core + // Locate an SEC Core instance and if found extract the machine type and entry point address // - Status = GetFileByType (EFI_FV_FILETYPE_SECURITY_CORE, 1, &SecCoreFile); - if (EFI_ERROR (Status) || SecCoreFile == NULL) { - // - // Maybe hardware does SEC job and we only have PEI Core? - // + Status = FindCorePeSection(FvImage->FileImage, FvInfo->Size, EFI_FV_FILETYPE_SECURITY_CORE, &SecPe32); + if (!EFI_ERROR(Status)) { - // - // Find the PEI Core. It may not exist if SEC loads DXE core directly - // - PeiCorePhysicalAddress = 0; - Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile); - if (!EFI_ERROR (Status) && PeiCoreFile != NULL) { - // - // PEI Core found, now find PE32 or TE section - // - Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section); - if (Status == EFI_NOT_FOUND) { - Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section); - } - - if (EFI_ERROR (Status)) { - Error (NULL, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file!"); - return EFI_ABORTED; - } - - Status = GetPe32Info ( - (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)), - &EntryPoint, - &BaseOfCode, - &MachineType - ); - - if (EFI_ERROR (Status)) { - Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core!"); - return EFI_ABORTED; - } - // - // Physical address is FV base + offset of PE32 + offset of the entry point - // - PeiCorePhysicalAddress = FvInfo->BaseAddress; - PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage; - PeiCorePhysicalAddress += EntryPoint; - DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress); - - if (MachineType == EFI_IMAGE_MACHINE_ARMT) { - memset (ResetVector, 0, sizeof (ResetVector)); - // Address of PEI Core, if we have one - ResetVector[1] = (UINT32)PeiCorePhysicalAddress; - } - - // - // Copy to the beginning of the FV - // - memcpy ((UINT8 *) ((UINTN) FvImage->FileImage), ResetVector, sizeof (ResetVector)); + Status = GetCoreMachineType(SecPe32, &MachineType); + if (EFI_ERROR(Status)) { + Error(NULL, 0, 3000, "Invalid", "Could not get the PE32 machine type for SEC Core."); + return EFI_ABORTED; + } + Status = GetCoreEntryPointAddress(FvImage->FileImage, FvInfo, SecPe32, &SecCoreEntryAddress); + if (EFI_ERROR(Status)) { + Error(NULL, 0, 3000, "Invalid", "Could not get the PE32 entry point address for SEC Core."); + return EFI_ABORTED; } - return EFI_SUCCESS; + VerboseMsg("UpdateArmResetVectorIfNeeded found SEC core entry at 0x%llx", (unsigned long long)SecCoreEntryAddress); + UpdateVectorSec = TRUE; } - + // - // Sec Core found, now find PE32 section + // Locate a PEI Core instance and if found extract the machine type and entry point address // - Status = GetSectionByType (SecCoreFile, EFI_SECTION_PE32, 1, &Pe32Section); - if (Status == EFI_NOT_FOUND) { - Status = GetSectionByType (SecCoreFile, EFI_SECTION_TE, 1, &Pe32Section); - } + Status = FindCorePeSection(FvImage->FileImage, FvInfo->Size, EFI_FV_FILETYPE_PEI_CORE, &PeiPe32); + if (!EFI_ERROR(Status)) { - if (EFI_ERROR (Status)) { - Error (NULL, 0, 3000, "Invalid", "could not find a PE32 section in the SEC core file."); - return EFI_ABORTED; - } + Status = GetCoreMachineType(PeiPe32, &PeiMachineType); + if (EFI_ERROR(Status)) { + Error(NULL, 0, 3000, "Invalid", "Could not get the PE32 machine type for PEI Core."); + return EFI_ABORTED; + } - Status = GetPe32Info ( - (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)), - &EntryPoint, - &BaseOfCode, - &MachineType - ); - if (EFI_ERROR (Status)) { - Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the SEC core."); - return EFI_ABORTED; + Status = GetCoreEntryPointAddress(FvImage->FileImage, FvInfo, PeiPe32, &PeiCoreEntryAddress); + if (EFI_ERROR(Status)) { + Error(NULL, 0, 3000, "Invalid", "Could not get the PE32 entry point address for PEI Core."); + return EFI_ABORTED; + } + + VerboseMsg("UpdateArmResetVectorIfNeeded found PEI core entry at 0x%llx", (unsigned long long)PeiCoreEntryAddress); + + // if we previously found an SEC Core make sure machine types match + if (UpdateVectorSec && (MachineType != PeiMachineType)) { + Error(NULL, 0, 3000, "Invalid", "SEC and PEI machine types do not match, can't update reset vector"); + return EFI_ABORTED; + } + else { + MachineType = PeiMachineType; + } + + UpdateVectorPei = TRUE; } - - if (MachineType != EFI_IMAGE_MACHINE_ARMT) { - // - // If SEC is not ARM we have nothing to do - // + + if (!UpdateVectorSec && !UpdateVectorPei) { return EFI_SUCCESS; } - - // - // Physical address is FV base + offset of PE32 + offset of the entry point - // - SecCorePhysicalAddress = FvInfo->BaseAddress; - SecCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage; - SecCorePhysicalAddress += EntryPoint; - DebugMsg (NULL, 0, 9, "SecCore physical entry point address", "Address = 0x%llX", (unsigned long long) SecCorePhysicalAddress); - // - // Find the PEI Core. It may not exist if SEC loads DXE core directly - // - PeiCorePhysicalAddress = 0; - Status = GetFileByType (EFI_FV_FILETYPE_PEI_CORE, 1, &PeiCoreFile); - if (!EFI_ERROR (Status) && PeiCoreFile != NULL) { + if (MachineType == EFI_IMAGE_MACHINE_ARMT) { + // ARM: Array of 4 UINT32s: + // 0 - is branch relative to SEC entry point + // 1 - PEI Entry Point + // 2 - movs pc,lr for a SWI handler + // 3 - Place holder for Common Exception Handler + UINT32 ResetVector[4]; + + memset(ResetVector, 0, sizeof (ResetVector)); + + // if we found an SEC core entry point then generate a branch instruction + // to it and populate a debugger SWI entry as well + if (UpdateVectorSec) { + + VerboseMsg("UpdateArmResetVectorIfNeeded updating ARM SEC vector"); + + // B SecEntryPoint - signed_immed_24 part +/-32MB offset + // on ARM, the PC is always 8 ahead, so we're not really jumping from the base address, but from base address + 8 + ResetVector[0] = (INT32)(SecCoreEntryAddress - FvInfo->BaseAddress - 8) >> 2; + + if (ResetVector[0] > 0x00FFFFFF) { + Error(NULL, 0, 3000, "Invalid", "SEC Entry point must be within 32MB of the start of the FV"); + return EFI_ABORTED; + } + + // Add opcode for an uncondional branch with no link. i.e.: " B SecEntryPoint" + ResetVector[0] |= ARMT_UNCONDITIONAL_JUMP_INSTRUCTION; + + // SWI handler movs pc,lr. Just in case a debugger uses SWI + ResetVector[2] = 0xE1B0F07E; + + // Place holder to support a common interrupt handler from ROM. + // Currently not suppprted. For this to be used the reset vector would not be in this FV + // and the exception vectors would be hard coded in the ROM and just through this address + // to find a common handler in the a module in the FV. + ResetVector[3] = 0; + } + + // if a PEI core entry was found place its address in the vector area + if (UpdateVectorPei) { + + VerboseMsg("UpdateArmResetVectorIfNeeded updating ARM PEI address"); + + // Address of PEI Core, if we have one + ResetVector[1] = (UINT32)PeiCoreEntryAddress; + } + // - // PEI Core found, now find PE32 or TE section + // Copy to the beginning of the FV // - Status = GetSectionByType (PeiCoreFile, EFI_SECTION_PE32, 1, &Pe32Section); - if (Status == EFI_NOT_FOUND) { - Status = GetSectionByType (PeiCoreFile, EFI_SECTION_TE, 1, &Pe32Section); - } - - if (EFI_ERROR (Status)) { - Error (NULL, 0, 3000, "Invalid", "could not find either a PE32 or a TE section in PEI core file!"); - return EFI_ABORTED; + memcpy(FvImage->FileImage, ResetVector, sizeof (ResetVector)); + + } else if (MachineType == EFI_IMAGE_MACHINE_AARCH64) { + // AArch64: Used as UINT64 ResetVector[2] + // 0 - is branch relative to SEC entry point + // 1 - PEI Entry Point + UINT64 ResetVector[2]; + + memset(ResetVector, 0, sizeof (ResetVector)); + + /* NOTE: + ARMT above has an entry in ResetVector[2] for SWI. The way we are using the ResetVector + array at the moment, for AArch64, does not allow us space for this as the header only + allows for a fixed amount of bytes at the start. If we are sure that UEFI will live + within the first 4GB of addressable RAM we could potensioally adopt the same ResetVector + layout as above. But for the moment we replace the four 32bit vectors with two 64bit + vectors in the same area of the Image heasder. This allows UEFI to start from a 64bit + base. + */ + + // if we found an SEC core entry point then generate a branch instruction to it + if (UpdateVectorSec) { + + VerboseMsg("UpdateArmResetVectorIfNeeded updating AArch64 SEC vector"); + + ResetVector[0] = (UINT64)(SecCoreEntryAddress - FvInfo->BaseAddress) >> 2; + + // B SecEntryPoint - signed_immed_26 part +/-128MB offset + if (ResetVector[0] > 0x03FFFFFF) { + Error(NULL, 0, 3000, "Invalid", "SEC Entry point must be within 128MB of the start of the FV"); + return EFI_ABORTED; + } + // Add opcode for an uncondional branch with no link. i.e.: " B SecEntryPoint" + ResetVector[0] |= ARM64_UNCONDITIONAL_JUMP_INSTRUCTION; } - - Status = GetPe32Info ( - (VOID *) ((UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32)), - &EntryPoint, - &BaseOfCode, - &MachineType - ); - - if (EFI_ERROR (Status)) { - Error (NULL, 0, 3000, "Invalid", "could not get the PE32 entry point for the PEI core!"); - return EFI_ABORTED; + + // if a PEI core entry was found place its address in the vector area + if (UpdateVectorPei) { + + VerboseMsg("UpdateArmResetVectorIfNeeded updating AArch64 PEI address"); + + // Address of PEI Core, if we have one + ResetVector[1] = (UINT64)PeiCoreEntryAddress; } + // - // Physical address is FV base + offset of PE32 + offset of the entry point + // Copy to the beginning of the FV // - PeiCorePhysicalAddress = FvInfo->BaseAddress; - PeiCorePhysicalAddress += (UINTN) Pe32Section.Pe32Section + sizeof (EFI_SECTION_PE32) - (UINTN) FvImage->FileImage; - PeiCorePhysicalAddress += EntryPoint; - DebugMsg (NULL, 0, 9, "PeiCore physical entry point address", "Address = 0x%llX", (unsigned long long) PeiCorePhysicalAddress); - } - - - // B SecEntryPoint - signed_immed_24 part +/-32MB offset - // on ARM, the PC is always 8 ahead, so we're not really jumping from the base address, but from base address + 8 - ResetVector[0] = (INT32)(SecCorePhysicalAddress - FvInfo->BaseAddress - 8) >> 2; - - if (ResetVector[0] > 0x00FFFFFF) { - Error (NULL, 0, 3000, "Invalid", "SEC Entry point must be within 32MB of the start of the FV"); - return EFI_ABORTED; - } - - // Add opcode for an uncondional branch with no link. AKA B SecEntryPoint - ResetVector[0] |= 0xEB000000; - - - // Address of PEI Core, if we have one - ResetVector[1] = (UINT32)PeiCorePhysicalAddress; - - // SWI handler movs pc,lr. Just in case a debugger uses SWI - ResetVector[2] = 0xE1B0F07E; - - // Place holder to support a common interrupt handler from ROM. - // Currently not suppprted. For this to be used the reset vector would not be in this FV - // and the exception vectors would be hard coded in the ROM and just through this address - // to find a common handler in the a module in the FV. - ResetVector[3] = 0; - - // - // Copy to the beginning of the FV - // - memcpy ((UINT8 *) ((UINTN) FvImage->FileImage), ResetVector, sizeof (ResetVector)); + memcpy(FvImage->FileImage, ResetVector, sizeof (ResetVector)); - DebugMsg (NULL, 0, 9, "Update Reset vector in FV Header", NULL); + } else { + Error(NULL, 0, 3000, "Invalid", "Unknown machine type"); + return EFI_ABORTED; + } return EFI_SUCCESS; } @@ -1867,8 +2356,8 @@ GetPe32Info ( Routine Description: - Retrieves the PE32 entry point offset and machine type from PE image or TeImage. - See EfiImage.h for machine types. The entry point offset is from the beginning + Retrieves the PE32 entry point offset and machine type from PE image or TeImage. + See EfiImage.h for machine types. The entry point offset is from the beginning of the PE32 buffer passed in. Arguments: @@ -1910,13 +2399,13 @@ Returns: *BaseOfCode = TeHeader->BaseOfCode + sizeof (EFI_TE_IMAGE_HEADER) - TeHeader->StrippedSize; *MachineType = TeHeader->Machine; } else { - + // - // Then check whether + // Then check whether // First is the DOS header // DosHeader = (EFI_IMAGE_DOS_HEADER *) Pe32; - + // // Verify DOS header is expected // @@ -1928,7 +2417,7 @@ Returns: // Immediately following is the NT header. // ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *) ((UINTN) Pe32 + DosHeader->e_lfanew); - + // // Verify NT header is expected // @@ -1947,8 +2436,8 @@ Returns: // // Verify machine type is supported // - if (*MachineType != EFI_IMAGE_MACHINE_IA32 && *MachineType != EFI_IMAGE_MACHINE_IA64 && *MachineType != EFI_IMAGE_MACHINE_X64 && *MachineType != EFI_IMAGE_MACHINE_EBC && - *MachineType != EFI_IMAGE_MACHINE_ARMT) { + if ((*MachineType != EFI_IMAGE_MACHINE_IA32) && (*MachineType != EFI_IMAGE_MACHINE_IA64) && (*MachineType != EFI_IMAGE_MACHINE_X64) && (*MachineType != EFI_IMAGE_MACHINE_EBC) && + (*MachineType != EFI_IMAGE_MACHINE_ARMT) && (*MachineType != EFI_IMAGE_MACHINE_AARCH64)) { Error (NULL, 0, 3000, "Invalid", "Unrecognized machine type in the PE32 file."); return EFI_UNSUPPORTED; } @@ -1995,17 +2484,19 @@ Returns: UINT8 *FvImage; UINTN FvImageSize; FILE *FvFile; - CHAR8 FvMapName [_MAX_PATH]; + CHAR8 *FvMapName; FILE *FvMapFile; EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader; FILE *FvExtHeaderFile; UINTN FileSize; - CHAR8 FvReportName[_MAX_PATH]; + CHAR8 *FvReportName; FILE *FvReportFile; FvBufferHeader = NULL; FvFile = NULL; + FvMapName = NULL; FvMapFile = NULL; + FvReportName = NULL; FvReportFile = NULL; if (InfFileImage != NULL) { @@ -2015,7 +2506,7 @@ Returns: InfMemoryFile.FileImage = InfFileImage; InfMemoryFile.CurrentFilePointer = InfFileImage; InfMemoryFile.Eof = InfFileImage + InfFileSize; - + // // Parse the FV inf file for header information // @@ -2037,17 +2528,17 @@ Returns: Error (NULL, 0, 1001, "Missing option", "Output file name"); return EFI_ABORTED; } - + if (mFvDataInfo.FvBlocks[0].Length == 0) { Error (NULL, 0, 1001, "Missing required argument", "Block Size"); return EFI_ABORTED; } - + // // Debug message Fv File System Guid // if (mFvDataInfo.FvFileSystemGuidSet) { - DebugMsg (NULL, 0, 9, "FV File System Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + DebugMsg (NULL, 0, 9, "FV File System Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", (unsigned) mFvDataInfo.FvFileSystemGuid.Data1, mFvDataInfo.FvFileSystemGuid.Data2, mFvDataInfo.FvFileSystemGuid.Data3, @@ -2070,7 +2561,11 @@ Returns: // // Open the FV Extension Header file // - FvExtHeaderFile = fopen (mFvDataInfo.FvExtHeaderFile, "rb"); + FvExtHeaderFile = fopen (LongFilePath (mFvDataInfo.FvExtHeaderFile), "rb"); + if (FvExtHeaderFile == NULL) { + Error (NULL, 0, 0001, "Error opening file", mFvDataInfo.FvExtHeaderFile); + return EFI_ABORTED; + } // // Get the file size @@ -2116,7 +2611,7 @@ Returns: // Debug message Fv Name Guid // if (mFvDataInfo.FvNameGuidSet) { - DebugMsg (NULL, 0, 9, "FV Name Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", + DebugMsg (NULL, 0, 9, "FV Name Guid", "%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X", (unsigned) mFvDataInfo.FvNameGuid.Data1, mFvDataInfo.FvNameGuid.Data2, mFvDataInfo.FvNameGuid.Data3, @@ -2130,7 +2625,8 @@ Returns: mFvDataInfo.FvNameGuid.Data4[7]); } - if (CompareGuid (&mFvDataInfo.FvFileSystemGuid, &mEfiFirmwareFileSystem2Guid) == 0) { + if (CompareGuid (&mFvDataInfo.FvFileSystemGuid, &mEfiFirmwareFileSystem2Guid) == 0 || + CompareGuid (&mFvDataInfo.FvFileSystemGuid, &mEfiFirmwareFileSystem3Guid) == 0) { mFvDataInfo.IsPiFvImage = TRUE; } @@ -2138,8 +2634,34 @@ Returns: // FvMap file to log the function address of all modules in one Fvimage // if (MapFileName != NULL) { + if (strlen (MapFileName) > MAX_LONG_FILE_PATH - 1) { + Error (NULL, 0, 1003, "Invalid option value", "MapFileName %s is too long!", MapFileName); + Status = EFI_ABORTED; + goto Finish; + } + + FvMapName = malloc (strlen (MapFileName) + 1); + if (FvMapName == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + Status = EFI_OUT_OF_RESOURCES; + goto Finish; + } + strcpy (FvMapName, MapFileName); } else { + if (strlen (FvFileName) + strlen (".map") > MAX_LONG_FILE_PATH - 1) { + Error (NULL, 0, 1003, "Invalid option value", "FvFileName %s is too long!", FvFileName); + Status = EFI_ABORTED; + goto Finish; + } + + FvMapName = malloc (strlen (FvFileName) + strlen (".map") + 1); + if (FvMapName == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + Status = EFI_OUT_OF_RESOURCES; + goto Finish; + } + strcpy (FvMapName, FvFileName); strcat (FvMapName, ".map"); } @@ -2148,6 +2670,19 @@ Returns: // // FvReport file to log the FV information in one Fvimage // + if (strlen (FvFileName) + strlen (".txt") > MAX_LONG_FILE_PATH - 1) { + Error (NULL, 0, 1003, "Invalid option value", "FvFileName %s is too long!", FvFileName); + Status = EFI_ABORTED; + goto Finish; + } + + FvReportName = malloc (strlen (FvFileName) + strlen (".txt") + 1); + if (FvReportName == NULL) { + Error (NULL, 0, 4001, "Resource", "memory cannot be allocated!"); + Status = EFI_OUT_OF_RESOURCES; + goto Finish; + } + strcpy (FvReportName, FvFileName); strcat (FvReportName, ".txt"); @@ -2157,10 +2692,10 @@ Returns: // Status = CalculateFvSize (&mFvDataInfo); if (EFI_ERROR (Status)) { - return Status; + goto Finish; } VerboseMsg ("the generated FV image size is %u bytes", (unsigned) mFvDataInfo.Size); - + // // support fv image and empty fv image // @@ -2171,7 +2706,8 @@ Returns: // FvBufferHeader = malloc (FvImageSize + sizeof (UINT64)); if (FvBufferHeader == NULL) { - return EFI_OUT_OF_RESOURCES; + Status = EFI_OUT_OF_RESOURCES; + goto Finish; } FvImage = (UINT8 *) (((UINTN) FvBufferHeader + 7) & ~7); @@ -2180,7 +2716,7 @@ Returns: // if (mFvDataInfo.FvAttributes == 0) { // - // Set Default Fv Attribute + // Set Default Fv Attribute // mFvDataInfo.FvAttributes = FV_DEFAULT_ATTRIBUTE; } @@ -2211,7 +2747,7 @@ Returns: FvHeader->Revision = EFI_FVH_REVISION; FvHeader->ExtHeaderOffset = 0; FvHeader->Reserved[0] = 0; - + // // Copy firmware block map // @@ -2260,19 +2796,21 @@ Returns: // // Open FvMap file // - FvMapFile = fopen (FvMapName, "w"); + FvMapFile = fopen (LongFilePath (FvMapName), "w"); if (FvMapFile == NULL) { Error (NULL, 0, 0001, "Error opening file", FvMapName); - return EFI_ABORTED; + Status = EFI_ABORTED; + goto Finish; } - + // // Open FvReport file // - FvReportFile = fopen(FvReportName, "w"); + FvReportFile = fopen (LongFilePath (FvReportName), "w"); if (FvReportFile == NULL) { Error (NULL, 0, 0001, "Error opening file", FvReportName); - return EFI_ABORTED; + Status = EFI_ABORTED; + goto Finish; } // // record FV size information into FvMap file. @@ -2303,7 +2841,7 @@ Returns: // // Add FV Extended Header contents to the FV as a PAD file // - AddPadFile (&FvImageMemoryFile, 4, VtfFileImage, FvExtHeader); + AddPadFile (&FvImageMemoryFile, 4, VtfFileImage, FvExtHeader, 0); // // Fv Extension header change update Fv Header Check sum @@ -2345,40 +2883,43 @@ Returns: if (!mArm) { // // Update reset vector (SALE_ENTRY for IPF) - // Now for IA32 and IA64 platform, the fv which has bsf file must have the - // EndAddress of 0xFFFFFFFF. Thus, only this type fv needs to update the - // reset vector. If the PEI Core is found, the VTF file will probably get - // corrupted by updating the entry point. + // Now for IA32 and IA64 platform, the fv which has bsf file must have the + // EndAddress of 0xFFFFFFFF (unless the section was rebased). + // Thus, only this type fv needs to update the reset vector. + // If the PEI Core is found, the VTF file will probably get + // corrupted by updating the entry point. // - if ((mFvDataInfo.BaseAddress + mFvDataInfo.Size) == FV_IMAGES_TOP_ADDRESS) { + if (mFvDataInfo.ForceRebase == 1 || + (mFvDataInfo.BaseAddress + mFvDataInfo.Size) == FV_IMAGES_TOP_ADDRESS) { Status = UpdateResetVector (&FvImageMemoryFile, &mFvDataInfo, VtfFileImage); - if (EFI_ERROR(Status)) { + if (EFI_ERROR(Status)) { Error (NULL, 0, 3000, "Invalid", "Could not update the reset vector."); - goto Finish; + goto Finish; } DebugMsg (NULL, 0, 9, "Update Reset vector in VTF file", NULL); } } - } + } if (mArm) { Status = UpdateArmResetVectorIfNeeded (&FvImageMemoryFile, &mFvDataInfo); - if (EFI_ERROR (Status)) { + if (EFI_ERROR (Status)) { Error (NULL, 0, 3000, "Invalid", "Could not update the reset vector."); - goto Finish; - } - + goto Finish; + } + // // Update Checksum for FvHeader // FvHeader->Checksum = 0; FvHeader->Checksum = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16)); } - + // // Update FV Alignment attribute to the largest alignment of all the FFS files in the FV // - if ((((FvHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16)) < MaxFfsAlignment) { + if (((FvHeader->Attributes & EFI_FVB2_WEAK_ALIGNMENT) != EFI_FVB2_WEAK_ALIGNMENT) && + (((FvHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16)) < MaxFfsAlignment) { FvHeader->Attributes = ((MaxFfsAlignment << 16) | (FvHeader->Attributes & 0xFFFF)); // // Update Checksum for FvHeader @@ -2387,11 +2928,20 @@ Returns: FvHeader->Checksum = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16)); } -WriteFile: + // + // If there are large FFS in FV, the file system GUID should set to system 3 GUID. + // + if (mIsLargeFfs && CompareGuid (&FvHeader->FileSystemGuid, &mEfiFirmwareFileSystem2Guid) == 0) { + memcpy (&FvHeader->FileSystemGuid, &mEfiFirmwareFileSystem3Guid, sizeof (EFI_GUID)); + FvHeader->Checksum = 0; + FvHeader->Checksum = CalculateChecksum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength / sizeof (UINT16)); + } + +WriteFile: // // Write fv file // - FvFile = fopen (FvFileName, "wb"); + FvFile = fopen (LongFilePath (FvFileName), "wb"); if (FvFile == NULL) { Error (NULL, 0, 0001, "Error opening file", FvFileName); Status = EFI_ABORTED; @@ -2412,12 +2962,20 @@ Finish: if (FvExtHeader != NULL) { free (FvExtHeader); } - + + if (FvMapName != NULL) { + free (FvMapName); + } + + if (FvReportName != NULL) { + free (FvReportName); + } + if (FvFile != NULL) { fflush (FvFile); fclose (FvFile); } - + if (FvMapFile != NULL) { fflush (FvMapFile); fclose (FvMapFile); @@ -2523,13 +3081,12 @@ Returns: UINTN FfsFileSize; UINTN FvExtendHeaderSize; UINT32 FfsAlignment; + UINT32 FfsHeaderSize; EFI_FFS_FILE_HEADER FfsHeader; - BOOLEAN VtfFileFlag; UINTN VtfFileSize; - + FvExtendHeaderSize = 0; VtfFileSize = 0; - VtfFileFlag = FALSE; fpin = NULL; Index = 0; @@ -2540,31 +3097,36 @@ Returns: for (Index = 0; FvInfoPtr->FvBlocks[Index].NumBlocks > 0 && FvInfoPtr->FvBlocks[Index].Length > 0; Index++) { FvInfoPtr->Size += FvInfoPtr->FvBlocks[Index].NumBlocks * FvInfoPtr->FvBlocks[Index].Length; } - + // - // Caculate the required sizes for all FFS files. + // Calculate the required sizes for all FFS files. // CurrentOffset = sizeof (EFI_FIRMWARE_VOLUME_HEADER); - + for (Index = 1;; Index ++) { CurrentOffset += sizeof (EFI_FV_BLOCK_MAP_ENTRY); if (FvInfoPtr->FvBlocks[Index].NumBlocks == 0 || FvInfoPtr->FvBlocks[Index].Length == 0) { break; } } - + // // Calculate PI extension header // if (mFvDataInfo.FvExtHeaderFile[0] != '\0') { - fpin = fopen (mFvDataInfo.FvExtHeaderFile, "rb"); + fpin = fopen (LongFilePath (mFvDataInfo.FvExtHeaderFile), "rb"); if (fpin == NULL) { Error (NULL, 0, 0001, "Error opening file", mFvDataInfo.FvExtHeaderFile); return EFI_ABORTED; } FvExtendHeaderSize = _filelength (fileno (fpin)); fclose (fpin); - CurrentOffset += sizeof (EFI_FFS_FILE_HEADER) + FvExtendHeaderSize; + if (sizeof (EFI_FFS_FILE_HEADER) + FvExtendHeaderSize >= MAX_FFS_SIZE) { + CurrentOffset += sizeof (EFI_FFS_FILE_HEADER2) + FvExtendHeaderSize; + mIsLargeFfs = TRUE; + } else { + CurrentOffset += sizeof (EFI_FFS_FILE_HEADER) + FvExtendHeaderSize; + } CurrentOffset = (CurrentOffset + 7) & (~7); } else if (mFvDataInfo.FvNameGuidSet) { CurrentOffset += sizeof (EFI_FFS_FILE_HEADER) + sizeof (EFI_FIRMWARE_VOLUME_EXT_HEADER); @@ -2579,7 +3141,7 @@ Returns: // Open FFS file // fpin = NULL; - fpin = fopen (FvInfoPtr->FvFiles[Index], "rb"); + fpin = fopen (LongFilePath (FvInfoPtr->FvFiles[Index]), "rb"); if (fpin == NULL) { Error (NULL, 0, 0001, "Error opening file", FvInfoPtr->FvFiles[Index]); return EFI_ABORTED; @@ -2588,6 +3150,12 @@ Returns: // Get the file size // FfsFileSize = _filelength (fileno (fpin)); + if (FfsFileSize >= MAX_FFS_SIZE) { + FfsHeaderSize = sizeof(EFI_FFS_FILE_HEADER2); + mIsLargeFfs = TRUE; + } else { + FfsHeaderSize = sizeof(EFI_FFS_FILE_HEADER); + } // // Read Ffs File header // @@ -2596,57 +3164,61 @@ Returns: // close file // fclose (fpin); - + if (FvInfoPtr->IsPiFvImage) { - // - // Check whether this ffs file is vtf file - // - if (IsVtfFile (&FfsHeader)) { - if (VtfFileFlag) { - // - // One Fv image can't have two vtf files. - // - return EFI_ABORTED; - } - VtfFileFlag = TRUE; + // + // Check whether this ffs file is vtf file + // + if (IsVtfFile (&FfsHeader)) { + if (VtfFileFlag) { + // + // One Fv image can't have two vtf files. + // + Error (NULL, 0, 3000,"Invalid", "One Fv image can't have two vtf files."); + return EFI_ABORTED; + } + VtfFileFlag = TRUE; VtfFileSize = FfsFileSize; continue; } // - // Get the alignment of FFS file + // Get the alignment of FFS file // ReadFfsAlignment (&FfsHeader, &FfsAlignment); FfsAlignment = 1 << FfsAlignment; // // Add Pad file // - if (((CurrentOffset + sizeof (EFI_FFS_FILE_HEADER)) % FfsAlignment) != 0) { - CurrentOffset = (CurrentOffset + sizeof (EFI_FFS_FILE_HEADER) * 2 + FfsAlignment - 1) & ~(FfsAlignment - 1); - CurrentOffset -= sizeof (EFI_FFS_FILE_HEADER); + if (((CurrentOffset + FfsHeaderSize) % FfsAlignment) != 0) { + // + // Only EFI_FFS_FILE_HEADER is needed for a pad section. + // + CurrentOffset = (CurrentOffset + FfsHeaderSize + sizeof(EFI_FFS_FILE_HEADER) + FfsAlignment - 1) & ~(FfsAlignment - 1); + CurrentOffset -= FfsHeaderSize; } - } + } // // Add ffs file size // if (FvInfoPtr->SizeofFvFiles[Index] > FfsFileSize) { - CurrentOffset += FvInfoPtr->SizeofFvFiles[Index]; + CurrentOffset += FvInfoPtr->SizeofFvFiles[Index]; } else { - CurrentOffset += FfsFileSize; + CurrentOffset += FfsFileSize; } - + // // Make next ffs file start at QWord Boundry // if (FvInfoPtr->IsPiFvImage) { - CurrentOffset = (CurrentOffset + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1); + CurrentOffset = (CurrentOffset + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1); } } CurrentOffset += VtfFileSize; - DebugMsg (NULL, 0, 9, "FvImage size", "The caculated fv image size is 0x%x and the current set fv image size is 0x%x", (unsigned) CurrentOffset, (unsigned) FvInfoPtr->Size); - - if (FvInfoPtr->Size == 0) { + 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); + + if (FvInfoPtr->Size == 0) { // // Update FvInfo data // @@ -2661,7 +3233,7 @@ Returns: 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); return EFI_INVALID_PARAMETER; } - + // // Set Fv Size Information // @@ -2716,7 +3288,7 @@ Returns: EFI_STATUS GetChildFvFromFfs ( - IN FV_INFO *FvInfo, + IN FV_INFO *FvInfo, IN EFI_FFS_FILE_HEADER *FfsFile, IN UINTN XipOffset ) @@ -2742,16 +3314,42 @@ Returns: EFI_FILE_SECTION_POINTER SubFvSection; EFI_FIRMWARE_VOLUME_HEADER *SubFvImageHeader; EFI_PHYSICAL_ADDRESS SubFvBaseAddress; + EFI_FILE_SECTION_POINTER CorePe32; + UINT16 MachineType; for (Index = 1;; Index++) { // - // Find FV section + // Find FV section // Status = GetSectionByType (FfsFile, EFI_SECTION_FIRMWARE_VOLUME_IMAGE, Index, &SubFvSection); if (EFI_ERROR (Status)) { break; } - SubFvImageHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) SubFvSection.FVImageSection + sizeof (EFI_FIRMWARE_VOLUME_IMAGE_SECTION)); + SubFvImageHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) SubFvSection.FVImageSection + GetSectionHeaderLength(SubFvSection.FVImageSection)); + + // + // See if there's an SEC core in the child FV + Status = FindCorePeSection(SubFvImageHeader, SubFvImageHeader->FvLength, EFI_FV_FILETYPE_SECURITY_CORE, &CorePe32); + + // if we couldn't find the SEC core, look for a PEI core + if (EFI_ERROR(Status)) { + Status = FindCorePeSection(SubFvImageHeader, SubFvImageHeader->FvLength, EFI_FV_FILETYPE_PEI_CORE, &CorePe32); + } + + if (!EFI_ERROR(Status)) { + Status = GetCoreMachineType(CorePe32, &MachineType); + if (EFI_ERROR(Status)) { + Error(NULL, 0, 3000, "Invalid", "Could not get the PE32 machine type for SEC/PEI Core."); + return EFI_ABORTED; + } + + // machine type is ARM, set a flag so ARM reset vector procesing occurs + if ((MachineType == EFI_IMAGE_MACHINE_ARMT) || (MachineType == EFI_IMAGE_MACHINE_AARCH64)) { + VerboseMsg("Located ARM/AArch64 SEC/PEI core in child FV"); + mArm = TRUE; + } + } + // // Rebase on Flash // @@ -2763,9 +3361,9 @@ Returns: } EFI_STATUS -FfsRebase ( - IN OUT FV_INFO *FvInfo, - IN CHAR8 *FileName, +FfsRebase ( + IN OUT FV_INFO *FvInfo, + IN CHAR8 *FileName, IN OUT EFI_FFS_FILE_HEADER *FfsFile, IN UINTN XipOffset, IN FILE *FvMapFile @@ -2778,7 +3376,7 @@ Routine Description: rebase any PE32 sections found in the file using the base address. Arguments: - + FvInfo A pointer to FV_INFO struture. FileName Ffs File PathName FfsFile A pointer to Ffs file image. @@ -2797,10 +3395,9 @@ Returns: { EFI_STATUS Status; PE_COFF_LOADER_IMAGE_CONTEXT ImageContext; - PE_COFF_LOADER_IMAGE_CONTEXT OrigImageContext; + PE_COFF_LOADER_IMAGE_CONTEXT OrigImageContext; EFI_PHYSICAL_ADDRESS XipBase; EFI_PHYSICAL_ADDRESS NewPe32BaseAddress; - EFI_PHYSICAL_ADDRESS *BaseToUpdate; UINTN Index; EFI_FILE_SECTION_POINTER CurrentPe32Section; EFI_FFS_FILE_STATE SavedState; @@ -2808,16 +3405,17 @@ Returns: EFI_TE_IMAGE_HEADER *TEImageHeader; UINT8 *MemoryImagePointer; EFI_IMAGE_SECTION_HEADER *SectionHeader; - CHAR8 PeFileName [_MAX_PATH]; + CHAR8 PeFileName [MAX_LONG_FILE_PATH]; CHAR8 *Cptr; FILE *PeFile; UINT8 *PeFileBuffer; UINT32 PeFileSize; CHAR8 *PdbPointer; + UINT32 FfsHeaderSize; + UINT32 CurSecHdrSize; - Index = 0; + Index = 0; MemoryImagePointer = NULL; - BaseToUpdate = NULL; TEImageHeader = NULL; ImgHdr = NULL; SectionHeader = NULL; @@ -2826,11 +3424,20 @@ Returns: PeFileBuffer = NULL; // - // Don't need to relocate image when BaseAddress is not set. + // Don't need to relocate image when BaseAddress is zero and no ForceRebase Flag specified. + // + if ((FvInfo->BaseAddress == 0) && (FvInfo->ForceRebase == -1)) { + return EFI_SUCCESS; + } + + // + // If ForceRebase Flag specified to FALSE, will always not take rebase action. // - if (FvInfo->BaseAddress == 0) { + if (FvInfo->ForceRebase == 0) { return EFI_SUCCESS; } + + XipBase = FvInfo->BaseAddress + XipOffset; // @@ -2857,6 +3464,8 @@ Returns: default: return EFI_SUCCESS; } + + FfsHeaderSize = GetFfsHeaderLength(FfsFile); // // Rebase each PE32 section // @@ -2866,7 +3475,7 @@ Returns: // Init Value // NewPe32BaseAddress = 0; - + // // Find Pe Image // @@ -2874,12 +3483,13 @@ Returns: if (EFI_ERROR (Status)) { break; } + CurSecHdrSize = GetSectionHeaderLength(CurrentPe32Section.CommonHeader); // // Initialize context // memset (&ImageContext, 0, sizeof (ImageContext)); - ImageContext.Handle = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION)); + ImageContext.Handle = (VOID *) ((UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize); ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE) FfsRebaseImageRead; Status = PeCoffLoaderGetImageInfo (&ImageContext); if (EFI_ERROR (Status)) { @@ -2887,7 +3497,8 @@ Returns: return Status; } - if (ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) { + if ( (ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) || + (ImageContext.Machine == EFI_IMAGE_MACHINE_AARCH64) ) { mArm = TRUE; } @@ -2895,7 +3506,7 @@ Returns: // Keep Image Context for PE image in FV // memcpy (&OrigImageContext, &ImageContext, sizeof (ImageContext)); - + // // Get File PdbPointer // @@ -2904,7 +3515,7 @@ Returns: // // Get PeHeader pointer // - ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) + ImageContext.PeCoffHeaderOffset); + ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize + ImageContext.PeCoffHeaderOffset); // // Calculate the PE32 base address, based on file type @@ -2921,17 +3532,22 @@ Returns: // // Xip module has the same section alignment and file alignment. // - Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName); + Error (NULL, 0, 3000, "Invalid", "PE image Section-Alignment and File-Alignment do not match : %s.", FileName); return EFI_ABORTED; } // - // PeImage has no reloc section. It will try to get reloc data from the original EFI image. + // PeImage has no reloc section. It will try to get reloc data from the original EFI image. // if (ImageContext.RelocationsStripped) { // - // Construct the original efi file Name + // Construct the original efi file Name // - strcpy (PeFileName, FileName); + if (strlen (FileName) >= MAX_LONG_FILE_PATH) { + Error (NULL, 0, 2000, "Invalid", "The file name %s is too long.", FileName); + return EFI_ABORTED; + } + strncpy (PeFileName, FileName, MAX_LONG_FILE_PATH - 1); + PeFileName[MAX_LONG_FILE_PATH - 1] = 0; Cptr = PeFileName + strlen (PeFileName); while (*Cptr != '.') { Cptr --; @@ -2945,7 +3561,7 @@ Returns: *(Cptr + 3) = 'i'; *(Cptr + 4) = '\0'; } - PeFile = fopen (PeFileName, "rb"); + PeFile = fopen (LongFilePath (PeFileName), "rb"); if (PeFile == NULL) { Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName); //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName); @@ -2958,6 +3574,7 @@ Returns: PeFileSize = _filelength (fileno (PeFile)); PeFileBuffer = (UINT8 *) malloc (PeFileSize); if (PeFileBuffer == NULL) { + fclose (PeFile); Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName); return EFI_OUT_OF_RESOURCES; } @@ -2981,8 +3598,7 @@ Returns: ImageContext.RelocationsStripped = FALSE; } - NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) - (UINTN)FfsFile; - BaseToUpdate = &XipBase; + NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile; break; case EFI_FV_FILETYPE_DRIVER: @@ -2994,11 +3610,10 @@ Returns: // // Xip module has the same section alignment and file alignment. // - Error (NULL, 0, 3000, "Invalid", "Section-Alignment and File-Alignment do not match : %s.", FileName); + Error (NULL, 0, 3000, "Invalid", "PE image Section-Alignment and File-Alignment do not match : %s.", FileName); return EFI_ABORTED; } - NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + sizeof (EFI_PE32_SECTION) - (UINTN)FfsFile; - BaseToUpdate = &XipBase; + NewPe32BaseAddress = XipBase + (UINTN) CurrentPe32Section.Pe32Section + CurSecHdrSize - (UINTN)FfsFile; break; default: @@ -3007,7 +3622,7 @@ Returns: // return EFI_SUCCESS; } - + // // Relocation doesn't exist // @@ -3029,14 +3644,14 @@ Returns: } memset ((VOID *) MemoryImagePointer, 0, (UINTN) ImageContext.ImageSize + ImageContext.SectionAlignment); ImageContext.ImageAddress = ((UINTN) MemoryImagePointer + ImageContext.SectionAlignment - 1) & (~((UINTN) ImageContext.SectionAlignment - 1)); - + Status = PeCoffLoaderLoadImage (&ImageContext); if (EFI_ERROR (Status)) { Error (NULL, 0, 3000, "Invalid", "LocateImage() call failed on rebase of %s", FileName); free ((VOID *) MemoryImagePointer); return Status; } - + ImageContext.DestinationAddress = NewPe32BaseAddress; Status = PeCoffLoaderRelocateImage (&ImageContext); if (EFI_ERROR (Status)) { @@ -3050,15 +3665,15 @@ Returns: // SectionHeader = (EFI_IMAGE_SECTION_HEADER *) ( (UINTN) ImgHdr + - sizeof (UINT32) + - sizeof (EFI_IMAGE_FILE_HEADER) + + sizeof (UINT32) + + sizeof (EFI_IMAGE_FILE_HEADER) + ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader ); - + for (Index = 0; Index < ImgHdr->Pe32.FileHeader.NumberOfSections; Index ++, SectionHeader ++) { CopyMem ( - (UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER) + SectionHeader->PointerToRawData, - (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress), + (UINT8 *) CurrentPe32Section.Pe32Section + CurSecHdrSize + SectionHeader->PointerToRawData, + (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress), SectionHeader->SizeOfRawData ); } @@ -3069,7 +3684,7 @@ Returns: free (PeFileBuffer); PeFileBuffer = NULL; } - + // // Update Image Base Address // @@ -3093,8 +3708,8 @@ Returns: FfsFile->IntegrityCheck.Checksum.File = 0; FfsFile->State = 0; FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 ( - (UINT8 *) (FfsFile + 1), - GetLength (FfsFile->Size) - sizeof (EFI_FFS_FILE_HEADER) + (UINT8 *) ((UINT8 *)FfsFile + FfsHeaderSize), + GetFfsFileLength (FfsFile) - FfsHeaderSize ); FfsFile->State = SavedState; } @@ -3124,13 +3739,13 @@ Returns: // return EFI_SUCCESS; } - + // // Now process TE sections // for (Index = 1;; Index++) { NewPe32BaseAddress = 0; - + // // Find Te Image // @@ -3138,12 +3753,14 @@ Returns: if (EFI_ERROR (Status)) { break; } - + + CurSecHdrSize = GetSectionHeaderLength(CurrentPe32Section.CommonHeader); + // // Calculate the TE base address, the FFS file base plus the offset of the TE section less the size stripped off // by GenTEImage // - TEImageHeader = (EFI_TE_IMAGE_HEADER *) ((UINT8 *) CurrentPe32Section.Pe32Section + sizeof (EFI_COMMON_SECTION_HEADER)); + TEImageHeader = (EFI_TE_IMAGE_HEADER *) ((UINT8 *) CurrentPe32Section.Pe32Section + CurSecHdrSize); // // Initialize context, load image info. @@ -3157,7 +3774,8 @@ Returns: return Status; } - if (ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) { + if ( (ImageContext.Machine == EFI_IMAGE_MACHINE_ARMT) || + (ImageContext.Machine == EFI_IMAGE_MACHINE_AARCH64) ) { mArm = TRUE; } @@ -3182,9 +3800,14 @@ Returns: // if (ImageContext.RelocationsStripped) { // - // Construct the original efi file name + // Construct the original efi file name // - strcpy (PeFileName, FileName); + if (strlen (FileName) >= MAX_LONG_FILE_PATH) { + Error (NULL, 0, 2000, "Invalid", "The file name %s is too long.", FileName); + return EFI_ABORTED; + } + strncpy (PeFileName, FileName, MAX_LONG_FILE_PATH - 1); + PeFileName[MAX_LONG_FILE_PATH - 1] = 0; Cptr = PeFileName + strlen (PeFileName); while (*Cptr != '.') { Cptr --; @@ -3200,7 +3823,7 @@ Returns: *(Cptr + 4) = '\0'; } - PeFile = fopen (PeFileName, "rb"); + PeFile = fopen (LongFilePath (PeFileName), "rb"); if (PeFile == NULL) { Warning (NULL, 0, 0, "Invalid", "The file %s has no .reloc section.", FileName); //Error (NULL, 0, 3000, "Invalid", "The file %s has no .reloc section.", FileName); @@ -3212,6 +3835,7 @@ Returns: PeFileSize = _filelength (fileno (PeFile)); PeFileBuffer = (UINT8 *) malloc (PeFileSize); if (PeFileBuffer == NULL) { + fclose (PeFile); Error (NULL, 0, 4001, "Resource", "memory cannot be allocated on rebase of %s", FileName); return EFI_OUT_OF_RESOURCES; } @@ -3265,7 +3889,7 @@ Returns: } // // Reloacate TeImage - // + // ImageContext.DestinationAddress = NewPe32BaseAddress; Status = PeCoffLoaderRelocateImage (&ImageContext); if (EFI_ERROR (Status)) { @@ -3273,7 +3897,7 @@ Returns: free ((VOID *) MemoryImagePointer); return Status; } - + // // Copy the relocated image into raw image file. // @@ -3281,19 +3905,19 @@ Returns: for (Index = 0; Index < TEImageHeader->NumberOfSections; Index ++, SectionHeader ++) { if (!ImageContext.IsTeImage) { CopyMem ( - (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData, - (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress), + (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData, + (VOID*) (UINTN) (ImageContext.ImageAddress + SectionHeader->VirtualAddress), SectionHeader->SizeOfRawData ); } else { CopyMem ( - (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData, - (VOID*) (UINTN) (ImageContext.ImageAddress + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->VirtualAddress), + (UINT8 *) TEImageHeader + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->PointerToRawData, + (VOID*) (UINTN) (ImageContext.ImageAddress + sizeof (EFI_TE_IMAGE_HEADER) - TEImageHeader->StrippedSize + SectionHeader->VirtualAddress), SectionHeader->SizeOfRawData ); } } - + // // Free the allocated memory resource // @@ -3303,7 +3927,7 @@ Returns: free (PeFileBuffer); PeFileBuffer = NULL; } - + // // Update Image Base Address // @@ -3317,8 +3941,8 @@ Returns: FfsFile->IntegrityCheck.Checksum.File = 0; FfsFile->State = 0; FfsFile->IntegrityCheck.Checksum.File = CalculateChecksum8 ( - (UINT8 *)(FfsFile + 1), - GetLength (FfsFile->Size) - sizeof (EFI_FFS_FILE_HEADER) + (UINT8 *)((UINT8 *)FfsFile + FfsHeaderSize), + GetFfsFileLength (FfsFile) - FfsHeaderSize ); FfsFile->State = SavedState; } @@ -3334,14 +3958,14 @@ Returns: } WriteMapFile ( - FvMapFile, - PdbPointer, + FvMapFile, + PdbPointer, FfsFile, - NewPe32BaseAddress, + NewPe32BaseAddress, &OrigImageContext ); } - + return EFI_SUCCESS; } @@ -3388,12 +4012,12 @@ Returns: // // Get Pad file size. // - FileLength = (*(UINT32 *)(PadFile->Size)) & 0x00FFFFFF; - FileLength = (FileLength + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1); + FileLength = GetFfsFileLength(PadFile); + FileLength = (FileLength + EFI_FFS_FILE_HEADER_ALIGNMENT - 1) & ~(EFI_FFS_FILE_HEADER_ALIGNMENT - 1); // // FixPoint must be align on 0x1000 relative to FvImage Header // - FixPoint = (UINT8*) PadFile + sizeof (EFI_FFS_FILE_HEADER); + FixPoint = (UINT8*) PadFile + GetFfsHeaderLength(PadFile); FixPoint = FixPoint + 0x1000 - (((UINTN) FixPoint - (UINTN) FvImage->FileImage) & 0xFFF); // // FixPoint be larger at the last place of one fv image. @@ -3402,15 +4026,15 @@ Returns: FixPoint += 0x1000; } FixPoint -= 0x1000; - - if ((UINTN) FixPoint < ((UINTN) PadFile + sizeof (EFI_FFS_FILE_HEADER))) { + + if ((UINTN) FixPoint < ((UINTN) PadFile + GetFfsHeaderLength(PadFile))) { // // No alignment FixPoint in this Pad File. // continue; } - if ((UINTN) FvImage->Eof - (UINTN)FixPoint <= 0x20000) { + if ((UINTN) FvImage->Eof - (UINTN)FixPoint <= 0x20000) { // // Find the position to place ApResetVector // @@ -3418,7 +4042,7 @@ Returns: return EFI_SUCCESS; } } - + return EFI_NOT_FOUND; } @@ -3445,7 +4069,7 @@ Returns: EFI_NOT_FOUND A required string was not found in the INF file. --*/ { - CHAR8 Value[_MAX_PATH]; + CHAR8 Value[MAX_LONG_FILE_PATH]; UINT64 Value64; UINTN Index, Number; EFI_STATUS Status; @@ -3497,7 +4121,7 @@ Returns: CapInfo->Flags |= CAPSULE_FLAGS_INITIATE_RESET; } } else if (strstr (Value, "PersistAcrossReset") != NULL) { - CapInfo->Flags |= CAPSULE_FLAGS_PERSIST_ACROSS_RESET; + CapInfo->Flags |= CAPSULE_FLAGS_PERSIST_ACROSS_RESET; if (strstr (Value, "InitiateReset") != NULL) { CapInfo->Flags |= CAPSULE_FLAGS_INITIATE_RESET; } @@ -3508,6 +4132,19 @@ Returns: DebugMsg (NULL, 0, 9, "Capsule Flag", Value); } + Status = FindToken (InfFile, OPTIONS_SECTION_STRING, EFI_OEM_CAPSULE_FLAGS_STRING, 0, Value); + if (Status == EFI_SUCCESS) { + Status = AsciiStringToUint64 (Value, FALSE, &Value64); + if (EFI_ERROR (Status) || Value64 > 0xffff) { + Error (NULL, 0, 2000, "Invalid parameter", + "invalid Flag setting for %s. Must be integer value between 0x0000 and 0xffff.", + EFI_OEM_CAPSULE_FLAGS_STRING); + return EFI_ABORTED; + } + CapInfo->Flags |= Value64; + DebugMsg (NULL, 0, 9, "Capsule Extend Flag", Value); + } + // // Read Capsule File name // @@ -3537,12 +4174,12 @@ Returns: // Add the file // strcpy (CapInfo->CapFiles[Index], Value); - DebugMsg (NULL, 0, 9, "Capsule component file", "the %uth file name is %s", (unsigned) Index, CapInfo->CapFiles[Index]); + DebugMsg (NULL, 0, 9, "Capsule component file", "the %uth file name is %s", (unsigned) Index, CapInfo->CapFiles[Index]); } else { break; } } - + if (Index == 0) { Warning (NULL, 0, 0, "Capsule components are not specified.", NULL); } @@ -3585,7 +4222,7 @@ Returns: UINT32 Index; FILE *fpin, *fpout; EFI_STATUS Status; - + if (InfFileImage != NULL) { // // Initialize file structures @@ -3593,7 +4230,7 @@ Returns: InfMemoryFile.FileImage = InfFileImage; InfMemoryFile.CurrentFilePointer = InfFileImage; InfMemoryFile.Eof = InfFileImage + InfFileSize; - + // // Parse the Cap inf file for header information // @@ -3602,7 +4239,7 @@ Returns: return Status; } } - + if (mCapDataInfo.HeaderSize == 0) { // // make header size align 16 bytes. @@ -3615,16 +4252,16 @@ Returns: Error (NULL, 0, 2000, "Invalid parameter", "The specified HeaderSize cannot be less than the size of EFI_CAPSULE_HEADER."); return EFI_INVALID_PARAMETER; } - + if (CapFileName == NULL && mCapDataInfo.CapName[0] != '\0') { CapFileName = mCapDataInfo.CapName; } - + if (CapFileName == NULL) { Error (NULL, 0, 2001, "Missing required argument", "Output Capsule file name"); return EFI_INVALID_PARAMETER; } - + // // Set Default Capsule Guid value // @@ -3638,7 +4275,7 @@ Returns: FileSize = 0; CapSize = mCapDataInfo.HeaderSize; while (mCapDataInfo.CapFiles [Index][0] != '\0') { - fpin = fopen (mCapDataInfo.CapFiles[Index], "rb"); + fpin = fopen (LongFilePath (mCapDataInfo.CapFiles[Index]), "rb"); if (fpin == NULL) { Error (NULL, 0, 0001, "Error opening file", mCapDataInfo.CapFiles[Index]); return EFI_ABORTED; @@ -3662,7 +4299,7 @@ Returns: // Initialize the capsule header to zero // memset (CapBuffer, 0, mCapDataInfo.HeaderSize); - + // // create capsule header and get capsule body // @@ -3676,7 +4313,7 @@ Returns: FileSize = 0; CapSize = CapsuleHeader->HeaderSize; while (mCapDataInfo.CapFiles [Index][0] != '\0') { - fpin = fopen (mCapDataInfo.CapFiles[Index], "rb"); + fpin = fopen (LongFilePath (mCapDataInfo.CapFiles[Index]), "rb"); if (fpin == NULL) { Error (NULL, 0, 0001, "Error opening file", mCapDataInfo.CapFiles[Index]); free (CapBuffer); @@ -3688,11 +4325,11 @@ Returns: Index ++; CapSize += FileSize; } - + // // write capsule data into the output file // - fpout = fopen (CapFileName, "wb"); + fpout = fopen (LongFilePath (CapFileName), "wb"); if (fpout == NULL) { Error (NULL, 0, 0001, "Error opening file", CapFileName); free (CapBuffer); @@ -3701,7 +4338,8 @@ Returns: fwrite (CapBuffer, 1, CapSize, fpout); fclose (fpout); - + free (CapBuffer); + VerboseMsg ("The size of the generated capsule image is %u bytes", (unsigned) CapSize); return EFI_SUCCESS;