mirror of https://github.com/acidanthera/audk.git
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:
parent
f5bc9da5a3
commit
a3251d8446
|
@ -24,6 +24,7 @@ import re
|
|||
import cPickle
|
||||
import array
|
||||
import shutil
|
||||
from struct import pack
|
||||
from UserDict import IterableUserDict
|
||||
from UserList import UserList
|
||||
|
||||
|
@ -2007,6 +2008,26 @@ class SkuClass():
|
|||
AvailableSkuIdSet = property(__GetAvailableSkuIds)
|
||||
SkuUsageType = property(__SkuUsageType)
|
||||
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
|
||||
|
|
|
@ -360,6 +360,7 @@ class CapsuleClassObject :
|
|||
# TokensDict[var] = value
|
||||
self.TokensDict = {}
|
||||
self.CapsuleDataList = []
|
||||
self.FmpPayloadList = []
|
||||
|
||||
## VTF data in FDF
|
||||
#
|
||||
|
|
|
@ -22,6 +22,9 @@ import subprocess
|
|||
import StringIO
|
||||
from Common.Misc import SaveFileOnChange
|
||||
from GenFds import GenFds
|
||||
from Common.Misc import PackRegistryFormatGuid
|
||||
import uuid
|
||||
from struct import pack
|
||||
|
||||
|
||||
T_CHAR_LF = '\n'
|
||||
|
@ -42,6 +45,88 @@ class Capsule (CapsuleClassObject) :
|
|||
self.BlockNum = 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
|
||||
#
|
||||
# @param self The object pointer
|
||||
|
@ -52,6 +137,10 @@ class Capsule (CapsuleClassObject) :
|
|||
return GenFds.ImageBinDict[self.UiCapsuleName.upper() + 'cap']
|
||||
|
||||
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.writelines("[files]" + T_CHAR_LF)
|
||||
CapFileList = []
|
||||
|
|
|
@ -18,6 +18,9 @@
|
|||
import Ffs
|
||||
from GenFdsGlobalVariable import GenFdsGlobalVariable
|
||||
import StringIO
|
||||
from struct import pack
|
||||
import os
|
||||
from Common.Misc import SaveFileOnChange
|
||||
|
||||
## base class for capsule data
|
||||
#
|
||||
|
@ -155,3 +158,70 @@ class CapsuleAfile (CapsuleData):
|
|||
#
|
||||
def GenCapsuleSubItem(self):
|
||||
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
|
||||
|
|
|
@ -194,6 +194,7 @@ class FileProfile :
|
|||
self.VtfList = []
|
||||
self.RuleDict = {}
|
||||
self.OptRomDict = {}
|
||||
self.FmpPayloadDict = {}
|
||||
|
||||
## The syntax parser for FDF
|
||||
#
|
||||
|
@ -1304,6 +1305,9 @@ class FdfParser:
|
|||
while self.__GetFv():
|
||||
pass
|
||||
|
||||
while self.__GetFmp():
|
||||
pass
|
||||
|
||||
while self.__GetCapsule():
|
||||
pass
|
||||
|
||||
|
@ -1387,7 +1391,7 @@ class FdfParser:
|
|||
|
||||
S = self.__Token.upper()
|
||||
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."):
|
||||
raise Warning("Unknown section", self.FileName, self.CurrentLineNumber)
|
||||
self.__UndoToken()
|
||||
|
@ -2024,7 +2028,7 @@ class FdfParser:
|
|||
|
||||
S = self.__Token.upper()
|
||||
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."):
|
||||
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()
|
||||
|
@ -2996,6 +3000,67 @@ class FdfParser:
|
|||
else:
|
||||
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
|
||||
#
|
||||
# Get capsule section contents and store its data into capsule list of self.Profile
|
||||
|
@ -3070,7 +3135,7 @@ class FdfParser:
|
|||
def __GetCapsuleTokens(self, Obj):
|
||||
if not self.__GetNextToken():
|
||||
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()
|
||||
if not self.__IsToken("="):
|
||||
raise Warning("expected '='", self.FileName, self.CurrentLineNumber)
|
||||
|
@ -3121,7 +3186,8 @@ class FdfParser:
|
|||
IsFd = self.__GetFdStatement(Obj)
|
||||
IsAnyFile = self.__GetAnyFileStatement(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
|
||||
|
||||
## __GetFvStatement() method
|
||||
|
@ -3180,23 +3246,32 @@ class FdfParser:
|
|||
CapsuleObj.CapsuleDataList.append(CapsuleFd)
|
||||
return True
|
||||
|
||||
## __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):
|
||||
|
||||
if not self.__IsKeyword("FILE"):
|
||||
def __GetFmpStatement(self, CapsuleObj):
|
||||
if not self.__IsKeyword("FMP"):
|
||||
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"):
|
||||
self.__UndoToken()
|
||||
return False
|
||||
return None
|
||||
|
||||
if not self.__IsToken("="):
|
||||
raise Warning("expected '='", self.FileName, self.CurrentLineNumber)
|
||||
|
@ -3208,6 +3283,21 @@ class FdfParser:
|
|||
AnyFileName = GenFdsGlobalVariable.ReplaceWorkspaceMacro(AnyFileName)
|
||||
if not os.path.exists(AnyFileName):
|
||||
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.FileName = AnyFileName
|
||||
|
|
Loading…
Reference in New Issue