BaseTools: Supported FMP capsule image.

Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Yingke Liu <yingke.d.liu@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>

git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@17678 6f19259b-4bc3-4df7-8a09-765794883524
This commit is contained in:
Yingke Liu
2015-06-23 06:46:01 +00:00
committed by yingke
parent f5bc9da5a3
commit a3251d8446
5 changed files with 289 additions and 18 deletions

View File

@@ -24,6 +24,7 @@ import re
import cPickle import cPickle
import array import array
import shutil import shutil
from struct import pack
from UserDict import IterableUserDict from UserDict import IterableUserDict
from UserList import UserList from UserList import UserList
@@ -2007,6 +2008,26 @@ class SkuClass():
AvailableSkuIdSet = property(__GetAvailableSkuIds) AvailableSkuIdSet = property(__GetAvailableSkuIds)
SkuUsageType = property(__SkuUsageType) SkuUsageType = property(__SkuUsageType)
AvailableSkuIdNumSet = property(__GetAvailableSkuIdNumber) AvailableSkuIdNumSet = property(__GetAvailableSkuIdNumber)
#
# Pack a registry format GUID
#
def PackRegistryFormatGuid(Guid):
Guid = Guid.split('-')
return pack('=LHHBBBBBBBB',
int(Guid[0], 16),
int(Guid[1], 16),
int(Guid[2], 16),
int(Guid[3][-4:-2], 16),
int(Guid[3][-2:], 16),
int(Guid[4][-12:-10], 16),
int(Guid[4][-10:-8], 16),
int(Guid[4][-8:-6], 16),
int(Guid[4][-6:-4], 16),
int(Guid[4][-4:-2], 16),
int(Guid[4][-2:], 16)
)
## ##
# #
# This acts like the main() function for the script, unless it is 'import'ed into another # This acts like the main() function for the script, unless it is 'import'ed into another

View File

@@ -360,6 +360,7 @@ class CapsuleClassObject :
# TokensDict[var] = value # TokensDict[var] = value
self.TokensDict = {} self.TokensDict = {}
self.CapsuleDataList = [] self.CapsuleDataList = []
self.FmpPayloadList = []
## VTF data in FDF ## VTF data in FDF
# #

View File

