Hi, all
  This BaseTool feature is to help generate UEFI FMP format capsule image. It 
reuses Capsule section and bases on specific capsule GUID to know this is FMP 
capsule image. The following is sample in FDF file for FMP capsule. It will be 
documented in FDF spec. If you have any comments for it, please let me know. 

Platform.fdf file:
[FmpPayload.Payload1]
IMAGE_HEADER_INIT_VERSION = 0x02                                                
 # FMP payload header
IMAGE_TYPE_ID  = 938A6F2E-9711-49CE-90D5-7ED68AC96501 # FMP payload header
IMAGE_INDEX    = 0x1    # FMP payload header
HARDWARE_INSTANCE = 0x0 # FMP payload header

FILE DATA = UpdateImage.bin
FILE DATA = VendorCodeByes.bin  # optional

[Capsule.FmpCapsuleImage]
CAPSULE_GUID  = 6dcbd5ed-e82d-4c44-bda1-7194199ad92a  # normal header FMP  
special Guid defined in UEFI spec
CAPSULE_FLAGS = PersistAcrossReset,InitiateReset   # normal header
CAPSULE_HEADER_SIZE = 0x20                                      # normal header
CAPSULE_HEADER_INIT_VERSION = 0x1                     # FMP header

FILE DATA = Driver1.efi
FILE DATA = Driver2.efi  # zero or more
FMP_PAYLOAD = Payload1   # zero or more

Thanks
Liming
-----Original Message-----
From: Yingke Liu [mailto:yingke.d....@intel.com] 
Sent: Monday, June 15, 2015 3:39 PM
To: edk2-devel@lists.sourceforge.net
Subject: [edk2] [Patch] BaseTools: Supported FMP capsule image.

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

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

Reply via email to