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