BaseTools: Add FMMT Python Tool
The FMMT python tool is used for firmware files operation, which has the Fv/FFs-based 'View'&'Add'&'Delete'&'Replace' operation function: 1.Parse a FD(Firmware Device) / FV(Firmware Volume) / FFS(Firmware Files) 2.Add a new FFS into a FV file (both included in a FD file or not) 3.Replace an FFS in a FV file with a new FFS file 4.Delete an FFS in a FV file (both included in a FD file or not) 5.Extract the FFS from a FV file (both included in a FD file or not) This version of FMMT Python tool does not support PEIM rebase feature, this feature will be added in future update. Currently the FMMT C tool is saved in edk2-staging repo, but its quality and coding style can't meet the Edk2 quality, which is hard to maintain (Hard/Duplicate Code; Regression bugs; Restrict usage). The new Python version keeps same functions with origin C version. It has higher quality and better coding style, and it is much easier to extend new functions and to maintain. REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1847 RFC Link: https://edk2.groups.io/g/devel/message/82877 Staging Link: https://github.com/tianocore/edk2-staging/tree/PyFMMT Cc: Bob Feng <bob.c.feng@intel.com> Cc: Liming Gao <gaoliming@byosoft.com.cn> Signed-off-by: Yuwei Chen <yuwei.chen@intel.com> Reviewed-by: Bob Feng <bob.c.feng@intel.com> Acked-by: Liming Gao <gaoliming@byosoft.com.cn>
This commit is contained in:
committed by
mergify[bot]
parent
101f4c7892
commit
a64b944942
197
BaseTools/Source/Python/FMMT/core/FMMTOperation.py
Normal file
197
BaseTools/Source/Python/FMMT/core/FMMTOperation.py
Normal file
@ -0,0 +1,197 @@
|
||||
## @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:
|
||||
for item in FmmtParser.WholeFvTree.Findlist:
|
||||
if item.Parent.key != Fv_name and item.Parent.Data.Name != Fv_name:
|
||||
FmmtParser.WholeFvTree.Findlist.remove(item)
|
||||
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:
|
||||
for item in FmmtParser.WholeFvTree.Findlist:
|
||||
if item.Parent.key != Fv_name and item.Parent.Data.Name != Fv_name:
|
||||
FmmtParser.WholeFvTree.Findlist.remove(item)
|
||||
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:
|
||||
for item in FmmtParser.WholeFvTree.Findlist:
|
||||
if item.Parent.key != Fv_name and item.Parent.Data.Name != Fv_name:
|
||||
FmmtParser.WholeFvTree.Findlist.remove(item)
|
||||
if FmmtParser.WholeFvTree.Findlist != []:
|
||||
TargetNode = FmmtParser.WholeFvTree.Findlist[0]
|
||||
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 not found!!!')
|
Reference in New Issue
Block a user