You've already forked edk2-upstream
mirror of
https://github.com/Dasharo/edk2-upstream.git
synced 2026-03-06 15:03:57 -08:00
1.Add FFS file type check: Only allow rebase operation for EFI_FV_FILETYPE_SECURITY_CORE, EFI_FV_FILETYPE_PEI_CORE, EFI_FV_FILETYPE_DXE_CORE, EFI_FV_FILETYPE_PEIM, EFI_FV_FILETYPE_DRIVER, EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE types, improving safety and compliance. 2.Automatically detect and complete the PE/COFF or TE image relocation table (reloc section) to ensure integrity and compatibility of the rebase operation. 3.After rebase, automatically update FFS checksum and FV header information to ensure correct data structure. 4.Support recursive processing for nested FVs, ensuring all related FFS files' PE/TE images are properly rebased and reloc tables are completed. 5.Use table-driven architecture for relocation types, making it easier to extend to more platforms. 6.Improve error handling and logging for better robustness and maintainability. Please attention, only IA32 and X64 PE/COFF image are supported now. For other Arch, will support it after testing. Signed-off-by: Yuwei Chen <yuwei.chen@intel.com>
891 lines
50 KiB
Python
891 lines
50 KiB
Python
## @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 FirmwareStorageFormat.FfsFileHeader 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) -> 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)
|
|
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:
|
|
# Save original pad size before modifying PadData
|
|
Original_Pad_Size = len(TargetTree.Data.PadData)
|
|
TargetTree.Data.PadData = b'\x00' * New_Pad_Size
|
|
self.Remain_New_Free_Space = (
|
|
len(TargetTree.Data.OriData) +
|
|
Original_Pad_Size -
|
|
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.Status = True
|
|
self.ModifyTest(TargetTree, self.Remain_New_Free_Space)
|
|
|
|
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)
|
|
Original_Data_Size = len(ParTree.Data.OriData)
|
|
Needed_Space = len(CompressedData) - Original_Data_Size
|
|
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
|
|
Original_Pad_Size = len(ParTree.Data.PadData)
|
|
if ParTree.NextRel:
|
|
New_Pad_Size = GetPadSize(ParTree.Data.Size, SECTION_COMMON_ALIGNMENT)
|
|
Delta_Pad_Size = New_Pad_Size - Original_Pad_Size
|
|
ParTree.Data.PadData = b'\x00' * New_Pad_Size
|
|
Needed_Space += Delta_Pad_Size
|
|
else:
|
|
ParTree.Data.PadData = b''
|
|
if Needed_Space < 0:
|
|
if ParTree.NextRel:
|
|
self.Remain_New_Free_Space = (
|
|
Original_Data_Size + Original_Pad_Size -
|
|
len(CompressedData) - New_Pad_Size
|
|
)
|
|
else:
|
|
self.Remain_New_Free_Space = (
|
|
Original_Data_Size - 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.Ffs_PecoffRebase()
|
|
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 Needed_Space == 0:
|
|
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
|
|
elif 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 + len(self.TargetFfs.Data.PadData) - self.NewFfs.Data.Size - len(self.NewFfs.Data.PadData)
|
|
# 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)
|
|
# 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)
|
|
# 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)
|
|
self.Status = True
|
|
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.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)
|
|
self.Status = True
|
|
elif TargetLen == 0:
|
|
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)
|
|
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
|
|
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
|
|
|
|
def ShrinkFv(self) -> bool:
|
|
TargetFv = self.NewFfs
|
|
TargetFv.Data.Data = b''
|
|
if not TargetFv.Data.Free_Space:
|
|
self.Status = True
|
|
else:
|
|
BlockSize = TargetFv.Data.Header.BlockMap[0].Length
|
|
New_Free_Space = TargetFv.Data.Free_Space%BlockSize
|
|
Removed_Space = TargetFv.Data.Free_Space - New_Free_Space
|
|
TargetFv.Child[-1].Data.Data = b'\xff' * New_Free_Space
|
|
TargetFv.Data.Size -= Removed_Space
|
|
TargetFv.Data.Header.FvLength = TargetFv.Data.Size
|
|
if struct2stream(TargetFv.Data.Header.FileSystemGuid) == EFI_FIRMWARE_FILE_SYSTEM3_GUID_BYTE:
|
|
if TargetFv.Data.Size <= 0xFFFFFF:
|
|
TargetFv.Data.Header.FileSystemGuid = ModifyGuidFormat(
|
|
"8c8ce578-8a3d-4f1c-9935-896185c32dd3")
|
|
|
|
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.ModFvExt()
|
|
TargetFv.Data.ModFvSize()
|
|
TargetFv.Data.ModExtHeaderData()
|
|
ModifyFvExtData(TargetFv)
|
|
TargetFv.Data.ModCheckSum()
|
|
self.Status = True
|
|
return self.Status
|
|
|
|
def Ffs_PecoffRebase(self):
|
|
# --- FFS type filtering, only do PE/TE rebase for specific FFS types ---
|
|
ALLOWED_REBASE_TYPES = {
|
|
EFI_FV_FILETYPE_SECURITY_CORE,
|
|
EFI_FV_FILETYPE_PEI_CORE,
|
|
EFI_FV_FILETYPE_DXE_CORE,
|
|
EFI_FV_FILETYPE_PEIM,
|
|
EFI_FV_FILETYPE_DRIVER,
|
|
EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER,
|
|
EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE,
|
|
}
|
|
if self.NewFfs.Data.Header.Type not in ALLOWED_REBASE_TYPES:
|
|
return
|
|
|
|
# Recursively process child Fv
|
|
if self.NewFfs.Data.Header.Type == EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE:
|
|
# Traverse all FFS file nodes in child Fv and recursively rebase
|
|
for child in self.NewFfs.Child:
|
|
# Only process FFS file type nodes
|
|
if hasattr(child, 'Data') and hasattr(child.Data, 'Header') and hasattr(child.Data.Header, 'Type'):
|
|
# Avoid infinite recursion, exclude non-FFS types
|
|
if child.Data.Header.Type in ALLOWED_REBASE_TYPES:
|
|
# Construct recursive FvHandler instance
|
|
sub_handler = FvHandler(child)
|
|
sub_handler.Ffs_PecoffRebase()
|
|
# After recursion, return directly, do not process PE/TE
|
|
return
|
|
|
|
new_pe_exist = False
|
|
origin_pe_exist = False
|
|
# Handle the current FFS being replaced - check for PE32
|
|
for NewSection in self.NewFfs.Child:
|
|
if NewSection.Data.Type == EFI_SECTION_PE32 or NewSection.Data.Type == EFI_SECTION_TE:
|
|
if NewSection.Child[0].Data.Name == 'PeCoff':
|
|
New_Pecoff = NewSection.Child[0]
|
|
# Check and complete the relocation table (reloc section) for PE/COFF or TE image
|
|
# If there is no relocation table, complete it; if present, skip
|
|
if hasattr(New_Pecoff.Data, 'FillPeReloc'):
|
|
# If HasRelocTable method exists, check first; otherwise, complete directly (idempotent)
|
|
if hasattr(New_Pecoff.Data, 'HasRelocTable'):
|
|
if not New_Pecoff.Data.HasRelocTable():
|
|
New_Pecoff.Data.FillPeReloc()
|
|
else:
|
|
New_Pecoff.Data.FillPeReloc()
|
|
new_pe_image_address = NewSection.Child[0].Data.ImageAddress if hasattr(NewSection.Child[0].Data, 'ImageAddress') else 0
|
|
new_pe_exist = True
|
|
break
|
|
# Check original FFS for PE32 or TE
|
|
for OriSection in self.TargetFfs.Child:
|
|
if OriSection.Data.Type == EFI_SECTION_PE32 or OriSection.Data.Type == EFI_SECTION_TE:
|
|
if (len(OriSection.Child) > 0) and OriSection.Child[0].Data.Name == 'PeCoff':
|
|
Ori_Pecoff = OriSection.Child[0]
|
|
origin_pe_image_address = OriSection.Child[0].Data.ImageAddress if hasattr(OriSection.Child[0].Data, 'ImageAddress') else 0
|
|
origin_pe_exist = True
|
|
break
|
|
|
|
# Handle PE32 rebasing
|
|
if new_pe_exist and origin_pe_exist:
|
|
if new_pe_image_address == 0x0 and origin_pe_image_address != 0x0:
|
|
New_Pecoff.Data.PeCoffRebase(origin_pe_image_address)
|
|
NewSection.Child[0].Data.Data = New_Pecoff.Data.Data
|
|
elif origin_pe_image_address != new_pe_image_address:
|
|
delta_image_address = origin_pe_image_address - new_pe_image_address
|
|
New_Pecoff.Data.PeCoffRebase(delta_image_address)
|
|
NewSection.Child[0].Data.Data = New_Pecoff.Data.Data
|
|
|
|
# If new PE/TE exist, we need to rebuild the FFS data
|
|
# This is necessary to ensure the new PE/TE sections are correctly integrated into the FFS structure
|
|
if new_pe_exist:
|
|
# Rebuild the FFS data
|
|
NewFfs_Data = b''
|
|
for item in self.NewFfs.Child:
|
|
if item.type == SECTION_TREE and not item.Data.OriData and item.Data.ExtHeader:
|
|
NewFfs_Data += 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:
|
|
NewFfs_Data += struct2stream(item.Data.Header) + item.Data.OriData + item.Data.PadData
|
|
elif item.type == SECTION_TREE and item.Data.OriData and item.Data.ExtHeader:
|
|
NewFfs_Data += struct2stream(item.Data.Header) + struct2stream(item.Data.ExtHeader) + item.Data.OriData + item.Data.PadData
|
|
elif item.type == FFS_FREE_SPACE:
|
|
NewFfs_Data += item.Data.Data + item.Data.PadData
|
|
else:
|
|
NewFfs_Data += struct2stream(item.Data.Header) + item.Data.Data + item.Data.PadData
|
|
self.NewFfs.Data.Data = NewFfs_Data
|
|
|
|
# Rebase subsequent FFS files in the SAME FV only
|
|
self._rebase_subsequent_ffs_in_current_fv()
|
|
|
|
# Checksum and update
|
|
# 1. FFS checksum
|
|
if hasattr(self.NewFfs, 'Data') and hasattr(self.NewFfs.Data, 'ModCheckSum'):
|
|
self.NewFfs.Data.ModCheckSum()
|
|
# 2. FV alignment/capacity refresh (if parent FV node exists)
|
|
if hasattr(self.NewFfs, 'Parent') and self.NewFfs.Parent and hasattr(self.NewFfs.Parent, 'Data'):
|
|
if hasattr(self.NewFfs.Parent.Data, 'ModFvExt'):
|
|
self.NewFfs.Parent.Data.ModFvExt()
|
|
if hasattr(self.NewFfs.Parent.Data, 'ModFvSize'):
|
|
self.NewFfs.Parent.Data.ModFvSize()
|
|
if hasattr(self.NewFfs.Parent.Data, 'ModExtHeaderData'):
|
|
self.NewFfs.Parent.Data.ModExtHeaderData()
|
|
if hasattr(self.NewFfs.Parent.Data, 'ModCheckSum'):
|
|
self.NewFfs.Parent.Data.ModCheckSum()
|
|
|
|
def _rebase_subsequent_ffs_in_current_fv(self):
|
|
# Rebase PE/COFF images in subsequent FFS files within the current FV only
|
|
if not hasattr(self, 'TargetFfs') or self.TargetFfs is None:
|
|
return
|
|
|
|
# Calculate size change from the replacement
|
|
old_size = self.TargetFfs.Data.Size + len(self.TargetFfs.Data.PadData)
|
|
new_size = self.NewFfs.Data.Size + len(self.NewFfs.Data.PadData)
|
|
size_delta = new_size - old_size
|
|
|
|
if size_delta == 0:
|
|
return # No size change, no rebasing needed
|
|
|
|
# Get the current FV (where the replacement is happening)
|
|
current_fv = self.TargetFfs.Parent
|
|
if not current_fv:
|
|
return
|
|
|
|
# Find the index of the target FFS in the current FV
|
|
try:
|
|
target_index = current_fv.Child.index(self.TargetFfs)
|
|
except ValueError:
|
|
return
|
|
|
|
# Process only subsequent FFS files in the SAME FV
|
|
for i in range(target_index + 1, len(current_fv.Child)):
|
|
subsequent_ffs = current_fv.Child[i]
|
|
|
|
# Skip free space entries
|
|
if subsequent_ffs.type == FFS_FREE_SPACE:
|
|
continue
|
|
# Look for PE32 sections in this FFS and rebase them
|
|
self._rebase_ffs_pe_sections(subsequent_ffs, size_delta)
|
|
# Checksum update
|
|
if hasattr(subsequent_ffs, 'Data') and hasattr(subsequent_ffs.Data, 'ModCheckSum'):
|
|
subsequent_ffs.Data.ModCheckSum()
|
|
|
|
def _rebase_ffs_pe_sections(self, ffs_node, address_delta):
|
|
# Rebase PE/COFF and TE images in a specific FFS node
|
|
found_pe = False
|
|
for section in ffs_node.Child:
|
|
# Check for PE32 sections
|
|
if hasattr(section.Data, 'Type') and (section.Data.Type == EFI_SECTION_PE32 or section.Data.Type == EFI_SECTION_TE):
|
|
for child in section.Child:
|
|
if hasattr(child.Data, 'Name') and child.Data.Name == 'PeCoff':
|
|
old_address = child.Data.ImageAddress if hasattr(child.Data, 'ImageAddress') else 0
|
|
child.Data.PeCoffRebase(address_delta)
|
|
section.Data.Data = child.Data.Data
|
|
found_pe = True
|
|
# Checksum update
|
|
if hasattr(ffs_node, 'Data') and hasattr(ffs_node.Data, 'ModCheckSum'):
|
|
ffs_node.Data.ModCheckSum()
|
|
break
|
|
|
|
# Handle nested sections recursively
|
|
elif hasattr(section, 'Child') and section.Child:
|
|
nested_found = self._rebase_nested_sections(section, address_delta)
|
|
found_pe = found_pe or nested_found
|
|
|
|
if not found_pe:
|
|
logger.debug('No PE/COFF or TE found in this FFS')
|
|
|
|
return found_pe
|
|
|
|
def _rebase_nested_sections(self, section_node, address_delta):
|
|
# Recursively rebase PE/COFF and TE images in nested sections within current FV
|
|
found_pe = False
|
|
for child in section_node.Child:
|
|
# Check for PE32 sections
|
|
if hasattr(child.Data, 'Type') and (child.Data.Type == EFI_SECTION_PE32 or child.Data.Type == EFI_SECTION_TE):
|
|
for pe_child in child.Child:
|
|
if hasattr(pe_child.Data, 'Name') and pe_child.Data.Name == 'PeCoff':
|
|
old_address = pe_child.Data.ImageAddress if hasattr(pe_child.Data, 'ImageAddress') else 0
|
|
pe_child.Data.PeCoffRebase(address_delta)
|
|
found_pe = True
|
|
break
|
|
# Continue recursing
|
|
elif hasattr(child, 'Child') and child.Child:
|
|
nested_found = self._rebase_nested_sections(child, address_delta)
|
|
found_pe = found_pe or nested_found
|
|
|
|
return found_pe
|