@@ -22,6 +22,9 @@ import subprocess
import StringIO import StringIO
from Common.Misc import SaveFileOnChange from Common.Misc import SaveFileOnChange
from GenFds import GenFds from GenFds import GenFds
from Common.Misc import PackRegistryFormatGuid
import uuid
from struct import pack
T_CHAR_LF = '\n' T_CHAR_LF = '\n'
@@ -42,6 +45,88 @@ class Capsule (CapsuleClassObject) :
self.BlockNum = None self.BlockNum = None
self.CapsuleName = None self.CapsuleName = None
## Generate FMP capsule
#
# @retval string Generated Capsule file path
#
def GenFmpCapsule(self):
#
# Generate capsule header
# typedef struct {
# EFI_GUID CapsuleGuid;
# UINT32 HeaderSize;
# UINT32 Flags;
# UINT32 CapsuleImageSize;
# } EFI_CAPSULE_HEADER;
#
Header = StringIO.StringIO()
#
# Use FMP capsule GUID: 6DCBD5ED-E82D-4C44-BDA1-7194199AD92A
#
Header.write(PackRegistryFormatGuid('6DCBD5ED-E82D-4C44-BDA1-7194199AD92A'))
HdrSize = 0
if 'CAPSULE_HEADER_SIZE' in self.TokensDict:
Header.write(pack('=I', int(self.TokensDict['CAPSULE_HEADER_SIZE'], 16)))
HdrSize = int(self.TokensDict['CAPSULE_HEADER_SIZE'], 16)
else:
Header.write(pack('=I', 0x20))
HdrSize = 0x20
Flags = 0
if 'CAPSULE_FLAGS' in self.TokensDict:
for flag in self.TokensDict['CAPSULE_FLAGS'].split(','):
flag = flag.strip()
if flag == 'PopulateSystemTable':
Flags |= 0x00010000 | 0x00020000
elif flag == 'PersistAcrossReset':
Flags |= 0x00010000
elif flag == 'InitiateReset':
Flags |= 0x00040000
Header.write(pack('=I', Flags))
#
# typedef struct {
# UINT32 Version;
# UINT16 EmbeddedDriverCount;
# UINT16 PayloadItemCount;
# // UINT64 ItemOffsetList[];
# } EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER;
#
FwMgrHdr = StringIO.StringIO()
if 'CAPSULE_HEADER_INIT_VERSION' in self.TokensDict:
FwMgrHdr.write(pack('=I', int(self.TokensDict['CAPSULE_HEADER_INIT_VERSION'], 16)))
else:
FwMgrHdr.write(pack('=I', 0x00000001))
FwMgrHdr.write(pack('=HH', len(self.CapsuleDataList), len(self.FmpPayloadList)))
FwMgrHdrSize = 4+2+2+8*(len(self.CapsuleDataList)+len(self.FmpPayloadList))
PreSize = FwMgrHdrSize
Content = StringIO.StringIO()
for driver in self.CapsuleDataList:
FileName = driver.GenCapsuleSubItem()
FwMgrHdr.write(pack('=Q', PreSize))
PreSize += os.path.getsize(FileName)
File = open(FileName, 'rb')
Content.write(File.read())
File.close()
for fmp in self.FmpPayloadList:
payload = fmp.GenCapsuleSubItem()
FwMgrHdr.write(pack('=Q', PreSize))
PreSize += len(payload)
Content.write(payload)
BodySize = len(FwMgrHdr.getvalue()) + len(Content.getvalue())
Header.write(pack('=I', HdrSize + BodySize))
#
# The real capsule header structure is 28 bytes
#
Header.write('\x00'*(HdrSize-28))
Header.write(FwMgrHdr.getvalue())
Header.write(Content.getvalue())
#
# Generate FMP capsule file
#
CapOutputFile = os.path.join(GenFdsGlobalVariable.FvDir, self.UiCapsuleName) + '.Cap'
SaveFileOnChange(CapOutputFile, Header.getvalue(), True)
return CapOutputFile
## Generate capsule ## Generate capsule
# #
# @param self The object pointer # @param self The object pointer
@@ -52,6 +137,10 @@ class Capsule (CapsuleClassObject) :
return GenFds.ImageBinDict[self.UiCapsuleName.upper() + 'cap'] return GenFds.ImageBinDict[self.UiCapsuleName.upper() + 'cap']
GenFdsGlobalVariable.InfLogger( "\nGenerate %s Capsule" %self.UiCapsuleName) GenFdsGlobalVariable.InfLogger( "\nGenerate %s Capsule" %self.UiCapsuleName)
if ('CAPSULE_GUID' in self.TokensDict and
uuid.UUID(self.TokensDict['CAPSULE_GUID']) == uuid.UUID('6DCBD5ED-E82D-4C44-BDA1-7194199AD92A')):
return self.GenFmpCapsule()
CapInfFile = self.GenCapInf() CapInfFile = self.GenCapInf()
CapInfFile.writelines("[files]" + T_CHAR_LF) CapInfFile.writelines("[files]" + T_CHAR_LF)
CapFileList = [] CapFileList = []

View File

