## @ SyncBinFvInf.py
|
#
|
# Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
|
# SPDX-License-Identifier: BSD-2-Clause-Patent
|
#
|
##
|
|
import os
|
import re
|
import sys
|
import time
|
import shutil
|
from ctypes import *
|
|
class GUID(Structure):
|
_fields_ = [
|
('Guid1', c_uint32),
|
('Guid2', c_uint16),
|
('Guid3', c_uint16),
|
('Guid4', ARRAY(c_uint8, 8)),
|
]
|
|
|
class EFI_FIRMWARE_VOLUME_HEADER(Structure):
|
_fields_ = [
|
('ZeroVector', ARRAY(c_uint8, 16)),
|
('FileSystemGuid', GUID),
|
('FvLength', c_uint64),
|
('Signature', c_uint32),
|
('Attributes', c_uint32),
|
('HeaderLength', c_uint16),
|
('Checksum', c_uint16),
|
('ExtHeaderOffset', c_uint16),
|
('Reserved', c_uint8),
|
('Revision', c_uint8),
|
]
|
|
#
|
# File Types Definitions
|
#
|
EFI_FV_FILETYPE_ALL = 0x00
|
EFI_FV_FILETYPE_RAW = 0x01
|
EFI_FV_FILETYPE_FREEFORM = 0x02
|
EFI_FV_FILETYPE_SECURITY_CORE = 0x03
|
EFI_FV_FILETYPE_PEI_CORE = 0x04
|
EFI_FV_FILETYPE_DXE_CORE = 0x05
|
EFI_FV_FILETYPE_PEIM = 0x06
|
EFI_FV_FILETYPE_DRIVER = 0x07
|
EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER = 0x08
|
EFI_FV_FILETYPE_APPLICATION = 0x09
|
EFI_FV_FILETYPE_SMM = 0x0A
|
EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE = 0x0B
|
EFI_FV_FILETYPE_COMBINED_SMM_DXE = 0x0C
|
EFI_FV_FILETYPE_SMM_CORE = 0x0D
|
EFI_FV_FILETYPE_OEM_MIN = 0xc0
|
EFI_FV_FILETYPE_OEM_MAX = 0xdf
|
EFI_FV_FILETYPE_DEBUG_MIN = 0xe0
|
EFI_FV_FILETYPE_DEBUG_MAX = 0xef
|
EFI_FV_FILETYPE_FFS_MIN = 0xf0
|
EFI_FV_FILETYPE_FFS_MAX = 0xff
|
EFI_FV_FILETYPE_FFS_PAD = 0xf0
|
#
|
# FFS File Attributes.
|
#
|
FFS_ATTRIB_LARGE_FILE = 0x01
|
FFS_ATTRIB_DATA_ALIGNMENT_2 = 0x02
|
FFS_ATTRIB_FIXED = 0x04
|
FFS_ATTRIB_DATA_ALIGNMENT = 0x38
|
FFS_ATTRIB_CHECKSUM = 0x40
|
|
#
|
# FFS File State Bits.
|
#
|
EFI_FILE_HEADER_CONSTRUCTION = 0x01
|
EFI_FILE_HEADER_VALID = 0x02
|
EFI_FILE_DATA_VALID = 0x04
|
EFI_FILE_MARKED_FOR_UPDATE = 0x08
|
EFI_FILE_DELETED = 0x10
|
EFI_FILE_HEADER_INVALID = 0x20
|
|
class EFI_FFS_FILE_HEADER(Structure):
|
_fields_ = [
|
('Name', GUID),
|
('IntegrityCheck', c_uint16),
|
('Type', c_uint8),
|
('Attributes', c_uint8),
|
('Size', ARRAY(c_uint8, 3)),
|
('State', c_uint8),
|
]
|
|
class EFI_FFS_FILE_HEADER2(Structure):
|
_fields_ = [
|
('Name', GUID),
|
('IntegrityCheck', c_uint16),
|
('Type', c_uint8),
|
('Attributes', c_uint8),
|
('Size', ARRAY(c_uint8, 3)),
|
('State', c_uint8),
|
('ExtendedSize', c_uint64),
|
]
|
|
#
|
# Pseudo type. It is used as a wild card when retrieving sections.
|
# The section type EFI_SECTION_ALL matches all section types.
|
#
|
EFI_SECTION_ALL = 0x00
|
|
#
|
# Encapsulation section Type values.
|
#
|
EFI_SECTION_COMPRESSION = 0x01
|
|
EFI_SECTION_GUID_DEFINED = 0x02
|
|
EFI_SECTION_DISPOSABLE = 0x03
|
|
#
|
# Leaf section Type values.
|
#
|
EFI_SECTION_PE32 = 0x10
|
EFI_SECTION_PIC = 0x11
|
EFI_SECTION_TE = 0x12
|
EFI_SECTION_DXE_DEPEX = 0x13
|
EFI_SECTION_VERSION = 0x14
|
EFI_SECTION_USER_INTERFACE = 0x15
|
EFI_SECTION_COMPATIBILITY16 = 0x16
|
EFI_SECTION_FIRMWARE_VOLUME_IMAGE = 0x17
|
EFI_SECTION_FREEFORM_SUBTYPE_GUID = 0x18
|
EFI_SECTION_RAW = 0x19
|
EFI_SECTION_PEI_DEPEX = 0x1B
|
EFI_SECTION_SMM_DEPEX = 0x1C
|
|
class EFI_COMMON_SECTION_HEADER(Structure):
|
_fields_ = [
|
('Size', ARRAY(c_uint8, 3)),
|
('Type', c_uint8),
|
]
|
|
class EFI_COMMON_SECTION_HEADER2(Structure):
|
_fields_ = [
|
('Size', ARRAY(c_uint8, 3)),
|
('Type', c_uint8),
|
('ExtendedSize', c_uint32),
|
]
|
|
class FileChecker:
|
def __init__(self):
|
self.SyncSectionList = ["Packages", "PatchPcd", "PcdEx"]
|
self.RebasePcd = ["", "", ""]
|
self.FvName = ""
|
self.FfsGuidList = []
|
self.FfsInfList = []
|
self.FfsOffsetList = []
|
self.PeOffsetList = []
|
self.target = ""
|
self.sourceRoot = ""
|
self.sourceInfList = []
|
self.destRoot = ""
|
self.reportFile = ""
|
|
def GetSectionName(self, line):
|
splitLine = line[1:-1].split(".")
|
return splitLine[0]
|
|
def IsSyncSection(self, line):
|
name = self.GetSectionName(line)
|
for sectionName in self.SyncSectionList:
|
if (cmp (sectionName, name) == 0) :
|
return True
|
return False
|
|
def PrintRebasePcd(self, pcd):
|
if cmp (pcd[0], "") != 0:
|
print "PCD: " + pcd[0] + "|" + pcd[1] + "(" + pcd[2] + ")"
|
|
def PrintList(self, fileList):
|
for file in fileList:
|
print file
|
|
def GetFileList(self, dir, fileList, checkFunc):
|
if os.path.isdir(dir):
|
for sub in os.listdir(dir):
|
if sub[0] == "." :
|
continue
|
newDir = os.path.join(dir,sub)
|
if (os.path.isdir(newDir) == True):
|
self.GetFileList(newDir, fileList, checkFunc)
|
else :
|
AppendName = checkFunc (newDir)
|
if cmp (AppendName, "") != 0:
|
#print "AppendName = " + AppendName
|
if AppendName not in fileList:
|
fileList.append(AppendName)
|
|
def GetInfFileGuid(self, fileName):
|
guid = ""
|
try :
|
file = open(fileName)
|
except Exception:
|
print "fail to open " + fileName
|
return
|
try:
|
while 1:
|
line = file.readline()
|
if not line:
|
break
|
|
newline = line[:-1]
|
|
if cmp (line[:11], " FILE_GUID") == 0:
|
splitLine = line.split("=")
|
templine = splitLine[1]
|
guid = templine[1:1+36]
|
finally:
|
file.close()
|
return guid
|
|
def GetInfNameFromGuid(self, fileList, guid):
|
for file in fileList:
|
fileGuid = self.GetInfFileGuid (file)
|
if (cmp (fileGuid.upper(), guid.upper()) == 0) :
|
return file
|
return ""
|
|
def CheckSourceInf(self, file):
|
if (cmp (file[-4:], ".inf") == 0) and (file.find("BinPkg") != -1) and (file.find(self.target) != -1) and (file.find("FVFSP") == -1):
|
return file
|
return ""
|
|
def ParseInfFile(self, fileName, destFile, Offset):
|
SyncToDest = False
|
PatchOffset = False
|
try :
|
file = open(fileName)
|
except Exception:
|
print "fail to open " + fileName
|
return
|
try:
|
while 1:
|
line = file.readline()
|
if not line:
|
break
|
|
newline = line[:-1]
|
|
if cmp (line[0], "[") == 0:
|
SyncToDest = self.IsSyncSection(line)
|
PatchOffset = False
|
|
if SyncToDest == True :
|
if (cmp (self.GetSectionName(line), "PatchPcd") == 0) :
|
PatchOffset = True
|
|
if (PatchOffset == True) and ('|' in line) :
|
splitLine = line.split("|")
|
|
destFile.writelines(splitLine[0] + "|" + splitLine[1] + "|")
|
|
DataOffset = int(splitLine[2], 16)
|
DataOffset = DataOffset + int(Offset, 16)
|
destFile.writelines(hex(DataOffset))
|
|
destFile.writelines(" # " + splitLine[2][:-1] + "+" + Offset + "\n")
|
else :
|
destFile.writelines(line)
|
else :
|
destFile.write("# ")
|
destFile.writelines(line)
|
|
finally:
|
file.close()
|
return
|
|
def ParseInfFiles(self, fileList, FfsOffsetList, destFileName, RebasePcd):
|
try :
|
destFile = open(destFileName, "a")
|
except Exception:
|
print "fail to open " + destFileName
|
return
|
try:
|
if cmp (RebasePcd[0], "") != 0 :
|
destFile.write("\n#![Pcd]\n")
|
destFile.write("#! ")
|
destFile.write(RebasePcd[0])
|
destFile.write("|")
|
destFile.write(RebasePcd[1])
|
destFile.write("\n\n")
|
|
index = 0
|
for file in fileList:
|
if (cmp (file, "") == 0) :
|
index = index + 1
|
continue
|
print "handling - (" + str(index) + ") :" + file
|
self.ParseInfFile (file, destFile, FfsOffsetList[index])
|
index = index + 1
|
finally:
|
destFile.close()
|
return
|
|
def GetGuildFfsGuidList(self, fileName):
|
self.FfsGuidList = []
|
self.FfsOffsetList = []
|
try :
|
file = open(fileName)
|
except Exception:
|
print "fail to open " + fileName
|
return
|
try:
|
while 1:
|
line = file.readline()
|
if not line:
|
break
|
|
#0x000D4868 A8499E65-A6F6-48B0-96DB-45C266030D83
|
MatchString = "(0x[0-9a-fA-F]{8}) ([0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12})"
|
match = re.match(MatchString, line)
|
if match is not None:
|
offset = match.group(1)
|
self.FfsOffsetList.append(offset)
|
ffsGuid = match.group(2)
|
self.FfsGuidList.append(ffsGuid)
|
finally:
|
file.close()
|
return
|
|
def GetPeOffsetList(self, fileName):
|
self.PeOffsetList = []
|
try :
|
file = open(fileName, "rb")
|
except Exception:
|
print "fail to open " + fileName
|
return
|
try:
|
FvBuffer = file.read()
|
FvData = bytearray(FvBuffer)
|
|
for FfsOffset in self.FfsOffsetList:
|
PeOffsetFound = False
|
PeOffset = int(FfsOffset, 16)
|
FfsHeader = EFI_FFS_FILE_HEADER.from_buffer (FvData, PeOffset)
|
FfsSize = FfsHeader.Size[0] + (FfsHeader.Size[1] << 8) + (FfsHeader.Size[2] << 16)
|
PeOffset = PeOffset + sizeof(EFI_FFS_FILE_HEADER)
|
while (PeOffset < int(FfsOffset, 16) + FfsSize) :
|
SectionHeader = EFI_COMMON_SECTION_HEADER.from_buffer (FvData, PeOffset)
|
if (SectionHeader.Type == EFI_SECTION_PE32) or (SectionHeader.Type == EFI_SECTION_TE) :
|
PeOffset = PeOffset + sizeof(EFI_COMMON_SECTION_HEADER)
|
self.PeOffsetList.append(hex(PeOffset))
|
PeOffsetFound = True
|
break
|
else:
|
SectionSize = SectionHeader.Size[0] + (SectionHeader.Size[1] << 8) + (SectionHeader.Size[2] << 16)
|
PeOffset = (PeOffset + SectionSize + 3) & ~0x3
|
if (PeOffsetFound == False):
|
self.PeOffsetList.append(0)
|
|
finally:
|
file.close()
|
return
|
|
def ProcessFvInf(self, fvName, RebasePcd):
|
destFile = os.path.join(self.destRoot,fvName+"\\"+self.target+"\\"+fvName+".Fv.txt")
|
print "\nprocessing - " + destFile
|
self.GetGuildFfsGuidList (destFile)
|
|
#print "FfsGuidList"
|
#self.PrintList(self.FfsGuidList)
|
#print "FfsOffsetList"
|
#self.PrintList(self.FfsOffsetList)
|
|
destFile = os.path.join(self.destRoot,fvName+"\\"+self.target+"\\"+fvName+".Fv")
|
self.GetPeOffsetList (destFile)
|
|
#print "PeOffsetList"
|
#self.PrintList(self.PeOffsetList)
|
|
self.FfsInfList = []
|
for guid in self.FfsGuidList:
|
fileName = self.GetInfNameFromGuid(self.sourceInfList, guid)
|
print " adding - " + guid + " : " + fileName
|
self.FfsInfList.append(fileName)
|
|
#print "FfsInfList"
|
#self.PrintList(self.FfsInfList)
|
|
shutil.copy(os.path.join(self.destRoot,fvName+"\\"+self.target+"\\"+fvName+".Base.inf"),os.path.join(self.destRoot,fvName+"\\"+self.target+"\\"+fvName+".inf"))
|
|
self.ParseInfFiles (self.FfsInfList, self.PeOffsetList, os.path.join(self.destRoot,fvName+"\\"+self.target+"\\"+fvName+".inf"), RebasePcd)
|
|
def GetPcdFromReport(self, file, pcd):
|
FoundPkg = False
|
pcdSplit = pcd.split(".")
|
TargetPkg = pcdSplit[0]
|
TargetPcd = pcdSplit[1]
|
while 1:
|
line = file.readline()
|
if not line:
|
break
|
|
newline = line[:-1]
|
|
if (cmp (newline, TargetPkg) == 0):
|
FoundPkg = True
|
continue
|
|
if (cmp (newline, "") == 0) or ((cmp (newline[0], " ") != 0) and (cmp (newline[0], "0") != 0)):
|
FoundPkg = False
|
|
if (FoundPkg == True) :
|
newline = newline.strip()
|
splitLine = newline.split(" ", 2)
|
if (cmp (splitLine[0], "*F") == 0) or (cmp (splitLine[0], "*P") == 0):
|
if (cmp (splitLine[1], TargetPcd) == 0):
|
print "found - " + TargetPkg + "." + TargetPcd
|
|
splitLine = splitLine[2].strip()[1:].strip().split(" ", 1)
|
if (cmp (splitLine[0], "FIXED") == 0) or (cmp (splitLine[0], "PATCH") == 0):
|
SplitLine = splitLine[1].strip()[1:].split(")", 1)
|
Type = SplitLine[0]
|
Value = SplitLine[1].strip()[1:].strip().split()[0]
|
print " Type - (" + Type + "), Value - (" + Value + ")"
|
return [Value, Type]
|
return ["", ""]
|
|
def GetRebaseAddressFromReport(self):
|
try :
|
file = open(self.reportFile)
|
except Exception:
|
print "fail to open " + self.reportFile
|
return
|
try:
|
file.seek(0)
|
if (cmp(self.RebasePcd[0], "") != 0):
|
print "checking - " + self.RebasePcd[0]
|
ValuePair = self.GetPcdFromReport (file, self.RebasePcd[0])
|
self.RebasePcd[1] = ValuePair[0]
|
self.RebasePcd[2] = ValuePair[1]
|
finally:
|
file.close()
|
|
def DumpFileList(self, dir):
|
#print "DumpFileList - " + dir
|
if os.path.exists(dir) == False:
|
return
|
if os.path.isdir(dir):
|
for sub in os.listdir(dir):
|
#print "Get sub - " + sub
|
if sub[0] == "." :
|
continue
|
newDir = os.path.join(dir,sub)
|
if (os.path.isdir(newDir) == True):
|
self.DumpFileList(newDir)
|
else :
|
print "file - " + newDir
|
|
def main():
|
global FileChecker
|
|
fileChecker = FileChecker()
|
|
if (len(sys.argv) != 6) and (len(sys.argv) != 7):
|
print "usage: SyncBinFvInf <Target> <SourceRoot> <DestRoot> <ReportFile> <FspFvName> [<RebasePcdName>]"
|
return 0
|
|
fileChecker.target = sys.argv[1]
|
fileChecker.sourceRoot = sys.argv[2]
|
fileChecker.destRoot = sys.argv[3]
|
fileChecker.reportFile = sys.argv[4]
|
fileChecker.FvName = sys.argv[5]
|
if (len(sys.argv) == 7):
|
fileChecker.RebasePcd[0] = sys.argv[6]
|
|
fileChecker.GetRebaseAddressFromReport()
|
fileChecker.PrintRebasePcd (fileChecker.RebasePcd)
|
|
fileChecker.GetFileList (fileChecker.sourceRoot, fileChecker.sourceInfList, fileChecker.CheckSourceInf)
|
|
fileChecker.ProcessFvInf (fileChecker.FvName, fileChecker.RebasePcd)
|
|
if __name__ == '__main__':
|
sys.exit(main())
|