mirror of https://github.com/acidanthera/audk.git
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> Reviewed-by: Bob Feng <bob.c.feng@intel.com>
This commit is contained in:
parent
94057f7402
commit
f6f66e0c30
|
@ -31,6 +31,7 @@ import json
|
||||||
from Common.Uefi.Capsule.UefiCapsuleHeader import UefiCapsuleHeaderClass
|
from Common.Uefi.Capsule.UefiCapsuleHeader import UefiCapsuleHeaderClass
|
||||||
from Common.Uefi.Capsule.FmpCapsuleHeader import FmpCapsuleHeaderClass
|
from Common.Uefi.Capsule.FmpCapsuleHeader import FmpCapsuleHeaderClass
|
||||||
from Common.Uefi.Capsule.FmpAuthHeader import FmpAuthHeaderClass
|
from Common.Uefi.Capsule.FmpAuthHeader import FmpAuthHeaderClass
|
||||||
|
from Common.Uefi.Capsule.CapsuleDependency import CapsuleDependencyClass
|
||||||
from Common.Edk2.Capsule.FmpPayloadHeader import FmpPayloadHeaderClass
|
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)
|
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)
|
OpenSslTrustedPublicCertFile = ConvertJsonValue (Config, 'OpenSslTrustedPublicCertFile', os.path.expandvars, Required = False, Default = None, Open = True)
|
||||||
SigningToolPath = ConvertJsonValue (Config, 'SigningToolPath', os.path.expandvars, Required = False, Default = None)
|
SigningToolPath = ConvertJsonValue (Config, 'SigningToolPath', os.path.expandvars, Required = False, Default = None)
|
||||||
|
DepexExp = ConvertJsonValue (Config, 'Dependencies', str, Required = False, Default = None)
|
||||||
|
|
||||||
#
|
#
|
||||||
# Read binary input file
|
# Read binary input file
|
||||||
|
@ -330,7 +332,8 @@ if __name__ == '__main__':
|
||||||
OpenSslSignerPrivateCertFile,
|
OpenSslSignerPrivateCertFile,
|
||||||
OpenSslOtherPublicCertFile,
|
OpenSslOtherPublicCertFile,
|
||||||
OpenSslTrustedPublicCertFile,
|
OpenSslTrustedPublicCertFile,
|
||||||
SigningToolPath
|
SigningToolPath,
|
||||||
|
DepexExp
|
||||||
))
|
))
|
||||||
|
|
||||||
def GenerateOutputJson (PayloadJsonDescriptorList):
|
def GenerateOutputJson (PayloadJsonDescriptorList):
|
||||||
|
@ -348,7 +351,8 @@ if __name__ == '__main__':
|
||||||
"OpenSslSignerPrivateCertFile": str(PayloadDescriptor.OpenSslSignerPrivateCertFile),
|
"OpenSslSignerPrivateCertFile": str(PayloadDescriptor.OpenSslSignerPrivateCertFile),
|
||||||
"OpenSslOtherPublicCertFile": str(PayloadDescriptor.OpenSslOtherPublicCertFile),
|
"OpenSslOtherPublicCertFile": str(PayloadDescriptor.OpenSslOtherPublicCertFile),
|
||||||
"OpenSslTrustedPublicCertFile": str(PayloadDescriptor.OpenSslTrustedPublicCertFile),
|
"OpenSslTrustedPublicCertFile": str(PayloadDescriptor.OpenSslTrustedPublicCertFile),
|
||||||
"SigningToolPath": str(PayloadDescriptor.SigningToolPath)
|
"SigningToolPath": str(PayloadDescriptor.SigningToolPath),
|
||||||
|
"Dependencies" : str(PayloadDescriptor.DepexExp)
|
||||||
}for PayloadDescriptor in PayloadJsonDescriptorList
|
}for PayloadDescriptor in PayloadJsonDescriptorList
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -424,7 +428,8 @@ if __name__ == '__main__':
|
||||||
OpenSslSignerPrivateCertFile = None,
|
OpenSslSignerPrivateCertFile = None,
|
||||||
OpenSslOtherPublicCertFile = None,
|
OpenSslOtherPublicCertFile = None,
|
||||||
OpenSslTrustedPublicCertFile = None,
|
OpenSslTrustedPublicCertFile = None,
|
||||||
SigningToolPath = None
|
SigningToolPath = None,
|
||||||
|
DepexExp = None
|
||||||
):
|
):
|
||||||
self.Payload = Payload
|
self.Payload = Payload
|
||||||
self.Guid = Guid
|
self.Guid = Guid
|
||||||
|
@ -438,6 +443,7 @@ if __name__ == '__main__':
|
||||||
self.OpenSslOtherPublicCertFile = OpenSslOtherPublicCertFile
|
self.OpenSslOtherPublicCertFile = OpenSslOtherPublicCertFile
|
||||||
self.OpenSslTrustedPublicCertFile = OpenSslTrustedPublicCertFile
|
self.OpenSslTrustedPublicCertFile = OpenSslTrustedPublicCertFile
|
||||||
self.SigningToolPath = SigningToolPath
|
self.SigningToolPath = SigningToolPath
|
||||||
|
self.DepexExp = DepexExp
|
||||||
|
|
||||||
self.UseSignTool = self.SignToolPfxFile is not None
|
self.UseSignTool = self.SignToolPfxFile is not None
|
||||||
self.UseOpenSsl = (self.OpenSslSignerPrivateCertFile is not None and
|
self.UseOpenSsl = (self.OpenSslSignerPrivateCertFile is not None and
|
||||||
|
@ -446,6 +452,7 @@ if __name__ == '__main__':
|
||||||
self.AnyOpenSsl = (self.OpenSslSignerPrivateCertFile is not None or
|
self.AnyOpenSsl = (self.OpenSslSignerPrivateCertFile is not None or
|
||||||
self.OpenSslOtherPublicCertFile is not None or
|
self.OpenSslOtherPublicCertFile is not None or
|
||||||
self.OpenSslTrustedPublicCertFile is not None)
|
self.OpenSslTrustedPublicCertFile is not None)
|
||||||
|
self.UseDependency = self.DepexExp is not None
|
||||||
|
|
||||||
def Validate(self, args):
|
def Validate(self, args):
|
||||||
if self.UseSignTool and self.AnyOpenSsl:
|
if self.UseSignTool and self.AnyOpenSsl:
|
||||||
|
@ -544,7 +551,8 @@ if __name__ == '__main__':
|
||||||
args.OpenSslSignerPrivateCertFile,
|
args.OpenSslSignerPrivateCertFile,
|
||||||
args.OpenSslOtherPublicCertFile,
|
args.OpenSslOtherPublicCertFile,
|
||||||
args.OpenSslTrustedPublicCertFile,
|
args.OpenSslTrustedPublicCertFile,
|
||||||
args.SigningToolPath
|
args.SigningToolPath,
|
||||||
|
None
|
||||||
))
|
))
|
||||||
for SinglePayloadDescriptor in PayloadDescriptorList:
|
for SinglePayloadDescriptor in PayloadDescriptorList:
|
||||||
try:
|
try:
|
||||||
|
@ -564,6 +572,12 @@ if __name__ == '__main__':
|
||||||
except:
|
except:
|
||||||
print ('GenerateCapsule: error: can not encode FMP Payload Header')
|
print ('GenerateCapsule: error: can not encode FMP Payload Header')
|
||||||
sys.exit (1)
|
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:
|
if SinglePayloadDescriptor.UseOpenSsl or SinglePayloadDescriptor.UseSignTool:
|
||||||
#
|
#
|
||||||
# Sign image with 64-bit MonotonicCount appended to end of image
|
# Sign image with 64-bit MonotonicCount appended to end of image
|
||||||
|
@ -657,7 +671,8 @@ if __name__ == '__main__':
|
||||||
args.OpenSslSignerPrivateCertFile,
|
args.OpenSslSignerPrivateCertFile,
|
||||||
args.OpenSslOtherPublicCertFile,
|
args.OpenSslOtherPublicCertFile,
|
||||||
args.OpenSslTrustedPublicCertFile,
|
args.OpenSslTrustedPublicCertFile,
|
||||||
args.SigningToolPath
|
args.SigningToolPath,
|
||||||
|
None
|
||||||
))
|
))
|
||||||
#
|
#
|
||||||
# Perform additional verification on payload descriptors
|
# Perform additional verification on payload descriptors
|
||||||
|
@ -700,7 +715,8 @@ if __name__ == '__main__':
|
||||||
PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile,
|
PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile,
|
||||||
PayloadDescriptorList[Index].OpenSslOtherPublicCertFile,
|
PayloadDescriptorList[Index].OpenSslOtherPublicCertFile,
|
||||||
PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile,
|
PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile,
|
||||||
PayloadDescriptorList[Index].SigningToolPath
|
PayloadDescriptorList[Index].SigningToolPath,
|
||||||
|
None
|
||||||
))
|
))
|
||||||
else:
|
else:
|
||||||
PayloadDescriptorList[0].Payload = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload
|
PayloadDescriptorList[0].Payload = FmpCapsuleHeader.GetFmpCapsuleImageHeader (0).Payload
|
||||||
|
@ -718,6 +734,7 @@ if __name__ == '__main__':
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
None
|
None
|
||||||
))
|
))
|
||||||
GUID = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageTypeId
|
GUID = FmpCapsuleHeader.GetFmpCapsuleImageHeader (Index).UpdateImageTypeId
|
||||||
|
@ -736,7 +753,8 @@ if __name__ == '__main__':
|
||||||
PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile,
|
PayloadDescriptorList[Index].OpenSslSignerPrivateCertFile,
|
||||||
PayloadDescriptorList[Index].OpenSslOtherPublicCertFile,
|
PayloadDescriptorList[Index].OpenSslOtherPublicCertFile,
|
||||||
PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile,
|
PayloadDescriptorList[Index].OpenSslTrustedPublicCertFile,
|
||||||
PayloadDescriptorList[Index].SigningToolPath
|
PayloadDescriptorList[Index].SigningToolPath,
|
||||||
|
None
|
||||||
))
|
))
|
||||||
JsonIndex = 0
|
JsonIndex = 0
|
||||||
for SinglePayloadDescriptor in PayloadDescriptorList:
|
for SinglePayloadDescriptor in PayloadDescriptorList:
|
||||||
|
@ -782,6 +800,23 @@ if __name__ == '__main__':
|
||||||
if args.Verbose:
|
if args.Verbose:
|
||||||
print ('--------')
|
print ('--------')
|
||||||
print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')
|
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:
|
try:
|
||||||
SinglePayloadDescriptor.Payload = FmpPayloadHeader.Decode (SinglePayloadDescriptor.Payload)
|
SinglePayloadDescriptor.Payload = FmpPayloadHeader.Decode (SinglePayloadDescriptor.Payload)
|
||||||
PayloadJsonDescriptorList[JsonIndex].FwVersion = FmpPayloadHeader.FwVersion
|
PayloadJsonDescriptorList[JsonIndex].FwVersion = FmpPayloadHeader.FwVersion
|
||||||
|
@ -852,6 +887,18 @@ if __name__ == '__main__':
|
||||||
except:
|
except:
|
||||||
print ('--------')
|
print ('--------')
|
||||||
print ('No EFI_FIRMWARE_IMAGE_AUTHENTICATION')
|
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:
|
try:
|
||||||
Result = FmpPayloadHeader.Decode (Result)
|
Result = FmpPayloadHeader.Decode (Result)
|
||||||
print ('--------')
|
print ('--------')
|
||||||
|
@ -973,6 +1020,7 @@ if __name__ == '__main__':
|
||||||
FmpCapsuleHeader = FmpCapsuleHeaderClass ()
|
FmpCapsuleHeader = FmpCapsuleHeaderClass ()
|
||||||
FmpAuthHeader = FmpAuthHeaderClass ()
|
FmpAuthHeader = FmpAuthHeaderClass ()
|
||||||
FmpPayloadHeader = FmpPayloadHeaderClass ()
|
FmpPayloadHeader = FmpPayloadHeaderClass ()
|
||||||
|
CapsuleDependency = CapsuleDependencyClass ()
|
||||||
|
|
||||||
EmbeddedDriverDescriptorList = []
|
EmbeddedDriverDescriptorList = []
|
||||||
PayloadDescriptorList = []
|
PayloadDescriptorList = []
|
||||||
|
|
|
@ -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)))
|
Loading…
Reference in New Issue