@@ -18,6 +18,9 @@
import Ffs import Ffs
from GenFdsGlobalVariable import GenFdsGlobalVariable from GenFdsGlobalVariable import GenFdsGlobalVariable
import StringIO import StringIO
from struct import pack
import os
from Common.Misc import SaveFileOnChange
## base class for capsule data ## base class for capsule data
# #
@@ -155,3 +158,70 @@ class CapsuleAfile (CapsuleData):
# #
def GenCapsuleSubItem(self): def GenCapsuleSubItem(self):
return self.FileName return self.FileName
class CapsulePayload(CapsuleData):
'''Generate payload file, the header is defined below:
#pragma pack(1)
typedef struct {
UINT32 Version;
EFI_GUID UpdateImageTypeId;
UINT8 UpdateImageIndex;
UINT8 reserved_bytes[3];
UINT32 UpdateImageSize;
UINT32 UpdateVendorCodeSize;
UINT64 UpdateHardwareInstance; //Introduced in v2
} EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER;
'''
def __init__(self):
self.UiName = None
self.Version = None
self.ImageTypeId = None
self.ImageIndex = None
self.HardwareInstance = None
self.ImageFile = None
self.VendorCodeFile = None
def GenCapsuleSubItem(self):
if not self.Version:
self.Version = 0x00000002
ImageFileSize = os.path.getsize(self.ImageFile)
VendorFileSize = 0
if self.VendorCodeFile:
VendorFileSize = os.path.getsize(self.VendorCodeFile)
#
# Fill structure
#
Guid = self.ImageTypeId.split('-')
Buffer = pack('=ILHHBBBBBBBBBBBBIIQ',
int(self.Version,16),
int(Guid[0], 16),
int(Guid[1], 16),
int(Guid[2], 16),
int(Guid[3][-4:-2], 16),
int(Guid[3][-2:], 16),
int(Guid[4][-12:-10], 16),
int(Guid[4][-10:-8], 16),
int(Guid[4][-8:-6], 16),
int(Guid[4][-6:-4], 16),
int(Guid[4][-4:-2], 16),
int(Guid[4][-2:], 16),
int(self.ImageIndex, 16),
0,
0,
0,
ImageFileSize,
VendorFileSize,
int(self.HardwareInstance, 16)
)
#
# Append file content to the structure
#
ImageFile = open(self.ImageFile, 'rb')
Buffer += ImageFile.read()
ImageFile.close()
if self.VendorCodeFile:
VendorFile = open(self.VendorCodeFile, 'rb')
Buffer += VendorFile.read()
VendorFile.close()
return Buffer

View File

