summaryrefslogtreecommitdiffstats
path: root/BaseTools/Source/Python/FMMT/core/FvHandler.py
diff options
context:
space:
mode:
Diffstat (limited to 'BaseTools/Source/Python/FMMT/core/FvHandler.py')
-rw-r--r--BaseTools/Source/Python/FMMT/core/FvHandler.py641
1 files changed, 641 insertions, 0 deletions
diff --git a/BaseTools/Source/Python/FMMT/core/FvHandler.py b/BaseTools/Source/Python/FMMT/core/FvHandler.py
new file mode 100644
index 0000000000..c81541ec18
--- /dev/null
+++ b/BaseTools/Source/Python/FMMT/core/FvHandler.py
@@ -0,0 +1,641 @@
+## @file
+# This file is used to the implementation of Bios layout handler.
+#
+# Copyright (c) 2021-, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+import os
+from core.BiosTree import *
+from core.GuidTools import GUIDTools
+from core.BiosTreeNode import *
+from FirmwareStorageFormat.Common import *
+from utils.FmmtLogger import FmmtLogger as logger
+
+EFI_FVB2_ERASE_POLARITY = 0x00000800
+
+def ChangeSize(TargetTree, size_delta: int=0) -> None:
+ # If Size increase delta, then should be: size_delta = -delta
+ if type(TargetTree.Data.Header) == type(EFI_FFS_FILE_HEADER2()) or type(TargetTree.Data.Header) == type(EFI_COMMON_SECTION_HEADER2()):
+ TargetTree.Data.Size -= size_delta
+ TargetTree.Data.Header.ExtendedSize -= size_delta
+ elif TargetTree.type == SECTION_TREE and TargetTree.Data.OriData:
+ OriSize = TargetTree.Data.Header.SECTION_SIZE
+ OriSize -= size_delta
+ TargetTree.Data.Header.Size[0] = OriSize % (16**2)
+ TargetTree.Data.Header.Size[1] = OriSize % (16**4) //(16**2)
+ TargetTree.Data.Header.Size[2] = OriSize // (16**4)
+ else:
+ TargetTree.Data.Size -= size_delta
+ TargetTree.Data.Header.Size[0] = TargetTree.Data.Size % (16**2)
+ TargetTree.Data.Header.Size[1] = TargetTree.Data.Size % (16**4) //(16**2)
+ TargetTree.Data.Header.Size[2] = TargetTree.Data.Size // (16**4)
+
+def ModifyFfsType(TargetFfs) -> None:
+ if type(TargetFfs.Data.Header) == type(EFI_FFS_FILE_HEADER()) and TargetFfs.Data.Size > 0xFFFFFF:
+ ExtendSize = TargetFfs.Data.Header.FFS_FILE_SIZE + 8
+ New_Header = EFI_FFS_FILE_HEADER2()
+ New_Header.Name = TargetFfs.Data.Header.Name
+ New_Header.IntegrityCheck = TargetFfs.Data.Header.IntegrityCheck
+ New_Header.Type = TargetFfs.Data.Header.Type
+ New_Header.Attributes = TargetFfs.Data.Header.Attributes | 0x01 # set the Attribute with FFS_ATTRIB_LARGE_FILE (0x01)
+ NewSize = 0
+ New_Header.Size[0] = NewSize % (16**2) # minus the delta size of Header
+ New_Header.Size[1] = NewSize % (16**4) //(16**2)
+ New_Header.Size[2] = NewSize // (16**4)
+ New_Header.State = TargetFfs.Data.Header.State
+ New_Header.ExtendedSize = ExtendSize
+ TargetFfs.Data.Header = New_Header
+ TargetFfs.Data.Size = TargetFfs.Data.Header.FFS_FILE_SIZE
+ TargetFfs.Data.HeaderLength = TargetFfs.Data.Header.HeaderLength
+ TargetFfs.Data.ModCheckSum()
+ elif type(TargetFfs.Data.Header) == type(EFI_FFS_FILE_HEADER2()) and TargetFfs.Data.Size <= 0xFFFFFF:
+ New_Header = EFI_FFS_FILE_HEADER()
+ New_Header.Name = TargetFfs.Data.Header.Name
+ New_Header.IntegrityCheck = TargetFfs.Data.Header.IntegrityCheck
+ New_Header.Type = TargetFfs.Data.Header.Type
+ New_Header.Attributes = TargetFfs.Data.Header.Attributes - 1 # remove the FFS_ATTRIB_LARGE_FILE (0x01) from Attribute
+ New_Header.Size[0] = (TargetFfs.Data.Size - 8) % (16**2) # minus the delta size of Header
+ New_Header.Size[1] = (TargetFfs.Data.Size - 8) % (16**4) //(16**2)
+ New_Header.Size[2] = (TargetFfs.Data.Size - 8) // (16**4)
+ New_Header.State = TargetFfs.Data.Header.State
+ TargetFfs.Data.Header = New_Header
+ TargetFfs.Data.Size = TargetFfs.Data.Header.FFS_FILE_SIZE
+ TargetFfs.Data.HeaderLength = TargetFfs.Data.Header.HeaderLength
+ TargetFfs.Data.ModCheckSum()
+ if struct2stream(TargetFfs.Parent.Data.Header.FileSystemGuid) == EFI_FIRMWARE_FILE_SYSTEM3_GUID_BYTE:
+ NeedChange = True
+ for item in TargetFfs.Parent.Child:
+ if type(item.Data.Header) == type(EFI_FFS_FILE_HEADER2()):
+ NeedChange = False
+ if NeedChange:
+ TargetFfs.Parent.Data.Header.FileSystemGuid = ModifyGuidFormat("8c8ce578-8a3d-4f1c-9935-896185c32dd3")
+
+ if type(TargetFfs.Data.Header) == type(EFI_FFS_FILE_HEADER2()):
+ TarParent = TargetFfs.Parent
+ while TarParent:
+ if TarParent.type == FV_TREE and struct2stream(TarParent.Data.Header.FileSystemGuid) == EFI_FIRMWARE_FILE_SYSTEM2_GUID_BYTE:
+ TarParent.Data.Header.FileSystemGuid = ModifyGuidFormat("5473C07A-3DCB-4dca-BD6F-1E9689E7349A")
+ TarParent = TarParent.Parent
+
+def PadSectionModify(PadSection, Offset) -> None:
+ # Offset > 0, Size decrease; Offset < 0, Size increase;
+ ChangeSize(PadSection, Offset)
+ PadSection.Data.Data = (PadSection.Data.Size - PadSection.Data.HeaderLength) * b'\xff'
+
+def ModifySectionType(TargetSection) -> None:
+ # If Section Size is increased larger than 0xFFFFFF, need modify Section Header from EFI_COMMON_SECTION_HEADER to EFI_COMMON_SECTION_HEADER2.
+ if type(TargetSection.Data.Header) == type(EFI_COMMON_SECTION_HEADER()) and TargetSection.Data.Size >= 0xFFFFFF:
+ New_Header = EFI_COMMON_SECTION_HEADER2()
+ New_Header.Type = TargetSection.Data.Header.Type
+ NewSize = 0xFFFFFF
+ New_Header.Size[0] = NewSize % (16**2) # minus the delta size of Header
+ New_Header.Size[1] = NewSize % (16**4) //(16**2)
+ New_Header.Size[2] = NewSize // (16**4)
+ New_Header.ExtendedSize = TargetSection.Data.Size + 4
+ TargetSection.Data.Header = New_Header
+ TargetSection.Data.Size = TargetSection.Data.Header.SECTION_SIZE
+ # Align the Header's added 4 bit to 8-alignment to promise the following Ffs's align correctly.
+ if TargetSection.LastRel.Data.IsPadSection:
+ PadSectionModify(TargetSection.LastRel, -4)
+ else:
+ SecParent = TargetSection.Parent
+ Target_index = SecParent.Child.index(TargetSection)
+ NewPadSection = SectionNode(b'\x00\x00\x00\x19')
+ SecParent.insertChild(NewPadSection, Target_index)
+ # If Section Size is decreased smaller than 0xFFFFFF, need modify Section Header from EFI_COMMON_SECTION_HEADER2 to EFI_COMMON_SECTION_HEADER.
+ elif type(TargetSection.Data.Header) == type(EFI_COMMON_SECTION_HEADER2()) and TargetSection.Data.Size < 0xFFFFFF:
+ New_Header = EFI_COMMON_SECTION_HEADER()
+ New_Header.Type = TargetSection.Data.Header.Type
+ New_Header.Size[0] = (TargetSection.Data.Size - 4) % (16**2) # minus the delta size of Header
+ New_Header.Size[1] = (TargetSection.Data.Size - 4) % (16**4) //(16**2)
+ New_Header.Size[2] = (TargetSection.Data.Size - 4) // (16**4)
+ TargetSection.Data.Header = New_Header
+ TargetSection.Data.Size = TargetSection.Data.Header.SECTION_SIZE
+ # Align the Header's added 4 bit to 8-alignment to promise the following Ffs's align correctly.
+ if TargetSection.LastRel.Data.IsPadSection:
+ PadSectionModify(TargetSection.LastRel, -4)
+ else:
+ SecParent = TargetSection.Parent
+ Target_index = SecParent.Child.index(TargetSection)
+ NewPadSection = SectionNode(b'\x00\x00\x00\x19')
+ SecParent.insertChild(NewPadSection, Target_index)
+
+def ModifyFvExtData(TreeNode) -> None:
+ FvExtData = b''
+ if TreeNode.Data.Header.ExtHeaderOffset:
+ FvExtHeader = struct2stream(TreeNode.Data.ExtHeader)
+ FvExtData += FvExtHeader
+ if TreeNode.Data.Header.ExtHeaderOffset and TreeNode.Data.ExtEntryExist:
+ FvExtEntry = struct2stream(TreeNode.Data.ExtEntry)
+ FvExtData += FvExtEntry
+ if FvExtData:
+ InfoNode = TreeNode.Child[0]
+ InfoNode.Data.Data = FvExtData + InfoNode.Data.Data[TreeNode.Data.ExtHeader.ExtHeaderSize:]
+ InfoNode.Data.ModCheckSum()
+
+def ModifyFvSystemGuid(TargetFv) -> None:
+ if struct2stream(TargetFv.Data.Header.FileSystemGuid) == EFI_FIRMWARE_FILE_SYSTEM2_GUID_BYTE:
+ TargetFv.Data.Header.FileSystemGuid = ModifyGuidFormat("5473C07A-3DCB-4dca-BD6F-1E9689E7349A")
+ TargetFv.Data.ModCheckSum()
+ TargetFv.Data.Data = b''
+ for item in TargetFv.Child:
+ if item.type == FFS_FREE_SPACE:
+ TargetFv.Data.Data += item.Data.Data + item.Data.PadData
+ else:
+ TargetFv.Data.Data += struct2stream(item.Data.Header)+ item.Data.Data + item.Data.PadData
+
+class FvHandler:
+ def __init__(self, NewFfs, TargetFfs) -> None:
+ self.NewFfs = NewFfs
+ self.TargetFfs = TargetFfs
+ self.Status = False
+ self.Remain_New_Free_Space = 0
+
+ ## Use for Compress the Section Data
+ def CompressData(self, TargetTree) -> None:
+ TreePath = TargetTree.GetTreePath()
+ pos = len(TreePath)
+ self.Status = False
+ while pos:
+ if not self.Status:
+ if TreePath[pos-1].type == SECTION_TREE and TreePath[pos-1].Data.Type == 0x02:
+ self.CompressSectionData(TreePath[pos-1], None, TreePath[pos-1].Data.ExtHeader.SectionDefinitionGuid)
+ else:
+ if pos == len(TreePath):
+ self.CompressSectionData(TreePath[pos-1], pos)
+ else:
+ self.CompressSectionData(TreePath[pos-1], None)
+ pos -= 1
+
+ def CompressSectionData(self, TargetTree, pos: int, GuidTool=None) -> None:
+ NewData = b''
+ temp_save_child = TargetTree.Child
+ if TargetTree.Data:
+ # Update current node data as adding all the header and data of its child node.
+ for item in temp_save_child:
+ if item.type == SECTION_TREE and not item.Data.OriData and item.Data.ExtHeader:
+ NewData += struct2stream(item.Data.Header) + struct2stream(item.Data.ExtHeader) + item.Data.Data + item.Data.PadData
+ elif item.type == SECTION_TREE and item.Data.OriData and not item.Data.ExtHeader:
+ NewData += struct2stream(item.Data.Header) + item.Data.OriData + item.Data.PadData
+ elif item.type == SECTION_TREE and item.Data.OriData and item.Data.ExtHeader:
+ NewData += struct2stream(item.Data.Header) + struct2stream(item.Data.ExtHeader) + item.Data.OriData + item.Data.PadData
+ elif item.type == FFS_FREE_SPACE:
+ NewData += item.Data.Data + item.Data.PadData
+ else:
+ NewData += struct2stream(item.Data.Header) + item.Data.Data + item.Data.PadData
+ # If node is FFS_TREE, update Pad data and Header info.
+ # Remain_New_Free_Space is used for move more free space into lst level Fv.
+ if TargetTree.type == FFS_TREE:
+ New_Pad_Size = GetPadSize(len(NewData), 8)
+ Size_delta = len(NewData) - len(TargetTree.Data.Data)
+ ChangeSize(TargetTree, -Size_delta)
+ Delta_Pad_Size = len(TargetTree.Data.PadData) - New_Pad_Size
+ self.Remain_New_Free_Space += Delta_Pad_Size
+ TargetTree.Data.PadData = b'\xff' * New_Pad_Size
+ TargetTree.Data.ModCheckSum()
+ # If node is FV_TREE, update Pad data and Header info.
+ # Consume Remain_New_Free_Space is used for move more free space into lst level Fv.
+ elif TargetTree.type == FV_TREE or TargetTree.type == SEC_FV_TREE and not pos:
+ if self.Remain_New_Free_Space:
+ if TargetTree.Data.Free_Space:
+ TargetTree.Data.Free_Space += self.Remain_New_Free_Space
+ NewData += self.Remain_New_Free_Space * b'\xff'
+ TargetTree.Child[-1].Data.Data += self.Remain_New_Free_Space * b'\xff'
+ else:
+ TargetTree.Data.Data += self.Remain_New_Free_Space * b'\xff'
+ New_Free_Space = BIOSTREE('FREE_SPACE')
+ New_Free_Space.type = FFS_FREE_SPACE
+ New_Free_Space.Data = FreeSpaceNode(b'\xff' * self.Remain_New_Free_Space)
+ TargetTree.insertChild(New_Free_Space)
+ self.Remain_New_Free_Space = 0
+ if TargetTree.type == SEC_FV_TREE:
+ Size_delta = len(NewData) + self.Remain_New_Free_Space - len(TargetTree.Data.Data)
+ TargetTree.Data.Header.FvLength += Size_delta
+ TargetTree.Data.ModFvExt()
+ TargetTree.Data.ModFvSize()
+ TargetTree.Data.ModExtHeaderData()
+ ModifyFvExtData(TargetTree)
+ TargetTree.Data.ModCheckSum()
+ # If node is SECTION_TREE and not guided section, update Pad data and Header info.
+ # Remain_New_Free_Space is used for move more free space into lst level Fv.
+ elif TargetTree.type == SECTION_TREE and TargetTree.Data.Type != 0x02:
+ New_Pad_Size = GetPadSize(len(NewData), 4)
+ Size_delta = len(NewData) - len(TargetTree.Data.Data)
+ ChangeSize(TargetTree, -Size_delta)
+ if TargetTree.NextRel:
+ Delta_Pad_Size = len(TargetTree.Data.PadData) - New_Pad_Size
+ self.Remain_New_Free_Space += Delta_Pad_Size
+ TargetTree.Data.PadData = b'\x00' * New_Pad_Size
+ TargetTree.Data.Data = NewData
+ if GuidTool:
+ guidtool = GUIDTools().__getitem__(struct2stream(GuidTool))
+ if not guidtool.ifexist:
+ logger.error("GuidTool {} is not found when decompressing {} file.\n".format(guidtool.command, TargetTree.Parent.Data.Name))
+ raise Exception("Process Failed: GuidTool not found!")
+ CompressedData = guidtool.pack(TargetTree.Data.Data)
+ if len(CompressedData) < len(TargetTree.Data.OriData):
+ New_Pad_Size = GetPadSize(len(CompressedData), SECTION_COMMON_ALIGNMENT)
+ Size_delta = len(CompressedData) - len(TargetTree.Data.OriData)
+ ChangeSize(TargetTree, -Size_delta)
+ if TargetTree.NextRel:
+ TargetTree.Data.PadData = b'\x00' * New_Pad_Size
+ self.Remain_New_Free_Space = len(TargetTree.Data.OriData) + len(TargetTree.Data.PadData) - len(CompressedData) - New_Pad_Size
+ else:
+ TargetTree.Data.PadData = b''
+ self.Remain_New_Free_Space = len(TargetTree.Data.OriData) - len(CompressedData)
+ TargetTree.Data.OriData = CompressedData
+ elif len(CompressedData) == len(TargetTree.Data.OriData):
+ TargetTree.Data.OriData = CompressedData
+ elif len(CompressedData) > len(TargetTree.Data.OriData):
+ New_Pad_Size = GetPadSize(len(CompressedData), SECTION_COMMON_ALIGNMENT)
+ self.Remain_New_Free_Space = len(CompressedData) + New_Pad_Size - len(TargetTree.Data.OriData) - len(TargetTree.Data.PadData)
+ self.ModifyTest(TargetTree, self.Remain_New_Free_Space)
+ self.Status = True
+
+ def ModifyTest(self, ParTree, Needed_Space: int) -> None:
+ # If have needed space, will find if there have free space in parent tree, meanwhile update the node data.
+ if Needed_Space > 0:
+ # If current node is a Fv node
+ if ParTree.type == FV_TREE or ParTree.type == SEC_FV_TREE:
+ ParTree.Data.Data = b''
+ # First check if Fv free space is enough for needed space.
+ # If so, use the current Fv free space;
+ # Else, use all the Free space, and recalculate needed space, continue finding in its parent node.
+ Needed_Space = Needed_Space - ParTree.Data.Free_Space
+ if Needed_Space < 0:
+ ParTree.Child[-1].Data.Data = b'\xff' * (-Needed_Space)
+ ParTree.Data.Free_Space = (-Needed_Space)
+ self.Status = True
+ else:
+ if ParTree.type == FV_TREE:
+ self.Status = False
+ else:
+ BlockSize = ParTree.Data.Header.BlockMap[0].Length
+ New_Add_Len = BlockSize - Needed_Space%BlockSize
+ if New_Add_Len % BlockSize:
+ ParTree.Child[-1].Data.Data = b'\xff' * New_Add_Len
+ ParTree.Data.Free_Space = New_Add_Len
+ Needed_Space += New_Add_Len
+ else:
+ ParTree.Child.remove(ParTree.Child[-1])
+ ParTree.Data.Free_Space = 0
+ ParTree.Data.Size += Needed_Space
+ ParTree.Data.Header.Fvlength = ParTree.Data.Size
+ ModifyFvSystemGuid(ParTree)
+ for item in ParTree.Child:
+ if item.type == FFS_FREE_SPACE:
+ ParTree.Data.Data += item.Data.Data + item.Data.PadData
+ else:
+ ParTree.Data.Data += struct2stream(item.Data.Header)+ item.Data.Data + item.Data.PadData
+ ParTree.Data.ModFvExt()
+ ParTree.Data.ModFvSize()
+ ParTree.Data.ModExtHeaderData()
+ ModifyFvExtData(ParTree)
+ ParTree.Data.ModCheckSum()
+ # If current node is a Ffs node
+ elif ParTree.type == FFS_TREE:
+ ParTree.Data.Data = b''
+ OriHeaderLen = ParTree.Data.HeaderLength
+ # Update its data as adding all the header and data of its child node.
+ for item in ParTree.Child:
+ if item.Data.OriData:
+ if item.Data.ExtHeader:
+ ParTree.Data.Data += struct2stream(item.Data.Header) + struct2stream(item.Data.ExtHeader) + item.Data.OriData + item.Data.PadData
+ else:
+ ParTree.Data.Data += struct2stream(item.Data.Header)+ item.Data.OriData + item.Data.PadData
+ else:
+ if item.Data.ExtHeader:
+ ParTree.Data.Data += struct2stream(item.Data.Header) + struct2stream(item.Data.ExtHeader) + item.Data.Data + item.Data.PadData
+ else:
+ ParTree.Data.Data += struct2stream(item.Data.Header)+ item.Data.Data + item.Data.PadData
+ ChangeSize(ParTree, -Needed_Space)
+ ModifyFfsType(ParTree)
+ # Recalculate pad data, update needed space with Delta_Pad_Size.
+ Needed_Space += ParTree.Data.HeaderLength - OriHeaderLen
+ New_Pad_Size = GetPadSize(ParTree.Data.Size, FFS_COMMON_ALIGNMENT)
+ Delta_Pad_Size = New_Pad_Size - len(ParTree.Data.PadData)
+ Needed_Space += Delta_Pad_Size
+ ParTree.Data.PadData = b'\xff' * GetPadSize(ParTree.Data.Size, FFS_COMMON_ALIGNMENT)
+ ParTree.Data.ModCheckSum()
+ # If current node is a Section node
+ elif ParTree.type == SECTION_TREE:
+ OriData = ParTree.Data.Data
+ OriHeaderLen = ParTree.Data.HeaderLength
+ ParTree.Data.Data = b''
+ # Update its data as adding all the header and data of its child node.
+ for item in ParTree.Child:
+ if item.type == SECTION_TREE and item.Data.ExtHeader and item.Data.Type != 0x02:
+ ParTree.Data.Data += struct2stream(item.Data.Header) + struct2stream(item.Data.ExtHeader) + item.Data.Data + item.Data.PadData
+ elif item.type == SECTION_TREE and item.Data.ExtHeader and item.Data.Type == 0x02:
+ ParTree.Data.Data += struct2stream(item.Data.Header) + struct2stream(item.Data.ExtHeader) + item.Data.OriData + item.Data.PadData
+ else:
+ ParTree.Data.Data += struct2stream(item.Data.Header) + item.Data.Data + item.Data.PadData
+ # If the current section is guided section
+ if ParTree.Data.Type == 0x02:
+ guidtool = GUIDTools().__getitem__(struct2stream(ParTree.Data.ExtHeader.SectionDefinitionGuid))
+ if not guidtool.ifexist:
+ logger.error("GuidTool {} is not found when decompressing {} file.\n".format(guidtool.command, ParTree.Parent.Data.Name))
+ raise Exception("Process Failed: GuidTool not found!")
+ # Recompress current data, and recalculate the needed space
+ CompressedData = guidtool.pack(ParTree.Data.Data)
+ Needed_Space = len(CompressedData) - len(ParTree.Data.OriData)
+ ParTree.Data.OriData = CompressedData
+ New_Size = ParTree.Data.HeaderLength + len(CompressedData)
+ ParTree.Data.Header.Size[0] = New_Size % (16**2)
+ ParTree.Data.Header.Size[1] = New_Size % (16**4) //(16**2)
+ ParTree.Data.Header.Size[2] = New_Size // (16**4)
+ ParTree.Data.Size = ParTree.Data.Header.SECTION_SIZE
+ ModifySectionType(ParTree)
+ Needed_Space += ParTree.Data.HeaderLength - OriHeaderLen
+ # Update needed space with Delta_Pad_Size
+ if ParTree.NextRel:
+ New_Pad_Size = GetPadSize(ParTree.Data.Size, SECTION_COMMON_ALIGNMENT)
+ Delta_Pad_Size = New_Pad_Size - len(ParTree.Data.PadData)
+ ParTree.Data.PadData = b'\x00' * New_Pad_Size
+ Needed_Space += Delta_Pad_Size
+ else:
+ ParTree.Data.PadData = b''
+ if Needed_Space < 0:
+ self.Remain_New_Free_Space = len(ParTree.Data.OriData) - len(CompressedData)
+ # If current section is not guided section
+ elif Needed_Space:
+ ChangeSize(ParTree, -Needed_Space)
+ ModifySectionType(ParTree)
+ # Update needed space with Delta_Pad_Size
+ Needed_Space += ParTree.Data.HeaderLength - OriHeaderLen
+ New_Pad_Size = GetPadSize(ParTree.Data.Size, SECTION_COMMON_ALIGNMENT)
+ Delta_Pad_Size = New_Pad_Size - len(ParTree.Data.PadData)
+ Needed_Space += Delta_Pad_Size
+ ParTree.Data.PadData = b'\x00' * New_Pad_Size
+ NewParTree = ParTree.Parent
+ ROOT_TYPE = [ROOT_FV_TREE, ROOT_FFS_TREE, ROOT_SECTION_TREE, ROOT_TREE]
+ if NewParTree and NewParTree.type not in ROOT_TYPE:
+ self.ModifyTest(NewParTree, Needed_Space)
+ # If current node have enough space, will recompress all the related node data, return true.
+ else:
+ self.CompressData(ParTree)
+ self.Status = True
+
+ def ReplaceFfs(self) -> bool:
+ logger.debug('Start Replacing Process......')
+ TargetFv = self.TargetFfs.Parent
+ # If the Fv Header Attributes is EFI_FVB2_ERASE_POLARITY, Child Ffs Header State need be reversed.
+ if TargetFv.Data.Header.Attributes & EFI_FVB2_ERASE_POLARITY:
+ self.NewFfs.Data.Header.State = c_uint8(
+ ~self.NewFfs.Data.Header.State)
+ # NewFfs parsing will not calculate the PadSize, thus recalculate.
+ self.NewFfs.Data.PadData = b'\xff' * GetPadSize(self.NewFfs.Data.Size, FFS_COMMON_ALIGNMENT)
+ if self.NewFfs.Data.Size >= self.TargetFfs.Data.Size:
+ Needed_Space = self.NewFfs.Data.Size + len(self.NewFfs.Data.PadData) - self.TargetFfs.Data.Size - len(self.TargetFfs.Data.PadData)
+ # If TargetFv have enough free space, just move part of the free space to NewFfs.
+ if TargetFv.Data.Free_Space >= Needed_Space:
+ # Modify TargetFv Child info and BiosTree.
+ TargetFv.Child[-1].Data.Data = b'\xff' * (TargetFv.Data.Free_Space - Needed_Space)
+ TargetFv.Data.Free_Space -= Needed_Space
+ Target_index = TargetFv.Child.index(self.TargetFfs)
+ TargetFv.Child.remove(self.TargetFfs)
+ TargetFv.insertChild(self.NewFfs, Target_index)
+ # Modify TargetFv Header and ExtHeader info.
+ TargetFv.Data.ModFvExt()
+ TargetFv.Data.ModFvSize()
+ TargetFv.Data.ModExtHeaderData()
+ ModifyFvExtData(TargetFv)
+ TargetFv.Data.ModCheckSum()
+ # Recompress from the Fv node to update all the related node data.
+ self.CompressData(TargetFv)
+ # return the Status
+ self.Status = True
+ # If TargetFv do not have enough free space, need move part of the free space of TargetFv's parent Fv to TargetFv/NewFfs.
+ else:
+ if TargetFv.type == FV_TREE:
+ self.Status = False
+ else:
+ # Recalculate TargetFv needed space to keep it match the BlockSize setting.
+ Needed_Space -= TargetFv.Data.Free_Space
+ BlockSize = TargetFv.Data.Header.BlockMap[0].Length
+ New_Add_Len = BlockSize - Needed_Space%BlockSize
+ Target_index = TargetFv.Child.index(self.TargetFfs)
+ if New_Add_Len % BlockSize:
+ TargetFv.Child[-1].Data.Data = b'\xff' * New_Add_Len
+ TargetFv.Data.Free_Space = New_Add_Len
+ Needed_Space += New_Add_Len
+ TargetFv.insertChild(self.NewFfs, Target_index)
+ TargetFv.Child.remove(self.TargetFfs)
+ else:
+ TargetFv.Child.remove(self.TargetFfs)
+ TargetFv.Data.Free_Space = 0
+ TargetFv.insertChild(self.NewFfs)
+ # Encapsulate the Fv Data for update.
+ TargetFv.Data.Data = b''
+ for item in TargetFv.Child:
+ if item.type == FFS_FREE_SPACE:
+ TargetFv.Data.Data += item.Data.Data + item.Data.PadData
+ else:
+ TargetFv.Data.Data += struct2stream(item.Data.Header)+ item.Data.Data + item.Data.PadData
+ TargetFv.Data.Size += Needed_Space
+ # Modify TargetFv Data Header and ExtHeader info.
+ TargetFv.Data.Header.FvLength = TargetFv.Data.Size
+ TargetFv.Data.ModFvExt()
+ TargetFv.Data.ModFvSize()
+ TargetFv.Data.ModExtHeaderData()
+ ModifyFvExtData(TargetFv)
+ TargetFv.Data.ModCheckSum()
+ # Start free space calculating and moving process.
+ self.ModifyTest(TargetFv.Parent, Needed_Space)
+ else:
+ New_Free_Space = self.TargetFfs.Data.Size - self.NewFfs.Data.Size
+ # If TargetFv already have free space, move the new free space into it.
+ if TargetFv.Data.Free_Space:
+ TargetFv.Child[-1].Data.Data += b'\xff' * New_Free_Space
+ TargetFv.Data.Free_Space += New_Free_Space
+ Target_index = TargetFv.Child.index(self.TargetFfs)
+ TargetFv.Child.remove(self.TargetFfs)
+ TargetFv.insertChild(self.NewFfs, Target_index)
+ self.Status = True
+ # If TargetFv do not have free space, create free space for Fv.
+ else:
+ New_Free_Space_Tree = BIOSTREE('FREE_SPACE')
+ New_Free_Space_Tree.type = FFS_FREE_SPACE
+ New_Free_Space_Tree.Data = FfsNode(b'\xff' * New_Free_Space)
+ TargetFv.Data.Free_Space = New_Free_Space
+ TargetFv.insertChild(New_Free_Space)
+ Target_index = TargetFv.Child.index(self.TargetFfs)
+ TargetFv.Child.remove(self.TargetFfs)
+ TargetFv.insertChild(self.NewFfs, Target_index)
+ self.Status = True
+ # Modify TargetFv Header and ExtHeader info.
+ TargetFv.Data.ModFvExt()
+ TargetFv.Data.ModFvSize()
+ TargetFv.Data.ModExtHeaderData()
+ ModifyFvExtData(TargetFv)
+ TargetFv.Data.ModCheckSum()
+ # Recompress from the Fv node to update all the related node data.
+ self.CompressData(TargetFv)
+ logger.debug('Done!')
+ return self.Status
+
+ def AddFfs(self) -> bool:
+ logger.debug('Start Adding Process......')
+ # NewFfs parsing will not calculate the PadSize, thus recalculate.
+ self.NewFfs.Data.PadData = b'\xff' * GetPadSize(self.NewFfs.Data.Size, FFS_COMMON_ALIGNMENT)
+ if self.TargetFfs.type == FFS_FREE_SPACE:
+ TargetLen = self.NewFfs.Data.Size + len(self.NewFfs.Data.PadData) - self.TargetFfs.Data.Size - len(self.TargetFfs.Data.PadData)
+ TargetFv = self.TargetFfs.Parent
+ # If the Fv Header Attributes is EFI_FVB2_ERASE_POLARITY, Child Ffs Header State need be reversed.
+ if TargetFv.Data.Header.Attributes & EFI_FVB2_ERASE_POLARITY:
+ self.NewFfs.Data.Header.State = c_uint8(
+ ~self.NewFfs.Data.Header.State)
+ # If TargetFv have enough free space, just move part of the free space to NewFfs, split free space to NewFfs and new free space.
+ if TargetLen < 0:
+ self.Status = True
+ self.TargetFfs.Data.Data = b'\xff' * (-TargetLen)
+ TargetFv.Data.Free_Space = (-TargetLen)
+ TargetFv.Data.ModFvExt()
+ TargetFv.Data.ModExtHeaderData()
+ ModifyFvExtData(TargetFv)
+ TargetFv.Data.ModCheckSum()
+ TargetFv.insertChild(self.NewFfs, -1)
+ ModifyFfsType(self.NewFfs)
+ # Recompress from the Fv node to update all the related node data.
+ self.CompressData(TargetFv)
+ elif TargetLen == 0:
+ self.Status = True
+ TargetFv.Child.remove(self.TargetFfs)
+ TargetFv.insertChild(self.NewFfs)
+ ModifyFfsType(self.NewFfs)
+ # Recompress from the Fv node to update all the related node data.
+ self.CompressData(TargetFv)
+ # If TargetFv do not have enough free space, need move part of the free space of TargetFv's parent Fv to TargetFv/NewFfs.
+ else:
+ if TargetFv.type == FV_TREE:
+ self.Status = False
+ elif TargetFv.type == SEC_FV_TREE:
+ # Recalculate TargetFv needed space to keep it match the BlockSize setting.
+ BlockSize = TargetFv.Data.Header.BlockMap[0].Length
+ New_Add_Len = BlockSize - TargetLen%BlockSize
+ if New_Add_Len % BlockSize:
+ self.TargetFfs.Data.Data = b'\xff' * New_Add_Len
+ self.TargetFfs.Data.Size = New_Add_Len
+ TargetLen += New_Add_Len
+ TargetFv.insertChild(self.NewFfs, -1)
+ TargetFv.Data.Free_Space = New_Add_Len
+ else:
+ TargetFv.Child.remove(self.TargetFfs)
+ TargetFv.insertChild(self.NewFfs)
+ TargetFv.Data.Free_Space = 0
+ ModifyFfsType(self.NewFfs)
+ ModifyFvSystemGuid(TargetFv)
+ TargetFv.Data.Data = b''
+ for item in TargetFv.Child:
+ if item.type == FFS_FREE_SPACE:
+ TargetFv.Data.Data += item.Data.Data + item.Data.PadData
+ else:
+ TargetFv.Data.Data += struct2stream(item.Data.Header)+ item.Data.Data + item.Data.PadData
+ # Encapsulate the Fv Data for update.
+ TargetFv.Data.Size += TargetLen
+ TargetFv.Data.Header.FvLength = TargetFv.Data.Size
+ TargetFv.Data.ModFvExt()
+ TargetFv.Data.ModFvSize()
+ TargetFv.Data.ModExtHeaderData()
+ ModifyFvExtData(TargetFv)
+ TargetFv.Data.ModCheckSum()
+ # Start free space calculating and moving process.
+ self.ModifyTest(TargetFv.Parent, TargetLen)
+ else:
+ # If TargetFv do not have free space, need directly move part of the free space of TargetFv's parent Fv to TargetFv/NewFfs.
+ TargetLen = self.NewFfs.Data.Size + len(self.NewFfs.Data.PadData)
+ TargetFv = self.TargetFfs.Parent
+ if TargetFv.Data.Header.Attributes & EFI_FVB2_ERASE_POLARITY:
+ self.NewFfs.Data.Header.State = c_uint8(
+ ~self.NewFfs.Data.Header.State)
+ if TargetFv.type == FV_TREE:
+ self.Status = False
+ elif TargetFv.type == SEC_FV_TREE:
+ BlockSize = TargetFv.Data.Header.BlockMap[0].Length
+ New_Add_Len = BlockSize - TargetLen%BlockSize
+ if New_Add_Len % BlockSize:
+ New_Free_Space = BIOSTREE('FREE_SPACE')
+ New_Free_Space.type = FFS_FREE_SPACE
+ New_Free_Space.Data = FreeSpaceNode(b'\xff' * New_Add_Len)
+ TargetLen += New_Add_Len
+ TargetFv.Data.Free_Space = New_Add_Len
+ TargetFv.insertChild(self.NewFfs)
+ TargetFv.insertChild(New_Free_Space)
+ else:
+ TargetFv.insertChild(self.NewFfs)
+ ModifyFfsType(self.NewFfs)
+ ModifyFvSystemGuid(TargetFv)
+ TargetFv.Data.Data = b''
+ for item in TargetFv.Child:
+ if item.type == FFS_FREE_SPACE:
+ TargetFv.Data.Data += item.Data.Data + item.Data.PadData
+ else:
+ TargetFv.Data.Data += struct2stream(item.Data.Header)+ item.Data.Data + item.Data.PadData
+ TargetFv.Data.Size += TargetLen
+ TargetFv.Data.Header.FvLength = TargetFv.Data.Size
+ TargetFv.Data.ModFvExt()
+ TargetFv.Data.ModFvSize()
+ TargetFv.Data.ModExtHeaderData()
+ ModifyFvExtData(TargetFv)
+ TargetFv.Data.ModCheckSum()
+ self.ModifyTest(TargetFv.Parent, TargetLen)
+ logger.debug('Done!')
+ return self.Status
+
+ def DeleteFfs(self) -> bool:
+ logger.debug('Start Deleting Process......')
+ Delete_Ffs = self.TargetFfs
+ Delete_Fv = Delete_Ffs.Parent
+ # Calculate free space
+ Add_Free_Space = Delete_Ffs.Data.Size + len(Delete_Ffs.Data.PadData)
+ # If Ffs parent Fv have free space, follow the rules to merge the new free space.
+ if Delete_Fv.Data.Free_Space:
+ # If Fv is a Section fv, free space need to be recalculated to keep align with BlockSize.
+ # Other free space saved in self.Remain_New_Free_Space, will be moved to the 1st level Fv.
+ if Delete_Fv.type == SEC_FV_TREE:
+ Used_Size = Delete_Fv.Data.Size - Delete_Fv.Data.Free_Space - Add_Free_Space
+ BlockSize = Delete_Fv.Data.Header.BlockMap[0].Length
+ New_Free_Space = BlockSize - Used_Size % BlockSize
+ self.Remain_New_Free_Space += Delete_Fv.Data.Free_Space + Add_Free_Space - New_Free_Space
+ Delete_Fv.Child[-1].Data.Data = New_Free_Space * b'\xff'
+ Delete_Fv.Data.Free_Space = New_Free_Space
+ # If Fv is lst level Fv, new free space will be merged with origin free space.
+ else:
+ Used_Size = Delete_Fv.Data.Size - Delete_Fv.Data.Free_Space - Add_Free_Space
+ Delete_Fv.Child[-1].Data.Data += Add_Free_Space * b'\xff'
+ Delete_Fv.Data.Free_Space += Add_Free_Space
+ New_Free_Space = Delete_Fv.Data.Free_Space
+ # If Ffs parent Fv not have free space, will create new free space node to save the free space.
+ else:
+ # If Fv is a Section fv, new free space need to be recalculated to keep align with BlockSize.
+ # Then create a Free spcae node to save the 0xff data, and insert into the Fv.
+ # If have more space left, move to 1st level fv.
+ if Delete_Fv.type == SEC_FV_TREE:
+ Used_Size = Delete_Fv.Data.Size - Add_Free_Space
+ BlockSize = Delete_Fv.Data.Header.BlockMap[0].Length
+ New_Free_Space = BlockSize - Used_Size % BlockSize
+ self.Remain_New_Free_Space += Add_Free_Space - New_Free_Space
+ Add_Free_Space = New_Free_Space
+ # If Fv is lst level Fv, new free space node will be created to save the free space.
+ else:
+ Used_Size = Delete_Fv.Data.Size - Add_Free_Space
+ New_Free_Space = Add_Free_Space
+ New_Free_Space_Info = FfsNode(Add_Free_Space * b'\xff')
+ New_Free_Space_Info.Data = Add_Free_Space * b'\xff'
+ New_Ffs_Tree = BIOSTREE(New_Free_Space_Info.Name)
+ New_Ffs_Tree.type = FFS_FREE_SPACE
+ New_Ffs_Tree.Data = New_Free_Space_Info
+ Delete_Fv.insertChild(New_Ffs_Tree)
+ Delete_Fv.Data.Free_Space = Add_Free_Space
+ Delete_Fv.Child.remove(Delete_Ffs)
+ Delete_Fv.Data.Header.FvLength = Used_Size + New_Free_Space
+ Delete_Fv.Data.ModFvExt()
+ Delete_Fv.Data.ModFvSize()
+ Delete_Fv.Data.ModExtHeaderData()
+ ModifyFvExtData(Delete_Fv)
+ Delete_Fv.Data.ModCheckSum()
+ # Recompress from the Fv node to update all the related node data.
+ self.CompressData(Delete_Fv)
+ self.Status = True
+ logger.debug('Done!')
+ return self.Status