* [PATCH v1] BaseTools/Capsule: Add capsule dependency support
@ 2020-01-10 1:57 aaron.li
2020-01-15 2:12 ` Bob Feng
0 siblings, 1 reply; 2+ messages in thread
From: aaron.li @ 2020-01-10 1:57 UTC (permalink / raw)
To: devel; +Cc: Bob Feng, Liming Gao
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>
---
BaseTools/Source/Python/Capsule/GenerateCapsule.py | 62 ++-
BaseTools/Source/Python/Common/Uefi/Capsule/CapsuleDependency.py | 409 ++++++++++++++++++++
2 files changed, 464 insertions(+), 7 deletions(-)
diff --git a/BaseTools/Source/Python/Capsule/GenerateCapsule.py b/BaseTools/Source/Python/Capsule/GenerateCapsule.py
index 6838beb682..a8de988253 100644
--- a/BaseTools/Source/Python/Capsule/GenerateCapsule.py
+++ b/BaseTools/Source/Python/Capsule/GenerateCapsule.py
@@ -31,6 +31,7 @@ import json
from Common.Uefi.Capsule.UefiCapsuleHeader import UefiCapsuleHeaderClass
from Common.Uefi.Capsule.FmpCapsuleHeader import FmpCapsuleHeaderClass
from Common.Uefi.Capsule.FmpAuthHeader import FmpAuthHeaderClass
+from Common.Uefi.Capsule.CapsuleDependency import CapsuleDependencyClass
from Common.Edk2.Capsule.FmpPayloadHeader import FmpPayloadHeaderClass
#
@@ -306,6 +307,7 @@ if __name__ == '__main__':
OpenSslOtherPublicCertFile = ConvertJsonValue (Config, 'OpenSslOtherPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True)
OpenSslTrustedPublicCertFile = ConvertJsonValue (Config, 'OpenSslTrustedPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True)
SigningToolPath = ConvertJsonValue (Config, 'SigningToolPath', os.path.expandvars, Required = False, Default = None)
+ DepexExp = ConvertJsonValue (Config, 'Dependencies', str, Required = False, Default = None)
#
# Read binary input file
@@ -330,7 +332,8 @@ if __name__ == '__main__':
OpenSslSignerPrivateCertFile,
OpenSslOtherPublicCertFile,
OpenSslTrustedPublicCertFile,
- SigningToolPath
+ SigningToolPath,
+ DepexExp
))
def GenerateOutputJson (PayloadJsonDescriptorList):
@@ -348,7 +351,8 @@ if __name__ == '__main__':
"OpenSslSignerPrivateCertFile": str(PayloadDescriptor.OpenSslSignerPrivateCertFile),
"OpenSslOtherPublicCertFile": str(PayloadDescriptor.OpenSslOtherPublicCertFile),
"OpenSslTrustedPublicCertFile": str(PayloadDescriptor.OpenSslTrustedPublicCertFile),
- "SigningToolPath": str(PayloadDescriptor.SigningToolPath)
+ "SigningToolPath": str(PayloadDescriptor.SigningToolPath),
+ "Dependencies" : str(PayloadDescriptor.DepexExp)
}for PayloadDescriptor in PayloadJsonDescriptorList
]
}
@@ -424,7 +428,8 @@ if __name__ == '__main__':
OpenSslSignerPrivateCertFile = None,
OpenSslOtherPublicCertFile = None,
OpenSslTrustedPublicCertFile = None,
- SigningToolPath = None
+ SigningToolPath = None,
+ DepexExp = None
):
self.Payload = Payload
self.Guid = Guid
@@ -438,6 +443,7 @@ if __name__ == '__main__':
self.OpenSslOtherPublicCertFile = OpenSslOtherPublicCertFile
self.OpenSslTrustedPublicCertFile = OpenSslTrustedPublicCertFile
self.SigningToolPath = SigningToolPath
+ self.DepexExp = DepexExp
self.UseSignTool = self.SignToolPfxFile is not None
self.UseOpenSsl = (self.OpenSslSignerPrivateCertFile is not None and
@@ -446,6 +452,7 @@ if __name__ == '__main__':
self.AnyOpenSsl = (self.OpenSslSignerPrivateCertFile is not None or
self.OpenSslOtherPublicCertFile is not None or
self.OpenSslTrustedPublicCertFile is not None)
+ self.UseDependency = self.DepexExp is not None
def Validate(self, args):
if self.UseSignTool and self.AnyOpenSsl:
@@ -544,7 +551,8 @@ if __name__ == '__main__':
args.OpenSslSignerPrivateCertFile,
args.OpenSslOtherPublicCertFile,
args.OpenSslTrustedPublicCertFile,
- args.SigningToolPath
+ args.SigningToolPath,
+ None
))
for SinglePayloadDescriptor in PayloadDescriptorList:
try:
@@ -564,6 +572,12 @@ if __name__ == '__main__':
except:
print ('GenerateCapsule: error: can not encode FMP Payload Header')
sys.exit (1)
+ if SinglePayloadDescriptor.UseDependency:
+ CapsuleDependency.Payload = Result
+ CapsuleDependency.DepexExp = SinglePayloadDescriptor.DepexExp
+ Result = CapsuleDependency.Encode ()
+ if args.Verbose:
+ CapsuleDependency.DumpInfo ()
if SinglePayloadDescriptor.UseOpenSsl or SinglePayloadDescriptor.UseSignTool:
#
# Sign image with 64-bit MonotonicCount appended to end of image
@@ -657,7 +671,8 @@ if __name__ == '__main__':
args.OpenSslSignerPrivateCertFile,
args.OpenSslOtherPublicCertFile,
args.OpenSslTrustedPublicCertFile,
- args.SigningToolPath
+ args.SigningToolPath,
+ None
))
#
# Perform additional verification on payload descriptors
@@ -700,7 +715,8 @@ if __name__ == '__main__':
PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile,
PayloadDescriptorList[Index].OpenSslOtherPublicCertFile,
PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile,
- PayloadDescriptorList[Index].SigningToolPath
+ PayloadDescriptorList[Index].SigningToolPath,
+ None
))
else:
PayloadDescriptorList[0].Payload = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload
@@ -708,6 +724,7 @@ if __name__ == '__main__':
if Index > 0:
PayloadDecodeFile = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload
PayloadDescriptorList.append (PayloadDescriptor (PayloadDecodeFile,
+ None,
None,
None,
None,
@@ -736,7 +753,8 @@ if __name__ == '__main__':
PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile,
PayloadDescriptorList[Index].OpenSslOtherPublicCertFile,
PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile,
- PayloadDescriptorList[Index].SigningToolPath
+ PayloadDescriptorList[Index].SigningToolPath,
+ None
))
JsonIndex = 0
for SinglePayloadDescriptor in PayloadDescriptorList:
@@ -782,6 +800,23 @@ if __name__ == '__main__':
if args.Verbose:
print ('--------')
print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')
+
+ PayloadSignature = struct.unpack ('<I', SinglePayloadDescriptor.Payload[0:4])
+ if PayloadSignature != FmpPayloadHeader.Signature:
+ SinglePayloadDescriptor.UseDependency = True
+ try:
+ SinglePayloadDescriptor.Payload = CapsuleDependency.Decode (SinglePayloadDescriptor.Payload)
+ PayloadJsonDescriptorList[JsonIndex].DepexExp = CapsuleDependency.DepexExp
+ if args.Verbose:
+ print ('--------')
+ CapsuleDependency.DumpInfo ()
+ except Exception as Msg:
+ print ('GenerateCapsule: error: invalid dependency expression')
+ else:
+ if args.Verbose:
+ print ('--------')
+ print ('No EFI_FIRMWARE_IMAGE_DEP')
+
try:
SinglePayloadDescriptor.Payload = FmpPayloadHeader.Decode (SinglePayloadDescriptor.Payload)
PayloadJsonDescriptorList[JsonIndex].FwVersion = FmpPayloadHeader.FwVersion
@@ -852,6 +887,18 @@ if __name__ == '__main__':
except:
print ('--------')
print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')
+
+ PayloadSignature = struct.unpack ('<I', Result[0:4])
+ if PayloadSignature != FmpPayloadHeader.Signature:
+ try:
+ Result = CapsuleDependency.Decode (Result)
+ print ('--------')
+ CapsuleDependency.DumpInfo ()
+ except:
+ print ('GenerateCapsule: error: invalid dependency expression')
+ else:
+ print ('--------')
+ print ('No EFI_FIRMWARE_IMAGE_DEP')
try:
Result = FmpPayloadHeader.Decode (Result)
print ('--------')
@@ -973,6 +1020,7 @@ if __name__ == '__main__':
FmpCapsuleHeader = FmpCapsuleHeaderClass ()
FmpAuthHeader = FmpAuthHeaderClass ()
FmpPayloadHeader = FmpPayloadHeaderClass ()
+ CapsuleDependency = CapsuleDependencyClass ()
EmbeddedDriverDescriptorList = []
PayloadDescriptorList = []
diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/CapsuleDependency.py b/BaseTools/Source/Python/Common/Uefi/Capsule/CapsuleDependency.py
new file mode 100644
index 0000000000..74004857a7
--- /dev/null
+++ b/BaseTools/Source/Python/Common/Uefi/Capsule/CapsuleDependency.py
@@ -0,0 +1,409 @@
+## @file
+# Module that encodes and decodes a capsule dependency.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+import struct
+import json
+import sys
+import uuid
+import re
+
+'''
+CapsuleDependency
+'''
+
+class OpConvert (object):
+ def __init__ (self):
+ # Opcode: (OperandSize, PackSize, PackFmt, EncodeConvert, DecodeConvert)
+ self._DepexOperations = {0x00: (16, 16, 's', self.Str2Guid, self.Guid2Str),
+ 0x01: (4, 1, 'I', self.Str2Uint, self.Uint2Str),
+ 0x02: (1, 0, 's', self.Str2Utf8, self.Byte2Str),
+ }
+
+ def Str2Uint (self, Data):
+ try:
+ Value = int (Data, 16)
+ except:
+ Message = '{Data} is not a valid integer value.'.format (Data = Data)
+ raise ValueError (Message)
+ if Value < 0 or Value > 0xFFFFFFFF:
+ Message = '{Data} is not an UINT32.'.format (Data = Data)
+ raise ValueError (Message)
+ return Value
+
+ def Uint2Str (self, Data):
+ if Data < 0 or Data > 0xFFFFFFFF:
+ Message = '{Data} is not an UINT32.'.format (Data = Data)
+ raise ValueError (Message)
+ return "0x{Data:08x}".format (Data = Data)
+
+ def Str2Guid (self, Data):
+ try:
+ Guid = uuid.UUID (Data)
+ except:
+ Message = '{Data} is not a valid registry format GUID value.'.format (Data = Data)
+ raise ValueError (Message)
+ return Guid.bytes_le
+
+ def Guid2Str (self, Data):
+ try:
+ Guid = uuid.UUID (bytes_le = Data)
+ except:
+ Message = '{Data} is not a valid binary format GUID value.'.format (Data = Data)
+ raise ValueError (Message)
+ return str (Guid).upper ()
+
+ def Str2Utf8 (self, Data):
+ if isinstance (Data, str):
+ return Data.encode ('utf-8')
+ else:
+ Message = '{Data} is not a valid string.'.format (Data = Data)
+ raise ValueError (Message)
+
+ def Byte2Str (self, Data):
+ if isinstance (Data, bytes):
+ if Data[-1:] == b'\x00':
+ return str (Data[:-1], 'utf-8')
+ else:
+ return str (Data, 'utf-8')
+ else:
+ Message = '{Data} is not a valid binary string.'.format (Data = Data)
+ raise ValueError (Message)
+
+ def OpEncode (self, Opcode, Operand = None):
+ BinTemp = struct.pack ('<b', Opcode)
+ if Opcode <= 0x02 and Operand != None:
+ OperandSize, PackSize, PackFmt, EncodeConvert, DecodeConvert = self._DepexOperations[Opcode]
+ Value = EncodeConvert (Operand)
+ if Opcode == 0x02:
+ PackSize = len (Value) + 1
+ BinTemp += struct.pack ('<{PackSize}{PackFmt}'.format (PackSize = PackSize, PackFmt = PackFmt), Value)
+ return BinTemp
+
+ def OpDecode (self, Buffer):
+ Opcode = struct.unpack ('<b', Buffer[0:1])[0]
+ if Opcode <= 0x02:
+ OperandSize, PackSize, PackFmt, EncodeConvert, DecodeConvert = self._DepexOperations[Opcode]
+ if Opcode == 0x02:
+ try:
+ PackSize = Buffer[1:].index (b'\x00') + 1
+ OperandSize = PackSize
+ except:
+ Message = 'CapsuleDependency: OpConvert: error: decode failed with wrong opcode/string.'
+ raise ValueError (Message)
+ try:
+ Operand = DecodeConvert (struct.unpack ('<{PackSize}{PackFmt}'.format (PackSize = PackSize, PackFmt = PackFmt), Buffer[1:1+OperandSize])[0])
+ except:
+ Message = 'CapsuleDependency: OpConvert: error: decode failed with unpack failure.'
+ raise ValueError (Message)
+ else:
+ Operand = None
+ OperandSize = 0
+ return (Opcode, Operand, OperandSize)
+
+class CapsuleDependencyClass (object):
+ # //**************************************************************
+ # // Image Attribute - Dependency
+ # //**************************************************************
+ # typedef struct {
+ # UINT8 Dependencies[];
+ # } EFI_FIRMWARE_IMAGE_DEP
+
+ # {expression operator : [precedence, opcode, type (1:unary/2:binocular)]}
+ _opReference = {'&&': [2, 0x03, 2],
+ '||': [1, 0x04, 2],
+ '~': [5, 0x05, 1],
+ '==': [3, 0x08, 2],
+ '>': [4, 0x09, 2],
+ '>=': [4, 0x0A, 2],
+ '<': [4, 0x0B, 2],
+ '<=': [4, 0x0C, 2],
+ }
+
+ def __init__ (self):
+ self.Payload = b''
+ self._DepexExp = None
+ self._DepexList = []
+ self._DepexDump = []
+ self.Depex = b''
+ self._Valid = False
+ self._DepexSize = 0
+ self._opReferenceReverse = {v[1] : k for k, v in self._opReference.items ()}
+ self.OpConverter = OpConvert ()
+
+ @property
+ def DepexExp (self):
+ return self._DepexExp
+
+ @DepexExp.setter
+ def DepexExp (self, DepexExp = ''):
+ if isinstance (DepexExp, str):
+ DepexExp = re.sub (r'\n',r' ',DepexExp)
+ DepexExp = re.sub (r'\(',r' ( ',DepexExp)
+ DepexExp = re.sub (r'\)',r' ) ',DepexExp)
+ DepexExp = re.sub (r'~',r' ~ ',DepexExp)
+ self._DepexList = re.findall(r"[^\s\"\']+|\"[^\"]*\"|\'[^\']*\'",DepexExp)
+ self._DepexExp = " ".join(self._DepexList)
+
+ else:
+ Msg = 'Input Depex Expression is not valid string.'
+ raise ValueError (Msg)
+
+ def IsValidOperator (self, op):
+ return op in self._opReference.keys ()
+
+ def IsValidUnaryOperator (self, op):
+ return op in self._opReference.keys () and self._opReference[op][2] == 1
+
+ def IsValidBinocularOperator (self, op):
+ return op in self._opReference.keys () and self._opReference[op][2] == 2
+
+ def IsValidGuid (self, operand):
+ try:
+ uuid.UUID (operand)
+ except:
+ return False
+ return True
+
+ def IsValidVersion (self, operand):
+ try:
+ Value = int (operand, 16)
+ if Value < 0 or Value > 0xFFFFFFFF:
+ return False
+ except:
+ return False
+ return True
+
+ def IsValidBoolean (self, operand):
+ try:
+ return operand.upper () in ['TRUE', 'FALSE']
+ except:
+ return False
+
+ def IsValidOperand (self, operand):
+ return self.IsValidVersion (operand) or self.IsValidGuid (operand) or self.IsValidBoolean (operand)
+
+ def IsValidString (self, operand):
+ return operand[0] == "\"" and operand[-1] == "\"" and len(operand) >= 2
+
+ # Check if priority of current operater is greater than pervious op
+ def PriorityNotGreater (self, prevOp, currOp):
+ return self._opReference[currOp][0] <= self._opReference[prevOp][0]
+
+ def ValidateDepex (self):
+ OpList = self._DepexList
+
+ i = 0
+ while i < len (OpList):
+ Op = OpList[i]
+
+ if Op == 'DECLARE':
+ i += 1
+ if i >= len (OpList):
+ Msg = 'No more Operand after {Op}.'.format (Op = OpList[i-1])
+ raise IndexError (Msg)
+ # Check valid string
+ if not self.IsValidString(OpList[i]):
+ Msg = '{Operand} after {Op} is not a valid expression input.'.format (Operand = OpList[i], Op = OpList[i-1])
+ raise ValueError (Msg)
+
+ elif Op == '(':
+ # Expression cannot end with (
+ if i == len (OpList) - 1:
+ Msg = 'Expression cannot end with \'(\''
+ raise ValueError (Msg)
+ # The previous op after '(' cannot be a binocular operator
+ if self.IsValidBinocularOperator (OpList[i+1]) :
+ Msg = '{Op} after \'(\' is not a valid expression input.'.format (Op = OpList[i+1])
+ raise ValueError (Msg)
+
+ elif Op == ')':
+ # Expression cannot start with )
+ if i == 0:
+ Msg = 'Expression cannot start with \')\''
+ raise ValueError (Msg)
+ # The previous op before ')' cannot be an operator
+ if self.IsValidOperator (OpList[i-1]):
+ Msg = '{Op} before \')\' is not a valid expression input.'.format (Op = OpList[i-1])
+ raise ValueError (Msg)
+ # The next op after ')' cannot be operand or unary operator
+ if (i + 1) < len (OpList) and (self.IsValidOperand (OpList[i+1]) or self.IsValidUnaryOperator (OpList[i+1])):
+ Msg = '{Op} after \')\' is not a valid expression input.'.format (Op = OpList[i+1])
+ raise ValueError (Msg)
+
+ elif self.IsValidOperand (Op):
+ # The next expression of operand cannot be operand or unary operator
+ if (i + 1) < len (OpList) and (self.IsValidOperand (OpList[i+1]) or self.IsValidUnaryOperator (OpList[i+1])):
+ Msg = '{Op} after {PrevOp} is not a valid expression input.'.format (Op = OpList[i+1], PrevOp = Op)
+ raise ValueError (Msg)
+
+ elif self.IsValidOperator (Op):
+ # The next op of operator cannot binocular operator
+ if (i + 1) < len (OpList) and self.IsValidBinocularOperator (OpList[i+1]):
+ Msg = '{Op} after {PrevOp} is not a valid expression input.'.format (Op = OpList[i+1], PrevOp = Op)
+ raise ValueError (Msg)
+ # The first op can not be binocular operator
+ if i == 0 and self.IsValidBinocularOperator (Op):
+ Msg = 'Expression cannot start with an operator {Op}.'.format (Op = Op)
+ raise ValueError (Msg)
+ # The last op can not be operator
+ if i == len (OpList) - 1:
+ Msg = 'Expression cannot ended with an operator {Op}.'.format (Op = Op)
+ raise ValueError (Msg)
+ # The next op of unary operator cannot be guid / version
+ if self.IsValidUnaryOperator (Op) and (self.IsValidGuid (OpList[i+1]) or self.IsValidVersion (OpList[i+1])):
+ Msg = '{Op} after {PrevOp} is not a valid expression input.'.format (Op = OpList[i+1], PrevOp = Op)
+ raise ValueError (Msg)
+
+ else:
+ Msg = '{Op} is not a valid expression input.'.format (Op = Op)
+ raise ValueError (Msg)
+ i += 1
+
+ def Encode (self):
+ # initialize
+ self.Depex = b''
+ self._DepexDump = []
+ OperandStack = []
+ OpeartorStack = []
+ OpList = self._DepexList
+
+ self.ValidateDepex ()
+
+ # convert
+ i = 0
+ while i < len (OpList):
+ Op = OpList[i]
+ if Op == 'DECLARE':
+ # This declare next expression value is a VERSION_STRING
+ i += 1
+ self.Depex += self.OpConverter.OpEncode (0x02, OpList[i][1:-1])
+
+ elif Op == '(':
+ OpeartorStack.append (Op)
+
+ elif Op == ')':
+ while (OpeartorStack and OpeartorStack[-1] != '('):
+ Operator = OpeartorStack.pop ()
+ self.Depex += self.OpConverter.OpEncode (self._opReference[Operator][1])
+ try:
+ OpeartorStack.pop () # pop out '('
+ except:
+ Msg = 'Pop out \'(\' failed, too many \')\''
+ raise ValueError (Msg)
+
+ elif self.IsValidGuid (Op):
+ if not OperandStack:
+ OperandStack.append (self.OpConverter.OpEncode (0x00, Op))
+ else:
+ # accroding to uefi spec 2.8, the guid/version operands is a reversed order in firmware comparison.
+ self.Depex += self.OpConverter.OpEncode (0x00, Op)
+ self.Depex += OperandStack.pop ()
+
+ elif self.IsValidVersion (Op):
+ if not OperandStack:
+ OperandStack.append (self.OpConverter.OpEncode (0x01, Op))
+ else:
+ # accroding to uefi spec 2.8, the guid/version operands is a reversed order in firmware comparison.
+ self.Depex += self.OpConverter.OpEncode (0x01, Op)
+ self.Depex += OperandStack.pop ()
+
+ elif self.IsValidBoolean (Op):
+ if Op.upper () == 'FALSE':
+ self.Depex += self.OpConverter.OpEncode (0x07)
+ elif Op.upper () == 'TRUE':
+ self.Depex += self.OpConverter.OpEncode (0x06)
+
+ elif self.IsValidOperator (Op):
+ while (OpeartorStack and OpeartorStack[-1] != '(' and self.PriorityNotGreater (OpeartorStack[-1], Op)):
+ Operator = OpeartorStack.pop ()
+ self.Depex += self.OpConverter.OpEncode (self._opReference[Operator][1])
+ OpeartorStack.append (Op)
+
+ i += 1
+
+ while OpeartorStack:
+ Operator = OpeartorStack.pop ()
+ if Operator == '(':
+ Msg = 'Too many \'(\'.'
+ raise ValueError (Msg)
+ self.Depex += self.OpConverter.OpEncode (self._opReference[Operator][1])
+ self.Depex += self.OpConverter.OpEncode (0x0D)
+
+ self._Valid = True
+ self._DepexSize = len (self.Depex)
+ return self.Depex + self.Payload
+
+ def Decode (self, Buffer):
+ # initialize
+ self.Depex = Buffer
+ OperandStack = []
+ DepexLen = 0
+
+ while True:
+ Opcode, Operand, OperandSize = self.OpConverter.OpDecode (Buffer[DepexLen:])
+ DepexLen += OperandSize + 1
+
+ if Opcode == 0x0D:
+ break
+
+ elif Opcode == 0x02:
+ if not OperandStack:
+ OperandStack.append ('DECLARE \"{String}\"'.format (String = Operand))
+ else:
+ PrevOperand = OperandStack.pop ()
+ OperandStack.append ('{Operand} DECLARE \"{String}\"'.format (Operand = PrevOperand, String = Operand))
+
+ elif Opcode in [0x00, 0x01]:
+ OperandStack.append (Operand)
+
+ elif Opcode == 0x06:
+ OperandStack.append ('TRUE')
+
+ elif Opcode == 0x07:
+ OperandStack.append ('FALSE')
+
+ elif self.IsValidOperator (self._opReferenceReverse[Opcode]):
+ Operator = self._opReferenceReverse[Opcode]
+ if self.IsValidUnaryOperator (self._opReferenceReverse[Opcode]) and len (OperandStack) >= 1:
+ Oprand = OperandStack.pop ()
+ OperandStack.append (' ( {Operator} {Oprand} )'.format (Operator = Operator, Oprand = Oprand))
+ elif self.IsValidBinocularOperator (self._opReferenceReverse[Opcode]) and len (OperandStack) >= 2:
+ Oprand1 = OperandStack.pop ()
+ Oprand2 = OperandStack.pop ()
+ OperandStack.append (' ( {Oprand1} {Operator} {Oprand2} )'.format (Operator = Operator, Oprand1 = Oprand1, Oprand2 = Oprand2))
+ else:
+ Msg = 'No enough Operands for {Opcode:02X}.'.format (Opcode = Opcode)
+ raise ValueError (Msg)
+
+ else:
+ Msg = '{Opcode:02X} is not a valid OpCode.'.format (Opcode = Opcode)
+ raise ValueError (Msg)
+
+ self.DepexExp = OperandStack[0].strip (' ')
+ self.Payload = Buffer[DepexLen:]
+ self._Valid = True
+ self._DepexSize = DepexLen
+ return self.Payload
+
+
+ def DumpInfo (self):
+ DepexLen = 0
+ Opcode = None
+ Buffer = self.Depex
+
+ if self._Valid == True:
+ print ('EFI_FIRMWARE_IMAGE_DEP.Dependencies = {')
+ while Opcode != 0x0D:
+ Opcode, Operand, OperandSize = self.OpConverter.OpDecode (Buffer[DepexLen:])
+ DepexLen += OperandSize + 1
+ if Operand:
+ print (' {Opcode:02X}, {Operand},'.format (Opcode = Opcode, Operand = Operand))
+ else:
+ print (' {Opcode:02X},'.format (Opcode = Opcode))
+ print ('}')
+
+ print ('sizeof (EFI_FIRMWARE_IMAGE_DEP.Dependencies) = {Size:08X}'.format (Size = self._DepexSize))
+ print ('sizeof (Payload) = {Size:08X}'.format (Size = len (self.Payload)))
--
2.18.0.windows.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH v1] BaseTools/Capsule: Add capsule dependency support
2020-01-10 1:57 [PATCH v1] BaseTools/Capsule: Add capsule dependency support aaron.li
@ 2020-01-15 2:12 ` Bob Feng
0 siblings, 0 replies; 2+ messages in thread
From: Bob Feng @ 2020-01-15 2:12 UTC (permalink / raw)
To: Li, Aaron, devel@edk2.groups.io; +Cc: Gao, Liming
Reviewed-by: Bob Feng <bob.c.feng@intel.com>
-----Original Message-----
From: Li, Aaron
Sent: Friday, January 10, 2020 9:58 AM
To: devel@edk2.groups.io
Cc: Feng, Bob C <bob.c.feng@intel.com>; Gao, Liming <liming.gao@intel.com>
Subject: [PATCH v1] BaseTools/Capsule: Add capsule dependency support
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>
---
BaseTools/Source/Python/Capsule/GenerateCapsule.py | 62 ++-
BaseTools/Source/Python/Common/Uefi/Capsule/CapsuleDependency.py | 409 ++++++++++++++++++++
2 files changed, 464 insertions(+), 7 deletions(-)
diff --git a/BaseTools/Source/Python/Capsule/GenerateCapsule.py b/BaseTools/Source/Python/Capsule/GenerateCapsule.py
index 6838beb682..a8de988253 100644
--- a/BaseTools/Source/Python/Capsule/GenerateCapsule.py
+++ b/BaseTools/Source/Python/Capsule/GenerateCapsule.py
@@ -31,6 +31,7 @@ import json
from Common.Uefi.Capsule.UefiCapsuleHeader import UefiCapsuleHeaderClass from Common.Uefi.Capsule.FmpCapsuleHeader import FmpCapsuleHeaderClass
from Common.Uefi.Capsule.FmpAuthHeader import FmpAuthHeaderClass
+from Common.Uefi.Capsule.CapsuleDependency import
+CapsuleDependencyClass
from Common.Edk2.Capsule.FmpPayloadHeader import FmpPayloadHeaderClass
#
@@ -306,6 +307,7 @@ if __name__ == '__main__':
OpenSslOtherPublicCertFile = ConvertJsonValue (Config, 'OpenSslOtherPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True)
OpenSslTrustedPublicCertFile = ConvertJsonValue (Config, 'OpenSslTrustedPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True)
SigningToolPath = ConvertJsonValue (Config, 'SigningToolPath', os.path.expandvars, Required = False, Default = None)
+ DepexExp = ConvertJsonValue (Config, 'Dependencies', str, Required = False, Default = None)
#
# Read binary input file
@@ -330,7 +332,8 @@ if __name__ == '__main__':
OpenSslSignerPrivateCertFile,
OpenSslOtherPublicCertFile,
OpenSslTrustedPublicCertFile,
- SigningToolPath
+ SigningToolPath,
+ DepexExp
))
def GenerateOutputJson (PayloadJsonDescriptorList):
@@ -348,7 +351,8 @@ if __name__ == '__main__':
"OpenSslSignerPrivateCertFile": str(PayloadDescriptor.OpenSslSignerPrivateCertFile),
"OpenSslOtherPublicCertFile": str(PayloadDescriptor.OpenSslOtherPublicCertFile),
"OpenSslTrustedPublicCertFile": str(PayloadDescriptor.OpenSslTrustedPublicCertFile),
- "SigningToolPath": str(PayloadDescriptor.SigningToolPath)
+ "SigningToolPath": str(PayloadDescriptor.SigningToolPath),
+ "Dependencies" :
+ str(PayloadDescriptor.DepexExp)
}for PayloadDescriptor in PayloadJsonDescriptorList
]
}
@@ -424,7 +428,8 @@ if __name__ == '__main__':
OpenSslSignerPrivateCertFile = None,
OpenSslOtherPublicCertFile = None,
OpenSslTrustedPublicCertFile = None,
- SigningToolPath = None
+ SigningToolPath = None,
+ DepexExp = None
):
self.Payload = Payload
self.Guid = Guid
@@ -438,6 +443,7 @@ if __name__ == '__main__':
self.OpenSslOtherPublicCertFile = OpenSslOtherPublicCertFile
self.OpenSslTrustedPublicCertFile = OpenSslTrustedPublicCertFile
self.SigningToolPath = SigningToolPath
+ self.DepexExp = DepexExp
self.UseSignTool = self.SignToolPfxFile is not None
self.UseOpenSsl = (self.OpenSslSignerPrivateCertFile is not None and @@ -446,6 +452,7 @@ if __name__ == '__main__':
self.AnyOpenSsl = (self.OpenSslSignerPrivateCertFile is not None or
self.OpenSslOtherPublicCertFile is not None or
self.OpenSslTrustedPublicCertFile is not None)
+ self.UseDependency = self.DepexExp is not None
def Validate(self, args):
if self.UseSignTool and self.AnyOpenSsl:
@@ -544,7 +551,8 @@ if __name__ == '__main__':
args.OpenSslSignerPrivateCertFile,
args.OpenSslOtherPublicCertFile,
args.OpenSslTrustedPublicCertFile,
- args.SigningToolPath
+ args.SigningToolPath,
+ None
))
for SinglePayloadDescriptor in PayloadDescriptorList:
try:
@@ -564,6 +572,12 @@ if __name__ == '__main__':
except:
print ('GenerateCapsule: error: can not encode FMP Payload Header')
sys.exit (1)
+ if SinglePayloadDescriptor.UseDependency:
+ CapsuleDependency.Payload = Result
+ CapsuleDependency.DepexExp = SinglePayloadDescriptor.DepexExp
+ Result = CapsuleDependency.Encode ()
+ if args.Verbose:
+ CapsuleDependency.DumpInfo ()
if SinglePayloadDescriptor.UseOpenSsl or SinglePayloadDescriptor.UseSignTool:
#
# Sign image with 64-bit MonotonicCount appended to end of image @@ -657,7 +671,8 @@ if __name__ == '__main__':
args.OpenSslSignerPrivateCertFile,
args.OpenSslOtherPublicCertFile,
args.OpenSslTrustedPublicCertFile,
- args.SigningToolPath
+ args.SigningToolPath,
+ None
))
#
# Perform additional verification on payload descriptors @@ -700,7 +715,8 @@ if __name__ == '__main__':
PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile,
PayloadDescriptorList[Index].OpenSslOtherPublicCertFile,
PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile,
- PayloadDescriptorList[Index].SigningToolPath
+ PayloadDescriptorList[Index].SigningToolPath,
+ None
))
else:
PayloadDescriptorList[0].Payload = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload @@ -708,6 +724,7 @@ if __name__ == '__main__':
if Index > 0:
PayloadDecodeFile = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).Payload
PayloadDescriptorList.append (PayloadDescriptor (PayloadDecodeFile,
+ None,
None,
None,
None, @@ -736,7 +753,8 @@ if __name__ == '__main__':
PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile,
PayloadDescriptorList[Index].OpenSslOtherPublicCertFile,
PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile,
- PayloadDescriptorList[Index].SigningToolPath
+ PayloadDescriptorList[Index].SigningToolPath,
+ None
))
JsonIndex = 0
for SinglePayloadDescriptor in PayloadDescriptorList:
@@ -782,6 +800,23 @@ if __name__ == '__main__':
if args.Verbose:
print ('--------')
print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')
+
+ PayloadSignature = struct.unpack ('<I', SinglePayloadDescriptor.Payload[0:4])
+ if PayloadSignature != FmpPayloadHeader.Signature:
+ SinglePayloadDescriptor.UseDependency = True
+ try:
+ SinglePayloadDescriptor.Payload = CapsuleDependency.Decode (SinglePayloadDescriptor.Payload)
+ PayloadJsonDescriptorList[JsonIndex].DepexExp = CapsuleDependency.DepexExp
+ if args.Verbose:
+ print ('--------')
+ CapsuleDependency.DumpInfo ()
+ except Exception as Msg:
+ print ('GenerateCapsule: error: invalid dependency expression')
+ else:
+ if args.Verbose:
+ print ('--------')
+ print ('No EFI_FIRMWARE_IMAGE_DEP')
+
try:
SinglePayloadDescriptor.Payload = FmpPayloadHeader.Decode (SinglePayloadDescriptor.Payload)
PayloadJsonDescriptorList[JsonIndex].FwVersion = FmpPayloadHeader.FwVersion @@ -852,6 +887,18 @@ if __name__ == '__main__':
except:
print ('--------')
print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')
+
+ PayloadSignature = struct.unpack ('<I', Result[0:4])
+ if PayloadSignature != FmpPayloadHeader.Signature:
+ try:
+ Result = CapsuleDependency.Decode (Result)
+ print ('--------')
+ CapsuleDependency.DumpInfo ()
+ except:
+ print ('GenerateCapsule: error: invalid dependency expression')
+ else:
+ print ('--------')
+ print ('No EFI_FIRMWARE_IMAGE_DEP')
try:
Result = FmpPayloadHeader.Decode (Result)
print ('--------') @@ -973,6 +1020,7 @@ if __name__ == '__main__':
FmpCapsuleHeader = FmpCapsuleHeaderClass ()
FmpAuthHeader = FmpAuthHeaderClass ()
FmpPayloadHeader = FmpPayloadHeaderClass ()
+ CapsuleDependency = CapsuleDependencyClass ()
EmbeddedDriverDescriptorList = []
PayloadDescriptorList = []
diff --git a/BaseTools/Source/Python/Common/Uefi/Capsule/CapsuleDependency.py b/BaseTools/Source/Python/Common/Uefi/Capsule/CapsuleDependency.py
new file mode 100644
index 0000000000..74004857a7
--- /dev/null
+++ b/BaseTools/Source/Python/Common/Uefi/Capsule/CapsuleDependency.py
@@ -0,0 +1,409 @@
+## @file
+# Module that encodes and decodes a capsule dependency.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR> #
+SPDX-License-Identifier: BSD-2-Clause-Patent # import struct import
+json import sys import uuid import re
+
+'''
+CapsuleDependency
+'''
+
+class OpConvert (object):
+ def __init__ (self):
+ # Opcode: (OperandSize, PackSize, PackFmt, EncodeConvert, DecodeConvert)
+ self._DepexOperations = {0x00: (16, 16, 's', self.Str2Guid, self.Guid2Str),
+ 0x01: (4, 1, 'I', self.Str2Uint, self.Uint2Str),
+ 0x02: (1, 0, 's', self.Str2Utf8, self.Byte2Str),
+ }
+
+ def Str2Uint (self, Data):
+ try:
+ Value = int (Data, 16)
+ except:
+ Message = '{Data} is not a valid integer value.'.format (Data = Data)
+ raise ValueError (Message)
+ if Value < 0 or Value > 0xFFFFFFFF:
+ Message = '{Data} is not an UINT32.'.format (Data = Data)
+ raise ValueError (Message)
+ return Value
+
+ def Uint2Str (self, Data):
+ if Data < 0 or Data > 0xFFFFFFFF:
+ Message = '{Data} is not an UINT32.'.format (Data = Data)
+ raise ValueError (Message)
+ return "0x{Data:08x}".format (Data = Data)
+
+ def Str2Guid (self, Data):
+ try:
+ Guid = uuid.UUID (Data)
+ except:
+ Message = '{Data} is not a valid registry format GUID value.'.format (Data = Data)
+ raise ValueError (Message)
+ return Guid.bytes_le
+
+ def Guid2Str (self, Data):
+ try:
+ Guid = uuid.UUID (bytes_le = Data)
+ except:
+ Message = '{Data} is not a valid binary format GUID value.'.format (Data = Data)
+ raise ValueError (Message)
+ return str (Guid).upper ()
+
+ def Str2Utf8 (self, Data):
+ if isinstance (Data, str):
+ return Data.encode ('utf-8')
+ else:
+ Message = '{Data} is not a valid string.'.format (Data = Data)
+ raise ValueError (Message)
+
+ def Byte2Str (self, Data):
+ if isinstance (Data, bytes):
+ if Data[-1:] == b'\x00':
+ return str (Data[:-1], 'utf-8')
+ else:
+ return str (Data, 'utf-8')
+ else:
+ Message = '{Data} is not a valid binary string.'.format (Data = Data)
+ raise ValueError (Message)
+
+ def OpEncode (self, Opcode, Operand = None):
+ BinTemp = struct.pack ('<b', Opcode)
+ if Opcode <= 0x02 and Operand != None:
+ OperandSize, PackSize, PackFmt, EncodeConvert, DecodeConvert = self._DepexOperations[Opcode]
+ Value = EncodeConvert (Operand)
+ if Opcode == 0x02:
+ PackSize = len (Value) + 1
+ BinTemp += struct.pack ('<{PackSize}{PackFmt}'.format (PackSize = PackSize, PackFmt = PackFmt), Value)
+ return BinTemp
+
+ def OpDecode (self, Buffer):
+ Opcode = struct.unpack ('<b', Buffer[0:1])[0]
+ if Opcode <= 0x02:
+ OperandSize, PackSize, PackFmt, EncodeConvert, DecodeConvert = self._DepexOperations[Opcode]
+ if Opcode == 0x02:
+ try:
+ PackSize = Buffer[1:].index (b'\x00') + 1
+ OperandSize = PackSize
+ except:
+ Message = 'CapsuleDependency: OpConvert: error: decode failed with wrong opcode/string.'
+ raise ValueError (Message)
+ try:
+ Operand = DecodeConvert (struct.unpack ('<{PackSize}{PackFmt}'.format (PackSize = PackSize, PackFmt = PackFmt), Buffer[1:1+OperandSize])[0])
+ except:
+ Message = 'CapsuleDependency: OpConvert: error: decode failed with unpack failure.'
+ raise ValueError (Message)
+ else:
+ Operand = None
+ OperandSize = 0
+ return (Opcode, Operand, OperandSize)
+
+class CapsuleDependencyClass (object):
+ # //**************************************************************
+ # // Image Attribute - Dependency
+ # //**************************************************************
+ # typedef struct {
+ # UINT8 Dependencies[];
+ # } EFI_FIRMWARE_IMAGE_DEP
+
+ # {expression operator : [precedence, opcode, type (1:unary/2:binocular)]}
+ _opReference = {'&&': [2, 0x03, 2],
+ '||': [1, 0x04, 2],
+ '~': [5, 0x05, 1],
+ '==': [3, 0x08, 2],
+ '>': [4, 0x09, 2],
+ '>=': [4, 0x0A, 2],
+ '<': [4, 0x0B, 2],
+ '<=': [4, 0x0C, 2],
+ }
+
+ def __init__ (self):
+ self.Payload = b''
+ self._DepexExp = None
+ self._DepexList = []
+ self._DepexDump = []
+ self.Depex = b''
+ self._Valid = False
+ self._DepexSize = 0
+ self._opReferenceReverse = {v[1] : k for k, v in self._opReference.items ()}
+ self.OpConverter = OpConvert ()
+
+ @property
+ def DepexExp (self):
+ return self._DepexExp
+
+ @DepexExp.setter
+ def DepexExp (self, DepexExp = ''):
+ if isinstance (DepexExp, str):
+ DepexExp = re.sub (r'\n',r' ',DepexExp)
+ DepexExp = re.sub (r'\(',r' ( ',DepexExp)
+ DepexExp = re.sub (r'\)',r' ) ',DepexExp)
+ DepexExp = re.sub (r'~',r' ~ ',DepexExp)
+ self._DepexList = re.findall(r"[^\s\"\']+|\"[^\"]*\"|\'[^\']*\'",DepexExp)
+ self._DepexExp = " ".join(self._DepexList)
+
+ else:
+ Msg = 'Input Depex Expression is not valid string.'
+ raise ValueError (Msg)
+
+ def IsValidOperator (self, op):
+ return op in self._opReference.keys ()
+
+ def IsValidUnaryOperator (self, op):
+ return op in self._opReference.keys () and
+ self._opReference[op][2] == 1
+
+ def IsValidBinocularOperator (self, op):
+ return op in self._opReference.keys () and
+ self._opReference[op][2] == 2
+
+ def IsValidGuid (self, operand):
+ try:
+ uuid.UUID (operand)
+ except:
+ return False
+ return True
+
+ def IsValidVersion (self, operand):
+ try:
+ Value = int (operand, 16)
+ if Value < 0 or Value > 0xFFFFFFFF:
+ return False
+ except:
+ return False
+ return True
+
+ def IsValidBoolean (self, operand):
+ try:
+ return operand.upper () in ['TRUE', 'FALSE']
+ except:
+ return False
+
+ def IsValidOperand (self, operand):
+ return self.IsValidVersion (operand) or self.IsValidGuid
+ (operand) or self.IsValidBoolean (operand)
+
+ def IsValidString (self, operand):
+ return operand[0] == "\"" and operand[-1] == "\"" and
+ len(operand) >= 2
+
+ # Check if priority of current operater is greater than pervious op
+ def PriorityNotGreater (self, prevOp, currOp):
+ return self._opReference[currOp][0] <=
+ self._opReference[prevOp][0]
+
+ def ValidateDepex (self):
+ OpList = self._DepexList
+
+ i = 0
+ while i < len (OpList):
+ Op = OpList[i]
+
+ if Op == 'DECLARE':
+ i += 1
+ if i >= len (OpList):
+ Msg = 'No more Operand after {Op}.'.format (Op = OpList[i-1])
+ raise IndexError (Msg)
+ # Check valid string
+ if not self.IsValidString(OpList[i]):
+ Msg = '{Operand} after {Op} is not a valid expression input.'.format (Operand = OpList[i], Op = OpList[i-1])
+ raise ValueError (Msg)
+
+ elif Op == '(':
+ # Expression cannot end with (
+ if i == len (OpList) - 1:
+ Msg = 'Expression cannot end with \'(\''
+ raise ValueError (Msg)
+ # The previous op after '(' cannot be a binocular operator
+ if self.IsValidBinocularOperator (OpList[i+1]) :
+ Msg = '{Op} after \'(\' is not a valid expression input.'.format (Op = OpList[i+1])
+ raise ValueError (Msg)
+
+ elif Op == ')':
+ # Expression cannot start with )
+ if i == 0:
+ Msg = 'Expression cannot start with \')\''
+ raise ValueError (Msg)
+ # The previous op before ')' cannot be an operator
+ if self.IsValidOperator (OpList[i-1]):
+ Msg = '{Op} before \')\' is not a valid expression input.'.format (Op = OpList[i-1])
+ raise ValueError (Msg)
+ # The next op after ')' cannot be operand or unary operator
+ if (i + 1) < len (OpList) and (self.IsValidOperand (OpList[i+1]) or self.IsValidUnaryOperator (OpList[i+1])):
+ Msg = '{Op} after \')\' is not a valid expression input.'.format (Op = OpList[i+1])
+ raise ValueError (Msg)
+
+ elif self.IsValidOperand (Op):
+ # The next expression of operand cannot be operand or unary operator
+ if (i + 1) < len (OpList) and (self.IsValidOperand (OpList[i+1]) or self.IsValidUnaryOperator (OpList[i+1])):
+ Msg = '{Op} after {PrevOp} is not a valid expression input.'.format (Op = OpList[i+1], PrevOp = Op)
+ raise ValueError (Msg)
+
+ elif self.IsValidOperator (Op):
+ # The next op of operator cannot binocular operator
+ if (i + 1) < len (OpList) and self.IsValidBinocularOperator (OpList[i+1]):
+ Msg = '{Op} after {PrevOp} is not a valid expression input.'.format (Op = OpList[i+1], PrevOp = Op)
+ raise ValueError (Msg)
+ # The first op can not be binocular operator
+ if i == 0 and self.IsValidBinocularOperator (Op):
+ Msg = 'Expression cannot start with an operator {Op}.'.format (Op = Op)
+ raise ValueError (Msg)
+ # The last op can not be operator
+ if i == len (OpList) - 1:
+ Msg = 'Expression cannot ended with an operator {Op}.'.format (Op = Op)
+ raise ValueError (Msg)
+ # The next op of unary operator cannot be guid / version
+ if self.IsValidUnaryOperator (Op) and (self.IsValidGuid (OpList[i+1]) or self.IsValidVersion (OpList[i+1])):
+ Msg = '{Op} after {PrevOp} is not a valid expression input.'.format (Op = OpList[i+1], PrevOp = Op)
+ raise ValueError (Msg)
+
+ else:
+ Msg = '{Op} is not a valid expression input.'.format (Op = Op)
+ raise ValueError (Msg)
+ i += 1
+
+ def Encode (self):
+ # initialize
+ self.Depex = b''
+ self._DepexDump = []
+ OperandStack = []
+ OpeartorStack = []
+ OpList = self._DepexList
+
+ self.ValidateDepex ()
+
+ # convert
+ i = 0
+ while i < len (OpList):
+ Op = OpList[i]
+ if Op == 'DECLARE':
+ # This declare next expression value is a VERSION_STRING
+ i += 1
+ self.Depex += self.OpConverter.OpEncode (0x02,
+ OpList[i][1:-1])
+
+ elif Op == '(':
+ OpeartorStack.append (Op)
+
+ elif Op == ')':
+ while (OpeartorStack and OpeartorStack[-1] != '('):
+ Operator = OpeartorStack.pop ()
+ self.Depex += self.OpConverter.OpEncode (self._opReference[Operator][1])
+ try:
+ OpeartorStack.pop () # pop out '('
+ except:
+ Msg = 'Pop out \'(\' failed, too many \')\''
+ raise ValueError (Msg)
+
+ elif self.IsValidGuid (Op):
+ if not OperandStack:
+ OperandStack.append (self.OpConverter.OpEncode (0x00, Op))
+ else:
+ # accroding to uefi spec 2.8, the guid/version operands is a reversed order in firmware comparison.
+ self.Depex += self.OpConverter.OpEncode (0x00, Op)
+ self.Depex += OperandStack.pop ()
+
+ elif self.IsValidVersion (Op):
+ if not OperandStack:
+ OperandStack.append (self.OpConverter.OpEncode (0x01, Op))
+ else:
+ # accroding to uefi spec 2.8, the guid/version operands is a reversed order in firmware comparison.
+ self.Depex += self.OpConverter.OpEncode (0x01, Op)
+ self.Depex += OperandStack.pop ()
+
+ elif self.IsValidBoolean (Op):
+ if Op.upper () == 'FALSE':
+ self.Depex += self.OpConverter.OpEncode (0x07)
+ elif Op.upper () == 'TRUE':
+ self.Depex += self.OpConverter.OpEncode (0x06)
+
+ elif self.IsValidOperator (Op):
+ while (OpeartorStack and OpeartorStack[-1] != '(' and self.PriorityNotGreater (OpeartorStack[-1], Op)):
+ Operator = OpeartorStack.pop ()
+ self.Depex += self.OpConverter.OpEncode (self._opReference[Operator][1])
+ OpeartorStack.append (Op)
+
+ i += 1
+
+ while OpeartorStack:
+ Operator = OpeartorStack.pop ()
+ if Operator == '(':
+ Msg = 'Too many \'(\'.'
+ raise ValueError (Msg)
+ self.Depex += self.OpConverter.OpEncode (self._opReference[Operator][1])
+ self.Depex += self.OpConverter.OpEncode (0x0D)
+
+ self._Valid = True
+ self._DepexSize = len (self.Depex)
+ return self.Depex + self.Payload
+
+ def Decode (self, Buffer):
+ # initialize
+ self.Depex = Buffer
+ OperandStack = []
+ DepexLen = 0
+
+ while True:
+ Opcode, Operand, OperandSize = self.OpConverter.OpDecode (Buffer[DepexLen:])
+ DepexLen += OperandSize + 1
+
+ if Opcode == 0x0D:
+ break
+
+ elif Opcode == 0x02:
+ if not OperandStack:
+ OperandStack.append ('DECLARE \"{String}\"'.format (String = Operand))
+ else:
+ PrevOperand = OperandStack.pop ()
+ OperandStack.append ('{Operand} DECLARE
+ \"{String}\"'.format (Operand = PrevOperand, String = Operand))
+
+ elif Opcode in [0x00, 0x01]:
+ OperandStack.append (Operand)
+
+ elif Opcode == 0x06:
+ OperandStack.append ('TRUE')
+
+ elif Opcode == 0x07:
+ OperandStack.append ('FALSE')
+
+ elif self.IsValidOperator (self._opReferenceReverse[Opcode]):
+ Operator = self._opReferenceReverse[Opcode]
+ if self.IsValidUnaryOperator (self._opReferenceReverse[Opcode]) and len (OperandStack) >= 1:
+ Oprand = OperandStack.pop ()
+ OperandStack.append (' ( {Operator} {Oprand} )'.format (Operator = Operator, Oprand = Oprand))
+ elif self.IsValidBinocularOperator (self._opReferenceReverse[Opcode]) and len (OperandStack) >= 2:
+ Oprand1 = OperandStack.pop ()
+ Oprand2 = OperandStack.pop ()
+ OperandStack.append (' ( {Oprand1} {Operator} {Oprand2} )'.format (Operator = Operator, Oprand1 = Oprand1, Oprand2 = Oprand2))
+ else:
+ Msg = 'No enough Operands for {Opcode:02X}.'.format (Opcode = Opcode)
+ raise ValueError (Msg)
+
+ else:
+ Msg = '{Opcode:02X} is not a valid OpCode.'.format (Opcode = Opcode)
+ raise ValueError (Msg)
+
+ self.DepexExp = OperandStack[0].strip (' ')
+ self.Payload = Buffer[DepexLen:]
+ self._Valid = True
+ self._DepexSize = DepexLen
+ return self.Payload
+
+
+ def DumpInfo (self):
+ DepexLen = 0
+ Opcode = None
+ Buffer = self.Depex
+
+ if self._Valid == True:
+ print ('EFI_FIRMWARE_IMAGE_DEP.Dependencies = {')
+ while Opcode != 0x0D:
+ Opcode, Operand, OperandSize = self.OpConverter.OpDecode (Buffer[DepexLen:])
+ DepexLen += OperandSize + 1
+ if Operand:
+ print (' {Opcode:02X}, {Operand},'.format (Opcode = Opcode, Operand = Operand))
+ else:
+ print (' {Opcode:02X},'.format (Opcode = Opcode))
+ print ('}')
+
+ print ('sizeof (EFI_FIRMWARE_IMAGE_DEP.Dependencies) = {Size:08X}'.format (Size = self._DepexSize))
+ print ('sizeof (Payload) = {Size:08X}'.format (Size = len (self.Payload)))
--
2.18.0.windows.1
^ permalink raw reply related [flat|nested] 2+ messages in thread
end of thread, other threads:[~2020-01-15 2:12 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-01-10 1:57 [PATCH v1] BaseTools/Capsule: Add capsule dependency support aaron.li
2020-01-15 2:12 ` Bob Feng
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox