summaryrefslogtreecommitdiff
path: root/BaseTools/Source
diff options
context:
space:
mode:
authorYingke Liu <yingke.d.liu@intel.com>2015-06-23 06:46:01 +0000
committeryingke <yingke@Edk2>2015-06-23 06:46:01 +0000
commita3251d844695f90711bfe094f12755fd01742369 (patch)
treef2b29b86c0cc238b74491233adbca4b04aa83eac /BaseTools/Source
parentf5bc9da5a3b36b73f5bff4b31f81ed7278f14ec1 (diff)
downloadedk2-platforms-a3251d844695f90711bfe094f12755fd01742369.tar.xz
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
Diffstat (limited to 'BaseTools/Source')
-rw-r--r--BaseTools/Source/Python/Common/Misc.py21
-rw-r--r--BaseTools/Source/Python/CommonDataClass/FdfClass.py1
-rw-r--r--BaseTools/Source/Python/GenFds/Capsule.py89
-rw-r--r--BaseTools/Source/Python/GenFds/CapsuleData.py72
-rw-r--r--BaseTools/Source/Python/GenFds/FdfParser.py122
5 files changed, 288 insertions, 17 deletions
diff --git a/BaseTools/Source/Python/Common/Misc.py b/BaseTools/Source/Python/Common/Misc.py
index fc1680b5ed..8ba5819cc1 100644
--- a/BaseTools/Source/Python/Common/Misc.py
+++ b/BaseTools/Source/Python/Common/Misc.py
@@ -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
diff --git a/BaseTools/Source/Python/CommonDataClass/FdfClass.py b/BaseTools/Source/Python/CommonDataClass/FdfClass.py
index ce3df12058..f758d35ba1 100644
--- a/BaseTools/Source/Python/CommonDataClass/FdfClass.py
+++ b/BaseTools/Source/Python/CommonDataClass/FdfClass.py
@@ -360,6 +360,7 @@ class CapsuleClassObject :
# TokensDict[var] = value
self.TokensDict = {}
self.CapsuleDataList = []
+ self.FmpPayloadList = []
## VTF data in FDF
#
diff --git a/BaseTools/Source/Python/GenFds/Capsule.py b/BaseTools/Source/Python/GenFds/Capsule.py
index 85f95a69c1..1683433e43 100644
--- a/BaseTools/Source/Python/GenFds/Capsule.py
+++ b/BaseTools/Source/Python/GenFds/Capsule.py
@@ -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 = []
diff --git a/BaseTools/Source/Python/GenFds/CapsuleData.py b/BaseTools/Source/Python/GenFds/CapsuleData.py
index 2d532bea04..efc281222b 100644
--- a/BaseTools/Source/Python/GenFds/CapsuleData.py
+++ b/BaseTools/Source/Python/GenFds/CapsuleData.py
@@ -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
#
@@ -154,4 +157,71 @@ class CapsuleAfile (CapsuleData):
# @retval string Generated file name
#
def GenCapsuleSubItem(self):
- return self.FileName \ No newline at end of file
+ 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
diff --git a/BaseTools/Source/Python/GenFds/FdfParser.py b/BaseTools/Source/Python/GenFds/FdfParser.py
index 8091a51f35..ffc54abc84 100644
--- a/BaseTools/Source/Python/GenFds/FdfParser.py
+++ b/BaseTools/Source/Python/GenFds/FdfParser.py
@@ -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):
+ def __GetFmpStatement(self, CapsuleObj):
+ if not self.__IsKeyword("FMP"):
+ return False
- if not self.__IsKeyword("FILE"):
+ 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