]> git.proxmox.com Git - mirror_edk2.git/commitdiff
BaseTools/Capsule: Add capsule dependency support
authorLi, Aaron <aaron.li@intel.com>
Fri, 10 Jan 2020 01:57:35 +0000 (09:57 +0800)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Wed, 15 Jan 2020 03:16:46 +0000 (03:16 +0000)
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=2412

Capsule generate tool support encode capsule dependencies through '-j'
command with a JSON file. To enable dependency feature, "Dependencies"
field for each payload in JSON file is required.
The value of "Dependencies" field is C style infix notation expression.
For example:
  "Dependencies":"72E2945A-00DA-448E-9AA7-075AD840F9D4 > 0x00000001"

The relation of Dependency Expression Opcode in UEFI2.8 chap 23.2 and
infix notation expression value is as follows:
+-----------------------------+--------------------------+
| OPCODE                      | INFIX EXPRESSION VALUE   |
+-----------------------------+--------------------------+
| 0x00 (PUSH_GUID)            | {GUID}                   |
| 0x01 (PUSH_VERSION)         | {UINT32}                 |
| 0x02 (DECLEAR_VERSION_NAME} | DECLEAR "{VERSION_NAME}" |
| 0x03 (AND)                  | &&                       |
| 0x04 (OR)                   | ||                       |
| 0x05 (NOT)                  | ~                        |
| 0x06 (TRUE)                 | TRUE                     |
| 0x07 (FALSE)                | FALSE                    |
| 0x08 (EQ)                   | ==                       |
| 0x09 (GT)                   | >                        |
| 0x0A (GTE)                  | >=                       |
| 0x0B (LT)                   | <                        |
| 0x0C (LTE)                  | <=                       |
+-----------------------------+--------------------------+

Cc: Bob Feng <bob.c.feng@intel.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Aaron Li <aaron.li@intel.com>
Reviewed-by: Bob Feng <bob.c.feng@intel.com>
BaseTools/Source/Python/Capsule/GenerateCapsule.py
BaseTools/Source/Python/Common/Uefi/Capsule/CapsuleDependency.py [new file with mode: 0644]

index 6838beb682064be18dede26f7682e288b69e654f..a8de988253cf2c32b226acb73aeea654109c90a2 100644 (file)
@@ -31,6 +31,7 @@ import json
 from Common.Uefi.Capsule.UefiCapsuleHeader import UefiCapsuleHeaderClass\r
 from Common.Uefi.Capsule.FmpCapsuleHeader  import FmpCapsuleHeaderClass\r
 from Common.Uefi.Capsule.FmpAuthHeader     import FmpAuthHeaderClass\r
+from Common.Uefi.Capsule.CapsuleDependency import CapsuleDependencyClass\r
 from Common.Edk2.Capsule.FmpPayloadHeader  import FmpPayloadHeaderClass\r
 \r
 #\r
@@ -306,6 +307,7 @@ if __name__ == '__main__':
             OpenSslOtherPublicCertFile   = ConvertJsonValue (Config, 'OpenSslOtherPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True)\r
             OpenSslTrustedPublicCertFile = ConvertJsonValue (Config, 'OpenSslTrustedPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True)\r
             SigningToolPath              = ConvertJsonValue (Config, 'SigningToolPath', os.path.expandvars, Required = False, Default = None)\r
+            DepexExp                     = ConvertJsonValue (Config, 'Dependencies', str, Required = False, Default = None)\r
 \r
             #\r
             # Read binary input file\r
@@ -330,7 +332,8 @@ if __name__ == '__main__':
                                             OpenSslSignerPrivateCertFile,\r
                                             OpenSslOtherPublicCertFile,\r
                                             OpenSslTrustedPublicCertFile,\r
-                                            SigningToolPath\r
+                                            SigningToolPath,\r
+                                            DepexExp\r
                                             ))\r
 \r
     def GenerateOutputJson (PayloadJsonDescriptorList):\r
