#endif\r
#include <assert.h>\r
\r
+#include <Guid/FfsSectionAlignmentPadding.h>\r
+\r
#include "GenFvInternalLib.h"\r
#include "FvLib.h"\r
#include "PeCoffLib.h"\r
BOOLEAN mArm = FALSE;\r
STATIC UINT32 MaxFfsAlignment = 0;\r
\r
-EFI_GUID mEfiFirmwareVolumeTopFileGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;\r
+EFI_GUID mEfiFirmwareVolumeTopFileGuid = EFI_FFS_VOLUME_TOP_FILE_GUID;\r
EFI_GUID mFileGuidArray [MAX_NUMBER_OF_FILES_IN_FV];\r
-EFI_GUID mZeroGuid = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};\r
-EFI_GUID mDefaultCapsuleGuid = {0x3B6686BD, 0x0D76, 0x4030, { 0xB7, 0x0E, 0xB5, 0x51, 0x9E, 0x2F, 0xC5, 0xA0 }};\r
+EFI_GUID mZeroGuid = {0x0, 0x0, 0x0, {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}};\r
+EFI_GUID mDefaultCapsuleGuid = {0x3B6686BD, 0x0D76, 0x4030, { 0xB7, 0x0E, 0xB5, 0x51, 0x9E, 0x2F, 0xC5, 0xA0 }};\r
+EFI_GUID mEfiFfsSectionAlignmentPaddingGuid = EFI_FFS_SECTION_ALIGNMENT_PADDING_GUID;\r
\r
CHAR8 *mFvbAttributeName[] = {\r
EFI_FVB2_READ_DISABLED_CAP_STRING, \r
return EFI_SUCCESS;\r
}\r
\r
+STATIC\r
+BOOLEAN\r
+AdjustInternalFfsPadding (\r
+ IN OUT EFI_FFS_FILE_HEADER *FfsFile,\r
+ IN OUT MEMORY_FILE *FvImage,\r
+ IN UINTN Alignment,\r
+ IN OUT UINTN *FileSize\r
+ )\r
+/*++\r
+\r
+Routine Description:\r
+\r
+ This function looks for a dedicated alignment padding section in the FFS, and\r
+ shrinks it to the size required to line up subsequent sections correctly.\r
+\r
+Arguments:\r
+\r
+ FfsFile A pointer to Ffs file image.\r
+ FvImage The memory image of the FV to adjust it to.\r
+ Alignment Current file alignment\r
+ FileSize Reference to a variable holding the size of the FFS file\r
+\r
+Returns:\r
+\r
+ TRUE Padding section was found and updated successfully\r
+ FALSE Otherwise\r
+\r
+--*/\r
+{\r
+ EFI_FILE_SECTION_POINTER PadSection;\r
+ UINT8 *Remainder;\r
+ EFI_STATUS Status;\r
+ UINT32 FfsHeaderLength;\r
+ UINT32 FfsFileLength;\r
+ UINT32 PadSize;\r
+ UINTN Misalignment;\r
+ EFI_FFS_INTEGRITY_CHECK *IntegrityCheck;\r
+\r
+ //\r
+ // Figure out the misalignment: all FFS sections are aligned relative to the\r
+ // start of the FFS payload, so use that as the base of the misalignment\r
+ // computation.\r
+ //\r
+ FfsHeaderLength = GetFfsHeaderLength(FfsFile);\r
+ Misalignment = (UINTN) FvImage->CurrentFilePointer -\r
+ (UINTN) FvImage->FileImage + FfsHeaderLength;\r
+ Misalignment &= Alignment - 1;\r
+ if (Misalignment == 0) {\r
+ // Nothing to do, return success\r
+ return TRUE;\r
+ }\r
+\r
+ //\r
+ // We only apply this optimization to FFS files with the FIXED attribute set,\r
+ // since the FFS will not be loadable at arbitrary offsets anymore after\r
+ // we adjust the size of the padding section.\r
+ //\r
+ if ((FfsFile->Attributes & FFS_ATTRIB_FIXED) == 0) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Look for a dedicated padding section that we can adjust to compensate\r
+ // for the misalignment. If such a padding section exists, it precedes all\r
+ // sections with alignment requirements, and so the adjustment will correct\r
+ // all of them.\r
+ //\r
+ Status = GetSectionByType (FfsFile, EFI_SECTION_FREEFORM_SUBTYPE_GUID, 1,\r
+ &PadSection);\r
+ if (EFI_ERROR (Status) ||\r
+ CompareGuid (&PadSection.FreeformSubtypeSection->SubTypeGuid,\r
+ &mEfiFfsSectionAlignmentPaddingGuid) != 0) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Find out if the size of the padding section is sufficient to compensate\r
+ // for the misalignment.\r
+ //\r
+ PadSize = GetSectionFileLength (PadSection.CommonHeader);\r
+ if (Misalignment > PadSize - sizeof (EFI_FREEFORM_SUBTYPE_GUID_SECTION)) {\r
+ return FALSE;\r
+ }\r
+\r
+ //\r
+ // Move the remainder of the FFS file towards the front, and adjust the\r
+ // file size output parameter.\r
+ //\r
+ Remainder = (UINT8 *) PadSection.CommonHeader + PadSize;\r
+ memmove (Remainder - Misalignment, Remainder,\r
+ *FileSize - (UINTN) (Remainder - (UINTN) FfsFile));\r
+ *FileSize -= Misalignment;\r
+\r
+ //\r
+ // Update the padding section's length with the new values. Note that the\r
+ // padding is always < 64 KB, so we can ignore EFI_COMMON_SECTION_HEADER2\r
+ // ExtendedSize.\r
+ //\r
+ PadSize -= Misalignment;\r
+ PadSection.CommonHeader->Size[0] = (UINT8) (PadSize & 0xff);\r
+ PadSection.CommonHeader->Size[1] = (UINT8) ((PadSize & 0xff00) >> 8);\r
+ PadSection.CommonHeader->Size[2] = (UINT8) ((PadSize & 0xff0000) >> 16);\r
+\r
+ //\r
+ // Update the FFS header with the new overall length\r
+ //\r
+ FfsFileLength = GetFfsFileLength (FfsFile) - Misalignment;\r
+ if (FfsHeaderLength > sizeof(EFI_FFS_FILE_HEADER)) {\r
+ ((EFI_FFS_FILE_HEADER2 *)FfsFile)->ExtendedSize = FfsFileLength;\r
+ } else {\r
+ FfsFile->Size[0] = (UINT8) (FfsFileLength & 0x000000FF);\r
+ FfsFile->Size[1] = (UINT8) ((FfsFileLength & 0x0000FF00) >> 8);\r
+ FfsFile->Size[2] = (UINT8) ((FfsFileLength & 0x00FF0000) >> 16);\r
+ }\r
+\r
+ //\r
+ // Clear the alignment bits: these have become meaningless now that we have\r
+ // adjusted the padding section.\r
+ //\r
+ FfsFile->Attributes &= ~FFS_ATTRIB_DATA_ALIGNMENT;\r
+\r
+ //\r
+ // Recalculate the FFS header checksum. Instead of setting Header and State\r
+ // both to zero, set Header to (UINT8)(-State) so State preserves its original\r
+ // value\r
+ //\r
+ IntegrityCheck = &FfsFile->IntegrityCheck;\r
+ IntegrityCheck->Checksum.Header = (UINT8) (0x100 - FfsFile->State);\r
+ IntegrityCheck->Checksum.File = 0;\r
+\r
+ IntegrityCheck->Checksum.Header = CalculateChecksum8 (\r
+ (UINT8 *) FfsFile, FfsHeaderLength);\r
+\r
+ if (FfsFile->Attributes & FFS_ATTRIB_CHECKSUM) {\r
+ //\r
+ // Ffs header checksum = zero, so only need to calculate ffs body.\r
+ //\r
+ IntegrityCheck->Checksum.File = CalculateChecksum8 (\r
+ (UINT8 *) FfsFile + FfsHeaderLength,\r
+ FfsFileLength - FfsHeaderLength);\r
+ } else {\r
+ IntegrityCheck->Checksum.File = FFS_FIXED_CHECKSUM;\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
EFI_STATUS\r
AddFile (\r
IN OUT MEMORY_FILE *FvImage,\r
//\r
// Add pad file if necessary\r
//\r
- Status = AddPadFile (FvImage, 1 << CurrentFileAlignment, *VtfFileImage, NULL, FileSize);\r
- if (EFI_ERROR (Status)) {\r
- Error (NULL, 0, 4002, "Resource", "FV space is full, could not add pad file for data alignment property.");\r
- free (FileBuffer);\r
- return EFI_ABORTED;\r
+ if (!AdjustInternalFfsPadding ((EFI_FFS_FILE_HEADER *) FileBuffer, FvImage,\r
+ 1 << CurrentFileAlignment, &FileSize)) {\r
+ Status = AddPadFile (FvImage, 1 << CurrentFileAlignment, *VtfFileImage, NULL, FileSize);\r
+ if (EFI_ERROR (Status)) {\r
+ Error (NULL, 0, 4002, "Resource", "FV space is full, could not add pad file for data alignment property.");\r
+ free (FileBuffer);\r
+ return EFI_ABORTED;\r
+ }\r
}\r
//\r
// Add file\r