board_inspector: improve readability and performance of AML parser

This patch refines the AML parser to improve its readability and
performance in the following ways.

  1. A Tree object now has the parts of the corresponding object being
     member fields. As an example, a Tree with label `DefMethod` now has
     members `NameString`, `MethodFlags` and `TermList`.
  2. It is now possible to assign names each part of an object. The grammar
     is updated to assign different names to the parts with the same type
     in the same object.

Tracked-On: #6298
Signed-off-by: Junjie Mao <junjie.mao@intel.com>
This commit is contained in:
Junjie Mao 2021-07-16 14:47:31 +08:00 committed by Xie, Nanlin
parent 6e79479a0a
commit 60da7d6bfd
8 changed files with 328 additions and 268 deletions

View File

@ -57,13 +57,13 @@ class OperationFieldDecl(NamedDecl):
print(f"{self.name}: {self.__class__.__name__}, {self.length} bits") print(f"{self.name}: {self.__class__.__name__}, {self.length} bits")
class AliasDecl(NamedDecl): class AliasDecl(NamedDecl):
def __init__(self, name, target, tree): def __init__(self, name, source, tree):
super().__init__(name, tree) super().__init__(name, tree)
self.name = name self.name = name
self.target = target self.source = source
def dump(self): def dump(self):
print(f"{self.name}: {self.__class__.__name__}, aliasing {self.target}") print(f"{self.name}: {self.__class__.__name__}, aliasing {self.source}")
class MethodDecl(NamedDecl): class MethodDecl(NamedDecl):
def __init__(self, name, nargs, tree): def __init__(self, name, nargs, tree):

View File

@ -48,10 +48,10 @@ class BufferBase(Object):
self.__length = length self.__length = length
self.__fields = {} # name -> (offset, bitwidth, access_width) self.__fields = {} # name -> (offset, bitwidth, access_width)
def read(self, norm_idx, bit_width): def read(self, byte_idx, bit_width):
return NotImplementedError(self.__class__.__name__) return NotImplementedError(self.__class__.__name__)
def write(self, norm_idx, value, bit_width): def write(self, byte_idx, value, bit_width):
return NotImplementedError(self.__class__.__name__) return NotImplementedError(self.__class__.__name__)
def create_field(self, name, offset, bitwidth, access_width): def create_field(self, name, offset, bitwidth, access_width):
@ -69,23 +69,23 @@ class BufferBase(Object):
# Bits out of byte boundary # Bits out of byte boundary
if bit_idx % access_width > 0: if bit_idx % access_width > 0:
norm_idx = floor(bit_idx / access_width) byte_idx = bit_idx // 8
bit_count = (access_width - bit_idx % access_width) bit_count = (access_width - bit_idx % access_width)
if bit_count > bit_remaining: if bit_count > bit_remaining:
bit_count = bit_remaining bit_count = bit_remaining
mask = self.bitmask(bit_idx % access_width + bit_count - 1, bit_idx % access_width) mask = self.bitmask(bit_idx % access_width + bit_count - 1, bit_idx % access_width)
acc = (self.read(norm_idx, access_width) & mask) >> (bit_idx % access_width) acc = (self.read(byte_idx, access_width) & mask) >> (bit_idx % access_width)
acc_bit_count += bit_count acc_bit_count += bit_count
bit_idx += bit_count bit_idx += bit_count
bit_remaining -= bit_count bit_remaining -= bit_count
while bit_remaining > 0: while bit_remaining > 0:
norm_idx = floor(bit_idx / access_width) byte_idx = bit_idx // 8
bit_count = access_width if bit_remaining >= access_width else bit_remaining bit_count = min(access_width, bit_remaining)
mask = self.bitmask(bit_count - 1, 0) mask = self.bitmask(bit_count - 1, 0)
acc |= (self.read(norm_idx, access_width) & mask) << acc_bit_count acc |= (self.read(byte_idx, access_width) & mask) << acc_bit_count
acc_bit_count += bit_count acc_bit_count += bit_count
bit_idx += bit_count bit_idx += bit_count
bit_remaining -= bit_count bit_remaining -= bit_count
@ -100,9 +100,9 @@ class BufferBase(Object):
assert offset + bitwidth <= self.__length * 8, \ assert offset + bitwidth <= self.__length * 8, \
f"Buffer overflow: attempt to access field {name} at bit {offset + bitwidth} while the buffer has only {len(self.__data) * 8} bits" f"Buffer overflow: attempt to access field {name} at bit {offset + bitwidth} while the buffer has only {len(self.__data) * 8} bits"
# Bits out of byte boundary # Bits out of access_width boundary
if bit_idx % access_width > 0: if bit_idx % access_width > 0:
norm_idx = floor(bit_idx / access_width) byte_idx = bit_idx // 8
bit_count = (access_width - bit_idx % access_width) bit_count = (access_width - bit_idx % access_width)
if bit_count > bit_remaining: if bit_count > bit_remaining:
bit_count = bit_remaining bit_count = bit_remaining
@ -110,20 +110,20 @@ class BufferBase(Object):
mask_of_write = self.bitmask(bit_idx % access_width + bit_count - 1, bit_idx % access_width) mask_of_write = self.bitmask(bit_idx % access_width + bit_count - 1, bit_idx % access_width)
mask_of_keep = ((1 << access_width) - 1) - mask_of_write mask_of_keep = ((1 << access_width) - 1) - mask_of_write
v = (value & ((1 << bit_count) - 1)) << (bit_idx % access_width) v = (value & ((1 << bit_count) - 1)) << (bit_idx % access_width)
self.write(norm_idx, (v & mask_of_write) | (self.read(norm_idx, access_width) & mask_of_keep), access_width) self.write(byte_idx, (v & mask_of_write) | (self.read(byte_idx, access_width) & mask_of_keep), access_width)
value >>= bit_count value >>= bit_count
bit_idx += bit_count bit_idx += bit_count
bit_remaining -= bit_count bit_remaining -= bit_count
while bit_remaining > 0: while bit_remaining > 0:
norm_idx = floor(bit_idx / access_width) byte_idx = bit_idx // 8
bit_count = access_width if bit_remaining >= access_width else bit_remaining bit_count = min(access_width, bit_remaining)
mask_of_write = self.bitmask(bit_count - 1, 0) mask_of_write = self.bitmask(bit_count - 1, 0)
mask_of_keep = ((1 << access_width) - 1) - mask_of_write mask_of_keep = ((1 << access_width) - 1) - mask_of_write
v = (value & ((1 << bit_count) - 1)) v = (value & ((1 << bit_count) - 1))
self.write(norm_idx, (v & mask_of_write) | (self.read(norm_idx, access_width) & mask_of_keep), access_width) self.write(byte_idx, (v & mask_of_write) | (self.read(byte_idx, access_width) & mask_of_keep), access_width)
value >>= bit_count value >>= bit_count
bit_idx += bit_count bit_idx += bit_count
@ -142,16 +142,14 @@ class Buffer(BufferBase):
def data(self): def data(self):
return bytes(self.__data) return bytes(self.__data)
def read(self, norm_idx, bit_width): def read(self, byte_idx, bit_width):
acc = 0 acc = 0
byte_width = bit_width // 8 byte_width = min(bit_width // 8, len(self.__data) - byte_idx)
offset = norm_idx * byte_width return int.from_bytes(self.__data[byte_idx : (byte_idx + byte_width)], sys.byteorder)
return int.from_bytes(self.__data[offset : (offset + byte_width)], sys.byteorder)
def write(self, norm_idx, value, bit_width): def write(self, byte_idx, value, bit_width):
byte_width = bit_width // 8 byte_width = min(bit_width // 8, len(self.__data) - byte_idx)
offset = norm_idx * byte_width self.__data[byte_idx : (byte_idx + byte_width)] = value.to_bytes(byte_width, sys.byteorder)
self.__data[offset : (offset + byte_width)] = value.to_bytes(byte_width, sys.byteorder)
def get(self): def get(self):
return self.__data return self.__data
@ -175,18 +173,16 @@ class StreamIOBuffer(BufferBase):
self.__stream = stream self.__stream = stream
self.__base = base self.__base = base
def read(self, norm_idx, bit_width): def read(self, byte_idx, bit_width):
byte_width = bit_width // 8 byte_width = bit_width // 8
address = norm_idx * byte_width self.__stream.seek(self.__base + byte_idx)
self.__stream.seek(self.__base + address)
data = self.__stream.read(byte_width) data = self.__stream.read(byte_width)
return int.from_bytes(data, sys.byteorder) return int.from_bytes(data, sys.byteorder)
def write(self, norm_idx, value, bit_width): def write(self, byte_idx, value, bit_width):
# Do not allow writes to stream I/O buffer unless the base is explicitly marked as writable # Do not allow writes to stream I/O buffer unless the base is explicitly marked as writable
byte_width = bit_width // 8 byte_width = bit_width // 8
address = norm_idx * byte_width self.__stream.seek(self.__base + byte_idx)
self.__stream.seek(self.__base + address)
self.__stream.write(value.to_bytes(byte_width, sys.byteorder)) self.__stream.write(value.to_bytes(byte_width, sys.byteorder))
class IndexedIOBuffer(BufferBase): class IndexedIOBuffer(BufferBase):
@ -196,12 +192,12 @@ class IndexedIOBuffer(BufferBase):
self.__index_register = index_register self.__index_register = index_register
self.__data_register = data_register self.__data_register = data_register
def read(self, norm_idx, bit_width): def read(self, byte_idx, bit_width):
assert bit_width == 8, f"Indexed I/O buffers can only be read one byte at a time" assert bit_width == 8, f"Indexed I/O buffers can only be read one byte at a time"
self.__index_register.set(Integer(norm_idx, 8)) self.__index_register.set(Integer(byte_idx, 8))
return self.__data_register.get() return self.__data_register.get()
def write(self, norm_idx, value, bit_width): def write(self, byte_idx, value, bit_width):
# Do not allow writes to indexed I/O buffer # Do not allow writes to indexed I/O buffer
assert False, "Cannot write to indexed I/O buffers" assert False, "Cannot write to indexed I/O buffers"
@ -274,7 +270,7 @@ class Integer(Object):
class Method(Object): class Method(Object):
def __init__(self, tree): def __init__(self, tree):
self.tree = tree self.tree = tree
self.name = tree.children[1].children self.name = tree.children[1].value
self.body = tree.children[3] self.body = tree.children[3]
class PredefinedMethod(Object): class PredefinedMethod(Object):

View File

@ -136,15 +136,15 @@ AML_DATA_REGION_OP = 0x885b
AMLCode = ("DefBlockHeader", "TermObj*") AMLCode = ("DefBlockHeader", "TermObj*")
DefBlockHeader = ("TableSignature", "TableLength", "SpecCompliance", "CheckSum", "OemID", "OemTableID", "OemRevision", "CreatorID", "CreatorRevision") DefBlockHeader = ("TableSignature", "TableLength", "SpecCompliance", "CheckSum", "OemID", "OemTableID", "OemRevision", "CreatorID", "CreatorRevision")
TableSignature = ("DWordData",) TableSignature = ["DWordData"]
TableLength = ("DWordData",) TableLength = ["DWordData"]
SpecCompliance = ("ByteData",) SpecCompliance = ["ByteData"]
CheckSum = ("ByteData",) CheckSum = ["ByteData"]
OemID = ("TWordData",) OemID = ["TWordData"]
OemTableID = ("QWordData",) OemTableID = ["QWordData"]
OemRevision = ("DWordData",) OemRevision = ["DWordData"]
CreatorID = ("DWordData",) CreatorID = ["DWordData"]
CreatorRevision = ("DWordData",) CreatorRevision = ["DWordData"]
################################################################################ ################################################################################
# 20.2.2 Name Objects Encoding # 20.2.2 Name Objects Encoding
@ -202,7 +202,7 @@ TermArg = ["ExpressionOpcode", "DataObject", "ArgObj", "LocalObj"]
NameSpaceModifierObj = ["DefAlias", "DefName", "DefScope"] NameSpaceModifierObj = ["DefAlias", "DefName", "DefScope"]
DefAlias = (AML_ALIAS_OP, "NameString", "NameString") DefAlias = (AML_ALIAS_OP, "NameString:SourceObject", "NameString:AliasObject")
DefName = (AML_NAME_OP, "NameString", "DataRefObject") DefName = (AML_NAME_OP, "NameString", "DataRefObject")
DefScope = (AML_SCOPE_OP, "PkgLength", "NameString", "TermList") DefScope = (AML_SCOPE_OP, "PkgLength", "NameString", "TermList")
@ -214,68 +214,68 @@ NamedObj = ["DefBankField", "DefCreateBitField", "DefCreateByteField", "DefCreat
"DefField", "DefIndexField", "DefMethod", "DefMutex", "DefOpRegion", "DefPowerRes", "DefProcessor", "DefField", "DefIndexField", "DefMethod", "DefMutex", "DefOpRegion", "DefPowerRes", "DefProcessor",
"DefThermalZone"] "DefThermalZone"]
DefBankField = (AML_BANK_FIELD_OP, "PkgLength", "NameString", "NameString", "BankValue", "FieldFlags", "FieldList") DefBankField = (AML_BANK_FIELD_OP, "PkgLength", "NameString:RegionName", "NameString:BankName", "BankValue", "FieldFlags", "FieldList")
BankValue = ("TermArg",) BankValue = ["TermArg"]
FieldFlags = ("ByteData",) FieldFlags = ["ByteData"]
FieldList = ("FieldElement*",) FieldList = ("FieldElement*",)
NamedField = ("NameSeg", "FieldLength") NamedField = ("NameSeg", "FieldLength")
ReservedField = (AML_RESERVED_FIELD_PREFIX, "FieldLength") ReservedField = (AML_RESERVED_FIELD_PREFIX, "FieldLength")
AccessField = (AML_ACCESS_FIELD_PREFIX, "AccessType", "AccessAttrib") AccessField = (AML_ACCESS_FIELD_PREFIX, "AccessType", "AccessAttrib")
AccessType = ("ByteData",) AccessType = ["ByteData"]
AccessAttrib = ("ByteData",) AccessAttrib = ["ByteData"]
ConnectFieldDef = ["NameString", "BufferData"] ConnectFieldDef = ["NameString"] # FIXME: ACPI spec allows "BufferData" here but does not define what "BufferData" is
ConnectField = (AML_CONNECT_FIELD_PREFIX, "ConnectFieldDef") ConnectField = (AML_CONNECT_FIELD_PREFIX, "ConnectFieldDef")
DefCreateBitField = (AML_CREATE_BIT_FIELD_OP, "SourceBuff", "BitIndex", "NameString") DefCreateBitField = (AML_CREATE_BIT_FIELD_OP, "SourceBuff", "BitIndex", "NameString")
SourceBuff = ("TermArg",) SourceBuff = ["TermArg"]
BitIndex = ("TermArg",) BitIndex = ["TermArg"]
DefCreateByteField = (AML_CREATE_BYTE_FIELD_OP, "SourceBuff", "ByteIndex", "NameString") DefCreateByteField = (AML_CREATE_BYTE_FIELD_OP, "SourceBuff", "ByteIndex", "NameString")
ByteIndex = ("TermArg",) ByteIndex = ["TermArg"]
DefCreateDWordField = (AML_CREATE_DWORD_FIELD_OP, "SourceBuff", "ByteIndex", "NameString") DefCreateDWordField = (AML_CREATE_DWORD_FIELD_OP, "SourceBuff", "ByteIndex", "NameString")
DefCreateField = (AML_CREATE_FIELD_OP, "SourceBuff", "BitIndex", "NumBits", "NameString") DefCreateField = (AML_CREATE_FIELD_OP, "SourceBuff", "BitIndex", "NumBits", "NameString")
NumBits = ("TermArg",) NumBits = ["TermArg"]
DefCreateQWordField = (AML_CREATE_QWORD_FIELD_OP, "SourceBuff", "ByteIndex", "NameString") DefCreateQWordField = (AML_CREATE_QWORD_FIELD_OP, "SourceBuff", "ByteIndex", "NameString")
DefCreateWordField = (AML_CREATE_WORD_FIELD_OP, "SourceBuff", "ByteIndex", "NameString") DefCreateWordField = (AML_CREATE_WORD_FIELD_OP, "SourceBuff", "ByteIndex", "NameString")
DefDataRegion = (AML_DATA_REGION_OP, "NameString", "TermArg", "TermArg", "TermArg") DefDataRegion = (AML_DATA_REGION_OP, "NameString", "TermArg:Signature", "TermArg:OEMID", "TermArg:OEMTableID")
DefDevice = (AML_DEVICE_OP, "PkgLength", "NameString", "TermList") DefDevice = (AML_DEVICE_OP, "PkgLength", "NameString", "TermList")
DefEvent = (AML_EVENT_OP, "NameString") DefEvent = (AML_EVENT_OP, "NameString")
DefExternal = (AML_EXTERNAL_OP, "NameString", "ObjectType", "ArgumentCount") DefExternal = (AML_EXTERNAL_OP, "NameString", "ObjectType", "ArgumentCount")
ObjectType = ("ByteData",) ObjectType = ["ByteData"]
ArgumentCount = ("ByteData",) ArgumentCount = ["ByteData"]
DefField = (AML_FIELD_OP, "PkgLength", "NameString", "FieldFlags", "FieldList") DefField = (AML_FIELD_OP, "PkgLength", "NameString", "FieldFlags", "FieldList")
DefIndexField = (AML_INDEX_FIELD_OP, "PkgLength", "NameString", "NameString", "FieldFlags", "FieldList") DefIndexField = (AML_INDEX_FIELD_OP, "PkgLength", "NameString:IndexName", "NameString:DataName", "FieldFlags", "FieldList")
DefMethod = (AML_METHOD_OP, "PkgLength", "NameString", "MethodFlags", "TermList") DefMethod = (AML_METHOD_OP, "PkgLength", "NameString", "MethodFlags", "TermList")
MethodFlags = ("ByteData",) MethodFlags = ["ByteData"]
DefMutex = (AML_MUTEX_OP, "NameString", "SyncFlags") DefMutex = (AML_MUTEX_OP, "NameString", "SyncFlags")
SyncFlags = ("ByteData",) SyncFlags = ["ByteData"]
DefOpRegion = (AML_REGION_OP, "NameString", "RegionSpace", "RegionOffset", "RegionLen") DefOpRegion = (AML_REGION_OP, "NameString", "RegionSpace", "RegionOffset", "RegionLen")
RegionSpace = ("ByteData",) RegionSpace = ["ByteData"]
RegionOffset = ("TermArg",) RegionOffset = ["TermArg"]
RegionLen = ("TermArg",) RegionLen = ["TermArg"]
DefPowerRes = (AML_POWER_RESOURCE_OP, "PkgLength", "NameString", "SystemLevel", "ResourceOrder", "TermList") DefPowerRes = (AML_POWER_RESOURCE_OP, "PkgLength", "NameString", "SystemLevel", "ResourceOrder", "TermList")
SystemLevel = ("ByteData",) SystemLevel = ["ByteData"]
ResourceOrder = ("WordData",) ResourceOrder = ["WordData"]
DefProcessor = (AML_PROCESSOR_OP, "PkgLength", "NameString", "ProcID", "PblkAddr", "PblkLen", "TermList") DefProcessor = (AML_PROCESSOR_OP, "PkgLength", "NameString", "ProcID", "PblkAddr", "PblkLen", "TermList")
ProcID = ("ByteData",) ProcID = ["ByteData"]
PblkAddr = ("DWordData",) PblkAddr = ["DWordData"]
PblkLen = ("ByteData",) PblkLen = ["ByteData"]
DefThermalZone = (AML_THERMAL_ZONE_OP, "PkgLength", "NameString", "TermList") DefThermalZone = (AML_THERMAL_ZONE_OP, "PkgLength", "NameString", "TermList")
ExtendedAccessField = (AML_EXTENDED_ACCESS_FIELD_PREFIX, "AccessType", "ExtendedAccessAttrib", "AccessLength") ExtendedAccessField = (AML_EXTENDED_ACCESS_FIELD_PREFIX, "AccessType", "ExtendedAccessAttrib", "AccessLength")
ExtendedAccessAttrib = ("ByteData",) ExtendedAccessAttrib = ["ByteData"]
AccessLength = ("ByteData",) AccessLength = ["ByteData"]
FieldElement = ["NamedField", "ReservedField", "AccessField", "ExtendedAccessField", "ConnectField"] FieldElement = ["NamedField", "ReservedField", "AccessField", "ExtendedAccessField", "ConnectField"]
# 20.2.5.3 Statement Opcodes Encoding # 20.2.5.3 Statement Opcodes Encoding
@ -293,35 +293,35 @@ DefContinue = (AML_CONTINUE_OP,)
DefElse = (AML_ELSE_OP, "PkgLength", "TermList") DefElse = (AML_ELSE_OP, "PkgLength", "TermList")
DefFatal = (AML_FATAL_OP, "FatalType", "FatalCode", "FataArg") DefFatal = (AML_FATAL_OP, "FatalType", "FatalCode", "FataArg")
FatalType = ("ByteData",) FatalType = ["ByteData"]
FatalCode = ("DWordData",) FatalCode = ["DWordData"]
FatalArg = ("TermArg",) FatalArg = ["TermArg"]
DefIfElse = (AML_IF_OP, "PkgLength", "Predicate", "TermList", "DefElse?") DefIfElse = (AML_IF_OP, "PkgLength", "Predicate", "TermList", "DefElse?")
Predicate = ("TermArg",) Predicate = ["TermArg"]
DefNoop = (AML_NOOP_OP,) DefNoop = (AML_NOOP_OP,)
DefNotify = (AML_NOTIFY_OP, "NotifyObject", "NotifyValue") DefNotify = (AML_NOTIFY_OP, "NotifyObject", "NotifyValue")
NotifyObject = ("SuperName",) NotifyObject = ["SuperName"]
NotifyValue = ("TermArg",) NotifyValue = ["TermArg"]
DefRelease = (AML_RELEASE_OP, "MutexObject") DefRelease = (AML_RELEASE_OP, "MutexObject")
MutexObject = ("SuperName",) MutexObject = ["SuperName"]
DefReset = (AML_RESET_OP, "EventObject") DefReset = (AML_RESET_OP, "EventObject")
EventObject = ("SuperName",) EventObject = ["SuperName"]
DefReturn = (AML_RETURN_OP, "ArgObject") DefReturn = (AML_RETURN_OP, "ArgObject")
ArgObject = ("TermArg",) ArgObject = ["TermArg"]
DefSignal = (AML_SIGNAL_OP, "EventObject") DefSignal = (AML_SIGNAL_OP, "EventObject")
DefSleep = (AML_SLEEP_OP, "MsecTime") DefSleep = (AML_SLEEP_OP, "MsecTime")
MsecTime = ("TermArg",) MsecTime = ["TermArg"]
DefStall = (AML_STALL_OP, "UsecTime") DefStall = (AML_STALL_OP, "UsecTime")
UsecTime = ("TermArg",) UsecTime = ["TermArg"]
DefUnload = (AML_UNLOAD_OP, "Target") DefUnload = (AML_UNLOAD_OP, "Target")
@ -342,21 +342,21 @@ ExpressionOpcode = ["DefAcquire", "DefAdd", "DefAnd", "DefBuffer", "DefConcat",
ReferenceTypeOpcode = ["DefRefOf", "DefDerefOf", "DefIndex"] ReferenceTypeOpcode = ["DefRefOf", "DefDerefOf", "DefIndex"]
DefAcquire = (AML_ACQUIRE_OP, "MutexObject", "Timeout") DefAcquire = (AML_ACQUIRE_OP, "MutexObject", "Timeout")
Timeout = ("WordData",) Timeout = ["WordData"]
DefAdd = (AML_ADD_OP, "Operand", "Operand", "Target") DefAdd = (AML_ADD_OP, "Operand:LeftOperand", "Operand:RightOperand", "Target")
Operand = ["TermArg"] Operand = ["TermArg"]
DefAnd = (AML_AND_OP, "Operand", "Operand", "Target") DefAnd = (AML_AND_OP, "Operand:LeftOperand", "Operand:RightOperand", "Target")
DefBuffer = (AML_BUFFER_OP, "PkgLength", "BufferSize", "ByteList") DefBuffer = (AML_BUFFER_OP, "PkgLength", "BufferSize", "ByteList")
BufferSize = ("TermArg",) BufferSize = ["TermArg"]
DefConcat = (AML_CONCAT_OP, "Data", "Data", "Target") DefConcat = (AML_CONCAT_OP, "Data:Data1", "Data:Data2", "Target")
Data = ("TermArg",) Data = ["TermArg"]
DefConcatRes = (AML_CONCAT_RES_OP, "BufData", "BufData", "Target") DefConcatRes = (AML_CONCAT_RES_OP, "BufData:BufData1", "BufData:BufData2", "Target")
BufData = ("TermArg",) BufData = ["TermArg"]
DefCondRefOf = (AML_CONDITIONAL_REF_OF_OP, "SuperName", "Target") DefCondRefOf = (AML_CONDITIONAL_REF_OF_OP, "SuperName", "Target")
@ -365,80 +365,80 @@ DefCopyObject = (AML_COPY_OBJECT_OP, "TermArg", "SimpleName")
DefDecrement = (AML_DECREMENT_OP, "SuperName") DefDecrement = (AML_DECREMENT_OP, "SuperName")
DefDerefOf = (AML_DEREF_OF_OP, "ObjReference") DefDerefOf = (AML_DEREF_OF_OP, "ObjReference")
ObjReference = ("TermArg",) ObjReference = ["TermArg"]
DefDivide = (AML_DIVIDE_OP, "Dividend", "Divisor", "Remainder", "Quotient") DefDivide = (AML_DIVIDE_OP, "Dividend", "Divisor", "Remainder", "Quotient")
Dividend = ("TermArg",) Dividend = ["TermArg"]
Divisor = ("TermArg",) Divisor = ["TermArg"]
Remainder = ("Target",) Remainder = ["Target"]
Quotient = ("Target",) Quotient = ["Target"]
DefFindSetLeftBit = (AML_FIND_SET_LEFT_BIT_OP, "Operand", "Target") DefFindSetLeftBit = (AML_FIND_SET_LEFT_BIT_OP, "Operand", "Target")
DefFindSetRightBit = (AML_FIND_SET_RIGHT_BIT_OP, "Operand", "Target") DefFindSetRightBit = (AML_FIND_SET_RIGHT_BIT_OP, "Operand", "Target")
DefFromBCD = (AML_FROM_BCD_OP, "BCDValue", "Target") DefFromBCD = (AML_FROM_BCD_OP, "BCDValue", "Target")
BCDValue = ("TermArg",) BCDValue = ["TermArg"]
DefIncrement = (AML_INCREMENT_OP, "SuperName") DefIncrement = (AML_INCREMENT_OP, "SuperName")
DefIndex = (AML_INDEX_OP, "BuffPkgStrObj", "IndexValue", "Target") DefIndex = (AML_INDEX_OP, "BuffPkgStrObj", "IndexValue", "Target")
BuffPkgStrObj = ("TermArg",) BuffPkgStrObj = ["TermArg"]
IndexValue = ("TermArg",) IndexValue = ["TermArg"]
DefLAnd = (AML_LAND_OP, "Operand", "Operand") DefLAnd = (AML_LAND_OP, "Operand:LeftOperand", "Operand:RightOperand")
DefLEqual = (AML_LEQUAL_OP, "Operand", "Operand") DefLEqual = (AML_LEQUAL_OP, "Operand:LeftOperand", "Operand:RightOperand")
DefLGreater = (AML_LGREATER_OP, "Operand", "Operand") DefLGreater = (AML_LGREATER_OP, "Operand:LeftOperand", "Operand:RightOperand")
# DefLGreaterEqual is equivalent to (AML_LNOT_OP, DefLLess) # DefLGreaterEqual is equivalent to (AML_LNOT_OP, DefLLess)
DefLLess = (AML_LLESS_OP, "Operand", "Operand") DefLLess = (AML_LLESS_OP, "Operand:LeftOperand", "Operand:RightOperand")
# DefLLessEqual is equivalent to (AML_LNOT_OP, DefLGreater) # DefLLessEqual is equivalent to (AML_LNOT_OP, DefLGreater)
DefLNot = (AML_LNOT_OP, "Operand") DefLNot = (AML_LNOT_OP, "Operand")
# DefLNotEqual is equivalent to (AML_LNOT_OP, DefLEqual) # DefLNotEqual is equivalent to (AML_LNOT_OP, DefLEqual)
DefLoad = (AML_LOAD_OP, "NameString", "Target") DefLoad = (AML_LOAD_OP, "NameString", "Target")
DefLoadTable = (AML_LOAD_TABLE_OP, "TermArg", "TermArg", "TermArg", "TermArg", "TermArg", "TermArg") DefLoadTable = (AML_LOAD_TABLE_OP, "TermArg:Signature", "TermArg:OEMID", "TermArg:TableID", "TermArg:RootPath", "TermArg:ParameterPath", "TermArg:ParameterData")
DefLOr = (AML_LOR_OP, "Operand", "Operand") DefLOr = (AML_LOR_OP, "Operand:LeftOperand", "Operand:RightOperand")
DefMatch = (AML_MATCH_OP, "SearchPkg", "MatchOpcode", "Operand", "MatchOpcode", "Operand", "StartIndex") DefMatch = (AML_MATCH_OP, "SearchPkg", "MatchOpcode:MatchOpcode1", "Operand:Operand1", "MatchOpcode:MatchOpcode2", "Operand:Operand2", "StartIndex")
SearchPkg = ("TermArg",) SearchPkg = ["TermArg"]
MatchOpcode = ("ByteData",) MatchOpcode = ["ByteData"]
StartIndex = ("TermArg",) StartIndex = ["TermArg"]
DefMid = (AML_MID_OP, "MidObj", "TermArg", "TermArg", "Target") DefMid = (AML_MID_OP, "MidObj", "TermArg:Source", "TermArg:Index", "Target")
MidObj = ("TermArg",) MidObj = ["TermArg"]
DefMod = (AML_MOD_OP, "Dividend", "Divisor", "Target") DefMod = (AML_MOD_OP, "Dividend", "Divisor", "Target")
DefMultiply = (AML_MULTIPLY_OP, "Operand", "Operand", "Target") DefMultiply = (AML_MULTIPLY_OP, "Operand:LeftOperand", "Operand:RightOperand", "Target")
DefNAnd = (AML_NAND_OP, "Operand", "Operand", "Target") DefNAnd = (AML_NAND_OP, "Operand:LeftOperand", "Operand:RightOperand", "Target")
DefNOr = (AML_NOR_OP, "Operand", "Operand", "Target") DefNOr = (AML_NOR_OP, "Operand:LeftOperand", "Operand:RightOperand", "Target")
DefNot = (AML_NOT_OP, "Operand", "Target") DefNot = (AML_NOT_OP, "Operand", "Target")
DefObjectType = (AML_OBJECT_TYPE_OP, "ObjectTypeContent") DefObjectType = (AML_OBJECT_TYPE_OP, "ObjectTypeContent")
ObjectTypeContent = ["SimpleName", "DebugObj", "DefRefof", "DefDerefof", "DefIndex"] ObjectTypeContent = ["SimpleName", "DebugObj", "DefRefof", "DefDerefof", "DefIndex"]
DefOr = (AML_OR_OP, "Operand", "Operand", "Target") DefOr = (AML_OR_OP, "Operand:LeftOperand", "Operand:RightOperand", "Target")
DefPackage = (AML_PACKAGE_OP, "PkgLength", "NumElements", "PackageElementList") DefPackage = (AML_PACKAGE_OP, "PkgLength", "NumElements", "PackageElementList")
DefVarPackage = (AML_VAR_PACKAGE_OP, "PkgLength", "VarNumElements", "PackageElementList") DefVarPackage = (AML_VAR_PACKAGE_OP, "PkgLength", "VarNumElements", "PackageElementList")
NumElements = ("ByteData",) NumElements = ["ByteData"]
VarNumElements = ("TermArg",) VarNumElements = ["TermArg"]
PackageElementList = ("PackageElement*",) PackageElementList = ("PackageElement*",)
PackageElement = ["DataRefObject", "NameString"] PackageElement = ["DataRefObject", "NameString"]
DefRefOf = (AML_REF_OF_OP, "SuperName") DefRefOf = (AML_REF_OF_OP, "SuperName")
DefShiftLeft = (AML_SHIFT_LEFT_OP, "Operand", "ShiftCount", "Target") DefShiftLeft = (AML_SHIFT_LEFT_OP, "Operand", "ShiftCount", "Target")
ShiftCount = ("TermArg",) ShiftCount = ["TermArg"]
DefShiftRight = (AML_SHIFT_RIGHT_OP, "Operand", "ShiftCount", "Target") DefShiftRight = (AML_SHIFT_RIGHT_OP, "Operand", "ShiftCount", "Target")
DefSizeOf = (AML_SIZE_OF_OP, "SuperName") DefSizeOf = (AML_SIZE_OF_OP, "SuperName")
DefStore = (AML_STORE_OP, "TermArg", "SuperName") DefStore = (AML_STORE_OP, "TermArg", "SuperName")
DefSubtract = (AML_SUBTRACT_OP, "Operand", "Operand", "Target") DefSubtract = (AML_SUBTRACT_OP, "Operand:LeftOperand", "Operand:RightOperand", "Target")
DefTimer = (AML_TIMER_OP,) DefTimer = (AML_TIMER_OP,)
@ -453,11 +453,11 @@ DefToHexString = (AML_TO_HEX_STRING_OP, "Operand", "Target")
DefToInteger = (AML_TO_INTEGER_OP, "Operand", "Target") DefToInteger = (AML_TO_INTEGER_OP, "Operand", "Target")
DefToString = (AML_TO_STRING_OP, "TermArg", "LengthArg", "Target") DefToString = (AML_TO_STRING_OP, "TermArg", "LengthArg", "Target")
LengthArg = ("TermArg",) LengthArg = ["TermArg"]
DefWait = (AML_WAIT_OP, "EventObject", "Operand") DefWait = (AML_WAIT_OP, "EventObject", "Operand")
DefXOr = (AML_XOR_OP, "Operand", "Operand", "Target") DefXOr = (AML_XOR_OP, "Operand:LeftOperand", "Operand:RightOperand", "Target")
################################################################################ ################################################################################
# 20.2.6 Miscellaneous Objects Encoding # 20.2.6 Miscellaneous Objects Encoding
@ -492,3 +492,24 @@ Local7Op = (AML_LOCAL7_OP,)
################################################################################ ################################################################################
DebugObj = (AML_DEBUG_OP,) DebugObj = (AML_DEBUG_OP,)
################################################################################
# Helper methods
################################################################################
def __get_spec(sym, fn):
spec = globals()[sym]
if isinstance(spec, tuple):
return tuple(map(fn, spec))
else:
return spec
def get_definition(sym):
def __get_definition(elem):
return elem.split(":")[0] if isinstance(elem, str) else elem
return __get_spec(sym, __get_definition)
def get_names(sym):
def __get_names(elem):
return elem.split(":")[-1] if isinstance(elem, str) else elem
return __get_spec(sym, __get_names)

View File

@ -86,9 +86,13 @@ class ConcreteInterpreter(Interpreter):
def interpret_method_call(self, name, *args): def interpret_method_call(self, name, *args):
stack_depth_before = len(self.stack) stack_depth_before = len(self.stack)
name_string = Tree("NameString", name) name_string = Tree("NameString", [name])
name_string.register_structure(("value",))
name_string.complete_parsing()
name_string.scope = self.context.parent(name) name_string.scope = self.context.parent(name)
pseudo_invocation = Tree("MethodInvocation", [name_string]) pseudo_invocation = Tree("MethodInvocation", [name_string])
pseudo_invocation.register_structure(("NameString", "TermArg*"))
pseudo_invocation.complete_parsing()
try: try:
val = self.interpret(pseudo_invocation) val = self.interpret(pseudo_invocation)
except: except:
@ -118,7 +122,7 @@ class ConcreteInterpreter(Interpreter):
return None return None
def NameString(self, tree): def NameString(self, tree):
name = tree.children name = tree.value
obj = self.context.lookup_binding(name) obj = self.context.lookup_binding(name)
if not obj: if not obj:
sym = self.context.lookup_symbol(name) sym = self.context.lookup_symbol(name)
@ -133,7 +137,7 @@ class ConcreteInterpreter(Interpreter):
# 20.2.3 Data Objects Encoding # 20.2.3 Data Objects Encoding
def ByteList(self, tree): def ByteList(self, tree):
return RawDataBuffer(tree.children) return RawDataBuffer(tree.value)
def ByteConst(self, tree): def ByteConst(self, tree):
return self.interpret(tree.children[0]) return self.interpret(tree.children[0])
@ -148,19 +152,19 @@ class ConcreteInterpreter(Interpreter):
return self.interpret(tree.children[0]) return self.interpret(tree.children[0])
def String(self, tree): def String(self, tree):
return String(tree.children) return String(tree.value)
def ByteData(self, tree): def ByteData(self, tree):
return Integer(tree.children) return Integer(tree.value)
def WordData(self, tree): def WordData(self, tree):
return Integer(tree.children) return Integer(tree.value)
def DWordData(self, tree): def DWordData(self, tree):
return Integer(tree.children) return Integer(tree.value)
def QWordData(self, tree): def QWordData(self, tree):
return Integer(tree.children) return Integer(tree.value)
def ZeroOp(self, tree): def ZeroOp(self, tree):
return Integer(0x00) return Integer(0x00)
@ -210,7 +214,7 @@ class ConcreteInterpreter(Interpreter):
return Integer(value.fn(args)) return Integer(value.fn(args))
else: else:
assert value == None or isinstance(value, Object), \ assert value == None or isinstance(value, Object), \
f"{tree.children[0].children} evaluates to a non-object value {value}" f"{tree.children[0]} evaluates to a non-object value {value}"
return value return value
# 20.2.5.1 Namespace Modifier Objects Encoding # 20.2.5.1 Namespace Modifier Objects Encoding
@ -219,7 +223,7 @@ class ConcreteInterpreter(Interpreter):
def DefName(self, tree): def DefName(self, tree):
self.context.change_scope(tree.children[0].scope) self.context.change_scope(tree.children[0].scope)
name = tree.children[0].children name = tree.children[0].value
obj = self.context.lookup_binding(name) obj = self.context.lookup_binding(name)
if not obj: if not obj:
obj = self.interpret(tree.children[1]) obj = self.interpret(tree.children[1])
@ -229,7 +233,7 @@ class ConcreteInterpreter(Interpreter):
# 20.2.5.2 Named Objects Encoding # 20.2.5.2 Named Objects Encoding
def NamedField(self, tree): def NamedField(self, tree):
name = tree.children[0].children name = tree.children[0].value
sym = self.context.lookup_symbol(self.context.realpath(tree.scope, name)) sym = self.context.lookup_symbol(self.context.realpath(tree.scope, name))
assert isinstance(sym, OperationFieldDecl) assert isinstance(sym, OperationFieldDecl)
assert sym.region, f"Field {sym.name} does not belong to any operation region." assert sym.region, f"Field {sym.name} does not belong to any operation region."
@ -253,7 +257,7 @@ class ConcreteInterpreter(Interpreter):
buf = self.interpret(tree.children[0]) buf = self.interpret(tree.children[0])
assert isinstance(buf, Buffer) assert isinstance(buf, Buffer)
index = self.interpret(tree.children[1]).get() index = self.interpret(tree.children[1]).get()
name = tree.children[name_idx].children name = tree.children[name_idx].value
if bitwidth == 1 or name_idx == 3: if bitwidth == 1 or name_idx == 3:
buf.create_field(name, index, bitwidth, 8) buf.create_field(name, index, bitwidth, 8)
else: else:
@ -283,13 +287,13 @@ class ConcreteInterpreter(Interpreter):
return self.create_field(tree, numbits, 3) return self.create_field(tree, numbits, 3)
def DefDevice(self, tree): def DefDevice(self, tree):
name = tree.children[1].children name = tree.children[1].value
fullpath = self.context.realpath(tree.scope, name) fullpath = self.context.realpath(tree.scope, name)
sym = self.context.lookup_symbol(fullpath) sym = self.context.lookup_symbol(fullpath)
return Device(sym) return Device(sym)
def DefExternal(self, tree): def DefExternal(self, tree):
logging.info(f"The loaded tables do not have a definition of {tree.children[0].children}") logging.info(f"The loaded tables do not have a definition of {tree.children[0].value}")
return None return None
def DefField(self, tree): def DefField(self, tree):
@ -300,7 +304,7 @@ class ConcreteInterpreter(Interpreter):
return Method(tree) return Method(tree)
def DefOpRegion(self, tree): def DefOpRegion(self, tree):
name = tree.children[0].children name = tree.children[0].value
sym = self.context.lookup_symbol(self.context.realpath(tree.scope, name)) sym = self.context.lookup_symbol(self.context.realpath(tree.scope, name))
space = self.interpret(tree.children[1]).get() space = self.interpret(tree.children[1]).get()

View File

@ -56,7 +56,8 @@ class Factory:
self.mark_end() self.mark_end()
return tree return tree
def opcodes(self): @property
def decoder(self):
raise NotImplementedError raise NotImplementedError
################################################################################ ################################################################################
@ -66,17 +67,20 @@ class Factory:
class NameSegFactory(Factory): class NameSegFactory(Factory):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.__opcodes = [] self.__decoder = {}
for i in range(ord('A'), ord('Z') + 1): for i in range(ord('A'), ord('Z') + 1):
self.__opcodes.append(i) self.__decoder[i] = self
self.__opcodes.append(ord('_')) self.__decoder[ord('_')] = self
self.label = "NameSeg" self.label = "NameSeg"
def match(self, context, stream, tree): def match(self, context, stream, tree):
tree.children = stream.get_fixed_length_string(4) tree.register_structure(("value",))
tree.append_child(stream.get_fixed_length_string(4))
tree.complete_parsing()
def opcodes(self): @property
return self.__opcodes def decoder(self):
return self.__decoder
NameSeg = NameSegFactory() NameSeg = NameSegFactory()
@ -84,12 +88,14 @@ class NameStringFactory(Factory):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.label = "NameString" self.label = "NameString"
self.__opcodes = [] self.__decoder = {}
for i in range(ord('A'), ord('Z') + 1): for i in range(ord('A'), ord('Z') + 1):
self.__opcodes.append(i) self.__decoder[i] = self
self.__opcodes.extend([ord('_'), ord('\\'), ord('^'), grammar.AML_DUAL_NAME_PREFIX, grammar.AML_MULTI_NAME_PREFIX]) for i in [ord('_'), ord('\\'), ord('^'), grammar.AML_DUAL_NAME_PREFIX, grammar.AML_MULTI_NAME_PREFIX]:
self.__decoder[i] = self
def match(self, context, stream, tree): def match(self, context, stream, tree):
tree.register_structure(("value",))
acc = "" acc = ""
# Namespace prefixes # Namespace prefixes
@ -117,10 +123,12 @@ class NameStringFactory(Factory):
stream.seek(-1) stream.seek(-1)
acc += stream.get_fixed_length_string(4) acc += stream.get_fixed_length_string(4)
tree.children = acc tree.append_child(acc)
tree.complete_parsing()
def opcodes(self): @property
return self.__opcodes def decoder(self):
return self.__decoder
NameString = NameStringFactory() NameString = NameStringFactory()
@ -135,12 +143,11 @@ class ConstDataFactory(Factory):
self.width = width self.width = width
def match(self, context, stream, tree): def match(self, context, stream, tree):
tree.children = stream.get_integer(self.width) tree.register_structure(("value",))
tree.append_child(stream.get_integer(self.width))
tree.complete_parsing()
return tree return tree
def opcodes(self):
return None
ByteData = ConstDataFactory("ByteData", 1) ByteData = ConstDataFactory("ByteData", 1)
WordData = ConstDataFactory("WordData", 2) WordData = ConstDataFactory("WordData", 2)
DWordData = ConstDataFactory("DWordData", 4) DWordData = ConstDataFactory("DWordData", 4)
@ -155,11 +162,14 @@ class StringFactory(Factory):
def match(self, context, stream, tree): def match(self, context, stream, tree):
assert stream.get_opcode()[0] == grammar.AML_STRING_PREFIX assert stream.get_opcode()[0] == grammar.AML_STRING_PREFIX
tree.children = stream.get_string() tree.register_structure(("value",))
tree.append_child(stream.get_string())
tree.complete_parsing()
return tree return tree
def opcodes(self): @property
return [grammar.AML_STRING_PREFIX] def decoder(self):
return {grammar.AML_STRING_PREFIX: self}
String = StringFactory() String = StringFactory()
@ -169,7 +179,9 @@ class ByteListFactory(Factory):
self.label = "ByteList" self.label = "ByteList"
def match(self, context, stream, tree): def match(self, context, stream, tree):
tree.children = stream.get_buffer() tree.register_structure(("value",))
tree.append_child(stream.get_buffer())
tree.complete_parsing()
stream.pop_scope() stream.pop_scope()
ByteList = ByteListFactory() ByteList = ByteListFactory()
@ -200,10 +212,12 @@ class PkgLengthFactory(Factory):
byte_count = pkg_lead_byte >> 6 byte_count = pkg_lead_byte >> 6
assert byte_count <= 3 assert byte_count <= 3
tree.children = self.get_package_length(byte_count, stream.get_integer(byte_count + 1)) tree.register_structure(("value",))
tree.append_child(self.get_package_length(byte_count, stream.get_integer(byte_count + 1)))
tree.complete_parsing()
if self.create_new_scope: if self.create_new_scope:
remaining = tree.children - byte_count - 1 remaining = tree.value - byte_count - 1
stream.push_scope(remaining) stream.push_scope(remaining)
tree.package_range = (stream.current, remaining) tree.package_range = (stream.current, remaining)
return tree return tree
@ -218,27 +232,33 @@ FieldLength = PkgLengthFactory("FieldLength", False)
class MethodInvocationFactory(Factory): class MethodInvocationFactory(Factory):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self.__opcodes = None self.__decoder = None
self.label = "MethodInvocation" self.label = "MethodInvocation"
def match(self, context, stream, tree): def match(self, context, stream, tree):
tree.register_structure(("NameString", "TermArg*"))
child_namestring = Tree() child_namestring = Tree()
globals()["NameString"].parse(context, child_namestring) globals()["NameString"].parse(context, child_namestring)
tree.append_child(child_namestring) tree.append_child(child_namestring)
sym = context.lookup_symbol(child_namestring.children) sym = context.lookup_symbol(child_namestring.value)
if isinstance(sym, (MethodDecl, PredefinedMethodDecl)): if isinstance(sym, (MethodDecl, PredefinedMethodDecl)):
for i in range(0, sym.nargs): for i in range(0, sym.nargs):
child_arg = Tree() child_arg = Tree()
globals()["TermArg"].parse(context, child_arg) globals()["TermArg"].parse(context, child_arg)
tree.append_child(child_arg) tree.append_child(child_arg)
tree.complete_parsing()
return tree return tree
def opcodes(self): @property
if not self.__opcodes: def decoder(self):
self.__opcodes = globals()["NameString"].opcodes() if not self.__decoder:
return self.__opcodes self.__decoder = {}
for k in globals()["NameString"].decoder.keys():
self.__decoder[k] = self
return self.__decoder
MethodInvocation = MethodInvocationFactory() MethodInvocation = MethodInvocationFactory()
@ -250,15 +270,31 @@ class SequenceFactory(Factory):
def __init__(self, label, seq): def __init__(self, label, seq):
super().__init__() super().__init__()
self.label = label self.label = label
# Some objects in ACPI AML have multiple occurrences of the same type of object in the grammar. In order to
# refer to these different occurrences, the grammar module uses the following notation to give names to each of
# them:
#
# "<object type>:<alias name>"
#
# The grammar module provides the get_definition() and get_names() methods to get the specification solely in
# object types or alias names, respectively. For objects without aliases, the type is reused as the name.
try:
self.seq = grammar.get_definition(label)
self.structure = grammar.get_names(label)
except KeyError:
self.seq = seq self.seq = seq
self.__opcodes = None self.structure = seq
self.__decoder = None
def match(self, context, stream, tree): def match(self, context, stream, tree):
tree.register_structure(self.structure)
# When a TermList is empty, the stream has already come to the end of the current scope here. Do not attempt to # When a TermList is empty, the stream has already come to the end of the current scope here. Do not attempt to
# peek the next opcode in such cases. # peek the next opcode in such cases.
if stream.at_end() and \ if stream.at_end() and \
(self.seq[0][-1] in ["*", "?"]): (self.seq[0][-1] in ["*", "?"]):
stream.pop_scope() stream.pop_scope()
tree.complete_parsing()
return tree return tree
opcode, opcode_width = stream.peek_opcode() opcode, opcode_width = stream.peek_opcode()
@ -268,6 +304,7 @@ class SequenceFactory(Factory):
# cleanup actions upon exceptions. # cleanup actions upon exceptions.
to_recover_from_deferred_mode = False to_recover_from_deferred_mode = False
to_pop_stream_scope = False to_pop_stream_scope = False
completed = True
for i,elem in enumerate(self.seq): for i,elem in enumerate(self.seq):
pos = stream.current pos = stream.current
@ -288,7 +325,7 @@ class SequenceFactory(Factory):
factory = globals()[elem] factory = globals()[elem]
if not stream.at_end(): if not stream.at_end():
sub_opcode, _ = stream.peek_opcode() sub_opcode, _ = stream.peek_opcode()
if sub_opcode in factory.opcodes(): if sub_opcode in factory.decoder.keys():
child = Tree() child = Tree()
factory.parse(context, child) factory.parse(context, child)
tree.append_child(child) tree.append_child(child)
@ -312,7 +349,7 @@ class SequenceFactory(Factory):
context.enter_deferred_mode() context.enter_deferred_mode()
to_recover_from_deferred_mode = True to_recover_from_deferred_mode = True
elif child.label == "NameString": elif child.label == "NameString":
self.hook_named(context, tree, child.children) self.hook_named(context, tree, child.value)
except (DecodeError, DeferLater, ScopeMismatch, UndefinedSymbol) as e: except (DecodeError, DeferLater, ScopeMismatch, UndefinedSymbol) as e:
if to_pop_stream_scope: if to_pop_stream_scope:
stream.pop_scope(force=True) stream.pop_scope(force=True)
@ -321,49 +358,54 @@ class SequenceFactory(Factory):
tree.context_scope = context.get_scope() tree.context_scope = context.get_scope()
tree.factory = SequenceFactory(f"{self.label}.deferred", self.seq[i:]) tree.factory = SequenceFactory(f"{self.label}.deferred", self.seq[i:])
stream.seek(package_end, absolute=True) stream.seek(package_end, absolute=True)
completed = False
break break
else: else:
raise e raise e
if completed:
tree.complete_parsing()
if to_recover_from_deferred_mode: if to_recover_from_deferred_mode:
context.exit_deferred_mode() context.exit_deferred_mode()
return tree return tree
def opcodes(self): @property
if not self.__opcodes: def decoder(self):
if not self.__decoder:
if isinstance(self.seq[0], int): if isinstance(self.seq[0], int):
self.__opcodes = [self.seq[0]] self.__decoder = {self.seq[0]: self}
else: else:
self.__opcodes = globals()[self.seq[0]].opcodes() self.__decoder = {}
return self.__opcodes for k in globals()[self.seq[0]].decoder.keys():
self.__decoder[k] = self
return self.__decoder
class OptionFactory(Factory): class OptionFactory(Factory):
def __init__(self, label, opts): def __init__(self, label, opts):
super().__init__() super().__init__()
self.label = label self.label = label
self.opts = opts self.opts = opts
self.__opcodes = None self.__decoder = None
def match(self, context, stream, tree): def match(self, context, stream, tree):
opcode, _ = stream.peek_opcode() opcode, _ = stream.peek_opcode()
try:
for opt in self.opts: if len(self.opts) == 1:
factory = globals()[opt] globals()[self.opts[0]].parse(context, tree)
matched_opcodes = factory.opcodes() else:
if matched_opcodes is None or opcode in matched_opcodes: self.decoder[opcode].parse(context, tree)
child = Tree()
tree.append_child(child)
factory.parse(context, child)
return tree return tree
except KeyError:
raise DecodeError(opcode, self.label) raise DecodeError(opcode, self.label)
def opcodes(self): @property
if not self.__opcodes: def decoder(self):
self.__opcodes = [] if not self.__decoder:
self.__decoder = {}
for opt in self.opts: for opt in self.opts:
self.__opcodes.extend(globals()[opt].opcodes()) self.__decoder.update(globals()[opt].decoder)
return self.__opcodes return self.__decoder
class DeferredExpansion(Transformer): class DeferredExpansion(Transformer):
def __init__(self, context): def __init__(self, context):
@ -390,6 +432,7 @@ class DeferredExpansion(Transformer):
tree.children.extend(aux_tree.children) tree.children.extend(aux_tree.children)
tree.deferred_range = None tree.deferred_range = None
tree.factory = None tree.factory = None
tree.complete_parsing()
except (DecodeError, DeferLater, ScopeMismatch, UndefinedSymbol) as e: except (DecodeError, DeferLater, ScopeMismatch, UndefinedSymbol) as e:
logging.debug(f"expansion of {tree.label} at {hex(tree.deferred_range[0])} failed due to: " + str(e)) logging.debug(f"expansion of {tree.label} at {hex(tree.deferred_range[0])} failed due to: " + str(e))
@ -402,9 +445,9 @@ class DeferredExpansion(Transformer):
################################################################################ ################################################################################
def DefAlias_hook_post(context, tree): def DefAlias_hook_post(context, tree):
target = tree.children[0].children source = tree.SourceObject.value
name = tree.children[1].children alias = tree.AliasObject.value
sym = AliasDecl(name, target, tree) sym = AliasDecl(alias, source, tree)
context.register_symbol(sym) context.register_symbol(sym)
def DefName_hook_named(context, tree, name): def DefName_hook_named(context, tree, name):
@ -419,32 +462,32 @@ def DefScope_hook_post(context, tree):
def DefCreateBitField_hook_named(context, tree, name): def DefCreateBitField_hook_named(context, tree, name):
name = tree.children[2].children name = tree.children[2].value
sym = FieldDecl(name, 1, tree) sym = FieldDecl(name, 1, tree)
context.register_symbol(sym) context.register_symbol(sym)
def DefCreateByteField_hook_named(context, tree, name): def DefCreateByteField_hook_named(context, tree, name):
name = tree.children[2].children name = tree.children[2].value
sym = FieldDecl(name, 8, tree) sym = FieldDecl(name, 8, tree)
context.register_symbol(sym) context.register_symbol(sym)
def DefCreateDWordField_hook_named(context, tree, name): def DefCreateDWordField_hook_named(context, tree, name):
name = tree.children[2].children name = tree.children[2].value
sym = FieldDecl(name, 32, tree) sym = FieldDecl(name, 32, tree)
context.register_symbol(sym) context.register_symbol(sym)
def DefCreateField_hook_named(context, tree, name): def DefCreateField_hook_named(context, tree, name):
name = tree.children[3].children name = tree.children[3].value
sym = FieldDecl(name, 0, tree) sym = FieldDecl(name, 0, tree)
context.register_symbol(sym) context.register_symbol(sym)
def DefCreateQWordField_hook_named(context, tree, name): def DefCreateQWordField_hook_named(context, tree, name):
name = tree.children[2].children name = tree.children[2].value
sym = FieldDecl(name, 64, tree) sym = FieldDecl(name, 64, tree)
context.register_symbol(sym) context.register_symbol(sym)
def DefCreateWordField_hook_named(context, tree, name): def DefCreateWordField_hook_named(context, tree, name):
name = tree.children[2].children name = tree.children[2].value
sym = FieldDecl(name, 16, tree) sym = FieldDecl(name, 16, tree)
context.register_symbol(sym) context.register_symbol(sym)
@ -457,9 +500,9 @@ def DefDevice_hook_post(context, tree):
context.pop_scope() context.pop_scope()
def DefExternal_hook_post(context, tree): def DefExternal_hook_post(context, tree):
name = tree.children[0].children name = tree.NameString.value
ty = tree.children[1].children[0].children ty = tree.ObjectType.value
nargs = tree.children[2].children[0].children nargs = tree.ArgumentCount.value
if ty == 0x8: # an external method if ty == 0x8: # an external method
sym = MethodDecl(name, nargs, tree) sym = MethodDecl(name, nargs, tree)
@ -479,52 +522,50 @@ access_width_map = {
def DefField_hook_post(context, tree): def DefField_hook_post(context, tree):
# Update the fields with region & offset info # Update the fields with region & offset info
region_name = context.lookup_symbol(tree.children[1].children).name region_name = context.lookup_symbol(tree.NameString.value).name
flags = tree.children[2].children[0].children flags = tree.FieldFlags.value
access_width = access_width_map[flags & 0xF] access_width = access_width_map[flags & 0xF]
fields = tree.children[3].children fields = tree.FieldList.FieldElements
bit_offset = 0 bit_offset = 0
for field in fields: for field in fields:
field = field.children[0]
if field.label == "NamedField": if field.label == "NamedField":
name = field.children[0].children name = field.NameSeg.value
length = field.children[1].children length = field.FieldLength.value
sym = context.lookup_symbol(name) sym = context.lookup_symbol(name)
assert isinstance(sym, OperationFieldDecl) assert isinstance(sym, OperationFieldDecl)
sym.set_location(region_name, bit_offset, access_width) sym.set_location(region_name, bit_offset, access_width)
bit_offset += length bit_offset += length
elif field.label == "ReservedField": elif field.label == "ReservedField":
length = field.children[0].children length = field.FieldLength.value
bit_offset += length bit_offset += length
else: else:
break break
def DefIndexField_hook_post(context, tree): def DefIndexField_hook_post(context, tree):
# Update the fields with region & offset info # Update the fields with region & offset info
index_register = context.lookup_symbol(tree.children[1].children) index_register = context.lookup_symbol(tree.IndexName.value)
data_register = context.lookup_symbol(tree.children[2].children) data_register = context.lookup_symbol(tree.DataName.value)
flags = tree.children[3].children[0].children flags = tree.FieldFlags.value
access_width = access_width_map[flags & 0xF] access_width = access_width_map[flags & 0xF]
fields = tree.children[4].children fields = tree.FieldList.FieldElements
bit_offset = 0 bit_offset = 0
for field in fields: for field in fields:
field = field.children[0]
if field.label == "NamedField": if field.label == "NamedField":
name = field.children[0].children name = field.NameSeg.value
length = field.children[1].children length = field.FieldLength.value
sym = context.lookup_symbol(name) sym = context.lookup_symbol(name)
assert isinstance(sym, OperationFieldDecl) assert isinstance(sym, OperationFieldDecl)
sym.set_indexed_location(index_register, data_register, bit_offset, access_width) sym.set_indexed_location(index_register, data_register, bit_offset, access_width)
bit_offset += length bit_offset += length
elif field.label == "ReservedField": elif field.label == "ReservedField":
length = field.children[0].children length = field.FieldLength.value
bit_offset += length bit_offset += length
else: else:
break break
def NamedField_hook_post(context, tree): def NamedField_hook_post(context, tree):
name = tree.children[0].children name = tree.NameSeg.value
length = tree.children[1].children length = tree.FieldLength.value
sym = OperationFieldDecl(name, length, tree) sym = OperationFieldDecl(name, length, tree)
context.register_symbol(sym) context.register_symbol(sym)
@ -534,8 +575,9 @@ def DefMethod_hook_named(context, tree, name):
def DefMethod_hook_post(context, tree): def DefMethod_hook_post(context, tree):
context.pop_scope() context.pop_scope()
if len(tree.children) >= 3: if len(tree.children) >= 3:
name = tree.children[1].children # Parsing of the method may be deferred. Do not use named fields to access its children.
flags = tree.children[2].children[0].children name = tree.children[1].value
flags = tree.children[2].value
nargs = flags & 0x7 nargs = flags & 0x7
sym = MethodDecl(name, nargs, tree) sym = MethodDecl(name, nargs, tree)
context.register_symbol(sym) context.register_symbol(sym)

View File

@ -13,6 +13,8 @@ class Tree:
self.children = copy(children) self.children = copy(children)
self.scope = None self.scope = None
self.structure = None
self.package_range = None self.package_range = None
self.deferred_range = None self.deferred_range = None
@ -22,6 +24,26 @@ class Tree:
def append_child(self, child): def append_child(self, child):
self.children.append(child) self.children.append(child)
def register_structure(self, structure):
self.structure = structure
def complete_parsing(self):
i = 0
for elem in self.structure:
if isinstance(elem, str):
if elem.endswith("?"):
if i < len(self.children):
setattr(self, elem[:-1], self.children[i])
else:
setattr(self, elem[:-1], None)
break
elif elem.endswith("*"):
setattr(self, elem[:-1] + "s", self.children[i:])
break
else:
setattr(self, elem, self.children[i])
i += 1
class Visitor: class Visitor:
def __init__(self): def __init__(self):
self.depth = 0 self.depth = 0
@ -35,7 +57,6 @@ class Visitor:
def visit_topdown(self, tree): def visit_topdown(self, tree):
self.__visit(tree) self.__visit(tree)
if isinstance(tree.children, list):
self.depth += 1 self.depth += 1
for child in tree.children: for child in tree.children:
if isinstance(child, Tree): if isinstance(child, Tree):
@ -57,7 +78,6 @@ class Transformer:
def transform_topdown(self, tree): def transform_topdown(self, tree):
new_tree = self.__transform(tree) new_tree = self.__transform(tree)
if isinstance(new_tree.children, list):
self.depth += 1 self.depth += 1
for i, child in enumerate(tree.children): for i, child in enumerate(tree.children):
if isinstance(child, Tree): if isinstance(child, Tree):
@ -66,7 +86,6 @@ class Transformer:
return new_tree return new_tree
def transform_bottomup(self, tree): def transform_bottomup(self, tree):
if isinstance(tree.children, list):
self.depth += 1 self.depth += 1
for i, child in enumerate(tree.children): for i, child in enumerate(tree.children):
if isinstance(child, Tree): if isinstance(child, Tree):
@ -74,28 +93,6 @@ class Transformer:
self.depth -= 1 self.depth -= 1
return self.__transform(tree) return self.__transform(tree)
single_operand_op = ["MethodInvocation"]
for sym in dir(grammar):
# Ignore builtin members and opcode constants
if sym.startswith("__") or (sym.upper() == sym):
continue
definition = getattr(grammar, sym)
if isinstance(definition, tuple) and\
isinstance(definition[0], int) and\
len(definition) == 2:
single_operand_op.append(sym)
class FlattenTransformer(Transformer):
def default(self, tree):
if tree.label not in single_operand_op and \
isinstance(tree.children, list) and \
len(tree.children) == 1 and \
not tree.deferred_range:
return tree.children[0]
else:
return tree
class Interpreter: class Interpreter:
def __init__(self, context): def __init__(self, context):
self.context = context self.context = context

View File

@ -13,11 +13,12 @@ class PrintLayoutVisitor(Visitor):
def default(self, tree): def default(self, tree):
indent = " " * self.depth indent = " " * self.depth
print(f"{indent}{tree.label}", end="") print(f"{indent}{tree.label}", end="")
if isinstance(tree.children, int): if hasattr(tree, "value"):
print(f" = {hex(tree.children)}", end="") if isinstance(tree.value, int):
elif isinstance(tree.children, str): print(f" = {hex(tree.value)}", end="")
if self.__is_printable(tree.children): elif isinstance(tree.value, str):
print(f" = '{tree.children}'", end="") if self.__is_printable(tree.value):
print(f" = '{tree.value}'", end="")
if tree.deferred_range: if tree.deferred_range:
print(f" (deferred at {hex(tree.deferred_range[0])}, length {hex(tree.deferred_range[1])})", end="") print(f" (deferred at {hex(tree.deferred_range[0])}, length {hex(tree.deferred_range[1])})", end="")
if tree.factory: if tree.factory:
@ -39,7 +40,7 @@ class ConditionallyUnregisterSymbolVisitor(Visitor):
def f(tree): def f(tree):
if self.conditionally_hidden: if self.conditionally_hidden:
scope = tree.scope scope = tree.scope
name = tree.children[name_string_idx].children name = tree.children[name_string_idx].value
realpath = self.context.realpath(scope, name) realpath = self.context.realpath(scope, name)
self.context.unregister_object(realpath) self.context.unregister_object(realpath)
return f return f

View File

@ -8,7 +8,7 @@ import logging
from acpiparser.aml.stream import Stream from acpiparser.aml.stream import Stream
from acpiparser.aml.parser import AMLCode, DeferredExpansion from acpiparser.aml.parser import AMLCode, DeferredExpansion
from acpiparser.aml.tree import Tree, FlattenTransformer from acpiparser.aml.tree import Tree
from acpiparser.aml.context import Context from acpiparser.aml.context import Context
from acpiparser.aml.interpreter import ConcreteInterpreter from acpiparser.aml.interpreter import ConcreteInterpreter
from acpiparser.aml.visitors import ConditionallyUnregisterSymbolVisitor from acpiparser.aml.visitors import ConditionallyUnregisterSymbolVisitor
@ -29,7 +29,6 @@ def DSDT(val):
tree = Tree() tree = Tree()
AMLCode.parse(context, tree) AMLCode.parse(context, tree)
tree = DeferredExpansion(context).transform_topdown(tree) tree = DeferredExpansion(context).transform_topdown(tree)
tree = FlattenTransformer().transform_bottomup(tree)
trees.append(tree) trees.append(tree)
except Exception as e: except Exception as e:
context.current_stream.dump() context.current_stream.dump()