@@ -348,7 +351,8 @@ if __name__ == '__main__':
                                   "OpenSslSignerPrivateCertFile": str(PayloadDescriptor.OpenSslSignerPrivateCertFile),\r
                                   "OpenSslOtherPublicCertFile": str(PayloadDescriptor.OpenSslOtherPublicCertFile),\r
                                   "OpenSslTrustedPublicCertFile": str(PayloadDescriptor.OpenSslTrustedPublicCertFile),\r
-                                  "SigningToolPath": str(PayloadDescriptor.SigningToolPath)\r
+                                  "SigningToolPath": str(PayloadDescriptor.SigningToolPath),\r
+                                  "Dependencies" : str(PayloadDescriptor.DepexExp)\r
                               }for PayloadDescriptor in PayloadJsonDescriptorList\r
                           ]\r
                       }\r
@@ -424,7 +428,8 @@ if __name__ == '__main__':
                      OpenSslSignerPrivateCertFile = None,\r
                      OpenSslOtherPublicCertFile   = None,\r
                      OpenSslTrustedPublicCertFile = None,\r
-                     SigningToolPath              = None\r
+                     SigningToolPath              = None,\r
+                     DepexExp                     = None\r
                      ):\r
             self.Payload                      = Payload\r
             self.Guid                         = Guid\r
@@ -438,6 +443,7 @@ if __name__ == '__main__':
             self.OpenSslOtherPublicCertFile   = OpenSslOtherPublicCertFile\r
             self.OpenSslTrustedPublicCertFile = OpenSslTrustedPublicCertFile\r
             self.SigningToolPath              = SigningToolPath\r
+            self.DepexExp                     = DepexExp\r
 \r
             self.UseSignTool = self.SignToolPfxFile is not None\r
             self.UseOpenSsl  = (self.OpenSslSignerPrivateCertFile is not None and\r
@@ -446,6 +452,7 @@ if __name__ == '__main__':
             self.AnyOpenSsl  = (self.OpenSslSignerPrivateCertFile is not None or\r
                                 self.OpenSslOtherPublicCertFile is not None or\r
                                 self.OpenSslTrustedPublicCertFile is not None)\r
+            self.UseDependency = self.DepexExp is not None\r
 \r
         def Validate(self, args):\r
             if self.UseSignTool and self.AnyOpenSsl:\r
@@ -544,7 +551,8 @@ if __name__ == '__main__':
                                             args.OpenSslSignerPrivateCertFile,\r
                                             args.OpenSslOtherPublicCertFile,\r
                                             args.OpenSslTrustedPublicCertFile,\r
-                                            args.SigningToolPath\r
+                                            args.SigningToolPath,\r
+                                            None\r
                                             ))\r
         for SinglePayloadDescriptor in PayloadDescriptorList:\r
             try:\r
@@ -564,6 +572,12 @@ if __name__ == '__main__':
             except:\r
                 print ('GenerateCapsule: error: can not encode FMP Payload Header')\r
                 sys.exit (1)\r
+            if SinglePayloadDescriptor.UseDependency:\r
+                CapsuleDependency.Payload = Result\r
+                CapsuleDependency.DepexExp = SinglePayloadDescriptor.DepexExp\r
+                Result = CapsuleDependency.Encode ()\r
+                if args.Verbose:\r
+                    CapsuleDependency.DumpInfo ()\r
             if SinglePayloadDescriptor.UseOpenSsl or SinglePayloadDescriptor.UseSignTool:\r
                 #\r
                 # Sign image with 64-bit MonotonicCount appended to end of image\r
@@ -657,7 +671,8 @@ if __name__ == '__main__':
                                             args.OpenSslSignerPrivateCertFile,\r
                                             args.OpenSslOtherPublicCertFile,\r
                                             args.OpenSslTrustedPublicCertFile,\r
-                                            args.SigningToolPath\r
+                                            args.SigningToolPath,\r
+                                            None\r
                                             ))\r
         #\r
         # Perform additional verification on payload descriptors\r
@@ -700,7 +715,8 @@ if __name__ == '__main__':
                                                                 PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile,\r
                                                                 PayloadDescriptorList[Index].OpenSslOtherPublicCertFile,\r
                                                                 PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile,\r
-                                                                PayloadDescriptorList[Index].SigningToolPath\r
+                                                                PayloadDescriptorList[Index].SigningToolPath,\r
+                                                                None\r
                                                                 ))\r
                 else:\r
                     PayloadDescriptorList[0].Payload = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload\r
@@ -718,6 +734,7 @@ if __name__ == '__main__':
                                                             None,\r
                                                             None,\r
                                                             None,\r
+                                                            None,\r
                                                             None\r
                                                             ))\r
                         GUID = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageTypeId\r
@@ -736,7 +753,8 @@ if __name__ == '__main__':
                                                             PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile,\r
                                                             PayloadDescriptorList[Index].OpenSslOtherPublicCertFile,\r
                                                             PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile,\r
-                                                            PayloadDescriptorList[Index].SigningToolPath\r
+                                                            PayloadDescriptorList[Index].SigningToolPath,\r
+                                                            None\r
                                                             ))\r
                 JsonIndex = 0\r
                 for SinglePayloadDescriptor in PayloadDescriptorList:\r
@@ -782,6 +800,23 @@ if __name__ == '__main__':
                         if args.Verbose:\r
                             print ('--------')\r
                             print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')\r
+\r
+                    PayloadSignature = struct.unpack ('<I', SinglePayloadDescriptor.Payload[0:4])\r
+                    if PayloadSignature != FmpPayloadHeader.Signature:\r
+                        SinglePayloadDescriptor.UseDependency = True\r
+                        try:\r
+                            SinglePayloadDescriptor.Payload = CapsuleDependency.Decode (SinglePayloadDescriptor.Payload)\r
+                            PayloadJsonDescriptorList[JsonIndex].DepexExp = CapsuleDependency.DepexExp\r
+                            if args.Verbose:\r
+                                print ('--------')\r
+                                CapsuleDependency.DumpInfo ()\r
+                        except Exception as Msg:\r
+                            print ('GenerateCapsule: error: invalid dependency expression')\r
+                    else:\r
+                        if args.Verbose:\r
+                            print ('--------')\r
+                            print ('No EFI_FIRMWARE_IMAGE_DEP')\r
+\r
                     try:\r
                         SinglePayloadDescriptor.Payload = FmpPayloadHeader.Decode (SinglePayloadDescriptor.Payload)\r
                         PayloadJsonDescriptorList[JsonIndex].FwVersion = FmpPayloadHeader.FwVersion\r
@@ -852,6 +887,18 @@ if __name__ == '__main__':
                     except:\r
                         print ('--------')\r
                         print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')\r
+\r
+                    PayloadSignature = struct.unpack ('<I', Result[0:4])\r
+                    if PayloadSignature != FmpPayloadHeader.Signature:\r
+                        try:\r
+                            Result = CapsuleDependency.Decode (Result)\r
+                            print ('--------')\r
+                            CapsuleDependency.DumpInfo ()\r
+                        except:\r
+                            print ('GenerateCapsule: error: invalid dependency expression')\r
+                    else:\r
+                        print ('--------')\r
+                        print ('No EFI_FIRMWARE_IMAGE_DEP')\r
                     try:\r
                         Result = FmpPayloadHeader.Decode (Result)\r
                         print ('--------')\r
@@ -973,6 +1020,7 @@ if __name__ == '__main__':
     FmpCapsuleHeader  = FmpCapsuleHeaderClass ()\r
     FmpAuthHeader     = FmpAuthHeaderClass ()\r
     FmpPayloadHeader  = FmpPayloadHeaderClass ()\r
+    CapsuleDependency = CapsuleDependencyClass ()\r
 \r
     EmbeddedDriverDescriptorList = []\r
     PayloadDescriptorList = []\r
diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/CapsuleDependency.py b/BaseTools/Source/Python/Common/Uefi/Capsule/CapsuleDependency.py
new file mode 100644 (file)
index 0000000..7400485
--- /dev/null
@@ -0,0 +1,409 @@
+## @file\r
+# Module that encodes and decodes a capsule dependency.\r
+#\r
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+# SPDX-License-Identifier: BSD-2-Clause-Patent\r
+#\r
+import struct\r
+import json\r
+import sys\r
+import uuid\r
+import re\r
+\r
+'''\r
+CapsuleDependency\r
+'''\r
+\r
+class OpConvert (object):\r
+    def __init__ (self):\r
+        # Opcode: (OperandSize, PackSize, PackFmt, EncodeConvert, DecodeConvert)\r
+        self._DepexOperations = {0x00:    (16, 16, 's', self.Str2Guid, self.Guid2Str),\r
+                                 0x01:    (4,  1,  'I', self.Str2Uint, self.Uint2Str),\r
+                                 0x02:    (1,  0,  's', self.Str2Utf8, self.Byte2Str),\r
+                                 }\r
+\r
+    def Str2Uint (self, Data):\r
+        try:\r
+            Value = int (Data, 16)\r
+        except:\r
+            Message = '{Data} is not a valid integer value.'.format (Data = Data)\r
+            raise ValueError (Message)\r
+        if Value < 0 or Value > 0xFFFFFFFF:\r
+            Message = '{Data} is not an UINT32.'.format (Data = Data)\r
+            raise ValueError (Message)\r
+        return Value\r
+\r
+    def Uint2Str (self, Data):\r
+        if Data < 0 or Data > 0xFFFFFFFF:\r
+            Message = '{Data} is not an UINT32.'.format (Data = Data)\r
+            raise ValueError (Message)\r
+        return "0x{Data:08x}".format (Data = Data)\r
+\r
+    def Str2Guid (self, Data):\r
+        try:\r
+            Guid = uuid.UUID (Data)\r
+        except:\r
+            Message = '{Data} is not a valid registry format GUID value.'.format (Data = Data)\r
+            raise ValueError (Message)\r
+        return Guid.bytes_le\r
+\r
+    def Guid2Str (self, Data):\r
+        try:\r
+            Guid = uuid.UUID (bytes_le = Data)\r
+        except:\r
+            Message = '{Data} is not a valid binary format GUID value.'.format (Data = Data)\r
+            raise ValueError (Message)\r
+        return str (Guid).upper ()\r
+\r
+    def Str2Utf8 (self, Data):\r
+        if isinstance (Data, str):\r
+            return Data.encode ('utf-8')\r
+        else:\r
+            Message = '{Data} is not a valid string.'.format (Data = Data)\r
+            raise ValueError (Message)\r
+\r
+    def Byte2Str (self, Data):\r
+        if isinstance (Data, bytes):\r
+            if Data[-1:] == b'\x00':\r
+                return str (Data[:-1], 'utf-8')\r
+            else:\r
+                return str (Data, 'utf-8')\r
+        else:\r
+            Message = '{Data} is not a valid binary string.'.format (Data = Data)\r
+            raise ValueError (Message)\r
+\r
+    def OpEncode (self, Opcode, Operand = None):\r
+        BinTemp = struct.pack ('<b', Opcode)\r
+        if Opcode <= 0x02 and Operand != None:\r
+            OperandSize, PackSize, PackFmt, EncodeConvert, DecodeConvert = self._DepexOperations[Opcode]\r
+            Value = EncodeConvert (Operand)\r
+            if Opcode == 0x02:\r
+                PackSize = len (Value) + 1\r
+            BinTemp += struct.pack ('<{PackSize}{PackFmt}'.format (PackSize = PackSize, PackFmt = PackFmt), Value)\r
+        return BinTemp\r
+\r
+    def OpDecode (self, Buffer):\r
+        Opcode = struct.unpack ('<b', Buffer[0:1])[0]\r
+        if Opcode <= 0x02:\r
+            OperandSize, PackSize, PackFmt, EncodeConvert, DecodeConvert = self._DepexOperations[Opcode]\r
+            if Opcode == 0x02:\r
+                try:\r
+                    PackSize = Buffer[1:].index (b'\x00') + 1\r
+                    OperandSize = PackSize\r
+                except:\r
+                    Message = 'CapsuleDependency: OpConvert: error: decode failed with wrong opcode/string.'\r
+                    raise ValueError (Message)\r
+            try:\r
+                Operand = DecodeConvert (struct.unpack ('<{PackSize}{PackFmt}'.format (PackSize = PackSize, PackFmt = PackFmt), Buffer[1:1+OperandSize])[0])\r
+            except:\r
+                Message = 'CapsuleDependency: OpConvert: error: decode failed with unpack failure.'\r
+                raise ValueError (Message)\r
+        else:\r
+            Operand = None\r
+            OperandSize = 0\r
+        return (Opcode, Operand, OperandSize)\r
+\r
+class CapsuleDependencyClass (object):\r
+    # //**************************************************************\r
+    # // Image Attribute - Dependency\r
+    # //**************************************************************\r
+    # typedef struct {\r
+    #   UINT8 Dependencies[];\r
+    # } EFI_FIRMWARE_IMAGE_DEP\r
+\r
+    # {expression operator : [precedence, opcode, type (1:unary/2:binocular)]}\r
+    _opReference = {'&&':  [2, 0x03, 2],\r
+                    '||':  [1, 0x04, 2],\r
+                    '~':   [5, 0x05, 1],\r
+                    '==':  [3, 0x08, 2],\r
+                    '>':   [4, 0x09, 2],\r
+                    '>=':  [4, 0x0A, 2],\r
+                    '<':   [4, 0x0B, 2],\r
+                    '<=':  [4, 0x0C, 2],\r
+                    }\r
+\r
+    def __init__ (self):\r
+        self.Payload              = b''\r
+        self._DepexExp            = None\r
+        self._DepexList           = []\r
+        self._DepexDump           = []\r
+        self.Depex                = b''\r
+        self._Valid               = False\r
+        self._DepexSize           = 0\r
+        self._opReferenceReverse  = {v[1] : k for k, v in self._opReference.items ()}\r
+        self.OpConverter          = OpConvert ()\r
+\r
+    @property\r
+    def DepexExp (self):\r
+        return self._DepexExp\r
+\r
+    @DepexExp.setter\r
+    def DepexExp (self, DepexExp = ''):\r
+        if isinstance (DepexExp, str):\r
+            DepexExp = re.sub (r'\n',r' ',DepexExp)\r
+            DepexExp = re.sub (r'\(',r' ( ',DepexExp)\r
+            DepexExp = re.sub (r'\)',r' ) ',DepexExp)\r
+            DepexExp = re.sub (r'~',r' ~ ',DepexExp)\r
+            self._DepexList = re.findall(r"[^\s\"\']+|\"[^\"]*\"|\'[^\']*\'",DepexExp)\r
+            self._DepexExp  = " ".join(self._DepexList)\r
+\r
+        else:\r
+            Msg = 'Input Depex Expression is not valid string.'\r
+            raise ValueError (Msg)\r
+\r
+    def IsValidOperator (self, op):\r
+        return op in self._opReference.keys ()\r
+\r
+    def IsValidUnaryOperator (self, op):\r
+        return op in self._opReference.keys () and self._opReference[op][2] == 1\r
+\r
+    def IsValidBinocularOperator (self, op):\r
+        return op in self._opReference.keys () and self._opReference[op][2] == 2\r
+\r
+    def IsValidGuid (self, operand):\r
+        try:\r
+            uuid.UUID (operand)\r
+        except:\r
+            return False\r
+        return True\r
+\r
+    def IsValidVersion (self, operand):\r
+        try:\r
+            Value = int (operand, 16)\r
+            if Value < 0 or Value > 0xFFFFFFFF:\r
+                return False\r
+        except:\r
+            return False\r
+        return True\r
+\r
+    def IsValidBoolean (self, operand):\r
+        try:\r
+            return operand.upper () in ['TRUE', 'FALSE']\r
+        except:\r
+            return False\r
+\r
+    def IsValidOperand (self, operand):\r
+        return self.IsValidVersion (operand) or self.IsValidGuid (operand) or self.IsValidBoolean (operand)\r
+\r
+    def IsValidString (self, operand):\r
+        return operand[0] == "\"" and operand[-1] == "\"" and len(operand) >= 2\r
+\r
+    # Check if priority of current operater is greater than pervious op\r
+    def PriorityNotGreater (self, prevOp, currOp):\r
+        return self._opReference[currOp][0] <= self._opReference[prevOp][0]\r
+\r
+    def ValidateDepex (self):\r
+        OpList = self._DepexList\r
+\r
+        i = 0\r
+        while i < len (OpList):\r
+            Op = OpList[i]\r
+\r
+            if Op == 'DECLARE':\r
+                i += 1\r
+                if i >= len (OpList):\r
+                    Msg = 'No more Operand after {Op}.'.format (Op = OpList[i-1])\r
+                    raise IndexError (Msg)\r
+                # Check valid string\r
+                if not self.IsValidString(OpList[i]):\r
+                    Msg = '{Operand} after {Op} is not a valid expression input.'.format (Operand = OpList[i], Op = OpList[i-1])\r
+                    raise ValueError (Msg)\r
+\r
+            elif Op == '(':\r
+                # Expression cannot end with (\r
+                if i == len (OpList) - 1:\r
+                    Msg = 'Expression cannot end with \'(\''\r
+                    raise ValueError (Msg)\r
+                # The previous op after '(' cannot be a binocular operator\r
+                if self.IsValidBinocularOperator (OpList[i+1]) :\r
+                    Msg = '{Op} after \'(\' is not a valid expression input.'.format (Op = OpList[i+1])\r
+                    raise ValueError (Msg)\r
+\r
+            elif Op == ')':\r
+                # Expression cannot start with )\r
+                if i == 0:\r
+                    Msg = 'Expression cannot start with \')\''\r
+                    raise ValueError (Msg)\r
+                # The previous op before ')' cannot be an operator\r
+                if self.IsValidOperator (OpList[i-1]):\r
+                    Msg = '{Op} before \')\' is not a valid expression input.'.format (Op = OpList[i-1])\r
+                    raise ValueError (Msg)\r
+                # The next op after ')' cannot be operand or unary operator\r
+                if (i + 1) < len (OpList) and (self.IsValidOperand (OpList[i+1]) or self.IsValidUnaryOperator (OpList[i+1])):\r
+                    Msg = '{Op} after \')\' is not a valid expression input.'.format (Op = OpList[i+1])\r
+                    raise ValueError (Msg)\r
+\r
+            elif self.IsValidOperand (Op):\r
+                # The next expression of operand cannot be operand or unary operator\r
+                if (i + 1) < len (OpList) and (self.IsValidOperand (OpList[i+1]) or self.IsValidUnaryOperator (OpList[i+1])):\r
+                    Msg = '{Op} after {PrevOp} is not a valid expression input.'.format (Op = OpList[i+1], PrevOp = Op)\r
+                    raise ValueError (Msg)\r
+\r
+            elif self.IsValidOperator (Op):\r
+                # The next op of operator cannot binocular operator\r
+                if (i + 1) < len (OpList) and self.IsValidBinocularOperator (OpList[i+1]):\r
+                    Msg = '{Op} after {PrevOp} is not a valid expression input.'.format (Op = OpList[i+1], PrevOp = Op)\r
+                    raise ValueError (Msg)\r
+                # The first op can not be binocular operator\r
+                if i == 0 and self.IsValidBinocularOperator (Op):\r
+                    Msg = 'Expression cannot start with an operator {Op}.'.format (Op = Op)\r
+                    raise ValueError (Msg)\r
+                # The last op can not be operator\r
+                if i == len (OpList) - 1:\r
+                    Msg = 'Expression cannot ended with an operator {Op}.'.format (Op = Op)\r
+                    raise ValueError (Msg)\r
+                # The next op of unary operator cannot be guid / version\r
+                if self.IsValidUnaryOperator (Op) and (self.IsValidGuid (OpList[i+1]) or self.IsValidVersion (OpList[i+1])):\r
+                    Msg = '{Op} after {PrevOp} is not a valid expression input.'.format (Op = OpList[i+1], PrevOp = Op)\r
+                    raise ValueError (Msg)\r
+\r
+            else:\r
+                Msg = '{Op} is not a valid expression input.'.format (Op = Op)\r
+                raise ValueError (Msg)\r
+            i += 1\r
+\r
+    def Encode (self):\r
+        # initialize\r
+        self.Depex = b''\r
+        self._DepexDump = []\r
+        OperandStack = []\r
+        OpeartorStack = []\r
+        OpList = self._DepexList\r
+\r
+        self.ValidateDepex ()\r
+\r
+        # convert\r
+        i = 0\r
+        while i < len (OpList):\r
+            Op = OpList[i]\r
+            if Op == 'DECLARE':\r
+                # This declare next expression value is a VERSION_STRING\r
+                i += 1\r
+                self.Depex += self.OpConverter.OpEncode (0x02, OpList[i][1:-1])\r
+\r
+            elif Op == '(':\r
+                OpeartorStack.append (Op)\r
+\r
+            elif Op == ')':\r
+                while (OpeartorStack and OpeartorStack[-1] != '('):\r
+                    Operator = OpeartorStack.pop ()\r
+                    self.Depex += self.OpConverter.OpEncode (self._opReference[Operator][1])\r
+                try:\r
+                    OpeartorStack.pop () # pop out '('\r
+                except:\r
+                    Msg = 'Pop out \'(\' failed, too many \')\''\r
+                    raise ValueError (Msg)\r
+\r
+            elif self.IsValidGuid (Op):\r
+                if not OperandStack:\r
+                    OperandStack.append (self.OpConverter.OpEncode (0x00, Op))\r
+                else:\r
+                    # accroding to uefi spec 2.8, the guid/version operands is a reversed order in firmware comparison.\r
+                    self.Depex += self.OpConverter.OpEncode (0x00, Op)\r
+                    self.Depex += OperandStack.pop ()\r
+\r
+            elif self.IsValidVersion (Op):\r
+                if not OperandStack:\r
+                    OperandStack.append (self.OpConverter.OpEncode (0x01, Op))\r
+                else:\r
+                    # accroding to uefi spec 2.8, the guid/version operands is a reversed order in firmware comparison.\r
+                    self.Depex += self.OpConverter.OpEncode (0x01, Op)\r
+                    self.Depex += OperandStack.pop ()\r
+\r
+            elif self.IsValidBoolean (Op):\r
+                if Op.upper () == 'FALSE':\r
+                    self.Depex += self.OpConverter.OpEncode (0x07)\r
+                elif Op.upper () == 'TRUE':\r
+                    self.Depex += self.OpConverter.OpEncode (0x06)\r
+\r
+            elif self.IsValidOperator (Op):\r
+                while (OpeartorStack and OpeartorStack[-1] != '(' and self.PriorityNotGreater (OpeartorStack[-1], Op)):\r
+                    Operator = OpeartorStack.pop ()\r
+                    self.Depex += self.OpConverter.OpEncode (self._opReference[Operator][1])\r
+                OpeartorStack.append (Op)\r
+\r
+            i += 1\r
+\r
+        while OpeartorStack:\r
+            Operator = OpeartorStack.pop ()\r
+            if Operator == '(':\r
+                Msg = 'Too many \'(\'.'\r
+                raise ValueError (Msg)\r
+            self.Depex += self.OpConverter.OpEncode (self._opReference[Operator][1])\r
+        self.Depex += self.OpConverter.OpEncode (0x0D)\r
+\r
+        self._Valid = True\r
+        self._DepexSize = len (self.Depex)\r
+        return self.Depex + self.Payload\r
+\r
+    def Decode (self, Buffer):\r
+        # initialize\r
+        self.Depex = Buffer\r
+        OperandStack = []\r
+        DepexLen = 0\r
+\r
+        while True:\r
+            Opcode, Operand, OperandSize = self.OpConverter.OpDecode (Buffer[DepexLen:])\r
+            DepexLen += OperandSize + 1\r
+\r
+            if Opcode == 0x0D:\r
+                break\r
+\r
+            elif Opcode == 0x02:\r
+                if not OperandStack:\r
+                    OperandStack.append ('DECLARE \"{String}\"'.format (String = Operand))\r
+                else:\r
+                    PrevOperand = OperandStack.pop ()\r
+                    OperandStack.append ('{Operand} DECLARE \"{String}\"'.format (Operand = PrevOperand, String = Operand))\r
+\r
+            elif Opcode in [0x00, 0x01]:\r
+                OperandStack.append (Operand)\r
+\r
+            elif Opcode == 0x06:\r
+                OperandStack.append ('TRUE')\r
+\r
+            elif Opcode == 0x07:\r
+                OperandStack.append ('FALSE')\r
+\r
+            elif self.IsValidOperator (self._opReferenceReverse[Opcode]):\r
+                Operator = self._opReferenceReverse[Opcode]\r
+                if self.IsValidUnaryOperator (self._opReferenceReverse[Opcode]) and len (OperandStack) >= 1:\r
+                    Oprand = OperandStack.pop ()\r
+                    OperandStack.append (' ( {Operator} {Oprand} )'.format (Operator = Operator, Oprand = Oprand))\r
+                elif self.IsValidBinocularOperator (self._opReferenceReverse[Opcode]) and len (OperandStack) >= 2:\r
+                    Oprand1 = OperandStack.pop ()\r
+                    Oprand2 = OperandStack.pop ()\r
+                    OperandStack.append (' ( {Oprand1} {Operator} {Oprand2} )'.format (Operator = Operator, Oprand1 = Oprand1, Oprand2 = Oprand2))\r
+                else:\r
+                    Msg = 'No enough Operands for {Opcode:02X}.'.format (Opcode = Opcode)\r
+                    raise ValueError (Msg)\r
+\r
+            else:\r
+                Msg = '{Opcode:02X} is not a valid OpCode.'.format (Opcode = Opcode)\r
+                raise ValueError (Msg)\r
+\r
+        self.DepexExp = OperandStack[0].strip (' ')\r
+        self.Payload = Buffer[DepexLen:]\r
+        self._Valid = True\r
+        self._DepexSize = DepexLen\r
+        return self.Payload\r
+\r
+\r
+    def DumpInfo (self):\r
+        DepexLen = 0\r
+        Opcode = None\r
+        Buffer = self.Depex\r
+\r
+        if self._Valid == True:\r
+            print ('EFI_FIRMWARE_IMAGE_DEP.Dependencies = {')\r
+            while Opcode != 0x0D:\r
+                Opcode, Operand, OperandSize = self.OpConverter.OpDecode (Buffer[DepexLen:])\r
+                DepexLen += OperandSize + 1\r
+                if Operand:\r
+                    print ('    {Opcode:02X}, {Operand},'.format (Opcode = Opcode, Operand = Operand))\r
+                else:\r
+                    print ('    {Opcode:02X},'.format (Opcode = Opcode))\r
+            print ('}')\r
+\r
+            print ('sizeof (EFI_FIRMWARE_IMAGE_DEP.Dependencies)    = {Size:08X}'.format (Size = self._DepexSize))\r
+            print ('sizeof (Payload)                                = {Size:08X}'.format (Size = len (self.Payload)))\r