## @ SyncBinFvInf.py # # Copyright (c) 2017, Intel Corporation. All rights reserved.
# 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 []" 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())