diff --git a/misc/config_tools/board_inspector/acpiparser/aml/builder.py b/misc/config_tools/board_inspector/acpiparser/aml/builder.py new file mode 100644 index 000000000..543af45f7 --- /dev/null +++ b/misc/config_tools/board_inspector/acpiparser/aml/builder.py @@ -0,0 +1,140 @@ +# Copyright (C) 2021 Intel Corporation. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +from . import grammar +from . import datatypes +from .tree import Tree + +### Basic data types + +def __build_value(label, value): + tree = Tree(label, [value]) + tree.register_structure(("value",)) + tree.complete_parsing() + return tree + +def __build_string(label, s): + assert isinstance(s, str) + return __build_value(label, s) + +def __build_const_data(label, data): + assert isinstance(data, int) + return __build_value(label, data) + +NameSeg = lambda x: __build_string("NameSeg", x) +NameString = lambda x: __build_string("NameString", x) +String = lambda x: __build_string("String", x) + +def ByteList(data): + assert isinstance(data, (bytes, bytearray)) + return __build_value("ByteList", data) + +ByteData = lambda x: __build_const_data("ByteData", x) +WordData = lambda x: __build_const_data("WordData", x) +DWordData = lambda x: __build_const_data("DWordData", x) +TWordData = lambda x: __build_const_data("TWordData", x) +QWordData = lambda x: __build_const_data("QWordData", x) + +def PkgLength(length=0): + return __build_const_data("PkgLength", length) + +FieldLength = lambda x: __build_const_data("FieldLength", x) + +### Sequences + +def MethodInvocation(name, *args): + if isinstance(name, str): + name_tree = NameString(name) + else: + name_tree = name + tree = Tree("MethodInvocation", [name]) + for arg in args: + assert isinstance(arg, Tree) + tree.append_child(arg) + tree.register_structure(("NameString", "TermArg*")) + tree.complete_parsing() + return tree + +def __create_sequence_builder(label): + def aux(tree, elem, arg): + if isinstance(arg, Tree): + # TODO: validate the given arg + tree.append_child(arg) + else: + tree.append_child(globals()[elem](arg)) + + seq = grammar.get_definition(label) + structure = grammar.get_names(label) + + def fn(*args): + tree = Tree(label) + it = iter(args) + for elem in seq: + if isinstance(elem, int): # The leading opcode + continue + elif elem.endswith("*"): + for arg in it: + aux(tree, elem, arg) + elif elem.endswith("?"): + try: + aux(tree, elem, next(it)) + except StopIteration: + pass + else: + aux(tree, elem, next(it)) + tree.register_structure(structure) + tree.complete_parsing() + return tree + return fn + +def build_value(value): + if isinstance(value, (int, datatypes.Integer)): + if isinstance(value, int): + value = datatypes.Integer(value) + v = value.get() + return \ + ZeroOp() if v == 0 else \ + OneOp() if v == 1 else \ + ByteConst(v) if v <= 0xff else \ + WordConst(v) if v <= 0xffff else \ + DWordConst(v) if v <= 0xffffffff else \ + QWordConst(v) + elif isinstance(value, datatypes.Buffer): + buffer_size = len(value.get()) + builder = ByteConst if buffer_size <= 0xff else \ + WordConst if buffer_size <= 0xffff else \ + DWordConst if buffer_size <= 0xffffffff else \ + QWordConst + return DefBuffer( + PkgLength(), + builder(buffer_size), + ByteList(value.get())) + elif isinstance(value, datatypes.Package): + elements = list(map(build_value, value.elements)) + return DefPackage( + PkgLength(), + len(value.elements), + PackageElementList(elements)) + elif isinstance(value, (str, datatypes.String)): + if isinstance(value, str): + return String(value) + else: + return String(value.get()) + elif isinstance(value, datatypes.BufferField): + return build_value(value.to_integer()) + else: + return None + +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): + globals()[sym] = __create_sequence_builder(sym) + elif isinstance(definition, list) and len(definition) == 1: + if definition[0] in globals().keys(): + globals()[sym] = globals()[definition[0]] diff --git a/misc/config_tools/board_inspector/acpiparser/aml/interpreter.py b/misc/config_tools/board_inspector/acpiparser/aml/interpreter.py index 4238ac477..37d41c941 100644 --- a/misc/config_tools/board_inspector/acpiparser/aml/interpreter.py +++ b/misc/config_tools/board_inspector/acpiparser/aml/interpreter.py @@ -6,6 +6,7 @@ from .context import * from .datatypes import * from .tree import Tree, Interpreter +from . import builder class MethodReturn(Exception): """ A pseudo exception to return from a method""" @@ -86,13 +87,18 @@ class ConcreteInterpreter(Interpreter): def interpret_method_call(self, name, *args): stack_depth_before = len(self.stack) - name_string = Tree("NameString", [name]) - name_string.register_structure(("value",)) - name_string.complete_parsing() + name_string = builder.NameString(name) name_string.scope = self.context.parent(name) - pseudo_invocation = Tree("MethodInvocation", [name_string]) - pseudo_invocation.register_structure(("NameString", "TermArg*")) - pseudo_invocation.complete_parsing() + + arg_trees = [] + for arg in args: + v = builder.build_value(arg) + if v != None: + arg_trees.append(v) + else: + raise NotImplementedError(f"Unsupported type of method argument: {arg}") + + pseudo_invocation = builder.MethodInvocation(name_string, *arg_trees) try: val = self.interpret(pseudo_invocation) except: