mirror of
https://github.com/projectacrn/acrn-hypervisor.git
synced 2025-06-27 15:56:54 +00:00
board_inspector: add a visitor to generate AML binary from trees
This patch introduces a visitor that converts an arbitrary AML tree to an AML binary. Most nodes can be converted in a straightforward way by following the defined grammar, but the following nodes require some additional effort: - NameStrings can be formatted as either a NameSeg (i.e. four upper case characters), a DualNamePath, a MultiNamePath or a NullName. - PkgLengths are recalculated according to the actual length of the following object (in case they are changed dynamically after being generated by the parser) and generated following the AML encoding of such lengths. The visitor works in a bottom-up manner, i.e. the children are visited and converted to binary before the parent. The whole trees parsed from DSDT/SSDTs are now also stored in the Context for further reference. Tracked-On: #6287 Signed-off-by: Junjie Mao <junjie.mao@intel.com>
This commit is contained in:
parent
b119a0b824
commit
55554e7d56
@ -142,6 +142,7 @@ class Context:
|
|||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.streams = {}
|
self.streams = {}
|
||||||
self.current_stream = None
|
self.current_stream = None
|
||||||
|
self.trees = {}
|
||||||
|
|
||||||
# Loaded namespace
|
# Loaded namespace
|
||||||
self.__symbol_table = {}
|
self.__symbol_table = {}
|
||||||
|
@ -63,6 +63,14 @@ class Visitor:
|
|||||||
self.visit_topdown(child)
|
self.visit_topdown(child)
|
||||||
self.depth -= 1
|
self.depth -= 1
|
||||||
|
|
||||||
|
def visit_bottomup(self, tree):
|
||||||
|
self.depth += 1
|
||||||
|
for child in tree.children:
|
||||||
|
if isinstance(child, Tree):
|
||||||
|
self.visit_bottomup(child)
|
||||||
|
self.depth -= 1
|
||||||
|
self.__visit(tree)
|
||||||
|
|
||||||
class Transformer:
|
class Transformer:
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.depth = 0
|
self.depth = 0
|
||||||
|
@ -3,7 +3,10 @@
|
|||||||
# SPDX-License-Identifier: BSD-3-Clause
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
#
|
#
|
||||||
|
|
||||||
|
import sys
|
||||||
|
|
||||||
from .tree import Visitor
|
from .tree import Visitor
|
||||||
|
from . import grammar
|
||||||
|
|
||||||
class PrintLayoutVisitor(Visitor):
|
class PrintLayoutVisitor(Visitor):
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -69,3 +72,124 @@ class ConditionallyUnregisterSymbolVisitor(Visitor):
|
|||||||
self.depth -= 1
|
self.depth -= 1
|
||||||
elif tree.label not in ["DefMethod"]:
|
elif tree.label not in ["DefMethod"]:
|
||||||
super().visit_topdown(tree)
|
super().visit_topdown(tree)
|
||||||
|
|
||||||
|
class GenerateBinaryVisitor(Visitor):
|
||||||
|
def __init__(self):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __format_length(length):
|
||||||
|
assert length <= 0x0FFFFFFF
|
||||||
|
if length <= 0x3F:
|
||||||
|
return length.to_bytes(1, sys.byteorder)
|
||||||
|
else:
|
||||||
|
first_byte_value = length & 0xF
|
||||||
|
rest_byte_value = length >> 4
|
||||||
|
if rest_byte_value <= 0xFF:
|
||||||
|
first_byte = (first_byte_value + (1 << 6)).to_bytes(1, sys.byteorder)
|
||||||
|
rest_bytes = rest_byte_value.to_bytes(1, sys.byteorder)
|
||||||
|
elif rest_byte_value <= 0xFFFF:
|
||||||
|
first_byte = (first_byte_value + (2 << 6)).to_bytes(1, sys.byteorder)
|
||||||
|
rest_bytes = rest_byte_value.to_bytes(2, sys.byteorder)
|
||||||
|
else:
|
||||||
|
first_byte = (first_byte_value + (3 << 6)).to_bytes(1, sys.byteorder)
|
||||||
|
rest_bytes = rest_byte_value.to_bytes(3, sys.byteorder)
|
||||||
|
return first_byte + rest_bytes
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def __format_pkg_length(length):
|
||||||
|
assert length <= 0x0FFFFFFB
|
||||||
|
if length <= 0x3E:
|
||||||
|
length += 1
|
||||||
|
elif length <= 0x0FFD:
|
||||||
|
length += 2
|
||||||
|
elif length <= 0x0FFFFC:
|
||||||
|
length += 3
|
||||||
|
else:
|
||||||
|
length += 4
|
||||||
|
return GenerateBinaryVisitor.__format_length(length)
|
||||||
|
|
||||||
|
def generate(self, tree):
|
||||||
|
self.acc = []
|
||||||
|
self.visit(tree)
|
||||||
|
assert len(self.acc) == 1
|
||||||
|
return self.acc.pop()
|
||||||
|
|
||||||
|
def ByteData(self, tree):
|
||||||
|
self.acc.append(tree.value.to_bytes(1, sys.byteorder))
|
||||||
|
|
||||||
|
def WordData(self, tree):
|
||||||
|
self.acc.append(tree.value.to_bytes(2, sys.byteorder))
|
||||||
|
|
||||||
|
def DWordData(self, tree):
|
||||||
|
self.acc.append(tree.value.to_bytes(4, sys.byteorder))
|
||||||
|
|
||||||
|
def TWordData(self, tree):
|
||||||
|
self.acc.append(tree.value.to_bytes(6, sys.byteorder))
|
||||||
|
|
||||||
|
def QWordData(self, tree):
|
||||||
|
self.acc.append(tree.value.to_bytes(8, sys.byteorder))
|
||||||
|
|
||||||
|
def NameSeg(self, tree):
|
||||||
|
name = tree.value[:4]
|
||||||
|
if len(name) < 4:
|
||||||
|
name += ("_" * (4 - len(name)))
|
||||||
|
self.acc.append(bytes(name, "ascii"))
|
||||||
|
|
||||||
|
def NameString(self, tree):
|
||||||
|
acc = bytearray()
|
||||||
|
segs = tree.value.lstrip("^\\")
|
||||||
|
if len(segs) < len(tree.value):
|
||||||
|
acc.extend(bytes(tree.value[:len(tree.value) - len(segs)], "ascii"))
|
||||||
|
if segs:
|
||||||
|
nr_dots = segs.count(".")
|
||||||
|
if nr_dots == 1:
|
||||||
|
acc.append(grammar.AML_DUAL_NAME_PREFIX)
|
||||||
|
elif nr_dots >= 2:
|
||||||
|
acc.append(grammar.AML_MULTI_NAME_PREFIX)
|
||||||
|
acc.append(nr_dots + 1)
|
||||||
|
acc.extend(bytes(segs.replace(".", ""), "ascii"))
|
||||||
|
else:
|
||||||
|
acc.append(grammar.AML_NULL_NAME)
|
||||||
|
self.acc.append(acc)
|
||||||
|
|
||||||
|
def String(self, tree):
|
||||||
|
acc = bytearray()
|
||||||
|
acc.append(grammar.AML_STRING_PREFIX)
|
||||||
|
acc.extend(bytes(tree.value, "latin-1"))
|
||||||
|
acc.append(0)
|
||||||
|
self.acc.append(acc)
|
||||||
|
|
||||||
|
def ByteList(self, tree):
|
||||||
|
self.acc.append(tree.value)
|
||||||
|
|
||||||
|
def PkgLength(self, tree):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def FieldLength(self, tree):
|
||||||
|
self.acc.append(self.__format_length(tree.value))
|
||||||
|
|
||||||
|
def default(self, tree):
|
||||||
|
assert tree.structure and isinstance(tree.structure, tuple)
|
||||||
|
assert tree.structure != ("value",), f"{tree.label} is not expected to be handled by the default handler"
|
||||||
|
|
||||||
|
parts = []
|
||||||
|
for child in reversed(tree.children):
|
||||||
|
if child.label == "PkgLength":
|
||||||
|
if tree.label == "DefIfElse" and tree.DefElse:
|
||||||
|
# The last component of a DefIfElse clause (i.e. DefElse) is not counted by the PkgLength of the
|
||||||
|
# DefIfElse.
|
||||||
|
length = sum(map(len, parts[1:]))
|
||||||
|
else:
|
||||||
|
length = sum(map(len, parts))
|
||||||
|
parts.append(self.__format_pkg_length(length))
|
||||||
|
else:
|
||||||
|
parts.append(self.acc.pop())
|
||||||
|
if isinstance(tree.structure[0], int):
|
||||||
|
opcode = tree.structure[0]
|
||||||
|
if opcode <= 0xFF:
|
||||||
|
parts.append(opcode.to_bytes(1, sys.byteorder))
|
||||||
|
else:
|
||||||
|
parts.append(opcode.to_bytes(2, sys.byteorder))
|
||||||
|
|
||||||
|
self.acc.append(b''.join(reversed(parts)))
|
||||||
|
@ -21,7 +21,6 @@ def DSDT(val):
|
|||||||
tables = [val] + list(map(lambda x: os.path.join(table_dir, x), ssdt))
|
tables = [val] + list(map(lambda x: os.path.join(table_dir, x), ssdt))
|
||||||
|
|
||||||
context = Context()
|
context = Context()
|
||||||
trees = []
|
|
||||||
try:
|
try:
|
||||||
for t in tables:
|
for t in tables:
|
||||||
logging.info(f"Loading {t}")
|
logging.info(f"Loading {t}")
|
||||||
@ -29,13 +28,13 @@ def DSDT(val):
|
|||||||
tree = Tree()
|
tree = Tree()
|
||||||
AMLCode.parse(context, tree)
|
AMLCode.parse(context, tree)
|
||||||
tree = DeferredExpansion(context).transform_topdown(tree)
|
tree = DeferredExpansion(context).transform_topdown(tree)
|
||||||
trees.append(tree)
|
context.trees[os.path.basename(t)] = tree
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
context.current_stream.dump()
|
context.current_stream.dump()
|
||||||
raise
|
raise
|
||||||
|
|
||||||
context.skip_external_on_lookup()
|
context.skip_external_on_lookup()
|
||||||
visitor = ConditionallyUnregisterSymbolVisitor(ConcreteInterpreter(context))
|
visitor = ConditionallyUnregisterSymbolVisitor(ConcreteInterpreter(context))
|
||||||
for tree in trees:
|
for tree in context.trees.values():
|
||||||
visitor.visit_topdown(tree)
|
visitor.visit_topdown(tree)
|
||||||
return context
|
return context
|
||||||
|
Loading…
Reference in New Issue
Block a user