You've already forked edk2-upstream
mirror of
https://github.com/Dasharo/edk2-upstream.git
synced 2026-03-06 15:03:57 -08:00
This patch adds and improves the rebase functionality for firmware images (PE/COFF/TE) in the FMMT tool. Key features include: 1.Automatically rebases PE/COFF/TE images within FFS files when the firmware volume (FV) layout is adjusted or FFS files are moved, ensuring correct loading and execution at new addresses. 2.Implements recursive rebase logic for nested sections, guaranteeing all relevant images are properly relocated. 3.Adds support for rebasing subsequent FFS files within the same FV, enhancing compatibility and stability during firmware layout changes. 4.Core code changes are mainly in FvHandler.py, BiosTreeNode.py, and BinaryFactoryProduct.py, covering rebase flag detection, address calculation, and actual relocation operations. 5.This feature improves the flexibility of firmware space management and enhances the automation and reliability of the FMMT tool. Co-Auther: Ashraf Ali S <ashraf.ali.s@intel.com> Signed-off-by: Yuwei Chen <yuwei.chen@intel.com>
253 lines
11 KiB
Python
253 lines
11 KiB
Python
## @file
|
|
# This file is used to define the Bios layout tree structure and related operations.
|
|
#
|
|
# Copyright (c) 2021-, Intel Corporation. All rights reserved.<BR>
|
|
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
##
|
|
import collections
|
|
from FirmwareStorageFormat.Common import *
|
|
from utils.FmmtLogger import FmmtLogger as logger
|
|
|
|
ROOT_TREE = 'ROOT'
|
|
ROOT_FV_TREE = 'ROOT_FV_TREE'
|
|
ROOT_FFS_TREE = 'ROOT_FFS_TREE'
|
|
ROOT_SECTION_TREE = 'ROOT_SECTION_TREE'
|
|
ROOT_ELF_TREE = 'ROOT_ELF_TREE'
|
|
|
|
FV_TREE = 'FV'
|
|
DATA_FV_TREE = 'DATA_FV'
|
|
FFS_TREE = 'FFS'
|
|
FFS_PAD = 'FFS_PAD'
|
|
FFS_FREE_SPACE = 'FFS_FREE_SPACE'
|
|
SECTION_TREE = 'SECTION'
|
|
SEC_FV_TREE = 'SEC_FV_IMAGE'
|
|
BINARY_DATA = 'BINARY'
|
|
ELF_TREE = 'ELF'
|
|
PECOFF_TREE = 'PECOFF_TREE'
|
|
|
|
RootType = [ROOT_TREE, ROOT_FV_TREE, ROOT_FFS_TREE, ROOT_SECTION_TREE]
|
|
FvType = [FV_TREE, SEC_FV_TREE]
|
|
FfsType = [FFS_TREE, FFS_PAD]
|
|
SecType = SECTION_TREE
|
|
ElfType = [ROOT_ELF_TREE, ELF_TREE]
|
|
PeCoffTree = PECOFF_TREE
|
|
|
|
class BIOSTREE:
|
|
def __init__(self, NodeName: str) -> None:
|
|
self.key = NodeName
|
|
self.type = None
|
|
self.Data = None
|
|
self.Child = []
|
|
self.Findlist = []
|
|
self.Parent = None
|
|
self.NextRel = None
|
|
self.LastRel = None
|
|
|
|
def HasChild(self) -> bool:
|
|
if self.Child == []:
|
|
return False
|
|
else:
|
|
return True
|
|
|
|
def isFinalChild(self) -> bool:
|
|
ParTree = self.Parent
|
|
if ParTree:
|
|
if ParTree.Child[-1] == self:
|
|
return True
|
|
return False
|
|
|
|
# FvTree.insertChild()
|
|
def insertChild(self, newNode, pos: int=None) -> None:
|
|
if len(self.Child) == 0:
|
|
self.Child.append(newNode)
|
|
else:
|
|
if not pos or pos == len(self.Child):
|
|
LastTree = self.Child[-1]
|
|
self.Child.append(newNode)
|
|
LastTree.NextRel = newNode
|
|
newNode.LastRel = LastTree
|
|
else:
|
|
newNode.NextRel = self.Child[pos-1].NextRel
|
|
newNode.LastRel = self.Child[pos].LastRel
|
|
self.Child[pos-1].NextRel = newNode
|
|
self.Child[pos].LastRel = newNode
|
|
self.Child.insert(pos, newNode)
|
|
newNode.Parent = self
|
|
|
|
# lastNode.insertRel(newNode)
|
|
def insertRel(self, newNode) -> None:
|
|
if self.Parent:
|
|
parentTree = self.Parent
|
|
new_index = parentTree.Child.index(self) + 1
|
|
parentTree.Child.insert(new_index, newNode)
|
|
self.NextRel = newNode
|
|
newNode.LastRel = self
|
|
|
|
def deleteNode(self, deletekey: str) -> None:
|
|
FindStatus, DeleteTree = self.FindNode(deletekey)
|
|
if FindStatus:
|
|
parentTree = DeleteTree.Parent
|
|
lastTree = DeleteTree.LastRel
|
|
nextTree = DeleteTree.NextRel
|
|
if parentTree:
|
|
index = parentTree.Child.index(DeleteTree)
|
|
del parentTree.Child[index]
|
|
if lastTree and nextTree:
|
|
lastTree.NextRel = nextTree
|
|
nextTree.LastRel = lastTree
|
|
elif lastTree:
|
|
lastTree.NextRel = None
|
|
elif nextTree:
|
|
nextTree.LastRel = None
|
|
return DeleteTree
|
|
else:
|
|
logger.error('Could not find the target tree')
|
|
return None
|
|
|
|
def FindNode(self, key: str, Findlist: list) -> None:
|
|
if self.key == key or (self.Data and self.Data.Name == key) or (self.type == FFS_TREE and self.Data.UiName == key):
|
|
Findlist.append(self)
|
|
for item in self.Child:
|
|
item.FindNode(key, Findlist)
|
|
|
|
def GetTreePath(self):
|
|
BiosTreePath = [self]
|
|
while self.Parent:
|
|
BiosTreePath.insert(0, self.Parent)
|
|
self = self.Parent
|
|
return BiosTreePath
|
|
|
|
def parserTree(self, TargetDict: dict=None, Info: list=None, space: int=0, ParFvId="") -> None:
|
|
Key = list(TargetDict.keys())[0]
|
|
if TargetDict[Key]["Type"] in RootType:
|
|
Info.append("Image File: {}".format(Key))
|
|
Info.append("FilesNum: {}".format(TargetDict.get(Key).get('FilesNum')))
|
|
Info.append("\n")
|
|
elif TargetDict[Key]["Type"] == ROOT_ELF_TREE:
|
|
Info.append("ELF File: {}\n".format(Key))
|
|
elif TargetDict[Key]["Type"] == ELF_TREE:
|
|
ProducerId = ""
|
|
ImageId = ""
|
|
if TargetDict.get(Key).get('IfExist'):
|
|
Identifier = TargetDict.get(Key).get('Identifier')
|
|
for item in TargetDict.get(Key).get('ProducerId'):
|
|
ProducerId += chr(item)
|
|
for item in TargetDict.get(Key).get('ImageId'):
|
|
ImageId += chr(item)
|
|
Info.append("- UNIVERSAL_PAYLOAD_INFO")
|
|
Info.append(" - 4 bytes align: {}".format(TargetDict.get(Key).get('Upld_Info_Align')))
|
|
Info.append(" - Identifier: {} # 0x48444c50--PLDH / 0x444c5055--UPLD".format(hex(Identifier)))
|
|
Info.append(" - SpecRevision: {}".format(hex(TargetDict.get(Key).get('SpecRevision'))))
|
|
Info.append(" - Attribute: {}".format(hex(TargetDict.get(Key).get('Attribute'))))
|
|
Info.append(" - Revision: {}".format(hex(TargetDict.get(Key).get('Revision'))))
|
|
Info.append(" - Capability: {}".format(hex(TargetDict.get(Key).get('Capability'))))
|
|
Info.append(" - ProducerId: {}".format(ProducerId))
|
|
Info.append(" - ImageId: {}".format(ImageId))
|
|
Info.append("\n")
|
|
Info.append("- UPLD buffer")
|
|
Info.append(" Buffer: {}".format(TargetDict.get(Key).get('Upld_Buffer')))
|
|
else:
|
|
print("Do not find the Upld Info section!!!\n")
|
|
elif TargetDict[Key]["Type"] in FvType:
|
|
space += 2
|
|
if TargetDict[Key]["Type"] == SEC_FV_TREE:
|
|
Info.append("{}Child FV named {} of {}".format(space*" ", Key, ParFvId))
|
|
space += 2
|
|
else:
|
|
Info.append("FvId: {}".format(Key))
|
|
ParFvId = Key
|
|
Info.append("{}FvNameGuid: {}".format(space*" ", TargetDict.get(Key).get('FvNameGuid')))
|
|
Info.append("{}Attributes: {}".format(space*" ", TargetDict.get(Key).get('Attributes')))
|
|
Info.append("{}Total Volume Size: {}".format(space*" ", TargetDict.get(Key).get('Size')))
|
|
Info.append("{}Free Volume Size: {}".format(space*" ", TargetDict.get(Key).get('FreeSize')))
|
|
Info.append("{}Volume Offset: {}".format(space*" ", TargetDict.get(Key).get('Offset')))
|
|
Info.append("{}FilesNum: {}".format(space*" ", TargetDict.get(Key).get('FilesNum')))
|
|
elif TargetDict[Key]["Type"] in FfsType:
|
|
space += 2
|
|
if TargetDict.get(Key).get('UiName') != "b''":
|
|
Info.append("{}File: {} / {}".format(space*" ", Key, TargetDict.get(Key).get('UiName')))
|
|
else:
|
|
Info.append("{}File: {}".format(space*" ", Key))
|
|
if "Files" in list(TargetDict[Key].keys()):
|
|
for item in TargetDict[Key]["Files"]:
|
|
self.parserTree(item, Info, space, ParFvId)
|
|
|
|
def ExportTree(self,TreeInfo: dict=None) -> dict:
|
|
if TreeInfo is None:
|
|
TreeInfo =collections.OrderedDict()
|
|
|
|
if self.type == ROOT_TREE or self.type == ROOT_FV_TREE or self.type == ROOT_FFS_TREE or self.type == ROOT_SECTION_TREE or self.type == ROOT_ELF_TREE:
|
|
key = str(self.key)
|
|
TreeInfo[self.key] = collections.OrderedDict()
|
|
TreeInfo[self.key]["Name"] = key
|
|
TreeInfo[self.key]["Type"] = self.type
|
|
TreeInfo[self.key]["FilesNum"] = len(self.Child)
|
|
elif self.type == ELF_TREE:
|
|
key = str(self.Data.Name)
|
|
TreeInfo[key] = collections.OrderedDict()
|
|
TreeInfo[key]["Name"] = key
|
|
TreeInfo[key]["Type"] = self.type
|
|
TreeInfo[key]["IfExist"] = self.Data.UpldInfo
|
|
if self.Data.UpldInfo:
|
|
TreeInfo[key]["Identifier"] = self.Data.UpldInfo.Identifier
|
|
TreeInfo[key]["SpecRevision"] = self.Data.UpldInfo.SpecRevision
|
|
TreeInfo[key]["Attribute"] = self.Data.UpldInfo.Attribute
|
|
TreeInfo[key]["Revision"] = self.Data.UpldInfo.Revision
|
|
TreeInfo[key]["Capability"] = self.Data.UpldInfo.Capability
|
|
TreeInfo[key]["ProducerId"] = self.Data.UpldInfo.ProducerId
|
|
TreeInfo[key]["ImageId"] = self.Data.UpldInfo.ImageId
|
|
TreeInfo[key]["Upld_Info_Align"] = self.Data.Upld_Info_Align
|
|
TreeInfo[key]["Upld_Buffer"] = self.Data.UpldBuffer
|
|
elif self.type == FV_TREE or self.type == SEC_FV_TREE:
|
|
key = str(self.Data.FvId)
|
|
TreeInfo[key] = collections.OrderedDict()
|
|
TreeInfo[key]["Name"] = key
|
|
if self.Data.FvId != self.Data.Name:
|
|
TreeInfo[key]["FvNameGuid"] = str(self.Data.Name)
|
|
TreeInfo[key]["Type"] = self.type
|
|
TreeInfo[key]["Attributes"] = hex(self.Data.Header.Attributes)
|
|
TreeInfo[key]["Size"] = hex(self.Data.Header.FvLength)
|
|
TreeInfo[key]["FreeSize"] = hex(self.Data.Free_Space)
|
|
TreeInfo[key]["Offset"] = hex(self.Data.HOffset)
|
|
TreeInfo[key]["FilesNum"] = len(self.Child)
|
|
elif self.type == FFS_TREE:
|
|
key = str(self.Data.Name)
|
|
TreeInfo[key] = collections.OrderedDict()
|
|
TreeInfo[key]["Name"] = key
|
|
TreeInfo[key]["UiName"] = '{}'.format(self.Data.UiName)
|
|
TreeInfo[key]["Version"] = '{}'.format(self.Data.Version)
|
|
TreeInfo[key]["Type"] = self.type
|
|
TreeInfo[key]["Size"] = hex(self.Data.Size)
|
|
TreeInfo[key]["Offset"] = hex(self.Data.HOffset)
|
|
TreeInfo[key]["FilesNum"] = len(self.Child)
|
|
elif self.type == FFS_PAD:
|
|
key = str(self.Data.Name)
|
|
TreeInfo[key] = collections.OrderedDict()
|
|
TreeInfo[key]["Name"] = key
|
|
TreeInfo[key]["UiName"] = 'Ffs_pad'
|
|
TreeInfo[key]["Type"] = self.type
|
|
TreeInfo[key]["Size"] = hex(self.Data.Size)
|
|
TreeInfo[key]["Offset"] = hex(self.Data.HOffset)
|
|
elif self.type == SECTION_TREE and self.Data.Type == 0x02:
|
|
key = str(self.Data.Name)
|
|
TreeInfo[key] = collections.OrderedDict()
|
|
TreeInfo[key]["Name"] = key
|
|
TreeInfo[key]["Type"] = self.type
|
|
TreeInfo[key]["Size"] = hex(len(self.Data.OriData) + self.Data.HeaderLength)
|
|
TreeInfo[key]["DecompressedSize"] = hex(self.Data.Size)
|
|
TreeInfo[key]["Offset"] = hex(self.Data.HOffset)
|
|
TreeInfo[key]["FilesNum"] = len(self.Child)
|
|
elif self is not None:
|
|
key = str(self.Data.Name)
|
|
TreeInfo[key] = collections.OrderedDict()
|
|
TreeInfo[key]["Name"] = key
|
|
TreeInfo[key]["Type"] = self.type
|
|
TreeInfo[key]["Size"] = hex(self.Data.Size)
|
|
TreeInfo[key]["Offset"] = hex(self.Data.HOffset)
|
|
TreeInfo[key]["FilesNum"] = len(self.Child)
|
|
|
|
for item in self.Child:
|
|
TreeInfo[key].setdefault('Files',[]).append( item.ExportTree())
|
|
|
|
return TreeInfo
|