256 lines
7.2 KiB
Python
256 lines
7.2 KiB
Python
import os
|
|
import copy
|
|
import subprocess
|
|
from typing import List, Optional, Callable
|
|
from utilities.asl import ASL, ASLSource
|
|
|
|
|
|
ACPICA_BUFFER_PRINT_PREFIX = " 0000: "
|
|
|
|
|
|
def _parse_acpiexec_buffers(raw_output: str) -> List[List[int]]:
|
|
lines = raw_output.split("\n")
|
|
answers = []
|
|
|
|
for i, line in enumerate(lines):
|
|
if "Evaluating" in line:
|
|
lines = lines[i + 1:]
|
|
break
|
|
|
|
for line in lines:
|
|
if not line.startswith(ACPICA_BUFFER_PRINT_PREFIX):
|
|
continue
|
|
|
|
line = line.removeprefix(ACPICA_BUFFER_PRINT_PREFIX)
|
|
buffer_bytes = []
|
|
|
|
for x in line.split(" "):
|
|
# Buffers are printed out with ascii disassembly at the end.
|
|
# Skip as soon as we encounter empty space.
|
|
if x == "":
|
|
break
|
|
|
|
buffer_bytes.append(int(x, base=16))
|
|
|
|
answers.append(buffer_bytes)
|
|
|
|
return answers
|
|
|
|
|
|
def _generate_for_each_bit_combination(
|
|
src: ASLSource, per_combo_cb: Callable,
|
|
final_cb: Optional[Callable] = None
|
|
) -> None:
|
|
methods = []
|
|
|
|
for i in range(0, 64):
|
|
method_name = f"FT{i}"
|
|
methods.append(method_name)
|
|
|
|
src.l(ASL.method(method_name))
|
|
src.block_begin()
|
|
|
|
for j in range(0, 65):
|
|
if (i >= j):
|
|
continue
|
|
|
|
per_combo_cb(i, j, src)
|
|
|
|
src.block_end()
|
|
|
|
src.l(ASL.method("MAIN"))
|
|
src.block_begin()
|
|
for method in methods:
|
|
src.l(ASL.invoke(method))
|
|
|
|
if final_cb is not None:
|
|
final_cb(src)
|
|
|
|
src.block_end()
|
|
src.finalize()
|
|
|
|
|
|
_READS_ANSWERS_NAME = "buffer-reads-answers"
|
|
_WRITES_ANSWERS_NAME = "buffer-writes-answers"
|
|
|
|
|
|
def _generate_buffer_reads_answers(
|
|
compiler: str, bin_dir: str, src: ASLSource
|
|
) -> List[List[int]]:
|
|
output_path = os.path.join(bin_dir, _READS_ANSWERS_NAME + ".aml")
|
|
if not os.path.exists(output_path):
|
|
_do_generate_buffer_reads_answers(compiler, bin_dir, src)
|
|
|
|
raw_answers = subprocess.check_output(
|
|
["acpiexec", "-b", "execute MAIN", output_path],
|
|
universal_newlines=True
|
|
)
|
|
return _parse_acpiexec_buffers(raw_answers)
|
|
|
|
|
|
def _generate_buffer_writes_answers(
|
|
compiler: str, bin_dir: str, src: ASLSource
|
|
) -> List[List[int]]:
|
|
output_path = os.path.join(bin_dir, _WRITES_ANSWERS_NAME + ".aml")
|
|
if not os.path.exists(output_path):
|
|
_do_generate_buffer_writes_answers(compiler, bin_dir, src)
|
|
|
|
raw_answers = subprocess.check_output(
|
|
["acpiexec", "-b", "execute MAIN", output_path],
|
|
universal_newlines=True
|
|
)
|
|
return _parse_acpiexec_buffers(raw_answers)
|
|
|
|
|
|
def _do_generate_buffer_reads_answers(
|
|
compiler: str, bin_dir: str, src: ASLSource
|
|
) -> None:
|
|
def gen_buffer_dump(i, j, src):
|
|
field_size = j - i
|
|
field_name = f"FI{field_size:02X}"
|
|
|
|
src.l(ASL.create_field("BUFF", i, field_size, field_name))
|
|
src.l(ASL.assign("Debug", field_name))
|
|
|
|
_generate_for_each_bit_combination(src, gen_buffer_dump)
|
|
|
|
answers_src_path = os.path.join(bin_dir, _READS_ANSWERS_NAME + ".asl")
|
|
src.dump(answers_src_path)
|
|
ASLSource.compile(answers_src_path, compiler, bin_dir)
|
|
|
|
|
|
def _do_generate_buffer_writes_answers(
|
|
compiler: str, bin_dir: str, src: ASLSource
|
|
) -> None:
|
|
def gen_buffer_dump(i, j, src):
|
|
field_size = j - i
|
|
field_name = f"FI{field_size:02X}"
|
|
|
|
src.l(ASL.create_field("BUFX", i, field_size, field_name))
|
|
src.l(ASL.assign(field_name, "BUFF"))
|
|
src.l(ASL.assign("Debug", field_name))
|
|
|
|
_generate_for_each_bit_combination(src, gen_buffer_dump)
|
|
|
|
writes_src_path = os.path.join(bin_dir, _WRITES_ANSWERS_NAME + ".asl")
|
|
src.dump(writes_src_path)
|
|
ASLSource.compile(writes_src_path, compiler, bin_dir)
|
|
|
|
|
|
_READS_TEST_NAME = "2080-buffer-reads"
|
|
_WRITES_TEST_NAME = "2080-buffer-writes"
|
|
|
|
|
|
def generate_buffer_reads_test(compiler: str, bin_dir: str) -> str:
|
|
output_path = os.path.join(bin_dir, _READS_TEST_NAME + ".asl")
|
|
if os.path.exists(output_path):
|
|
return output_path
|
|
|
|
return _do_generate_buffer_reads_test(compiler, bin_dir)
|
|
|
|
|
|
def generate_buffer_writes_test(compiler: str, bin_dir: str) -> str:
|
|
output_path = os.path.join(bin_dir, _WRITES_TEST_NAME + ".asl")
|
|
if os.path.exists(output_path):
|
|
return output_path
|
|
|
|
return _do_generate_buffer_writes_test(compiler, bin_dir)
|
|
|
|
|
|
def _generate_buffer_test_prologue() -> ASLSource:
|
|
src = ASLSource(2)
|
|
|
|
src.l(ASL.name(
|
|
"BUFF",
|
|
ASL.buffer([0xAC, 0x12, 0x42, 0xCA, 0xDE, 0xFF, 0xCB, 0xDD])
|
|
))
|
|
src.l(ASL.name(
|
|
"BUFX",
|
|
ASL.buffer(count=8)
|
|
))
|
|
|
|
return src
|
|
|
|
|
|
def _generate_buffer_test_harness(src: ASLSource) -> None:
|
|
src.l(ASL.name("FAIL", 0))
|
|
src.l(ASL.name("PASS", 0))
|
|
|
|
src.l(ASL.method("FDBG", 3))
|
|
src.block_begin()
|
|
src.l(ASL.assign("Debug", "Arg0"))
|
|
src.l(ASL.assign("Debug", "Arg1"))
|
|
src.l(ASL.assign("Debug", "Arg2"))
|
|
src.l(ASL.increment("FAIL"))
|
|
src.block_end()
|
|
|
|
|
|
def _do_generate_buffer_reads_test(compiler: str, bin_dir: str) -> str:
|
|
src = _generate_buffer_test_prologue()
|
|
answers = _generate_buffer_reads_answers(compiler, bin_dir,
|
|
copy.deepcopy(src))
|
|
|
|
_generate_buffer_test_harness(src)
|
|
|
|
answer_idx = 0
|
|
|
|
def gen_buffer_check(i, j, src):
|
|
nonlocal answer_idx
|
|
field_size = j - i
|
|
field_name = f"FI{field_size:02X}"
|
|
|
|
src.l(ASL.create_field("BUFF", i, field_size, field_name))
|
|
src.iff(ASL.equal(field_name, ASL.buffer(answers[answer_idx])))
|
|
answer_idx += 1
|
|
src.l(ASL.increment("PASS"))
|
|
src.elsee()
|
|
src.l(ASL.invoke("FDBG", [
|
|
field_name, "__LINE__", f'"{field_name}"'
|
|
]))
|
|
src.block_end()
|
|
|
|
_generate_for_each_bit_combination(src, gen_buffer_check,
|
|
lambda src: src.l(ASL.returnn("FAIL")))
|
|
|
|
test_src_path = os.path.join(bin_dir, _READS_TEST_NAME + ".asl")
|
|
src.dump_as_test_case(test_src_path, "Reads from buffer fields",
|
|
"int", "0")
|
|
|
|
return test_src_path
|
|
|
|
|
|
def _do_generate_buffer_writes_test(compiler: str, bin_dir: str) -> str:
|
|
src = _generate_buffer_test_prologue()
|
|
answers = _generate_buffer_writes_answers(compiler, bin_dir,
|
|
copy.deepcopy(src))
|
|
|
|
_generate_buffer_test_harness(src)
|
|
|
|
answer_idx = 0
|
|
|
|
def gen_buffer_check(i, j, src):
|
|
nonlocal answer_idx
|
|
field_size = j - i
|
|
field_name = f"FI{field_size:02X}"
|
|
|
|
src.l(ASL.create_field("BUFX", i, field_size, field_name))
|
|
src.l(ASL.assign(field_name, "BUFF"))
|
|
src.iff(ASL.equal(field_name, ASL.buffer(answers[answer_idx])))
|
|
answer_idx += 1
|
|
src.l(ASL.increment("PASS"))
|
|
src.elsee()
|
|
src.l(ASL.invoke("FDBG", [
|
|
field_name, "__LINE__", f'"{field_name}"'
|
|
]))
|
|
src.block_end()
|
|
src.l(ASL.assign("BUFX", 0))
|
|
|
|
_generate_for_each_bit_combination(src, gen_buffer_check,
|
|
lambda src: src.l(ASL.returnn("FAIL")))
|
|
|
|
test_src_path = os.path.join(bin_dir, _WRITES_TEST_NAME + ".asl")
|
|
src.dump_as_test_case(test_src_path, "Writes to buffer fields",
|
|
"int", "0")
|
|
|
|
return test_src_path
|