@@ -194,6 +194,7 @@ class FileProfile :
self.VtfList = [] self.VtfList = []
self.RuleDict = {} self.RuleDict = {}
self.OptRomDict = {} self.OptRomDict = {}
self.FmpPayloadDict = {}
## The syntax parser for FDF ## The syntax parser for FDF
# #
@@ -1304,6 +1305,9 @@ class FdfParser:
while self.__GetFv(): while self.__GetFv():
pass pass
while self.__GetFmp():
pass
while self.__GetCapsule(): while self.__GetCapsule():
pass pass
@@ -1387,7 +1391,7 @@ class FdfParser:
S = self.__Token.upper() S = self.__Token.upper()
if S.startswith("[") and not S.startswith("[FD."): if S.startswith("[") and not S.startswith("[FD."):
if not S.startswith("[FV.") and not S.startswith("[CAPSULE.") \ if not S.startswith("[FV.") and not S.startswith('[FMPPAYLOAD.') and not S.startswith("[CAPSULE.") \
and not S.startswith("[VTF.") and not S.startswith("[RULE.") and not S.startswith("[OPTIONROM."): and not S.startswith("[VTF.") and not S.startswith("[RULE.") and not S.startswith("[OPTIONROM."):
raise Warning("Unknown section", self.FileName, self.CurrentLineNumber) raise Warning("Unknown section", self.FileName, self.CurrentLineNumber)
self.__UndoToken() self.__UndoToken()
@@ -2024,7 +2028,7 @@ class FdfParser:
S = self.__Token.upper() S = self.__Token.upper()
if S.startswith("[") and not S.startswith("[FV."): if S.startswith("[") and not S.startswith("[FV."):
if not S.startswith("[CAPSULE.") \ if not S.startswith('[FMPPAYLOAD.') and not S.startswith("[CAPSULE.") \
and not S.startswith("[VTF.") and not S.startswith("[RULE.") and not S.startswith("[OPTIONROM."): and not S.startswith("[VTF.") and not S.startswith("[RULE.") and not S.startswith("[OPTIONROM."):
raise Warning("Unknown section or section appear sequence error (The correct sequence should be [FD.], [FV.], [Capsule.], [VTF.], [Rule.], [OptionRom.])", self.FileName, self.CurrentLineNumber) raise Warning("Unknown section or section appear sequence error (The correct sequence should be [FD.], [FV.], [Capsule.], [VTF.], [Rule.], [OptionRom.])", self.FileName, self.CurrentLineNumber)
self.__UndoToken() self.__UndoToken()
@@ -2996,6 +3000,67 @@ class FdfParser:
else: else:
return True return True
def __GetFmp(self):
if not self.__GetNextToken():
return False
S = self.__Token.upper()
if not S.startswith("[FMPPAYLOAD."):
if not S.startswith("[CAPSULE.") and not S.startswith("[VTF.") and not S.startswith("[RULE.") and not S.startswith("[OPTIONROM."):
raise Warning("Unknown section or section appear sequence error (The correct sequence should be [FD.], [FV.], [FmpPayload.], [Capsule.], [VTF.], [Rule.], [OptionRom.])", self.FileName, self.CurrentLineNumber)
self.__UndoToken()
return False
self.__UndoToken()
self.__SkipToToken("[FMPPAYLOAD.", True)
FmpUiName = self.__GetUiName().upper()
if FmpUiName in self.Profile.FmpPayloadDict:
raise Warning("Duplicated FMP UI name found: %s" % FmpUiName, self.FileName, self.CurrentLineNumber)
FmpData = CapsuleData.CapsulePayload()
FmpData.UiName = FmpUiName
if not self.__IsToken( "]"):
raise Warning("expected ']'", self.FileName, self.CurrentLineNumber)
if not self.__GetNextToken():
raise Warning("The FMP payload section is empty!", self.FileName, self.CurrentLineNumber)
FmpKeyList = ['IMAGE_HEADER_INIT_VERSION', 'IMAGE_TYPE_ID', 'IMAGE_INDEX', 'HARDWARE_INSTANCE']
while self.__Token in FmpKeyList:
Name = self.__Token
FmpKeyList.remove(Name)
if not self.__IsToken("="):
raise Warning("expected '='", self.FileName, self.CurrentLineNumber)
if Name == 'IMAGE_TYPE_ID':
if not self.__GetNextGuid():
raise Warning("expected GUID value for IMAGE_TYPE_ID", self.FileName, self.CurrentLineNumber)
FmpData.ImageTypeId = self.__Token
else:
if not self.__GetNextToken():
raise Warning("expected value of %s" % Name, self.FileName, self.CurrentLineNumber)
Value = self.__Token
if Name == 'IMAGE_HEADER_INIT_VERSION':
FmpData.Version = Value
elif Name == 'IMAGE_INDEX':
FmpData.ImageIndex = Value
elif Name == 'HARDWARE_INSTANCE':
FmpData.HardwareInstance = Value
if not self.__GetNextToken():
break
else:
self.__UndoToken()
if FmpKeyList:
raise Warning("Missing keywords %s in FMP payload section" % ', '.join(FmpKeyList), self.FileName, self.CurrentLineNumber)
ImageFile = self.__ParseRawFileStatement()
if not ImageFile:
raise Warning("Missing image file in FMP payload section", self.FileName, self.CurrentLineNumber)
FmpData.ImageFile = ImageFile
VendorCodeFile = self.__ParseRawFileStatement()
if VendorCodeFile:
FmpData.VendorCodeFile = VendorCodeFile
self.Profile.FmpPayloadDict[FmpUiName] = FmpData
return True
## __GetCapsule() method ## __GetCapsule() method
# #
# Get capsule section contents and store its data into capsule list of self.Profile # Get capsule section contents and store its data into capsule list of self.Profile
@@ -3070,7 +3135,7 @@ class FdfParser:
def __GetCapsuleTokens(self, Obj): def __GetCapsuleTokens(self, Obj):
if not self.__GetNextToken(): if not self.__GetNextToken():
return False return False
while self.__Token in ("CAPSULE_GUID", "CAPSULE_HEADER_SIZE", "CAPSULE_FLAGS", "OEM_CAPSULE_FLAGS"): while self.__Token in ("CAPSULE_GUID", "CAPSULE_HEADER_SIZE", "CAPSULE_FLAGS", "OEM_CAPSULE_FLAGS", "CAPSULE_HEADER_INIT_VERSION"):
Name = self.__Token.strip() Name = self.__Token.strip()
if not self.__IsToken("="): if not self.__IsToken("="):
raise Warning("expected '='", self.FileName, self.CurrentLineNumber) raise Warning("expected '='", self.FileName, self.CurrentLineNumber)
@@ -3121,7 +3186,8 @@ class FdfParser:
IsFd = self.__GetFdStatement(Obj) IsFd = self.__GetFdStatement(Obj)
IsAnyFile = self.__GetAnyFileStatement(Obj) IsAnyFile = self.__GetAnyFileStatement(Obj)
IsAfile = self.__GetAfileStatement(Obj) IsAfile = self.__GetAfileStatement(Obj)
if not (IsInf or IsFile or IsFv or IsFd or IsAnyFile or IsAfile): IsFmp = self.__GetFmpStatement(Obj)
if not (IsInf or IsFile or IsFv or IsFd or IsAnyFile or IsAfile or IsFmp):
break break
## __GetFvStatement() method ## __GetFvStatement() method
@@ -3180,23 +3246,32 @@ class FdfParser:
CapsuleObj.CapsuleDataList.append(CapsuleFd) CapsuleObj.CapsuleDataList.append(CapsuleFd)
return True return True
## __GetAnyFileStatement() method def __GetFmpStatement(self, CapsuleObj):
# if not self.__IsKeyword("FMP"):
# Get AnyFile for capsule
#
# @param self The object pointer
# @param CapsuleObj for whom AnyFile is got
# @retval True Successfully find a Anyfile statement
# @retval False Not able to find a AnyFile statement
#
def __GetAnyFileStatement(self, CapsuleObj):
if not self.__IsKeyword("FILE"):
return False return False
if not self.__IsKeyword("PAYLOAD"):
self.__UndoToken()
return False
if not self.__IsToken("="):
raise Warning("expected '='", self.FileName, self.CurrentLineNumber)
if not self.__GetNextToken():
raise Warning("expected payload name after FMP PAYLOAD =", self.FileName, self.CurrentLineNumber)
Payload = self.__Token.upper()
if Payload not in self.Profile.FmpPayloadDict:
raise Warning("This FMP Payload does not exist: %s" % self.__Token, self.FileName, self.CurrentLineNumber)
CapsuleObj.FmpPayloadList.append(self.Profile.FmpPayloadDict[Payload])
return True
def __ParseRawFileStatement(self):
if not self.__IsKeyword("FILE"):
return None
if not self.__IsKeyword("DATA"): if not self.__IsKeyword("DATA"):
self.__UndoToken() self.__UndoToken()
return False return None
if not self.__IsToken("="): if not self.__IsToken("="):
raise Warning("expected '='", self.FileName, self.CurrentLineNumber) raise Warning("expected '='", self.FileName, self.CurrentLineNumber)
@@ -3208,6 +3283,21 @@ class FdfParser:
AnyFileName = GenFdsGlobalVariable.ReplaceWorkspaceMacro(AnyFileName) AnyFileName = GenFdsGlobalVariable.ReplaceWorkspaceMacro(AnyFileName)
if not os.path.exists(AnyFileName): if not os.path.exists(AnyFileName):
raise Warning("File %s not exists"%AnyFileName, self.FileName, self.CurrentLineNumber) raise Warning("File %s not exists"%AnyFileName, self.FileName, self.CurrentLineNumber)
return AnyFileName
## __GetAnyFileStatement() method
#
# Get AnyFile for capsule
#
# @param self The object pointer
# @param CapsuleObj for whom AnyFile is got
# @retval True Successfully find a Anyfile statement
# @retval False Not able to find a AnyFile statement
#
def __GetAnyFileStatement(self, CapsuleObj):
AnyFileName = self.__ParseRawFileStatement()
if not AnyFileName:
return False
CapsuleAnyFile = CapsuleData.CapsuleAnyFile() CapsuleAnyFile = CapsuleData.CapsuleAnyFile()
CapsuleAnyFile.FileName = AnyFileName CapsuleAnyFile.FileName = AnyFileName