mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-08-17 15:51:34 +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. 3. Invocation to intermediate factories is now skipped. As an example, when parsing a ByteConst that acts as a ByteIndex, the original implementation invokes the following factories in sequence: ByteIndex -> TermArg -> DataObject -> ComputationalData -> ByteConst The factories TermArg, DataObject and ComputationalData does nothing but forward the parsing to the next-level factory according to the opcode of the next object. With this patch, the invocation sequence becomes: ByteIndex -> ByteConst i.e. ByteIndex directly passes to ByteConst which can parse the next opcode. Tracked-On: #6298 Signed-off-by: Junjie Mao <junjie.mao@intel.com>
This commit is contained in:
parent
d325966612
commit
3bcb3146ad
@ -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,24 @@ class BufferBase(Object):
|
||||
|
||||
# Bits out of byte boundary
|
||||
if bit_idx % access_width > 0:
|
||||
norm_idx = floor(bit_idx / access_width)
|
||||
# byte_idx shall be (access_width // 8)-byte aligned
|
||||
byte_idx = (bit_idx // access_width) * (access_width // 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 +101,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 // access_width) * (access_width // 8)
|
||||
bit_count = (access_width - bit_idx % access_width)
|
||||
if bit_count > bit_remaining:
|
||||
bit_count = bit_remaining
|
||||
@ -110,20 +111,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 +143,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,17 +174,15 @@ 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):
|
||||
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):
|
||||
@ -195,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"
|
||||
|
||||
@ -273,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
|
||||
# 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.__opcodes = None
|
||||
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()
|
||||
|
||||
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)
|
||||
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)
|
||||
|
||||
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,7 +57,6 @@ 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):
|
||||
@ -57,7 +78,6 @@ 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):
|
||||
@ -66,7 +86,6 @@ class Transformer:
|
||||
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):
|
||||
@ -74,28 +93,6 @@ class Transformer:
|
||||
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