Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Yingke Liu <yingke.d....@intel.com>
---
 BaseTools/Source/Python/Common/Misc.py             |  21 ++++
 .../Source/Python/CommonDataClass/FdfClass.py      |   1 +
 BaseTools/Source/Python/GenFds/Capsule.py          |  89 +++++++++++++++
 BaseTools/Source/Python/GenFds/CapsuleData.py      |  72 +++++++++++-
 BaseTools/Source/Python/GenFds/FdfParser.py        | 122 ++++++++++++++++++---
 5 files changed, 288 insertions(+), 17 deletions(-)

diff --git a/BaseTools/Source/Python/Common/Misc.py 
b/BaseTools/Source/Python/Common/Misc.py
index fc1680b..8ba5819 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 ce3df12..f758d35 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 85f95a6..1683433 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 2d532be..efc2812 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 8091a51..ffc54ab 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
-- 
1.9.5.msysgit.0


------------------------------------------------------------------------------
_______________________________________________
edk2-devel mailing list
edk2-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/edk2-devel

Reply via email to