audk/BaseTools/Source/Python/FMMT/core/BiosTree.py

243 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'
RootType = [ROOT_TREE, ROOT_FV_TREE, ROOT_FFS_TREE, ROOT_SECTION_TREE]
FvType = [FV_TREE, SEC_FV_TREE]
FfsType = FFS_TREE
SecType = SECTION_TREE
ElfType = [ROOT_ELF_TREE, ELF_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 == 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