Commit a64b9449 authored by Chen, Christine's avatar Chen, Christine Committed by mergify[bot]
Browse files

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: default avatarYuwei Chen <yuwei.chen@intel.com>
Reviewed-by: default avatarBob Feng <bob.c.feng@intel.com>
Acked-by: default avatarLiming Gao <gaoliming@byosoft.com.cn>
parent 101f4c78
#!/usr/bin/env bash
#python `dirname $0`/RunToolFromSource.py `basename $0` $*
# If a ${PYTHON_COMMAND} command is available, use it in preference to python
if command -v ${PYTHON_COMMAND} >/dev/null 2>&1; then
python_exe=${PYTHON_COMMAND}
fi
full_cmd=${BASH_SOURCE:-$0} # see http://mywiki.wooledge.org/BashFAQ/028 for a discussion of why $0 is not a good choice here
dir=$(dirname "$full_cmd")
cmd=${full_cmd##*/}
export PYTHONPATH="$dir/../../Source/Python:$dir/../../Source/Python/FMMT:$dir/../../Source/Python${PYTHONPATH:+:"$PYTHONPATH"}"
exec "${python_exe:-python}" -m $cmd.$cmd "$@"
@setlocal
@set ToolName=%~n0%
@set PYTHONPATH=%PYTHONPATH%;%BASE_TOOLS_PATH%\Source\Python;%BASE_TOOLS_PATH%\Source\Python\FMMT
@%PYTHON_COMMAND% -m %ToolName%.%ToolName% %*
# @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'")
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.")
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
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 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])
else:
parser.print_help()
except Exception as e:
print(e)
return status
if __name__ == "__main__":
exit(main())
## @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
# FMMT
## Overview
This FMMT tool is the python implementation of the edk2 FMMT tool which locates at https://github.com/tianocore/edk2-staging/tree/FceFmmt.
This implementation has the same usage as the edk2 FMMT, but it's more readable and relaiable.
# FMMT User Guide
#### Last updated April 28, 2022
Important Changes and Updates:
- Oct 13, 2021 Initial Draft of FMMT Python Tool
- Apr 28, 2022 Optimize functions & Command line
#### Note:
- FMMT Python Tool keeps same function with origin FMMT C Tool. It is much easier to maintain and extend other functions.
#### Known issue:
- Currently, FMMT Python tool does not support PEIM rebase feature, this feature will be added in future update.
# 1. Introduction
## 1.1 Overview
The Firmware Device is a persistent physical repository that contains firmware code and/or data. The firmware code and/or data stored in Firmware Volumes. Detail layout of Firmware Volumes is described in ?Figure 1. The Firmware Volume Format?.
![](Img/FirmwareVolumeFormat.png)
? Figure 1. The Firmware Volume Format
In firmware development, binary file has its firmware layout following the Platform-Initialization Specification. Thus, operation on FV file / FFS file (Firmware File) is an efficient and convenient way for firmware function testing and developing. FMMT Python tool is used for firmware files operation.
## 1.2 Tool Capabilities
The FMMT tool is capable of:
- Parse a FD (Firmware Device) / FV (Firmware Volume) / FFS (Firmware Files)
- Add a new FFS into a FV file (both included in a FD file or not)
- Replace an FFS in a FV file with a new FFS file
- Delete an FFS in a FV file (both included in a FD file or not)
- Extract the FFS from a FV file (both included in a FD file or not)
## 1.3 References
| Document |
| ------------------------------------------------ |
| UEFI Platform Initialization (PI) Specification |
# 2. FMMT Python Tool Usage
## 2.1 Required Files
### 2.1.1 Independent use
When independent use the FMMT Python Tool, the following files and settings are required:
- GuidTool executable files used for Decompress/Compress Firmware data.
- Environment variables path with GuidTool path setting.
### 2.1.2 Use with Build System
When use the FMMT Python Tool with Build System:
- If only use Edk2 based GuidTool, do not need other preparation.
- If use other customized GuidTool, need prepare the config file with GuidTool info. The syntax for GuidTool definition shown as follow:
***ToolsGuid ShortName Command***
-- Example: ***3d532050-5cda-4fd0-879e-0f7f630d5afb BROTLI BrotliCompress***
## 2.2 Syntax
### 2.2.1 Syntax for Parse file
***-v < Inputfile > < Outputfile > -l < LogFileType > -c < ConfigFilePath >***
- Parse *Inputfile*, show its firmware layout with log file. *Outputfile* is optional, if inputs, the *Inputfile* will be encapsulated into *Outputfile* following the parsed firmware layout. *"-l LogFileType"* is optional, it decides the format of log file which saves Binary layout. Currently supports: json, txt. More formats will be added in the future. *"-c ConfigFilePath "* is optional, target FmmtConf.ini file can be selected with this parameter. If not provided, default FmmtConf.ini file will be used.
- Ex: py -3 FMMT.py -v test.fd
### 2.2.2 Syntax for Add a new FFS
***-a < Inputfile > < TargetFvName/TargetFvGuid > < NewFfsFile > < Outputfile >***
- Add the *NewFfsFile* into *Inputfile*. *TargetFvName/TargetFvGuid* (Name or Guid) is the TargetFv which *NewFfsFile* will be added into.
- Ex: py -3 FMMT.py -a Ovmf.fd 6938079b-b503-4e3d-9d24-b28337a25806 NewAdd.ffs output.fd
### 2.2.3 Syntax for Delete an FFS
***-d < Inputfile > < TargetFvName/TargetFvGuid > < TargetFfsName > < Outputfile >***
- Delete the Ffs from *Inputfile*. TargetFfsName (Guid) is the TargetFfs which will be deleted. *TargetFvName/TargetFvGuid* is optional, which is the parent of TargetFfs*.*
- Ex: py -3 FMMT.py -d Ovmf.fd 6938079b-b503-4e3d-9d24-b28337a25806 S3Resume2Pei output.fd
### 2.2.4 Syntax for Replace an FFS
? ***-r < Inputfile > < TargetFvName/TargetFvGuid > < TargetFfsName > < NewFfsFile > < Outputfile >***
- Replace the Ffs with the NewFfsFile. TargetFfsName (Guid) is the TargetFfs which will be replaced. *TargetFvName/TargetFvGuid* is optional, which is the parent of TargetFfs*.*
- Ex: py -3 FMMT.py -r Ovmf.fd 6938079b-b503-4e3d-9d24-b28337a25806 S3Resume2Pei NewS3Resume2Pei.ffs output.fd
### 2.2.5 Syntax for Extract an FFS
***-e < Inputfile > < TargetFvName/TargetFvGuid > < TargetFfsName > < Outputfile >***
- Extract the Ffs from the Inputfile. TargetFfsName (Guid) is the TargetFfs which will be extracted. *TargetFvName/TargetFvGuid* is optional, which is the parent of TargetFfs*.*
- Ex: py -3 FMMT.py -e Ovmf.fd 6938079b-b503-4e3d-9d24-b28337a25806 S3Resume2Pei output.fd
# 3. FMMT Python Tool Design
FMMT Python Tool uses the NodeTree saves whole Firmware layout. Each Node have its Data field, which saves the FirmwareClass(FD/FV/FFS/SECTION/BINARY) Data. All the parse/add/delete/replace/extract operations are based on the NodeTree (adjusting the layout and data).
## 3.1 NodeTree
A whole NodeTree saves all the Firmware info.
- Parent & Child relationship figured out the Firmware layout.
- Each Node have several fields. ?Data? field saves an FirmwareClass instance which contains all the data info of the info.
### 3.1.1 NodeTree Format
The NodeTree will be created with parse function. When parse a file, a Root Node will be initialized firstly. The Data split and Tree construction process is described with an FD file shown as ?Figure 2. The NodeTree format?:
- A Root Node is initialized.
- Use the ?FV Signature? as FV key to split Whole FD Data. ?FV0?, ?FV1?, ?FV2?? Node created.
- After FV level Node created, use the ?Ffs Data Size? as FFS key to split each FV Data. ?Ffs0?...Node created.
- After FFS level Node created, use the ?Section Data Size? as Section key to split each Ffs Data. ?Section0?...Node created.
- If some of Section includes other Sections, continue use the ?Section Data Size? as Section key to split each Section Data.
- After all Node created, the whole NodeTree saves all the info. (Can be used in other functions or print the whole firmware layout into log file)
![](Img/NodeTreeFormat.png)
? Figure 2. The NodeTree format
### 3.1.2 Node Factory and Product
As 3.1.1, Each Node is created by data split and recognition. To extend the NodeTree usage, Factory pattern is used in Node created process.
Each Node have its Factory to create Product and use Product ParserData function to deal with the data.
## 3.2 GuidTool
There are two ways to set the GuidTool. One from Config file, another from environment variables.
Current GuidTool first check if has Config file.
- If have, load the config GuidTool Information.
- Else get from environment variables.
### 3.2.1 Get from Config file
- Config file should in same folder with FMMT.py or the path in environment variables.
- Content should follow the format:
***ToolsGuid ShortName Command***
### 3.2.2 Get from Environment Variables
- The GuidTool Command used must be set in environment variables.
### 3.2.3 Edk2 Based GuidTool
| ***Guid*** | ***ShortName*** | ***Command*** |
| ------------------------------------------ | --------------- | --------------------- |
| ***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*** |
\ No newline at end of file
## @file
# This file is used to define the FMMT dependent external tool.
#
# Copyright (c) 2021-, Intel Corporation. All rights reserved.<BR>
# SPDX-License-Identifier: BSD-2-Clause-Patent
##
\ No newline at end of file
## @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_FV_TREE = 'ROOT_FV_TREE'
ROOT_FFS_TREE = 'ROOT_FFS_TREE'
ROOT_SECTION_TREE = 'ROOT_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 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: