mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-07-04 11:07:51 +00:00
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:
parent
6e79479a0a
commit
60da7d6bfd
@ -57,13 +57,13 @@ class OperationFieldDecl(NamedDecl):
|
||||
print(f"{self.name}: {self.__class__.__name__}, {self.length} bits")
|
||||
|
||||
class AliasDecl(NamedDecl):
|
||||
def __init__(self, name, target, tree):
|
||||
def __init__(self, name, source, tree):
|
||||
super().__init__(name, tree)
|
||||
self.name = name
|
||||
self.target = target
|
||||
self.source = source
|
||||
|
||||
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):
|
||||
def __init__(self, name, nargs, tree):
|
||||
|
@ -48,10 +48,10 @@ class BufferBase(Object):
|
||||
self.__length = length
|
||||
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__)
|
||||
|
||||
def write(self, norm_idx, value, bit_width):
|
||||
def write(self, byte_idx, value, bit_width):
|
||||
return NotImplementedError(self.__class__.__name__)
|
||||
|
||||
def create_field(self, name, offset, bitwidth, access_width):
|
||||
@ -69,23 +69,23 @@ class BufferBase(Object):
|
||||
|
||||
# Bits out of byte boundary
|
||||
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)
|
||||
if bit_count > bit_remaining:
|
||||
bit_count = bit_remaining
|
||||
|
||||
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
|
||||
bit_idx += bit_count
|
||||
bit_remaining -= bit_count
|
||||
|
||||
while bit_remaining > 0:
|
||||
norm_idx = floor(bit_idx / access_width)
|
||||
bit_count = access_width if bit_remaining >= access_width else bit_remaining
|
||||
byte_idx = bit_idx // 8
|
||||
bit_count = min(access_width, bit_remaining)
|
||||
|
||||
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
|
||||
bit_idx += bit_count
|
||||
bit_remaining -= bit_count
|
||||
@ -100,9 +100,9 @@ class BufferBase(Object):
|
||||
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"
|
||||
|
||||
# Bits out of byte boundary
|
||||
# Bits out of access_width boundary
|
||||
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)
|
||||
if 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_keep = ((1 << access_width) - 1) - mask_of_write
|
||||
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
|
||||
bit_idx += bit_count
|
||||
bit_remaining -= bit_count
|
||||
|
||||
while bit_remaining > 0:
|
||||
norm_idx = floor(bit_idx / access_width)
|
||||
bit_count = access_width if bit_remaining >= access_width else bit_remaining
|
||||
byte_idx = bit_idx // 8
|
||||
bit_count = min(access_width, bit_remaining)
|
||||
|
||||
mask_of_write = self.bitmask(bit_count - 1, 0)
|
||||
mask_of_keep = ((1 << access_width) - 1) - mask_of_write
|
||||
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
|
||||
bit_idx += bit_count
|
||||
@ -142,16 +142,14 @@ class Buffer(BufferBase):
|
||||
def data(self):
|
||||
return bytes(self.__data)
|
||||
|
||||
def read(self, norm_idx, bit_width):
|
||||
def read(self, byte_idx, bit_width):
|
||||
acc = 0
|
||||
byte_width = bit_width // 8
|
||||
offset = norm_idx * byte_width
|
||||
return int.from_bytes(self.__data[offset : (offset + byte_width)], sys.byteorder)
|
||||
byte_width = min(bit_width // 8, len(self.__data) - byte_idx)
|
||||
return int.from_bytes(self.__data[byte_idx : (byte_idx + byte_width)], sys.byteorder)
|
||||
|
||||
def write(self, norm_idx, value, bit_width):
|
||||
byte_width = bit_width // 8
|
||||
offset = norm_idx * byte_width
|
||||
self.__data[offset : (offset + byte_width)] = value.to_bytes(byte_width, sys.byteorder)
|
||||
def write(self, byte_idx, value, bit_width):
|
||||
byte_width = min(bit_width // 8, len(self.__data) - byte_idx)
|
||||
self.__data[byte_idx : (byte_idx + byte_width)] = value.to_bytes(byte_width, sys.byteorder)
|
||||
|
||||
def get(self):
|
||||
return self.__data
|
||||
@ -175,18 +173,16 @@ class StreamIOBuffer(BufferBase):
|
||||
self.__stream = stream
|
||||
self.__base = base
|
||||
|
||||
def read(self, norm_idx, bit_width):
|
||||
def read(self, byte_idx, bit_width):
|
||||
byte_width = bit_width // 8
|
||||
address = norm_idx * byte_width
|
||||
self.__stream.seek(self.__base + address)
|
||||
self.__stream.seek(self.__base + byte_idx)
|
||||
data = self.__stream.read(byte_width)
|
||||
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
|
||||
byte_width = bit_width // 8
|
||||
address = norm_idx * byte_width
|
||||
self.__stream.seek(self.__base + address)
|
||||
self.__stream.seek(self.__base + byte_idx)
|
||||
self.__stream.write(value.to_bytes(byte_width, sys.byteorder))
|
||||
|
||||
class IndexedIOBuffer(BufferBase):
|
||||
@ -196,12 +192,12 @@ class IndexedIOBuffer(BufferBase):
|
||||
self.__index_register = index_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"
|
||||
self.__index_register.set(Integer(norm_idx, 8))
|
||||
self.__index_register.set(Integer(byte_idx, 8))
|
||||
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
|
||||
assert False, "Cannot write to indexed I/O buffers"
|
||||
|
||||
@ -274,7 +270,7 @@ class Integer(Object):
|
||||
class Method(Object):
|
||||
def __init__(self, tree):
|
||||
self.tree = tree
|
||||
self.name = tree.children[1].children
|
||||
self.name = tree.children[1].value
|
||||
self.body = tree.children[3]
|
||||
|
||||
class PredefinedMethod(Object):
|
||||
|
@ -136,15 +136,15 @@ AML_DATA_REGION_OP = 0x885b
|
||||
|
||||
AMLCode = ("DefBlockHeader", "TermObj*")
|
||||
DefBlockHeader = ("TableSignature", "TableLength", "SpecCompliance", "CheckSum", "OemID", "OemTableID", "OemRevision", "CreatorID", "CreatorRevision")
|
||||
TableSignature = ("DWordData",)
|
||||
TableLength = ("DWordData",)
|
||||
SpecCompliance = ("ByteData",)
|
||||
CheckSum = ("ByteData",)
|
||||
OemID = ("TWordData",)
|
||||
OemTableID = ("QWordData",)
|
||||
OemRevision = ("DWordData",)
|
||||
CreatorID = ("DWordData",)
|
||||
CreatorRevision = ("DWordData",)
|
||||
TableSignature = ["DWordData"]
|
||||
TableLength = ["DWordData"]
|
||||
SpecCompliance = ["ByteData"]
|
||||
CheckSum = ["ByteData"]
|
||||
OemID = ["TWordData"]
|
||||
OemTableID = ["QWordData"]
|
||||
OemRevision = ["DWordData"]
|
||||
CreatorID = ["DWordData"]
|
||||
CreatorRevision = ["DWordData"]
|
||||
|
||||
################################################################################
|
||||
# 20.2.2 Name Objects Encoding
|
||||
@ -202,7 +202,7 @@ TermArg = ["ExpressionOpcode", "DataObject", "ArgObj", "LocalObj"]
|
||||
|
||||
NameSpaceModifierObj = ["DefAlias", "DefName", "DefScope"]
|
||||
|
||||
DefAlias = (AML_ALIAS_OP, "NameString", "NameString")
|
||||
DefAlias = (AML_ALIAS_OP, "NameString:SourceObject", "NameString:AliasObject")
|
||||
DefName = (AML_NAME_OP, "NameString", "DataRefObject")
|
||||
DefScope = (AML_SCOPE_OP, "PkgLength", "NameString", "TermList")
|
||||
|
||||
@ -214,68 +214,68 @@ NamedObj = ["DefBankField", "DefCreateBitField", "DefCreateByteField", "DefCreat
|
||||
"DefField", "DefIndexField", "DefMethod", "DefMutex", "DefOpRegion", "DefPowerRes", "DefProcessor",
|
||||
"DefThermalZone"]
|
||||
|
||||
DefBankField = (AML_BANK_FIELD_OP, "PkgLength", "NameString", "NameString", "BankValue", "FieldFlags", "FieldList")
|
||||
BankValue = ("TermArg",)
|
||||
FieldFlags = ("ByteData",)
|
||||
DefBankField = (AML_BANK_FIELD_OP, "PkgLength", "NameString:RegionName", "NameString:BankName", "BankValue", "FieldFlags", "FieldList")
|
||||
BankValue = ["TermArg"]
|
||||
FieldFlags = ["ByteData"]
|
||||
FieldList = ("FieldElement*",)
|
||||
NamedField = ("NameSeg", "FieldLength")
|
||||
ReservedField = (AML_RESERVED_FIELD_PREFIX, "FieldLength")
|
||||
AccessField = (AML_ACCESS_FIELD_PREFIX, "AccessType", "AccessAttrib")
|
||||
AccessType = ("ByteData",)
|
||||
AccessAttrib = ("ByteData",)
|
||||
ConnectFieldDef = ["NameString", "BufferData"]
|
||||
AccessType = ["ByteData"]
|
||||
AccessAttrib = ["ByteData"]
|
||||
ConnectFieldDef = ["NameString"] # FIXME: ACPI spec allows "BufferData" here but does not define what "BufferData" is
|
||||
ConnectField = (AML_CONNECT_FIELD_PREFIX, "ConnectFieldDef")
|
||||
|
||||
DefCreateBitField = (AML_CREATE_BIT_FIELD_OP, "SourceBuff", "BitIndex", "NameString")
|
||||
SourceBuff = ("TermArg",)
|
||||
BitIndex = ("TermArg",)
|
||||
SourceBuff = ["TermArg"]
|
||||
BitIndex = ["TermArg"]
|
||||
DefCreateByteField = (AML_CREATE_BYTE_FIELD_OP, "SourceBuff", "ByteIndex", "NameString")
|
||||
ByteIndex = ("TermArg",)
|
||||
ByteIndex = ["TermArg"]
|
||||
DefCreateDWordField = (AML_CREATE_DWORD_FIELD_OP, "SourceBuff", "ByteIndex", "NameString")
|
||||
DefCreateField = (AML_CREATE_FIELD_OP, "SourceBuff", "BitIndex", "NumBits", "NameString")
|
||||
NumBits = ("TermArg",)
|
||||
NumBits = ["TermArg"]
|
||||
DefCreateQWordField = (AML_CREATE_QWORD_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")
|
||||
|
||||
DefEvent = (AML_EVENT_OP, "NameString")
|
||||
|
||||
DefExternal = (AML_EXTERNAL_OP, "NameString", "ObjectType", "ArgumentCount")
|
||||
ObjectType = ("ByteData",)
|
||||
ArgumentCount = ("ByteData",)
|
||||
ObjectType = ["ByteData"]
|
||||
ArgumentCount = ["ByteData"]
|
||||
|
||||
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")
|
||||
MethodFlags = ("ByteData",)
|
||||
MethodFlags = ["ByteData"]
|
||||
|
||||
DefMutex = (AML_MUTEX_OP, "NameString", "SyncFlags")
|
||||
SyncFlags = ("ByteData",)
|
||||
SyncFlags = ["ByteData"]
|
||||
|
||||
DefOpRegion = (AML_REGION_OP, "NameString", "RegionSpace", "RegionOffset", "RegionLen")
|
||||
RegionSpace = ("ByteData",)
|
||||
RegionOffset = ("TermArg",)
|
||||
RegionLen = ("TermArg",)
|
||||
RegionSpace = ["ByteData"]
|
||||
RegionOffset = ["TermArg"]
|
||||
RegionLen = ["TermArg"]
|
||||
|
||||
DefPowerRes = (AML_POWER_RESOURCE_OP, "PkgLength", "NameString", "SystemLevel", "ResourceOrder", "TermList")
|
||||
SystemLevel = ("ByteData",)
|
||||
ResourceOrder = ("WordData",)
|
||||
SystemLevel = ["ByteData"]
|
||||
ResourceOrder = ["WordData"]
|
||||
|
||||
DefProcessor = (AML_PROCESSOR_OP, "PkgLength", "NameString", "ProcID", "PblkAddr", "PblkLen", "TermList")
|
||||
ProcID = ("ByteData",)
|
||||
PblkAddr = ("DWordData",)
|
||||
PblkLen = ("ByteData",)
|
||||
ProcID = ["ByteData"]
|
||||
PblkAddr = ["DWordData"]
|
||||
PblkLen = ["ByteData"]
|
||||
|
||||
DefThermalZone = (AML_THERMAL_ZONE_OP, "PkgLength", "NameString", "TermList")
|
||||
|
||||
ExtendedAccessField = (AML_EXTENDED_ACCESS_FIELD_PREFIX, "AccessType", "ExtendedAccessAttrib", "AccessLength")
|
||||
ExtendedAccessAttrib = ("ByteData",)
|
||||
AccessLength = ("ByteData",)
|
||||
ExtendedAccessAttrib = ["ByteData"]
|
||||
AccessLength = ["ByteData"]
|
||||
FieldElement = ["NamedField", "ReservedField", "AccessField", "ExtendedAccessField", "ConnectField"]
|
||||
|
||||
# 20.2.5.3 Statement Opcodes Encoding
|
||||
@ -293,35 +293,35 @@ DefContinue = (AML_CONTINUE_OP,)
|
||||
DefElse = (AML_ELSE_OP, "PkgLength", "TermList")
|
||||
|
||||
DefFatal = (AML_FATAL_OP, "FatalType", "FatalCode", "FataArg")
|
||||
FatalType = ("ByteData",)
|
||||
FatalCode = ("DWordData",)
|
||||
FatalArg = ("TermArg",)
|
||||
FatalType = ["ByteData"]
|
||||
FatalCode = ["DWordData"]
|
||||
FatalArg = ["TermArg"]
|
||||
|
||||
DefIfElse = (AML_IF_OP, "PkgLength", "Predicate", "TermList", "DefElse?")
|
||||
Predicate = ("TermArg",)
|
||||
Predicate = ["TermArg"]
|
||||
|
||||
DefNoop = (AML_NOOP_OP,)
|
||||
|
||||
DefNotify = (AML_NOTIFY_OP, "NotifyObject", "NotifyValue")
|
||||
NotifyObject = ("SuperName",)
|
||||
NotifyValue = ("TermArg",)
|
||||
NotifyObject = ["SuperName"]
|
||||
NotifyValue = ["TermArg"]
|
||||
|
||||
DefRelease = (AML_RELEASE_OP, "MutexObject")
|
||||
MutexObject = ("SuperName",)
|
||||
MutexObject = ["SuperName"]
|
||||
|
||||
DefReset = (AML_RESET_OP, "EventObject")
|
||||
EventObject = ("SuperName",)
|
||||
EventObject = ["SuperName"]
|
||||
|
||||
DefReturn = (AML_RETURN_OP, "ArgObject")
|
||||
ArgObject = ("TermArg",)
|
||||
ArgObject = ["TermArg"]
|
||||
|
||||
DefSignal = (AML_SIGNAL_OP, "EventObject")
|
||||
|
||||
DefSleep = (AML_SLEEP_OP, "MsecTime")
|
||||
MsecTime = ("TermArg",)
|
||||
MsecTime = ["TermArg"]
|
||||
|
||||
DefStall = (AML_STALL_OP, "UsecTime")
|
||||
UsecTime = ("TermArg",)
|
||||
UsecTime = ["TermArg"]
|
||||
|
||||
DefUnload = (AML_UNLOAD_OP, "Target")
|
||||
|
||||
@ -342,21 +342,21 @@ ExpressionOpcode = ["DefAcquire", "DefAdd", "DefAnd", "DefBuffer", "DefConcat",
|
||||
ReferenceTypeOpcode = ["DefRefOf", "DefDerefOf", "DefIndex"]
|
||||
|
||||
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"]
|
||||
|
||||
DefAnd = (AML_AND_OP, "Operand", "Operand", "Target")
|
||||
DefAnd = (AML_AND_OP, "Operand:LeftOperand", "Operand:RightOperand", "Target")
|
||||
|
||||
DefBuffer = (AML_BUFFER_OP, "PkgLength", "BufferSize", "ByteList")
|
||||
BufferSize = ("TermArg",)
|
||||
BufferSize = ["TermArg"]
|
||||
|
||||
DefConcat = (AML_CONCAT_OP, "Data", "Data", "Target")
|
||||
Data = ("TermArg",)
|
||||
DefConcat = (AML_CONCAT_OP, "Data:Data1", "Data:Data2", "Target")
|
||||
Data = ["TermArg"]
|
||||
|
||||
DefConcatRes = (AML_CONCAT_RES_OP, "BufData", "BufData", "Target")
|
||||
BufData = ("TermArg",)
|
||||
DefConcatRes = (AML_CONCAT_RES_OP, "BufData:BufData1", "BufData:BufData2", "Target")
|
||||
BufData = ["TermArg"]
|
||||
|
||||
DefCondRefOf = (AML_CONDITIONAL_REF_OF_OP, "SuperName", "Target")
|
||||
|
||||
@ -365,80 +365,80 @@ DefCopyObject = (AML_COPY_OBJECT_OP, "TermArg", "SimpleName")
|
||||
DefDecrement = (AML_DECREMENT_OP, "SuperName")
|
||||
|
||||
DefDerefOf = (AML_DEREF_OF_OP, "ObjReference")
|
||||
ObjReference = ("TermArg",)
|
||||
ObjReference = ["TermArg"]
|
||||
|
||||
DefDivide = (AML_DIVIDE_OP, "Dividend", "Divisor", "Remainder", "Quotient")
|
||||
Dividend = ("TermArg",)
|
||||
Divisor = ("TermArg",)
|
||||
Remainder = ("Target",)
|
||||
Quotient = ("Target",)
|
||||
Dividend = ["TermArg"]
|
||||
Divisor = ["TermArg"]
|
||||
Remainder = ["Target"]
|
||||
Quotient = ["Target"]
|
||||
|
||||
DefFindSetLeftBit = (AML_FIND_SET_LEFT_BIT_OP, "Operand", "Target")
|
||||
DefFindSetRightBit = (AML_FIND_SET_RIGHT_BIT_OP, "Operand", "Target")
|
||||
|
||||
DefFromBCD = (AML_FROM_BCD_OP, "BCDValue", "Target")
|
||||
BCDValue = ("TermArg",)
|
||||
BCDValue = ["TermArg"]
|
||||
|
||||
DefIncrement = (AML_INCREMENT_OP, "SuperName")
|
||||
|
||||
DefIndex = (AML_INDEX_OP, "BuffPkgStrObj", "IndexValue", "Target")
|
||||
BuffPkgStrObj = ("TermArg",)
|
||||
IndexValue = ("TermArg",)
|
||||
BuffPkgStrObj = ["TermArg"]
|
||||
IndexValue = ["TermArg"]
|
||||
|
||||
DefLAnd = (AML_LAND_OP, "Operand", "Operand")
|
||||
DefLEqual = (AML_LEQUAL_OP, "Operand", "Operand")
|
||||
DefLGreater = (AML_LGREATER_OP, "Operand", "Operand")
|
||||
DefLAnd = (AML_LAND_OP, "Operand:LeftOperand", "Operand:RightOperand")
|
||||
DefLEqual = (AML_LEQUAL_OP, "Operand:LeftOperand", "Operand:RightOperand")
|
||||
DefLGreater = (AML_LGREATER_OP, "Operand:LeftOperand", "Operand:RightOperand")
|
||||
# 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)
|
||||
DefLNot = (AML_LNOT_OP, "Operand")
|
||||
# DefLNotEqual is equivalent to (AML_LNOT_OP, DefLEqual)
|
||||
|
||||
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")
|
||||
SearchPkg = ("TermArg",)
|
||||
MatchOpcode = ("ByteData",)
|
||||
StartIndex = ("TermArg",)
|
||||
DefMatch = (AML_MATCH_OP, "SearchPkg", "MatchOpcode:MatchOpcode1", "Operand:Operand1", "MatchOpcode:MatchOpcode2", "Operand:Operand2", "StartIndex")
|
||||
SearchPkg = ["TermArg"]
|
||||
MatchOpcode = ["ByteData"]
|
||||
StartIndex = ["TermArg"]
|
||||
|
||||
DefMid = (AML_MID_OP, "MidObj", "TermArg", "TermArg", "Target")
|
||||
MidObj = ("TermArg",)
|
||||
DefMid = (AML_MID_OP, "MidObj", "TermArg:Source", "TermArg:Index", "Target")
|
||||
MidObj = ["TermArg"]
|
||||
|
||||
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")
|
||||
DefNOr = (AML_NOR_OP, "Operand", "Operand", "Target")
|
||||
DefNAnd = (AML_NAND_OP, "Operand:LeftOperand", "Operand:RightOperand", "Target")
|
||||
DefNOr = (AML_NOR_OP, "Operand:LeftOperand", "Operand:RightOperand", "Target")
|
||||
DefNot = (AML_NOT_OP, "Operand", "Target")
|
||||
|
||||
DefObjectType = (AML_OBJECT_TYPE_OP, "ObjectTypeContent")
|
||||
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")
|
||||
DefVarPackage = (AML_VAR_PACKAGE_OP, "PkgLength", "VarNumElements", "PackageElementList")
|
||||
NumElements = ("ByteData",)
|
||||
VarNumElements = ("TermArg",)
|
||||
NumElements = ["ByteData"]
|
||||
VarNumElements = ["TermArg"]
|
||||
PackageElementList = ("PackageElement*",)
|
||||
PackageElement = ["DataRefObject", "NameString"]
|
||||
|
||||
DefRefOf = (AML_REF_OF_OP, "SuperName")
|
||||
|
||||
DefShiftLeft = (AML_SHIFT_LEFT_OP, "Operand", "ShiftCount", "Target")
|
||||
ShiftCount = ("TermArg",)
|
||||
ShiftCount = ["TermArg"]
|
||||
DefShiftRight = (AML_SHIFT_RIGHT_OP, "Operand", "ShiftCount", "Target")
|
||||
|
||||
DefSizeOf = (AML_SIZE_OF_OP, "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,)
|
||||
|
||||
@ -453,11 +453,11 @@ DefToHexString = (AML_TO_HEX_STRING_OP, "Operand", "Target")
|
||||
DefToInteger = (AML_TO_INTEGER_OP, "Operand", "Target")
|
||||
|
||||
DefToString = (AML_TO_STRING_OP, "TermArg", "LengthArg", "Target")
|
||||
LengthArg = ("TermArg",)
|
||||
LengthArg = ["TermArg"]
|
||||
|
||||
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
|
||||
@ -492,3 +492,24 @@ Local7Op = (AML_LOCAL7_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)
|
||||
|
@ -86,9 +86,13 @@ class ConcreteInterpreter(Interpreter):
|
||||
|
||||
def interpret_method_call(self, name, *args):
|
||||
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)
|
||||
pseudo_invocation = Tree("MethodInvocation", [name_string])
|
||||
pseudo_invocation.register_structure(("NameString", "TermArg*"))
|
||||
pseudo_invocation.complete_parsing()
|
||||
try:
|
||||
val = self.interpret(pseudo_invocation)
|
||||
except:
|
||||
@ -118,7 +122,7 @@ class ConcreteInterpreter(Interpreter):
|
||||
return None
|
||||
|
||||
def NameString(self, tree):
|
||||
name = tree.children
|
||||
name = tree.value
|
||||
obj = self.context.lookup_binding(name)
|
||||
if not obj:
|
||||
sym = self.context.lookup_symbol(name)
|
||||
@ -133,7 +137,7 @@ class ConcreteInterpreter(Interpreter):
|
||||
|
||||
# 20.2.3 Data Objects Encoding
|
||||
def ByteList(self, tree):
|
||||
return RawDataBuffer(tree.children)
|
||||
return RawDataBuffer(tree.value)
|
||||
|
||||
def ByteConst(self, tree):
|
||||
return self.interpret(tree.children[0])
|
||||
@ -148,19 +152,19 @@ class ConcreteInterpreter(Interpreter):
|
||||
return self.interpret(tree.children[0])
|
||||
|
||||
def String(self, tree):
|
||||
return String(tree.children)
|
||||
return String(tree.value)
|
||||
|
||||
def ByteData(self, tree):
|
||||
return Integer(tree.children)
|
||||
return Integer(tree.value)
|
||||
|
||||
def WordData(self, tree):
|
||||
return Integer(tree.children)
|
||||
return Integer(tree.value)
|
||||
|
||||
def DWordData(self, tree):
|
||||
return Integer(tree.children)
|
||||
return Integer(tree.value)
|
||||
|
||||
def QWordData(self, tree):
|
||||
return Integer(tree.children)
|
||||
return Integer(tree.value)
|
||||
|
||||
def ZeroOp(self, tree):
|
||||
return Integer(0x00)
|
||||
@ -210,7 +214,7 @@ class ConcreteInterpreter(Interpreter):
|
||||
return Integer(value.fn(args))
|
||||
else:
|
||||
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
|
||||
|
||||
# 20.2.5.1 Namespace Modifier Objects Encoding
|
||||
@ -219,7 +223,7 @@ class ConcreteInterpreter(Interpreter):
|
||||
|
||||
def DefName(self, tree):
|
||||
self.context.change_scope(tree.children[0].scope)
|
||||
name = tree.children[0].children
|
||||
name = tree.children[0].value
|
||||
obj = self.context.lookup_binding(name)
|
||||
if not obj:
|
||||
obj = self.interpret(tree.children[1])
|
||||
@ -229,7 +233,7 @@ class ConcreteInterpreter(Interpreter):
|
||||
|
||||
# 20.2.5.2 Named Objects Encoding
|
||||
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))
|
||||
assert isinstance(sym, OperationFieldDecl)
|
||||
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])
|
||||
assert isinstance(buf, Buffer)
|
||||
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:
|
||||
buf.create_field(name, index, bitwidth, 8)
|
||||
else:
|
||||
@ -283,13 +287,13 @@ class ConcreteInterpreter(Interpreter):
|
||||
return self.create_field(tree, numbits, 3)
|
||||
|
||||
def DefDevice(self, tree):
|
||||
name = tree.children[1].children
|
||||
name = tree.children[1].value
|
||||
fullpath = self.context.realpath(tree.scope, name)
|
||||
sym = self.context.lookup_symbol(fullpath)
|
||||
return Device(sym)
|
||||
|
||||
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
|
||||
|
||||
def DefField(self, tree):
|
||||
@ -300,7 +304,7 @@ class ConcreteInterpreter(Interpreter):
|
||||
return Method(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))
|
||||
|
||||
space = self.interpret(tree.children[1]).get()
|
||||
|
@ -56,7 +56,8 @@ class Factory:
|
||||
self.mark_end()
|
||||
return tree
|
||||
|
||||
def opcodes(self):
|
||||
@property
|
||||
def decoder(self):
|
||||
raise NotImplementedError
|
||||
|
||||
################################################################################
|
||||
@ -66,17 +67,20 @@ class Factory:
|
||||
class NameSegFactory(Factory):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.__opcodes = []
|
||||
self.__decoder = {}
|
||||
for i in range(ord('A'), ord('Z') + 1):
|
||||
self.__opcodes.append(i)
|
||||
self.__opcodes.append(ord('_'))
|
||||
self.__decoder[i] = self
|
||||
self.__decoder[ord('_')] = self
|
||||
self.label = "NameSeg"
|
||||
|
||||
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):
|
||||
return self.__opcodes
|
||||
@property
|
||||
def decoder(self):
|
||||
return self.__decoder
|
||||
|
||||
NameSeg = NameSegFactory()
|
||||
|
||||
@ -84,12 +88,14 @@ class NameStringFactory(Factory):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.label = "NameString"
|
||||
self.__opcodes = []
|
||||
self.__decoder = {}
|
||||
for i in range(ord('A'), ord('Z') + 1):
|
||||
self.__opcodes.append(i)
|
||||
self.__opcodes.extend([ord('_'), ord('\\'), ord('^'), grammar.AML_DUAL_NAME_PREFIX, grammar.AML_MULTI_NAME_PREFIX])
|
||||
self.__decoder[i] = self
|
||||
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):
|
||||
tree.register_structure(("value",))
|
||||
acc = ""
|
||||
|
||||
# Namespace prefixes
|
||||
@ -117,10 +123,12 @@ class NameStringFactory(Factory):
|
||||
stream.seek(-1)
|
||||
acc += stream.get_fixed_length_string(4)
|
||||
|
||||
tree.children = acc
|
||||
tree.append_child(acc)
|
||||
tree.complete_parsing()
|
||||
|
||||
def opcodes(self):
|
||||
return self.__opcodes
|
||||
@property
|
||||
def decoder(self):
|
||||
return self.__decoder
|
||||
|
||||
NameString = NameStringFactory()
|
||||
|
||||
@ -135,12 +143,11 @@ class ConstDataFactory(Factory):
|
||||
self.width = width
|
||||
|
||||
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
|
||||
|
||||
def opcodes(self):
|
||||
return None
|
||||
|
||||
ByteData = ConstDataFactory("ByteData", 1)
|
||||
WordData = ConstDataFactory("WordData", 2)
|
||||
DWordData = ConstDataFactory("DWordData", 4)
|
||||
@ -155,11 +162,14 @@ class StringFactory(Factory):
|
||||
def match(self, context, stream, tree):
|
||||
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
|
||||
|
||||
def opcodes(self):
|
||||
return [grammar.AML_STRING_PREFIX]
|
||||
@property
|
||||
def decoder(self):
|
||||
return {grammar.AML_STRING_PREFIX: self}
|
||||
|
||||
String = StringFactory()
|
||||
|
||||
@ -169,7 +179,9 @@ class ByteListFactory(Factory):
|
||||
self.label = "ByteList"
|
||||
|
||||
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()
|
||||
|
||||
ByteList = ByteListFactory()
|
||||
@ -200,10 +212,12 @@ class PkgLengthFactory(Factory):
|
||||
byte_count = pkg_lead_byte >> 6
|
||||
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:
|
||||
remaining = tree.children - byte_count - 1
|
||||
remaining = tree.value - byte_count - 1
|
||||
stream.push_scope(remaining)
|
||||
tree.package_range = (stream.current, remaining)
|
||||
return tree
|
||||
@ -218,27 +232,33 @@ FieldLength = PkgLengthFactory("FieldLength", False)
|
||||
class MethodInvocationFactory(Factory):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.__opcodes = None
|
||||
self.__decoder = None
|
||||
self.label = "MethodInvocation"
|
||||
|
||||
def match(self, context, stream, tree):
|
||||
tree.register_structure(("NameString", "TermArg*"))
|
||||
|
||||
child_namestring = Tree()
|
||||
globals()["NameString"].parse(context, 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)):
|
||||
for i in range(0, sym.nargs):
|
||||
child_arg = Tree()
|
||||
globals()["TermArg"].parse(context, child_arg)
|
||||
tree.append_child(child_arg)
|
||||
|
||||
tree.complete_parsing()
|
||||
return tree
|
||||
|
||||
def opcodes(self):
|
||||
if not self.__opcodes:
|
||||
self.__opcodes = globals()["NameString"].opcodes()
|
||||
return self.__opcodes
|
||||
@property
|
||||
def decoder(self):
|
||||
if not self.__decoder:
|
||||
self.__decoder = {}
|
||||
for k in globals()["NameString"].decoder.keys():
|
||||
self.__decoder[k] = self
|
||||
return self.__decoder
|
||||
|
||||
MethodInvocation = MethodInvocationFactory()
|
||||
|
||||
@ -250,15 +270,31 @@ class SequenceFactory(Factory):
|
||||
def __init__(self, label, seq):
|
||||
super().__init__()
|
||||
self.label = label
|
||||
self.seq = seq
|
||||
self.__opcodes = None
|
||||
# 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.structure = seq
|
||||
self.__decoder = None
|
||||
|
||||
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
|
||||
# peek the next opcode in such cases.
|
||||
if stream.at_end() and \
|
||||
(self.seq[0][-1] in ["*", "?"]):
|
||||
stream.pop_scope()
|
||||
tree.complete_parsing()
|
||||
return tree
|
||||
|
||||
opcode, opcode_width = stream.peek_opcode()
|
||||
@ -268,6 +304,7 @@ class SequenceFactory(Factory):
|
||||
# cleanup actions upon exceptions.
|
||||
to_recover_from_deferred_mode = False
|
||||
to_pop_stream_scope = False
|
||||
completed = True
|
||||
|
||||
for i,elem in enumerate(self.seq):
|
||||
pos = stream.current
|
||||
@ -288,7 +325,7 @@ class SequenceFactory(Factory):
|
||||
factory = globals()[elem]
|
||||
if not stream.at_end():
|
||||
sub_opcode, _ = stream.peek_opcode()
|
||||
if sub_opcode in factory.opcodes():
|
||||
if sub_opcode in factory.decoder.keys():
|
||||
child = Tree()
|
||||
factory.parse(context, child)
|
||||
tree.append_child(child)
|
||||
@ -312,7 +349,7 @@ class SequenceFactory(Factory):
|
||||
context.enter_deferred_mode()
|
||||
to_recover_from_deferred_mode = True
|
||||
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:
|
||||
if to_pop_stream_scope:
|
||||
stream.pop_scope(force=True)
|
||||
@ -321,49 +358,54 @@ class SequenceFactory(Factory):
|
||||
tree.context_scope = context.get_scope()
|
||||
tree.factory = SequenceFactory(f"{self.label}.deferred", self.seq[i:])
|
||||
stream.seek(package_end, absolute=True)
|
||||
completed = False
|
||||
break
|
||||
else:
|
||||
raise e
|
||||
|
||||
if completed:
|
||||
tree.complete_parsing()
|
||||
|
||||
if to_recover_from_deferred_mode:
|
||||
context.exit_deferred_mode()
|
||||
return tree
|
||||
|
||||
def opcodes(self):
|
||||
if not self.__opcodes:
|
||||
@property
|
||||
def decoder(self):
|
||||
if not self.__decoder:
|
||||
if isinstance(self.seq[0], int):
|
||||
self.__opcodes = [self.seq[0]]
|
||||
self.__decoder = {self.seq[0]: self}
|
||||
else:
|
||||
self.__opcodes = globals()[self.seq[0]].opcodes()
|
||||
return self.__opcodes
|
||||
self.__decoder = {}
|
||||
for k in globals()[self.seq[0]].decoder.keys():
|
||||
self.__decoder[k] = self
|
||||
return self.__decoder
|
||||
|
||||
class OptionFactory(Factory):
|
||||
def __init__(self, label, opts):
|
||||
super().__init__()
|
||||
self.label = label
|
||||
self.opts = opts
|
||||
self.__opcodes = None
|
||||
self.__decoder = None
|
||||
|
||||
def match(self, context, stream, tree):
|
||||
opcode, _ = stream.peek_opcode()
|
||||
try:
|
||||
if len(self.opts) == 1:
|
||||
globals()[self.opts[0]].parse(context, tree)
|
||||
else:
|
||||
self.decoder[opcode].parse(context, tree)
|
||||
return tree
|
||||
except KeyError:
|
||||
raise DecodeError(opcode, self.label)
|
||||
|
||||
for opt in self.opts:
|
||||
factory = globals()[opt]
|
||||
matched_opcodes = factory.opcodes()
|
||||
if matched_opcodes is None or opcode in matched_opcodes:
|
||||
child = Tree()
|
||||
tree.append_child(child)
|
||||
factory.parse(context, child)
|
||||
return tree
|
||||
|
||||
raise DecodeError(opcode, self.label)
|
||||
|
||||
def opcodes(self):
|
||||
if not self.__opcodes:
|
||||
self.__opcodes = []
|
||||
@property
|
||||
def decoder(self):
|
||||
if not self.__decoder:
|
||||
self.__decoder = {}
|
||||
for opt in self.opts:
|
||||
self.__opcodes.extend(globals()[opt].opcodes())
|
||||
return self.__opcodes
|
||||
self.__decoder.update(globals()[opt].decoder)
|
||||
return self.__decoder
|
||||
|
||||
class DeferredExpansion(Transformer):
|
||||
def __init__(self, context):
|
||||
@ -390,6 +432,7 @@ class DeferredExpansion(Transformer):
|
||||
tree.children.extend(aux_tree.children)
|
||||
tree.deferred_range = None
|
||||
tree.factory = None
|
||||
tree.complete_parsing()
|
||||
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))
|
||||
|
||||
@ -402,9 +445,9 @@ class DeferredExpansion(Transformer):
|
||||
################################################################################
|
||||
|
||||
def DefAlias_hook_post(context, tree):
|
||||
target = tree.children[0].children
|
||||
name = tree.children[1].children
|
||||
sym = AliasDecl(name, target, tree)
|
||||
source = tree.SourceObject.value
|
||||
alias = tree.AliasObject.value
|
||||
sym = AliasDecl(alias, source, tree)
|
||||
context.register_symbol(sym)
|
||||
|
||||
def DefName_hook_named(context, tree, name):
|
||||
@ -419,32 +462,32 @@ def DefScope_hook_post(context, tree):
|
||||
|
||||
|
||||
def DefCreateBitField_hook_named(context, tree, name):
|
||||
name = tree.children[2].children
|
||||
name = tree.children[2].value
|
||||
sym = FieldDecl(name, 1, tree)
|
||||
context.register_symbol(sym)
|
||||
|
||||
def DefCreateByteField_hook_named(context, tree, name):
|
||||
name = tree.children[2].children
|
||||
name = tree.children[2].value
|
||||
sym = FieldDecl(name, 8, tree)
|
||||
context.register_symbol(sym)
|
||||
|
||||
def DefCreateDWordField_hook_named(context, tree, name):
|
||||
name = tree.children[2].children
|
||||
name = tree.children[2].value
|
||||
sym = FieldDecl(name, 32, tree)
|
||||
context.register_symbol(sym)
|
||||
|
||||
def DefCreateField_hook_named(context, tree, name):
|
||||
name = tree.children[3].children
|
||||
name = tree.children[3].value
|
||||
sym = FieldDecl(name, 0, tree)
|
||||
context.register_symbol(sym)
|
||||
|
||||
def DefCreateQWordField_hook_named(context, tree, name):
|
||||
name = tree.children[2].children
|
||||
name = tree.children[2].value
|
||||
sym = FieldDecl(name, 64, tree)
|
||||
context.register_symbol(sym)
|
||||
|
||||
def DefCreateWordField_hook_named(context, tree, name):
|
||||
name = tree.children[2].children
|
||||
name = tree.children[2].value
|
||||
sym = FieldDecl(name, 16, tree)
|
||||
context.register_symbol(sym)
|
||||
|
||||
@ -457,9 +500,9 @@ def DefDevice_hook_post(context, tree):
|
||||
context.pop_scope()
|
||||
|
||||
def DefExternal_hook_post(context, tree):
|
||||
name = tree.children[0].children
|
||||
ty = tree.children[1].children[0].children
|
||||
nargs = tree.children[2].children[0].children
|
||||
name = tree.NameString.value
|
||||
ty = tree.ObjectType.value
|
||||
nargs = tree.ArgumentCount.value
|
||||
|
||||
if ty == 0x8: # an external method
|
||||
sym = MethodDecl(name, nargs, tree)
|
||||
@ -479,52 +522,50 @@ access_width_map = {
|
||||
|
||||
def DefField_hook_post(context, tree):
|
||||
# Update the fields with region & offset info
|
||||
region_name = context.lookup_symbol(tree.children[1].children).name
|
||||
flags = tree.children[2].children[0].children
|
||||
region_name = context.lookup_symbol(tree.NameString.value).name
|
||||
flags = tree.FieldFlags.value
|
||||
access_width = access_width_map[flags & 0xF]
|
||||
fields = tree.children[3].children
|
||||
fields = tree.FieldList.FieldElements
|
||||
bit_offset = 0
|
||||
for field in fields:
|
||||
field = field.children[0]
|
||||
if field.label == "NamedField":
|
||||
name = field.children[0].children
|
||||
length = field.children[1].children
|
||||
name = field.NameSeg.value
|
||||
length = field.FieldLength.value
|
||||
sym = context.lookup_symbol(name)
|
||||
assert isinstance(sym, OperationFieldDecl)
|
||||
sym.set_location(region_name, bit_offset, access_width)
|
||||
bit_offset += length
|
||||
elif field.label == "ReservedField":
|
||||
length = field.children[0].children
|
||||
length = field.FieldLength.value
|
||||
bit_offset += length
|
||||
else:
|
||||
break
|
||||
|
||||
def DefIndexField_hook_post(context, tree):
|
||||
# Update the fields with region & offset info
|
||||
index_register = context.lookup_symbol(tree.children[1].children)
|
||||
data_register = context.lookup_symbol(tree.children[2].children)
|
||||
flags = tree.children[3].children[0].children
|
||||
index_register = context.lookup_symbol(tree.IndexName.value)
|
||||
data_register = context.lookup_symbol(tree.DataName.value)
|
||||
flags = tree.FieldFlags.value
|
||||
access_width = access_width_map[flags & 0xF]
|
||||
fields = tree.children[4].children
|
||||
fields = tree.FieldList.FieldElements
|
||||
bit_offset = 0
|
||||
for field in fields:
|
||||
field = field.children[0]
|
||||
if field.label == "NamedField":
|
||||
name = field.children[0].children
|
||||
length = field.children[1].children
|
||||
name = field.NameSeg.value
|
||||
length = field.FieldLength.value
|
||||
sym = context.lookup_symbol(name)
|
||||
assert isinstance(sym, OperationFieldDecl)
|
||||
sym.set_indexed_location(index_register, data_register, bit_offset, access_width)
|
||||
bit_offset += length
|
||||
elif field.label == "ReservedField":
|
||||
length = field.children[0].children
|
||||
length = field.FieldLength.value
|
||||
bit_offset += length
|
||||
else:
|
||||
break
|
||||
|
||||
def NamedField_hook_post(context, tree):
|
||||
name = tree.children[0].children
|
||||
length = tree.children[1].children
|
||||
name = tree.NameSeg.value
|
||||
length = tree.FieldLength.value
|
||||
sym = OperationFieldDecl(name, length, tree)
|
||||
context.register_symbol(sym)
|
||||
|
||||
@ -534,8 +575,9 @@ def DefMethod_hook_named(context, tree, name):
|
||||
def DefMethod_hook_post(context, tree):
|
||||
context.pop_scope()
|
||||
if len(tree.children) >= 3:
|
||||
name = tree.children[1].children
|
||||
flags = tree.children[2].children[0].children
|
||||
# Parsing of the method may be deferred. Do not use named fields to access its children.
|
||||
name = tree.children[1].value
|
||||
flags = tree.children[2].value
|
||||
nargs = flags & 0x7
|
||||
sym = MethodDecl(name, nargs, tree)
|
||||
context.register_symbol(sym)
|
||||
|
@ -13,6 +13,8 @@ class Tree:
|
||||
self.children = copy(children)
|
||||
self.scope = None
|
||||
|
||||
self.structure = None
|
||||
|
||||
self.package_range = None
|
||||
|
||||
self.deferred_range = None
|
||||
@ -22,6 +24,26 @@ class Tree:
|
||||
def append_child(self, 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:
|
||||
def __init__(self):
|
||||
self.depth = 0
|
||||
@ -35,12 +57,11 @@ class Visitor:
|
||||
|
||||
def visit_topdown(self, tree):
|
||||
self.__visit(tree)
|
||||
if isinstance(tree.children, list):
|
||||
self.depth += 1
|
||||
for child in tree.children:
|
||||
if isinstance(child, Tree):
|
||||
self.visit_topdown(child)
|
||||
self.depth -= 1
|
||||
self.depth += 1
|
||||
for child in tree.children:
|
||||
if isinstance(child, Tree):
|
||||
self.visit_topdown(child)
|
||||
self.depth -= 1
|
||||
|
||||
class Transformer:
|
||||
def __init__(self):
|
||||
@ -57,45 +78,21 @@ class Transformer:
|
||||
|
||||
def transform_topdown(self, tree):
|
||||
new_tree = self.__transform(tree)
|
||||
if isinstance(new_tree.children, list):
|
||||
self.depth += 1
|
||||
for i, child in enumerate(tree.children):
|
||||
if isinstance(child, Tree):
|
||||
tree.children[i] = self.transform_topdown(child)
|
||||
self.depth -= 1
|
||||
self.depth += 1
|
||||
for i, child in enumerate(tree.children):
|
||||
if isinstance(child, Tree):
|
||||
tree.children[i] = self.transform_topdown(child)
|
||||
self.depth -= 1
|
||||
return new_tree
|
||||
|
||||
def transform_bottomup(self, tree):
|
||||
if isinstance(tree.children, list):
|
||||
self.depth += 1
|
||||
for i, child in enumerate(tree.children):
|
||||
if isinstance(child, Tree):
|
||||
tree.children[i] = self.transform_bottomup(child)
|
||||
self.depth -= 1
|
||||
self.depth += 1
|
||||
for i, child in enumerate(tree.children):
|
||||
if isinstance(child, Tree):
|
||||
tree.children[i] = self.transform_bottomup(child)
|
||||
self.depth -= 1
|
||||
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:
|
||||
def __init__(self, context):
|
||||
self.context = context
|
||||
|
@ -13,11 +13,12 @@ class PrintLayoutVisitor(Visitor):
|
||||
def default(self, tree):
|
||||
indent = " " * self.depth
|
||||
print(f"{indent}{tree.label}", end="")
|
||||
if isinstance(tree.children, int):
|
||||
print(f" = {hex(tree.children)}", end="")
|
||||
elif isinstance(tree.children, str):
|
||||
if self.__is_printable(tree.children):
|
||||
print(f" = '{tree.children}'", end="")
|
||||
if hasattr(tree, "value"):
|
||||
if isinstance(tree.value, int):
|
||||
print(f" = {hex(tree.value)}", end="")
|
||||
elif isinstance(tree.value, str):
|
||||
if self.__is_printable(tree.value):
|
||||
print(f" = '{tree.value}'", end="")
|
||||
if tree.deferred_range:
|
||||
print(f" (deferred at {hex(tree.deferred_range[0])}, length {hex(tree.deferred_range[1])})", end="")
|
||||
if tree.factory:
|
||||
@ -39,7 +40,7 @@ class ConditionallyUnregisterSymbolVisitor(Visitor):
|
||||
def f(tree):
|
||||
if self.conditionally_hidden:
|
||||
scope = tree.scope
|
||||
name = tree.children[name_string_idx].children
|
||||
name = tree.children[name_string_idx].value
|
||||
realpath = self.context.realpath(scope, name)
|
||||
self.context.unregister_object(realpath)
|
||||
return f
|
||||
|
@ -8,7 +8,7 @@ import logging
|
||||
|
||||
from acpiparser.aml.stream import Stream
|
||||
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.interpreter import ConcreteInterpreter
|
||||
from acpiparser.aml.visitors import ConditionallyUnregisterSymbolVisitor
|
||||
@ -29,7 +29,6 @@ def DSDT(val):
|
||||
tree = Tree()
|
||||
AMLCode.parse(context, tree)
|
||||
tree = DeferredExpansion(context).transform_topdown(tree)
|
||||
tree = FlattenTransformer().transform_bottomup(tree)
|
||||
trees.append(tree)
|
||||
except Exception as e:
|
||||
context.current_stream.dump()
|
||||
|
Loading…
Reference in New Issue
Block a user