diff options
| author | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
|---|---|---|
| committer | kx <kx@radix.pro> | 2024-06-04 06:43:08 +0300 |
| commit | 7e2ccccace24636f29ddc210b94606abd4c7e42b (patch) | |
| tree | 545d43ea12671048956cafeb12303e84d601e571 /BaseTools/Source/Python/FMMT | |
| parent | 27b044605cd5f6b33a3d231576003850b3fe305b (diff) | |
| download | edk2-trunk.tar.xz | |
Renormalized end-of-lines from master@27b044605cd5f6b33a3d231576003850b3fe305btrunk
Diffstat (limited to 'BaseTools/Source/Python/FMMT')
| -rw-r--r-- | BaseTools/Source/Python/FMMT/FMMT.py | 326 | ||||
| -rw-r--r-- | BaseTools/Source/Python/FMMT/FmmtConf.ini | 22 | ||||
| -rw-r--r-- | BaseTools/Source/Python/FMMT/core/BinaryFactoryProduct.py | 828 | ||||
| -rw-r--r-- | BaseTools/Source/Python/FMMT/core/BiosTree.py | 484 | ||||
| -rw-r--r-- | BaseTools/Source/Python/FMMT/core/BiosTreeNode.py | 496 | ||||
| -rw-r--r-- | BaseTools/Source/Python/FMMT/core/FMMTOperation.py | 464 | ||||
| -rw-r--r-- | BaseTools/Source/Python/FMMT/core/FMMTParser.py | 174 | ||||
| -rw-r--r-- | BaseTools/Source/Python/FMMT/core/FvHandler.py | 1366 | ||||
| -rw-r--r-- | BaseTools/Source/Python/FMMT/core/GuidTools.py | 358 | ||||
| -rw-r--r-- | BaseTools/Source/Python/FMMT/utils/FmmtLogger.py | 62 |
10 files changed, 2290 insertions, 2290 deletions
diff --git a/BaseTools/Source/Python/FMMT/FMMT.py b/BaseTools/Source/Python/FMMT/FMMT.py index 7505b6c88a..1b1923c2a3 100644 --- a/BaseTools/Source/Python/FMMT/FMMT.py +++ b/BaseTools/Source/Python/FMMT/FMMT.py @@ -1,163 +1,163 @@ -# @file
-# Firmware Module Management Tool.
-#
-# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
-#
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-#
-##
-
-# Import Modules
-#
-import argparse
-from core.FMMTOperation import *
-
-parser = argparse.ArgumentParser(description='''
-View the Binary Structure of FD/FV/Ffs/Section, and Delete/Extract/Add/Replace a Ffs from/into a FV.
-''')
-parser.add_argument("--version", action="version", version='%(prog)s Version 1.0',
- help="Print debug information.")
-parser.add_argument("-v", "--View", dest="View", nargs='+',
- help="View each FV and the named files within each FV: '-v inputfile outputfile, inputfiletype(.Fd/.Fv/.ffs/.sec)'")
-parser.add_argument("-d", "--Delete", dest="Delete", nargs='+',
- help="Delete a Ffs from FV: '-d inputfile TargetFvName(Optional) TargetFfsName outputfile\
- If not given TargetFvName, all the existed target Ffs will be deleted'")
-parser.add_argument("-e", "--Extract", dest="Extract", nargs='+',
- help="Extract a Ffs Info: '-e inputfile TargetFvName(Optional) TargetFfsName outputfile\
- If not given TargetFvName, the first found target Ffs will be extracted.\
- If only given TargetFvName, not given TargetFfsName, the TargetFv will be extracted to output file'")
-parser.add_argument("-a", "--Add", dest="Add", nargs='+',
- help="Add a Ffs into a FV:'-a inputfile TargetFvName newffsfile outputfile'")
-parser.add_argument("-r", "--Replace", dest="Replace", nargs='+',
- help="Replace a Ffs in a FV: '-r inputfile TargetFvName(Optional) TargetFfsName newffsfile outputfile\
- If not given TargetFvName, all the existed target Ffs will be replaced with new Ffs file)'")
-parser.add_argument("-l", "--LayoutFileName", dest="LayoutFileName", nargs='+',
- help="The output file which saves Binary layout: '-l xxx.txt'/'-l xxx.json'\
- If only provide file format as 'txt', \
- the file will be generated with default name (Layout_'InputFileName'.txt). \
- Currently supports two formats: json, txt. More formats will be added in the future")
-parser.add_argument("-c", "--ConfigFilePath", dest="ConfigFilePath", nargs='+',
- help="Provide the target FmmtConf.ini file path: '-c C:\\Code\\FmmtConf.ini' \
- FmmtConf file saves the target guidtool used in compress/uncompress process.\
- If do not provide, FMMT tool will search the inputfile folder for FmmtConf.ini firstly, if not found,\
- the FmmtConf.ini saved in FMMT tool's folder will be used as default.")
-parser.add_argument("-s", "--ShrinkFv", dest="ShrinkFv", nargs='+',
- help="Shrink the Fv file: '-s InputFvfile OutputFvfile")
-
-def print_banner():
- print("")
-
-class FMMT():
- def __init__(self) -> None:
- self.firmware_packet = {}
-
- def SetConfigFilePath(self, configfilepath:str) -> str:
- os.environ['FmmtConfPath'] = os.path.abspath(configfilepath)
-
- def SetDestPath(self, inputfile:str) -> str:
- os.environ['FmmtConfPath'] = ''
- self.dest_path = os.path.dirname(os.path.abspath(inputfile))
- old_env = os.environ['PATH']
- os.environ['PATH'] = self.dest_path + os.pathsep + old_env
-
- def CheckFfsName(self, FfsName:str) -> str:
- try:
- return uuid.UUID(FfsName)
- except:
- return FfsName
-
- def GetFvName(self, FvName:str) -> str:
- try:
- return uuid.UUID(FvName)
- except:
- return FvName
-
- def View(self, inputfile: str, layoutfilename: str=None, outputfile: str=None) -> None:
- # ViewFile(inputfile, ROOT_TYPE, logfile, outputfile)
- self.SetDestPath(inputfile)
- filetype = os.path.splitext(inputfile)[1].lower()
- if filetype == '.fd':
- ROOT_TYPE = ROOT_TREE
- elif filetype == '.fv':
- ROOT_TYPE = ROOT_FV_TREE
- elif filetype == '.ffs':
- ROOT_TYPE = ROOT_FFS_TREE
- elif filetype == '.sec':
- ROOT_TYPE = ROOT_SECTION_TREE
- elif filetype == '.elf':
- ROOT_TYPE = ROOT_ELF_TREE
- else:
- ROOT_TYPE = ROOT_TREE
- ViewFile(inputfile, ROOT_TYPE, layoutfilename, outputfile)
-
- def Delete(self, inputfile: str, TargetFfs_name: str, outputfile: str, Fv_name: str=None) -> None:
- self.SetDestPath(inputfile)
- if Fv_name:
- DeleteFfs(inputfile, self.CheckFfsName(TargetFfs_name), outputfile, self.GetFvName(Fv_name))
- else:
- DeleteFfs(inputfile, self.CheckFfsName(TargetFfs_name), outputfile)
-
- def Extract(self, inputfile: str, Ffs_name: str, outputfile: str, Fv_name: str=None) -> None:
- self.SetDestPath(inputfile)
- if Fv_name:
- ExtractFfs(inputfile, self.CheckFfsName(Ffs_name), outputfile, self.GetFvName(Fv_name))
- else:
- ExtractFfs(inputfile, self.CheckFfsName(Ffs_name), outputfile)
-
- def Add(self, inputfile: str, Fv_name: str, newffsfile: str, outputfile: str) -> None:
- self.SetDestPath(inputfile)
- AddNewFfs(inputfile, self.CheckFfsName(Fv_name), newffsfile, outputfile)
-
- def Replace(self,inputfile: str, Ffs_name: str, newffsfile: str, outputfile: str, Fv_name: str=None) -> None:
- self.SetDestPath(inputfile)
- if Fv_name:
- ReplaceFfs(inputfile, self.CheckFfsName(Ffs_name), newffsfile, outputfile, self.GetFvName(Fv_name))
- else:
- ReplaceFfs(inputfile, self.CheckFfsName(Ffs_name), newffsfile, outputfile)
-
- def Shrink(self,inputfile: str, outputfile: str) -> None:
- self.SetDestPath(inputfile)
- ShrinkFv(inputfile, outputfile)
-
-def main():
- args=parser.parse_args()
- status=0
-
- try:
- fmmt=FMMT()
- if args.ConfigFilePath:
- fmmt.SetConfigFilePath(args.ConfigFilePath[0])
- if args.View:
- if args.LayoutFileName:
- fmmt.View(args.View[0], args.LayoutFileName[0])
- else:
- fmmt.View(args.View[0])
- elif args.Delete:
- if len(args.Delete) == 4:
- fmmt.Delete(args.Delete[0],args.Delete[2],args.Delete[3],args.Delete[1])
- else:
- fmmt.Delete(args.Delete[0],args.Delete[1],args.Delete[2])
- elif args.Extract:
- if len(args.Extract) == 4:
- fmmt.Extract(args.Extract[0],args.Extract[2],args.Extract[3], args.Extract[1])
- else:
- fmmt.Extract(args.Extract[0],args.Extract[1],args.Extract[2])
- elif args.Add:
- fmmt.Add(args.Add[0],args.Add[1],args.Add[2],args.Add[3])
- elif args.Replace:
- if len(args.Replace) == 5:
- fmmt.Replace(args.Replace[0],args.Replace[2],args.Replace[3],args.Replace[4],args.Replace[1])
- else:
- fmmt.Replace(args.Replace[0],args.Replace[1],args.Replace[2],args.Replace[3])
- elif args.ShrinkFv:
- fmmt.Shrink(args.ShrinkFv[0], args.ShrinkFv[1])
- else:
- parser.print_help()
- except Exception as e:
- print(e)
-
- return status
-
-
-if __name__ == "__main__":
- exit(main())
+# @file +# Firmware Module Management Tool. +# +# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR> +# +# SPDX-License-Identifier: BSD-2-Clause-Patent +# +## + +# Import Modules +# +import argparse +from core.FMMTOperation import * + +parser = argparse.ArgumentParser(description=''' +View the Binary Structure of FD/FV/Ffs/Section, and Delete/Extract/Add/Replace a Ffs from/into a FV. +''') +parser.add_argument("--version", action="version", version='%(prog)s Version 1.0', + help="Print debug information.") +parser.add_argument("-v", "--View", dest="View", nargs='+', + help="View each FV and the named files within each FV: '-v inputfile outputfile, inputfiletype(.Fd/.Fv/.ffs/.sec)'") +parser.add_argument("-d", "--Delete", dest="Delete", nargs='+', + help="Delete a Ffs from FV: '-d inputfile TargetFvName(Optional) TargetFfsName outputfile\ + If not given TargetFvName, all the existed target Ffs will be deleted'") +parser.add_argument("-e", "--Extract", dest="Extract", nargs='+', + help="Extract a Ffs Info: '-e inputfile TargetFvName(Optional) TargetFfsName outputfile\ + If not given TargetFvName, the first found target Ffs will be extracted.\ + If only given TargetFvName, not given TargetFfsName, the TargetFv will be extracted to output file'") +parser.add_argument("-a", "--Add", dest="Add", nargs='+', + help="Add a Ffs into a FV:'-a inputfile TargetFvName newffsfile outputfile'") +parser.add_argument("-r", "--Replace", dest="Replace", nargs='+', + help="Replace a Ffs in a FV: '-r inputfile TargetFvName(Optional) TargetFfsName newffsfile outputfile\ + If not given TargetFvName, all the existed target Ffs will be replaced with new Ffs file)'") +parser.add_argument("-l", "--LayoutFileName", dest="LayoutFileName", nargs='+', + help="The output file which saves Binary layout: '-l xxx.txt'/'-l xxx.json'\ + If only provide file format as 'txt', \ + the file will be generated with default name (Layout_'InputFileName'.txt). \ + Currently supports two formats: json, txt. More formats will be added in the future") +parser.add_argument("-c", "--ConfigFilePath", dest="ConfigFilePath", nargs='+', + help="Provide the target FmmtConf.ini file path: '-c C:\\Code\\FmmtConf.ini' \ + FmmtConf file saves the target guidtool used in compress/uncompress process.\ + If do not provide, FMMT tool will search the inputfile folder for FmmtConf.ini firstly, if not found,\ + the FmmtConf.ini saved in FMMT tool's folder will be used as default.") +parser.add_argument("-s", "--ShrinkFv", dest="ShrinkFv", nargs='+', + help="Shrink the Fv file: '-s InputFvfile OutputFvfile") + +def print_banner(): + print("") + +class FMMT(): + def __init__(self) -> None: + self.firmware_packet = {} + + def SetConfigFilePath(self, configfilepath:str) -> str: + os.environ['FmmtConfPath'] = os.path.abspath(configfilepath) + + def SetDestPath(self, inputfile:str) -> str: + os.environ['FmmtConfPath'] = '' + self.dest_path = os.path.dirname(os.path.abspath(inputfile)) + old_env = os.environ['PATH'] + os.environ['PATH'] = self.dest_path + os.pathsep + old_env + + def CheckFfsName(self, FfsName:str) -> str: + try: + return uuid.UUID(FfsName) + except: + return FfsName + + def GetFvName(self, FvName:str) -> str: + try: + return uuid.UUID(FvName) + except: + return FvName + + def View(self, inputfile: str, layoutfilename: str=None, outputfile: str=None) -> None: + # ViewFile(inputfile, ROOT_TYPE, logfile, outputfile) + self.SetDestPath(inputfile) + filetype = os.path.splitext(inputfile)[1].lower() + if filetype == '.fd': + ROOT_TYPE = ROOT_TREE + elif filetype == '.fv': + ROOT_TYPE = ROOT_FV_TREE + elif filetype == '.ffs': + ROOT_TYPE = ROOT_FFS_TREE + elif filetype == '.sec': + ROOT_TYPE = ROOT_SECTION_TREE + elif filetype == '.elf': + ROOT_TYPE = ROOT_ELF_TREE + else: + ROOT_TYPE = ROOT_TREE + ViewFile(inputfile, ROOT_TYPE, layoutfilename, outputfile) + + def Delete(self, inputfile: str, TargetFfs_name: str, outputfile: str, Fv_name: str=None) -> None: + self.SetDestPath(inputfile) + if Fv_name: + DeleteFfs(inputfile, self.CheckFfsName(TargetFfs_name), outputfile, self.GetFvName(Fv_name)) + else: + DeleteFfs(inputfile, self.CheckFfsName(TargetFfs_name), outputfile) + + def Extract(self, inputfile: str, Ffs_name: str, outputfile: str, Fv_name: str=None) -> None: + self.SetDestPath(inputfile) + if Fv_name: + ExtractFfs(inputfile, self.CheckFfsName(Ffs_name), outputfile, self.GetFvName(Fv_name)) + else: + ExtractFfs(inputfile, self.CheckFfsName(Ffs_name), outputfile) + + def Add(self, inputfile: str, Fv_name: str, newffsfile: str, outputfile: str) -> None: + self.SetDestPath(inputfile) + AddNewFfs(inputfile, self.CheckFfsName(Fv_name), newffsfile, outputfile) + + def Replace(self,inputfile: str, Ffs_name: str, newffsfile: str, outputfile: str, Fv_name: str=None) -> None: + self.SetDestPath(inputfile) + if Fv_name: + ReplaceFfs(inputfile, self.CheckFfsName(Ffs_name), newffsfile, outputfile, self.GetFvName(Fv_name)) + else: + ReplaceFfs(inputfile, self.CheckFfsName(Ffs_name), newffsfile, outputfile) + + def Shrink(self,inputfile: str, outputfile: str) -> None: + self.SetDestPath(inputfile) + ShrinkFv(inputfile, outputfile) + +def main(): + args=parser.parse_args() + status=0 + + try: + fmmt=FMMT() + if args.ConfigFilePath: + fmmt.SetConfigFilePath(args.ConfigFilePath[0]) + if args.View: + if args.LayoutFileName: + fmmt.View(args.View[0], args.LayoutFileName[0]) + else: + fmmt.View(args.View[0]) + elif args.Delete: + if len(args.Delete) == 4: + fmmt.Delete(args.Delete[0],args.Delete[2],args.Delete[3],args.Delete[1]) + else: + fmmt.Delete(args.Delete[0],args.Delete[1],args.Delete[2]) + elif args.Extract: + if len(args.Extract) == 4: + fmmt.Extract(args.Extract[0],args.Extract[2],args.Extract[3], args.Extract[1]) + else: + fmmt.Extract(args.Extract[0],args.Extract[1],args.Extract[2]) + elif args.Add: + fmmt.Add(args.Add[0],args.Add[1],args.Add[2],args.Add[3]) + elif args.Replace: + if len(args.Replace) == 5: + fmmt.Replace(args.Replace[0],args.Replace[2],args.Replace[3],args.Replace[4],args.Replace[1]) + else: + fmmt.Replace(args.Replace[0],args.Replace[1],args.Replace[2],args.Replace[3]) + elif args.ShrinkFv: + fmmt.Shrink(args.ShrinkFv[0], args.ShrinkFv[1]) + else: + parser.print_help() + except Exception as e: + print(e) + + return status + + +if __name__ == "__main__": + exit(main()) diff --git a/BaseTools/Source/Python/FMMT/FmmtConf.ini b/BaseTools/Source/Python/FMMT/FmmtConf.ini index aa2444f11b..338e075ce5 100644 --- a/BaseTools/Source/Python/FMMT/FmmtConf.ini +++ b/BaseTools/Source/Python/FMMT/FmmtConf.ini @@ -1,11 +1,11 @@ -## @file
-# This file is used to define the FMMT dependent external tool guid.
-#
-# Copyright (c) 2021-, Intel Corporation. All rights reserved.<BR>
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-##
-a31280ad-481e-41b6-95e8-127f4c984779 TIANO TianoCompress
-ee4e5898-3914-4259-9d6e-dc7bd79403cf LZMA LzmaCompress
-fc1bcdb0-7d31-49aa-936a-a4600d9dd083 CRC32 GenCrc32
-d42ae6bd-1352-4bfb-909a-ca72a6eae889 LZMAF86 LzmaF86Compress
-3d532050-5cda-4fd0-879e-0f7f630d5afb BROTLI BrotliCompress
+## @file +# This file is used to define the FMMT dependent external tool guid. +# +# Copyright (c) 2021-, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +a31280ad-481e-41b6-95e8-127f4c984779 TIANO TianoCompress +ee4e5898-3914-4259-9d6e-dc7bd79403cf LZMA LzmaCompress +fc1bcdb0-7d31-49aa-936a-a4600d9dd083 CRC32 GenCrc32 +d42ae6bd-1352-4bfb-909a-ca72a6eae889 LZMAF86 LzmaF86Compress +3d532050-5cda-4fd0-879e-0f7f630d5afb BROTLI BrotliCompress diff --git a/BaseTools/Source/Python/FMMT/core/BinaryFactoryProduct.py b/BaseTools/Source/Python/FMMT/core/BinaryFactoryProduct.py index de174f26ab..9eca6c1950 100644 --- a/BaseTools/Source/Python/FMMT/core/BinaryFactoryProduct.py +++ b/BaseTools/Source/Python/FMMT/core/BinaryFactoryProduct.py @@ -1,414 +1,414 @@ -## @file
-# This file is used to implement of the various bianry parser.
-#
-# Copyright (c) 2021-, Intel Corporation. All rights reserved.<BR>
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-##
-from re import T
-import copy
-import os
-import sys
-from FirmwareStorageFormat.Common import *
-from core.BiosTreeNode import *
-from core.BiosTree import *
-from core.GuidTools import GUIDTools
-from utils.FmmtLogger import FmmtLogger as logger
-
-ROOT_TREE = 'ROOT'
-ROOT_ELF_TREE = 'ROOT_ELF_TREE'
-ROOT_FV_TREE = 'ROOT_FV_TREE'
-ROOT_FFS_TREE = 'ROOT_FFS_TREE'
-ROOT_SECTION_TREE = 'ROOT_SECTION_TREE'
-
-ELF_TREE = 'ELF'
-ELF_SECTION_TREE = 'ELF_SECTION_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'
-Fv_count = 0
-
-## Abstract factory
-class BinaryFactory():
- type:list = []
-
- def Create_Product():
- pass
-
-class BinaryProduct():
- ## Use GuidTool to decompress data.
- def DeCompressData(self, GuidTool, Section_Data: bytes, FileName) -> bytes:
- guidtool = GUIDTools().__getitem__(struct2stream(GuidTool))
- if not guidtool.ifexist:
- logger.error("GuidTool {} is not found when decompressing {} file.\n".format(guidtool.command, FileName))
- raise Exception("Process Failed: GuidTool not found!")
- DecompressedData = guidtool.unpack(Section_Data)
- return DecompressedData
-
- def ParserData():
- pass
-
-class ElfFactory(BinaryFactory):
- type = [ROOT_ELF_TREE, ELF_TREE]
-
- def Create_Product():
- return ElfProduct()
-
-class SectionFactory(BinaryFactory):
- type = [SECTION_TREE]
-
- def Create_Product():
- return SectionProduct()
-
-class FfsFactory(BinaryFactory):
- type = [ROOT_SECTION_TREE, FFS_TREE]
-
- def Create_Product():
- return FfsProduct()
-
-class FvFactory(BinaryFactory):
- type = [ROOT_FFS_TREE, FV_TREE, SEC_FV_TREE]
-
- def Create_Product():
- return FvProduct()
-
-class FdFactory(BinaryFactory):
- type = [ROOT_FV_TREE, ROOT_TREE]
-
- def Create_Product():
- return FdProduct()
-
-class SectionProduct(BinaryProduct):
- ## Decompress the compressed section.
- def ParserData(self, Section_Tree, whole_Data: bytes, Rel_Whole_Offset: int=0) -> None:
- if Section_Tree.Data.Type == 0x01:
- Section_Tree.Data.OriData = Section_Tree.Data.Data
- self.ParserSection(Section_Tree, b'')
- # Guided Define Section
- elif Section_Tree.Data.Type == 0x02:
- Section_Tree.Data.OriData = Section_Tree.Data.Data
- DeCompressGuidTool = Section_Tree.Data.ExtHeader.SectionDefinitionGuid
- Section_Tree.Data.Data = self.DeCompressData(DeCompressGuidTool, Section_Tree.Data.Data, Section_Tree.Parent.Data.Name)
- Section_Tree.Data.Size = len(Section_Tree.Data.Data) + Section_Tree.Data.HeaderLength
- self.ParserSection(Section_Tree, b'')
- elif Section_Tree.Data.Type == 0x03:
- Section_Tree.Data.OriData = Section_Tree.Data.Data
- self.ParserSection(Section_Tree, b'')
- # SEC_FV Section
- elif Section_Tree.Data.Type == 0x17:
- global Fv_count
- Sec_Fv_Info = FvNode(Fv_count, Section_Tree.Data.Data)
- Sec_Fv_Tree = BIOSTREE('FV'+ str(Fv_count))
- Sec_Fv_Tree.type = SEC_FV_TREE
- Sec_Fv_Tree.Data = Sec_Fv_Info
- Sec_Fv_Tree.Data.HOffset = Section_Tree.Data.DOffset
- Sec_Fv_Tree.Data.DOffset = Sec_Fv_Tree.Data.HOffset + Sec_Fv_Tree.Data.Header.HeaderLength
- Sec_Fv_Tree.Data.Data = Section_Tree.Data.Data[Sec_Fv_Tree.Data.Header.HeaderLength:]
- Section_Tree.insertChild(Sec_Fv_Tree)
- Fv_count += 1
-
- def ParserSection(self, ParTree, Whole_Data: bytes, Rel_Whole_Offset: int=0) -> None:
- Rel_Offset = 0
- Section_Offset = 0
- # Get the Data from parent tree, if do not have the tree then get it from the whole_data.
- if ParTree.Data != None:
- Data_Size = len(ParTree.Data.Data)
- Section_Offset = ParTree.Data.DOffset
- Whole_Data = ParTree.Data.Data
- else:
- Data_Size = len(Whole_Data)
- # Parser all the data to collect all the Section recorded in its Parent Section.
- while Rel_Offset < Data_Size:
- # Create a SectionNode and set it as the SectionTree's Data
- Section_Info = SectionNode(Whole_Data[Rel_Offset:])
- Section_Tree = BIOSTREE(Section_Info.Name)
- Section_Tree.type = SECTION_TREE
- Section_Info.Data = Whole_Data[Rel_Offset+Section_Info.HeaderLength: Rel_Offset+Section_Info.Size]
- Section_Info.DOffset = Section_Offset + Section_Info.HeaderLength + Rel_Whole_Offset
- Section_Info.HOffset = Section_Offset + Rel_Whole_Offset
- Section_Info.ROffset = Rel_Offset
- if Section_Info.Header.Type == 0:
- break
- # The final Section in parent Section does not need to add padding, else must be 4-bytes align with parent Section start offset
- Pad_Size = 0
- if (Rel_Offset+Section_Info.HeaderLength+len(Section_Info.Data) != Data_Size):
- Pad_Size = GetPadSize(Section_Info.Size, SECTION_COMMON_ALIGNMENT)
- Section_Info.PadData = Pad_Size * b'\x00'
- if Section_Info.Header.Type == 0x02:
- Section_Info.DOffset = Section_Offset + Section_Info.ExtHeader.DataOffset + Rel_Whole_Offset
- Section_Info.Data = Whole_Data[Rel_Offset+Section_Info.ExtHeader.DataOffset: Rel_Offset+Section_Info.Size]
- if Section_Info.Header.Type == 0x14:
- ParTree.Data.Version = Section_Info.ExtHeader.GetVersionString()
- if Section_Info.Header.Type == 0x15:
- ParTree.Data.UiName = Section_Info.ExtHeader.GetUiString()
- if Section_Info.Header.Type == 0x19:
- if Section_Info.Data.replace(b'\x00', b'') == b'':
- Section_Info.IsPadSection = True
- Section_Offset += Section_Info.Size + Pad_Size
- Rel_Offset += Section_Info.Size + Pad_Size
- Section_Tree.Data = Section_Info
- ParTree.insertChild(Section_Tree)
-
-class FfsProduct(BinaryProduct):
- # ParserFFs / GetSection
- def ParserData(self, ParTree, Whole_Data: bytes, Rel_Whole_Offset: int=0) -> None:
- Rel_Offset = 0
- Section_Offset = 0
- # Get the Data from parent tree, if do not have the tree then get it from the whole_data.
- if ParTree.Data != None:
- Data_Size = len(ParTree.Data.Data)
- Section_Offset = ParTree.Data.DOffset
- Whole_Data = ParTree.Data.Data
- else:
- Data_Size = len(Whole_Data)
- # Parser all the data to collect all the Section recorded in Ffs.
- while Rel_Offset < Data_Size:
- # Create a SectionNode and set it as the SectionTree's Data
- Section_Info = SectionNode(Whole_Data[Rel_Offset:])
- Section_Tree = BIOSTREE(Section_Info.Name)
- Section_Tree.type = SECTION_TREE
- Section_Info.Data = Whole_Data[Rel_Offset+Section_Info.HeaderLength: Rel_Offset+Section_Info.Size]
- Section_Info.DOffset = Section_Offset + Section_Info.HeaderLength + Rel_Whole_Offset
- Section_Info.HOffset = Section_Offset + Rel_Whole_Offset
- Section_Info.ROffset = Rel_Offset
- if Section_Info.Header.Type == 0:
- break
- # The final Section in Ffs does not need to add padding, else must be 4-bytes align with Ffs start offset
- Pad_Size = 0
- if (Rel_Offset+Section_Info.HeaderLength+len(Section_Info.Data) != Data_Size):
- Pad_Size = GetPadSize(Section_Info.Size, SECTION_COMMON_ALIGNMENT)
- Section_Info.PadData = Pad_Size * b'\x00'
- if Section_Info.Header.Type == 0x02:
- Section_Info.DOffset = Section_Offset + Section_Info.ExtHeader.DataOffset + Rel_Whole_Offset
- Section_Info.Data = Whole_Data[Rel_Offset+Section_Info.ExtHeader.DataOffset: Rel_Offset+Section_Info.Size]
- # If Section is Version or UI type, it saves the version and UI info of its parent Ffs.
- if Section_Info.Header.Type == 0x14:
- ParTree.Data.Version = Section_Info.ExtHeader.GetVersionString()
- if Section_Info.Header.Type == 0x15:
- ParTree.Data.UiName = Section_Info.ExtHeader.GetUiString()
- if Section_Info.Header.Type == 0x19:
- if Section_Info.Data.replace(b'\x00', b'') == b'':
- Section_Info.IsPadSection = True
- Section_Offset += Section_Info.Size + Pad_Size
- Rel_Offset += Section_Info.Size + Pad_Size
- Section_Tree.Data = Section_Info
- ParTree.insertChild(Section_Tree)
-
-class FvProduct(BinaryProduct):
- ## ParserFv / GetFfs
- def ParserData(self, ParTree, Whole_Data: bytes, Rel_Whole_Offset: int=0) -> None:
- Ffs_Offset = 0
- Rel_Offset = 0
- # Get the Data from parent tree, if do not have the tree then get it from the whole_data.
- if ParTree.Data != None:
- Data_Size = len(ParTree.Data.Data)
- Ffs_Offset = ParTree.Data.DOffset
- Whole_Data = ParTree.Data.Data
- else:
- Data_Size = len(Whole_Data)
- # Parser all the data to collect all the Ffs recorded in Fv.
- while Rel_Offset < Data_Size:
- # Create a FfsNode and set it as the FFsTree's Data
- if Data_Size - Rel_Offset < 24:
- Ffs_Tree = BIOSTREE('Free_Space')
- Ffs_Tree.type = FFS_FREE_SPACE
- Ffs_Tree.Data = FreeSpaceNode(Whole_Data[Rel_Offset:])
- Ffs_Tree.Data.HOffset = Ffs_Offset + Rel_Whole_Offset
- Ffs_Tree.Data.DOffset = Ffs_Tree.Data.HOffset
- ParTree.Data.Free_Space = Data_Size - Rel_Offset
- ParTree.insertChild(Ffs_Tree)
- Rel_Offset = Data_Size
- else:
- Ffs_Info = FfsNode(Whole_Data[Rel_Offset:])
- Ffs_Tree = BIOSTREE(Ffs_Info.Name)
- Ffs_Info.HOffset = Ffs_Offset + Rel_Whole_Offset
- Ffs_Info.DOffset = Ffs_Offset + Ffs_Info.Header.HeaderLength + Rel_Whole_Offset
- Ffs_Info.ROffset = Rel_Offset
- if Ffs_Info.Name == PADVECTOR:
- Ffs_Tree.type = FFS_PAD
- Ffs_Info.Data = Whole_Data[Rel_Offset+Ffs_Info.Header.HeaderLength: Rel_Offset+Ffs_Info.Size]
- Ffs_Info.Size = len(Ffs_Info.Data) + Ffs_Info.Header.HeaderLength
- # if current Ffs is the final ffs of Fv and full of b'\xff', define it with Free_Space
- if struct2stream(Ffs_Info.Header).replace(b'\xff', b'') == b'':
- Ffs_Tree.type = FFS_FREE_SPACE
- Ffs_Info.Data = Whole_Data[Rel_Offset:]
- Ffs_Info.Size = len(Ffs_Info.Data)
- ParTree.Data.Free_Space = Ffs_Info.Size
- else:
- Ffs_Tree.type = FFS_TREE
- Ffs_Info.Data = Whole_Data[Rel_Offset+Ffs_Info.Header.HeaderLength: Rel_Offset+Ffs_Info.Size]
- # The final Ffs in Fv does not need to add padding, else must be 8-bytes align with Fv start offset
- Pad_Size = 0
- if Ffs_Tree.type != FFS_FREE_SPACE and (Rel_Offset+Ffs_Info.Header.HeaderLength+len(Ffs_Info.Data) != Data_Size):
- Pad_Size = GetPadSize(Ffs_Info.Size, FFS_COMMON_ALIGNMENT)
- Ffs_Info.PadData = Pad_Size * b'\xff'
- Ffs_Offset += Ffs_Info.Size + Pad_Size
- Rel_Offset += Ffs_Info.Size + Pad_Size
- Ffs_Tree.Data = Ffs_Info
- ParTree.insertChild(Ffs_Tree)
-
-class FdProduct(BinaryProduct):
- type = [ROOT_FV_TREE, ROOT_TREE]
-
- ## Create DataTree with first level /fv Info, then parser each Fv.
- def ParserData(self, WholeFvTree, whole_data: bytes=b'', offset: int=0) -> None:
- # Get all Fv image in Fd with offset and length
- Fd_Struct = self.GetFvFromFd(whole_data)
- data_size = len(whole_data)
- Binary_count = 0
- global Fv_count
- # If the first Fv image is the Binary Fv, add it into the tree.
- if Fd_Struct[0][1] != 0:
- Binary_node = BIOSTREE('BINARY'+ str(Binary_count))
- Binary_node.type = BINARY_DATA
- Binary_node.Data = BinaryNode(str(Binary_count))
- Binary_node.Data.Data = whole_data[:Fd_Struct[0][1]]
- Binary_node.Data.Size = len(Binary_node.Data.Data)
- Binary_node.Data.HOffset = 0 + offset
- WholeFvTree.insertChild(Binary_node)
- Binary_count += 1
- # Add the first collected Fv image into the tree.
- Cur_node = BIOSTREE(Fd_Struct[0][0]+ str(Fv_count))
- Cur_node.type = Fd_Struct[0][0]
- Cur_node.Data = FvNode(Fv_count, whole_data[Fd_Struct[0][1]:Fd_Struct[0][1]+Fd_Struct[0][2][0]])
- Cur_node.Data.HOffset = Fd_Struct[0][1] + offset
- Cur_node.Data.DOffset = Cur_node.Data.HOffset+Cur_node.Data.Header.HeaderLength
- Cur_node.Data.Data = whole_data[Fd_Struct[0][1]+Cur_node.Data.Header.HeaderLength:Fd_Struct[0][1]+Cur_node.Data.Size]
- WholeFvTree.insertChild(Cur_node)
- Fv_count += 1
- Fv_num = len(Fd_Struct)
- # Add all the collected Fv image and the Binary Fv image between them into the tree.
- for i in range(Fv_num-1):
- if Fd_Struct[i][1]+Fd_Struct[i][2][0] != Fd_Struct[i+1][1]:
- Binary_node = BIOSTREE('BINARY'+ str(Binary_count))
- Binary_node.type = BINARY_DATA
- Binary_node.Data = BinaryNode(str(Binary_count))
- Binary_node.Data.Data = whole_data[Fd_Struct[i][1]+Fd_Struct[i][2][0]:Fd_Struct[i+1][1]]
- Binary_node.Data.Size = len(Binary_node.Data.Data)
- Binary_node.Data.HOffset = Fd_Struct[i][1]+Fd_Struct[i][2][0] + offset
- WholeFvTree.insertChild(Binary_node)
- Binary_count += 1
- Cur_node = BIOSTREE(Fd_Struct[i+1][0]+ str(Fv_count))
- Cur_node.type = Fd_Struct[i+1][0]
- Cur_node.Data = FvNode(Fv_count, whole_data[Fd_Struct[i+1][1]:Fd_Struct[i+1][1]+Fd_Struct[i+1][2][0]])
- Cur_node.Data.HOffset = Fd_Struct[i+1][1] + offset
- Cur_node.Data.DOffset = Cur_node.Data.HOffset+Cur_node.Data.Header.HeaderLength
- Cur_node.Data.Data = whole_data[Fd_Struct[i+1][1]+Cur_node.Data.Header.HeaderLength:Fd_Struct[i+1][1]+Cur_node.Data.Size]
- WholeFvTree.insertChild(Cur_node)
- Fv_count += 1
- # If the final Fv image is the Binary Fv, add it into the tree
- if Fd_Struct[-1][1] + Fd_Struct[-1][2][0] != data_size:
- Binary_node = BIOSTREE('BINARY'+ str(Binary_count))
- Binary_node.type = BINARY_DATA
- Binary_node.Data = BinaryNode(str(Binary_count))
- Binary_node.Data.Data = whole_data[Fd_Struct[-1][1]+Fd_Struct[-1][2][0]:]
- Binary_node.Data.Size = len(Binary_node.Data.Data)
- Binary_node.Data.HOffset = Fd_Struct[-1][1]+Fd_Struct[-1][2][0] + offset
- WholeFvTree.insertChild(Binary_node)
- Binary_count += 1
-
- ## Get the first level Fv from Fd file.
- def GetFvFromFd(self, whole_data: bytes=b'') -> list:
- Fd_Struct = []
- data_size = len(whole_data)
- cur_index = 0
- # Get all the EFI_FIRMWARE_FILE_SYSTEM2_GUID_BYTE FV image offset and length.
- while cur_index < data_size:
- if EFI_FIRMWARE_FILE_SYSTEM2_GUID_BYTE in whole_data[cur_index:]:
- target_index = whole_data[cur_index:].index(EFI_FIRMWARE_FILE_SYSTEM2_GUID_BYTE) + cur_index
- if whole_data[target_index+24:target_index+28] == FVH_SIGNATURE:
- Fd_Struct.append([FV_TREE, target_index - 16, unpack("Q", whole_data[target_index+16:target_index+24])])
- cur_index = Fd_Struct[-1][1] + Fd_Struct[-1][2][0]
- else:
- cur_index = target_index + 16
- else:
- cur_index = data_size
- cur_index = 0
- # Get all the EFI_FIRMWARE_FILE_SYSTEM3_GUID_BYTE FV image offset and length.
- while cur_index < data_size:
- if EFI_FIRMWARE_FILE_SYSTEM3_GUID_BYTE in whole_data[cur_index:]:
- target_index = whole_data[cur_index:].index(EFI_FIRMWARE_FILE_SYSTEM3_GUID_BYTE) + cur_index
- if whole_data[target_index+24:target_index+28] == FVH_SIGNATURE:
- Fd_Struct.append([FV_TREE, target_index - 16, unpack("Q", whole_data[target_index+16:target_index+24])])
- cur_index = Fd_Struct[-1][1] + Fd_Struct[-1][2][0]
- else:
- cur_index = target_index + 16
- else:
- cur_index = data_size
- cur_index = 0
- # Get all the EFI_SYSTEM_NVDATA_FV_GUID_BYTE FV image offset and length.
- while cur_index < data_size:
- if EFI_SYSTEM_NVDATA_FV_GUID_BYTE in whole_data[cur_index:]:
- target_index = whole_data[cur_index:].index(EFI_SYSTEM_NVDATA_FV_GUID_BYTE) + cur_index
- if whole_data[target_index+24:target_index+28] == FVH_SIGNATURE:
- Fd_Struct.append([DATA_FV_TREE, target_index - 16, unpack("Q", whole_data[target_index+16:target_index+24])])
- cur_index = Fd_Struct[-1][1] + Fd_Struct[-1][2][0]
- else:
- cur_index = target_index + 16
- else:
- cur_index = data_size
- # Sort all the collect Fv image with offset.
- Fd_Struct.sort(key=lambda x:x[1])
- tmp_struct = copy.deepcopy(Fd_Struct)
- tmp_index = 0
- Fv_num = len(Fd_Struct)
- # Remove the Fv image included in another Fv image.
- for i in range(1,Fv_num):
- if tmp_struct[i][1]+tmp_struct[i][2][0] < tmp_struct[i-1][1]+tmp_struct[i-1][2][0]:
- Fd_Struct.remove(Fd_Struct[i-tmp_index])
- tmp_index += 1
- return Fd_Struct
-
-class ElfSectionProduct(BinaryProduct):
- ## Decompress the compressed section.
- def ParserData(self, Section_Tree, whole_Data: bytes, Rel_Whole_Offset: int=0) -> None:
- pass
- def ParserSectionData(self, Section_Tree, whole_Data: bytes, Rel_Whole_Offset: int=0) -> None:
- pass
- def ParserProgramData(self, Section_Tree, whole_Data: bytes, Rel_Whole_Offset: int=0) -> None:
- pass
-
-class ElfProduct(BinaryProduct):
-
- def ParserData(self, ParTree, Whole_Data: bytes, Rel_Whole_Offset: int=0) -> None:
- Elf_Info = ElfNode(Whole_Data)
- if Elf_Info.Header.ELF_PHOff != 0:
- Elf_Info.GetProgramList(Whole_Data[Elf_Info.Header.ELF_PHOff:])
- if Elf_Info.Header.ELF_SHOff != 0:
- Elf_Info.GetSectionList(Whole_Data[Elf_Info.Header.ELF_SHOff:])
- Elf_Info.FindUPLDSection(Whole_Data)
- Elf_Tree = BIOSTREE(Elf_Info.Name)
- Elf_Tree.type = ELF_TREE
- Elf_Info.Data = Whole_Data[Elf_Info.HeaderLength:]
- Elf_Tree.Data = Elf_Info
- ParTree.insertChild(Elf_Tree)
-
-class ParserEntry():
- FactoryTable:dict = {
- SECTION_TREE: SectionFactory,
- ROOT_SECTION_TREE: FfsFactory,
- FFS_TREE: FfsFactory,
- ROOT_FFS_TREE: FvFactory,
- FV_TREE: FvFactory,
- SEC_FV_TREE: FvFactory,
- ROOT_FV_TREE: FdFactory,
- ROOT_TREE: FdFactory,
- ROOT_ELF_TREE: ElfFactory,
- }
-
- def GetTargetFactory(self, Tree_type: str) -> BinaryFactory:
- if Tree_type in self.FactoryTable:
- return self.FactoryTable[Tree_type]
-
- def Generate_Product(self, TargetFactory: BinaryFactory, Tree, Data: bytes, Offset: int) -> None:
- New_Product = TargetFactory.Create_Product()
- New_Product.ParserData(Tree, Data, Offset)
-
- def DataParser(self, Tree, Data: bytes, Offset: int) -> None:
- TargetFactory = self.GetTargetFactory(Tree.type)
- if TargetFactory:
- self.Generate_Product(TargetFactory, Tree, Data, Offset)
+## @file +# This file is used to implement of the various bianry parser. +# +# Copyright (c) 2021-, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +from re import T +import copy +import os +import sys +from FirmwareStorageFormat.Common import * +from core.BiosTreeNode import * +from core.BiosTree import * +from core.GuidTools import GUIDTools +from utils.FmmtLogger import FmmtLogger as logger + +ROOT_TREE = 'ROOT' +ROOT_ELF_TREE = 'ROOT_ELF_TREE' +ROOT_FV_TREE = 'ROOT_FV_TREE' +ROOT_FFS_TREE = 'ROOT_FFS_TREE' +ROOT_SECTION_TREE = 'ROOT_SECTION_TREE' + +ELF_TREE = 'ELF' +ELF_SECTION_TREE = 'ELF_SECTION_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' +Fv_count = 0 + +## Abstract factory +class BinaryFactory(): + type:list = [] + + def Create_Product(): + pass + +class BinaryProduct(): + ## Use GuidTool to decompress data. + def DeCompressData(self, GuidTool, Section_Data: bytes, FileName) -> bytes: + guidtool = GUIDTools().__getitem__(struct2stream(GuidTool)) + if not guidtool.ifexist: + logger.error("GuidTool {} is not found when decompressing {} file.\n".format(guidtool.command, FileName)) + raise Exception("Process Failed: GuidTool not found!") + DecompressedData = guidtool.unpack(Section_Data) + return DecompressedData + + def ParserData(): + pass + +class ElfFactory(BinaryFactory): + type = [ROOT_ELF_TREE, ELF_TREE] + + def Create_Product(): + return ElfProduct() + +class SectionFactory(BinaryFactory): + type = [SECTION_TREE] + + def Create_Product(): + return SectionProduct() + +class FfsFactory(BinaryFactory): + type = [ROOT_SECTION_TREE, FFS_TREE] + + def Create_Product(): + return FfsProduct() + +class FvFactory(BinaryFactory): + type = [ROOT_FFS_TREE, FV_TREE, SEC_FV_TREE] + + def Create_Product(): + return FvProduct() + +class FdFactory(BinaryFactory): + type = [ROOT_FV_TREE, ROOT_TREE] + + def Create_Product(): + return FdProduct() + +class SectionProduct(BinaryProduct): + ## Decompress the compressed section. + def ParserData(self, Section_Tree, whole_Data: bytes, Rel_Whole_Offset: int=0) -> None: + if Section_Tree.Data.Type == 0x01: + Section_Tree.Data.OriData = Section_Tree.Data.Data + self.ParserSection(Section_Tree, b'') + # Guided Define Section + elif Section_Tree.Data.Type == 0x02: + Section_Tree.Data.OriData = Section_Tree.Data.Data + DeCompressGuidTool = Section_Tree.Data.ExtHeader.SectionDefinitionGuid + Section_Tree.Data.Data = self.DeCompressData(DeCompressGuidTool, Section_Tree.Data.Data, Section_Tree.Parent.Data.Name) + Section_Tree.Data.Size = len(Section_Tree.Data.Data) + Section_Tree.Data.HeaderLength + self.ParserSection(Section_Tree, b'') + elif Section_Tree.Data.Type == 0x03: + Section_Tree.Data.OriData = Section_Tree.Data.Data + self.ParserSection(Section_Tree, b'') + # SEC_FV Section + elif Section_Tree.Data.Type == 0x17: + global Fv_count + Sec_Fv_Info = FvNode(Fv_count, Section_Tree.Data.Data) + Sec_Fv_Tree = BIOSTREE('FV'+ str(Fv_count)) + Sec_Fv_Tree.type = SEC_FV_TREE + Sec_Fv_Tree.Data = Sec_Fv_Info + Sec_Fv_Tree.Data.HOffset = Section_Tree.Data.DOffset + Sec_Fv_Tree.Data.DOffset = Sec_Fv_Tree.Data.HOffset + Sec_Fv_Tree.Data.Header.HeaderLength + Sec_Fv_Tree.Data.Data = Section_Tree.Data.Data[Sec_Fv_Tree.Data.Header.HeaderLength:] + Section_Tree.insertChild(Sec_Fv_Tree) + Fv_count += 1 + + def ParserSection(self, ParTree, Whole_Data: bytes, Rel_Whole_Offset: int=0) -> None: + Rel_Offset = 0 + Section_Offset = 0 + # Get the Data from parent tree, if do not have the tree then get it from the whole_data. + if ParTree.Data != None: + Data_Size = len(ParTree.Data.Data) + Section_Offset = ParTree.Data.DOffset + Whole_Data = ParTree.Data.Data + else: + Data_Size = len(Whole_Data) + # Parser all the data to collect all the Section recorded in its Parent Section. + while Rel_Offset < Data_Size: + # Create a SectionNode and set it as the SectionTree's Data + Section_Info = SectionNode(Whole_Data[Rel_Offset:]) + Section_Tree = BIOSTREE(Section_Info.Name) + Section_Tree.type = SECTION_TREE + Section_Info.Data = Whole_Data[Rel_Offset+Section_Info.HeaderLength: Rel_Offset+Section_Info.Size] + Section_Info.DOffset = Section_Offset + Section_Info.HeaderLength + Rel_Whole_Offset + Section_Info.HOffset = Section_Offset + Rel_Whole_Offset + Section_Info.ROffset = Rel_Offset + if Section_Info.Header.Type == 0: + break + # The final Section in parent Section does not need to add padding, else must be 4-bytes align with parent Section start offset + Pad_Size = 0 + if (Rel_Offset+Section_Info.HeaderLength+len(Section_Info.Data) != Data_Size): + Pad_Size = GetPadSize(Section_Info.Size, SECTION_COMMON_ALIGNMENT) + Section_Info.PadData = Pad_Size * b'\x00' + if Section_Info.Header.Type == 0x02: + Section_Info.DOffset = Section_Offset + Section_Info.ExtHeader.DataOffset + Rel_Whole_Offset + Section_Info.Data = Whole_Data[Rel_Offset+Section_Info.ExtHeader.DataOffset: Rel_Offset+Section_Info.Size] + if Section_Info.Header.Type == 0x14: + ParTree.Data.Version = Section_Info.ExtHeader.GetVersionString() + if Section_Info.Header.Type == 0x15: + ParTree.Data.UiName = Section_Info.ExtHeader.GetUiString() + if Section_Info.Header.Type == 0x19: + if Section_Info.Data.replace(b'\x00', b'') == b'': + Section_Info.IsPadSection = True + Section_Offset += Section_Info.Size + Pad_Size + Rel_Offset += Section_Info.Size + Pad_Size + Section_Tree.Data = Section_Info + ParTree.insertChild(Section_Tree) + +class FfsProduct(BinaryProduct): + # ParserFFs / GetSection + def ParserData(self, ParTree, Whole_Data: bytes, Rel_Whole_Offset: int=0) -> None: + Rel_Offset = 0 + Section_Offset = 0 + # Get the Data from parent tree, if do not have the tree then get it from the whole_data. + if ParTree.Data != None: + Data_Size = len(ParTree.Data.Data) + Section_Offset = ParTree.Data.DOffset + Whole_Data = ParTree.Data.Data + else: + Data_Size = len(Whole_Data) + # Parser all the data to collect all the Section recorded in Ffs. + while Rel_Offset < Data_Size: + # Create a SectionNode and set it as the SectionTree's Data + Section_Info = SectionNode(Whole_Data[Rel_Offset:]) + Section_Tree = BIOSTREE(Section_Info.Name) + Section_Tree.type = SECTION_TREE + Section_Info.Data = Whole_Data[Rel_Offset+Section_Info.HeaderLength: Rel_Offset+Section_Info.Size] + Section_Info.DOffset = Section_Offset + Section_Info.HeaderLength + Rel_Whole_Offset + Section_Info.HOffset = Section_Offset + Rel_Whole_Offset + Section_Info.ROffset = Rel_Offset + if Section_Info.Header.Type == 0: + break + # The final Section in Ffs does not need to add padding, else must be 4-bytes align with Ffs start offset + Pad_Size = 0 + if (Rel_Offset+Section_Info.HeaderLength+len(Section_Info.Data) != Data_Size): + Pad_Size = GetPadSize(Section_Info.Size, SECTION_COMMON_ALIGNMENT) + Section_Info.PadData = Pad_Size * b'\x00' + if Section_Info.Header.Type == 0x02: + Section_Info.DOffset = Section_Offset + Section_Info.ExtHeader.DataOffset + Rel_Whole_Offset + Section_Info.Data = Whole_Data[Rel_Offset+Section_Info.ExtHeader.DataOffset: Rel_Offset+Section_Info.Size] + # If Section is Version or UI type, it saves the version and UI info of its parent Ffs. + if Section_Info.Header.Type == 0x14: + ParTree.Data.Version = Section_Info.ExtHeader.GetVersionString() + if Section_Info.Header.Type == 0x15: + ParTree.Data.UiName = Section_Info.ExtHeader.GetUiString() + if Section_Info.Header.Type == 0x19: + if Section_Info.Data.replace(b'\x00', b'') == b'': + Section_Info.IsPadSection = True + Section_Offset += Section_Info.Size + Pad_Size + Rel_Offset += Section_Info.Size + Pad_Size + Section_Tree.Data = Section_Info + ParTree.insertChild(Section_Tree) + +class FvProduct(BinaryProduct): + ## ParserFv / GetFfs + def ParserData(self, ParTree, Whole_Data: bytes, Rel_Whole_Offset: int=0) -> None: + Ffs_Offset = 0 + Rel_Offset = 0 + # Get the Data from parent tree, if do not have the tree then get it from the whole_data. + if ParTree.Data != None: + Data_Size = len(ParTree.Data.Data) + Ffs_Offset = ParTree.Data.DOffset + Whole_Data = ParTree.Data.Data + else: + Data_Size = len(Whole_Data) + # Parser all the data to collect all the Ffs recorded in Fv. + while Rel_Offset < Data_Size: + # Create a FfsNode and set it as the FFsTree's Data + if Data_Size - Rel_Offset < 24: + Ffs_Tree = BIOSTREE('Free_Space') + Ffs_Tree.type = FFS_FREE_SPACE + Ffs_Tree.Data = FreeSpaceNode(Whole_Data[Rel_Offset:]) + Ffs_Tree.Data.HOffset = Ffs_Offset + Rel_Whole_Offset + Ffs_Tree.Data.DOffset = Ffs_Tree.Data.HOffset + ParTree.Data.Free_Space = Data_Size - Rel_Offset + ParTree.insertChild(Ffs_Tree) + Rel_Offset = Data_Size + else: + Ffs_Info = FfsNode(Whole_Data[Rel_Offset:]) + Ffs_Tree = BIOSTREE(Ffs_Info.Name) + Ffs_Info.HOffset = Ffs_Offset + Rel_Whole_Offset + Ffs_Info.DOffset = Ffs_Offset + Ffs_Info.Header.HeaderLength + Rel_Whole_Offset + Ffs_Info.ROffset = Rel_Offset + if Ffs_Info.Name == PADVECTOR: + Ffs_Tree.type = FFS_PAD + Ffs_Info.Data = Whole_Data[Rel_Offset+Ffs_Info.Header.HeaderLength: Rel_Offset+Ffs_Info.Size] + Ffs_Info.Size = len(Ffs_Info.Data) + Ffs_Info.Header.HeaderLength + # if current Ffs is the final ffs of Fv and full of b'\xff', define it with Free_Space + if struct2stream(Ffs_Info.Header).replace(b'\xff', b'') == b'': + Ffs_Tree.type = FFS_FREE_SPACE + Ffs_Info.Data = Whole_Data[Rel_Offset:] + Ffs_Info.Size = len(Ffs_Info.Data) + ParTree.Data.Free_Space = Ffs_Info.Size + else: + Ffs_Tree.type = FFS_TREE + Ffs_Info.Data = Whole_Data[Rel_Offset+Ffs_Info.Header.HeaderLength: Rel_Offset+Ffs_Info.Size] + # The final Ffs in Fv does not need to add padding, else must be 8-bytes align with Fv start offset + Pad_Size = 0 + if Ffs_Tree.type != FFS_FREE_SPACE and (Rel_Offset+Ffs_Info.Header.HeaderLength+len(Ffs_Info.Data) != Data_Size): + Pad_Size = GetPadSize(Ffs_Info.Size, FFS_COMMON_ALIGNMENT) + Ffs_Info.PadData = Pad_Size * b'\xff' + Ffs_Offset += Ffs_Info.Size + Pad_Size + Rel_Offset += Ffs_Info.Size + Pad_Size + Ffs_Tree.Data = Ffs_Info + ParTree.insertChild(Ffs_Tree) + +class FdProduct(BinaryProduct): + type = [ROOT_FV_TREE, ROOT_TREE] + + ## Create DataTree with first level /fv Info, then parser each Fv. + def ParserData(self, WholeFvTree, whole_data: bytes=b'', offset: int=0) -> None: + # Get all Fv image in Fd with offset and length + Fd_Struct = self.GetFvFromFd(whole_data) + data_size = len(whole_data) + Binary_count = 0 + global Fv_count + # If the first Fv image is the Binary Fv, add it into the tree. + if Fd_Struct[0][1] != 0: + Binary_node = BIOSTREE('BINARY'+ str(Binary_count)) + Binary_node.type = BINARY_DATA + Binary_node.Data = BinaryNode(str(Binary_count)) + Binary_node.Data.Data = whole_data[:Fd_Struct[0][1]] + Binary_node.Data.Size = len(Binary_node.Data.Data) + Binary_node.Data.HOffset = 0 + offset + WholeFvTree.insertChild(Binary_node) + Binary_count += 1 + # Add the first collected Fv image into the tree. + Cur_node = BIOSTREE(Fd_Struct[0][0]+ str(Fv_count)) + Cur_node.type = Fd_Struct[0][0] + Cur_node.Data = FvNode(Fv_count, whole_data[Fd_Struct[0][1]:Fd_Struct[0][1]+Fd_Struct[0][2][0]]) + Cur_node.Data.HOffset = Fd_Struct[0][1] + offset + Cur_node.Data.DOffset = Cur_node.Data.HOffset+Cur_node.Data.Header.HeaderLength + Cur_node.Data.Data = whole_data[Fd_Struct[0][1]+Cur_node.Data.Header.HeaderLength:Fd_Struct[0][1]+Cur_node.Data.Size] + WholeFvTree.insertChild(Cur_node) + Fv_count += 1 + Fv_num = len(Fd_Struct) + # Add all the collected Fv image and the Binary Fv image between them into the tree. + for i in range(Fv_num-1): + if Fd_Struct[i][1]+Fd_Struct[i][2][0] != Fd_Struct[i+1][1]: + Binary_node = BIOSTREE('BINARY'+ str(Binary_count)) + Binary_node.type = BINARY_DATA + Binary_node.Data = BinaryNode(str(Binary_count)) + Binary_node.Data.Data = whole_data[Fd_Struct[i][1]+Fd_Struct[i][2][0]:Fd_Struct[i+1][1]] + Binary_node.Data.Size = len(Binary_node.Data.Data) + Binary_node.Data.HOffset = Fd_Struct[i][1]+Fd_Struct[i][2][0] + offset + WholeFvTree.insertChild(Binary_node) + Binary_count += 1 + Cur_node = BIOSTREE(Fd_Struct[i+1][0]+ str(Fv_count)) + Cur_node.type = Fd_Struct[i+1][0] + Cur_node.Data = FvNode(Fv_count, whole_data[Fd_Struct[i+1][1]:Fd_Struct[i+1][1]+Fd_Struct[i+1][2][0]]) + Cur_node.Data.HOffset = Fd_Struct[i+1][1] + offset + Cur_node.Data.DOffset = Cur_node.Data.HOffset+Cur_node.Data.Header.HeaderLength + Cur_node.Data.Data = whole_data[Fd_Struct[i+1][1]+Cur_node.Data.Header.HeaderLength:Fd_Struct[i+1][1]+Cur_node.Data.Size] + WholeFvTree.insertChild(Cur_node) + Fv_count += 1 + # If the final Fv image is the Binary Fv, add it into the tree + if Fd_Struct[-1][1] + Fd_Struct[-1][2][0] != data_size: + Binary_node = BIOSTREE('BINARY'+ str(Binary_count)) + Binary_node.type = BINARY_DATA + Binary_node.Data = BinaryNode(str(Binary_count)) + Binary_node.Data.Data = whole_data[Fd_Struct[-1][1]+Fd_Struct[-1][2][0]:] + Binary_node.Data.Size = len(Binary_node.Data.Data) + Binary_node.Data.HOffset = Fd_Struct[-1][1]+Fd_Struct[-1][2][0] + offset + WholeFvTree.insertChild(Binary_node) + Binary_count += 1 + + ## Get the first level Fv from Fd file. + def GetFvFromFd(self, whole_data: bytes=b'') -> list: + Fd_Struct = [] + data_size = len(whole_data) + cur_index = 0 + # Get all the EFI_FIRMWARE_FILE_SYSTEM2_GUID_BYTE FV image offset and length. + while cur_index < data_size: + if EFI_FIRMWARE_FILE_SYSTEM2_GUID_BYTE in whole_data[cur_index:]: + target_index = whole_data[cur_index:].index(EFI_FIRMWARE_FILE_SYSTEM2_GUID_BYTE) + cur_index + if whole_data[target_index+24:target_index+28] == FVH_SIGNATURE: + Fd_Struct.append([FV_TREE, target_index - 16, unpack("Q", whole_data[target_index+16:target_index+24])]) + cur_index = Fd_Struct[-1][1] + Fd_Struct[-1][2][0] + else: + cur_index = target_index + 16 + else: + cur_index = data_size + cur_index = 0 + # Get all the EFI_FIRMWARE_FILE_SYSTEM3_GUID_BYTE FV image offset and length. + while cur_index < data_size: + if EFI_FIRMWARE_FILE_SYSTEM3_GUID_BYTE in whole_data[cur_index:]: + target_index = whole_data[cur_index:].index(EFI_FIRMWARE_FILE_SYSTEM3_GUID_BYTE) + cur_index + if whole_data[target_index+24:target_index+28] == FVH_SIGNATURE: + Fd_Struct.append([FV_TREE, target_index - 16, unpack("Q", whole_data[target_index+16:target_index+24])]) + cur_index = Fd_Struct[-1][1] + Fd_Struct[-1][2][0] + else: + cur_index = target_index + 16 + else: + cur_index = data_size + cur_index = 0 + # Get all the EFI_SYSTEM_NVDATA_FV_GUID_BYTE FV image offset and length. + while cur_index < data_size: + if EFI_SYSTEM_NVDATA_FV_GUID_BYTE in whole_data[cur_index:]: + target_index = whole_data[cur_index:].index(EFI_SYSTEM_NVDATA_FV_GUID_BYTE) + cur_index + if whole_data[target_index+24:target_index+28] == FVH_SIGNATURE: + Fd_Struct.append([DATA_FV_TREE, target_index - 16, unpack("Q", whole_data[target_index+16:target_index+24])]) + cur_index = Fd_Struct[-1][1] + Fd_Struct[-1][2][0] + else: + cur_index = target_index + 16 + else: + cur_index = data_size + # Sort all the collect Fv image with offset. + Fd_Struct.sort(key=lambda x:x[1]) + tmp_struct = copy.deepcopy(Fd_Struct) + tmp_index = 0 + Fv_num = len(Fd_Struct) + # Remove the Fv image included in another Fv image. + for i in range(1,Fv_num): + if tmp_struct[i][1]+tmp_struct[i][2][0] < tmp_struct[i-1][1]+tmp_struct[i-1][2][0]: + Fd_Struct.remove(Fd_Struct[i-tmp_index]) + tmp_index += 1 + return Fd_Struct + +class ElfSectionProduct(BinaryProduct): + ## Decompress the compressed section. + def ParserData(self, Section_Tree, whole_Data: bytes, Rel_Whole_Offset: int=0) -> None: + pass + def ParserSectionData(self, Section_Tree, whole_Data: bytes, Rel_Whole_Offset: int=0) -> None: + pass + def ParserProgramData(self, Section_Tree, whole_Data: bytes, Rel_Whole_Offset: int=0) -> None: + pass + +class ElfProduct(BinaryProduct): + + def ParserData(self, ParTree, Whole_Data: bytes, Rel_Whole_Offset: int=0) -> None: + Elf_Info = ElfNode(Whole_Data) + if Elf_Info.Header.ELF_PHOff != 0: + Elf_Info.GetProgramList(Whole_Data[Elf_Info.Header.ELF_PHOff:]) + if Elf_Info.Header.ELF_SHOff != 0: + Elf_Info.GetSectionList(Whole_Data[Elf_Info.Header.ELF_SHOff:]) + Elf_Info.FindUPLDSection(Whole_Data) + Elf_Tree = BIOSTREE(Elf_Info.Name) + Elf_Tree.type = ELF_TREE + Elf_Info.Data = Whole_Data[Elf_Info.HeaderLength:] + Elf_Tree.Data = Elf_Info + ParTree.insertChild(Elf_Tree) + +class ParserEntry(): + FactoryTable:dict = { + SECTION_TREE: SectionFactory, + ROOT_SECTION_TREE: FfsFactory, + FFS_TREE: FfsFactory, + ROOT_FFS_TREE: FvFactory, + FV_TREE: FvFactory, + SEC_FV_TREE: FvFactory, + ROOT_FV_TREE: FdFactory, + ROOT_TREE: FdFactory, + ROOT_ELF_TREE: ElfFactory, + } + + def GetTargetFactory(self, Tree_type: str) -> BinaryFactory: + if Tree_type in self.FactoryTable: + return self.FactoryTable[Tree_type] + + def Generate_Product(self, TargetFactory: BinaryFactory, Tree, Data: bytes, Offset: int) -> None: + New_Product = TargetFactory.Create_Product() + New_Product.ParserData(Tree, Data, Offset) + + def DataParser(self, Tree, Data: bytes, Offset: int) -> None: + TargetFactory = self.GetTargetFactory(Tree.type) + if TargetFactory: + self.Generate_Product(TargetFactory, Tree, Data, Offset) diff --git a/BaseTools/Source/Python/FMMT/core/BiosTree.py b/BaseTools/Source/Python/FMMT/core/BiosTree.py index c5a7b017f4..f776519bd1 100644 --- a/BaseTools/Source/Python/FMMT/core/BiosTree.py +++ b/BaseTools/Source/Python/FMMT/core/BiosTree.py @@ -1,242 +1,242 @@ -## @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
+## @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 diff --git a/BaseTools/Source/Python/FMMT/core/BiosTreeNode.py b/BaseTools/Source/Python/FMMT/core/BiosTreeNode.py index 5ca4c20dc6..ba6a027c40 100644 --- a/BaseTools/Source/Python/FMMT/core/BiosTreeNode.py +++ b/BaseTools/Source/Python/FMMT/core/BiosTreeNode.py @@ -1,248 +1,248 @@ -## @file
-# This file is used to define the BIOS Tree Node.
-#
-# Copyright (c) 2021-, Intel Corporation. All rights reserved.<BR>
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-##
-from FirmwareStorageFormat.UPLHeader import *
-from FirmwareStorageFormat.FvHeader import *
-from FirmwareStorageFormat.FfsFileHeader import *
-from FirmwareStorageFormat.SectionHeader import *
-from FirmwareStorageFormat.Common import *
-from utils.FmmtLogger import FmmtLogger as logger
-import uuid
-
-SectionHeaderType = {
- 0x01:'EFI_COMPRESSION_SECTION',
- 0x02:'EFI_GUID_DEFINED_SECTION',
- 0x03:'EFI_SECTION_DISPOSABLE',
- 0x10:'EFI_SECTION_PE32',
- 0x11:'EFI_SECTION_PIC',
- 0x12:'EFI_SECTION_TE',
- 0x13:'EFI_SECTION_DXE_DEPEX',
- 0x14:'EFI_SECTION_VERSION',
- 0x15:'EFI_SECTION_USER_INTERFACE',
- 0x16:'EFI_SECTION_COMPATIBILITY16',
- 0x17:'EFI_SECTION_FIRMWARE_VOLUME_IMAGE',
- 0x18:'EFI_FREEFORM_SUBTYPE_GUID_SECTION',
- 0x19:'EFI_SECTION_RAW',
- 0x1B:'EFI_SECTION_PEI_DEPEX',
- 0x1C:'EFI_SECTION_MM_DEPEX'
-}
-HeaderType = [0x01, 0x02, 0x14, 0x15, 0x18]
-
-class BinaryNode:
- def __init__(self, name: str) -> None:
- self.Size = 0
- self.Name = "BINARY" + str(name)
- self.HOffset = 0
- self.Data = b''
-
-class ElfNode:
- def __init__(self, buffer: bytes) -> None:
- self.Header = ELF_HEADER32.from_buffer_copy(buffer)
- if self.Header.ELF_Identification[0:4] != b'\x7fELF':
- logger.error('Invalid Elf Header! Elf Identification {} is not ".ELF".'.format(self.Header.ELF_Identification))
- raise Exception("Process Failed: Invalid ELF Header Identification!")
- self.Class = self.Header.ELF_Identification[4]
- if self.Class == 0x02:
- self.Header = ELF_HEADER64.from_buffer_copy(buffer)
- elif self.Class != 0x01:
- logger.error('Invalid Elf Class! Elf Class {} is not 0x01 or 0x02.'.format(self.Class))
- raise Exception("Process Failed: Invalid ELF Class!")
-
- self.ProList = []
- self.SecList = []
- self.UpldInfoSection = None
- self.UpldInfo = None
- self.UpldBuffer = b''
- self.Name = "ELF"
- self.HeaderLength = len(struct2stream(self.Header))
- self.HOffset = 0
- self.DOffset = 0
- self.ROffset = 0
- self.Data = b''
- self.PadData = b''
- self.Upld_Info_Align = False
-
- def GetProgramList(self, buffer: bytes) -> None:
- for i in range(self.Header.ELF_PHNum):
- if self.Class == 0x01:
- ElfProgramHeader = ELF_PROGRAM_HEADER32.from_buffer_copy(buffer[i*self.Header.ELF_PHEntSize:])
- elif self.Class == 0x02:
- ElfProgramHeader = ELF_PROGRAM_HEADER64.from_buffer_copy(buffer[i*self.Header.ELF_PHEntSize:])
- self.ProList.append(ElfProgramHeader)
-
- def GetSectionList(self, buffer: bytes) -> None:
- for i in range(self.Header.ELF_SHNum):
- if self.Class == 0x01:
- ElfSectionHeader = ELF_SECTION_HEADER32.from_buffer_copy(buffer[i*self.Header.ELF_SHEntSize:])
- elif self.Class == 0x02:
- ElfSectionHeader = ELF_SECTION_HEADER64.from_buffer_copy(buffer[i*self.Header.ELF_SHEntSize:])
- self.SecList.append(ElfSectionHeader)
-
- def FindUPLDSection(self, buffer: bytes) -> None:
- for item in self.SecList:
- if buffer[item.SH_Offset:item.SH_Offset+4] == b'PLDH' or buffer[item.SH_Offset:item.SH_Offset+4] == b'UPLD':
- self.UpldInfoSection = item
- self.UpldInfo = UNIVERSAL_PAYLOAD_INFO.from_buffer_copy(buffer[item.SH_Offset:item.SH_Offset+item.SH_Size])
- self.UpldBuffer = struct2stream(self.UpldInfo)
- if (self.UpldInfoSection.SH_Offset) % 4 == 0:
- # if (self.UpldInfoSection.SH_Offset - self.Header.ELF_Entry) % 4 == 0:
- self.Upld_Info_Align = True
-
-class FvNode:
- def __init__(self, name, buffer: bytes) -> None:
- self.Header = EFI_FIRMWARE_VOLUME_HEADER.from_buffer_copy(buffer)
- Map_num = (self.Header.HeaderLength - 56)//8
- self.Header = Refine_FV_Header(Map_num).from_buffer_copy(buffer)
- self.FvId = "FV" + str(name)
- self.Name = "FV" + str(name)
- if self.Header.ExtHeaderOffset:
- self.ExtHeader = EFI_FIRMWARE_VOLUME_EXT_HEADER.from_buffer_copy(buffer[self.Header.ExtHeaderOffset:])
- self.Name = uuid.UUID(bytes_le=struct2stream(self.ExtHeader.FvName))
- self.ExtEntryOffset = self.Header.ExtHeaderOffset + 20
- if self.ExtHeader.ExtHeaderSize != 20:
- self.ExtEntryExist = 1
- self.ExtEntry = EFI_FIRMWARE_VOLUME_EXT_ENTRY.from_buffer_copy(buffer[self.ExtEntryOffset:])
- self.ExtTypeExist = 1
- if self.ExtEntry.ExtEntryType == 0x01:
- nums = (self.ExtEntry.ExtEntrySize - 8) // 16
- self.ExtEntry = Refine_FV_EXT_ENTRY_OEM_TYPE_Header(nums).from_buffer_copy(buffer[self.ExtEntryOffset:])
- elif self.ExtEntry.ExtEntryType == 0x02:
- nums = self.ExtEntry.ExtEntrySize - 20
- self.ExtEntry = Refine_FV_EXT_ENTRY_GUID_TYPE_Header(nums).from_buffer_copy(buffer[self.ExtEntryOffset:])
- elif self.ExtEntry.ExtEntryType == 0x03:
- self.ExtEntry = EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE.from_buffer_copy(buffer[self.ExtEntryOffset:])
- else:
- self.ExtTypeExist = 0
- else:
- self.ExtEntryExist = 0
- self.Size = self.Header.FvLength
- self.HeaderLength = self.Header.HeaderLength
- self.HOffset = 0
- self.DOffset = 0
- self.ROffset = 0
- self.Data = b''
- if self.Header.Signature != 1213613663:
- logger.error('Invalid Fv Header! Fv {} signature {} is not "_FVH".'.format(struct2stream(self.Header), self.Header.Signature))
- raise Exception("Process Failed: Fv Header Signature!")
- self.PadData = b''
- self.Free_Space = 0
- self.ModCheckSum()
-
- def ModCheckSum(self) -> None:
- # Fv Header Sums to 0.
- Header = struct2stream(self.Header)[::-1]
- Size = self.HeaderLength // 2
- Sum = 0
- for i in range(Size):
- Sum += int(Header[i*2: i*2 + 2].hex(), 16)
- if Sum & 0xffff:
- self.Header.Checksum = 0x10000 - (Sum - self.Header.Checksum) % 0x10000
-
- def ModFvExt(self) -> None:
- # If used space changes and self.ExtEntry.UsedSize exists, self.ExtEntry.UsedSize need to be changed.
- if self.Header.ExtHeaderOffset and self.ExtEntryExist and self.ExtTypeExist and self.ExtEntry.Hdr.ExtEntryType == 0x03:
- self.ExtEntry.UsedSize = self.Header.FvLength - self.Free_Space
-
- def ModFvSize(self) -> None:
- # If Fv Size changed, self.Header.FvLength and self.Header.BlockMap[i].NumBlocks need to be changed.
- BlockMapNum = len(self.Header.BlockMap)
- for i in range(BlockMapNum):
- if self.Header.BlockMap[i].Length:
- self.Header.BlockMap[i].NumBlocks = self.Header.FvLength // self.Header.BlockMap[i].Length
-
- def ModExtHeaderData(self) -> None:
- if self.Header.ExtHeaderOffset:
- ExtHeaderData = struct2stream(self.ExtHeader)
- ExtHeaderDataOffset = self.Header.ExtHeaderOffset - self.HeaderLength
- self.Data = self.Data[:ExtHeaderDataOffset] + ExtHeaderData + self.Data[ExtHeaderDataOffset+20:]
- if self.Header.ExtHeaderOffset and self.ExtEntryExist:
- ExtHeaderEntryData = struct2stream(self.ExtEntry)
- ExtHeaderEntryDataOffset = self.Header.ExtHeaderOffset + 20 - self.HeaderLength
- self.Data = self.Data[:ExtHeaderEntryDataOffset] + ExtHeaderEntryData + self.Data[ExtHeaderEntryDataOffset+len(ExtHeaderEntryData):]
-
-class FfsNode:
- def __init__(self, buffer: bytes) -> None:
- self.Header = EFI_FFS_FILE_HEADER.from_buffer_copy(buffer)
- # self.Attributes = unpack("<B", buffer[21:22])[0]
- if self.Header.FFS_FILE_SIZE != 0 and self.Header.Attributes != 0xff and self.Header.Attributes & 0x01 == 1:
- logger.error('Error Ffs Header! Ffs {} Header Size and Attributes is not matched!'.format(uuid.UUID(bytes_le=struct2stream(self.Header.Name))))
- raise Exception("Process Failed: Error Ffs Header!")
- if self.Header.FFS_FILE_SIZE == 0 and self.Header.Attributes & 0x01 == 1:
- self.Header = EFI_FFS_FILE_HEADER2.from_buffer_copy(buffer)
- self.Name = uuid.UUID(bytes_le=struct2stream(self.Header.Name))
- self.UiName = b''
- self.Version = b''
- self.Size = self.Header.FFS_FILE_SIZE
- self.HeaderLength = self.Header.HeaderLength
- self.HOffset = 0
- self.DOffset = 0
- self.ROffset = 0
- self.Data = b''
- self.PadData = b''
- self.SectionMaxAlignment = SECTION_COMMON_ALIGNMENT # 4-align
-
- def ModCheckSum(self) -> None:
- HeaderData = struct2stream(self.Header)
- HeaderSum = 0
- for item in HeaderData:
- HeaderSum += item
- HeaderSum -= self.Header.State
- HeaderSum -= self.Header.IntegrityCheck.Checksum.File
- if HeaderSum & 0xff:
- Header = self.Header.IntegrityCheck.Checksum.Header + 0x100 - HeaderSum % 0x100
- self.Header.IntegrityCheck.Checksum.Header = Header % 0x100
-
-class SectionNode:
- def __init__(self, buffer: bytes) -> None:
- if buffer[0:3] != b'\xff\xff\xff':
- self.Header = EFI_COMMON_SECTION_HEADER.from_buffer_copy(buffer)
- else:
- self.Header = EFI_COMMON_SECTION_HEADER2.from_buffer_copy(buffer)
- if self.Header.Type in SectionHeaderType:
- self.Name = SectionHeaderType[self.Header.Type]
- elif self.Header.Type == 0:
- self.Name = "EFI_SECTION_ALL"
- else:
- self.Name = "SECTION"
- if self.Header.Type in HeaderType:
- self.ExtHeader = self.GetExtHeader(self.Header.Type, buffer[self.Header.Common_Header_Size():], (self.Header.SECTION_SIZE-self.Header.Common_Header_Size()))
- self.HeaderLength = self.Header.Common_Header_Size() + self.ExtHeader.ExtHeaderSize()
- else:
- self.ExtHeader = None
- self.HeaderLength = self.Header.Common_Header_Size()
- self.Size = self.Header.SECTION_SIZE
- self.Type = self.Header.Type
- self.HOffset = 0
- self.DOffset = 0
- self.ROffset = 0
- self.Data = b''
- self.OriData = b''
- self.OriHeader = b''
- self.PadData = b''
- self.IsPadSection = False
- self.SectionMaxAlignment = SECTION_COMMON_ALIGNMENT # 4-align
-
- def GetExtHeader(self, Type: int, buffer: bytes, nums: int=0) -> None:
- if Type == 0x01:
- return EFI_COMPRESSION_SECTION.from_buffer_copy(buffer)
- elif Type == 0x02:
- return EFI_GUID_DEFINED_SECTION.from_buffer_copy(buffer)
- elif Type == 0x14:
- return Get_VERSION_Header((nums - 2)//2).from_buffer_copy(buffer)
- elif Type == 0x15:
- return Get_USER_INTERFACE_Header(nums//2).from_buffer_copy(buffer)
- elif Type == 0x18:
- return EFI_FREEFORM_SUBTYPE_GUID_SECTION.from_buffer_copy(buffer)
-
-class FreeSpaceNode:
- def __init__(self, buffer: bytes) -> None:
- self.Name = 'Free_Space'
- self.Data = buffer
- self.Size = len(buffer)
- self.HOffset = 0
- self.DOffset = 0
- self.ROffset = 0
- self.PadData = b''
+## @file +# This file is used to define the BIOS Tree Node. +# +# Copyright (c) 2021-, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +from FirmwareStorageFormat.UPLHeader import * +from FirmwareStorageFormat.FvHeader import * +from FirmwareStorageFormat.FfsFileHeader import * +from FirmwareStorageFormat.SectionHeader import * +from FirmwareStorageFormat.Common import * +from utils.FmmtLogger import FmmtLogger as logger +import uuid + +SectionHeaderType = { + 0x01:'EFI_COMPRESSION_SECTION', + 0x02:'EFI_GUID_DEFINED_SECTION', + 0x03:'EFI_SECTION_DISPOSABLE', + 0x10:'EFI_SECTION_PE32', + 0x11:'EFI_SECTION_PIC', + 0x12:'EFI_SECTION_TE', + 0x13:'EFI_SECTION_DXE_DEPEX', + 0x14:'EFI_SECTION_VERSION', + 0x15:'EFI_SECTION_USER_INTERFACE', + 0x16:'EFI_SECTION_COMPATIBILITY16', + 0x17:'EFI_SECTION_FIRMWARE_VOLUME_IMAGE', + 0x18:'EFI_FREEFORM_SUBTYPE_GUID_SECTION', + 0x19:'EFI_SECTION_RAW', + 0x1B:'EFI_SECTION_PEI_DEPEX', + 0x1C:'EFI_SECTION_MM_DEPEX' +} +HeaderType = [0x01, 0x02, 0x14, 0x15, 0x18] + +class BinaryNode: + def __init__(self, name: str) -> None: + self.Size = 0 + self.Name = "BINARY" + str(name) + self.HOffset = 0 + self.Data = b'' + +class ElfNode: + def __init__(self, buffer: bytes) -> None: + self.Header = ELF_HEADER32.from_buffer_copy(buffer) + if self.Header.ELF_Identification[0:4] != b'\x7fELF': + logger.error('Invalid Elf Header! Elf Identification {} is not ".ELF".'.format(self.Header.ELF_Identification)) + raise Exception("Process Failed: Invalid ELF Header Identification!") + self.Class = self.Header.ELF_Identification[4] + if self.Class == 0x02: + self.Header = ELF_HEADER64.from_buffer_copy(buffer) + elif self.Class != 0x01: + logger.error('Invalid Elf Class! Elf Class {} is not 0x01 or 0x02.'.format(self.Class)) + raise Exception("Process Failed: Invalid ELF Class!") + + self.ProList = [] + self.SecList = [] + self.UpldInfoSection = None + self.UpldInfo = None + self.UpldBuffer = b'' + self.Name = "ELF" + self.HeaderLength = len(struct2stream(self.Header)) + self.HOffset = 0 + self.DOffset = 0 + self.ROffset = 0 + self.Data = b'' + self.PadData = b'' + self.Upld_Info_Align = False + + def GetProgramList(self, buffer: bytes) -> None: + for i in range(self.Header.ELF_PHNum): + if self.Class == 0x01: + ElfProgramHeader = ELF_PROGRAM_HEADER32.from_buffer_copy(buffer[i*self.Header.ELF_PHEntSize:]) + elif self.Class == 0x02: + ElfProgramHeader = ELF_PROGRAM_HEADER64.from_buffer_copy(buffer[i*self.Header.ELF_PHEntSize:]) + self.ProList.append(ElfProgramHeader) + + def GetSectionList(self, buffer: bytes) -> None: + for i in range(self.Header.ELF_SHNum): + if self.Class == 0x01: + ElfSectionHeader = ELF_SECTION_HEADER32.from_buffer_copy(buffer[i*self.Header.ELF_SHEntSize:]) + elif self.Class == 0x02: + ElfSectionHeader = ELF_SECTION_HEADER64.from_buffer_copy(buffer[i*self.Header.ELF_SHEntSize:]) + self.SecList.append(ElfSectionHeader) + + def FindUPLDSection(self, buffer: bytes) -> None: + for item in self.SecList: + if buffer[item.SH_Offset:item.SH_Offset+4] == b'PLDH' or buffer[item.SH_Offset:item.SH_Offset+4] == b'UPLD': + self.UpldInfoSection = item + self.UpldInfo = UNIVERSAL_PAYLOAD_INFO.from_buffer_copy(buffer[item.SH_Offset:item.SH_Offset+item.SH_Size]) + self.UpldBuffer = struct2stream(self.UpldInfo) + if (self.UpldInfoSection.SH_Offset) % 4 == 0: + # if (self.UpldInfoSection.SH_Offset - self.Header.ELF_Entry) % 4 == 0: + self.Upld_Info_Align = True + +class FvNode: + def __init__(self, name, buffer: bytes) -> None: + self.Header = EFI_FIRMWARE_VOLUME_HEADER.from_buffer_copy(buffer) + Map_num = (self.Header.HeaderLength - 56)//8 + self.Header = Refine_FV_Header(Map_num).from_buffer_copy(buffer) + self.FvId = "FV" + str(name) + self.Name = "FV" + str(name) + if self.Header.ExtHeaderOffset: + self.ExtHeader = EFI_FIRMWARE_VOLUME_EXT_HEADER.from_buffer_copy(buffer[self.Header.ExtHeaderOffset:]) + self.Name = uuid.UUID(bytes_le=struct2stream(self.ExtHeader.FvName)) + self.ExtEntryOffset = self.Header.ExtHeaderOffset + 20 + if self.ExtHeader.ExtHeaderSize != 20: + self.ExtEntryExist = 1 + self.ExtEntry = EFI_FIRMWARE_VOLUME_EXT_ENTRY.from_buffer_copy(buffer[self.ExtEntryOffset:]) + self.ExtTypeExist = 1 + if self.ExtEntry.ExtEntryType == 0x01: + nums = (self.ExtEntry.ExtEntrySize - 8) // 16 + self.ExtEntry = Refine_FV_EXT_ENTRY_OEM_TYPE_Header(nums).from_buffer_copy(buffer[self.ExtEntryOffset:]) + elif self.ExtEntry.ExtEntryType == 0x02: + nums = self.ExtEntry.ExtEntrySize - 20 + self.ExtEntry = Refine_FV_EXT_ENTRY_GUID_TYPE_Header(nums).from_buffer_copy(buffer[self.ExtEntryOffset:]) + elif self.ExtEntry.ExtEntryType == 0x03: + self.ExtEntry = EFI_FIRMWARE_VOLUME_EXT_ENTRY_USED_SIZE_TYPE.from_buffer_copy(buffer[self.ExtEntryOffset:]) + else: + self.ExtTypeExist = 0 + else: + self.ExtEntryExist = 0 + self.Size = self.Header.FvLength + self.HeaderLength = self.Header.HeaderLength + self.HOffset = 0 + self.DOffset = 0 + self.ROffset = 0 + self.Data = b'' + if self.Header.Signature != 1213613663: + logger.error('Invalid Fv Header! Fv {} signature {} is not "_FVH".'.format(struct2stream(self.Header), self.Header.Signature)) + raise Exception("Process Failed: Fv Header Signature!") + self.PadData = b'' + self.Free_Space = 0 + self.ModCheckSum() + + def ModCheckSum(self) -> None: + # Fv Header Sums to 0. + Header = struct2stream(self.Header)[::-1] + Size = self.HeaderLength // 2 + Sum = 0 + for i in range(Size): + Sum += int(Header[i*2: i*2 + 2].hex(), 16) + if Sum & 0xffff: + self.Header.Checksum = 0x10000 - (Sum - self.Header.Checksum) % 0x10000 + + def ModFvExt(self) -> None: + # If used space changes and self.ExtEntry.UsedSize exists, self.ExtEntry.UsedSize need to be changed. + if self.Header.ExtHeaderOffset and self.ExtEntryExist and self.ExtTypeExist and self.ExtEntry.Hdr.ExtEntryType == 0x03: + self.ExtEntry.UsedSize = self.Header.FvLength - self.Free_Space + + def ModFvSize(self) -> None: + # If Fv Size changed, self.Header.FvLength and self.Header.BlockMap[i].NumBlocks need to be changed. + BlockMapNum = len(self.Header.BlockMap) + for i in range(BlockMapNum): + if self.Header.BlockMap[i].Length: + self.Header.BlockMap[i].NumBlocks = self.Header.FvLength // self.Header.BlockMap[i].Length + + def ModExtHeaderData(self) -> None: + if self.Header.ExtHeaderOffset: + ExtHeaderData = struct2stream(self.ExtHeader) + ExtHeaderDataOffset = self.Header.ExtHeaderOffset - self.HeaderLength + self.Data = self.Data[:ExtHeaderDataOffset] + ExtHeaderData + self.Data[ExtHeaderDataOffset+20:] + if self.Header.ExtHeaderOffset and self.ExtEntryExist: + ExtHeaderEntryData = struct2stream(self.ExtEntry) + ExtHeaderEntryDataOffset = self.Header.ExtHeaderOffset + 20 - self.HeaderLength + self.Data = self.Data[:ExtHeaderEntryDataOffset] + ExtHeaderEntryData + self.Data[ExtHeaderEntryDataOffset+len(ExtHeaderEntryData):] + +class FfsNode: + def __init__(self, buffer: bytes) -> None: + self.Header = EFI_FFS_FILE_HEADER.from_buffer_copy(buffer) + # self.Attributes = unpack("<B", buffer[21:22])[0] + if self.Header.FFS_FILE_SIZE != 0 and self.Header.Attributes != 0xff and self.Header.Attributes & 0x01 == 1: + logger.error('Error Ffs Header! Ffs {} Header Size and Attributes is not matched!'.format(uuid.UUID(bytes_le=struct2stream(self.Header.Name)))) + raise Exception("Process Failed: Error Ffs Header!") + if self.Header.FFS_FILE_SIZE == 0 and self.Header.Attributes & 0x01 == 1: + self.Header = EFI_FFS_FILE_HEADER2.from_buffer_copy(buffer) + self.Name = uuid.UUID(bytes_le=struct2stream(self.Header.Name)) + self.UiName = b'' + self.Version = b'' + self.Size = self.Header.FFS_FILE_SIZE + self.HeaderLength = self.Header.HeaderLength + self.HOffset = 0 + self.DOffset = 0 + self.ROffset = 0 + self.Data = b'' + self.PadData = b'' + self.SectionMaxAlignment = SECTION_COMMON_ALIGNMENT # 4-align + + def ModCheckSum(self) -> None: + HeaderData = struct2stream(self.Header) + HeaderSum = 0 + for item in HeaderData: + HeaderSum += item + HeaderSum -= self.Header.State + HeaderSum -= self.Header.IntegrityCheck.Checksum.File + if HeaderSum & 0xff: + Header = self.Header.IntegrityCheck.Checksum.Header + 0x100 - HeaderSum % 0x100 + self.Header.IntegrityCheck.Checksum.Header = Header % 0x100 + +class SectionNode: + def __init__(self, buffer: bytes) -> None: + if buffer[0:3] != b'\xff\xff\xff': + self.Header = EFI_COMMON_SECTION_HEADER.from_buffer_copy(buffer) + else: + self.Header = EFI_COMMON_SECTION_HEADER2.from_buffer_copy(buffer) + if self.Header.Type in SectionHeaderType: + self.Name = SectionHeaderType[self.Header.Type] + elif self.Header.Type == 0: + self.Name = "EFI_SECTION_ALL" + else: + self.Name = "SECTION" + if self.Header.Type in HeaderType: + self.ExtHeader = self.GetExtHeader(self.Header.Type, buffer[self.Header.Common_Header_Size():], (self.Header.SECTION_SIZE-self.Header.Common_Header_Size())) + self.HeaderLength = self.Header.Common_Header_Size() + self.ExtHeader.ExtHeaderSize() + else: + self.ExtHeader = None + self.HeaderLength = self.Header.Common_Header_Size() + self.Size = self.Header.SECTION_SIZE + self.Type = self.Header.Type + self.HOffset = 0 + self.DOffset = 0 + self.ROffset = 0 + self.Data = b'' + self.OriData = b'' + self.OriHeader = b'' + self.PadData = b'' + self.IsPadSection = False + self.SectionMaxAlignment = SECTION_COMMON_ALIGNMENT # 4-align + + def GetExtHeader(self, Type: int, buffer: bytes, nums: int=0) -> None: + if Type == 0x01: + return EFI_COMPRESSION_SECTION.from_buffer_copy(buffer) + elif Type == 0x02: + return EFI_GUID_DEFINED_SECTION.from_buffer_copy(buffer) + elif Type == 0x14: + return Get_VERSION_Header((nums - 2)//2).from_buffer_copy(buffer) + elif Type == 0x15: + return Get_USER_INTERFACE_Header(nums//2).from_buffer_copy(buffer) + elif Type == 0x18: + return EFI_FREEFORM_SUBTYPE_GUID_SECTION.from_buffer_copy(buffer) + +class FreeSpaceNode: + def __init__(self, buffer: bytes) -> None: + self.Name = 'Free_Space' + self.Data = buffer + self.Size = len(buffer) + self.HOffset = 0 + self.DOffset = 0 + self.ROffset = 0 + self.PadData = b'' diff --git a/BaseTools/Source/Python/FMMT/core/FMMTOperation.py b/BaseTools/Source/Python/FMMT/core/FMMTOperation.py index d4aa339703..d9ab6f69e4 100644 --- a/BaseTools/Source/Python/FMMT/core/FMMTOperation.py +++ b/BaseTools/Source/Python/FMMT/core/FMMTOperation.py @@ -1,232 +1,232 @@ -## @file
-# This file is used to define the functions to operate bios binary file.
-#
-# Copyright (c) 2021-, Intel Corporation. All rights reserved.<BR>
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-##
-from core.FMMTParser import *
-from core.FvHandler import *
-from utils.FvLayoutPrint import *
-from utils.FmmtLogger import FmmtLogger as logger
-
-global Fv_count
-Fv_count = 0
-
-# The ROOT_TYPE can be 'ROOT_TREE', 'ROOT_FV_TREE', 'ROOT_FFS_TREE', 'ROOT_SECTION_TREE'
-def ViewFile(inputfile: str, ROOT_TYPE: str, layoutfile: str=None, outputfile: str=None) -> None:
- if not os.path.exists(inputfile):
- logger.error("Invalid inputfile, can not open {}.".format(inputfile))
- raise Exception("Process Failed: Invalid inputfile!")
- # 1. Data Prepare
- with open(inputfile, "rb") as f:
- whole_data = f.read()
- FmmtParser = FMMTParser(inputfile, ROOT_TYPE)
- # 2. DataTree Create
- logger.debug('Parsing inputfile data......')
- FmmtParser.ParserFromRoot(FmmtParser.WholeFvTree, whole_data)
- logger.debug('Done!')
- # 3. Log Output
- InfoDict = FmmtParser.WholeFvTree.ExportTree()
- logger.debug('BinaryTree created, start parsing BinaryTree data......')
- FmmtParser.WholeFvTree.parserTree(InfoDict, FmmtParser.BinaryInfo)
- logger.debug('Done!')
- GetFormatter("").LogPrint(FmmtParser.BinaryInfo)
- if layoutfile:
- if os.path.splitext(layoutfile)[1]:
- layoutfilename = layoutfile
- layoutfileformat = os.path.splitext(layoutfile)[1][1:].lower()
- else:
- layoutfilename = "Layout_{}{}".format(os.path.basename(inputfile),".{}".format(layoutfile.lower()))
- layoutfileformat = layoutfile.lower()
- GetFormatter(layoutfileformat).dump(InfoDict, FmmtParser.BinaryInfo, layoutfilename)
- # 4. Data Encapsulation
- if outputfile:
- logger.debug('Start encapsulating data......')
- FmmtParser.Encapsulation(FmmtParser.WholeFvTree, False)
- with open(outputfile, "wb") as f:
- f.write(FmmtParser.FinalData)
- logger.debug('Encapsulated data is saved in {}.'.format(outputfile))
-
-def DeleteFfs(inputfile: str, TargetFfs_name: str, outputfile: str, Fv_name: str=None) -> None:
- if not os.path.exists(inputfile):
- logger.error("Invalid inputfile, can not open {}.".format(inputfile))
- raise Exception("Process Failed: Invalid inputfile!")
- # 1. Data Prepare
- with open(inputfile, "rb") as f:
- whole_data = f.read()
- FmmtParser = FMMTParser(inputfile, ROOT_TREE)
- # 2. DataTree Create
- logger.debug('Parsing inputfile data......')
- FmmtParser.ParserFromRoot(FmmtParser.WholeFvTree, whole_data)
- logger.debug('Done!')
- # 3. Data Modify
- FmmtParser.WholeFvTree.FindNode(TargetFfs_name, FmmtParser.WholeFvTree.Findlist)
- # Choose the Specfic DeleteFfs with Fv info
- if Fv_name:
- FindNum = len(FmmtParser.WholeFvTree.Findlist)
- for index in range(FindNum-1, -1, -1):
- if FmmtParser.WholeFvTree.Findlist[index].Parent.key != Fv_name and FmmtParser.WholeFvTree.Findlist[index].Parent.Data.Name != Fv_name:
- FmmtParser.WholeFvTree.Findlist.remove(FmmtParser.WholeFvTree.Findlist[index])
- Status = False
- if FmmtParser.WholeFvTree.Findlist != []:
- for Delete_Ffs in FmmtParser.WholeFvTree.Findlist:
- FfsMod = FvHandler(None, Delete_Ffs)
- Status = FfsMod.DeleteFfs()
- else:
- logger.error('Target Ffs not found!!!')
- # 4. Data Encapsulation
- if Status:
- logger.debug('Start encapsulating data......')
- FmmtParser.Encapsulation(FmmtParser.WholeFvTree, False)
- with open(outputfile, "wb") as f:
- f.write(FmmtParser.FinalData)
- logger.debug('Encapsulated data is saved in {}.'.format(outputfile))
-
-def AddNewFfs(inputfile: str, Fv_name: str, newffsfile: str, outputfile: str) -> None:
- if not os.path.exists(inputfile):
- logger.error("Invalid inputfile, can not open {}.".format(inputfile))
- raise Exception("Process Failed: Invalid inputfile!")
- if not os.path.exists(newffsfile):
- logger.error("Invalid ffsfile, can not open {}.".format(newffsfile))
- raise Exception("Process Failed: Invalid ffs file!")
- # 1. Data Prepare
- with open(inputfile, "rb") as f:
- whole_data = f.read()
- FmmtParser = FMMTParser(inputfile, ROOT_TREE)
- # 2. DataTree Create
- logger.debug('Parsing inputfile data......')
- FmmtParser.ParserFromRoot(FmmtParser.WholeFvTree, whole_data)
- logger.debug('Done!')
- # Get Target Fv and Target Ffs_Pad
- FmmtParser.WholeFvTree.FindNode(Fv_name, FmmtParser.WholeFvTree.Findlist)
- # Create new ffs Tree
- with open(newffsfile, "rb") as f:
- new_ffs_data = f.read()
- NewFmmtParser = FMMTParser(newffsfile, ROOT_FFS_TREE)
- Status = False
- # 3. Data Modify
- if FmmtParser.WholeFvTree.Findlist:
- for TargetFv in FmmtParser.WholeFvTree.Findlist:
- TargetFfsPad = TargetFv.Child[-1]
- logger.debug('Parsing newffsfile data......')
- if TargetFfsPad.type == FFS_FREE_SPACE:
- NewFmmtParser.ParserFromRoot(NewFmmtParser.WholeFvTree, new_ffs_data, TargetFfsPad.Data.HOffset)
- else:
- NewFmmtParser.ParserFromRoot(NewFmmtParser.WholeFvTree, new_ffs_data, TargetFfsPad.Data.HOffset+TargetFfsPad.Data.Size)
- logger.debug('Done!')
- FfsMod = FvHandler(NewFmmtParser.WholeFvTree.Child[0], TargetFfsPad)
- Status = FfsMod.AddFfs()
- else:
- logger.error('Target Fv not found!!!')
- # 4. Data Encapsulation
- if Status:
- logger.debug('Start encapsulating data......')
- FmmtParser.Encapsulation(FmmtParser.WholeFvTree, False)
- with open(outputfile, "wb") as f:
- f.write(FmmtParser.FinalData)
- logger.debug('Encapsulated data is saved in {}.'.format(outputfile))
-
-def ReplaceFfs(inputfile: str, Ffs_name: str, newffsfile: str, outputfile: str, Fv_name: str=None) -> None:
- if not os.path.exists(inputfile):
- logger.error("Invalid inputfile, can not open {}.".format(inputfile))
- raise Exception("Process Failed: Invalid inputfile!")
- # 1. Data Prepare
- with open(inputfile, "rb") as f:
- whole_data = f.read()
- FmmtParser = FMMTParser(inputfile, ROOT_TREE)
- # 2. DataTree Create
- logger.debug('Parsing inputfile data......')
- FmmtParser.ParserFromRoot(FmmtParser.WholeFvTree, whole_data)
- logger.debug('Done!')
- with open(newffsfile, "rb") as f:
- new_ffs_data = f.read()
- newFmmtParser = FMMTParser(newffsfile, FV_TREE)
- logger.debug('Parsing newffsfile data......')
- newFmmtParser.ParserFromRoot(newFmmtParser.WholeFvTree, new_ffs_data)
- logger.debug('Done!')
- Status = False
- # 3. Data Modify
- new_ffs = newFmmtParser.WholeFvTree.Child[0]
- new_ffs.Data.PadData = GetPadSize(new_ffs.Data.Size, FFS_COMMON_ALIGNMENT) * b'\xff'
- FmmtParser.WholeFvTree.FindNode(Ffs_name, FmmtParser.WholeFvTree.Findlist)
- if Fv_name:
- FindNum = len(FmmtParser.WholeFvTree.Findlist)
- for index in range(FindNum-1, -1, -1):
- if FmmtParser.WholeFvTree.Findlist[index].Parent.key != Fv_name and FmmtParser.WholeFvTree.Findlist[index].Parent.Data.Name != Fv_name:
- FmmtParser.WholeFvTree.Findlist.remove(FmmtParser.WholeFvTree.Findlist[index])
- if FmmtParser.WholeFvTree.Findlist != []:
- for TargetFfs in FmmtParser.WholeFvTree.Findlist:
- FfsMod = FvHandler(newFmmtParser.WholeFvTree.Child[0], TargetFfs)
- Status = FfsMod.ReplaceFfs()
- else:
- logger.error('Target Ffs not found!!!')
- # 4. Data Encapsulation
- if Status:
- logger.debug('Start encapsulating data......')
- FmmtParser.Encapsulation(FmmtParser.WholeFvTree, False)
- with open(outputfile, "wb") as f:
- f.write(FmmtParser.FinalData)
- logger.debug('Encapsulated data is saved in {}.'.format(outputfile))
-
-def ExtractFfs(inputfile: str, Ffs_name: str, outputfile: str, Fv_name: str=None) -> None:
- if not os.path.exists(inputfile):
- logger.error("Invalid inputfile, can not open {}.".format(inputfile))
- raise Exception("Process Failed: Invalid inputfile!")
- # 1. Data Prepare
- with open(inputfile, "rb") as f:
- whole_data = f.read()
- FmmtParser = FMMTParser(inputfile, ROOT_TREE)
- # 2. DataTree Create
- logger.debug('Parsing inputfile data......')
- FmmtParser.ParserFromRoot(FmmtParser.WholeFvTree, whole_data)
- logger.debug('Done!')
- FmmtParser.WholeFvTree.FindNode(Ffs_name, FmmtParser.WholeFvTree.Findlist)
- if Fv_name:
- FindNum = len(FmmtParser.WholeFvTree.Findlist)
- for index in range(FindNum-1, -1, -1):
- if FmmtParser.WholeFvTree.Findlist[index].Parent.key != Fv_name and FmmtParser.WholeFvTree.Findlist[index].Parent.Data.Name != Fv_name:
- FmmtParser.WholeFvTree.Findlist.remove(FmmtParser.WholeFvTree.Findlist[index])
- if FmmtParser.WholeFvTree.Findlist != []:
- TargetNode = FmmtParser.WholeFvTree.Findlist[0]
- if TargetNode.type == FV_TREE or TargetNode.type == SEC_FV_TREE or TargetNode.type == DATA_FV_TREE:
- FinalData = struct2stream(TargetNode.Data.Header) + TargetNode.Data.Data
- with open(outputfile, "wb") as f:
- f.write(FinalData)
- logger.debug('Extract fv data is saved in {}.'.format(outputfile))
- else:
- TargetFv = TargetNode.Parent
- if TargetFv.Data.Header.Attributes & EFI_FVB2_ERASE_POLARITY:
- TargetNode.Data.Header.State = c_uint8(
- ~TargetNode.Data.Header.State)
- FinalData = struct2stream(TargetNode.Data.Header) + TargetNode.Data.Data
- with open(outputfile, "wb") as f:
- f.write(FinalData)
- logger.debug('Extract ffs data is saved in {}.'.format(outputfile))
- else:
- logger.error('Target Ffs/Fv not found!!!')
-
-def ShrinkFv(inputfile: str, outputfile: str) -> None:
- if not os.path.exists(inputfile):
- logger.error("Invalid inputfile, can not open {}.".format(inputfile))
- raise Exception("Process Failed: Invalid inputfile!")
- # 1. Data Prepare
- with open(inputfile, "rb") as f:
- whole_data = f.read()
- FmmtParser = FMMTParser(inputfile, ROOT_TREE)
- # 2. DataTree Create
- logger.debug('Parsing inputfile data......')
- FmmtParser.ParserFromRoot(FmmtParser.WholeFvTree, whole_data)
- logger.debug('Done!')
- TargetFv = FmmtParser.WholeFvTree.Child[0]
- if TargetFv:
- FvMod = FvHandler(TargetFv)
- Status = FvMod.ShrinkFv()
- else:
- logger.error('Target Fv not found!!!')
- # 4. Data Encapsulation
- if Status:
- logger.debug('Start encapsulating data......')
- FmmtParser.Encapsulation(FmmtParser.WholeFvTree, False)
- with open(outputfile, "wb") as f:
- f.write(FmmtParser.FinalData)
- logger.debug('Encapsulated data is saved in {}.'.format(outputfile))
+## @file +# This file is used to define the functions to operate bios binary file. +# +# Copyright (c) 2021-, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +from core.FMMTParser import * +from core.FvHandler import * +from utils.FvLayoutPrint import * +from utils.FmmtLogger import FmmtLogger as logger + +global Fv_count +Fv_count = 0 + +# The ROOT_TYPE can be 'ROOT_TREE', 'ROOT_FV_TREE', 'ROOT_FFS_TREE', 'ROOT_SECTION_TREE' +def ViewFile(inputfile: str, ROOT_TYPE: str, layoutfile: str=None, outputfile: str=None) -> None: + if not os.path.exists(inputfile): + logger.error("Invalid inputfile, can not open {}.".format(inputfile)) + raise Exception("Process Failed: Invalid inputfile!") + # 1. Data Prepare + with open(inputfile, "rb") as f: + whole_data = f.read() + FmmtParser = FMMTParser(inputfile, ROOT_TYPE) + # 2. DataTree Create + logger.debug('Parsing inputfile data......') + FmmtParser.ParserFromRoot(FmmtParser.WholeFvTree, whole_data) + logger.debug('Done!') + # 3. Log Output + InfoDict = FmmtParser.WholeFvTree.ExportTree() + logger.debug('BinaryTree created, start parsing BinaryTree data......') + FmmtParser.WholeFvTree.parserTree(InfoDict, FmmtParser.BinaryInfo) + logger.debug('Done!') + GetFormatter("").LogPrint(FmmtParser.BinaryInfo) + if layoutfile: + if os.path.splitext(layoutfile)[1]: + layoutfilename = layoutfile + layoutfileformat = os.path.splitext(layoutfile)[1][1:].lower() + else: + layoutfilename = "Layout_{}{}".format(os.path.basename(inputfile),".{}".format(layoutfile.lower())) + layoutfileformat = layoutfile.lower() + GetFormatter(layoutfileformat).dump(InfoDict, FmmtParser.BinaryInfo, layoutfilename) + # 4. Data Encapsulation + if outputfile: + logger.debug('Start encapsulating data......') + FmmtParser.Encapsulation(FmmtParser.WholeFvTree, False) + with open(outputfile, "wb") as f: + f.write(FmmtParser.FinalData) + logger.debug('Encapsulated data is saved in {}.'.format(outputfile)) + +def DeleteFfs(inputfile: str, TargetFfs_name: str, outputfile: str, Fv_name: str=None) -> None: + if not os.path.exists(inputfile): + logger.error("Invalid inputfile, can not open {}.".format(inputfile)) + raise Exception("Process Failed: Invalid inputfile!") + # 1. Data Prepare + with open(inputfile, "rb") as f: + whole_data = f.read() + FmmtParser = FMMTParser(inputfile, ROOT_TREE) + # 2. DataTree Create + logger.debug('Parsing inputfile data......') + FmmtParser.ParserFromRoot(FmmtParser.WholeFvTree, whole_data) + logger.debug('Done!') + # 3. Data Modify + FmmtParser.WholeFvTree.FindNode(TargetFfs_name, FmmtParser.WholeFvTree.Findlist) + # Choose the Specfic DeleteFfs with Fv info + if Fv_name: + FindNum = len(FmmtParser.WholeFvTree.Findlist) + for index in range(FindNum-1, -1, -1): + if FmmtParser.WholeFvTree.Findlist[index].Parent.key != Fv_name and FmmtParser.WholeFvTree.Findlist[index].Parent.Data.Name != Fv_name: + FmmtParser.WholeFvTree.Findlist.remove(FmmtParser.WholeFvTree.Findlist[index]) + Status = False + if FmmtParser.WholeFvTree.Findlist != []: + for Delete_Ffs in FmmtParser.WholeFvTree.Findlist: + FfsMod = FvHandler(None, Delete_Ffs) + Status = FfsMod.DeleteFfs() + else: + logger.error('Target Ffs not found!!!') + # 4. Data Encapsulation + if Status: + logger.debug('Start encapsulating data......') + FmmtParser.Encapsulation(FmmtParser.WholeFvTree, False) + with open(outputfile, "wb") as f: + f.write(FmmtParser.FinalData) + logger.debug('Encapsulated data is saved in {}.'.format(outputfile)) + +def AddNewFfs(inputfile: str, Fv_name: str, newffsfile: str, outputfile: str) -> None: + if not os.path.exists(inputfile): + logger.error("Invalid inputfile, can not open {}.".format(inputfile)) + raise Exception("Process Failed: Invalid inputfile!") + if not os.path.exists(newffsfile): + logger.error("Invalid ffsfile, can not open {}.".format(newffsfile)) + raise Exception("Process Failed: Invalid ffs file!") + # 1. Data Prepare + with open(inputfile, "rb") as f: + whole_data = f.read() + FmmtParser = FMMTParser(inputfile, ROOT_TREE) + # 2. DataTree Create + logger.debug('Parsing inputfile data......') + FmmtParser.ParserFromRoot(FmmtParser.WholeFvTree, whole_data) + logger.debug('Done!') + # Get Target Fv and Target Ffs_Pad + FmmtParser.WholeFvTree.FindNode(Fv_name, FmmtParser.WholeFvTree.Findlist) + # Create new ffs Tree + with open(newffsfile, "rb") as f: + new_ffs_data = f.read() + NewFmmtParser = FMMTParser(newffsfile, ROOT_FFS_TREE) + Status = False + # 3. Data Modify + if FmmtParser.WholeFvTree.Findlist: + for TargetFv in FmmtParser.WholeFvTree.Findlist: + TargetFfsPad = TargetFv.Child[-1] + logger.debug('Parsing newffsfile data......') + if TargetFfsPad.type == FFS_FREE_SPACE: + NewFmmtParser.ParserFromRoot(NewFmmtParser.WholeFvTree, new_ffs_data, TargetFfsPad.Data.HOffset) + else: + NewFmmtParser.ParserFromRoot(NewFmmtParser.WholeFvTree, new_ffs_data, TargetFfsPad.Data.HOffset+TargetFfsPad.Data.Size) + logger.debug('Done!') + FfsMod = FvHandler(NewFmmtParser.WholeFvTree.Child[0], TargetFfsPad) + Status = FfsMod.AddFfs() + else: + logger.error('Target Fv not found!!!') + # 4. Data Encapsulation + if Status: + logger.debug('Start encapsulating data......') + FmmtParser.Encapsulation(FmmtParser.WholeFvTree, False) + with open(outputfile, "wb") as f: + f.write(FmmtParser.FinalData) + logger.debug('Encapsulated data is saved in {}.'.format(outputfile)) + +def ReplaceFfs(inputfile: str, Ffs_name: str, newffsfile: str, outputfile: str, Fv_name: str=None) -> None: + if not os.path.exists(inputfile): + logger.error("Invalid inputfile, can not open {}.".format(inputfile)) + raise Exception("Process Failed: Invalid inputfile!") + # 1. Data Prepare + with open(inputfile, "rb") as f: + whole_data = f.read() + FmmtParser = FMMTParser(inputfile, ROOT_TREE) + # 2. DataTree Create + logger.debug('Parsing inputfile data......') + FmmtParser.ParserFromRoot(FmmtParser.WholeFvTree, whole_data) + logger.debug('Done!') + with open(newffsfile, "rb") as f: + new_ffs_data = f.read() + newFmmtParser = FMMTParser(newffsfile, FV_TREE) + logger.debug('Parsing newffsfile data......') + newFmmtParser.ParserFromRoot(newFmmtParser.WholeFvTree, new_ffs_data) + logger.debug('Done!') + Status = False + # 3. Data Modify + new_ffs = newFmmtParser.WholeFvTree.Child[0] + new_ffs.Data.PadData = GetPadSize(new_ffs.Data.Size, FFS_COMMON_ALIGNMENT) * b'\xff' + FmmtParser.WholeFvTree.FindNode(Ffs_name, FmmtParser.WholeFvTree.Findlist) + if Fv_name: + FindNum = len(FmmtParser.WholeFvTree.Findlist) + for index in range(FindNum-1, -1, -1): + if FmmtParser.WholeFvTree.Findlist[index].Parent.key != Fv_name and FmmtParser.WholeFvTree.Findlist[index].Parent.Data.Name != Fv_name: + FmmtParser.WholeFvTree.Findlist.remove(FmmtParser.WholeFvTree.Findlist[index]) + if FmmtParser.WholeFvTree.Findlist != []: + for TargetFfs in FmmtParser.WholeFvTree.Findlist: + FfsMod = FvHandler(newFmmtParser.WholeFvTree.Child[0], TargetFfs) + Status = FfsMod.ReplaceFfs() + else: + logger.error('Target Ffs not found!!!') + # 4. Data Encapsulation + if Status: + logger.debug('Start encapsulating data......') + FmmtParser.Encapsulation(FmmtParser.WholeFvTree, False) + with open(outputfile, "wb") as f: + f.write(FmmtParser.FinalData) + logger.debug('Encapsulated data is saved in {}.'.format(outputfile)) + +def ExtractFfs(inputfile: str, Ffs_name: str, outputfile: str, Fv_name: str=None) -> None: + if not os.path.exists(inputfile): + logger.error("Invalid inputfile, can not open {}.".format(inputfile)) + raise Exception("Process Failed: Invalid inputfile!") + # 1. Data Prepare + with open(inputfile, "rb") as f: + whole_data = f.read() + FmmtParser = FMMTParser(inputfile, ROOT_TREE) + # 2. DataTree Create + logger.debug('Parsing inputfile data......') + FmmtParser.ParserFromRoot(FmmtParser.WholeFvTree, whole_data) + logger.debug('Done!') + FmmtParser.WholeFvTree.FindNode(Ffs_name, FmmtParser.WholeFvTree.Findlist) + if Fv_name: + FindNum = len(FmmtParser.WholeFvTree.Findlist) + for index in range(FindNum-1, -1, -1): + if FmmtParser.WholeFvTree.Findlist[index].Parent.key != Fv_name and FmmtParser.WholeFvTree.Findlist[index].Parent.Data.Name != Fv_name: + FmmtParser.WholeFvTree.Findlist.remove(FmmtParser.WholeFvTree.Findlist[index]) + if FmmtParser.WholeFvTree.Findlist != []: + TargetNode = FmmtParser.WholeFvTree.Findlist[0] + if TargetNode.type == FV_TREE or TargetNode.type == SEC_FV_TREE or TargetNode.type == DATA_FV_TREE: + FinalData = struct2stream(TargetNode.Data.Header) + TargetNode.Data.Data + with open(outputfile, "wb") as f: + f.write(FinalData) + logger.debug('Extract fv data is saved in {}.'.format(outputfile)) + else: + TargetFv = TargetNode.Parent + if TargetFv.Data.Header.Attributes & EFI_FVB2_ERASE_POLARITY: + TargetNode.Data.Header.State = c_uint8( + ~TargetNode.Data.Header.State) + FinalData = struct2stream(TargetNode.Data.Header) + TargetNode.Data.Data + with open(outputfile, "wb") as f: + f.write(FinalData) + logger.debug('Extract ffs data is saved in {}.'.format(outputfile)) + else: + logger.error('Target Ffs/Fv not found!!!') + +def ShrinkFv(inputfile: str, outputfile: str) -> None: + if not os.path.exists(inputfile): + logger.error("Invalid inputfile, can not open {}.".format(inputfile)) + raise Exception("Process Failed: Invalid inputfile!") + # 1. Data Prepare + with open(inputfile, "rb") as f: + whole_data = f.read() + FmmtParser = FMMTParser(inputfile, ROOT_TREE) + # 2. DataTree Create + logger.debug('Parsing inputfile data......') + FmmtParser.ParserFromRoot(FmmtParser.WholeFvTree, whole_data) + logger.debug('Done!') + TargetFv = FmmtParser.WholeFvTree.Child[0] + if TargetFv: + FvMod = FvHandler(TargetFv) + Status = FvMod.ShrinkFv() + else: + logger.error('Target Fv not found!!!') + # 4. Data Encapsulation + if Status: + logger.debug('Start encapsulating data......') + FmmtParser.Encapsulation(FmmtParser.WholeFvTree, False) + with open(outputfile, "wb") as f: + f.write(FmmtParser.FinalData) + logger.debug('Encapsulated data is saved in {}.'.format(outputfile)) diff --git a/BaseTools/Source/Python/FMMT/core/FMMTParser.py b/BaseTools/Source/Python/FMMT/core/FMMTParser.py index 25a2bde799..18de96c08e 100644 --- a/BaseTools/Source/Python/FMMT/core/FMMTParser.py +++ b/BaseTools/Source/Python/FMMT/core/FMMTParser.py @@ -1,87 +1,87 @@ -## @file
-# This file is used to define the interface of Bios Parser.
-#
-# Copyright (c) 2021-, Intel Corporation. All rights reserved.<BR>
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-##
-from FirmwareStorageFormat.Common import *
-from core.BinaryFactoryProduct import ParserEntry
-from core.BiosTreeNode import *
-from core.BiosTree import *
-from core.GuidTools import *
-from utils.FmmtLogger import FmmtLogger as logger
-
-class FMMTParser:
- def __init__(self, name: str, TYPE: str) -> None:
- self.WholeFvTree = BIOSTREE(name)
- self.WholeFvTree.type = TYPE
- self.FinalData = b''
- self.BinaryInfo = []
-
- ## Parser the nodes in WholeTree.
- def ParserFromRoot(self, WholeFvTree=None, whole_data: bytes=b'', Reloffset: int=0) -> None:
- if WholeFvTree.type == ROOT_TREE or WholeFvTree.type == ROOT_FV_TREE or WholeFvTree.type == ROOT_ELF_TREE:
- ParserEntry().DataParser(self.WholeFvTree, whole_data, Reloffset)
- else:
- ParserEntry().DataParser(WholeFvTree, whole_data, Reloffset)
- for Child in WholeFvTree.Child:
- self.ParserFromRoot(Child, "")
-
- ## Encapuslation all the data in tree into self.FinalData
- def Encapsulation(self, rootTree, CompressStatus: bool) -> None:
- # If current node is Root node, skip it.
- if rootTree.type == ROOT_TREE or rootTree.type == ROOT_FV_TREE or rootTree.type == ROOT_FFS_TREE or rootTree.type == ROOT_SECTION_TREE:
- logger.debug('Encapsulated successfully!')
- # If current node do not have Header, just add Data.
- elif rootTree.type == BINARY_DATA or rootTree.type == FFS_FREE_SPACE:
- self.FinalData += rootTree.Data.Data
- rootTree.Child = []
- # If current node do not have Child and ExtHeader, just add its Header and Data.
- elif rootTree.type == DATA_FV_TREE or rootTree.type == FFS_PAD:
- self.FinalData += struct2stream(rootTree.Data.Header) + rootTree.Data.Data + rootTree.Data.PadData
- if rootTree.isFinalChild():
- ParTree = rootTree.Parent
- if ParTree.type != 'ROOT':
- self.FinalData += ParTree.Data.PadData
- rootTree.Child = []
- # If current node is not Section node and may have Child and ExtHeader, add its Header,ExtHeader. If do not have Child, add its Data.
- elif rootTree.type == FV_TREE or rootTree.type == FFS_TREE or rootTree.type == SEC_FV_TREE:
- if rootTree.HasChild():
- self.FinalData += struct2stream(rootTree.Data.Header)
- else:
- self.FinalData += struct2stream(rootTree.Data.Header) + rootTree.Data.Data + rootTree.Data.PadData
- if rootTree.isFinalChild():
- ParTree = rootTree.Parent
- if ParTree.type != 'ROOT':
- self.FinalData += ParTree.Data.PadData
- # If current node is Section, need to consider its ExtHeader, Child and Compressed Status.
- elif rootTree.type == SECTION_TREE:
- # Not compressed section
- if rootTree.Data.OriData == b'' or (rootTree.Data.OriData != b'' and CompressStatus):
- if rootTree.HasChild():
- if rootTree.Data.ExtHeader:
- self.FinalData += struct2stream(rootTree.Data.Header) + struct2stream(rootTree.Data.ExtHeader)
- else:
- self.FinalData += struct2stream(rootTree.Data.Header)
- else:
- Data = rootTree.Data.Data
- if rootTree.Data.ExtHeader:
- self.FinalData += struct2stream(rootTree.Data.Header) + struct2stream(rootTree.Data.ExtHeader) + Data + rootTree.Data.PadData
- else:
- self.FinalData += struct2stream(rootTree.Data.Header) + Data + rootTree.Data.PadData
- if rootTree.isFinalChild():
- ParTree = rootTree.Parent
- self.FinalData += ParTree.Data.PadData
- # If compressed section
- else:
- Data = rootTree.Data.OriData
- rootTree.Child = []
- if rootTree.Data.ExtHeader:
- self.FinalData += struct2stream(rootTree.Data.Header) + struct2stream(rootTree.Data.ExtHeader) + Data + rootTree.Data.PadData
- else:
- self.FinalData += struct2stream(rootTree.Data.Header) + Data + rootTree.Data.PadData
- if rootTree.isFinalChild():
- ParTree = rootTree.Parent
- self.FinalData += ParTree.Data.PadData
- for Child in rootTree.Child:
- self.Encapsulation(Child, CompressStatus)
+## @file +# This file is used to define the interface of Bios Parser. +# +# Copyright (c) 2021-, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +from FirmwareStorageFormat.Common import * +from core.BinaryFactoryProduct import ParserEntry +from core.BiosTreeNode import * +from core.BiosTree import * +from core.GuidTools import * +from utils.FmmtLogger import FmmtLogger as logger + +class FMMTParser: + def __init__(self, name: str, TYPE: str) -> None: + self.WholeFvTree = BIOSTREE(name) + self.WholeFvTree.type = TYPE + self.FinalData = b'' + self.BinaryInfo = [] + + ## Parser the nodes in WholeTree. + def ParserFromRoot(self, WholeFvTree=None, whole_data: bytes=b'', Reloffset: int=0) -> None: + if WholeFvTree.type == ROOT_TREE or WholeFvTree.type == ROOT_FV_TREE or WholeFvTree.type == ROOT_ELF_TREE: + ParserEntry().DataParser(self.WholeFvTree, whole_data, Reloffset) + else: + ParserEntry().DataParser(WholeFvTree, whole_data, Reloffset) + for Child in WholeFvTree.Child: + self.ParserFromRoot(Child, "") + + ## Encapuslation all the data in tree into self.FinalData + def Encapsulation(self, rootTree, CompressStatus: bool) -> None: + # If current node is Root node, skip it. + if rootTree.type == ROOT_TREE or rootTree.type == ROOT_FV_TREE or rootTree.type == ROOT_FFS_TREE or rootTree.type == ROOT_SECTION_TREE: + logger.debug('Encapsulated successfully!') + # If current node do not have Header, just add Data. + elif rootTree.type == BINARY_DATA or rootTree.type == FFS_FREE_SPACE: + self.FinalData += rootTree.Data.Data + rootTree.Child = [] + # If current node do not have Child and ExtHeader, just add its Header and Data. + elif rootTree.type == DATA_FV_TREE or rootTree.type == FFS_PAD: + self.FinalData += struct2stream(rootTree.Data.Header) + rootTree.Data.Data + rootTree.Data.PadData + if rootTree.isFinalChild(): + ParTree = rootTree.Parent + if ParTree.type != 'ROOT': + self.FinalData += ParTree.Data.PadData + rootTree.Child = [] + # If current node is not Section node and may have Child and ExtHeader, add its Header,ExtHeader. If do not have Child, add its Data. + elif rootTree.type == FV_TREE or rootTree.type == FFS_TREE or rootTree.type == SEC_FV_TREE: + if rootTree.HasChild(): + self.FinalData += struct2stream(rootTree.Data.Header) + else: + self.FinalData += struct2stream(rootTree.Data.Header) + rootTree.Data.Data + rootTree.Data.PadData + if rootTree.isFinalChild(): + ParTree = rootTree.Parent + if ParTree.type != 'ROOT': + self.FinalData += ParTree.Data.PadData + # If current node is Section, need to consider its ExtHeader, Child and Compressed Status. + elif rootTree.type == SECTION_TREE: + # Not compressed section + if rootTree.Data.OriData == b'' or (rootTree.Data.OriData != b'' and CompressStatus): + if rootTree.HasChild(): + if rootTree.Data.ExtHeader: + self.FinalData += struct2stream(rootTree.Data.Header) + struct2stream(rootTree.Data.ExtHeader) + else: + self.FinalData += struct2stream(rootTree.Data.Header) + else: + Data = rootTree.Data.Data + if rootTree.Data.ExtHeader: + self.FinalData += struct2stream(rootTree.Data.Header) + struct2stream(rootTree.Data.ExtHeader) + Data + rootTree.Data.PadData + else: + self.FinalData += struct2stream(rootTree.Data.Header) + Data + rootTree.Data.PadData + if rootTree.isFinalChild(): + ParTree = rootTree.Parent + self.FinalData += ParTree.Data.PadData + # If compressed section + else: + Data = rootTree.Data.OriData + rootTree.Child = [] + if rootTree.Data.ExtHeader: + self.FinalData += struct2stream(rootTree.Data.Header) + struct2stream(rootTree.Data.ExtHeader) + Data + rootTree.Data.PadData + else: + self.FinalData += struct2stream(rootTree.Data.Header) + Data + rootTree.Data.PadData + if rootTree.isFinalChild(): + ParTree = rootTree.Parent + self.FinalData += ParTree.Data.PadData + for Child in rootTree.Child: + self.Encapsulation(Child, CompressStatus) diff --git a/BaseTools/Source/Python/FMMT/core/FvHandler.py b/BaseTools/Source/Python/FMMT/core/FvHandler.py index 7a60760336..0e11e47031 100644 --- a/BaseTools/Source/Python/FMMT/core/FvHandler.py +++ b/BaseTools/Source/Python/FMMT/core/FvHandler.py @@ -1,683 +1,683 @@ -## @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) -> 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:
- 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 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
+## @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) -> 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: + 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 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 diff --git a/BaseTools/Source/Python/FMMT/core/GuidTools.py b/BaseTools/Source/Python/FMMT/core/GuidTools.py index f6bdeffa50..65c997bea5 100644 --- a/BaseTools/Source/Python/FMMT/core/GuidTools.py +++ b/BaseTools/Source/Python/FMMT/core/GuidTools.py @@ -1,179 +1,179 @@ -## @file
-# This file is used to define the FMMT dependent external tool management class.
-#
-# Copyright (c) 2021-, Intel Corporation. All rights reserved.<BR>
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-##
-import glob
-import logging
-import os
-import shutil
-import sys
-import tempfile
-import uuid
-from FirmwareStorageFormat.Common import *
-from utils.FmmtLogger import FmmtLogger as logger
-import subprocess
-
-def ExecuteCommand(cmd: list) -> None:
- subprocess.run(cmd,stdout=subprocess.DEVNULL)
-
-class GUIDTool:
- def __init__(self, guid: str, short_name: str, command: str) -> None:
- self.guid: str = guid
- self.short_name: str = short_name
- self.command: str = command
- self.ifexist: bool = False
-
- def pack(self, buffer: bytes) -> bytes:
- """
- compress file.
- """
- tool = self.command
- if tool:
- tmp = tempfile.mkdtemp(dir=os.environ.get('tmp'))
- ToolInputFile = os.path.join(tmp, "pack_uncompress_sec_file")
- ToolOuputFile = os.path.join(tmp, "pack_sec_file")
- try:
- file = open(ToolInputFile, "wb")
- file.write(buffer)
- file.close()
- command = [tool, '-e', '-o', ToolOuputFile,
- ToolInputFile]
- ExecuteCommand(command)
- buf = open(ToolOuputFile, "rb")
- res_buffer = buf.read()
- except Exception as msg:
- logger.error(msg)
- return ""
- else:
- buf.close()
- if os.path.exists(tmp):
- shutil.rmtree(tmp)
- return res_buffer
- else:
- logger.error(
- "Error parsing section: EFI_SECTION_GUID_DEFINED cannot be parsed at this time.")
- logger.info("Its GUID is: %s" % self.guid)
- return ""
-
-
- def unpack(self, buffer: bytes) -> bytes:
- """
- buffer: remove common header
- uncompress file
- """
- tool = self.command
- if tool:
- tmp = tempfile.mkdtemp(dir=os.environ.get('tmp'))
- ToolInputFile = os.path.join(tmp, "unpack_sec_file")
- ToolOuputFile = os.path.join(tmp, "unpack_uncompress_sec_file")
- try:
- file = open(ToolInputFile, "wb")
- file.write(buffer)
- file.close()
- command = [tool, '-d', '-o', ToolOuputFile, ToolInputFile]
- ExecuteCommand(command)
- buf = open(ToolOuputFile, "rb")
- res_buffer = buf.read()
- except Exception as msg:
- logger.error(msg)
- return ""
- else:
- buf.close()
- if os.path.exists(tmp):
- shutil.rmtree(tmp)
- return res_buffer
- else:
- logger.error("Error parsing section: EFI_SECTION_GUID_DEFINED cannot be parsed at this time.")
- logger.info("Its GUID is: %s" % self.guid)
- return ""
-
-class GUIDTools:
- '''
- GUIDTools is responsible for reading FMMTConfig.ini, verify the tools and provide interfaces to access those tools.
- '''
- default_tools = {
- struct2stream(ModifyGuidFormat("a31280ad-481e-41b6-95e8-127f4c984779")): GUIDTool("a31280ad-481e-41b6-95e8-127f4c984779", "TIANO", "TianoCompress"),
- struct2stream(ModifyGuidFormat("ee4e5898-3914-4259-9d6e-dc7bd79403cf")): GUIDTool("ee4e5898-3914-4259-9d6e-dc7bd79403cf", "LZMA", "LzmaCompress"),
- struct2stream(ModifyGuidFormat("fc1bcdb0-7d31-49aa-936a-a4600d9dd083")): GUIDTool("fc1bcdb0-7d31-49aa-936a-a4600d9dd083", "CRC32", "GenCrc32"),
- struct2stream(ModifyGuidFormat("d42ae6bd-1352-4bfb-909a-ca72a6eae889")): GUIDTool("d42ae6bd-1352-4bfb-909a-ca72a6eae889", "LZMAF86", "LzmaF86Compress"),
- struct2stream(ModifyGuidFormat("3d532050-5cda-4fd0-879e-0f7f630d5afb")): GUIDTool("3d532050-5cda-4fd0-879e-0f7f630d5afb", "BROTLI", "BrotliCompress"),
- }
-
- def __init__(self, tooldef_file: str=None) -> None:
- self.dir = os.path.join(os.path.dirname(__file__), "..")
- self.tooldef_file = tooldef_file if tooldef_file else os.path.join(self.dir, "FmmtConf.ini")
- self.tooldef = dict()
-
- def SetConfigFile(self) -> None:
- if os.environ['FmmtConfPath']:
- self.tooldef_file = os.path.join(os.environ['FmmtConfPath'], 'FmmtConf.ini')
- else:
- PathList = os.environ['PATH'].split(os.pathsep)
- for CurrentPath in PathList:
- if os.path.exists(os.path.join(CurrentPath, 'FmmtConf.ini')):
- self.tooldef_file = os.path.join(CurrentPath, 'FmmtConf.ini')
- break
-
- def VerifyTools(self, guidtool) -> None:
- """
- Verify Tools and Update Tools path.
- """
- path_env = os.environ.get("PATH")
- path_env_list = path_env.split(os.pathsep)
- path_env_list.append(os.path.dirname(__file__))
- path_env_list = list(set(path_env_list))
- cmd = guidtool.command
- if os.path.isabs(cmd):
- if not os.path.exists(cmd):
- if guidtool not in self.default_tools:
- logger.error("Tool Not found %s, which causes compress/uncompress process error." % cmd)
- logger.error("Please goto edk2 repo in current console, run 'edksetup.bat rebuild' command, and try again.\n")
- else:
- logger.error("Tool Not found %s, which causes compress/uncompress process error." % cmd)
- else:
- guidtool.ifexist = True
- else:
- for syspath in path_env_list:
- if glob.glob(os.path.join(syspath, cmd+"*")):
- guidtool.ifexist = True
- break
- else:
- if guidtool not in self.default_tools:
- logger.error("Tool Not found %s, which causes compress/uncompress process error." % cmd)
- logger.error("Please goto edk2 repo in current console, run 'edksetup.bat rebuild' command, and try again.\n")
- else:
- logger.error("Tool Not found %s, which causes compress/uncompress process error." % cmd)
-
- def LoadingTools(self) -> None:
- self.SetConfigFile()
- if os.path.exists(self.tooldef_file):
- with open(self.tooldef_file, "r") as fd:
- config_data = fd.readlines()
- for line in config_data:
- try:
- if not line.startswith("#"):
- guid, short_name, command = line.split()
- new_format_guid = struct2stream(ModifyGuidFormat(guid.strip()))
- self.tooldef[new_format_guid] = GUIDTool(
- guid.strip(), short_name.strip(), command.strip())
- except:
- logger.error("GuidTool load error!")
- continue
- else:
- self.tooldef.update(self.default_tools)
-
- def __getitem__(self, guid):
- if not self.tooldef:
- self.LoadingTools()
- guid_tool = self.tooldef.get(guid)
- if guid_tool:
- self.VerifyTools(guid_tool)
- return guid_tool
- else:
- logger.error("{} GuidTool is not defined!".format(guid))
- raise Exception("Process Failed: is not defined!")
-
-guidtools = GUIDTools()
-
+## @file +# This file is used to define the FMMT dependent external tool management class. +# +# Copyright (c) 2021-, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent +## +import glob +import logging +import os +import shutil +import sys +import tempfile +import uuid +from FirmwareStorageFormat.Common import * +from utils.FmmtLogger import FmmtLogger as logger +import subprocess + +def ExecuteCommand(cmd: list) -> None: + subprocess.run(cmd,stdout=subprocess.DEVNULL) + +class GUIDTool: + def __init__(self, guid: str, short_name: str, command: str) -> None: + self.guid: str = guid + self.short_name: str = short_name + self.command: str = command + self.ifexist: bool = False + + def pack(self, buffer: bytes) -> bytes: + """ + compress file. + """ + tool = self.command + if tool: + tmp = tempfile.mkdtemp(dir=os.environ.get('tmp')) + ToolInputFile = os.path.join(tmp, "pack_uncompress_sec_file") + ToolOuputFile = os.path.join(tmp, "pack_sec_file") + try: + file = open(ToolInputFile, "wb") + file.write(buffer) + file.close() + command = [tool, '-e', '-o', ToolOuputFile, + ToolInputFile] + ExecuteCommand(command) + buf = open(ToolOuputFile, "rb") + res_buffer = buf.read() + except Exception as msg: + logger.error(msg) + return "" + else: + buf.close() + if os.path.exists(tmp): + shutil.rmtree(tmp) + return res_buffer + else: + logger.error( + "Error parsing section: EFI_SECTION_GUID_DEFINED cannot be parsed at this time.") + logger.info("Its GUID is: %s" % self.guid) + return "" + + + def unpack(self, buffer: bytes) -> bytes: + """ + buffer: remove common header + uncompress file + """ + tool = self.command + if tool: + tmp = tempfile.mkdtemp(dir=os.environ.get('tmp')) + ToolInputFile = os.path.join(tmp, "unpack_sec_file") + ToolOuputFile = os.path.join(tmp, "unpack_uncompress_sec_file") + try: + file = open(ToolInputFile, "wb") + file.write(buffer) + file.close() + command = [tool, '-d', '-o', ToolOuputFile, ToolInputFile] + ExecuteCommand(command) + buf = open(ToolOuputFile, "rb") + res_buffer = buf.read() + except Exception as msg: + logger.error(msg) + return "" + else: + buf.close() + if os.path.exists(tmp): + shutil.rmtree(tmp) + return res_buffer + else: + logger.error("Error parsing section: EFI_SECTION_GUID_DEFINED cannot be parsed at this time.") + logger.info("Its GUID is: %s" % self.guid) + return "" + +class GUIDTools: + ''' + GUIDTools is responsible for reading FMMTConfig.ini, verify the tools and provide interfaces to access those tools. + ''' + default_tools = { + struct2stream(ModifyGuidFormat("a31280ad-481e-41b6-95e8-127f4c984779")): GUIDTool("a31280ad-481e-41b6-95e8-127f4c984779", "TIANO", "TianoCompress"), + struct2stream(ModifyGuidFormat("ee4e5898-3914-4259-9d6e-dc7bd79403cf")): GUIDTool("ee4e5898-3914-4259-9d6e-dc7bd79403cf", "LZMA", "LzmaCompress"), + struct2stream(ModifyGuidFormat("fc1bcdb0-7d31-49aa-936a-a4600d9dd083")): GUIDTool("fc1bcdb0-7d31-49aa-936a-a4600d9dd083", "CRC32", "GenCrc32"), + struct2stream(ModifyGuidFormat("d42ae6bd-1352-4bfb-909a-ca72a6eae889")): GUIDTool("d42ae6bd-1352-4bfb-909a-ca72a6eae889", "LZMAF86", "LzmaF86Compress"), + struct2stream(ModifyGuidFormat("3d532050-5cda-4fd0-879e-0f7f630d5afb")): GUIDTool("3d532050-5cda-4fd0-879e-0f7f630d5afb", "BROTLI", "BrotliCompress"), + } + + def __init__(self, tooldef_file: str=None) -> None: + self.dir = os.path.join(os.path.dirname(__file__), "..") + self.tooldef_file = tooldef_file if tooldef_file else os.path.join(self.dir, "FmmtConf.ini") + self.tooldef = dict() + + def SetConfigFile(self) -> None: + if os.environ['FmmtConfPath']: + self.tooldef_file = os.path.join(os.environ['FmmtConfPath'], 'FmmtConf.ini') + else: + PathList = os.environ['PATH'].split(os.pathsep) + for CurrentPath in PathList: + if os.path.exists(os.path.join(CurrentPath, 'FmmtConf.ini')): + self.tooldef_file = os.path.join(CurrentPath, 'FmmtConf.ini') + break + + def VerifyTools(self, guidtool) -> None: + """ + Verify Tools and Update Tools path. + """ + path_env = os.environ.get("PATH") + path_env_list = path_env.split(os.pathsep) + path_env_list.append(os.path.dirname(__file__)) + path_env_list = list(set(path_env_list)) + cmd = guidtool.command + if os.path.isabs(cmd): + if not os.path.exists(cmd): + if guidtool not in self.default_tools: + logger.error("Tool Not found %s, which causes compress/uncompress process error." % cmd) + logger.error("Please goto edk2 repo in current console, run 'edksetup.bat rebuild' command, and try again.\n") + else: + logger.error("Tool Not found %s, which causes compress/uncompress process error." % cmd) + else: + guidtool.ifexist = True + else: + for syspath in path_env_list: + if glob.glob(os.path.join(syspath, cmd+"*")): + guidtool.ifexist = True + break + else: + if guidtool not in self.default_tools: + logger.error("Tool Not found %s, which causes compress/uncompress process error." % cmd) + logger.error("Please goto edk2 repo in current console, run 'edksetup.bat rebuild' command, and try again.\n") + else: + logger.error("Tool Not found %s, which causes compress/uncompress process error." % cmd) + + def LoadingTools(self) -> None: + self.SetConfigFile() + if os.path.exists(self.tooldef_file): + with open(self.tooldef_file, "r") as fd: + config_data = fd.readlines() + for line in config_data: + try: + if not line.startswith("#"): + guid, short_name, command = line.split() + new_format_guid = struct2stream(ModifyGuidFormat(guid.strip())) + self.tooldef[new_format_guid] = GUIDTool( + guid.strip(), short_name.strip(), command.strip()) + except: + logger.error("GuidTool load error!") + continue + else: + self.tooldef.update(self.default_tools) + + def __getitem__(self, guid): + if not self.tooldef: + self.LoadingTools() + guid_tool = self.tooldef.get(guid) + if guid_tool: + self.VerifyTools(guid_tool) + return guid_tool + else: + logger.error("{} GuidTool is not defined!".format(guid)) + raise Exception("Process Failed: is not defined!") + +guidtools = GUIDTools() + diff --git a/BaseTools/Source/Python/FMMT/utils/FmmtLogger.py b/BaseTools/Source/Python/FMMT/utils/FmmtLogger.py index 385f098310..d9ff5e324b 100644 --- a/BaseTools/Source/Python/FMMT/utils/FmmtLogger.py +++ b/BaseTools/Source/Python/FMMT/utils/FmmtLogger.py @@ -1,31 +1,31 @@ -## @file
-# This file is used to define the Fmmt Logger.
-#
-# Copyright (c) 2021-, Intel Corporation. All rights reserved.<BR>
-# SPDX-License-Identifier: BSD-2-Clause-Patent
-
-##
-
-import logging
-import sys
-import os
-
-logfile = 'FMMT_Build.log'
-if os.path.exists(logfile):
- os.remove(logfile)
-
-FmmtLogger = logging.getLogger('FMMT')
-FmmtLogger.setLevel(logging.DEBUG)
-
-log_stream_handler=logging.StreamHandler(sys.stdout)
-log_file_handler=logging.FileHandler(logfile)
-log_stream_handler.setLevel(logging.INFO)
-
-stream_format=logging.Formatter("%(levelname)-8s: %(message)s")
-file_format=logging.Formatter("%(levelname)-8s: %(message)s")
-
-log_stream_handler.setFormatter(stream_format)
-log_file_handler.setFormatter(file_format)
-
-FmmtLogger.addHandler(log_stream_handler)
-FmmtLogger.addHandler(log_file_handler)
+## @file +# This file is used to define the Fmmt Logger. +# +# Copyright (c) 2021-, Intel Corporation. All rights reserved.<BR> +# SPDX-License-Identifier: BSD-2-Clause-Patent + +## + +import logging +import sys +import os + +logfile = 'FMMT_Build.log' +if os.path.exists(logfile): + os.remove(logfile) + +FmmtLogger = logging.getLogger('FMMT') +FmmtLogger.setLevel(logging.DEBUG) + +log_stream_handler=logging.StreamHandler(sys.stdout) +log_file_handler=logging.FileHandler(logfile) +log_stream_handler.setLevel(logging.INFO) + +stream_format=logging.Formatter("%(levelname)-8s: %(message)s") +file_format=logging.Formatter("%(levelname)-8s: %(message)s") + +log_stream_handler.setFormatter(stream_format) +log_file_handler.setFormatter(file_format) + +FmmtLogger.addHandler(log_stream_handler) +FmmtLogger.addHandler(log_file_handler) |
