Integrate uACPI
This commit is contained in:
@ -0,0 +1,255 @@
|
||||
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
|
476
kernel/hal/x86_64/uACPI/tests/run_tests.py
Executable file
476
kernel/hal/x86_64/uACPI/tests/run_tests.py
Executable file
@ -0,0 +1,476 @@
|
||||
#!/usr/bin/python3
|
||||
import subprocess
|
||||
import argparse
|
||||
import os
|
||||
import sys
|
||||
import time
|
||||
import platform
|
||||
from multiprocessing import Manager, Pool, Queue
|
||||
from typing import List, Tuple, Optional
|
||||
from types import TracebackType
|
||||
from abc import ABC, abstractmethod
|
||||
|
||||
from utilities.asl import ASLSource
|
||||
import generated_test_cases.buffer_field as bf
|
||||
|
||||
|
||||
def abs_path_to_current_dir() -> str:
|
||||
return os.path.dirname(os.path.abspath(__file__))
|
||||
|
||||
|
||||
def generate_test_cases(compiler: str, bin_dir: str) -> List[str]:
|
||||
return [
|
||||
bf.generate_buffer_reads_test(compiler, bin_dir),
|
||||
bf.generate_buffer_writes_test(compiler, bin_dir),
|
||||
]
|
||||
|
||||
|
||||
ACPI_DUMPS_URL = "https://github.com/UltraOS/ACPIDumps.git"
|
||||
|
||||
|
||||
class TestCase(ABC):
|
||||
def __init__(self, path: str, name: str):
|
||||
self.path = path
|
||||
self.name = name
|
||||
|
||||
@abstractmethod
|
||||
def extra_runner_args(self) -> List[str]:
|
||||
pass
|
||||
|
||||
|
||||
class BarebonesTestCase(TestCase):
|
||||
def __init__(
|
||||
self, name: str
|
||||
) -> None:
|
||||
super().__init__(name, name)
|
||||
|
||||
def extra_runner_args(self) -> List[str]:
|
||||
return []
|
||||
|
||||
|
||||
class TestCaseWithMain(TestCase):
|
||||
def __init__(
|
||||
self, path: str, name: str, rtype: str, value: str
|
||||
) -> None:
|
||||
super().__init__(path, f"{os.path.basename(path)}:{name}")
|
||||
self.rtype = rtype
|
||||
self.value = value
|
||||
|
||||
def extra_runner_args(self) -> List[str]:
|
||||
return ["--expect", self.rtype, self.value]
|
||||
|
||||
|
||||
class TestCaseHardwareBlob(TestCase):
|
||||
def __init__(self, path: str) -> None:
|
||||
dsdt_path = os.path.join(path, "dsdt.dat")
|
||||
super().__init__(dsdt_path, os.path.basename(path))
|
||||
|
||||
self.ssdt_paths = [
|
||||
path for path in os.listdir(path)
|
||||
if path.startswith("ssdt") and path.endswith(".dat")
|
||||
]
|
||||
|
||||
def extract_ssdt_number(path: str) -> int:
|
||||
number = ""
|
||||
|
||||
assert path.startswith("ssdt")
|
||||
for c in path[4:]:
|
||||
if not c.isdigit():
|
||||
break
|
||||
number += c
|
||||
|
||||
# some blobs apparently come with just "ssdt.dat" and not
|
||||
# "ssdtX.dat", take that into account here.
|
||||
return 0 if not number else int(number)
|
||||
|
||||
if self.ssdt_paths:
|
||||
self.ssdt_paths.sort(key=extract_ssdt_number)
|
||||
self.ssdt_paths = [
|
||||
os.path.join(path, ssdt_path) for ssdt_path in self.ssdt_paths
|
||||
]
|
||||
|
||||
def extra_runner_args(self) -> List[str]:
|
||||
args = ["--enumerate-namespace"]
|
||||
|
||||
if self.ssdt_paths:
|
||||
args.append("--extra-tables")
|
||||
args.extend(self.ssdt_paths)
|
||||
|
||||
return args
|
||||
|
||||
|
||||
def generate_large_test_cases(extractor: str, bin_dir: str) -> List[TestCase]:
|
||||
acpi_dumps_dir = os.path.join(abs_path_to_current_dir(), "acpi-dumps")
|
||||
large_tests_dir = os.path.join(bin_dir, "large-tests")
|
||||
|
||||
if not os.path.exists(acpi_dumps_dir):
|
||||
subprocess.check_call(["git", "clone", ACPI_DUMPS_URL, acpi_dumps_dir])
|
||||
|
||||
os.makedirs(large_tests_dir, exist_ok=True)
|
||||
test_cases = []
|
||||
|
||||
def recurse_one(path, depth=1):
|
||||
for obj in os.listdir(path):
|
||||
if obj.startswith("."):
|
||||
continue
|
||||
|
||||
obj_path = os.path.join(path, obj)
|
||||
|
||||
if os.path.isdir(obj_path):
|
||||
recurse_one(obj_path, depth + 1)
|
||||
continue
|
||||
|
||||
if depth == 1 or not obj.endswith(".bin"):
|
||||
continue
|
||||
|
||||
print(f"Preparing HW blob {obj_path}...")
|
||||
|
||||
split_path = obj_path.split(os.path.sep)[-depth:]
|
||||
fixed_up_path = [
|
||||
seg.replace(" ", "_").lower() for seg in split_path
|
||||
]
|
||||
|
||||
test_case_name = "_".join(fixed_up_path).replace(".bin", "")
|
||||
this_test_dir = os.path.join(large_tests_dir, test_case_name)
|
||||
|
||||
if (not os.path.exists(this_test_dir) or not
|
||||
os.path.exists(os.path.join(this_test_dir, "dsdt.dat"))):
|
||||
os.makedirs(this_test_dir, exist_ok=True)
|
||||
|
||||
# These are two separate invocations because of a bug in
|
||||
# acpixtract where it exits with -1 when there isn't an SSDT
|
||||
# inside a blob, even though it's specified as optional in
|
||||
# code. Merge once https://github.com/acpica/acpica/pull/959
|
||||
# is shipped everywhere.
|
||||
subprocess.check_call(
|
||||
[extractor, "-sDSDT", obj_path], cwd=this_test_dir,
|
||||
stdout=subprocess.DEVNULL
|
||||
)
|
||||
subprocess.run(
|
||||
[extractor, "-sSSDT", obj_path], cwd=this_test_dir,
|
||||
stdout=subprocess.DEVNULL
|
||||
)
|
||||
|
||||
test_cases.append(TestCaseHardwareBlob(this_test_dir))
|
||||
|
||||
recurse_one(acpi_dumps_dir)
|
||||
return test_cases
|
||||
|
||||
|
||||
def get_case_name_and_expected_result(case: str) -> Tuple[str, str, str]:
|
||||
with open(case) as tc:
|
||||
name = tc.readline()
|
||||
name = name[name.find(":") + 1:].strip()
|
||||
|
||||
expected_line = tc.readline()
|
||||
expected_line = expected_line[expected_line.find(":") + 1:].strip()
|
||||
expected = [val.strip() for val in expected_line.split("=>")]
|
||||
|
||||
return name, expected[0], expected[1]
|
||||
|
||||
|
||||
class TestHeaderFooter:
|
||||
def __init__(self, text: str) -> None:
|
||||
self.hdr = "{:=^80}".format(" " + text + " ")
|
||||
|
||||
def __enter__(self) -> None:
|
||||
print(self.hdr, flush=True)
|
||||
|
||||
def __exit__(
|
||||
self, exc_type: Optional[type[BaseException]],
|
||||
ex: Optional[BaseException], traceback: Optional[TracebackType]
|
||||
) -> Optional[bool]:
|
||||
print("=" * len(self.hdr), flush=True)
|
||||
return None
|
||||
|
||||
|
||||
def run_resource_tests(runner: str) -> int:
|
||||
with TestHeaderFooter("Resource Conversion Tests"):
|
||||
return subprocess.run([runner, "resource-tests"]).returncode
|
||||
|
||||
|
||||
def compile_test_cases(
|
||||
test_cases: List[str], compiler: str, bin_dir: str
|
||||
) -> List[TestCase]:
|
||||
compiled_cases: List[TestCase] = []
|
||||
|
||||
for case in test_cases:
|
||||
print(f"Compiling {case}...", end="")
|
||||
|
||||
# Skip the table loading test for old iASL, it prints bogus error
|
||||
# messages and refuses to compile the test case no matter what I try:
|
||||
#
|
||||
# If (!Load(TABL)) {
|
||||
# Error 6126 - syntax error ^
|
||||
#
|
||||
if os.path.basename(case) == "table-loading-0.asl":
|
||||
out = subprocess.check_output([compiler, "-v"],
|
||||
universal_newlines=True)
|
||||
# I don't know which versions it's broken for specifically, this
|
||||
# one comes with Ubuntu 22.04, so hardcode it.
|
||||
if "20200925" in out:
|
||||
print("SKIPPED (bugged iASL)", flush=True)
|
||||
continue
|
||||
|
||||
compiled_cases.append(
|
||||
TestCaseWithMain(
|
||||
ASLSource.compile(case, compiler, bin_dir),
|
||||
*get_case_name_and_expected_result(case)
|
||||
)
|
||||
)
|
||||
print("")
|
||||
|
||||
return compiled_cases
|
||||
|
||||
|
||||
def run_single_test(case: TestCase, results: Queue, runner: str) -> bool:
|
||||
timeout = False
|
||||
start_time = time.time()
|
||||
proc = subprocess.Popen(
|
||||
[runner, case.path, *case.extra_runner_args()],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE,
|
||||
universal_newlines=True
|
||||
)
|
||||
|
||||
try:
|
||||
stdout, stderr = proc.communicate(timeout=60)
|
||||
elapsed_time = time.time() - start_time
|
||||
except subprocess.TimeoutExpired:
|
||||
proc.kill()
|
||||
stdout, stderr = proc.communicate()
|
||||
timeout = True
|
||||
|
||||
elapsed_time = time.time() - start_time
|
||||
|
||||
if proc.returncode == 0:
|
||||
results.put((True, case, elapsed_time))
|
||||
return True
|
||||
else:
|
||||
results.put((False, case, elapsed_time, stdout, stderr, timeout))
|
||||
return False
|
||||
|
||||
|
||||
def run_tests(cases: List[TestCase], runner: str, parallelism: int) -> bool:
|
||||
pass_count = 0
|
||||
fail_count = 0
|
||||
start_time = time.time()
|
||||
|
||||
def print_test_header(case: TestCase, success: bool, timeout: bool,
|
||||
elapsed: float) -> None:
|
||||
status_str = "OK" if success else "TIMEOUT" if timeout else "FAILED"
|
||||
|
||||
print(f"[{pass_count}/{len(cases)}] {case.name} "
|
||||
f"{status_str} in {elapsed:.2f}s", flush=True)
|
||||
|
||||
def format_output(data: str) -> str:
|
||||
return "\n".join(["\t" + line for line in data.split("\n")])
|
||||
|
||||
with Pool(processes=parallelism) as pool:
|
||||
manager = Manager()
|
||||
result_queue = manager.Queue()
|
||||
|
||||
pool.starmap_async(run_single_test,
|
||||
[(case, result_queue, runner) for case in cases])
|
||||
|
||||
while pass_count + fail_count < len(cases):
|
||||
success, case, elapsed_time, *args = result_queue.get()
|
||||
|
||||
if success:
|
||||
pass_count += 1
|
||||
|
||||
print_test_header(case, True, False, elapsed_time)
|
||||
else:
|
||||
fail_count += 1
|
||||
stdout, stderr, timeout = args
|
||||
|
||||
print_test_header(case, False, timeout, elapsed_time)
|
||||
|
||||
stdout_output = format_output(stdout)
|
||||
stderr_output = format_output(stderr)
|
||||
|
||||
if stdout_output:
|
||||
print(f"STDOUT FOR {case.name}:", flush=True)
|
||||
print(stdout_output, flush=True)
|
||||
else:
|
||||
print(f"NO STDOUT FROM TEST {case.name}", flush=True)
|
||||
|
||||
if stderr_output:
|
||||
print(f"STDERR FOR {case.name}:", flush=True)
|
||||
print(stderr_output, flush=True)
|
||||
else:
|
||||
print(f"NO STDERR FROM TEST {case.name}", flush=True)
|
||||
|
||||
pool.close()
|
||||
pool.join()
|
||||
|
||||
elapsed_time = time.time() - start_time
|
||||
|
||||
print(f"SUMMARY: {pass_count}/{len(cases)} in {elapsed_time:.2f}s", end="")
|
||||
|
||||
if not fail_count:
|
||||
print(" (ALL PASS!)")
|
||||
else:
|
||||
print(f" ({fail_count} FAILED)")
|
||||
|
||||
return not fail_count
|
||||
|
||||
|
||||
def test_relpath(*args: str) -> str:
|
||||
return os.path.join(abs_path_to_current_dir(), *args)
|
||||
|
||||
|
||||
def platform_name_for_binary(binary: str) -> str:
|
||||
if platform.system() == "Windows":
|
||||
binary += ".exe"
|
||||
|
||||
return binary
|
||||
|
||||
|
||||
def test_runner_binary() -> str:
|
||||
return platform_name_for_binary("test-runner")
|
||||
|
||||
|
||||
def barebones_test_runner_binary() -> str:
|
||||
return platform_name_for_binary("barebones-test-runner")
|
||||
|
||||
|
||||
def build_test_runner(bitness: int, watcom: bool) -> Tuple[str, str]:
|
||||
build_dir = f"build-{platform.system().lower()}-{bitness}bits"
|
||||
|
||||
if watcom:
|
||||
build_dir = f"{build_dir}-watcom"
|
||||
|
||||
runner_build_dir = test_relpath("runner", build_dir)
|
||||
runner_exe = os.path.join(runner_build_dir, test_runner_binary())
|
||||
barebones_runner_exe = os.path.join(
|
||||
runner_build_dir, barebones_test_runner_binary()
|
||||
)
|
||||
use_ninja = False
|
||||
|
||||
if platform.system() != "Windows":
|
||||
try:
|
||||
subprocess.run(["ninja", "--version"], check=True,
|
||||
stdout=subprocess.DEVNULL)
|
||||
use_ninja = True
|
||||
except FileNotFoundError:
|
||||
pass
|
||||
|
||||
cmake_args: List[str] = ["cmake"]
|
||||
|
||||
if watcom:
|
||||
cmake_args.extend(["-G", "Watcom WMake"])
|
||||
elif use_ninja:
|
||||
cmake_args.extend(["-G", "Ninja"])
|
||||
|
||||
cmake_args.append("..")
|
||||
|
||||
if not watcom and bitness == 32:
|
||||
if platform.system() == "Windows":
|
||||
cmake_args.extend(["-A", "Win32"])
|
||||
else:
|
||||
cmake_args.extend([
|
||||
"-DCMAKE_CXX_FLAGS=-m32",
|
||||
"-DCMAKE_C_FLAGS=-m32"
|
||||
])
|
||||
|
||||
if not os.path.isdir(runner_build_dir):
|
||||
os.makedirs(runner_build_dir, exist_ok=True)
|
||||
subprocess.run(cmake_args, cwd=runner_build_dir, check=True)
|
||||
|
||||
subprocess.run(["cmake", "--build", "."], cwd=runner_build_dir, check=True)
|
||||
return barebones_runner_exe, runner_exe
|
||||
|
||||
|
||||
def main() -> int:
|
||||
parser = argparse.ArgumentParser(description="Run uACPI tests")
|
||||
parser.add_argument("--asl-compiler",
|
||||
help="Compiler to use to build test cases",
|
||||
default="iasl")
|
||||
parser.add_argument("--acpi-extractor",
|
||||
help="ACPI extractor utility to use for ACPI dumps",
|
||||
default="acpixtract")
|
||||
parser.add_argument("--test-dir",
|
||||
default=test_relpath("test-cases"),
|
||||
help="The directory to run tests from, defaults to "
|
||||
"'test-cases' in the same directory")
|
||||
parser.add_argument("--test-runner",
|
||||
help="The test runner binary to invoke")
|
||||
parser.add_argument("--barebones-test-runner",
|
||||
help="The barebones test runner binary to invoke")
|
||||
parser.add_argument("--binary-directory",
|
||||
default=test_relpath("bin"),
|
||||
help="The directory to store intermediate files in, "
|
||||
"created & deleted automatically. Defaults to "
|
||||
"'bin' in the same directory")
|
||||
parser.add_argument("--bitness", default=64, choices=[32, 64], type=int,
|
||||
help="uACPI build bitness")
|
||||
parser.add_argument("--large", action="store_true",
|
||||
help="Run the large test suite as well")
|
||||
parser.add_argument("--barebones", action="store_true",
|
||||
help="Run the barebones test suite as well")
|
||||
parser.add_argument("--parallelism", type=int,
|
||||
default=os.cpu_count() or 1,
|
||||
help="Number of test runners to run in parallel")
|
||||
parser.add_argument("--watcom", action="store_true",
|
||||
help="Use OpenWatcom to build test runners")
|
||||
args = parser.parse_args()
|
||||
|
||||
if args.watcom:
|
||||
args.bitness = 32
|
||||
|
||||
test_compiler = args.asl_compiler
|
||||
test_dir = args.test_dir
|
||||
test_runner = args.test_runner
|
||||
bare_test_runner = args.barebones_test_runner
|
||||
|
||||
if test_runner is None or (args.barebones and bare_test_runner is None):
|
||||
bare_runner_default, runner_default = build_test_runner(args.bitness,
|
||||
args.watcom)
|
||||
|
||||
if bare_test_runner is None:
|
||||
bare_test_runner = bare_runner_default
|
||||
if test_runner is None:
|
||||
test_runner = runner_default
|
||||
|
||||
ret = run_resource_tests(test_runner)
|
||||
if ret != 0:
|
||||
sys.exit(ret)
|
||||
|
||||
bin_dir = args.binary_directory
|
||||
os.makedirs(bin_dir, exist_ok=True)
|
||||
|
||||
test_cases = [
|
||||
os.path.join(test_dir, f)
|
||||
for f in os.listdir(test_dir)
|
||||
if os.path.splitext(f)[1] == ".asl"
|
||||
]
|
||||
test_cases.extend(generate_test_cases(test_compiler, bin_dir))
|
||||
|
||||
base_test_cases = compile_test_cases(
|
||||
test_cases, test_compiler, bin_dir
|
||||
)
|
||||
with TestHeaderFooter("AML Tests"):
|
||||
ret = run_tests(base_test_cases, test_runner, args.parallelism)
|
||||
|
||||
if ret and args.large:
|
||||
large_test_cases = generate_large_test_cases(
|
||||
args.acpi_extractor, bin_dir
|
||||
)
|
||||
|
||||
with TestHeaderFooter("Large AML Tests"):
|
||||
ret = run_tests(large_test_cases, test_runner, args.parallelism)
|
||||
|
||||
if ret and args.barebones:
|
||||
bare_cases: List[TestCase] = [
|
||||
BarebonesTestCase("basic-operation"),
|
||||
BarebonesTestCase("table-installation"),
|
||||
]
|
||||
|
||||
with TestHeaderFooter("Barebones Mode Tests"):
|
||||
ret = run_tests(bare_cases, bare_test_runner, args.parallelism)
|
||||
|
||||
sys.exit(not ret)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
1
kernel/hal/x86_64/uACPI/tests/runner/.gitignore
vendored
Normal file
1
kernel/hal/x86_64/uACPI/tests/runner/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
build-*
|
168
kernel/hal/x86_64/uACPI/tests/runner/CMakeLists.txt
Normal file
168
kernel/hal/x86_64/uACPI/tests/runner/CMakeLists.txt
Normal file
@ -0,0 +1,168 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(TestRunner C)
|
||||
|
||||
set(CMAKE_C_STANDARD 17)
|
||||
set(CMAKE_C_STANDARD_REQUIRED ON)
|
||||
|
||||
include(${CMAKE_CURRENT_SOURCE_DIR}/../../uacpi.cmake)
|
||||
|
||||
foreach(CONF_TYPE ${CMAKE_CONFIGURATION_TYPES})
|
||||
string(TOUPPER ${CONF_TYPE} CONF_TYPE)
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_${CONF_TYPE} ${CMAKE_BINARY_DIR})
|
||||
endforeach(CONF_TYPE ${CMAKE_CONFIGURATION_TYPES})
|
||||
|
||||
macro (define_test_runner NAME)
|
||||
add_executable(
|
||||
${NAME}
|
||||
${ARGN}
|
||||
)
|
||||
target_sources(
|
||||
${NAME}
|
||||
PRIVATE
|
||||
${UACPI_SOURCES}
|
||||
)
|
||||
|
||||
target_include_directories(
|
||||
${NAME}
|
||||
PRIVATE
|
||||
${UACPI_INCLUDES}
|
||||
)
|
||||
|
||||
if (WATCOM)
|
||||
# Address sanitizer doesn't exist on Watcom.
|
||||
target_compile_definitions(
|
||||
${NAME}
|
||||
PRIVATE
|
||||
_LINUX_SOURCE
|
||||
)
|
||||
target_compile_options(
|
||||
${NAME}
|
||||
PRIVATE
|
||||
-we -wx
|
||||
)
|
||||
elseif (MSVC)
|
||||
# Address sanitizer on MSVC depends on a dynamic library that is not present in
|
||||
# PATH by default. Lets just not enable it here.
|
||||
target_compile_options(
|
||||
${NAME}
|
||||
PRIVATE
|
||||
/W3 /WX
|
||||
/wd4200 /wd4267 /wd4244
|
||||
)
|
||||
else ()
|
||||
target_compile_definitions(
|
||||
${NAME}
|
||||
PRIVATE
|
||||
_GNU_SOURCE
|
||||
)
|
||||
target_compile_options(
|
||||
${NAME}
|
||||
PRIVATE
|
||||
-fsanitize=address,undefined -g3 -Wall -Wextra -Werror
|
||||
)
|
||||
target_link_options(
|
||||
${NAME}
|
||||
PRIVATE
|
||||
-fsanitize=address,undefined -g3
|
||||
)
|
||||
add_compile_options(
|
||||
$<$<COMPILE_LANGUAGE:C>:-Wstrict-prototypes>
|
||||
)
|
||||
endif ()
|
||||
endmacro ()
|
||||
|
||||
define_test_runner(
|
||||
test-runner
|
||||
test_runner.c
|
||||
helpers.c
|
||||
interface_impl.c
|
||||
resource_tests.c
|
||||
api_tests.c
|
||||
)
|
||||
find_package(Threads REQUIRED)
|
||||
target_link_libraries(test-runner PRIVATE Threads::Threads)
|
||||
|
||||
define_test_runner(
|
||||
barebones-test-runner
|
||||
helpers.c
|
||||
barebones_runner.c
|
||||
)
|
||||
target_compile_definitions(
|
||||
barebones-test-runner
|
||||
PRIVATE
|
||||
-DUACPI_BAREBONES_MODE
|
||||
)
|
||||
|
||||
if (NOT REDUCED_HARDWARE_BUILD)
|
||||
set(REDUCED_HARDWARE_BUILD 0)
|
||||
endif()
|
||||
|
||||
if (REDUCED_HARDWARE_BUILD)
|
||||
target_compile_definitions(
|
||||
test-runner
|
||||
PRIVATE
|
||||
-DUACPI_REDUCED_HARDWARE
|
||||
)
|
||||
endif ()
|
||||
|
||||
if (NOT DEFINED SIZED_FREES_BUILD)
|
||||
set(SIZED_FREES_BUILD 1)
|
||||
endif()
|
||||
|
||||
if (SIZED_FREES_BUILD)
|
||||
target_compile_definitions(
|
||||
test-runner
|
||||
PRIVATE
|
||||
-DUACPI_SIZED_FREES
|
||||
)
|
||||
endif ()
|
||||
|
||||
if (NOT FORMATTED_LOGGING_BUILD)
|
||||
set(FORMATTED_LOGGING_BUILD 0)
|
||||
endif()
|
||||
|
||||
if (FORMATTED_LOGGING_BUILD)
|
||||
target_compile_definitions(
|
||||
test-runner
|
||||
PRIVATE
|
||||
-DUACPI_FORMATTED_LOGGING
|
||||
)
|
||||
endif ()
|
||||
|
||||
|
||||
if (NOT NATIVE_ALLOC_ZEROED)
|
||||
set(NATIVE_ALLOC_ZEROED 0)
|
||||
endif()
|
||||
|
||||
if (NATIVE_ALLOC_ZEROED)
|
||||
target_compile_definitions(
|
||||
test-runner
|
||||
PRIVATE
|
||||
-DUACPI_NATIVE_ALLOC_ZEROED
|
||||
)
|
||||
endif ()
|
||||
|
||||
if (NOT KERNEL_INITIALIZATION)
|
||||
set(KERNEL_INITIALIZATION 1)
|
||||
endif()
|
||||
|
||||
if (KERNEL_INITIALIZATION)
|
||||
target_compile_definitions(
|
||||
test-runner
|
||||
PRIVATE
|
||||
-DUACPI_KERNEL_INITIALIZATION
|
||||
)
|
||||
endif ()
|
||||
|
||||
if (NOT BUILTIN_STRING)
|
||||
set(BUILTIN_STRING 0)
|
||||
endif()
|
||||
|
||||
if (BUILTIN_STRING)
|
||||
target_compile_definitions(
|
||||
test-runner
|
||||
PRIVATE
|
||||
-DUACPI_USE_BUILTIN_STRING
|
||||
)
|
||||
endif ()
|
475
kernel/hal/x86_64/uACPI/tests/runner/api_tests.c
Normal file
475
kernel/hal/x86_64/uACPI/tests/runner/api_tests.c
Normal file
@ -0,0 +1,475 @@
|
||||
#include "helpers.h"
|
||||
#include <inttypes.h>
|
||||
#include <string.h>
|
||||
#include <uacpi/opregion.h>
|
||||
#include <uacpi/resources.h>
|
||||
#include <uacpi/types.h>
|
||||
|
||||
static void check_ok(uacpi_object **objects, uacpi_object_array *arr)
|
||||
{
|
||||
uacpi_u64 ret;
|
||||
uacpi_status st = uacpi_eval_integer(UACPI_NULL, "CHEK", arr, &ret);
|
||||
|
||||
ensure_ok_status(st);
|
||||
if (!ret)
|
||||
error("integer check failed");
|
||||
uacpi_object_unref(objects[1]);
|
||||
}
|
||||
|
||||
void test_object_api(void)
|
||||
{
|
||||
uacpi_status st;
|
||||
uacpi_object_array arr;
|
||||
uacpi_object *objects[2];
|
||||
uacpi_data_view view;
|
||||
uacpi_object *tmp;
|
||||
uint8_t buffer[4] = { 0xDE, 0xAD, 0xBE, 0xEF };
|
||||
uacpi_object *pkg[3];
|
||||
uacpi_object_array arr1;
|
||||
|
||||
arr.objects = objects;
|
||||
arr.count = UACPI_ARRAY_SIZE(objects);
|
||||
objects[0] = uacpi_object_create_integer(1);
|
||||
|
||||
st = uacpi_object_create_integer_safe(
|
||||
0xDEADBEEFDEADBEEF, UACPI_OVERFLOW_DISALLOW, &objects[1]
|
||||
);
|
||||
if (st != UACPI_STATUS_INVALID_ARGUMENT)
|
||||
error("expected integer creation to fail");
|
||||
|
||||
objects[1] = uacpi_object_create_integer(0xDEADBEEF);
|
||||
check_ok(objects, &arr);
|
||||
|
||||
st = uacpi_object_assign_integer(objects[0], 2);
|
||||
ensure_ok_status(st);
|
||||
|
||||
objects[1] = uacpi_object_create_cstring("Hello World");
|
||||
uacpi_object_ref(objects[1]);
|
||||
check_ok(objects, &arr);
|
||||
|
||||
view.const_text = "Hello World";
|
||||
// Don't include the null byte to check if this is accounted for
|
||||
view.length = 11;
|
||||
|
||||
uacpi_object_assign_string(objects[1], view);
|
||||
check_ok(objects, &arr);
|
||||
|
||||
st = uacpi_object_assign_integer(objects[0], 3);
|
||||
ensure_ok_status(st);
|
||||
tmp = uacpi_object_create_cstring("XXXX");
|
||||
objects[1] = uacpi_object_create_reference(tmp);
|
||||
uacpi_object_unref(tmp);
|
||||
check_ok(objects, &arr);
|
||||
|
||||
st = uacpi_object_assign_integer(objects[0], 4);
|
||||
ensure_ok_status(st);
|
||||
view.const_bytes = buffer;
|
||||
view.length = sizeof(buffer);
|
||||
objects[1] = uacpi_object_create_buffer(view);
|
||||
check_ok(objects, &arr);
|
||||
|
||||
st = uacpi_object_assign_integer(objects[0], 5);
|
||||
ensure_ok_status(st);
|
||||
|
||||
pkg[0] = uacpi_object_create_uninitialized();
|
||||
view.const_text = "First Element";
|
||||
view.length = strlen(view.const_text);
|
||||
uacpi_object_assign_string(pkg[0], view);
|
||||
|
||||
pkg[1] = uacpi_object_create_cstring("test");
|
||||
st = uacpi_object_assign_integer(pkg[1], 2);
|
||||
ensure_ok_status(st);
|
||||
|
||||
buffer[0] = 1;
|
||||
buffer[1] = 2;
|
||||
buffer[2] = 3;
|
||||
view.const_bytes = buffer;
|
||||
view.length = 3;
|
||||
pkg[2] = uacpi_object_create_buffer(view);
|
||||
st = uacpi_object_assign_buffer(pkg[2], view);
|
||||
|
||||
arr1.objects = pkg;
|
||||
arr1.count = 3;
|
||||
objects[1] = uacpi_object_create_package(arr1);
|
||||
uacpi_object_assign_package(objects[1], arr1);
|
||||
check_ok(objects, &arr);
|
||||
uacpi_object_unref(pkg[0]);
|
||||
uacpi_object_unref(pkg[1]);
|
||||
uacpi_object_unref(pkg[2]);
|
||||
|
||||
uacpi_object_unref(objects[0]);
|
||||
}
|
||||
|
||||
#define CHECK_VALUE(x, y) \
|
||||
if ((x) != (y)) \
|
||||
error("check at %d failed", __LINE__);
|
||||
#define CHECK_STRING(x, y) \
|
||||
if (strcmp((x), (y))) \
|
||||
error("check at %d failed", __LINE__);
|
||||
|
||||
static void eval_one(uacpi_object *arg, uacpi_address_space type)
|
||||
{
|
||||
uacpi_object_array arr = { 0 };
|
||||
uacpi_u64 out_value;
|
||||
uacpi_status st;
|
||||
|
||||
arr.objects = &arg;
|
||||
arr.count = 1;
|
||||
|
||||
st = uacpi_object_assign_integer(arg, type);
|
||||
ensure_ok_status(st);
|
||||
st = uacpi_eval_integer(NULL, "CHEK", &arr, &out_value);
|
||||
ensure_ok_status(st);
|
||||
|
||||
if (!out_value)
|
||||
error("%s test failed", uacpi_address_space_to_string(type));
|
||||
}
|
||||
|
||||
static uacpi_status ipmi_handler(uacpi_region_op op, uacpi_handle op_data)
|
||||
{
|
||||
uacpi_region_ipmi_rw_data *ipmi = op_data;
|
||||
uint64_t response;
|
||||
const char *command;
|
||||
|
||||
if (op == UACPI_REGION_OP_ATTACH || op == UACPI_REGION_OP_DETACH)
|
||||
return UACPI_STATUS_OK;
|
||||
CHECK_VALUE(op, UACPI_REGION_OP_IPMI_COMMAND);
|
||||
|
||||
CHECK_VALUE(ipmi->in_out_message.length, 66);
|
||||
|
||||
command = ipmi->in_out_message.const_text;
|
||||
if (!strcmp(command, "IPMICommandDEADBEE0"))
|
||||
response = 0xDEADBEE0;
|
||||
else if (!strcmp(command, "IPMICommandDEADBEEF"))
|
||||
response = 0xDEADBEEF;
|
||||
else
|
||||
error("invalid IPMI command %s", command);
|
||||
|
||||
CHECK_VALUE(ipmi->command, response);
|
||||
|
||||
memcpy(ipmi->in_out_message.data, &response, sizeof(response));
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
static uacpi_status gpio_handler(uacpi_region_op op, uacpi_handle op_data)
|
||||
{
|
||||
uacpi_region_gpio_rw_data *rw_data = op_data;
|
||||
uacpi_resource *res;
|
||||
uacpi_status ret;
|
||||
uacpi_resource_gpio_connection *gpio;
|
||||
uacpi_namespace_node *gpio_node;
|
||||
uacpi_u64 bit_offset;
|
||||
uacpi_u64 *state;
|
||||
uacpi_u64 i;
|
||||
|
||||
switch (op) {
|
||||
case UACPI_REGION_OP_ATTACH: {
|
||||
uacpi_region_attach_data *att_data = op_data;
|
||||
|
||||
CHECK_VALUE(att_data->gpio_info.num_pins, 6);
|
||||
att_data->out_region_context = do_calloc(1, sizeof(uint64_t));
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
case UACPI_REGION_OP_DETACH: {
|
||||
uacpi_region_detach_data *det_data = op_data;
|
||||
|
||||
free(det_data->region_context);
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = uacpi_get_resource_from_buffer(rw_data->connection, &res);
|
||||
ensure_ok_status(ret);
|
||||
|
||||
CHECK_VALUE(res->type, UACPI_RESOURCE_TYPE_GPIO_CONNECTION);
|
||||
gpio = &res->gpio_connection;
|
||||
|
||||
ret = uacpi_namespace_node_find(NULL, gpio->source.string, &gpio_node);
|
||||
ensure_ok_status(ret);
|
||||
|
||||
ret = uacpi_eval_simple_integer(gpio_node, "_UID", &bit_offset);
|
||||
ensure_ok_status(ret);
|
||||
|
||||
bit_offset *= 16;
|
||||
state = rw_data->region_context;
|
||||
|
||||
if (rw_data->num_pins == 0 || rw_data->num_pins > 3)
|
||||
error("bogus number of pins %d", rw_data->num_pins);
|
||||
|
||||
if (op == UACPI_REGION_OP_GPIO_READ)
|
||||
rw_data->value = 0;
|
||||
|
||||
for (i = 0; i < rw_data->num_pins; ++i) {
|
||||
uint64_t abs_pin = i + rw_data->pin_offset;
|
||||
bool value;
|
||||
|
||||
if (op == UACPI_REGION_OP_GPIO_READ) {
|
||||
value = (*state >> bit_offset) & (1ull << abs_pin);
|
||||
|
||||
if (value)
|
||||
rw_data->value |= (1ull << i);
|
||||
} else {
|
||||
unsigned long long mask = 1ull << abs_pin;
|
||||
|
||||
CHECK_VALUE(op, UACPI_REGION_OP_GPIO_WRITE);
|
||||
value = rw_data->value & (1ull << i);
|
||||
|
||||
if (value)
|
||||
*state |= mask;
|
||||
else
|
||||
*state &= ~mask;
|
||||
}
|
||||
}
|
||||
|
||||
uacpi_free_resource(res);
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
static uacpi_status pcc_handler(uacpi_region_op op, uacpi_handle op_data)
|
||||
{
|
||||
uacpi_region_pcc_send_data *rw_data = op_data;
|
||||
uint32_t x;
|
||||
|
||||
if (op == UACPI_REGION_OP_ATTACH) {
|
||||
uacpi_region_attach_data *att_data = op_data;
|
||||
|
||||
CHECK_VALUE(att_data->pcc_info.buffer.length, 0xFF);
|
||||
CHECK_VALUE(att_data->pcc_info.subspace_id, 0xCA)
|
||||
|
||||
att_data->out_region_context = att_data->pcc_info.buffer.data;
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
if (op == UACPI_REGION_OP_DETACH)
|
||||
return UACPI_STATUS_OK;
|
||||
CHECK_VALUE(op, UACPI_REGION_OP_PCC_SEND);
|
||||
|
||||
CHECK_VALUE(rw_data->buffer.data, rw_data->region_context);
|
||||
CHECK_STRING(rw_data->buffer.const_text, "HELLO");
|
||||
|
||||
memcpy(&x, rw_data->buffer.bytes + 12, sizeof(x));
|
||||
CHECK_VALUE(x, 0xDEADBEEF);
|
||||
|
||||
x = 0xBEEFDEAD;
|
||||
memcpy(rw_data->buffer.bytes + 12, &x, sizeof(x));
|
||||
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
static uacpi_status prm_handler(uacpi_region_op op, uacpi_handle op_data)
|
||||
{
|
||||
static const char response[] = "goodbyeworld";
|
||||
uacpi_region_prm_rw_data *rw_data = op_data;
|
||||
|
||||
if (op == UACPI_REGION_OP_ATTACH || op == UACPI_REGION_OP_DETACH)
|
||||
return UACPI_STATUS_OK;
|
||||
CHECK_VALUE(op, UACPI_REGION_OP_PRM_COMMAND);
|
||||
|
||||
CHECK_VALUE(rw_data->in_out_message.length, 26);
|
||||
CHECK_STRING(rw_data->in_out_message.const_text, "helloworld");
|
||||
|
||||
memcpy(rw_data->in_out_message.text, response, sizeof(response));
|
||||
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
static uacpi_status ffixedhw_handler(uacpi_region_op op, uacpi_handle op_data)
|
||||
{
|
||||
static const char response[] = "ok";
|
||||
uacpi_region_ffixedhw_rw_data *rw_data = op_data;
|
||||
|
||||
if (op == UACPI_REGION_OP_ATTACH) {
|
||||
uacpi_region_attach_data *att_data = op_data;
|
||||
|
||||
CHECK_VALUE(att_data->generic_info.base, 0xCAFEBABE);
|
||||
CHECK_VALUE(att_data->generic_info.length, 0xFEFECACA)
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
if (op == UACPI_REGION_OP_DETACH)
|
||||
return UACPI_STATUS_OK;
|
||||
CHECK_VALUE(op, UACPI_REGION_OP_FFIXEDHW_COMMAND);
|
||||
|
||||
CHECK_VALUE(rw_data->in_out_message.length, 256);
|
||||
CHECK_STRING(rw_data->in_out_message.const_text, "someguidandstuff");
|
||||
|
||||
memcpy(rw_data->in_out_message.text, "ok", sizeof(response));
|
||||
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
static uacpi_status generic_serial_bus_handler(
|
||||
uacpi_region_op op, uacpi_handle op_data
|
||||
)
|
||||
{
|
||||
uacpi_region_serial_rw_data *rw_data = op_data;
|
||||
uacpi_resource *res;
|
||||
uacpi_status ret;
|
||||
uacpi_resource_i2c_connection *gpio;
|
||||
uacpi_namespace_node *i2c_node;
|
||||
uacpi_u64 i2c_offset;
|
||||
uacpi_u16 response;
|
||||
|
||||
if (op == UACPI_REGION_OP_ATTACH || op == UACPI_REGION_OP_DETACH)
|
||||
return UACPI_STATUS_OK;
|
||||
CHECK_VALUE(
|
||||
true, (op == UACPI_REGION_OP_SERIAL_READ ||
|
||||
op == UACPI_REGION_OP_SERIAL_WRITE)
|
||||
);
|
||||
|
||||
ret = uacpi_get_resource_from_buffer(rw_data->connection, &res);
|
||||
ensure_ok_status(ret);
|
||||
|
||||
CHECK_VALUE(res->type, UACPI_RESOURCE_TYPE_SERIAL_I2C_CONNECTION);
|
||||
gpio = &res->i2c_connection;
|
||||
|
||||
ret = uacpi_namespace_node_find(
|
||||
NULL, gpio->common.source.string, &i2c_node
|
||||
);
|
||||
ensure_ok_status(ret);
|
||||
|
||||
ret = uacpi_eval_simple_integer(i2c_node, "_UID", &i2c_offset);
|
||||
ensure_ok_status(ret);
|
||||
|
||||
switch ((int)rw_data->command) {
|
||||
case 0x111:
|
||||
CHECK_VALUE(op, UACPI_REGION_OP_SERIAL_WRITE);
|
||||
CHECK_VALUE(i2c_offset, 0);
|
||||
CHECK_VALUE(rw_data->in_out_buffer.length, 2);
|
||||
CHECK_VALUE(rw_data->access_attribute, UACPI_ACCESS_ATTRIBUTE_QUICK);
|
||||
break;
|
||||
case 0x121:
|
||||
CHECK_VALUE(op, UACPI_REGION_OP_SERIAL_WRITE);
|
||||
CHECK_VALUE(i2c_offset, 0);
|
||||
CHECK_VALUE(rw_data->in_out_buffer.length, 3);
|
||||
CHECK_VALUE(
|
||||
rw_data->access_attribute, UACPI_ACCESS_ATTRIBUTE_SEND_RECEIVE
|
||||
);
|
||||
break;
|
||||
case 0x122:
|
||||
CHECK_VALUE(op, UACPI_REGION_OP_SERIAL_WRITE);
|
||||
CHECK_VALUE(i2c_offset, 0);
|
||||
CHECK_VALUE(rw_data->in_out_buffer.length, 3);
|
||||
CHECK_VALUE(rw_data->access_attribute, UACPI_ACCESS_ATTRIBUTE_BYTE);
|
||||
break;
|
||||
case 0x124:
|
||||
CHECK_VALUE(op, UACPI_REGION_OP_SERIAL_READ);
|
||||
CHECK_VALUE(i2c_offset, 0);
|
||||
CHECK_VALUE(rw_data->in_out_buffer.length, 4);
|
||||
CHECK_VALUE(rw_data->access_attribute, UACPI_ACCESS_ATTRIBUTE_WORD);
|
||||
break;
|
||||
case 0x128:
|
||||
CHECK_VALUE(op, UACPI_REGION_OP_SERIAL_READ);
|
||||
CHECK_VALUE(i2c_offset, 0);
|
||||
CHECK_VALUE(rw_data->in_out_buffer.length, 257);
|
||||
CHECK_VALUE(rw_data->access_attribute, UACPI_ACCESS_ATTRIBUTE_BLOCK);
|
||||
break;
|
||||
case 0x228:
|
||||
CHECK_VALUE(op, UACPI_REGION_OP_SERIAL_WRITE);
|
||||
CHECK_VALUE(i2c_offset, 0);
|
||||
CHECK_VALUE(rw_data->in_out_buffer.length, 4);
|
||||
CHECK_VALUE(
|
||||
rw_data->access_attribute, UACPI_ACCESS_ATTRIBUTE_PROCESS_CALL
|
||||
);
|
||||
break;
|
||||
case 0x229:
|
||||
CHECK_VALUE(op, UACPI_REGION_OP_SERIAL_READ);
|
||||
CHECK_VALUE(i2c_offset, 0);
|
||||
CHECK_VALUE(rw_data->in_out_buffer.length, 257);
|
||||
CHECK_VALUE(
|
||||
rw_data->access_attribute, UACPI_ACCESS_ATTRIBUTE_BLOCK_PROCESS_CALL
|
||||
);
|
||||
break;
|
||||
case 0x23B:
|
||||
CHECK_VALUE(op, UACPI_REGION_OP_SERIAL_WRITE);
|
||||
CHECK_VALUE(i2c_offset, 1);
|
||||
CHECK_VALUE(rw_data->in_out_buffer.length, 17);
|
||||
CHECK_VALUE(rw_data->access_attribute, UACPI_ACCESS_ATTRIBUTE_BYTES);
|
||||
CHECK_VALUE(rw_data->access_length, 15);
|
||||
break;
|
||||
case 0x23C:
|
||||
CHECK_VALUE(op, UACPI_REGION_OP_SERIAL_READ);
|
||||
CHECK_VALUE(i2c_offset, 1);
|
||||
CHECK_VALUE(rw_data->in_out_buffer.length, 257);
|
||||
CHECK_VALUE(
|
||||
rw_data->access_attribute, UACPI_ACCESS_ATTRIBUTE_RAW_BYTES
|
||||
);
|
||||
CHECK_VALUE(rw_data->access_length, 255);
|
||||
break;
|
||||
case 0x23D:
|
||||
CHECK_VALUE(op, UACPI_REGION_OP_SERIAL_READ);
|
||||
CHECK_VALUE(i2c_offset, 1);
|
||||
CHECK_VALUE(rw_data->in_out_buffer.length, 257);
|
||||
CHECK_VALUE(
|
||||
rw_data->access_attribute, UACPI_ACCESS_ATTRIBUTE_RAW_PROCESS_BYTES
|
||||
);
|
||||
CHECK_VALUE(rw_data->access_length, 123);
|
||||
break;
|
||||
default:
|
||||
error("bad serial command %" PRIu64, rw_data->command);
|
||||
}
|
||||
|
||||
if (op == UACPI_REGION_OP_SERIAL_WRITE) {
|
||||
uacpi_u16 value;
|
||||
|
||||
memcpy(&value, rw_data->in_out_buffer.const_bytes, sizeof(value));
|
||||
CHECK_VALUE(value, rw_data->command);
|
||||
}
|
||||
|
||||
response = rw_data->command + 1;
|
||||
memcpy(rw_data->in_out_buffer.bytes, &response, sizeof(response));
|
||||
|
||||
uacpi_free_resource(res);
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
void test_address_spaces(void)
|
||||
{
|
||||
uacpi_status st;
|
||||
uacpi_object *arg;
|
||||
|
||||
arg = uacpi_object_create_integer(0);
|
||||
|
||||
st = uacpi_install_address_space_handler(
|
||||
uacpi_namespace_root(), UACPI_ADDRESS_SPACE_IPMI, ipmi_handler, NULL
|
||||
);
|
||||
ensure_ok_status(st);
|
||||
eval_one(arg, UACPI_ADDRESS_SPACE_IPMI);
|
||||
|
||||
st = uacpi_install_address_space_handler(
|
||||
uacpi_namespace_root(), UACPI_ADDRESS_SPACE_GENERAL_PURPOSE_IO,
|
||||
gpio_handler, NULL
|
||||
);
|
||||
ensure_ok_status(st);
|
||||
eval_one(arg, UACPI_ADDRESS_SPACE_GENERAL_PURPOSE_IO);
|
||||
|
||||
st = uacpi_install_address_space_handler(
|
||||
uacpi_namespace_root(), UACPI_ADDRESS_SPACE_PCC, pcc_handler, NULL
|
||||
);
|
||||
ensure_ok_status(st);
|
||||
eval_one(arg, UACPI_ADDRESS_SPACE_PCC);
|
||||
|
||||
st = uacpi_install_address_space_handler(
|
||||
uacpi_namespace_root(), UACPI_ADDRESS_SPACE_PRM, prm_handler, NULL
|
||||
);
|
||||
ensure_ok_status(st);
|
||||
eval_one(arg, UACPI_ADDRESS_SPACE_PRM);
|
||||
|
||||
st = uacpi_install_address_space_handler(
|
||||
uacpi_namespace_root(), UACPI_ADDRESS_SPACE_FFIXEDHW, ffixedhw_handler,
|
||||
NULL
|
||||
);
|
||||
ensure_ok_status(st);
|
||||
eval_one(arg, UACPI_ADDRESS_SPACE_FFIXEDHW);
|
||||
|
||||
st = uacpi_install_address_space_handler(
|
||||
uacpi_namespace_root(), UACPI_ADDRESS_SPACE_GENERIC_SERIAL_BUS,
|
||||
generic_serial_bus_handler, NULL
|
||||
);
|
||||
ensure_ok_status(st);
|
||||
eval_one(arg, UACPI_ADDRESS_SPACE_GENERIC_SERIAL_BUS);
|
||||
|
||||
uacpi_object_unref(arg);
|
||||
}
|
219
kernel/hal/x86_64/uACPI/tests/runner/argparser.h
Normal file
219
kernel/hal/x86_64/uACPI/tests/runner/argparser.h
Normal file
@ -0,0 +1,219 @@
|
||||
#pragma once
|
||||
|
||||
#include "helpers.h"
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef enum {
|
||||
ARG_FLAG,
|
||||
ARG_PARAM,
|
||||
ARG_LIST,
|
||||
ARG_HELP,
|
||||
ARG_POSITIONAL,
|
||||
} arg_type_t;
|
||||
|
||||
typedef struct {
|
||||
const char *as_full;
|
||||
char as_short;
|
||||
arg_type_t type;
|
||||
const char *description;
|
||||
bool is_optional;
|
||||
bool parsed;
|
||||
vector_t values;
|
||||
} arg_spec_t;
|
||||
|
||||
#define ARG_POS(name, desc) \
|
||||
{ \
|
||||
.as_full = name, \
|
||||
.type = ARG_POSITIONAL, \
|
||||
.description = desc, \
|
||||
}
|
||||
#define ARG_LIST(name, short, desc) \
|
||||
{ \
|
||||
.as_full = name, \
|
||||
.as_short = short, \
|
||||
.type = ARG_LIST, \
|
||||
.description = desc, \
|
||||
.is_optional = true, \
|
||||
}
|
||||
#define ARG_FLAG(name, short, desc) \
|
||||
{ \
|
||||
.as_full = name, \
|
||||
.as_short = short, \
|
||||
.type = ARG_FLAG, \
|
||||
.description = desc, \
|
||||
.is_optional = true, \
|
||||
}
|
||||
#define ARG_PARAM(name, short, desc) \
|
||||
{ \
|
||||
.as_full = name, \
|
||||
.as_short = short, \
|
||||
.type = ARG_PARAM, \
|
||||
.description = desc, \
|
||||
.is_optional = true, \
|
||||
}
|
||||
#define ARG_HELP(name, short, desc) \
|
||||
{ \
|
||||
.as_full = name, \
|
||||
.as_short = short, \
|
||||
.type = ARG_HELP, \
|
||||
.description = desc, \
|
||||
.is_optional = true, \
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
arg_spec_t *const *positional_args;
|
||||
size_t num_positional_args;
|
||||
arg_spec_t *const *option_args;
|
||||
size_t num_option_args;
|
||||
} arg_parser_t;
|
||||
|
||||
static inline void print_help(const arg_parser_t *parser)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
printf("uACPI test runner:\n");
|
||||
|
||||
for (i = 0; i < parser->num_positional_args; i++)
|
||||
printf(
|
||||
" [%s] %s\n", parser->positional_args[i]->as_full,
|
||||
parser->positional_args[i]->description
|
||||
);
|
||||
|
||||
for (i = 0; i < parser->num_option_args; i++)
|
||||
printf(
|
||||
"%s [--%s/-%c] %s\n",
|
||||
parser->option_args[i]->is_optional ? "(optional)" : " ",
|
||||
parser->option_args[i]->as_full,
|
||||
parser->option_args[i]->as_short,
|
||||
parser->option_args[i]->description
|
||||
);
|
||||
}
|
||||
|
||||
static inline bool is_arg(const char *arg)
|
||||
{
|
||||
size_t length = strlen(arg);
|
||||
|
||||
switch (length) {
|
||||
case 0:
|
||||
case 1:
|
||||
return false;
|
||||
case 2:
|
||||
return arg[0] == '-';
|
||||
default:
|
||||
return arg[0] == '-' && arg[1] == '-';
|
||||
}
|
||||
}
|
||||
|
||||
static inline void parse_args(
|
||||
const arg_parser_t *parser, int argc, char *argv[]
|
||||
)
|
||||
{
|
||||
size_t num_args = argc;
|
||||
arg_spec_t *active_spec = NULL;
|
||||
size_t arg_index;
|
||||
|
||||
if (num_args < 2) {
|
||||
print_help(parser);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (parser->num_positional_args) {
|
||||
if ((num_args - 1) < parser->num_positional_args)
|
||||
error(
|
||||
"expected at least %zu positional arguments",
|
||||
parser->num_positional_args
|
||||
);
|
||||
|
||||
for (arg_index = 0; arg_index < parser->num_positional_args;
|
||||
++arg_index)
|
||||
vector_add(
|
||||
&parser->positional_args[arg_index]->values,
|
||||
argv[1 + arg_index], 0
|
||||
);
|
||||
}
|
||||
|
||||
for (arg_index = 1 + parser->num_positional_args; arg_index < num_args;
|
||||
++arg_index) {
|
||||
char *current_arg = argv[arg_index];
|
||||
bool is_new_arg = is_arg(current_arg);
|
||||
arg_spec_t *new_spec = NULL;
|
||||
size_t length;
|
||||
|
||||
if (active_spec) {
|
||||
if (!is_new_arg) {
|
||||
if (active_spec->type == ARG_FLAG)
|
||||
error("unexpected argument %s", current_arg);
|
||||
|
||||
if (active_spec->type == ARG_PARAM &&
|
||||
active_spec->values.count == 1)
|
||||
error("too many arguments for %s", active_spec->as_full);
|
||||
|
||||
vector_add(&active_spec->values, current_arg, 0);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((active_spec->type == ARG_PARAM ||
|
||||
active_spec->type == ARG_LIST) &&
|
||||
active_spec->values.count == 0)
|
||||
error("expected an argument for %s", active_spec->as_full);
|
||||
}
|
||||
|
||||
length = strlen(current_arg);
|
||||
|
||||
if (length >= 2) {
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < parser->num_option_args; i++) {
|
||||
arg_spec_t *spec = parser->option_args[i];
|
||||
|
||||
if (length == 2 && spec->as_short == current_arg[1]) {
|
||||
new_spec = spec;
|
||||
break;
|
||||
} else if (strcmp(spec->as_full, ¤t_arg[2]) == 0) {
|
||||
new_spec = spec;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (new_spec == NULL)
|
||||
error("unexpected argument %s", current_arg);
|
||||
|
||||
active_spec = new_spec;
|
||||
if (active_spec->type == ARG_HELP) {
|
||||
print_help(parser);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
active_spec->parsed = true;
|
||||
}
|
||||
}
|
||||
|
||||
static inline bool is_set(const arg_spec_t *spec)
|
||||
{
|
||||
return spec->parsed;
|
||||
}
|
||||
|
||||
static inline const char *get(const arg_spec_t *spec)
|
||||
{
|
||||
if (spec->values.count == 0)
|
||||
error("no argument provided for %s", spec->as_full);
|
||||
|
||||
return spec->values.blobs[0].data;
|
||||
}
|
||||
|
||||
static inline uint64_t get_uint(const arg_spec_t *spec)
|
||||
{
|
||||
return strtoull(get(spec), NULL, 10);
|
||||
}
|
||||
|
||||
static inline uint64_t get_uint_or(
|
||||
const arg_spec_t *spec, uint64_t default_value
|
||||
)
|
||||
{
|
||||
if (is_set(spec))
|
||||
return get_uint(spec);
|
||||
|
||||
return default_value;
|
||||
}
|
170
kernel/hal/x86_64/uACPI/tests/runner/barebones_runner.c
Normal file
170
kernel/hal/x86_64/uACPI/tests/runner/barebones_runner.c
Normal file
@ -0,0 +1,170 @@
|
||||
#include "argparser.h"
|
||||
#include "helpers.h"
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <uacpi/acpi.h>
|
||||
#include <uacpi/kernel_api.h>
|
||||
#include <uacpi/tables.h>
|
||||
#include <uacpi/uacpi.h>
|
||||
|
||||
void uacpi_kernel_log(enum uacpi_log_level lvl, const char *text)
|
||||
{
|
||||
printf("[%s] %s", uacpi_log_level_to_string(lvl), text);
|
||||
}
|
||||
|
||||
void *uacpi_kernel_map(uacpi_phys_addr addr, uacpi_size len)
|
||||
{
|
||||
UACPI_UNUSED(len);
|
||||
|
||||
return (void*)((uintptr_t)addr);
|
||||
}
|
||||
|
||||
void uacpi_kernel_unmap(void *ptr, uacpi_size len)
|
||||
{
|
||||
UACPI_UNUSED(ptr);
|
||||
UACPI_UNUSED(len);
|
||||
}
|
||||
|
||||
uacpi_phys_addr g_rsdp;
|
||||
|
||||
uacpi_status uacpi_kernel_get_rsdp(uacpi_phys_addr *out_addr)
|
||||
{
|
||||
*out_addr = g_rsdp;
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
static uint8_t test_dsdt[] = {
|
||||
0x53, 0x53, 0x44, 0x54, 0x35, 0x00, 0x00, 0x00,
|
||||
0x01, 0xa1, 0x75, 0x54, 0x45, 0x53, 0x54, 0x00,
|
||||
0x4f, 0x56, 0x45, 0x52, 0x52, 0x49, 0x44, 0x45,
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0x49, 0x4e, 0x54, 0x4c,
|
||||
0x25, 0x09, 0x20, 0x20, 0x08, 0x56, 0x41, 0x4c,
|
||||
0x5f, 0x0d, 0x54, 0x65, 0x73, 0x74, 0x52, 0x75,
|
||||
0x6e, 0x6e, 0x65, 0x72, 0x00
|
||||
};
|
||||
|
||||
static uint8_t test_mcfg[] = {
|
||||
0x4d, 0x43, 0x46, 0x47, 0x3c, 0x00, 0x00, 0x00,
|
||||
0x01, 0x39, 0x48, 0x50, 0x51, 0x4f, 0x45, 0x4d,
|
||||
0x38, 0x35, 0x34, 0x39, 0x20, 0x20, 0x20, 0x20,
|
||||
0x01, 0x00, 0x00, 0x00, 0x48, 0x50, 0x20, 0x20,
|
||||
0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f,
|
||||
0x00, 0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
static void ensure_signature_is(const char *signature, uacpi_table tbl)
|
||||
{
|
||||
if (strncmp(tbl.hdr->signature, signature, 4) == 0)
|
||||
return;
|
||||
|
||||
error(
|
||||
"incorrect table signature: expected %s got %.4s\n", signature,
|
||||
tbl.hdr->signature
|
||||
);
|
||||
}
|
||||
|
||||
static void find_one_table(const char *signature)
|
||||
{
|
||||
uacpi_table tbl;
|
||||
uacpi_status st;
|
||||
|
||||
st = uacpi_table_find_by_signature(signature, &tbl);
|
||||
ensure_ok_status(st);
|
||||
|
||||
ensure_signature_is(signature, tbl);
|
||||
|
||||
printf("%4.4s OK\n", signature);
|
||||
uacpi_table_unref(&tbl);
|
||||
}
|
||||
|
||||
static void test_basic_operation(void)
|
||||
{
|
||||
find_one_table(ACPI_FADT_SIGNATURE);
|
||||
find_one_table(ACPI_DSDT_SIGNATURE);
|
||||
}
|
||||
|
||||
static void test_table_installation(void)
|
||||
{
|
||||
uacpi_status st;
|
||||
uacpi_table tbl;
|
||||
|
||||
st = uacpi_table_install(test_mcfg, &tbl);
|
||||
ensure_ok_status(st);
|
||||
ensure_signature_is(ACPI_MCFG_SIGNATURE, tbl);
|
||||
uacpi_table_unref(&tbl);
|
||||
|
||||
find_one_table(ACPI_MCFG_SIGNATURE);
|
||||
|
||||
st = uacpi_table_install_physical(
|
||||
(uacpi_phys_addr)((uintptr_t)test_mcfg), &tbl
|
||||
);
|
||||
ensure_ok_status(st);
|
||||
ensure_signature_is(ACPI_MCFG_SIGNATURE, tbl);
|
||||
uacpi_table_unref(&tbl);
|
||||
}
|
||||
|
||||
static struct {
|
||||
const char *name;
|
||||
void (*func)(void);
|
||||
} test_cases[] = {
|
||||
{ "basic-operation", test_basic_operation },
|
||||
{ "table-installation", test_table_installation },
|
||||
};
|
||||
|
||||
static arg_spec_t TEST_CASE_ARG = ARG_POS("test-case", "name of the test case");
|
||||
|
||||
static arg_spec_t HELP_ARG = ARG_HELP(
|
||||
"help", 'h', "Display this menu and exit"
|
||||
);
|
||||
|
||||
static arg_spec_t *const POSITIONAL_ARGS[] = {
|
||||
&TEST_CASE_ARG,
|
||||
};
|
||||
|
||||
static arg_spec_t *const OPTION_ARGS[] = {
|
||||
&HELP_ARG,
|
||||
};
|
||||
|
||||
static const arg_parser_t PARSER = {
|
||||
.positional_args = POSITIONAL_ARGS,
|
||||
.num_positional_args = UACPI_ARRAY_SIZE(POSITIONAL_ARGS),
|
||||
.option_args = OPTION_ARGS,
|
||||
.num_option_args = UACPI_ARRAY_SIZE(OPTION_ARGS),
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
static uint8_t early_table_buf[4096];
|
||||
struct acpi_rsdp rsdp = { 0 };
|
||||
struct full_xsdt *xsdt;
|
||||
uacpi_status st;
|
||||
const char *test_case;
|
||||
size_t i;
|
||||
|
||||
parse_args(&PARSER, argc, argv);
|
||||
|
||||
xsdt = make_xsdt_blob(&rsdp, test_dsdt, sizeof(test_dsdt));
|
||||
|
||||
g_rsdp = (uacpi_phys_addr)((uintptr_t)&rsdp);
|
||||
|
||||
st = uacpi_setup_early_table_access(
|
||||
early_table_buf, sizeof(early_table_buf)
|
||||
);
|
||||
ensure_ok_status(st);
|
||||
|
||||
test_case = get(&TEST_CASE_ARG);
|
||||
|
||||
for (i = 0; i < UACPI_ARRAY_SIZE(test_cases); i++) {
|
||||
if (strcmp(test_case, test_cases[i].name) == 0) {
|
||||
test_cases[i].func();
|
||||
uacpi_state_reset();
|
||||
delete_xsdt(xsdt, 0);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
error("unknown test case '%s'", test_case);
|
||||
return 1;
|
||||
}
|
237
kernel/hal/x86_64/uACPI/tests/runner/helpers.c
Normal file
237
kernel/hal/x86_64/uACPI/tests/runner/helpers.c
Normal file
@ -0,0 +1,237 @@
|
||||
#include "helpers.h"
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <uacpi/acpi.h>
|
||||
|
||||
static uacpi_u8 gen_checksum(void *table, uacpi_size size)
|
||||
{
|
||||
uacpi_u8 *bytes = table;
|
||||
uacpi_u8 csum = 0;
|
||||
uacpi_size i;
|
||||
|
||||
for (i = 0; i < size; ++i)
|
||||
csum += bytes[i];
|
||||
|
||||
return 256 - csum;
|
||||
}
|
||||
|
||||
void set_oem(char (*oemid)[6])
|
||||
{
|
||||
memcpy(oemid, "uOEMID", sizeof(*oemid));
|
||||
}
|
||||
|
||||
void set_oem_table_id(char (*oemid_table_id)[8])
|
||||
{
|
||||
memcpy(oemid_table_id, "uTESTTBL", sizeof(*oemid_table_id));
|
||||
}
|
||||
|
||||
static void get_table_path(blob_t *item, const char *path)
|
||||
{
|
||||
*item = read_entire_file(path, sizeof(struct acpi_sdt_hdr));
|
||||
}
|
||||
|
||||
static void get_table_blob(blob_t *item, const void *data, size_t size)
|
||||
{
|
||||
item->data = do_malloc(size);
|
||||
item->size = size;
|
||||
memcpy(item->data, data, size);
|
||||
}
|
||||
|
||||
static struct full_xsdt *do_make_xsdt(
|
||||
struct acpi_rsdp *rsdp, const blob_t *tables, size_t num_tables
|
||||
)
|
||||
{
|
||||
size_t xsdt_bytes = sizeof(struct full_xsdt);
|
||||
struct full_xsdt *xsdt;
|
||||
size_t i;
|
||||
struct acpi_fadt *fadt;
|
||||
struct acpi_facs *facs;
|
||||
struct acpi_sdt_hdr *dsdt;
|
||||
|
||||
memcpy(
|
||||
&rsdp->signature, ACPI_RSDP_SIGNATURE,
|
||||
sizeof(ACPI_RSDP_SIGNATURE) - 1
|
||||
);
|
||||
set_oem(&rsdp->oemid);
|
||||
|
||||
xsdt_bytes += (num_tables - 1) * sizeof(struct acpi_sdt_hdr*);
|
||||
|
||||
xsdt = do_calloc(xsdt_bytes, 1);
|
||||
|
||||
set_oem(&xsdt->hdr.oemid);
|
||||
set_oem_table_id(&xsdt->hdr.oem_table_id);
|
||||
|
||||
for (i = 0; i < num_tables; ++i) {
|
||||
struct acpi_sdt_hdr *hdr = tables[i].data;
|
||||
char *signature = ACPI_DSDT_SIGNATURE;
|
||||
|
||||
if (hdr->length > tables[i].size)
|
||||
error("invalid table %zu size", i);
|
||||
|
||||
if (i > 0) {
|
||||
signature = ACPI_SSDT_SIGNATURE;
|
||||
xsdt->ssdts[i - 1] = hdr;
|
||||
}
|
||||
|
||||
memcpy(hdr, signature, sizeof(uacpi_object_name));
|
||||
|
||||
hdr->checksum = 0;
|
||||
hdr->checksum = gen_checksum(hdr, hdr->length);
|
||||
}
|
||||
|
||||
fadt = do_calloc(1, sizeof(*fadt));
|
||||
set_oem(&fadt->hdr.oemid);
|
||||
set_oem_table_id(&fadt->hdr.oem_table_id);
|
||||
|
||||
fadt->hdr.length = sizeof(*fadt);
|
||||
fadt->hdr.revision = 6;
|
||||
|
||||
fadt->pm1a_cnt_blk = 0xFFEE;
|
||||
fadt->pm1_cnt_len = 2;
|
||||
|
||||
fadt->pm1a_evt_blk = 0xDEAD;
|
||||
fadt->pm1_evt_len = 4;
|
||||
|
||||
fadt->pm2_cnt_blk = 0xCCDD;
|
||||
fadt->pm2_cnt_len = 1;
|
||||
|
||||
fadt->gpe0_blk_len = 0x20;
|
||||
fadt->gpe0_blk = 0xDEAD;
|
||||
|
||||
fadt->gpe1_base = 128;
|
||||
fadt->gpe1_blk = 0xBEEF;
|
||||
fadt->gpe1_blk_len = 0x20;
|
||||
|
||||
fadt->x_dsdt = (uacpi_phys_addr)((uintptr_t)tables[0].data);
|
||||
memcpy(
|
||||
fadt->hdr.signature, ACPI_FADT_SIGNATURE,
|
||||
sizeof(ACPI_FADT_SIGNATURE) - 1
|
||||
);
|
||||
|
||||
facs = do_calloc(1, sizeof(*facs));
|
||||
facs->length = sizeof(*facs);
|
||||
memcpy(
|
||||
facs->signature, ACPI_FACS_SIGNATURE,
|
||||
sizeof(ACPI_FACS_SIGNATURE) - 1
|
||||
);
|
||||
|
||||
fadt->x_firmware_ctrl = (uintptr_t)facs;
|
||||
|
||||
fadt->hdr.checksum = gen_checksum(fadt, sizeof(*fadt));
|
||||
|
||||
xsdt->fadt = fadt;
|
||||
xsdt->hdr.length = sizeof(*xsdt) +
|
||||
sizeof(struct acpi_sdt_hdr*) * (num_tables - 1);
|
||||
|
||||
dsdt = tables[0].data;
|
||||
xsdt->hdr.revision = dsdt->revision;
|
||||
memcpy(xsdt->hdr.oemid, dsdt->oemid, sizeof(dsdt->oemid));
|
||||
xsdt->hdr.oem_revision = dsdt->oem_revision;
|
||||
|
||||
if (sizeof(void*) == 4) {
|
||||
memcpy(
|
||||
xsdt->hdr.signature, ACPI_RSDT_SIGNATURE,
|
||||
sizeof(ACPI_XSDT_SIGNATURE) - 1
|
||||
);
|
||||
|
||||
rsdp->rsdt_addr = (size_t)xsdt;
|
||||
rsdp->revision = 1;
|
||||
rsdp->checksum = gen_checksum(rsdp, offsetof(struct acpi_rsdp, length));
|
||||
} else {
|
||||
memcpy(
|
||||
xsdt->hdr.signature, ACPI_XSDT_SIGNATURE,
|
||||
sizeof(ACPI_XSDT_SIGNATURE) - 1
|
||||
);
|
||||
|
||||
rsdp->xsdt_addr = (size_t)xsdt;
|
||||
rsdp->length = sizeof(*rsdp);
|
||||
rsdp->revision = 2;
|
||||
rsdp->checksum = gen_checksum(rsdp, offsetof(struct acpi_rsdp, length));
|
||||
rsdp->extended_checksum = gen_checksum(rsdp, sizeof(*rsdp));
|
||||
}
|
||||
xsdt->hdr.checksum = gen_checksum(xsdt, xsdt->hdr.length);
|
||||
|
||||
return xsdt;
|
||||
}
|
||||
|
||||
struct full_xsdt *make_xsdt(
|
||||
struct acpi_rsdp *rsdp, const char *dsdt_path, const vector_t *ssdts
|
||||
)
|
||||
{
|
||||
vector_t tables;
|
||||
size_t i;
|
||||
struct full_xsdt *xsdt;
|
||||
|
||||
vector_init(&tables, ssdts->count + 1);
|
||||
|
||||
get_table_path(&tables.blobs[0], dsdt_path);
|
||||
|
||||
for (i = 0; i < ssdts->count; ++i)
|
||||
get_table_path(&tables.blobs[1 + i], ssdts->blobs[i].data);
|
||||
|
||||
xsdt = do_make_xsdt(rsdp, tables.blobs, tables.count);
|
||||
vector_cleanup(&tables);
|
||||
return xsdt;
|
||||
}
|
||||
|
||||
struct full_xsdt *make_xsdt_blob(
|
||||
struct acpi_rsdp *rsdp, const void *dsdt, size_t dsdt_size
|
||||
)
|
||||
{
|
||||
blob_t blob;
|
||||
|
||||
get_table_blob(&blob, dsdt, dsdt_size);
|
||||
return do_make_xsdt(rsdp, &blob, 1);
|
||||
}
|
||||
|
||||
void delete_xsdt(struct full_xsdt *xsdt, size_t num_tables)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (xsdt->fadt) {
|
||||
free((void*)((uintptr_t)xsdt->fadt->x_dsdt));
|
||||
free((struct acpi_facs*)((uintptr_t)xsdt->fadt->x_firmware_ctrl));
|
||||
free(xsdt->fadt);
|
||||
}
|
||||
|
||||
for (i = 0; i < num_tables; i++)
|
||||
free(xsdt->ssdts[i]);
|
||||
|
||||
free(xsdt);
|
||||
}
|
||||
|
||||
blob_t read_entire_file(const char *path, size_t min_size)
|
||||
{
|
||||
FILE *file = fopen(path, "rb");
|
||||
long size;
|
||||
void *buf;
|
||||
blob_t blob = { 0 };
|
||||
|
||||
if (!file)
|
||||
error("failed to open file %s", path);
|
||||
|
||||
if (fseek(file, 0, SEEK_END))
|
||||
error("failed to seek file %s", path);
|
||||
|
||||
size = ftell(file);
|
||||
if (size < 0)
|
||||
error("failed to get size of file %s", path);
|
||||
if (size < (long)min_size)
|
||||
error("file %s is too small", path);
|
||||
if (fseek(file, 0, SEEK_SET))
|
||||
error("failed to seek file %s", path);
|
||||
|
||||
buf = do_malloc(size);
|
||||
|
||||
if (fread(buf, size, 1, file) != 1)
|
||||
error("failed to read from %s", path);
|
||||
|
||||
if (fclose(file))
|
||||
error("failed to close file %s", path);
|
||||
|
||||
blob.data = buf;
|
||||
blob.size = size;
|
||||
return blob;
|
||||
}
|
294
kernel/hal/x86_64/uACPI/tests/runner/helpers.h
Normal file
294
kernel/hal/x86_64/uACPI/tests/runner/helpers.h
Normal file
@ -0,0 +1,294 @@
|
||||
#pragma once
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <uacpi/acpi.h>
|
||||
#include <uacpi/internal/helpers.h>
|
||||
#include <uacpi/status.h>
|
||||
#include <uacpi/uacpi.h>
|
||||
|
||||
#ifdef __GNUC__
|
||||
#define NORETURN __attribute__((__noreturn__))
|
||||
#else
|
||||
#define NORETURN
|
||||
#endif
|
||||
|
||||
NORETURN static inline void error(const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
fprintf(stderr, "unexpected error: ");
|
||||
va_start(args, format);
|
||||
vfprintf(stderr, format, args);
|
||||
va_end(args);
|
||||
fputc('\n', stderr);
|
||||
uacpi_state_reset();
|
||||
exit(1);
|
||||
}
|
||||
|
||||
static inline void *do_malloc(size_t size)
|
||||
{
|
||||
void *ptr = malloc(size);
|
||||
|
||||
if (!ptr)
|
||||
error("failed to allocate %zu bytes of memory", size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static inline void *do_calloc(size_t nmemb, size_t size)
|
||||
{
|
||||
void *ptr = calloc(nmemb, size);
|
||||
|
||||
if (!ptr)
|
||||
error("failed to allocate %zu bytes of memory", nmemb * size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static inline void *do_realloc(void *ptr, size_t size)
|
||||
{
|
||||
ptr = realloc(ptr, size);
|
||||
|
||||
if (!ptr)
|
||||
error("failed to allocate %zu bytes of memory", size);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
void *data;
|
||||
size_t size;
|
||||
} blob_t;
|
||||
|
||||
typedef struct {
|
||||
blob_t *blobs;
|
||||
size_t capacity;
|
||||
size_t count;
|
||||
} vector_t;
|
||||
|
||||
static inline void vector_init(vector_t *vector, size_t items)
|
||||
{
|
||||
vector->blobs = do_calloc(items, sizeof(*vector->blobs));
|
||||
vector->capacity = items;
|
||||
vector->count = items;
|
||||
}
|
||||
|
||||
static inline void vector_add(vector_t *vector, void *data, size_t size)
|
||||
{
|
||||
if (vector->count >= vector->capacity) {
|
||||
vector->capacity = vector->capacity ? vector->capacity * 2 : 8;
|
||||
vector->blobs = do_realloc(
|
||||
vector->blobs, vector->capacity * sizeof(*vector->blobs)
|
||||
);
|
||||
}
|
||||
|
||||
vector->blobs[vector->count].data = data;
|
||||
vector->blobs[vector->count].size = size;
|
||||
vector->count += 1;
|
||||
}
|
||||
|
||||
static inline void vector_cleanup(vector_t *vector)
|
||||
{
|
||||
free(vector->blobs);
|
||||
vector->capacity = 0;
|
||||
vector->count = 0;
|
||||
}
|
||||
|
||||
static inline void *get_container(void *value, size_t offset)
|
||||
{
|
||||
return value ? (void*)((char*)value - offset) : NULL;
|
||||
}
|
||||
|
||||
#define CONTAINER(type, field, value) \
|
||||
((type*)get_container((value), offsetof(type, field)))
|
||||
|
||||
typedef struct hash_node {
|
||||
struct hash_node *prev;
|
||||
struct hash_node *next;
|
||||
uint64_t key;
|
||||
} hash_node_t;
|
||||
|
||||
typedef struct {
|
||||
hash_node_t **entries;
|
||||
size_t capacity;
|
||||
size_t count;
|
||||
} hash_table_t;
|
||||
|
||||
static inline uint64_t make_hash(uint64_t x)
|
||||
{
|
||||
x *= 0xe9770214b82cf957;
|
||||
x ^= x >> 47;
|
||||
x *= 0x2bdd9d20d060fc9b;
|
||||
x ^= x >> 44;
|
||||
x *= 0x65c487023b406173;
|
||||
return x;
|
||||
}
|
||||
|
||||
static inline hash_node_t *hash_table_find(hash_table_t *table, uint64_t key)
|
||||
{
|
||||
hash_node_t *current;
|
||||
|
||||
if (!table->capacity)
|
||||
return NULL;
|
||||
|
||||
current = table->entries[make_hash(key) % table->capacity];
|
||||
|
||||
while (current != NULL && current->key != key)
|
||||
current = current->next;
|
||||
|
||||
return current;
|
||||
}
|
||||
|
||||
#define HASH_TABLE_FIND(table, key, type, field) \
|
||||
CONTAINER(type, field, hash_table_find((table), (key)))
|
||||
|
||||
static inline hash_node_t *hash_table_get_or_add(
|
||||
hash_table_t *table, uint64_t key, size_t size, size_t offset
|
||||
)
|
||||
{
|
||||
uint64_t hash = make_hash(key);
|
||||
void *value;
|
||||
hash_node_t *node;
|
||||
size_t bucket;
|
||||
|
||||
if (table->capacity) {
|
||||
hash_node_t *current = table->entries[hash % table->capacity];
|
||||
|
||||
while (current != NULL) {
|
||||
if (current->key == key)
|
||||
return current;
|
||||
current = current->next;
|
||||
}
|
||||
}
|
||||
|
||||
if (table->count >= table->capacity - (table->capacity / 4)) {
|
||||
size_t new_cap = table->capacity ? table->capacity * 2 : 8;
|
||||
hash_node_t **new_entries = do_calloc(new_cap, sizeof(*table->entries));
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < table->capacity; i++) {
|
||||
hash_node_t *current = table->entries[i];
|
||||
|
||||
while (current != NULL) {
|
||||
hash_node_t *next = current->next;
|
||||
size_t bucket = make_hash(current->key) % new_cap;
|
||||
|
||||
current->prev = NULL;
|
||||
current->next = new_entries[bucket];
|
||||
if (current->next)
|
||||
current->next->prev = current;
|
||||
new_entries[bucket] = current;
|
||||
|
||||
current = next;
|
||||
}
|
||||
}
|
||||
|
||||
free(table->entries);
|
||||
table->entries = new_entries;
|
||||
table->capacity = new_cap;
|
||||
}
|
||||
|
||||
value = do_calloc(1, size);
|
||||
node = (void*)((char*)value + offset);
|
||||
node->key = key;
|
||||
|
||||
bucket = hash % table->capacity;
|
||||
node->prev = NULL;
|
||||
node->next = table->entries[bucket];
|
||||
if (node->next)
|
||||
node->next->prev = node;
|
||||
table->entries[bucket] = node;
|
||||
|
||||
table->count += 1;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
#define HASH_TABLE_GET_OR_ADD(table, key, type, field) \
|
||||
CONTAINER( \
|
||||
type, field, \
|
||||
hash_table_get_or_add( \
|
||||
(table), (key), sizeof(type), offsetof(type, field) \
|
||||
) \
|
||||
)
|
||||
|
||||
static inline void hash_table_remove(
|
||||
hash_table_t *table, hash_node_t *node, size_t offset
|
||||
)
|
||||
{
|
||||
if (node->prev)
|
||||
node->prev->next = node->next;
|
||||
else
|
||||
table->entries[make_hash(node->key) % table->capacity] = node->next;
|
||||
|
||||
if (node->next)
|
||||
node->next->prev = node->prev;
|
||||
|
||||
table->count -= 1;
|
||||
free((void*)((char*)node - offset));
|
||||
}
|
||||
|
||||
#define HASH_TABLE_REMOVE(table, value, type, field) \
|
||||
hash_table_remove((table), &(value)->field, offsetof(type, field))
|
||||
|
||||
static inline bool hash_table_empty(hash_table_t *table)
|
||||
{
|
||||
return table->count == 0;
|
||||
}
|
||||
|
||||
static inline void hash_table_cleanup(hash_table_t *table)
|
||||
{
|
||||
free(table->entries);
|
||||
table->capacity = 0;
|
||||
table->count = 0;
|
||||
}
|
||||
|
||||
extern bool g_expect_virtual_addresses;
|
||||
extern uacpi_phys_addr g_rsdp;
|
||||
|
||||
UACPI_PACKED(struct full_xsdt {
|
||||
struct acpi_sdt_hdr hdr;
|
||||
struct acpi_fadt *fadt;
|
||||
struct acpi_sdt_hdr *ssdts[];
|
||||
})
|
||||
|
||||
void set_oem(char (*oemid)[6]);
|
||||
void set_oem_table_id(char (*oemid_table_id)[8]);
|
||||
|
||||
struct full_xsdt *make_xsdt(
|
||||
struct acpi_rsdp *rsdp, const char *dsdt_path, const vector_t *ssdt_paths
|
||||
);
|
||||
struct full_xsdt *make_xsdt_blob(
|
||||
struct acpi_rsdp *rsdp, const void *dsdt, size_t dsdt_size
|
||||
);
|
||||
void delete_xsdt(struct full_xsdt *xsdt, size_t num_tables);
|
||||
|
||||
blob_t read_entire_file(const char *path, size_t min_size);
|
||||
|
||||
static inline void ensure_ok_status(uacpi_status st)
|
||||
{
|
||||
if (st == UACPI_STATUS_OK)
|
||||
return;
|
||||
|
||||
error("uACPI error: %s", uacpi_status_to_string(st));
|
||||
}
|
||||
|
||||
static inline const char *uacpi_log_level_to_string(uacpi_log_level lvl)
|
||||
{
|
||||
switch (lvl) {
|
||||
case UACPI_LOG_DEBUG:
|
||||
return "DEBUG";
|
||||
case UACPI_LOG_TRACE:
|
||||
return "TRACE";
|
||||
case UACPI_LOG_INFO:
|
||||
return "INFO";
|
||||
case UACPI_LOG_WARN:
|
||||
return "WARN";
|
||||
case UACPI_LOG_ERROR:
|
||||
return "ERROR";
|
||||
default:
|
||||
abort();
|
||||
return NULL;
|
||||
}
|
||||
}
|
605
kernel/hal/x86_64/uACPI/tests/runner/interface_impl.c
Normal file
605
kernel/hal/x86_64/uACPI/tests/runner/interface_impl.c
Normal file
@ -0,0 +1,605 @@
|
||||
#include "helpers.h"
|
||||
#include "os.h"
|
||||
#include <inttypes.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <uacpi/kernel_api.h>
|
||||
#include <uacpi/status.h>
|
||||
#include <uacpi/types.h>
|
||||
|
||||
uacpi_phys_addr g_rsdp;
|
||||
|
||||
uacpi_status uacpi_kernel_get_rsdp(uacpi_phys_addr *out_rsdp_address)
|
||||
{
|
||||
*out_rsdp_address = g_rsdp;
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
static uint8_t *io_space;
|
||||
|
||||
#ifdef UACPI_KERNEL_INITIALIZATION
|
||||
uacpi_status uacpi_kernel_initialize(uacpi_init_level lvl)
|
||||
{
|
||||
if (lvl == UACPI_INIT_LEVEL_EARLY)
|
||||
io_space = do_malloc(UINT16_MAX + 1);
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
void uacpi_kernel_deinitialize(void)
|
||||
{
|
||||
free(io_space);
|
||||
io_space = NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
uacpi_status uacpi_kernel_io_map(
|
||||
uacpi_io_addr base, uacpi_size len, uacpi_handle *out_handle
|
||||
)
|
||||
{
|
||||
UACPI_UNUSED(len);
|
||||
|
||||
*out_handle = (uacpi_handle)((uintptr_t)base);
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
void uacpi_kernel_io_unmap(uacpi_handle handle)
|
||||
{
|
||||
UACPI_UNUSED(handle);
|
||||
}
|
||||
|
||||
#define UACPI_IO_READ(bits) \
|
||||
uacpi_status uacpi_kernel_io_read##bits( \
|
||||
uacpi_handle handle, uacpi_size offset, uacpi_u##bits *out_value \
|
||||
) \
|
||||
{ \
|
||||
uacpi_io_addr addr = (uacpi_io_addr)((uintptr_t)handle) + offset; \
|
||||
\
|
||||
if (io_space && addr <= UINT16_MAX) \
|
||||
memcpy(out_value, &io_space[addr], bits / 8); \
|
||||
else \
|
||||
*out_value = (uacpi_u##bits)0xFFFFFFFFFFFFFFFF; \
|
||||
\
|
||||
return UACPI_STATUS_OK; \
|
||||
}
|
||||
|
||||
#define UACPI_IO_WRITE(bits) \
|
||||
uacpi_status uacpi_kernel_io_write##bits( \
|
||||
uacpi_handle handle, uacpi_size offset, uacpi_u##bits in_value \
|
||||
) \
|
||||
{ \
|
||||
uacpi_io_addr addr = (uacpi_io_addr)((uintptr_t)handle) + offset; \
|
||||
\
|
||||
if (io_space && addr <= UINT16_MAX) \
|
||||
memcpy(&io_space[addr], &in_value, bits / 8); \
|
||||
\
|
||||
return UACPI_STATUS_OK; \
|
||||
}
|
||||
|
||||
#define UACPI_PCI_READ(bits) \
|
||||
uacpi_status uacpi_kernel_pci_read##bits( \
|
||||
uacpi_handle handle, uacpi_size offset, uacpi_u##bits *value \
|
||||
) \
|
||||
{ \
|
||||
UACPI_UNUSED(handle); \
|
||||
UACPI_UNUSED(offset); \
|
||||
\
|
||||
*value = (uacpi_u##bits)0xFFFFFFFFFFFFFFFF; \
|
||||
return UACPI_STATUS_OK; \
|
||||
}
|
||||
|
||||
#define UACPI_PCI_WRITE(bits) \
|
||||
uacpi_status uacpi_kernel_pci_write##bits( \
|
||||
uacpi_handle handle, uacpi_size offset, uacpi_u##bits value \
|
||||
) \
|
||||
{ \
|
||||
UACPI_UNUSED(handle); \
|
||||
UACPI_UNUSED(offset); \
|
||||
UACPI_UNUSED(value); \
|
||||
\
|
||||
return UACPI_STATUS_OK; \
|
||||
}
|
||||
|
||||
UACPI_IO_READ(8)
|
||||
UACPI_IO_READ(16)
|
||||
UACPI_IO_READ(32)
|
||||
|
||||
UACPI_IO_WRITE(8)
|
||||
UACPI_IO_WRITE(16)
|
||||
UACPI_IO_WRITE(32)
|
||||
|
||||
UACPI_PCI_READ(8)
|
||||
UACPI_PCI_READ(16)
|
||||
UACPI_PCI_READ(32)
|
||||
|
||||
UACPI_PCI_WRITE(8)
|
||||
UACPI_PCI_WRITE(16)
|
||||
UACPI_PCI_WRITE(32)
|
||||
|
||||
uacpi_status uacpi_kernel_pci_device_open(
|
||||
uacpi_pci_address address, uacpi_handle *out_handle
|
||||
)
|
||||
{
|
||||
UACPI_UNUSED(address);
|
||||
|
||||
*out_handle = NULL;
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
void uacpi_kernel_pci_device_close(uacpi_handle handle)
|
||||
{
|
||||
UACPI_UNUSED(handle);
|
||||
}
|
||||
|
||||
bool g_expect_virtual_addresses = true;
|
||||
|
||||
typedef struct {
|
||||
hash_node_t node;
|
||||
uint64_t phys;
|
||||
size_t references;
|
||||
} virt_location_t;
|
||||
|
||||
typedef struct {
|
||||
hash_node_t node;
|
||||
void *virt;
|
||||
} mapping_t;
|
||||
|
||||
typedef struct {
|
||||
hash_node_t node;
|
||||
hash_table_t mappings;
|
||||
} phys_location_t;
|
||||
|
||||
static hash_table_t virt_locations;
|
||||
static hash_table_t phys_locations;
|
||||
|
||||
void *uacpi_kernel_map(uacpi_phys_addr addr, uacpi_size len)
|
||||
{
|
||||
if (!g_expect_virtual_addresses) {
|
||||
phys_location_t *phys_location = HASH_TABLE_FIND(
|
||||
&phys_locations, addr, phys_location_t, node
|
||||
);
|
||||
void *virt;
|
||||
virt_location_t *location;
|
||||
mapping_t *mapping;
|
||||
|
||||
if (phys_location != NULL) {
|
||||
mapping = HASH_TABLE_FIND(
|
||||
&phys_location->mappings, len, mapping_t, node
|
||||
);
|
||||
|
||||
if (mapping != NULL) {
|
||||
location = HASH_TABLE_FIND(
|
||||
&virt_locations, (uintptr_t)mapping->virt, virt_location_t,
|
||||
node
|
||||
);
|
||||
|
||||
location->references += 1;
|
||||
return mapping->virt;
|
||||
}
|
||||
|
||||
printf(
|
||||
"WARN: remapping physical 0x%016" PRIX64 " with size %zu\n",
|
||||
addr, len
|
||||
);
|
||||
}
|
||||
|
||||
virt = do_calloc(len, 1);
|
||||
|
||||
location = HASH_TABLE_GET_OR_ADD(
|
||||
&virt_locations, (uintptr_t)virt, virt_location_t, node
|
||||
);
|
||||
location->phys = addr;
|
||||
location->references = 1;
|
||||
|
||||
phys_location = HASH_TABLE_GET_OR_ADD(
|
||||
&phys_locations, addr, phys_location_t, node
|
||||
);
|
||||
mapping = HASH_TABLE_GET_OR_ADD(
|
||||
&phys_location->mappings, len, mapping_t, node
|
||||
);
|
||||
mapping->virt = virt;
|
||||
|
||||
return virt;
|
||||
}
|
||||
|
||||
return (void*)((uintptr_t)addr);
|
||||
}
|
||||
|
||||
void uacpi_kernel_unmap(void *addr, uacpi_size len)
|
||||
{
|
||||
virt_location_t *virt_location = HASH_TABLE_FIND(
|
||||
&virt_locations, (uintptr_t)addr, virt_location_t, node
|
||||
);
|
||||
phys_location_t *phys_location;
|
||||
mapping_t *mapping;
|
||||
|
||||
if (!virt_location)
|
||||
return;
|
||||
if (--virt_location->references > 0)
|
||||
return;
|
||||
|
||||
phys_location = HASH_TABLE_FIND(
|
||||
&phys_locations, virt_location->phys, phys_location_t, node
|
||||
);
|
||||
mapping = HASH_TABLE_FIND(&phys_location->mappings, len, mapping_t, node);
|
||||
if (!mapping) {
|
||||
printf(
|
||||
"WARN: cannot identify mapping virt=%p phys=0x%016" PRIX64 " with "
|
||||
"size %zu\n", addr, phys_location->node.key, len
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
HASH_TABLE_REMOVE(&phys_location->mappings, mapping, mapping_t, node);
|
||||
if (hash_table_empty(&phys_location->mappings)) {
|
||||
hash_table_cleanup(&phys_location->mappings);
|
||||
HASH_TABLE_REMOVE(
|
||||
&phys_locations, phys_location, phys_location_t, node
|
||||
);
|
||||
}
|
||||
|
||||
free((void*)((uintptr_t)virt_location->node.key));
|
||||
HASH_TABLE_REMOVE(&virt_locations, virt_location, virt_location_t, node);
|
||||
}
|
||||
|
||||
void interface_cleanup(void)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < phys_locations.capacity; i++) {
|
||||
phys_location_t *location = CONTAINER(
|
||||
phys_location_t, node, phys_locations.entries[i]
|
||||
);
|
||||
|
||||
while (location) {
|
||||
hash_table_cleanup(&location->mappings);
|
||||
location = CONTAINER(phys_location_t, node, location->node.next);
|
||||
}
|
||||
}
|
||||
|
||||
hash_table_cleanup(&phys_locations);
|
||||
hash_table_cleanup(&virt_locations);
|
||||
}
|
||||
|
||||
#ifdef UACPI_SIZED_FREES
|
||||
|
||||
typedef struct {
|
||||
hash_node_t node;
|
||||
size_t size;
|
||||
} allocation_t;
|
||||
|
||||
static hash_table_t allocations;
|
||||
|
||||
void *uacpi_kernel_alloc(uacpi_size size)
|
||||
{
|
||||
void *ret;
|
||||
allocation_t *allocation;
|
||||
|
||||
if (size == 0)
|
||||
abort();
|
||||
|
||||
ret = malloc(size);
|
||||
if (ret == NULL)
|
||||
return ret;
|
||||
|
||||
allocation = HASH_TABLE_GET_OR_ADD(
|
||||
&allocations, (uintptr_t)ret, allocation_t, node
|
||||
);
|
||||
allocation->size = size;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void uacpi_kernel_free(void *mem, uacpi_size size_hint)
|
||||
{
|
||||
allocation_t *allocation;
|
||||
|
||||
if (mem == NULL)
|
||||
return;
|
||||
|
||||
allocation = HASH_TABLE_FIND(
|
||||
&allocations, (uintptr_t)mem, allocation_t, node
|
||||
);
|
||||
if (!allocation)
|
||||
error("unable to find heap allocation %p\n", mem);
|
||||
|
||||
if (allocation->size != size_hint)
|
||||
error(
|
||||
"invalid free size: originally allocated %zu bytes, freeing as %zu",
|
||||
allocation->size, size_hint
|
||||
);
|
||||
|
||||
HASH_TABLE_REMOVE(&allocations, allocation, allocation_t, node);
|
||||
free(mem);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void *uacpi_kernel_alloc(uacpi_size size)
|
||||
{
|
||||
if (size == 0)
|
||||
error("attempted to allocate zero bytes");
|
||||
|
||||
return malloc(size);
|
||||
}
|
||||
|
||||
void uacpi_kernel_free(void *mem)
|
||||
{
|
||||
free(mem);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef UACPI_NATIVE_ALLOC_ZEROED
|
||||
|
||||
void *uacpi_kernel_alloc_zeroed(uacpi_size size)
|
||||
{
|
||||
void *ret = uacpi_kernel_alloc(size);
|
||||
|
||||
if (ret == NULL)
|
||||
return ret;
|
||||
|
||||
memset(ret, 0, size);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef UACPI_FORMATTED_LOGGING
|
||||
|
||||
void uacpi_kernel_vlog(
|
||||
uacpi_log_level level, const uacpi_char *format, va_list args
|
||||
)
|
||||
{
|
||||
printf("[uACPI][%s] ", uacpi_log_level_to_string(level));
|
||||
vprintf(format, args);
|
||||
}
|
||||
|
||||
void uacpi_kernel_log(uacpi_log_level level, const uacpi_char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
|
||||
uacpi_kernel_vlog(level, format, args);
|
||||
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
void uacpi_kernel_log(uacpi_log_level level, const uacpi_char *str)
|
||||
{
|
||||
printf("[uACPI][%s] %s", uacpi_log_level_to_string(level), str);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
uacpi_u64 uacpi_kernel_get_nanoseconds_since_boot(void)
|
||||
{
|
||||
return get_nanosecond_timer();
|
||||
}
|
||||
|
||||
void uacpi_kernel_stall(uacpi_u8 usec)
|
||||
{
|
||||
uint64_t end = get_nanosecond_timer() + (uint64_t)usec * 1000;
|
||||
|
||||
for (;;)
|
||||
if (get_nanosecond_timer() >= end)
|
||||
break;
|
||||
}
|
||||
|
||||
void uacpi_kernel_sleep(uacpi_u64 msec)
|
||||
{
|
||||
millisecond_sleep(msec);
|
||||
}
|
||||
|
||||
uacpi_handle uacpi_kernel_create_mutex(void)
|
||||
{
|
||||
mutex_t *mutex = do_malloc(sizeof(*mutex));
|
||||
|
||||
mutex_init(mutex);
|
||||
return mutex;
|
||||
}
|
||||
|
||||
void uacpi_kernel_free_mutex(uacpi_handle handle)
|
||||
{
|
||||
mutex_free(handle);
|
||||
free(handle);
|
||||
}
|
||||
|
||||
uacpi_thread_id uacpi_kernel_get_thread_id(void)
|
||||
{
|
||||
return get_thread_id();
|
||||
}
|
||||
|
||||
uacpi_status uacpi_kernel_acquire_mutex(uacpi_handle handle, uacpi_u16 timeout)
|
||||
{
|
||||
if (timeout == 0)
|
||||
return mutex_try_lock(handle) ? UACPI_STATUS_OK : UACPI_STATUS_TIMEOUT;
|
||||
|
||||
if (timeout == 0xFFFF) {
|
||||
mutex_lock(handle);
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
if (mutex_lock_timeout(handle, timeout * 1000000ull))
|
||||
return UACPI_STATUS_OK;
|
||||
|
||||
return UACPI_STATUS_TIMEOUT;
|
||||
}
|
||||
|
||||
void uacpi_kernel_release_mutex(uacpi_handle handle)
|
||||
{
|
||||
mutex_unlock(handle);
|
||||
}
|
||||
|
||||
typedef struct {
|
||||
mutex_t mutex;
|
||||
condvar_t condvar;
|
||||
size_t counter;
|
||||
} event_t;
|
||||
|
||||
uacpi_handle uacpi_kernel_create_event(void)
|
||||
{
|
||||
event_t *event = do_calloc(1, sizeof(*event));
|
||||
|
||||
mutex_init(&event->mutex);
|
||||
condvar_init(&event->condvar);
|
||||
return event;
|
||||
}
|
||||
|
||||
void uacpi_kernel_free_event(uacpi_handle handle)
|
||||
{
|
||||
event_t *event = handle;
|
||||
|
||||
condvar_free(&event->condvar);
|
||||
mutex_free(&event->mutex);
|
||||
free(handle);
|
||||
}
|
||||
|
||||
static bool event_pred(void *ptr)
|
||||
{
|
||||
event_t *event = ptr;
|
||||
|
||||
return event->counter != 0;
|
||||
}
|
||||
|
||||
uacpi_bool uacpi_kernel_wait_for_event(uacpi_handle handle, uacpi_u16 timeout)
|
||||
{
|
||||
event_t *event = handle;
|
||||
bool ok;
|
||||
|
||||
mutex_lock(&event->mutex);
|
||||
|
||||
if (event->counter > 0) {
|
||||
event->counter -= 1;
|
||||
mutex_unlock(&event->mutex);
|
||||
return UACPI_TRUE;
|
||||
}
|
||||
|
||||
if (timeout == 0) {
|
||||
mutex_unlock(&event->mutex);
|
||||
return UACPI_FALSE;
|
||||
}
|
||||
|
||||
if (timeout == 0xFFFF) {
|
||||
condvar_wait(&event->condvar, &event->mutex, event_pred, event);
|
||||
|
||||
event->counter -= 1;
|
||||
mutex_unlock(&event->mutex);
|
||||
return UACPI_TRUE;
|
||||
}
|
||||
|
||||
ok = condvar_wait_timeout(
|
||||
&event->condvar, &event->mutex, event_pred, event, timeout * 1000000ull
|
||||
);
|
||||
if (ok)
|
||||
event->counter -= 1;
|
||||
|
||||
mutex_unlock(&event->mutex);
|
||||
return ok ? UACPI_TRUE : UACPI_FALSE;
|
||||
}
|
||||
|
||||
void uacpi_kernel_signal_event(uacpi_handle handle)
|
||||
{
|
||||
event_t *event = handle;
|
||||
|
||||
mutex_lock(&event->mutex);
|
||||
|
||||
event->counter += 1;
|
||||
condvar_signal(&event->condvar);
|
||||
|
||||
mutex_unlock(&event->mutex);
|
||||
}
|
||||
|
||||
void uacpi_kernel_reset_event(uacpi_handle handle)
|
||||
{
|
||||
event_t *event = handle;
|
||||
|
||||
mutex_lock(&event->mutex);
|
||||
|
||||
event->counter = 0;
|
||||
|
||||
mutex_unlock(&event->mutex);
|
||||
}
|
||||
|
||||
uacpi_status uacpi_kernel_handle_firmware_request(uacpi_firmware_request *req)
|
||||
{
|
||||
switch (req->type) {
|
||||
case UACPI_FIRMWARE_REQUEST_TYPE_BREAKPOINT:
|
||||
printf("Ignoring breakpoint\n");
|
||||
break;
|
||||
case UACPI_FIRMWARE_REQUEST_TYPE_FATAL:
|
||||
printf(
|
||||
"Fatal firmware error: type: %" PRIx8 " code: %" PRIx32 " arg: "
|
||||
"%" PRIx64 "\n", req->fatal.type, req->fatal.code, req->fatal.arg
|
||||
);
|
||||
break;
|
||||
default:
|
||||
error("unknown firmware request type %d", req->type);
|
||||
}
|
||||
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
uacpi_status uacpi_kernel_install_interrupt_handler(
|
||||
uacpi_u32 irq, uacpi_interrupt_handler handler, uacpi_handle ctx,
|
||||
uacpi_handle *out_irq_handle
|
||||
)
|
||||
{
|
||||
UACPI_UNUSED(irq);
|
||||
UACPI_UNUSED(handler);
|
||||
UACPI_UNUSED(ctx);
|
||||
UACPI_UNUSED(out_irq_handle);
|
||||
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
uacpi_status uacpi_kernel_uninstall_interrupt_handler(
|
||||
uacpi_interrupt_handler handler, uacpi_handle irq_handle
|
||||
)
|
||||
{
|
||||
UACPI_UNUSED(handler);
|
||||
UACPI_UNUSED(irq_handle);
|
||||
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
uacpi_handle uacpi_kernel_create_spinlock(void)
|
||||
{
|
||||
return uacpi_kernel_create_mutex();
|
||||
}
|
||||
|
||||
void uacpi_kernel_free_spinlock(uacpi_handle handle)
|
||||
{
|
||||
uacpi_kernel_free_mutex(handle);
|
||||
}
|
||||
|
||||
uacpi_cpu_flags uacpi_kernel_lock_spinlock(uacpi_handle handle)
|
||||
{
|
||||
uacpi_kernel_acquire_mutex(handle, 0xFFFF);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void uacpi_kernel_unlock_spinlock(uacpi_handle handle, uacpi_cpu_flags flags)
|
||||
{
|
||||
UACPI_UNUSED(flags);
|
||||
|
||||
uacpi_kernel_release_mutex(handle);
|
||||
}
|
||||
|
||||
uacpi_status uacpi_kernel_schedule_work(
|
||||
uacpi_work_type type, uacpi_work_handler handler, uacpi_handle ctx
|
||||
)
|
||||
{
|
||||
UACPI_UNUSED(type);
|
||||
|
||||
handler(ctx);
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
uacpi_status uacpi_kernel_wait_for_work_completion(void)
|
||||
{
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
290
kernel/hal/x86_64/uACPI/tests/runner/os.h
Normal file
290
kernel/hal/x86_64/uACPI/tests/runner/os.h
Normal file
@ -0,0 +1,290 @@
|
||||
#pragma once
|
||||
|
||||
#include "helpers.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#else
|
||||
#ifdef __WATCOMC__
|
||||
#include <process.h> // provides gettid
|
||||
#elif defined(__APPLE__)
|
||||
#include <mach/mach_time.h>
|
||||
#endif
|
||||
#include <errno.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef CRITICAL_SECTION mutex_t;
|
||||
typedef CONDITION_VARIABLE condvar_t;
|
||||
#define HAVE_TIMED_WAIT 0
|
||||
#else
|
||||
typedef pthread_mutex_t mutex_t;
|
||||
typedef pthread_cond_t condvar_t;
|
||||
|
||||
#if defined(__WATCOMC__) || defined(__APPLE__)
|
||||
#define HAVE_TIMED_WAIT 0
|
||||
#else
|
||||
#define HAVE_TIMED_WAIT 1
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define NANOSECONDS_PER_SECOND 1000000000ull
|
||||
|
||||
static inline uint64_t get_nanosecond_timer(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
static LARGE_INTEGER frequency;
|
||||
LARGE_INTEGER counter;
|
||||
|
||||
if (frequency.QuadPart == 0)
|
||||
if (!QueryPerformanceFrequency(&frequency))
|
||||
error("QueryPerformanceFrequency failed");
|
||||
|
||||
if (!QueryPerformanceCounter(&counter))
|
||||
error("QueryPerformanceCounter failed");
|
||||
|
||||
counter.QuadPart *= NANOSECONDS_PER_SECOND;
|
||||
return counter.QuadPart / frequency.QuadPart;
|
||||
#elif defined(__APPLE__)
|
||||
static struct mach_timebase_info tb;
|
||||
static bool initialized;
|
||||
|
||||
if (!initialized) {
|
||||
if (mach_timebase_info(&tb) != KERN_SUCCESS)
|
||||
error("mach_timebase_info failed");
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
return (mach_absolute_time() * tb.numer) / tb.denom;
|
||||
#else
|
||||
struct timespec ts;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &ts))
|
||||
error("clock_gettime failed");
|
||||
|
||||
return ts.tv_sec * NANOSECONDS_PER_SECOND + ts.tv_nsec;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void *get_thread_id(void)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return (void*)((uintptr_t)GetCurrentThreadId());
|
||||
#elif defined(__APPLE__)
|
||||
uint64_t id;
|
||||
|
||||
if (pthread_threadid_np(NULL, &id))
|
||||
error("pthread_threadid_np failed");
|
||||
return (void*)id;
|
||||
#else
|
||||
return (void*)((uintptr_t)gettid());
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void millisecond_sleep(uint64_t milliseconds)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
Sleep(milliseconds);
|
||||
#else
|
||||
if (usleep(milliseconds * 1000))
|
||||
error("usleep failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void mutex_init(mutex_t *mutex)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
InitializeCriticalSection(mutex);
|
||||
#else
|
||||
if (pthread_mutex_init(mutex, NULL))
|
||||
error("pthread_mutex_init failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void mutex_free(mutex_t *mutex)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
DeleteCriticalSection(mutex);
|
||||
#else
|
||||
if (pthread_mutex_destroy(mutex))
|
||||
error("pthread_mutex_destroy failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool mutex_try_lock(mutex_t *mutex)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
return TryEnterCriticalSection(mutex);
|
||||
#else
|
||||
int err = pthread_mutex_trylock(mutex);
|
||||
|
||||
if (err == 0)
|
||||
return true;
|
||||
if (err != EBUSY)
|
||||
error("pthread_mutex_trylock failed");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void mutex_lock(mutex_t *mutex)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
EnterCriticalSection(mutex);
|
||||
#else
|
||||
if (pthread_mutex_lock(mutex))
|
||||
error("pthread_mutex_lock failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool mutex_lock_timeout(mutex_t *mutex, uint64_t timeout_ns)
|
||||
{
|
||||
#if !HAVE_TIMED_WAIT
|
||||
uint64_t end = get_nanosecond_timer() + timeout_ns;
|
||||
|
||||
do {
|
||||
if (mutex_try_lock(mutex))
|
||||
return true;
|
||||
millisecond_sleep(1);
|
||||
} while (get_nanosecond_timer() < end);
|
||||
|
||||
return false;
|
||||
#else
|
||||
struct timespec spec;
|
||||
int err;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &spec))
|
||||
error("clock_gettime failed");
|
||||
|
||||
spec.tv_nsec += timeout_ns;
|
||||
spec.tv_sec += spec.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||
spec.tv_nsec %= NANOSECONDS_PER_SECOND;
|
||||
|
||||
err = pthread_mutex_clocklock(mutex, CLOCK_MONOTONIC, &spec);
|
||||
if (err == 0)
|
||||
return true;
|
||||
if (err != ETIMEDOUT)
|
||||
error("pthread_mutex_clocklock failed");
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void mutex_unlock(mutex_t *mutex)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
LeaveCriticalSection(mutex);
|
||||
#else
|
||||
if (pthread_mutex_unlock(mutex))
|
||||
error("pthread_mutex_unlock failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void condvar_init(condvar_t *var)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
InitializeConditionVariable(var);
|
||||
#else
|
||||
if (pthread_cond_init(var, NULL))
|
||||
error("pthread_cond_init failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void condvar_free(condvar_t *var)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
UACPI_UNUSED(var);
|
||||
#else
|
||||
if (pthread_cond_destroy(var))
|
||||
error("pthread_cond_destroy failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
typedef bool (*condvar_pred_t)(void *ctx);
|
||||
|
||||
static inline void condvar_wait(
|
||||
condvar_t *var, mutex_t *mutex, condvar_pred_t pred, void *ctx
|
||||
)
|
||||
{
|
||||
while (!pred(ctx))
|
||||
#ifdef _WIN32
|
||||
if (!SleepConditionVariableCS(var, mutex, INFINITE))
|
||||
error("SleepConditionVariableCS failed");
|
||||
#else
|
||||
if (pthread_cond_wait(var, mutex))
|
||||
error("pthread_cond_wait failed");
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline bool condvar_wait_timeout(
|
||||
condvar_t *var, mutex_t *mutex, condvar_pred_t pred, void *ctx,
|
||||
uint64_t timeout_ns
|
||||
)
|
||||
{
|
||||
#if !HAVE_TIMED_WAIT
|
||||
uint64_t end = get_nanosecond_timer() + timeout_ns;
|
||||
|
||||
while (!pred(ctx)) {
|
||||
uint64_t cur = get_nanosecond_timer();
|
||||
#ifdef _WIN32
|
||||
DWORD milliseconds;
|
||||
#endif
|
||||
|
||||
if (cur >= end)
|
||||
return false;
|
||||
|
||||
#ifdef _WIN32
|
||||
milliseconds = (end - cur) / 1000;
|
||||
if (milliseconds == 0)
|
||||
milliseconds = 1;
|
||||
|
||||
if (!SleepConditionVariableCS(var, mutex, milliseconds) &&
|
||||
GetLastError() != ERROR_TIMEOUT) {
|
||||
error("SleepConditionVariableCS failed");
|
||||
}
|
||||
#else
|
||||
UACPI_UNUSED(var);
|
||||
mutex_unlock(mutex);
|
||||
millisecond_sleep(1);
|
||||
mutex_lock(mutex);
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
struct timespec spec;
|
||||
|
||||
if (clock_gettime(CLOCK_MONOTONIC, &spec))
|
||||
error("clock_gettime failed");
|
||||
|
||||
spec.tv_nsec += timeout_ns;
|
||||
spec.tv_sec += spec.tv_nsec / NANOSECONDS_PER_SECOND;
|
||||
spec.tv_nsec %= NANOSECONDS_PER_SECOND;
|
||||
|
||||
while (!pred(ctx)) {
|
||||
int err = pthread_cond_clockwait(var, mutex, CLOCK_MONOTONIC, &spec);
|
||||
|
||||
if (err == 0)
|
||||
continue;
|
||||
if (err != ETIMEDOUT)
|
||||
error("pthread_cond_clockwait failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void condvar_signal(condvar_t *var)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
WakeConditionVariable(var);
|
||||
#else
|
||||
if (pthread_cond_signal(var))
|
||||
error("pthread_cond_signal failed");
|
||||
#endif
|
||||
}
|
2476
kernel/hal/x86_64/uACPI/tests/runner/resource_tests.c
Normal file
2476
kernel/hal/x86_64/uACPI/tests/runner/resource_tests.c
Normal file
File diff suppressed because it is too large
Load Diff
570
kernel/hal/x86_64/uACPI/tests/runner/test_runner.c
Normal file
570
kernel/hal/x86_64/uACPI/tests/runner/test_runner.c
Normal file
@ -0,0 +1,570 @@
|
||||
#include "argparser.h"
|
||||
#include "helpers.h"
|
||||
#include <inttypes.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <uacpi/acpi.h>
|
||||
#include <uacpi/context.h>
|
||||
#include <uacpi/event.h>
|
||||
#include <uacpi/log.h>
|
||||
#include <uacpi/namespace.h>
|
||||
#include <uacpi/notify.h>
|
||||
#include <uacpi/opregion.h>
|
||||
#include <uacpi/osi.h>
|
||||
#include <uacpi/platform/types.h>
|
||||
#include <uacpi/resources.h>
|
||||
#include <uacpi/status.h>
|
||||
#include <uacpi/tables.h>
|
||||
#include <uacpi/types.h>
|
||||
#include <uacpi/uacpi.h>
|
||||
#include <uacpi/utilities.h>
|
||||
|
||||
void run_resource_tests(void);
|
||||
void test_object_api(void);
|
||||
void test_address_spaces(void);
|
||||
void interface_cleanup(void);
|
||||
|
||||
static uacpi_object_type string_to_object_type(const char *str)
|
||||
{
|
||||
if (strcmp(str, "int") == 0)
|
||||
return UACPI_OBJECT_INTEGER;
|
||||
if (strcmp(str, "str") == 0)
|
||||
return UACPI_OBJECT_STRING;
|
||||
|
||||
error("Unsupported type for validation: %s", str);
|
||||
return UACPI_OBJECT_UNINITIALIZED;
|
||||
}
|
||||
|
||||
static void validate_ret_against_expected(
|
||||
uacpi_object *obj, uacpi_object_type expected_type, const char *expected_val
|
||||
)
|
||||
{
|
||||
uacpi_object_type type = uacpi_object_get_type(obj);
|
||||
|
||||
if (type != expected_type)
|
||||
error(
|
||||
"returned type '%s' doesn't match expected '%s",
|
||||
uacpi_object_type_to_string(expected_type),
|
||||
uacpi_object_type_to_string(type)
|
||||
);
|
||||
|
||||
switch (type) {
|
||||
case UACPI_OBJECT_INTEGER: {
|
||||
uacpi_u64 expected_int = strtoull(expected_val, NULL, 0);
|
||||
uacpi_u64 actual_int;
|
||||
|
||||
uacpi_object_get_integer(obj, &actual_int);
|
||||
|
||||
if (expected_int != actual_int)
|
||||
error(
|
||||
"returned value '%" PRIu64 "' doesn't match expected '%" PRIu64
|
||||
"'", actual_int, expected_int
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
case UACPI_OBJECT_STRING: {
|
||||
uacpi_data_view view;
|
||||
const char *actual_str;
|
||||
|
||||
uacpi_object_get_string_or_buffer(obj, &view);
|
||||
actual_str = view.text;
|
||||
|
||||
if (strcmp(expected_val, actual_str) != 0)
|
||||
error(
|
||||
"returned value '%s' doesn't match expected '%s'",
|
||||
actual_str, expected_val
|
||||
);
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
static void nested_printf(uacpi_u32 depth, const char *fmt, ...)
|
||||
{
|
||||
va_list va;
|
||||
size_t padding = depth * 4;
|
||||
|
||||
while (padding-- > 0)
|
||||
printf(" ");
|
||||
|
||||
va_start(va, fmt);
|
||||
vprintf(fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
static void dump_resources(
|
||||
uacpi_u32 depth, uacpi_namespace_node *node,
|
||||
uacpi_status (*cb)(uacpi_namespace_node *, uacpi_resources **),
|
||||
const char *name
|
||||
)
|
||||
{
|
||||
uacpi_resources *res;
|
||||
uacpi_status ret = cb(node, &res);
|
||||
|
||||
if (ret == UACPI_STATUS_OK) {
|
||||
// TODO: dump resources here
|
||||
nested_printf(depth, " %s: <%u bytes>\n", name, res->length);
|
||||
uacpi_free_resources(res);
|
||||
} else if (ret != UACPI_STATUS_NOT_FOUND)
|
||||
nested_printf(
|
||||
depth, " %s: unable to evaluate (%s)\n", name,
|
||||
uacpi_status_to_string(ret)
|
||||
);
|
||||
}
|
||||
|
||||
static uacpi_iteration_decision dump_one_node(
|
||||
void *ptr, uacpi_namespace_node *node, uacpi_u32 depth
|
||||
)
|
||||
{
|
||||
struct uacpi_namespace_node_info *info;
|
||||
uacpi_status ret = uacpi_get_namespace_node_info(node, &info);
|
||||
const char *path;
|
||||
|
||||
UACPI_UNUSED(ptr);
|
||||
|
||||
if (uacpi_unlikely_error(ret)) {
|
||||
uacpi_object_name name = uacpi_namespace_node_name(node);
|
||||
|
||||
fprintf(
|
||||
stderr, "unable to get node %.4s info: %s\n", name.text,
|
||||
uacpi_status_to_string(ret)
|
||||
);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
path = uacpi_namespace_node_generate_absolute_path(node);
|
||||
nested_printf(
|
||||
depth, "%s [%s]", path, uacpi_object_type_to_string(info->type)
|
||||
);
|
||||
uacpi_free_absolute_path(path);
|
||||
|
||||
if (info->type == UACPI_OBJECT_METHOD)
|
||||
printf(" (%d args)", info->num_params);
|
||||
|
||||
if (info->flags)
|
||||
printf(" {\n");
|
||||
|
||||
if (info->flags)
|
||||
nested_printf(depth, " _ADR: %016" PRIX64 "\n", info->adr);
|
||||
|
||||
if (info->flags & UACPI_NS_NODE_INFO_HAS_HID)
|
||||
nested_printf(depth, " _HID: %s\n", info->hid.value);
|
||||
|
||||
if (info->flags & UACPI_NS_NODE_INFO_HAS_CID) {
|
||||
size_t i;
|
||||
|
||||
nested_printf(depth, " _CID: ");
|
||||
for (i = 0; i < info->cid.num_ids; ++i)
|
||||
printf("%s ", info->cid.ids[i].value);
|
||||
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (info->flags & UACPI_NS_NODE_INFO_HAS_UID)
|
||||
nested_printf(depth, " _UID: %s\n", info->uid.value);
|
||||
|
||||
if (info->flags & UACPI_NS_NODE_INFO_HAS_CLS)
|
||||
nested_printf(depth, " _CLS: %s\n", info->cls.value);
|
||||
|
||||
if (info->flags & UACPI_NS_NODE_INFO_HAS_SXD)
|
||||
nested_printf(
|
||||
depth, " _SxD: S1->D%d S2->D%d S3->D%d S4->D%d\n", info->sxd[0],
|
||||
info->sxd[1], info->sxd[2], info->sxd[3]
|
||||
);
|
||||
|
||||
if (info->flags & UACPI_NS_NODE_INFO_HAS_SXW)
|
||||
nested_printf(
|
||||
depth, " _SxW: S0->D%d S1->D%d S2->D%d S3->D%d S4->D%d\n",
|
||||
info->sxw[0], info->sxw[1], info->sxw[2], info->sxw[3], info->sxw[4]
|
||||
);
|
||||
|
||||
if (info->flags) {
|
||||
if (info->type == UACPI_OBJECT_DEVICE) {
|
||||
dump_resources(depth, node, uacpi_get_current_resources, "_CRS");
|
||||
dump_resources(depth, node, uacpi_get_possible_resources, "_PRS");
|
||||
}
|
||||
|
||||
nested_printf(depth, "}\n");
|
||||
} else
|
||||
printf("\n");
|
||||
|
||||
uacpi_free_namespace_node_info(info);
|
||||
return UACPI_ITERATION_DECISION_CONTINUE;
|
||||
}
|
||||
|
||||
static void enumerate_namespace(void)
|
||||
{
|
||||
uacpi_namespace_node *root = uacpi_namespace_root();
|
||||
|
||||
dump_one_node(NULL, root, 0);
|
||||
uacpi_namespace_for_each_child_simple(root, dump_one_node, NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* DefinitionBlock ("x.aml", "SSDT", 1, "uTEST", "OVERRIDE", 0xF0F0F0F0)
|
||||
* {
|
||||
* Name (VAL, "TestRunner")
|
||||
* }
|
||||
*/
|
||||
static uint8_t table_override[] = {
|
||||
0x53, 0x53, 0x44, 0x54, 0x35, 0x00, 0x00, 0x00,
|
||||
0x01, 0xa1, 0x75, 0x54, 0x45, 0x53, 0x54, 0x00,
|
||||
0x4f, 0x56, 0x45, 0x52, 0x52, 0x49, 0x44, 0x45,
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0x49, 0x4e, 0x54, 0x4c,
|
||||
0x25, 0x09, 0x20, 0x20, 0x08, 0x56, 0x41, 0x4c,
|
||||
0x5f, 0x0d, 0x54, 0x65, 0x73, 0x74, 0x52, 0x75,
|
||||
0x6e, 0x6e, 0x65, 0x72, 0x00
|
||||
};
|
||||
|
||||
/*
|
||||
* DefinitionBlock ("x.aml", "SSDT", 1, "uTEST", "RUNRIDTB", 0xF0F0F0F0)
|
||||
* {
|
||||
* Name (\_SI.TID, "uACPI")
|
||||
* Printf("TestRunner ID SSDT loaded!")
|
||||
* }
|
||||
*/
|
||||
static uint8_t runner_id_table[] = {
|
||||
0x53, 0x53, 0x44, 0x54, 0x55, 0x00, 0x00, 0x00,
|
||||
0x01, 0x45, 0x75, 0x54, 0x45, 0x53, 0x54, 0x00,
|
||||
0x52, 0x55, 0x4e, 0x52, 0x49, 0x44, 0x54, 0x42,
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0x49, 0x4e, 0x54, 0x4c,
|
||||
0x25, 0x09, 0x20, 0x20, 0x08, 0x5c, 0x2e, 0x5f,
|
||||
0x53, 0x49, 0x5f, 0x54, 0x49, 0x44, 0x5f, 0x0d,
|
||||
0x75, 0x41, 0x43, 0x50, 0x49, 0x00, 0x70, 0x0d,
|
||||
0x54, 0x65, 0x73, 0x74, 0x52, 0x75, 0x6e, 0x6e,
|
||||
0x65, 0x72, 0x20, 0x49, 0x44, 0x20, 0x53, 0x53,
|
||||
0x44, 0x54, 0x20, 0x6c, 0x6f, 0x61, 0x64, 0x65,
|
||||
0x64, 0x21, 0x00, 0x5b, 0x31
|
||||
};
|
||||
|
||||
static uacpi_table_installation_disposition handle_table_install(
|
||||
struct acpi_sdt_hdr *hdr, uacpi_u64 *out_override
|
||||
)
|
||||
{
|
||||
if (!strncmp(hdr->oem_table_id, "DENYTABL", sizeof(hdr->oem_table_id)))
|
||||
return UACPI_TABLE_INSTALLATION_DISPOSITON_DENY;
|
||||
|
||||
if (strncmp(hdr->oem_table_id, "OVERTABL", sizeof(hdr->oem_table_id)))
|
||||
return UACPI_TABLE_INSTALLATION_DISPOSITON_ALLOW;
|
||||
|
||||
*out_override = (uacpi_virt_addr)table_override;
|
||||
return UACPI_TABLE_INSTALLATION_DISPOSITON_VIRTUAL_OVERRIDE;
|
||||
}
|
||||
|
||||
static uacpi_status handle_notify(
|
||||
uacpi_handle handle, uacpi_namespace_node *node, uacpi_u64 value
|
||||
)
|
||||
{
|
||||
const char *path = uacpi_namespace_node_generate_absolute_path(node);
|
||||
|
||||
UACPI_UNUSED(handle);
|
||||
|
||||
printf("Received a notification from %s %" PRIx64 "\n", path, value);
|
||||
|
||||
free((void*)path);
|
||||
return UACPI_STATUS_OK;
|
||||
}
|
||||
|
||||
static uacpi_status handle_ec(uacpi_region_op op, uacpi_handle op_data)
|
||||
{
|
||||
switch (op) {
|
||||
case UACPI_REGION_OP_READ: {
|
||||
uacpi_region_rw_data *rw_data = (uacpi_region_rw_data*)op_data;
|
||||
|
||||
rw_data->value = 0;
|
||||
UACPI_FALLTHROUGH;
|
||||
}
|
||||
case UACPI_REGION_OP_ATTACH:
|
||||
case UACPI_REGION_OP_DETACH:
|
||||
case UACPI_REGION_OP_WRITE:
|
||||
return UACPI_STATUS_OK;
|
||||
default:
|
||||
return UACPI_STATUS_INVALID_ARGUMENT;
|
||||
}
|
||||
}
|
||||
|
||||
static uacpi_interrupt_ret handle_gpe(
|
||||
uacpi_handle handle, uacpi_namespace_node *node, uint16_t idx
|
||||
)
|
||||
{
|
||||
UACPI_UNUSED(handle);
|
||||
UACPI_UNUSED(node);
|
||||
UACPI_UNUSED(idx);
|
||||
|
||||
return UACPI_INTERRUPT_HANDLED | UACPI_GPE_REENABLE;
|
||||
}
|
||||
|
||||
static void run_test(
|
||||
const char *dsdt_path, const vector_t *ssdt_paths,
|
||||
uacpi_object_type expected_type, const char *expected_value,
|
||||
bool dump_namespace
|
||||
)
|
||||
{
|
||||
static uint8_t early_table_buf[4096];
|
||||
struct acpi_rsdp rsdp = { 0 };
|
||||
struct full_xsdt *xsdt = make_xsdt(&rsdp, dsdt_path, ssdt_paths);
|
||||
uacpi_status st;
|
||||
uacpi_table tbl;
|
||||
bool is_test_mode;
|
||||
uacpi_object *ret = NULL;
|
||||
|
||||
g_rsdp = (uacpi_phys_addr)((uintptr_t)&rsdp);
|
||||
|
||||
st = uacpi_setup_early_table_access(
|
||||
early_table_buf, sizeof(early_table_buf)
|
||||
);
|
||||
ensure_ok_status(st);
|
||||
|
||||
st = uacpi_table_find_by_signature(ACPI_DSDT_SIGNATURE, &tbl);
|
||||
ensure_ok_status(st);
|
||||
|
||||
if (strncmp(tbl.hdr->signature, ACPI_DSDT_SIGNATURE, 4) != 0)
|
||||
error("broken early table access!");
|
||||
|
||||
st = uacpi_table_unref(&tbl);
|
||||
ensure_ok_status(st);
|
||||
|
||||
st = uacpi_initialize(UACPI_FLAG_NO_ACPI_MODE);
|
||||
ensure_ok_status(st);
|
||||
|
||||
/*
|
||||
* Go through all AML tables and manually bump their reference counts here
|
||||
* so that they're mapped before the call to uacpi_namespace_load(). The
|
||||
* reason we need this is to disambiguate calls to uacpi_kernel_map() with
|
||||
* a synthetic physical address (that is actually a virtual address for
|
||||
* tables that we constructed earlier) or a real physical address that comes
|
||||
* from some operation region or any other AML code or action.
|
||||
*/
|
||||
uacpi_table_find_by_signature(ACPI_DSDT_SIGNATURE, &tbl);
|
||||
|
||||
st = uacpi_table_find_by_signature(ACPI_SSDT_SIGNATURE, &tbl);
|
||||
while (st == UACPI_STATUS_OK) {
|
||||
uacpi_table_ref(&tbl);
|
||||
st = uacpi_table_find_next_with_same_signature(&tbl);
|
||||
}
|
||||
|
||||
g_expect_virtual_addresses = false;
|
||||
|
||||
st = uacpi_install_notify_handler(
|
||||
uacpi_namespace_root(), handle_notify, NULL
|
||||
);
|
||||
ensure_ok_status(st);
|
||||
|
||||
st = uacpi_set_table_installation_handler(handle_table_install);
|
||||
ensure_ok_status(st);
|
||||
|
||||
st = uacpi_install_interface("TestRunner", UACPI_INTERFACE_KIND_FEATURE);
|
||||
ensure_ok_status(st);
|
||||
|
||||
st = uacpi_uninstall_interface("Windows 2006");
|
||||
ensure_ok_status(st);
|
||||
|
||||
st = uacpi_uninstall_interface("Windows 2006");
|
||||
if (st != UACPI_STATUS_NOT_FOUND)
|
||||
error("couldn't uninstall interface");
|
||||
|
||||
st = uacpi_enable_host_interface(UACPI_HOST_INTERFACE_3_0_THERMAL_MODEL);
|
||||
ensure_ok_status(st);
|
||||
|
||||
st = uacpi_enable_host_interface(UACPI_HOST_INTERFACE_MODULE_DEVICE);
|
||||
ensure_ok_status(st);
|
||||
|
||||
is_test_mode = expected_type != UACPI_OBJECT_UNINITIALIZED;
|
||||
if (is_test_mode) {
|
||||
st = uacpi_table_install(runner_id_table, NULL);
|
||||
ensure_ok_status(st);
|
||||
}
|
||||
|
||||
st = uacpi_namespace_load();
|
||||
ensure_ok_status(st);
|
||||
|
||||
if (is_test_mode) {
|
||||
uacpi_object *runner_id = UACPI_NULL;
|
||||
uacpi_data_view view;
|
||||
|
||||
st = uacpi_eval_typed(
|
||||
UACPI_NULL, "\\_SI.TID", UACPI_NULL, UACPI_OBJECT_STRING_BIT,
|
||||
&runner_id
|
||||
);
|
||||
ensure_ok_status(st);
|
||||
|
||||
st = uacpi_object_get_string_or_buffer(runner_id, &view);
|
||||
ensure_ok_status(st);
|
||||
|
||||
if (strcmp(view.text, "uACPI") != 0)
|
||||
error("invalid test runner id");
|
||||
uacpi_object_unref(runner_id);
|
||||
}
|
||||
|
||||
st = uacpi_install_address_space_handler(
|
||||
uacpi_namespace_root(), UACPI_ADDRESS_SPACE_EMBEDDED_CONTROLLER,
|
||||
handle_ec, NULL
|
||||
);
|
||||
ensure_ok_status(st);
|
||||
|
||||
st = uacpi_install_gpe_handler(
|
||||
UACPI_NULL, 123, UACPI_GPE_TRIGGERING_EDGE, handle_gpe, NULL
|
||||
);
|
||||
ensure_ok_status(st);
|
||||
|
||||
st = uacpi_enable_gpe(UACPI_NULL, 123);
|
||||
ensure_ok_status(st);
|
||||
|
||||
st = uacpi_disable_gpe(UACPI_NULL, 123);
|
||||
ensure_ok_status(st);
|
||||
|
||||
st = uacpi_uninstall_gpe_handler(UACPI_NULL, 123, handle_gpe);
|
||||
ensure_ok_status(st);
|
||||
|
||||
st = uacpi_namespace_initialize();
|
||||
ensure_ok_status(st);
|
||||
|
||||
if (dump_namespace)
|
||||
enumerate_namespace();
|
||||
|
||||
if (!is_test_mode)
|
||||
goto done;
|
||||
|
||||
if (strcmp(expected_value, "check-object-api-works") == 0) {
|
||||
test_object_api();
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (strcmp(expected_value, "check-address-spaces-work") == 0) {
|
||||
test_address_spaces();
|
||||
goto done;
|
||||
}
|
||||
|
||||
st = uacpi_eval(UACPI_NULL, "\\MAIN", UACPI_NULL, &ret);
|
||||
|
||||
ensure_ok_status(st);
|
||||
if (ret == NULL)
|
||||
error("\\MAIN didn't return a value");
|
||||
validate_ret_against_expected(ret, expected_type, expected_value);
|
||||
|
||||
uacpi_object_unref(ret);
|
||||
done:
|
||||
uacpi_state_reset();
|
||||
delete_xsdt(xsdt, ssdt_paths->count);
|
||||
interface_cleanup();
|
||||
}
|
||||
|
||||
static uacpi_log_level log_level_from_string(const char *arg)
|
||||
{
|
||||
static struct {
|
||||
const char *str;
|
||||
uacpi_log_level level;
|
||||
} log_levels[] = {
|
||||
{ "debug", UACPI_LOG_DEBUG },
|
||||
{ "trace", UACPI_LOG_TRACE },
|
||||
{ "info", UACPI_LOG_INFO },
|
||||
{ "warning", UACPI_LOG_WARN },
|
||||
{ "error", UACPI_LOG_ERROR },
|
||||
};
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < UACPI_ARRAY_SIZE(log_levels); i++)
|
||||
if (strcmp(log_levels[i].str, arg) == 0)
|
||||
return log_levels[i].level;
|
||||
|
||||
error("invalid log level %s", arg);
|
||||
return UACPI_LOG_INFO;
|
||||
}
|
||||
|
||||
static arg_spec_t DSDT_PATH_ARG = ARG_POS(
|
||||
"dsdt-path-or-keyword",
|
||||
"path to the DSDT to run or \"resource-tests\" to run the resource tests"
|
||||
);
|
||||
|
||||
static arg_spec_t EXPECT_ARG = ARG_LIST(
|
||||
"expect", 'r',
|
||||
"test mode, evaluate \\MAIN and expect <expected-type> <expected-value>"
|
||||
);
|
||||
static arg_spec_t EXTRA_TABLES_ARG = ARG_LIST(
|
||||
"extra-tables", 'x', "a list of extra SSDTs to load"
|
||||
);
|
||||
static arg_spec_t ENUMERATE_NAMESPACE_ARG = ARG_FLAG(
|
||||
"enumerate-namespace", 'd', "dump the entire namespace after loading it"
|
||||
);
|
||||
static arg_spec_t WHILE_LOOP_TIMEOUT_ARG = ARG_PARAM(
|
||||
"while-loop-timeout", 't',
|
||||
"number of seconds to use for the while loop timeout"
|
||||
);
|
||||
static arg_spec_t LOG_LEVEL_ARG = ARG_PARAM(
|
||||
"log-level", 'l',
|
||||
"log level to set, one of: debug, trace, info, warning, error"
|
||||
);
|
||||
static arg_spec_t HELP_ARG = ARG_HELP(
|
||||
"help", 'h', "Display this menu and exit"
|
||||
);
|
||||
|
||||
static arg_spec_t *const POSITIONAL_ARGS[] = {
|
||||
&DSDT_PATH_ARG,
|
||||
};
|
||||
|
||||
static arg_spec_t *const OPTION_ARGS[] = {
|
||||
&EXPECT_ARG,
|
||||
&EXTRA_TABLES_ARG,
|
||||
&ENUMERATE_NAMESPACE_ARG,
|
||||
&WHILE_LOOP_TIMEOUT_ARG,
|
||||
&LOG_LEVEL_ARG,
|
||||
&HELP_ARG,
|
||||
};
|
||||
|
||||
static const arg_parser_t PARSER = {
|
||||
.positional_args = POSITIONAL_ARGS,
|
||||
.num_positional_args = UACPI_ARRAY_SIZE(POSITIONAL_ARGS),
|
||||
.option_args = OPTION_ARGS,
|
||||
.num_option_args = UACPI_ARRAY_SIZE(OPTION_ARGS),
|
||||
};
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const char *dsdt_path_or_keyword;
|
||||
const char *expected_value = NULL;
|
||||
uacpi_object_type expected_type = UACPI_OBJECT_UNINITIALIZED;
|
||||
bool dump_namespace;
|
||||
uacpi_log_level log_level;
|
||||
|
||||
parse_args(&PARSER, argc, argv);
|
||||
|
||||
uacpi_context_set_loop_timeout(get_uint_or(&WHILE_LOOP_TIMEOUT_ARG, 3));
|
||||
|
||||
dsdt_path_or_keyword = get(&DSDT_PATH_ARG);
|
||||
if (strcmp(dsdt_path_or_keyword, "resource-tests") == 0) {
|
||||
run_resource_tests();
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (is_set(&EXPECT_ARG)) {
|
||||
if (EXPECT_ARG.values.count != 2)
|
||||
error("bad --expect format");
|
||||
|
||||
expected_type = string_to_object_type(EXPECT_ARG.values.blobs[0].data);
|
||||
expected_value = EXPECT_ARG.values.blobs[1].data;
|
||||
}
|
||||
|
||||
dump_namespace = is_set(&ENUMERATE_NAMESPACE_ARG);
|
||||
// Don't spam the log with traces if enumeration is enabled
|
||||
log_level = dump_namespace ? UACPI_LOG_INFO : UACPI_LOG_TRACE;
|
||||
|
||||
if (is_set(&LOG_LEVEL_ARG))
|
||||
log_level = log_level_from_string(get(&LOG_LEVEL_ARG));
|
||||
|
||||
uacpi_context_set_log_level(log_level);
|
||||
|
||||
run_test(
|
||||
dsdt_path_or_keyword, &EXTRA_TABLES_ARG.values, expected_type,
|
||||
expected_value, dump_namespace
|
||||
);
|
||||
|
||||
return 0;
|
||||
}
|
415
kernel/hal/x86_64/uACPI/tests/test-cases/address-spaces-work.asl
Normal file
415
kernel/hal/x86_64/uACPI/tests/test-cases/address-spaces-work.asl
Normal file
@ -0,0 +1,415 @@
|
||||
// Name: Support for various address spaces works
|
||||
// Expect: str => check-address-spaces-work
|
||||
|
||||
DefinitionBlock ("x.aml", "SSDT", 1, "uTEST", "ASPTESTS", 0xF0F0F0F0)
|
||||
{
|
||||
Method (MAIN) {
|
||||
// Skip for non-uacpi test runners
|
||||
Return ("check-address-spaces-work")
|
||||
}
|
||||
|
||||
Method (DOIP, 1, Serialized) {
|
||||
If (Arg0 == 0) {
|
||||
Local0 = "DEADBEE0"
|
||||
Local1 = 0xDEADBEE0
|
||||
} Else {
|
||||
Local0 = "DEADBEEF"
|
||||
Local1 = 0xDEADBEEF
|
||||
}
|
||||
|
||||
OperationRegion (IPMR, IPMI, 0xDEADBEE0, 10)
|
||||
Field (IPMR, BufferAcc, NoLock, Preserve) {
|
||||
CMD0, 120,
|
||||
|
||||
// Offset = base + 0xF
|
||||
CMD1, 1234,
|
||||
}
|
||||
|
||||
Name (REQ, Buffer (32) { })
|
||||
Name (RET, 0)
|
||||
|
||||
REQ = Concatenate("IPMICommand", Local0)
|
||||
|
||||
If (Arg0 == 0) {
|
||||
Local0 = CMD0 = REQ
|
||||
} Else {
|
||||
Local0 = CMD1 = REQ
|
||||
}
|
||||
|
||||
If (SizeOf(Local0) != 66) {
|
||||
Printf("Unexpected IPMI response size %o", SizeOf(Local0))
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
RET = Local0
|
||||
If (RET != Local1) {
|
||||
Printf("Unexpected IMPI response %o, expected %o", RET, Local1)
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Return (Ones)
|
||||
}
|
||||
|
||||
Device (GPO0)
|
||||
{
|
||||
Name (_HID, "INT33FC" /* Intel Baytrail GPIO Controller */)
|
||||
Name (_DDN, "ValleyView General Purpose Input/Output (GPIO) controller")
|
||||
Name (_UID, 0)
|
||||
}
|
||||
|
||||
Device (GPO1)
|
||||
{
|
||||
Name (_HID, "INT33FC" /* Intel Baytrail GPIO Controller */)
|
||||
Name (_DDN, "ValleyView GPNCORE controller")
|
||||
Name (_UID, 1)
|
||||
}
|
||||
|
||||
Method (DGIO, 0, Serialized) {
|
||||
OperationRegion (GPOP, GeneralPurposeIo, Zero, 0x06)
|
||||
Field (GPOP, ByteAcc, NoLock, Preserve)
|
||||
{
|
||||
Connection (
|
||||
GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly,
|
||||
"\\GPO0", 0x00, ResourceConsumer, ,
|
||||
)
|
||||
{ // Pin list
|
||||
0x0002, 0x0003, 0x0004, 0x0005, 0x0006
|
||||
}
|
||||
),
|
||||
CCU0, 1,
|
||||
CCU1, 3,
|
||||
CCU2, 1,
|
||||
Connection (
|
||||
GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly,
|
||||
"\\GPO1", 0x00, ResourceConsumer, ,
|
||||
)
|
||||
{ // Pin list
|
||||
0x005F
|
||||
}
|
||||
),
|
||||
CCU3, 1
|
||||
}
|
||||
|
||||
CCU0 = 1
|
||||
CCU1 = 2
|
||||
CCU2 = 0
|
||||
|
||||
Local0 = CCU0
|
||||
If (Local0 != 1) {
|
||||
Printf("Bad CCU0 return %o", Local0)
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Local0 = CCU1
|
||||
If (Local0 != 2) {
|
||||
Printf ("Bad CCU1 return %o", Local0)
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Local0 = CCU2
|
||||
If (Local0 != 0) {
|
||||
Printf ("Bad CCU2 return %o", Local0)
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Local0 = CCU3
|
||||
if (Local0 != 0) {
|
||||
Printf ("Bad CCU3 value %o", Local0)
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Return (Ones)
|
||||
}
|
||||
|
||||
Method (DPCC, 0, Serialized) {
|
||||
OperationRegion (GPOP, PCC, 0xCA, 0xFF)
|
||||
Field (GPOP, DWordAcc, NoLock, Preserve)
|
||||
{
|
||||
H, 8,
|
||||
E, 8,
|
||||
L0, 8,
|
||||
L1, 8,
|
||||
O, 8,
|
||||
Offset(12),
|
||||
CMD, 32,
|
||||
}
|
||||
|
||||
Field (GPOP, DWordAcc, NoLock, Preserve)
|
||||
{
|
||||
HELL, 48,
|
||||
}
|
||||
|
||||
H = "H"
|
||||
E = "E"
|
||||
L0 = "L"
|
||||
L1 = "L"
|
||||
O = "O"
|
||||
|
||||
If (ToString(HELL) != "HELLO") {
|
||||
Printf ("Unexpected HELL value %o", ToString(HELL))
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
// Invoke the test runner handler
|
||||
CMD = 0xDEADBEEF
|
||||
|
||||
// We expect it to modify the CMD field as a response
|
||||
If (CMD != 0xBEEFDEAD) {
|
||||
Printf ("Unexpected CMD value %o", CMD)
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Return (Ones)
|
||||
}
|
||||
|
||||
Method (DPRM, 0, Serialized) {
|
||||
OperationRegion (GPOP, PlatformRtMechanism, 0x00, 0xFF)
|
||||
Field (GPOP, BufferAcc, NoLock, Preserve)
|
||||
{
|
||||
DEAD, 80,
|
||||
}
|
||||
|
||||
Local0 = DEAD = "helloworld"
|
||||
Printf("Got a PRM response: %o", Local0)
|
||||
|
||||
If (SizeOf(Local0) != 26) {
|
||||
Printf ("Unexpected Local0 size %o", SizeOf(Local0))
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
If (ToString(Local0) != "goodbyeworld") {
|
||||
Printf ("Unexpected Local0 value %o", ToString(Local0))
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Return (Ones)
|
||||
}
|
||||
|
||||
|
||||
Method (DFHW, 0, Serialized) {
|
||||
OperationRegion (GPOP, FFixedHW, 0xCAFEBABE, 0xFEFECACA)
|
||||
Field (GPOP, BufferAcc, NoLock, Preserve)
|
||||
{
|
||||
X, 1,
|
||||
}
|
||||
|
||||
Local0 = X = "someguidandstuff"
|
||||
Printf("Got a FFixedHW response: %o", Local0)
|
||||
|
||||
If (SizeOf(Local0) != 256) {
|
||||
Printf ("Unexpected Local0 size %o", SizeOf(Local0))
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
If (ToString(Local0) != "ok") {
|
||||
Printf ("Unexpected Local0 value %o", ToString(Local0))
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Return (Ones)
|
||||
}
|
||||
|
||||
Scope (_SB) {
|
||||
Device (I2C0)
|
||||
{
|
||||
Name (_HID, "INT34B2")
|
||||
Name (_UID, 0)
|
||||
}
|
||||
|
||||
Device (I2C1)
|
||||
{
|
||||
Name (_HID, "80860F41" /* Intel Baytrail I2C Host Controller */)
|
||||
Name (_CID, "80860F41" /* Intel Baytrail I2C Host Controller */)
|
||||
Name (_DDN, "Intel(R) I2C Controller #5 - 80860F45")
|
||||
Name (_UID, 1)
|
||||
}
|
||||
}
|
||||
|
||||
Name (RES1, ResourceTemplate ()
|
||||
{
|
||||
I2cSerialBusV2 (0x0008, ControllerInitiated, 0x00061A80,
|
||||
AddressingMode7Bit, "\\_SB.I2C0",
|
||||
0x00, ResourceConsumer, , Exclusive,
|
||||
)
|
||||
})
|
||||
Name (RES2, ResourceTemplate ()
|
||||
{
|
||||
I2cSerialBusV2 (0x0040, ControllerInitiated, 0x00061A80,
|
||||
AddressingMode7Bit, "\\_SB.I2C1",
|
||||
0x00, ResourceConsumer, , Exclusive,
|
||||
)
|
||||
})
|
||||
|
||||
Method (DGSB, 0, Serialized) {
|
||||
Method (CHEK, 3) {
|
||||
If (SizeOf(Arg0) != Arg1) {
|
||||
Printf(
|
||||
"Bad resulting buffer length %o, expected %o",
|
||||
SizeOf(Arg0), Arg1
|
||||
)
|
||||
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Name (INT, 0)
|
||||
INT = Arg0
|
||||
|
||||
If (INT != Arg2) {
|
||||
Printf("Unexpected response %o, expected %o", INT, Arg2)
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Return (Ones)
|
||||
}
|
||||
|
||||
|
||||
OperationRegion (RCH1, GenericSerialBus, 0x100, 0x0100)
|
||||
Field (RCH1, BufferAcc, NoLock, Preserve)
|
||||
{
|
||||
Connection (RES1),
|
||||
Offset (0x11),
|
||||
|
||||
// Command == 0x111
|
||||
AccessAs (BufferAcc, AttribQuick),
|
||||
CMD0, 128,
|
||||
|
||||
// Command == 0x121
|
||||
AccessAs (BufferAcc, AttribSendReceive),
|
||||
CMD1, 8,
|
||||
|
||||
// Command == 0x122
|
||||
AccessAs (BufferAcc, AttribByte),
|
||||
CMD2, 16,
|
||||
|
||||
// Command == 0x124
|
||||
AccessAs (BufferAcc, AttribWord),
|
||||
CMD3, 32,
|
||||
|
||||
// Command == 0x128
|
||||
AccessAs (BufferAcc, AttribBlock),
|
||||
CMD4, 2048,
|
||||
|
||||
// Command == 0x228
|
||||
AccessAs (BufferAcc, AttribProcessCall),
|
||||
CMD5, 8,
|
||||
|
||||
// Command == 0x229
|
||||
AccessAs (BufferAcc, AttribBlockProcessCall),
|
||||
CMD6, 144,
|
||||
|
||||
Connection (RES2),
|
||||
|
||||
// Command == 0x23B
|
||||
AccessAs (BufferAcc, AttribBytes(15)),
|
||||
CMD7, 8,
|
||||
|
||||
// Command == 0x23C
|
||||
AccessAs (BufferAcc, AttribRawBytes(255)),
|
||||
CMD8, 8,
|
||||
|
||||
// Command == 0x23D
|
||||
AccessAs (BufferAcc, AttribRawProcessBytes(123)),
|
||||
CMD9, 8,
|
||||
}
|
||||
|
||||
Local0 = CMD0 = 0x111
|
||||
If (CHEK(Local0, 2, 0x112) != Ones) {
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Local0 = 0x121
|
||||
Local0 = CMD1 = Local0
|
||||
If (CHEK(Local0, 3, 0x122) != Ones) {
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Local0 = CMD2 = 0x122
|
||||
If (CHEK(Local0, 3, 0x123) != Ones) {
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Local0 = CMD3
|
||||
If (CHEK(Local0, 4, 0x125) != Ones) {
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Local0 = CMD4
|
||||
If (CHEK(Local0, 257, 0x129) != Ones) {
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Local0 = CMD5 = 0x228
|
||||
If (CHEK(Local0, 4, 0x229) != Ones) {
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Local0 = CMD6
|
||||
If (CHEK(Local0, 257, 0x22A) != Ones) {
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Local0 = CMD7 = 0x23B
|
||||
If (CHEK(Local0, 15 + 2, 0x23C) != Ones) {
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Local0 = CMD8
|
||||
If (CHEK(Local0, 255 + 2, 0x23D) != Ones) {
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Local0 = CMD9
|
||||
If (CHEK(Local0, 255 + 2, 0x23E) != Ones) {
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Return (Ones)
|
||||
}
|
||||
|
||||
/*
|
||||
* Arg0 -> The address space type
|
||||
* Return -> Ones on succeess, Zero on failure
|
||||
*/
|
||||
Method (CHEK, 1, Serialized) {
|
||||
Switch (Arg0) {
|
||||
Case (7) { // IPMI
|
||||
Local0 = DOIP(0)
|
||||
If (Local0 != Ones) {
|
||||
Break
|
||||
}
|
||||
|
||||
Local0 = DOIP(1)
|
||||
Break
|
||||
}
|
||||
Case (8) { // General Purpose IO
|
||||
Local0 = DGIO()
|
||||
Break
|
||||
}
|
||||
Case (9) { // Generic Serial Bus
|
||||
Local0 = DGSB()
|
||||
Break
|
||||
}
|
||||
Case (0x0A) { // PCC
|
||||
Local0 = DPCC()
|
||||
Break
|
||||
}
|
||||
Case (0x0B) { // PRM
|
||||
Local0 = DPRM()
|
||||
Break
|
||||
}
|
||||
Case (0x7F) { // FFixedHW
|
||||
Local0 = DFHW()
|
||||
Break
|
||||
}
|
||||
}
|
||||
|
||||
If (Local0 != Ones) {
|
||||
Printf("Address space %o failed: expected '%o', got '%o'!",
|
||||
Arg0, Ones, Local0)
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Printf("Address space %o OK", ToHexString(Arg0))
|
||||
Return (Ones)
|
||||
}
|
||||
}
|
71
kernel/hal/x86_64/uACPI/tests/test-cases/complex-package.asl
Normal file
71
kernel/hal/x86_64/uACPI/tests/test-cases/complex-package.asl
Normal file
@ -0,0 +1,71 @@
|
||||
// Name: Nested Package Doesn't Leak Memory
|
||||
// Expect: int => 1
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method(GPKG) {
|
||||
Local1 = 10
|
||||
Local0 = Package (Local1) {
|
||||
0x123,
|
||||
0x321,
|
||||
Package {
|
||||
0x321,
|
||||
"123",
|
||||
Package {
|
||||
0x321,
|
||||
Package {
|
||||
0x321,
|
||||
"123",
|
||||
Package {
|
||||
0x321,
|
||||
"123",
|
||||
Package {
|
||||
0x321,
|
||||
Package {
|
||||
0x321,
|
||||
"123",
|
||||
Package (Local1) {
|
||||
0x321,
|
||||
"123",
|
||||
999,
|
||||
},
|
||||
999,
|
||||
},
|
||||
"123",
|
||||
999,
|
||||
},
|
||||
999,
|
||||
},
|
||||
999,
|
||||
},
|
||||
"123",
|
||||
999,
|
||||
},
|
||||
999,
|
||||
},
|
||||
"Hello world",
|
||||
Package {
|
||||
0x321,
|
||||
"Hello",
|
||||
},
|
||||
Package {
|
||||
0x321,
|
||||
"World",
|
||||
},
|
||||
Package {
|
||||
Buffer (Local1) { 0xFF },
|
||||
0xDEADBEEF,
|
||||
},
|
||||
Buffer { 1, 2, 3 }
|
||||
}
|
||||
|
||||
Return (Local0)
|
||||
}
|
||||
|
||||
Method (MAIN) {
|
||||
Local0 = GPKG()
|
||||
Debug = Local0
|
||||
Local0 = 1
|
||||
Return (Local0)
|
||||
}
|
||||
}
|
127
kernel/hal/x86_64/uACPI/tests/test-cases/concat-res.asl
Normal file
127
kernel/hal/x86_64/uACPI/tests/test-cases/concat-res.asl
Normal file
@ -0,0 +1,127 @@
|
||||
// Name: Concatenate Resources
|
||||
// Expect: int => 1
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Name (BUF0, ResourceTemplate ()
|
||||
{
|
||||
WordBusNumber (ResourceProducer, MinFixed, MaxFixed, PosDecode,
|
||||
0x0000,
|
||||
0x0000,
|
||||
0x00FF,
|
||||
0x0000,
|
||||
0x0100,
|
||||
,, _Y00)
|
||||
DWordIO (ResourceProducer, MinFixed, MaxFixed, PosDecode, EntireRange,
|
||||
0x00000000,
|
||||
0x00000000,
|
||||
0x00000CF7,
|
||||
0x00000000,
|
||||
0x00000CF8,
|
||||
1, "\\SOME.PATH",, TypeStatic, DenseTranslation)
|
||||
IO (Decode16,
|
||||
0x0CF8,
|
||||
0x0CF8,
|
||||
0x01,
|
||||
0x08,
|
||||
)
|
||||
DWordMemory (ResourceProducer, PosDecode, MinFixed, MaxFixed, Cacheable, ReadWrite,
|
||||
0x00000000,
|
||||
0x000A0000,
|
||||
0x000BFFFF,
|
||||
0x00000000,
|
||||
0x00020000,
|
||||
123, "^^^^^^^^^ANOT.ER.PATH", , AddressRangeMemory, TypeStatic)
|
||||
})
|
||||
|
||||
Name (IIC0, ResourceTemplate ()
|
||||
{
|
||||
I2cSerialBusV2 (0x0000, ControllerInitiated, 0x00061A80,
|
||||
AddressingMode7Bit, "\\_SB.PCI0.I2C0",
|
||||
0x00, ResourceConsumer, _Y10, Exclusive,
|
||||
)
|
||||
})
|
||||
|
||||
Name (RBUF, ResourceTemplate ()
|
||||
{
|
||||
I2cSerialBusV2 (0x0029, ControllerInitiated, 0x00061A80,
|
||||
AddressingMode7Bit, "\\_SB.PCI0.I2C0",
|
||||
0x00, ResourceConsumer, , Exclusive,
|
||||
)
|
||||
GpioInt (Level, ActiveHigh, Exclusive, PullNone, 0x0000,
|
||||
"\\_SB.PCI0.GPI0", 0x00, ResourceConsumer, ,
|
||||
)
|
||||
{
|
||||
0x012A
|
||||
}
|
||||
GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly,
|
||||
"\\_SB.PCI0.GPI0", 0x00, ResourceConsumer, ,
|
||||
)
|
||||
{
|
||||
0x002F
|
||||
}
|
||||
GpioIo (Exclusive, PullDefault, 0x0000, 0x0000, IoRestrictionOutputOnly,
|
||||
"\\_SB.PCI0.GPI0", 0x00, ResourceConsumer, ,
|
||||
)
|
||||
{
|
||||
0x0124
|
||||
}
|
||||
})
|
||||
|
||||
// src0, src1, dst
|
||||
Method (CHEK, 3)
|
||||
{
|
||||
Local0 = (SizeOf(Arg0) + SizeOf(Arg1)) - 2
|
||||
|
||||
If (Local0 != SizeOf(Arg2)) {
|
||||
Printf("Invalid final buffer size: %o, expected %o",
|
||||
Local0, SizeOf(Arg2))
|
||||
Return (0)
|
||||
}
|
||||
|
||||
Local0 = 0
|
||||
Local1 = 0
|
||||
|
||||
While (Local0 < (SizeOf(Arg0) - 2)) {
|
||||
Local2 = DerefOf(Arg0[Local0])
|
||||
Local3 = DerefOf(Arg2[Local1])
|
||||
|
||||
If (Local2 != Local3) {
|
||||
Printf("Byte src=%o (dst=%o) mismatch, expected %o got %o",
|
||||
Local0, Local1, ToHexString(Local2), ToHexString(Local3))
|
||||
Return (0)
|
||||
}
|
||||
|
||||
Local0 += 1
|
||||
Local1 += 1
|
||||
}
|
||||
|
||||
Local0 = 0
|
||||
While (Local0 < SizeOf(Arg1)) {
|
||||
Local2 = DerefOf(Arg1[Local0])
|
||||
Local3 = DerefOf(Arg2[Local1])
|
||||
|
||||
If (Local2 != Local3) {
|
||||
Printf("Byte src=%o (dst=%o) mismatch, expected %o got %o",
|
||||
Local0, Local1, ToHexString(Local2), ToHexString(Local3))
|
||||
Return (0)
|
||||
}
|
||||
|
||||
Local0 += 1
|
||||
Local1 += 1
|
||||
}
|
||||
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = ConcatenateResTemplate(BUF0, IIC0)
|
||||
If (CHEK(BUF0, IIC0, Local0) != 1) {
|
||||
Return (0)
|
||||
}
|
||||
|
||||
Local1 = ConcatenateResTemplate(Local0, RBUF)
|
||||
Return(CHEK(Local0, RBUF, Local1))
|
||||
}
|
||||
}
|
34
kernel/hal/x86_64/uACPI/tests/test-cases/copy-a-method.asl
Normal file
34
kernel/hal/x86_64/uACPI/tests/test-cases/copy-a-method.asl
Normal file
@ -0,0 +1,34 @@
|
||||
// Name: Copy a local method and execute it
|
||||
// Expect: int => 3735928559
|
||||
|
||||
DefinitionBlock ("x.aml", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Name (TEST, "Hello world!")
|
||||
|
||||
Method (GETX) {
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Method (COPY) {
|
||||
Method (GETX, 1, Serialized) {
|
||||
Name (Y, 0xDEAD0000)
|
||||
Y += Arg0
|
||||
Return (Y)
|
||||
}
|
||||
|
||||
Return (RefOf(GETX))
|
||||
}
|
||||
|
||||
Method (COP1) {
|
||||
Local0 = COPY()
|
||||
Return (DerefOf(Local0))
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = COP1()
|
||||
CopyObject(Local0, TEST)
|
||||
|
||||
Return (TEST(0xBEEF))
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
// Name: CopyObject with Operation Region works
|
||||
// Expect: int => 0
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (REPL, 1) {
|
||||
Arg0 = 123
|
||||
}
|
||||
|
||||
Method (CAS0) {
|
||||
OperationRegion(MYRE, SystemMemory, 0, 128)
|
||||
Field (MYRE, AnyAcc, NoLock) {
|
||||
FILD, 32
|
||||
}
|
||||
FILD = 1
|
||||
|
||||
CopyObject(123, MYRE)
|
||||
}
|
||||
CAS0()
|
||||
|
||||
Method (CAS1) {
|
||||
OperationRegion(MYRE, SystemMemory, 0, 128)
|
||||
Field (MYRE, AnyAcc, NoLock) {
|
||||
FILD, 32
|
||||
}
|
||||
FILD = 1
|
||||
|
||||
REPL(RefOf(MYRE))
|
||||
}
|
||||
CAS1()
|
||||
|
||||
Method (CAS2) {
|
||||
OperationRegion(MYRE, SystemMemory, 0, 128)
|
||||
Field (MYRE, AnyAcc, NoLock) {
|
||||
FILD, 32
|
||||
}
|
||||
FILD = 1
|
||||
|
||||
Name (FAKE, 123)
|
||||
CopyObject(MYRE, FAKE)
|
||||
Field (FAKE, AnyAcc, NoLock) {
|
||||
FAKF, 32
|
||||
}
|
||||
|
||||
REPL(RefOf(MYRE))
|
||||
FAKF = 1
|
||||
}
|
||||
CAS2()
|
||||
|
||||
Method (CAS3) {
|
||||
OperationRegion(MYR0, SystemMemory, 0, 128)
|
||||
OperationRegion(MYR1, SystemMemory, 0, 128)
|
||||
CopyObject(123, MYR1)
|
||||
}
|
||||
CAS3()
|
||||
|
||||
Method (CAS4) {
|
||||
OperationRegion(MYRE, SystemMemory, 0, 128)
|
||||
Field (MYRE, AnyAcc, NoLock) {
|
||||
FILD, 32
|
||||
}
|
||||
|
||||
FILD = 1
|
||||
CopyObject(FILD, MYRE)
|
||||
FILD = 1
|
||||
}
|
||||
CAS4()
|
||||
|
||||
Name (MAIN, 0)
|
||||
}
|
@ -0,0 +1,27 @@
|
||||
// Name: CopyObject on yourself works
|
||||
// Expect: str => Hello World
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (BAR, 1, Serialized) {
|
||||
Debug = "Enter BAR"
|
||||
CopyObject (Arg0, BAR)
|
||||
Debug = "Leave BAR"
|
||||
}
|
||||
|
||||
Method (FOO) {
|
||||
Debug = "Enter FOO"
|
||||
CopyObject("Hello", FOO)
|
||||
BAR(" World")
|
||||
Debug = "Leave FOO"
|
||||
|
||||
Return (0x123)
|
||||
}
|
||||
|
||||
Method (MAIN) {
|
||||
Local0 = FOO()
|
||||
Printf("First invocation of FOO returned %o", Local0)
|
||||
|
||||
Return (Concatenate(FOO, BAR))
|
||||
}
|
||||
}
|
@ -0,0 +1,31 @@
|
||||
// Name: CopyObject to predefined works
|
||||
// Expect: str => HelloWorld
|
||||
|
||||
DefinitionBlock ("x.aml", "SSDT", 1, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (HELO) {
|
||||
Return ("Hello")
|
||||
}
|
||||
|
||||
Method (WRLD) {
|
||||
Return ("World")
|
||||
}
|
||||
|
||||
Method (MAIN) {
|
||||
OperationRegion(NVSM, SystemMemory, 0x100000, 128)
|
||||
Field (NVSM, ByteAcc, Lock, WriteAsZeros) {
|
||||
FILD, 8,
|
||||
}
|
||||
|
||||
FILD = 0xFF
|
||||
|
||||
CopyObject(HELO, \)
|
||||
CopyObject(WRLD, _GL)
|
||||
|
||||
If (FILD != 0xFF) {
|
||||
Return ("Locked field read-back failed")
|
||||
}
|
||||
|
||||
Return (Concatenate(\(), _GL()))
|
||||
}
|
||||
}
|
84
kernel/hal/x86_64/uACPI/tests/test-cases/duplicate-named.asl
Normal file
84
kernel/hal/x86_64/uACPI/tests/test-cases/duplicate-named.asl
Normal file
@ -0,0 +1,84 @@
|
||||
// Name: Duplicate named objects are skipped correctly
|
||||
// Expect: int => 11
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Name (MAIN, 0)
|
||||
|
||||
Name (TEST, "Hello World")
|
||||
Device (FOO) {
|
||||
ThermalZone (BAR) {
|
||||
Name (TEST, "Hello World")
|
||||
}
|
||||
}
|
||||
|
||||
// These all attempt to create duplicate objects
|
||||
Name (FOO.BAR.TEST, "duplicated test")
|
||||
MAIN += 1
|
||||
Method (TEST, 0, Serialized) {
|
||||
Debug = "Why is this executed?"
|
||||
Name (TEST, 123)
|
||||
CopyObject("Method didn't get skipped", MAIN)
|
||||
Return (333)
|
||||
}
|
||||
|
||||
Debug = "Ok, still here"
|
||||
MAIN += 1
|
||||
|
||||
ThermalZone (TEST) {
|
||||
Local0 = 123
|
||||
Debug = Local0
|
||||
CopyObject("???", MAIN)
|
||||
}
|
||||
ThermalZone (TEST) { }
|
||||
MAIN += 1
|
||||
|
||||
Processor (FOO.BAR.TEST, 0x02, 0x00000410, 0x06) { }
|
||||
MAIN += 1
|
||||
Processor (\TEST, 0x01, 0x00000410, 0x06) {
|
||||
Local2 = Package { 1, 2, 3 }
|
||||
Debug = Local2
|
||||
}
|
||||
|
||||
Device (\FOO.BAR.TEST)
|
||||
{
|
||||
Name (_HID, EisaId ("PNP0C0D"))
|
||||
}
|
||||
|
||||
MAIN += 1
|
||||
Device (\TEST) { }
|
||||
|
||||
// Alias to an object that doesn't exist, but new name is valid
|
||||
Alias(ZOO, BAR)
|
||||
Alias(PATH.THAT.DOES.NOT.EXIS.T, \BAZ)
|
||||
MAIN += 1
|
||||
// Alias to an object that does exist, but new name alrady exists
|
||||
Alias(\TEST, \MAIN)
|
||||
|
||||
// Alias to a non existant object and name also already exists
|
||||
Alias(ZOO, \TEST)
|
||||
Alias(PATH.THAT.DOES.NOT.EXIS.T, \FOO.BAR.TEST)
|
||||
|
||||
MAIN += 1
|
||||
Mutex(TEST, 15)
|
||||
|
||||
Debug = "Just a bit left"
|
||||
|
||||
Event(TEST)
|
||||
MAIN += 1
|
||||
OperationRegion(TEST, SystemMemory, 0x100000, 128)
|
||||
DataTableRegion(FOO.BAR.TEST, "DSDT", "", "")
|
||||
|
||||
Local0 = Buffer (256) { }
|
||||
|
||||
CreateBitField(Local0, 111, TEST)
|
||||
CreateByteField(Local0, 111, TEST)
|
||||
MAIN += 1
|
||||
CreateDWordField(Local0, 111, TEST)
|
||||
CreateQWordField(Local0, 111, TEST)
|
||||
MAIN += 1
|
||||
CreateField(Local0, 111, 11, FOO.BAR.TEST)
|
||||
|
||||
MAIN += 1
|
||||
Debug = "Made it to the end!"
|
||||
}
|
21
kernel/hal/x86_64/uACPI/tests/test-cases/empty-objects.asl
Normal file
21
kernel/hal/x86_64/uACPI/tests/test-cases/empty-objects.asl
Normal file
@ -0,0 +1,21 @@
|
||||
// Name: Empty objects behave correctly
|
||||
// Expect: int => 0
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (EMPT) { }
|
||||
|
||||
Method (MAIN) {
|
||||
Local0 = EMPT()
|
||||
Debug = Local0
|
||||
|
||||
Local0 = Package (0) { }
|
||||
Debug = Local0
|
||||
|
||||
Local0 = 0
|
||||
Local1 = Package(Local0) { }
|
||||
Debug = Local1
|
||||
|
||||
Return (0)
|
||||
}
|
||||
}
|
@ -0,0 +1,7 @@
|
||||
// Name: Eval supports plain objects
|
||||
// Expect: str => This is a plain string, not a method
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Name (MAIN, "This is a plain string, not a method")
|
||||
}
|
31
kernel/hal/x86_64/uACPI/tests/test-cases/event.asl
Normal file
31
kernel/hal/x86_64/uACPI/tests/test-cases/event.asl
Normal file
@ -0,0 +1,31 @@
|
||||
// Name: Event signal & wait
|
||||
// Expect: int => 0
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (MAIN, 0, Serialized)
|
||||
{
|
||||
Event (EVET)
|
||||
|
||||
Local0 = 5
|
||||
While (Local0--) {
|
||||
Signal(EVET)
|
||||
}
|
||||
|
||||
Local0 = 5
|
||||
While (Local0--) {
|
||||
Local1 = Wait(EVET, 0xFFFD + Local0)
|
||||
If (Local1 != Zero) {
|
||||
Return (Local1)
|
||||
}
|
||||
}
|
||||
|
||||
// This should fail
|
||||
Local1 = Wait(EVET, Zero)
|
||||
If (Local1 == Zero) {
|
||||
Return (One)
|
||||
}
|
||||
|
||||
Return (Zero)
|
||||
}
|
||||
}
|
48
kernel/hal/x86_64/uACPI/tests/test-cases/global-lock.asl
Normal file
48
kernel/hal/x86_64/uACPI/tests/test-cases/global-lock.asl
Normal file
@ -0,0 +1,48 @@
|
||||
// Name: Global lock works
|
||||
// Expect: int => 0
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (CHEK, 1, Serialized, 15)
|
||||
{
|
||||
If (Arg0 != 0) {
|
||||
Debug = "Failed to acquire the global lock!"
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Return (0)
|
||||
}
|
||||
|
||||
Method (MAIN, 0, Serialized)
|
||||
{
|
||||
Local0 = 0
|
||||
|
||||
Debug = "Acquiring the lock manually!"
|
||||
|
||||
Local0 += CHEK(Acquire (_GL, 0xFFFF))
|
||||
Local0 += CHEK(Acquire (_GL, 0xFFFF))
|
||||
Local0 += CHEK(Acquire (_GL, 0xFFFF))
|
||||
Local0 += CHEK(Acquire (_GL, 0xFFFF))
|
||||
|
||||
Debug = "Doing a field write..."
|
||||
|
||||
OperationRegion(NVSM, SystemMemory, 0x100000, 128)
|
||||
Field (NVSM, AnyAcc, Lock, WriteAsZeros) {
|
||||
FILD, 1,
|
||||
}
|
||||
|
||||
FILD = 1
|
||||
|
||||
Debug = "Write done, we should still be holding the lock!"
|
||||
Release(_GL)
|
||||
Release(_GL)
|
||||
Release(_GL)
|
||||
|
||||
Debug = "Should release NOW!"
|
||||
Release(_GL)
|
||||
|
||||
// TODO? Would be nice to have some way to actually verify that a lock is held...
|
||||
|
||||
Return (Local0)
|
||||
}
|
||||
}
|
24
kernel/hal/x86_64/uACPI/tests/test-cases/hanging-while.asl
Normal file
24
kernel/hal/x86_64/uACPI/tests/test-cases/hanging-while.asl
Normal file
@ -0,0 +1,24 @@
|
||||
// Name: Infinite While loops eventually ends
|
||||
// Expect: int => 1
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Name (LOOP, 0)
|
||||
|
||||
Method (HANG) {
|
||||
LOOP = 1
|
||||
While (LOOP++) { }
|
||||
}
|
||||
|
||||
HANG()
|
||||
|
||||
Method (MAIN) {
|
||||
Printf("Looped %o times before getting aborted", ToDecimalString(LOOP))
|
||||
|
||||
If (LOOP < 100) {
|
||||
Return (0)
|
||||
}
|
||||
|
||||
Return (1)
|
||||
}
|
||||
}
|
@ -0,0 +1,60 @@
|
||||
// Name: Increment And Decrement Fields & Indices
|
||||
// Expect: int => 150
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (BROK, 2) {
|
||||
Printf ("%o increment is broken", Arg0)
|
||||
Return (Arg1)
|
||||
}
|
||||
|
||||
Method (MAIN, 0, Serialized)
|
||||
{
|
||||
Local0 = Buffer { 1 }
|
||||
Local1 = Package {
|
||||
123, 22
|
||||
}
|
||||
|
||||
Debug = Increment(Local0[0])
|
||||
Debug = Decrement(Local1[0])
|
||||
|
||||
Local2 = Local1[1]
|
||||
Debug = Increment(Local2)
|
||||
|
||||
OperationRegion(NVSM, SystemMemory, 0x100000, 128)
|
||||
Field (NVSM, AnyAcc, NoLock, WriteAsZeros) {
|
||||
FILD, 1,
|
||||
}
|
||||
FILD = 0
|
||||
|
||||
Debug = Increment(FILD)
|
||||
|
||||
// We get a 2 here but write back 0 because field is one bit
|
||||
Local3 = Increment(FILD)
|
||||
If (FILD != 0) {
|
||||
Return (BROK("Field unit", 0xDEADBEEF))
|
||||
}
|
||||
|
||||
Local4 = Increment(FILD)
|
||||
If (FILD != 1) {
|
||||
Return (BROK("Field unit", 0xBEEFDEAD))
|
||||
}
|
||||
|
||||
If (DerefOf(Local2) != DerefOf(Local1[1])) {
|
||||
Return (BROK("Buffer index", 0xCAFEBABE))
|
||||
}
|
||||
|
||||
Return (
|
||||
// 2
|
||||
DerefOf(Local0[0]) +
|
||||
// 122
|
||||
DerefOf(Local1[0]) +
|
||||
// 23
|
||||
DerefOf(Local2) +
|
||||
// 2
|
||||
Local3 +
|
||||
// 1
|
||||
Local4
|
||||
)
|
||||
}
|
||||
}
|
39
kernel/hal/x86_64/uACPI/tests/test-cases/indices-0.asl
Normal file
39
kernel/hal/x86_64/uACPI/tests/test-cases/indices-0.asl
Normal file
@ -0,0 +1,39 @@
|
||||
// Name: Buffer Indices
|
||||
// Expect: str => HfVXoWorld
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (FAIL, 2)
|
||||
{
|
||||
Printf("Invalid string %o, expected %o", Arg0, Arg1)
|
||||
Return(1)
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = "HelloWorld"
|
||||
Local0[3] = "X"
|
||||
|
||||
Local1 = "HelXoWorld"
|
||||
If (Local0 != Local1) {
|
||||
Return(FAIL(Local0, Local1))
|
||||
}
|
||||
|
||||
Local2 = RefOf(Index(Local0, 2))
|
||||
Local2 = "V"
|
||||
|
||||
Local1 = "HeVXoWorld"
|
||||
If (Local0 != Local1) {
|
||||
Return(FAIL(Local0, Local1))
|
||||
}
|
||||
|
||||
CopyObject(Index(Local0, 1), Local2)
|
||||
Local0[1] = 0x66
|
||||
|
||||
If (DerefOf(Local2) != 0x66) {
|
||||
Return(1)
|
||||
}
|
||||
|
||||
Return (Local0)
|
||||
}
|
||||
}
|
52
kernel/hal/x86_64/uACPI/tests/test-cases/indices-1.asl
Normal file
52
kernel/hal/x86_64/uACPI/tests/test-cases/indices-1.asl
Normal file
@ -0,0 +1,52 @@
|
||||
// Name: Dump Package Contents
|
||||
// Expect: str => { HelloWorld, 123, deadbeef, { some string, { ffffffffeeeeeeee, middle package }, cafebabe } }
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (DUMP, 1)
|
||||
{
|
||||
Local0 = 0
|
||||
Local1 = "{ "
|
||||
|
||||
While (Local0 < SizeOf(Arg0)) {
|
||||
// If package, invoke DUMP recursively
|
||||
If (ObjectType(DerefOf(Arg0[Local0])) == 4) {
|
||||
Fprintf(Local1, "%o, %o", Local1, DUMP(DerefOf(Arg0[Local0])))
|
||||
Local0 += 1
|
||||
Continue;
|
||||
}
|
||||
|
||||
If (Local0 == 0) {
|
||||
Local3 = ""
|
||||
} Else {
|
||||
Local3 = ", "
|
||||
}
|
||||
|
||||
Fprintf(Local1, "%o%o%o", Local1, Local3, DerefOf(Arg0[Local0]))
|
||||
Local0 += 1
|
||||
}
|
||||
|
||||
Fprintf(Local1, "%o }", Local1)
|
||||
Return(Local1)
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = Package {
|
||||
"HelloWorld",
|
||||
0x123,
|
||||
0xDEADBEEF,
|
||||
Package {
|
||||
"some string",
|
||||
Package {
|
||||
0xFFFFFFFFEEEEEEEE,
|
||||
"middle package",
|
||||
},
|
||||
0xCAFEBABE,
|
||||
},
|
||||
}
|
||||
|
||||
Local1 = DUMP(Local0)
|
||||
Return(Local1)
|
||||
}
|
||||
}
|
50
kernel/hal/x86_64/uACPI/tests/test-cases/indices-2.asl
Normal file
50
kernel/hal/x86_64/uACPI/tests/test-cases/indices-2.asl
Normal file
@ -0,0 +1,50 @@
|
||||
// Name: Package Indices w/ References
|
||||
// Expect: int => 1062815831
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (TEST, 1)
|
||||
{
|
||||
Local0 = Package {
|
||||
1, 2, 3, "String"
|
||||
}
|
||||
Local1 = 0
|
||||
|
||||
Arg0[1] = RefOf(Local0)
|
||||
Arg0[2] = RefOf(Local1)
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = Package {
|
||||
"HelloWorld",
|
||||
0x123,
|
||||
0xDEADBEEF,
|
||||
Package {
|
||||
"some string",
|
||||
0xCAFEBABE
|
||||
}
|
||||
}
|
||||
|
||||
TEST(Local0)
|
||||
|
||||
Local1 = DerefOf(DerefOf(Local0[1])[3])
|
||||
If (Local1 != "String") {
|
||||
Printf("Invalid value at nested package %o", Local1)
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Local0[2] = "WHY?"
|
||||
Local2 = DerefOf(Local0[2])
|
||||
|
||||
// Why in little-endian ascii
|
||||
Local3 = 1062815831
|
||||
|
||||
If (Local2 != Local3) {
|
||||
Printf("Failed to implicit cast, expected %o, got %o", Local3, Local2)
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Return (Local2)
|
||||
}
|
||||
}
|
@ -0,0 +1,22 @@
|
||||
// Name: Infinite recursion eventually ends
|
||||
// Expect: int => 0
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Name (MAIN, 0xDEADBEEF)
|
||||
Name (ITER, 0)
|
||||
|
||||
Method (HANG) {
|
||||
ITER++
|
||||
HANG()
|
||||
}
|
||||
|
||||
HANG()
|
||||
Printf("Recursed %o times before stopping", ToDecimalString(ITER))
|
||||
|
||||
If (ITER > 64) {
|
||||
MAIN = 0
|
||||
} Else {
|
||||
Debug = "Recursion depth was too small"
|
||||
}
|
||||
}
|
12
kernel/hal/x86_64/uACPI/tests/test-cases/local0.asl
Normal file
12
kernel/hal/x86_64/uACPI/tests/test-cases/local0.asl
Normal file
@ -0,0 +1,12 @@
|
||||
// Name: Return Integer Using Local0
|
||||
// Expect: int => 0x123
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = 0x123
|
||||
Debug = Local0
|
||||
Return (Local0)
|
||||
}
|
||||
}
|
11
kernel/hal/x86_64/uACPI/tests/test-cases/local0_string.asl
Normal file
11
kernel/hal/x86_64/uACPI/tests/test-cases/local0_string.asl
Normal file
@ -0,0 +1,11 @@
|
||||
// Name: Return String Using Local0
|
||||
// Expect: str => hello world
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Debug = (Local0 = "hello world")
|
||||
Return (Local0)
|
||||
}
|
||||
}
|
61
kernel/hal/x86_64/uACPI/tests/test-cases/method-calls.asl
Normal file
61
kernel/hal/x86_64/uACPI/tests/test-cases/method-calls.asl
Normal file
@ -0,0 +1,61 @@
|
||||
// Name: Call methods with every ArgX
|
||||
// Expect: int => 8
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method(TES7, 7) {
|
||||
Local0 = Arg0 + Arg1 + Arg2 + Arg3 + Arg4 + Arg5 + Arg6
|
||||
If (Local0 != (1 + 2 + 3 + 4 + 5 + 6 + 7)) { Return (Local0) }
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Method(TES6, 6) {
|
||||
Local0 = Arg0 + Arg1 + Arg2 + Arg3 + Arg4 + Arg5
|
||||
If (Local0 != (1 + 2 + 3 + 4 + 5 + 6)) { Return (Local0) }
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Method(TES5, 5) {
|
||||
Local0 = Arg0 + Arg1 + Arg2 + Arg3 + Arg4
|
||||
If (Local0 != (1 + 2 + 3 + 4 + 5)) { Return (Local0) }
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Method(TES4, 4) {
|
||||
Local0 = Arg0 + Arg1 + Arg2 + Arg3
|
||||
If (Local0 != (1 + 2 + 3 + 4)) { Return (Local0) }
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Method(TES3, 3) {
|
||||
Local0 = Arg0 + Arg1 + Arg2
|
||||
If (Local0 != (1 + 2 + 3)) { Return (Local0) }
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Method(TES2, 2) {
|
||||
Local0 = Arg0 + Arg1
|
||||
If (Local0 != (1 + 2)) { Return (Local0) }
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Method(TES1, 1) {
|
||||
Local0 = Arg0
|
||||
If (Local0 != (1 + 2)) { Return (Local0) }
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Method(TES0, 0) { Return (1) }
|
||||
|
||||
Method (MAIN)
|
||||
{
|
||||
Return(TES7(1, 2, 3, 4, 5, 6, 7) +
|
||||
TES6(1, 2, 3, 4, 5, 6) +
|
||||
TES5(1, 2, 3, 4, 5) +
|
||||
TES4(1, 2, 3, 4) +
|
||||
TES3(1, 2, 3) +
|
||||
TES2(1, 2) +
|
||||
TES1(1) +
|
||||
TES0())
|
||||
}
|
||||
}
|
34
kernel/hal/x86_64/uACPI/tests/test-cases/multilevel_ref.asl
Normal file
34
kernel/hal/x86_64/uACPI/tests/test-cases/multilevel_ref.asl
Normal file
@ -0,0 +1,34 @@
|
||||
// Name: Multilevel reference w/ Increment
|
||||
// Expect: int => 0xDEAD0005
|
||||
|
||||
DefinitionBlock ("", "DSDT", 1, "uTTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = 0xDEAD0000
|
||||
|
||||
Local1 = RefOf(Local0)
|
||||
Debug = Local1
|
||||
|
||||
Local2 = RefOf(Local1)
|
||||
Debug = Local2
|
||||
|
||||
Local3 = RefOf(Local2)
|
||||
Debug = Local3
|
||||
|
||||
Local4 = RefOf(Local3)
|
||||
Debug = Local4
|
||||
|
||||
Local5 = RefOf(Local4)
|
||||
Debug = Local5
|
||||
|
||||
Debug = Increment(Local1)
|
||||
Debug = Increment(Local2)
|
||||
Debug = Increment(Local3)
|
||||
Debug = Increment(Local4)
|
||||
Debug = Increment(Local5)
|
||||
|
||||
Debug = Local0
|
||||
Return (DerefOf(Local5))
|
||||
}
|
||||
}
|
55
kernel/hal/x86_64/uACPI/tests/test-cases/mutex-1.asl
Normal file
55
kernel/hal/x86_64/uACPI/tests/test-cases/mutex-1.asl
Normal file
@ -0,0 +1,55 @@
|
||||
// Name: Automatic mutex release
|
||||
// Expect: int => 0
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (CHEK, 1, Serialized, 15)
|
||||
{
|
||||
If (Arg0 != 0) {
|
||||
Debug = "Failed to acquire mutex!"
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Return (0)
|
||||
}
|
||||
|
||||
Method (MAIN, 0, Serialized)
|
||||
{
|
||||
Mutex(MUT0, 0)
|
||||
Mutex(MUT1, 1)
|
||||
Mutex(MUT2, 2)
|
||||
Mutex(MUT3, 3)
|
||||
Mutex(MUT4, 4)
|
||||
Mutex(MUT5, 5)
|
||||
Mutex(MUT6, 6)
|
||||
Mutex(MUT7, 7)
|
||||
Mutex(MUT8, 8)
|
||||
Mutex(MUT9, 9)
|
||||
Mutex(MUTA, 10)
|
||||
Mutex(MUTB, 11)
|
||||
Mutex(MUTC, 12)
|
||||
Mutex(MUTD, 13)
|
||||
Mutex(MUTE, 14)
|
||||
Mutex(MUTF, 15)
|
||||
|
||||
Local0 = 0
|
||||
Local0 += CHEK(Acquire(MUT0, 0))
|
||||
Local0 += CHEK(Acquire(MUT1, 0))
|
||||
Local0 += CHEK(Acquire(MUT2, 0))
|
||||
Local0 += CHEK(Acquire(MUT3, 0))
|
||||
Local0 += CHEK(Acquire(MUT4, 0))
|
||||
Local0 += CHEK(Acquire(MUT5, 0))
|
||||
Local0 += CHEK(Acquire(MUT6, 0))
|
||||
Local0 += CHEK(Acquire(MUT7, 0))
|
||||
Local0 += CHEK(Acquire(MUT8, 0))
|
||||
Local0 += CHEK(Acquire(MUT9, 0))
|
||||
Local0 += CHEK(Acquire(MUTA, 0))
|
||||
Local0 += CHEK(Acquire(MUTB, 0))
|
||||
Local0 += CHEK(Acquire(MUTC, 0))
|
||||
Local0 += CHEK(Acquire(MUTD, 0xFFFE))
|
||||
Local0 += CHEK(Acquire(MUTE, 0xFFFD))
|
||||
Local0 += CHEK(Acquire(MUTF, 0xFFFF))
|
||||
|
||||
Return (Local0)
|
||||
}
|
||||
}
|
64
kernel/hal/x86_64/uACPI/tests/test-cases/mutex-2.asl
Normal file
64
kernel/hal/x86_64/uACPI/tests/test-cases/mutex-2.asl
Normal file
@ -0,0 +1,64 @@
|
||||
// Name: Out of order mutex release
|
||||
// Expect: int => 0
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (CHEK, 1, Serialized, 15)
|
||||
{
|
||||
If (Arg0 != 0) {
|
||||
Debug = "Failed to acquire mutex!"
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Return (0)
|
||||
}
|
||||
|
||||
Method (MAIN, 0, Serialized)
|
||||
{
|
||||
Mutex(MUT0)
|
||||
Mutex(MUT1)
|
||||
Mutex(MUT2)
|
||||
Mutex(MUT3)
|
||||
Mutex(MUT4)
|
||||
Mutex(MUT5)
|
||||
Mutex(MUT6)
|
||||
Mutex(MUT7)
|
||||
Mutex(MUT8)
|
||||
Mutex(MUT9)
|
||||
Mutex(MUTA)
|
||||
Mutex(MUTB)
|
||||
Mutex(MUTC)
|
||||
Mutex(MUTD)
|
||||
Mutex(MUTE)
|
||||
Mutex(MUTF)
|
||||
|
||||
Local0 = 0
|
||||
Local0 += CHEK(Acquire(MUT0, 0))
|
||||
Local0 += CHEK(Acquire(MUT1, 0))
|
||||
Local0 += CHEK(Acquire(MUT2, 0))
|
||||
Local0 += CHEK(Acquire(MUT3, 0))
|
||||
Local0 += CHEK(Acquire(MUT4, 0))
|
||||
Local0 += CHEK(Acquire(MUT5, 0))
|
||||
Local0 += CHEK(Acquire(MUT6, 0))
|
||||
Local0 += CHEK(Acquire(MUT7, 0))
|
||||
Local0 += CHEK(Acquire(MUT8, 0))
|
||||
Local0 += CHEK(Acquire(MUT9, 0xF))
|
||||
Local0 += CHEK(Acquire(MUTA, 0))
|
||||
Local0 += CHEK(Acquire(MUTB, 3))
|
||||
Local0 += CHEK(Acquire(MUTC, 123))
|
||||
Local0 += CHEK(Acquire(MUTD, 0xFFFE))
|
||||
Local0 += CHEK(Acquire(MUTE, 0xFFFD))
|
||||
Local0 += CHEK(Acquire(MUTF, 0xFFFF))
|
||||
|
||||
Release(MUTA)
|
||||
Release(MUT9)
|
||||
Release(MUTC)
|
||||
Release(MUT1)
|
||||
Release(MUT7)
|
||||
Release(MUTE)
|
||||
Release(MUTD)
|
||||
|
||||
// The rest are released automatically when we exit the outermost method
|
||||
Return (Local0)
|
||||
}
|
||||
}
|
37
kernel/hal/x86_64/uACPI/tests/test-cases/mutex-3.asl
Normal file
37
kernel/hal/x86_64/uACPI/tests/test-cases/mutex-3.asl
Normal file
@ -0,0 +1,37 @@
|
||||
// Name: Recursive mutex
|
||||
// Expect: int => 253
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (CHEK, 1, Serialized, 15)
|
||||
{
|
||||
If (Arg0 != 0) {
|
||||
Debug = "Failed to acquire mutex!"
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Return (0)
|
||||
}
|
||||
|
||||
Mutex (MUTX)
|
||||
|
||||
Method (ACQ, 1, Serialized) {
|
||||
CHEK(Acquire(MUTX, 0xFFFF))
|
||||
|
||||
Local0 = 0
|
||||
|
||||
If (Arg0 < 22) {
|
||||
Local0 += Arg0 + ACQ(Arg0 + 1)
|
||||
} Else {
|
||||
Local0 += Arg0
|
||||
}
|
||||
|
||||
Release(MUTX)
|
||||
Return (Local0)
|
||||
}
|
||||
|
||||
Method (MAIN, 0, Serialized)
|
||||
{
|
||||
Return (ACQ(0))
|
||||
}
|
||||
}
|
@ -0,0 +1,25 @@
|
||||
// Name: Notifications & Requests
|
||||
// Expect: int => 0
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (FATL, 1)
|
||||
{
|
||||
Fatal(0xFF, 0xDEADBEEF, ToInteger(Arg0))
|
||||
}
|
||||
|
||||
Device (PSP) {
|
||||
Name (_HID, "ACPI0000")
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Breakpoint
|
||||
FATL("0xCAFEBABEC0DEDEAD")
|
||||
Breakpoint
|
||||
|
||||
Notify(PSP, 0x10)
|
||||
|
||||
Return (0)
|
||||
}
|
||||
}
|
@ -0,0 +1,80 @@
|
||||
// Name: Public API for object mutation works
|
||||
// Expect: str => check-object-api-works
|
||||
|
||||
DefinitionBlock ("x.aml", "SSDT", 1, "uTEST", "APITESTS", 0xF0F0F0F0)
|
||||
{
|
||||
Method (MAIN) {
|
||||
// Skip for non-uacpi test runners
|
||||
Return ("check-object-api-works")
|
||||
}
|
||||
|
||||
/*
|
||||
* Arg0 -> Expected case
|
||||
* Arg1 -> The actual value
|
||||
* Return -> Ones on succeess, Zero on failure
|
||||
*/
|
||||
Method (CHEK, 2) {
|
||||
Switch (Arg0) {
|
||||
Case (1) {
|
||||
Local0 = 0xDEADBEEF
|
||||
Break
|
||||
}
|
||||
Case (2) {
|
||||
Local0 = "Hello World"
|
||||
Break
|
||||
}
|
||||
Case (3) {
|
||||
Local0 = "TEST"
|
||||
|
||||
/*
|
||||
* Arg1 is expected to be a reference to a string XXXX, store
|
||||
* into it here to invoke implicit case semantics.
|
||||
*/
|
||||
Arg1 = Local0
|
||||
Break
|
||||
}
|
||||
Case (4) {
|
||||
Local0 = Buffer { 0xDE, 0xAD, 0xBE, 0xEF }
|
||||
Break
|
||||
}
|
||||
Case (5) {
|
||||
If (ObjectType(Arg1) != 4) {
|
||||
Printf("Expected a Package, got %o", Arg1)
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
If (SizeOf(Arg1) != 3) {
|
||||
Printf("Expected a Package of 3 elements, got %o", SizeOf(Arg1))
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Local0 = Package {
|
||||
"First Element",
|
||||
2,
|
||||
Buffer { 1, 2, 3 },
|
||||
}
|
||||
Local1 = 0
|
||||
|
||||
While (Local1 < 3) {
|
||||
If (DerefOf(Local0[Local1]) != DerefOf(Arg1[Local1])) {
|
||||
Printf("Expected %o, got %o!", DerefOf(Local0[Local1]), DerefOf(Arg1[Local1]))
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Printf("Object %o OK", Local1)
|
||||
Local1++
|
||||
}
|
||||
|
||||
Return (Ones)
|
||||
}
|
||||
}
|
||||
|
||||
If (Local0 != Arg1) {
|
||||
Printf("Expected '%o', got '%o'!", Local0, Arg1)
|
||||
Return (Zero)
|
||||
}
|
||||
|
||||
Printf("Comparison %o OK", Arg0)
|
||||
Return (Ones)
|
||||
}
|
||||
}
|
81
kernel/hal/x86_64/uACPI/tests/test-cases/osi.asl
Normal file
81
kernel/hal/x86_64/uACPI/tests/test-cases/osi.asl
Normal file
@ -0,0 +1,81 @@
|
||||
// Name: _OSI works correctly
|
||||
// Expect: int => 0
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (CHEK, 2) {
|
||||
Local0 = _OSI(Arg0)
|
||||
|
||||
If (Local0 != Arg1) {
|
||||
Printf("_OSI(%o) failed (expected %o, got %o)", Arg0, Arg1, Local0)
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Return (0)
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = 0
|
||||
|
||||
If (!CondRefOf(_OSI)) {
|
||||
Debug = "No _OSI method!"
|
||||
Return (1111111)
|
||||
}
|
||||
|
||||
Local0 += CHEK("Windows 2000", Ones)
|
||||
Local0 += CHEK("Windows 2001", Ones)
|
||||
Local0 += CHEK("Windows 2001 SP1", Ones)
|
||||
Local0 += CHEK("Windows 2001.1", Ones)
|
||||
Local0 += CHEK("Windows 2001 SP2", Ones)
|
||||
Local0 += CHEK("Windows 2001.1 SP1", Ones)
|
||||
Local0 += CHEK("Windows 2006.1", Ones)
|
||||
Local0 += CHEK("Windows 2006 SP1", Ones)
|
||||
Local0 += CHEK("Windows 2006 SP2", Ones)
|
||||
Local0 += CHEK("Windows 2009", Ones)
|
||||
Local0 += CHEK("Windows 2012", Ones)
|
||||
Local0 += CHEK("Windows 2013", Ones)
|
||||
Local0 += CHEK("Windows 2015", Ones)
|
||||
Local0 += CHEK("Windows 2016", Ones)
|
||||
Local0 += CHEK("Windows 2017", Ones)
|
||||
Local0 += CHEK("Windows 2017.2", Ones)
|
||||
Local0 += CHEK("Windows 2018", Ones)
|
||||
Local0 += CHEK("Windows 2018.2", Ones)
|
||||
Local0 += CHEK("Windows 2019", Ones)
|
||||
|
||||
// ACPICA acpiexec
|
||||
If (_OSI("AnotherTestString")) {
|
||||
// do nothing
|
||||
Debug = "ACPICA acpiexec detected"
|
||||
} ElseIf (_OSI("TestRunner")) {
|
||||
Debug = "uACPI test runner detected"
|
||||
|
||||
// These are only enabled in uACPI test runner
|
||||
Local0 += CHEK("3.0 Thermal Model", Ones)
|
||||
Local0 += CHEK("Module Device", Ones)
|
||||
|
||||
// Don't check these in ACPICA, it might be too old to have these
|
||||
Local0 += CHEK("Windows 2020", Ones)
|
||||
Local0 += CHEK("Windows 2021", Ones)
|
||||
Local0 += CHEK("Windows 2022", Ones)
|
||||
} Else {
|
||||
Debug = "Neither uACPI nor ACPICA were detected, aborting test"
|
||||
Return (123321)
|
||||
}
|
||||
|
||||
// This is removed in both uACPI and ACPICA test runners
|
||||
Local0 += CHEK("Windows 2006", Zero)
|
||||
|
||||
Local0 += CHEK("Extended Address Space Descriptor", Ones)
|
||||
|
||||
Local0 += CHEK("Processor Aggregator Device", Zero)
|
||||
Local0 += CHEK("3.0 _SCP Extensions", Zero)
|
||||
Local0 += CHEK("Processor Device", Zero)
|
||||
Local0 += CHEK("", Zero)
|
||||
Local0 += CHEK("Windows 99999", Zero)
|
||||
Local0 += CHEK("Windows 2014", Zero)
|
||||
Local0 += CHEK("Linux", Zero)
|
||||
|
||||
Return (Local0)
|
||||
}
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
// Name: IO from deleted fields doesn't crash
|
||||
// Expect: int => 0
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
External(MAIN)
|
||||
|
||||
If (!CondRefOf(MAIN)) {
|
||||
Name (MAIN, Ones)
|
||||
|
||||
/*
|
||||
* Load ourselves again, we won't enter this branch a second time.
|
||||
* We expect this LoadTable call to fail because of the invalid
|
||||
* field store.
|
||||
*/
|
||||
MAIN = LoadTable("DSDT", "uTEST", "TESTTABL", "", "", 0)
|
||||
Return (0)
|
||||
}
|
||||
|
||||
Method (TEST) {
|
||||
OperationRegion(MYRE, SystemMemory, 0, 128)
|
||||
Field (MYRE, AnyAcc, NoLock) {
|
||||
FILD, 32
|
||||
}
|
||||
|
||||
FILD = 1
|
||||
Return (RefOf(FILD))
|
||||
}
|
||||
|
||||
Name (X, "")
|
||||
|
||||
/*
|
||||
* Get a dangling field object and make X be this field.
|
||||
* Then attempt to perform a read from it.
|
||||
*/
|
||||
Local0 = TEST()
|
||||
CopyObject(DerefOf(Local0), X)
|
||||
|
||||
Debug = X
|
||||
}
|
@ -0,0 +1,14 @@
|
||||
// Name: Modify Local0 Using RefOf Local1
|
||||
// Expect: int => 0x124
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = RefOf(Local1)
|
||||
Local0 = 0x123
|
||||
Debug = Local0
|
||||
Debug = Local1
|
||||
Return(Local1++)
|
||||
}
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
// Name: Modify Local0 Using Arg0
|
||||
// Expect: int => 124
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (TEST, 1, NotSerialized)
|
||||
{
|
||||
Local0 = RefOf(Arg0)
|
||||
Local0 = 123
|
||||
Arg0++
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = 200
|
||||
TEST(RefOf(Local0))
|
||||
Return (Local0)
|
||||
}
|
||||
}
|
17
kernel/hal/x86_64/uACPI/tests/test-cases/references-0.asl
Normal file
17
kernel/hal/x86_64/uACPI/tests/test-cases/references-0.asl
Normal file
@ -0,0 +1,17 @@
|
||||
// Name: Call-by-value w/ Store() doesn't modify Local
|
||||
// Expect: str => MyString
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (TEST, 1, NotSerialized)
|
||||
{
|
||||
Arg0 = 0xDEADBEEF
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = "MyString"
|
||||
TEST(Local0)
|
||||
Return (Local0)
|
||||
}
|
||||
}
|
17
kernel/hal/x86_64/uACPI/tests/test-cases/references-1.asl
Normal file
17
kernel/hal/x86_64/uACPI/tests/test-cases/references-1.asl
Normal file
@ -0,0 +1,17 @@
|
||||
// Name: Call-by-value w/ CopyObject() doesn't modify Local
|
||||
// Expect: str => MyString
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (TEST, 1, NotSerialized)
|
||||
{
|
||||
CopyObject(0xDEADBEEF, Arg0)
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = "MyString"
|
||||
TEST(Local0)
|
||||
Return (Local0)
|
||||
}
|
||||
}
|
24
kernel/hal/x86_64/uACPI/tests/test-cases/references-10.asl
Normal file
24
kernel/hal/x86_64/uACPI/tests/test-cases/references-10.asl
Normal file
@ -0,0 +1,24 @@
|
||||
// Name: Recursively modify ArgX
|
||||
// Expect: int => 0x100A
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (TEST, 2, NotSerialized)
|
||||
{
|
||||
Local0 = RefOf(Arg0)
|
||||
Local0++
|
||||
|
||||
Debug = Arg1
|
||||
Debug = DerefOf(Local0)
|
||||
If (Arg1--) {
|
||||
TEST(RefOf(Arg0), Arg1)
|
||||
}
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = 0x1000
|
||||
TEST(RefOf(Local0), 10)
|
||||
Return (Local0)
|
||||
}
|
||||
}
|
23
kernel/hal/x86_64/uACPI/tests/test-cases/references-3.asl
Normal file
23
kernel/hal/x86_64/uACPI/tests/test-cases/references-3.asl
Normal file
@ -0,0 +1,23 @@
|
||||
// Name: Call-by-value w/ Store() modifies strings through a reference
|
||||
// Expect: str => WHY?
|
||||
// NOTE:
|
||||
// This test seems bogus but it's actually corrrect, it produces
|
||||
// the same output on NT.
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (TEST, 1, NotSerialized)
|
||||
{
|
||||
Local0 = RefOf(Arg0)
|
||||
|
||||
// WHY? in little-endian ASCII
|
||||
Local0 = 0x3F594857
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = "MyST"
|
||||
TEST(Local0)
|
||||
Return (Local0)
|
||||
}
|
||||
}
|
18
kernel/hal/x86_64/uACPI/tests/test-cases/references-4.asl
Normal file
18
kernel/hal/x86_64/uACPI/tests/test-cases/references-4.asl
Normal file
@ -0,0 +1,18 @@
|
||||
// Name: Call-by-value w/ Store() does NOT modify integers even through a reference
|
||||
// Expect: int => 0x123
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (TEST, 1, NotSerialized)
|
||||
{
|
||||
Local0 = RefOf(Arg0)
|
||||
Local0 = 0xDEADBEEF
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = 0x123
|
||||
TEST(Local0)
|
||||
Return (Local0)
|
||||
}
|
||||
}
|
21
kernel/hal/x86_64/uACPI/tests/test-cases/references-5.asl
Normal file
21
kernel/hal/x86_64/uACPI/tests/test-cases/references-5.asl
Normal file
@ -0,0 +1,21 @@
|
||||
// Name: LocalX reference is rebindable via CopyObject
|
||||
// Expect: str => Modified
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (TEST, 1, NotSerialized)
|
||||
{
|
||||
Local0 = RefOf(Arg0)
|
||||
Local0 = "Modified String"
|
||||
|
||||
CopyObject("Wrong String", Local0)
|
||||
Local0 = 0xDEADBEEF
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = "MyString"
|
||||
TEST(Local0)
|
||||
Return (Local0)
|
||||
}
|
||||
}
|
18
kernel/hal/x86_64/uACPI/tests/test-cases/references-6.asl
Normal file
18
kernel/hal/x86_64/uACPI/tests/test-cases/references-6.asl
Normal file
@ -0,0 +1,18 @@
|
||||
// Name: ArgX reference is not rebindable via CopyObject
|
||||
// Expect: int => 0xDEADBEEF
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (TEST, 1, NotSerialized)
|
||||
{
|
||||
CopyObject(0xDEADC0DE, Arg0)
|
||||
CopyObject(0xDEADBEEF, Arg0)
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = "MyString"
|
||||
TEST(RefOf(Local0))
|
||||
Return (Local0)
|
||||
}
|
||||
}
|
25
kernel/hal/x86_64/uACPI/tests/test-cases/references-7.asl
Normal file
25
kernel/hal/x86_64/uACPI/tests/test-cases/references-7.asl
Normal file
@ -0,0 +1,25 @@
|
||||
// Name: ArgX non-reference is rebindable
|
||||
// Expect: str => MyString
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (TES0, 1, NotSerialized)
|
||||
{
|
||||
CopyObject("Hello World", Arg0)
|
||||
Debug = Arg0
|
||||
}
|
||||
|
||||
Method (TES1, 1, NotSerialized)
|
||||
{
|
||||
Arg0 = 0x123
|
||||
Debug = Arg0
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = "MyString"
|
||||
TES0(Local0)
|
||||
TES1(Local0)
|
||||
Return(Local0)
|
||||
}
|
||||
}
|
18
kernel/hal/x86_64/uACPI/tests/test-cases/references-8.asl
Normal file
18
kernel/hal/x86_64/uACPI/tests/test-cases/references-8.asl
Normal file
@ -0,0 +1,18 @@
|
||||
// Name: ArgX reference is not rebindable via Store
|
||||
// Expect: int => 0xDEADBEEF
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (TEST, 1, NotSerialized)
|
||||
{
|
||||
Store(0xDEADC0DE, Arg0)
|
||||
Store(0xDEADBEEF, Arg0)
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = "MyString"
|
||||
TEST(RefOf(Local0))
|
||||
Return (Local0)
|
||||
}
|
||||
}
|
18
kernel/hal/x86_64/uACPI/tests/test-cases/references-9.asl
Normal file
18
kernel/hal/x86_64/uACPI/tests/test-cases/references-9.asl
Normal file
@ -0,0 +1,18 @@
|
||||
// Name: Modification via LocalX reference implict-casts (string->int64)
|
||||
// Expect: int => 0x676E6F6C79726576
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (TEST, 1, NotSerialized)
|
||||
{
|
||||
Local0 = RefOf(Arg0)
|
||||
Local0 = "verylongstringbiggerthanint"
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = 0xDEADC0DEDEADBEEF
|
||||
TEST(RefOf(Local0))
|
||||
Return (Local0)
|
||||
}
|
||||
}
|
147
kernel/hal/x86_64/uACPI/tests/test-cases/reg-devices.asl
Normal file
147
kernel/hal/x86_64/uACPI/tests/test-cases/reg-devices.asl
Normal file
@ -0,0 +1,147 @@
|
||||
// Name: _REG gets called correctly
|
||||
// Expect: int => 0
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Name (RET, 0)
|
||||
|
||||
Device (PCI0) {
|
||||
Name (_HID, "PNP0000")
|
||||
|
||||
Method (_CID) {
|
||||
Local0 = Package {
|
||||
"idk",
|
||||
0x000A2E4F,
|
||||
"badid",
|
||||
0x02002E4F,
|
||||
0x030FD041,
|
||||
0x130FD041,
|
||||
0x120FD041,
|
||||
|
||||
// PCI Express root bridge
|
||||
"PNP0A08"
|
||||
}
|
||||
Return (Local0)
|
||||
}
|
||||
|
||||
Name (_SEG, 0x1)
|
||||
Name (_BBN, 0x10)
|
||||
|
||||
Device (HPET) {
|
||||
Name (_HID, "PNP0103")
|
||||
|
||||
OperationRegion(LOLX, SystemMemory, 0xDEADBEEF, 123)
|
||||
|
||||
Method (_REG, 2) {
|
||||
Debug = "HPET._REG shouldn't have been called"
|
||||
RET += 1
|
||||
}
|
||||
}
|
||||
|
||||
Name (STAT, 0)
|
||||
|
||||
Device (UHCI) {
|
||||
Name (_ADR, 0x0001000F)
|
||||
|
||||
Method (TEST, 1, Serialized) {
|
||||
Method (_REG, 2, Serialized) {
|
||||
Printf("PCIR _REG(%o, %o) called", Arg0, Arg1)
|
||||
|
||||
If (Arg0 != 2) {
|
||||
Printf("Invalid space value %o", Arg0)
|
||||
RET += 1
|
||||
}
|
||||
|
||||
Switch (Arg1) {
|
||||
Case (0) {
|
||||
If (STAT != 1) {
|
||||
Debug = "Trying to _REG(disconnect) before _REG(connect)"
|
||||
RET += 1
|
||||
Break
|
||||
}
|
||||
|
||||
STAT += 1
|
||||
Break
|
||||
|
||||
}
|
||||
Case (1) {
|
||||
If (STAT != 0) {
|
||||
Debug = "Trying to run _REG(connect) twice"
|
||||
RET += 1
|
||||
Break
|
||||
}
|
||||
|
||||
STAT += 1
|
||||
Break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
OperationRegion(PCIR, PCI_Config, 0x00, Arg0)
|
||||
Field (PCIR, AnyAcc, NoLock) {
|
||||
REG0, 8
|
||||
}
|
||||
|
||||
If (STAT != 1) {
|
||||
Debug = "No one ever called _REG on PCIR, giving up"
|
||||
RET += 1
|
||||
Return ()
|
||||
}
|
||||
|
||||
REG0 = 123
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Device (PCI1) {
|
||||
Name (STAT, 0)
|
||||
|
||||
// PCI root bus
|
||||
Name (_HID, "PNP0A03")
|
||||
|
||||
Device (XHCI) {
|
||||
Name (_ADR, 0x00030002)
|
||||
|
||||
OperationRegion(HREG, PCI_Config, 0x04, 0xF0)
|
||||
Field (HREG, AnyAcc, NoLock) {
|
||||
REG2, 8
|
||||
}
|
||||
|
||||
// This can only be called after loading the namespace
|
||||
Method (_REG, 2) {
|
||||
Printf("HREG _REG(%o, %o) called", Arg0, Arg1)
|
||||
|
||||
If (Arg0 != 2) {
|
||||
Printf("Invalid space value %o", Arg0)
|
||||
RET += 1
|
||||
}
|
||||
|
||||
If (Arg1 != 1 || STAT != 0) {
|
||||
Printf("Invalid Arg1 (%o) for state %o", Arg1, STAT)
|
||||
RET += 1
|
||||
}
|
||||
|
||||
STAT += 1
|
||||
}
|
||||
|
||||
Method (WRIT, 1) {
|
||||
REG2 = Arg0
|
||||
Return (Arg0)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Method (MAIN) {
|
||||
\PCI0.UHCI.TEST(0xFF)
|
||||
Local0 = 1
|
||||
|
||||
If (\PCI1.STAT == 1) {
|
||||
Local0 -= \PCI1.XHCI.WRIT(1)
|
||||
} Else {
|
||||
Debug = "PCI1.XHCI._REG was never called!"
|
||||
}
|
||||
|
||||
Return (RET + Local0)
|
||||
}
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
// Name: Return Integer 0 (Indirect)
|
||||
// Expect: int => 0
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (HELP, 0, NotSerialized)
|
||||
{
|
||||
Return (0)
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Return (HELP())
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
// Name: Return Integer 1 Using Ifs
|
||||
// Expect: int => 1
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (GET0, 1, NotSerialized)
|
||||
{
|
||||
Debug = "GET0 called"
|
||||
Return(Arg0)
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
If (GET0(0)) {
|
||||
Debug = "We shouldn't be here..."
|
||||
} Else {
|
||||
Local0 = 0
|
||||
|
||||
If (GET0(1)) {
|
||||
Debug = "Branch worked"
|
||||
Local0 = 1
|
||||
} Else {
|
||||
Debug = "Shouldn't see this either"
|
||||
Local0 = 2
|
||||
}
|
||||
|
||||
Return(Local0)
|
||||
}
|
||||
|
||||
Return (3)
|
||||
}
|
||||
}
|
@ -0,0 +1,20 @@
|
||||
// Name: Return Integer 0xDEAD (Double Indirect)
|
||||
// Expect: int => 0xDEAD
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (HELP, 0, NotSerialized)
|
||||
{
|
||||
Return (0xDEAD)
|
||||
}
|
||||
|
||||
Method (INDI, 0, NotSerialized)
|
||||
{
|
||||
Return (HELP())
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Return (INDI())
|
||||
}
|
||||
}
|
10
kernel/hal/x86_64/uACPI/tests/test-cases/return_byte.asl
Normal file
10
kernel/hal/x86_64/uACPI/tests/test-cases/return_byte.asl
Normal file
@ -0,0 +1,10 @@
|
||||
// Name: Return Integer (Byte 0xCA)
|
||||
// Expect: int => 0xCA
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Return (0xCA)
|
||||
}
|
||||
}
|
10
kernel/hal/x86_64/uACPI/tests/test-cases/return_dword.asl
Normal file
10
kernel/hal/x86_64/uACPI/tests/test-cases/return_dword.asl
Normal file
@ -0,0 +1,10 @@
|
||||
// Name: Return Integer (DWord 0xCAFEBABE)
|
||||
// Expect: int => 0xCAFEBABE
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Return (0xCAFEBABE)
|
||||
}
|
||||
}
|
10
kernel/hal/x86_64/uACPI/tests/test-cases/return_qword.asl
Normal file
10
kernel/hal/x86_64/uACPI/tests/test-cases/return_qword.asl
Normal file
@ -0,0 +1,10 @@
|
||||
// Name: Return Integer (QWord 0xCAFEBABEDEADC0DE)
|
||||
// Expect: int => 0xCAFEBABEDEADC0DE
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Return (0xCAFEBABEDEADC0DE)
|
||||
}
|
||||
}
|
10
kernel/hal/x86_64/uACPI/tests/test-cases/return_word.asl
Normal file
10
kernel/hal/x86_64/uACPI/tests/test-cases/return_word.asl
Normal file
@ -0,0 +1,10 @@
|
||||
// Name: Return Integer (Word 0xCAFE)
|
||||
// Expect: int => 0xCAFE
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Return (0xCAFE)
|
||||
}
|
||||
}
|
32
kernel/hal/x86_64/uACPI/tests/test-cases/scope.asl
Normal file
32
kernel/hal/x86_64/uACPI/tests/test-cases/scope.asl
Normal file
@ -0,0 +1,32 @@
|
||||
// Name: Scopes and undefined references
|
||||
// Expect: int => 13
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Name (MAIN, 0)
|
||||
|
||||
Scope (\PATH.THAT.DOES.NOT.EXIS.T) {
|
||||
Debug = "Why are we here"
|
||||
MAIN += 1
|
||||
}
|
||||
|
||||
Scope (\_SB) {
|
||||
MAIN += 3
|
||||
|
||||
Scope (^ANOT.HER) {
|
||||
MAIN += 4
|
||||
}
|
||||
|
||||
Scope (\_GPE) {
|
||||
MAIN += 10
|
||||
|
||||
Scope (PATH) {
|
||||
MAIN += 200
|
||||
}
|
||||
}
|
||||
|
||||
Scope (FAIL.TOO) {
|
||||
MAIN += 300
|
||||
}
|
||||
}
|
||||
}
|
50
kernel/hal/x86_64/uACPI/tests/test-cases/sleep.asl
Normal file
50
kernel/hal/x86_64/uACPI/tests/test-cases/sleep.asl
Normal file
@ -0,0 +1,50 @@
|
||||
// Name: Sleep & Stall
|
||||
// Expect: int => 0
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (CHEK, 4)
|
||||
{
|
||||
Local0 = Arg2 - Arg1
|
||||
|
||||
If (Local0 < Arg3) {
|
||||
Printf("%o finished too soon, elapsed %o, expected at least %o",
|
||||
Arg0, ToDecimalString(Local0), ToDecimalString(Arg3))
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Return (0)
|
||||
}
|
||||
|
||||
Method (STAL, 1) {
|
||||
Local1 = 0
|
||||
|
||||
While (Local1 < Arg0) {
|
||||
Stall(100)
|
||||
Local1 += 1
|
||||
}
|
||||
}
|
||||
|
||||
Method (MAIN, 0, Serialized)
|
||||
{
|
||||
Local0 = Timer
|
||||
|
||||
// Stall for 10 * 100 microseconds (aka 1ms)
|
||||
STAL(10)
|
||||
|
||||
If (CHEK("Stall", Local0, Timer, 10000) != 0) {
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Local0 = Timer
|
||||
|
||||
// Sleep for 2ms
|
||||
Sleep(2)
|
||||
|
||||
If (CHEK("Sleep", Local0, Timer, 20000) != 0) {
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Return (0)
|
||||
}
|
||||
}
|
@ -0,0 +1,26 @@
|
||||
// Name: Store Copies The Buffer
|
||||
// Expect: str => Hello
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (MODF, 0, NotSerialized)
|
||||
{
|
||||
Local1 = Store("Hello", Local0)
|
||||
Return (Local1)
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local1 = Store(MODF(), Local0)
|
||||
|
||||
// Modify the string at Local1
|
||||
Local2 = RefOf(Local1)
|
||||
Local2 = "Goodbye"
|
||||
|
||||
Debug = Local0
|
||||
Debug = Local1
|
||||
|
||||
// Local0 should still have the same value
|
||||
Return(Local0)
|
||||
}
|
||||
}
|
61
kernel/hal/x86_64/uACPI/tests/test-cases/table-loading-0.asl
Normal file
61
kernel/hal/x86_64/uACPI/tests/test-cases/table-loading-0.asl
Normal file
@ -0,0 +1,61 @@
|
||||
// Name: Load tables from buffers
|
||||
// Expect: str => Hello World 123
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (MAIN, 0, Serialized)
|
||||
{
|
||||
Name (WRLD, "World")
|
||||
|
||||
/*
|
||||
* Method (PRT0, 0, NotSerialized)
|
||||
* {
|
||||
* Return(Concatenate("Hello ", \MAIN.WRLD))
|
||||
* }
|
||||
*/
|
||||
External(\PRT0, MethodObj)
|
||||
Name (TABL, Buffer {
|
||||
0x53,0x53,0x44,0x54,0x40,0x00,0x00,0x00, /* 00000000 "SSDT@..." */
|
||||
0x02,0x86,0x75,0x54,0x45,0x53,0x54,0x00, /* 00000008 "..uTEST." */
|
||||
0x54,0x45,0x53,0x54,0x54,0x41,0x42,0x4C, /* 00000010 "TESTTAB0" */
|
||||
0xF0,0xF0,0xF0,0xF0,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */
|
||||
0x31,0x03,0x22,0x20,0x14,0x1B,0x50,0x52, /* 00000020 "1." ..PR" */
|
||||
0x54,0x30,0x00,0xA4,0x73,0x0D,0x48,0x65, /* 00000028 "T0..s.He" */
|
||||
0x6C,0x6C,0x6F,0x20,0x00,0x5C,0x2E,0x4D, /* 00000030 "llo .\.M" */
|
||||
0x41,0x49,0x4E,0x57,0x52,0x4C,0x44,0x00 /* 00000038 "AINWRLD." */
|
||||
})
|
||||
|
||||
If (!Load(TABL)) {
|
||||
Return ("Table 0 load failed")
|
||||
}
|
||||
|
||||
/*
|
||||
* Name (O123, "123")
|
||||
*
|
||||
* Method (PRT1, 2, NotSerialized)
|
||||
* {
|
||||
* Return(Concatenate(Concatenate(Arg0, " "), Arg1))
|
||||
* }
|
||||
*/
|
||||
External(\PRT1, MethodObj)
|
||||
External(\O123, StrObj)
|
||||
Name (TAB1, Buffer {
|
||||
0x53,0x53,0x44,0x54,0x3F,0x00,0x00,0x00, /* 00000000 "SSDT?..." */
|
||||
0x02,0x97,0x75,0x54,0x45,0x53,0x54,0x00, /* 00000008 "..uTEST." */
|
||||
0x54,0x45,0x53,0x54,0x54,0x41,0x42,0x4C, /* 00000010 "TESTTAB1" */
|
||||
0xF0,0xF0,0xF0,0xF0,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */
|
||||
0x31,0x03,0x22,0x20,0x08,0x4F,0x31,0x32, /* 00000020 "1." .O12" */
|
||||
0x33,0x0D,0x31,0x32,0x33,0x00,0x14,0x10, /* 00000028 "3.123..." */
|
||||
0x50,0x52,0x54,0x31,0x02,0xA4,0x73,0x73, /* 00000030 "PRT1..ss" */
|
||||
0x68,0x0D,0x20,0x00,0x00,0x69,0x00 /* 00000038 "h. ..i." */
|
||||
})
|
||||
|
||||
Load(TAB1, Local1)
|
||||
If (!Local1) {
|
||||
Return ("Table 1 load failed")
|
||||
}
|
||||
|
||||
Local0 = PRT0()
|
||||
Return (PRT1(Local0, O123))
|
||||
}
|
||||
}
|
76
kernel/hal/x86_64/uACPI/tests/test-cases/table-loading-1.asl
Normal file
76
kernel/hal/x86_64/uACPI/tests/test-cases/table-loading-1.asl
Normal file
@ -0,0 +1,76 @@
|
||||
// Name: Load tables from opregions & fields
|
||||
// Expect: str => Hello World 123
|
||||
|
||||
DefinitionBlock ("", "SSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (MAIN, 0, Serialized)
|
||||
{
|
||||
Name (WRLD, "World")
|
||||
|
||||
/*
|
||||
* Method (PRT0, 0, NotSerialized)
|
||||
* {
|
||||
* Return(Concatenate("Hello ", \MAIN.WRLD))
|
||||
* }
|
||||
*/
|
||||
External(\PRT0, MethodObj)
|
||||
Name (TAB0, Buffer {
|
||||
0x53,0x53,0x44,0x54,0x40,0x00,0x00,0x00, /* 00000000 "SSDT@..." */
|
||||
0x02,0x86,0x75,0x54,0x45,0x53,0x54,0x00, /* 00000008 "..uTEST." */
|
||||
0x54,0x45,0x53,0x54,0x54,0x41,0x42,0x4C, /* 00000010 "TESTTAB0" */
|
||||
0xF0,0xF0,0xF0,0xF0,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */
|
||||
0x31,0x03,0x22,0x20,0x14,0x1B,0x50,0x52, /* 00000020 "1." ..PR" */
|
||||
0x54,0x30,0x00,0xA4,0x73,0x0D,0x48,0x65, /* 00000028 "T0..s.He" */
|
||||
0x6C,0x6C,0x6F,0x20,0x00,0x5C,0x2E,0x4D, /* 00000030 "llo .\.M" */
|
||||
0x41,0x49,0x4E,0x57,0x52,0x4C,0x44,0x00 /* 00000038 "AINWRLD." */
|
||||
})
|
||||
OperationRegion(TABR, SystemMemory, 0xDEADBEE0, SizeOf(TAB0))
|
||||
Field (TABR, WordAcc, NoLock, WriteAsOnes) {
|
||||
COPY, 512,
|
||||
}
|
||||
COPY = TAB0
|
||||
|
||||
Load(TABR, Local0)
|
||||
If (!Local0) {
|
||||
Return ("Table 0 load failed")
|
||||
}
|
||||
|
||||
/*
|
||||
* Name (O123, "123")
|
||||
*
|
||||
* Method (PRT1, 2, NotSerialized)
|
||||
* {
|
||||
* Return(Concatenate(Concatenate(Arg0, " "), Arg1))
|
||||
* }
|
||||
*/
|
||||
External(\PRT1, MethodObj)
|
||||
External(\O123, StrObj)
|
||||
Name (TAB1, Buffer {
|
||||
0x53,0x53,0x44,0x54,0x3F,0x00,0x00,0x00, /* 00000000 "SSDT?..." */
|
||||
0x02,0x97,0x75,0x54,0x45,0x53,0x54,0x00, /* 00000008 "..uTEST." */
|
||||
0x54,0x45,0x53,0x54,0x54,0x41,0x42,0x4C, /* 00000010 "TESTTAB1" */
|
||||
0xF0,0xF0,0xF0,0xF0,0x49,0x4E,0x54,0x4C, /* 00000018 "....INTL" */
|
||||
0x31,0x03,0x22,0x20,0x08,0x4F,0x31,0x32, /* 00000020 "1." .O12" */
|
||||
0x33,0x0D,0x31,0x32,0x33,0x00,0x14,0x10, /* 00000028 "3.123..." */
|
||||
0x50,0x52,0x54,0x31,0x02,0xA4,0x73,0x73, /* 00000030 "PRT1..ss" */
|
||||
0x68,0x0D,0x20,0x00,0x00,0x69,0x00,0x00 /* 00000038 "h. ..i." */
|
||||
})
|
||||
OperationRegion(TABX, SystemMemory, 0xCAFEBAB0, SizeOf(TAB1))
|
||||
Field (TABX, DWordAcc, NoLock, Preserve) {
|
||||
BLOB, 512,
|
||||
}
|
||||
|
||||
// Copy the table into the operation region
|
||||
BLOB = TAB1
|
||||
|
||||
Load(BLOB, Local1)
|
||||
If (!Local1) {
|
||||
Return ("Table 1 load failed")
|
||||
}
|
||||
|
||||
Local0 = PRT0()
|
||||
Return (PRT1(Local0, O123))
|
||||
}
|
||||
|
||||
Debug = MAIN()
|
||||
}
|
113
kernel/hal/x86_64/uACPI/tests/test-cases/table-loading-2.asl
Normal file
113
kernel/hal/x86_64/uACPI/tests/test-cases/table-loading-2.asl
Normal file
@ -0,0 +1,113 @@
|
||||
// Name: Recursive table loads
|
||||
// Expect: int => 0
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
// Number of started table loads
|
||||
Name (NUMB, 0)
|
||||
|
||||
// Number of finished table loads
|
||||
Name (NUMA, 0)
|
||||
|
||||
/*
|
||||
* DefinitionBlock ("", "SSDT", 1, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
* {
|
||||
* External(NUMA, IntObj)
|
||||
* External(NUMB, IntObj)
|
||||
* External(ITEM, IntObj)
|
||||
* External(TABL, IntObj)
|
||||
*
|
||||
* // Recursively start 10 table loads
|
||||
* If (NUMB < 10) {
|
||||
* // Create an ITEM here to prove to the caller that we got invoked
|
||||
* If (!CondRefOf(ITEM)) {
|
||||
* Name (ITEM, 123)
|
||||
* }
|
||||
*
|
||||
* NUMB += 1
|
||||
* Local0 = Load(TABL)
|
||||
*
|
||||
* // The last load is expected to fail, everything before should succeed
|
||||
* If (!Local0) {
|
||||
* If (NUMB != 10) {
|
||||
* NUMA = 0xDEADBEEF
|
||||
* Printf("Table load %o failed", NUMB)
|
||||
* }
|
||||
* } Else {
|
||||
* NUMA += 1
|
||||
* }
|
||||
*
|
||||
*
|
||||
* // Return something bogus here to make sure the return value isn't
|
||||
* // propagated to the caller of Load.
|
||||
* Return (Package { 1, 2 ,3})
|
||||
* }
|
||||
*
|
||||
* // We're the last table load, do something naughty to cause an error
|
||||
* Local0 = Package { 1 }
|
||||
* Local1 = RefOf(Local0)
|
||||
*
|
||||
* // This code specifically attempts to perform a bogus implicit cast
|
||||
* Local1 = "Hello World"
|
||||
* }
|
||||
*/
|
||||
Name (TABL, Buffer {
|
||||
0x53, 0x53, 0x44, 0x54, 0xdc, 0x00, 0x00, 0x00,
|
||||
0x01, 0x33, 0x75, 0x54, 0x45, 0x53, 0x54, 0x00,
|
||||
0x54, 0x45, 0x53, 0x54, 0x54, 0x41, 0x42, 0x4c,
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0x49, 0x4e, 0x54, 0x4c,
|
||||
0x28, 0x06, 0x23, 0x20, 0xa0, 0x22, 0x00, 0x15,
|
||||
0x5c, 0x4e, 0x55, 0x4d, 0x41, 0x01, 0x00, 0x15,
|
||||
0x5c, 0x4e, 0x55, 0x4d, 0x42, 0x01, 0x00, 0x15,
|
||||
0x5c, 0x49, 0x54, 0x45, 0x4d, 0x01, 0x00, 0x15,
|
||||
0x5c, 0x54, 0x41, 0x42, 0x4c, 0x01, 0x00, 0xa0,
|
||||
0x4b, 0x07, 0x95, 0x4e, 0x55, 0x4d, 0x42, 0x0a,
|
||||
0x0a, 0xa0, 0x10, 0x92, 0x5b, 0x12, 0x49, 0x54,
|
||||
0x45, 0x4d, 0x00, 0x08, 0x49, 0x54, 0x45, 0x4d,
|
||||
0x0a, 0x7b, 0x72, 0x4e, 0x55, 0x4d, 0x42, 0x01,
|
||||
0x4e, 0x55, 0x4d, 0x42, 0x70, 0x5b, 0x20, 0x54,
|
||||
0x41, 0x42, 0x4c, 0x00, 0x60, 0xa0, 0x38, 0x92,
|
||||
0x60, 0xa0, 0x34, 0x92, 0x93, 0x4e, 0x55, 0x4d,
|
||||
0x42, 0x0a, 0x0a, 0x70, 0x0c, 0xef, 0xbe, 0xad,
|
||||
0xde, 0x4e, 0x55, 0x4d, 0x41, 0x70, 0x73, 0x73,
|
||||
0x0d, 0x54, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6c,
|
||||
0x6f, 0x61, 0x64, 0x20, 0x00, 0x4e, 0x55, 0x4d,
|
||||
0x42, 0x00, 0x0d, 0x20, 0x66, 0x61, 0x69, 0x6c,
|
||||
0x65, 0x64, 0x00, 0x00, 0x5b, 0x31, 0xa1, 0x0b,
|
||||
0x72, 0x4e, 0x55, 0x4d, 0x41, 0x01, 0x4e, 0x55,
|
||||
0x4d, 0x41, 0xa4, 0x12, 0x07, 0x03, 0x01, 0x0a,
|
||||
0x02, 0x0a, 0x03, 0x70, 0x12, 0x03, 0x01, 0x01,
|
||||
0x60, 0x70, 0x71, 0x60, 0x61, 0x70, 0x0d, 0x48,
|
||||
0x65, 0x6c, 0x6c, 0x6f, 0x20, 0x57, 0x6f, 0x72,
|
||||
0x6c, 0x64, 0x00, 0x61
|
||||
})
|
||||
|
||||
Method (MAIN, 0, Serialized)
|
||||
{
|
||||
Load(TABL, Local0)
|
||||
Printf("Recursive loads finished!")
|
||||
|
||||
If (!Local0) {
|
||||
Printf("Table load failed!")
|
||||
Return (0xCAFEBABE)
|
||||
}
|
||||
|
||||
External(ITEM, IntObj)
|
||||
If (ITEM != 123) {
|
||||
Printf("ITEM has incorrect value %o", ITEM)
|
||||
Return (0xDEADBEEF)
|
||||
}
|
||||
|
||||
If (NUMB != 10) {
|
||||
Printf("Invalid NUMB value %o", ToDecimalString(NUMB))
|
||||
Return (0xEEFFAABB)
|
||||
}
|
||||
|
||||
If (NUMA != 9) {
|
||||
Printf("Invalid NUMA value %o", ToDecimalString(NUMA))
|
||||
Return (0x11223344)
|
||||
}
|
||||
|
||||
Return (0)
|
||||
}
|
||||
}
|
106
kernel/hal/x86_64/uACPI/tests/test-cases/table-loading-3.asl
Normal file
106
kernel/hal/x86_64/uACPI/tests/test-cases/table-loading-3.asl
Normal file
@ -0,0 +1,106 @@
|
||||
// Name: Recursive table loads with LoadTable
|
||||
// Expect: int => 0
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
External(ITEM, IntObj)
|
||||
External(NUMB, IntObj)
|
||||
External(NUMA, IntObj)
|
||||
External(VISI, IntObj)
|
||||
|
||||
// All dynamic loads branch into here
|
||||
If (CondRefOf(ITEM)) {
|
||||
// Recursively start 10 table loads
|
||||
If (NUMB < 10) {
|
||||
NUMB += 1
|
||||
Local0 = NUMB
|
||||
|
||||
If (NUMB == 3) {
|
||||
Local0 = LoadTable("DSDT", "uTEST", "", "", "PARA", Local0)
|
||||
VISI += 1
|
||||
} ElseIf (NUMB == 5) {
|
||||
Local0 = LoadTable("DSDT", "", "", "", "PARA", Local0)
|
||||
VISI += 10
|
||||
} ElseIf (NUMB == 7) {
|
||||
Local0 = LoadTable("DSDT", "", "TESTTABL", "", "", Local0)
|
||||
VISI += 100
|
||||
} Else {
|
||||
Local0 = LoadTable("DSDT", "uTEST", "TESTTABL", "", "PARA", Local0)
|
||||
VISI += 1000
|
||||
}
|
||||
|
||||
// The last load is expected to fail, everything before should succeed
|
||||
If (!Local0) {
|
||||
If (NUMB != 10) {
|
||||
NUMA = 0xDEADBEEF
|
||||
Printf("Table load %o failed", NUMB)
|
||||
}
|
||||
} Else {
|
||||
NUMA += 1
|
||||
}
|
||||
|
||||
// Return something bogus here to make sure the return value isn't
|
||||
// propagated to the caller of Load.
|
||||
Return (Package { 1, 2 ,3})
|
||||
}
|
||||
|
||||
// We're the last table load, do something naughty to cause an error
|
||||
Local0 = Package { 1 }
|
||||
Local1 = RefOf(Local0)
|
||||
|
||||
// This code specifically attempts to perform a bogus implicit cast
|
||||
Local1 = "Hello World"
|
||||
}
|
||||
|
||||
Name (ITEM, 123)
|
||||
|
||||
// Number of started table loads
|
||||
Name (NUMB, 0)
|
||||
|
||||
// Number of finished table loads
|
||||
Name (NUMA, 0)
|
||||
|
||||
// Visited branches
|
||||
Name (VISI, 0)
|
||||
|
||||
Name (PARA, 0)
|
||||
Name (PASS, "FAIL")
|
||||
|
||||
Method (MAIN, 0, Serialized)
|
||||
{
|
||||
Local0 = LoadTable("DSDT", "uTEST", "TESTTABL", "", "PASS", 0x53534150)
|
||||
Printf("Recursive loads finished!")
|
||||
|
||||
If (!Local0) {
|
||||
Printf("Table load failed!")
|
||||
Return (0xCAFEBABE)
|
||||
}
|
||||
|
||||
If (NUMB != 10) {
|
||||
Printf("Invalid NUMB value %o", ToDecimalString(NUMB))
|
||||
Return (0xEEFFAABB)
|
||||
}
|
||||
|
||||
If (VISI != 7111) {
|
||||
Printf("Invalid VISI value %o", ToDecimalString(VISI))
|
||||
Return (0xAFFAAFFA)
|
||||
}
|
||||
|
||||
If (NUMA != 9) {
|
||||
Printf("Invalid NUMA value %o", ToDecimalString(NUMA))
|
||||
Return (0x11223344)
|
||||
}
|
||||
|
||||
If (PARA != 1) {
|
||||
Printf("Invalid PARA value %o", ToDecimalString(PARA))
|
||||
Return (0xDDFFBBCC)
|
||||
}
|
||||
|
||||
If (PASS != "PASS") {
|
||||
Printf("Invalid PASS value %o", PASS)
|
||||
Return (0xECECECEC)
|
||||
}
|
||||
|
||||
Return (0)
|
||||
}
|
||||
}
|
124
kernel/hal/x86_64/uACPI/tests/test-cases/table-loading-4.asl
Normal file
124
kernel/hal/x86_64/uACPI/tests/test-cases/table-loading-4.asl
Normal file
@ -0,0 +1,124 @@
|
||||
// Name: LoadTable scoping rules are correct
|
||||
// Expect: int => 0
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
External(SSDT, IntObj)
|
||||
External(VAL, IntObj)
|
||||
|
||||
// All dynamic loads branch into here
|
||||
If (CondRefOf(SSDT)) {
|
||||
Name (TEST, 0)
|
||||
TEST = VAL
|
||||
Return (Package { 1 })
|
||||
}
|
||||
|
||||
Name (SSDT, 123)
|
||||
Name (VAL, 1)
|
||||
|
||||
Device (DEV0) {
|
||||
Name (LRES, 0)
|
||||
}
|
||||
|
||||
Device (DEV1) { }
|
||||
Scope (_SB) {
|
||||
Device (DEV1) {
|
||||
Name (LRES, "XX")
|
||||
Device (DEV1) { }
|
||||
}
|
||||
}
|
||||
|
||||
Name (LRES, 99)
|
||||
Device (DEV2) {
|
||||
Name (LRES, 123)
|
||||
}
|
||||
|
||||
Method (LDTB, 3) {
|
||||
Local0 = LoadTable("DSDT", "uTEST", "TESTTABL", Arg0, Arg1, Arg2)
|
||||
VAL += 1
|
||||
|
||||
If (!Local0) {
|
||||
Printf("Table load failed!")
|
||||
Return (0)
|
||||
}
|
||||
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Method (MAIN)
|
||||
{
|
||||
/*
|
||||
* DEV0 is the scope, LRES should be evaluated relative to it.
|
||||
* TEST is expected to be loaded there as well.
|
||||
*/
|
||||
If (!LDTB("DEV0", "LRES", 0xFEBEFEBE)) {
|
||||
Return (1)
|
||||
}
|
||||
If (!CondRefOf(\DEV0.TEST, Local0)) {
|
||||
Printf("No TEST under \\DEV0")
|
||||
Return (1)
|
||||
}
|
||||
If (DerefOf(Local0) != 1) {
|
||||
Printf("Incorrect \\DEV0.TEST value %o", DerefOf(Local0))
|
||||
Return (1)
|
||||
}
|
||||
If (\DEV0.LRES != 0xFEBEFEBE) {
|
||||
Printf("\\DEV0.LRES has an incorrect value %o", \DEV0.LRES)
|
||||
Return (1)
|
||||
}
|
||||
|
||||
CopyObject(0, Local0)
|
||||
|
||||
Scope (\_SB.DEV1) {
|
||||
/*
|
||||
* We're already inside \_SB.DEV1, so this DEV1 should match
|
||||
* \_SB.DEV1.DEV1, note that there's also \DEV1, that shouldn't
|
||||
* get matched here.
|
||||
*
|
||||
* There's, however, no \_SB.DEV1.DEV1.LRES, so this should resolve
|
||||
* into \_SB.DEV1.LRES instead.
|
||||
*/
|
||||
Local0 = LoadTable("DSDT", "uTEST", "TESTTABL", "DEV1", "LRES", 0x4B4F)
|
||||
If (!Local0) {
|
||||
Printf("Table load failed!")
|
||||
Return (0)
|
||||
}
|
||||
VAL += 1
|
||||
}
|
||||
If (!CondRefOf(\_SB.DEV1.DEV1.TEST, Local0)) {
|
||||
Printf("No TEST under _SB.DEV1.DEV1")
|
||||
Return (1)
|
||||
}
|
||||
If (DerefOf(Local0) != 2) {
|
||||
Printf("Incorrect \\_SB.DEV1.DEV1.TEST value %o", DerefOf(Local0))
|
||||
}
|
||||
If (\_SB.DEV1.LRES != "OK") {
|
||||
Printf("DEV1.LRES has an incorrect value %o", \_SB.DEV1.LRES)
|
||||
Return (1)
|
||||
}
|
||||
|
||||
CopyObject(0, Local0)
|
||||
|
||||
/*
|
||||
* DEV2 relative load, however, LRES is specified as an absolute path
|
||||
* so it shouldn't get resolved to DEV2.LRES.
|
||||
*/
|
||||
If (!LDTB("DEV2", "\\LRES", 0xCAFEBABE)) {
|
||||
Return (1)
|
||||
}
|
||||
If (!CondRefOf(\DEV2.TEST, Local0)) {
|
||||
Printf("No TEST under \\DEV2")
|
||||
Return (1)
|
||||
}
|
||||
If (DerefOf(Local0) != 3) {
|
||||
Printf("Incorrect \\DEV2.TEST value %o", DerefOf(Local0))
|
||||
Return (1)
|
||||
}
|
||||
If (\LRES != 0xCAFEBABE) {
|
||||
Printf("\\LRES has an incorrect value %o", \LRES)
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Return (0)
|
||||
}
|
||||
}
|
64
kernel/hal/x86_64/uACPI/tests/test-cases/table-loading-5.asl
Normal file
64
kernel/hal/x86_64/uACPI/tests/test-cases/table-loading-5.asl
Normal file
@ -0,0 +1,64 @@
|
||||
// Name: Load/LoadTable handle bogus-sized tables correctly
|
||||
// Expect: int => 0
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
External(\SSDT, IntObj)
|
||||
External(\OK, IntObj)
|
||||
External(\TYPE, IntObj)
|
||||
|
||||
// All dynamic loads branch into here
|
||||
If (CondRefOf(\OK)) {
|
||||
if (TYPE == 0) {
|
||||
Local0 = Load(\SSDT)
|
||||
} Else {
|
||||
DataTableRegion (DSDT, "DSDT", "uTEST", "TESTTABL")
|
||||
Field (DSDT, DwordAcc, NoLock, Preserve) {
|
||||
SIGN, 32,
|
||||
LENG, 32,
|
||||
}
|
||||
|
||||
// Make our own length bogus, then try to load ourselves, this should fail
|
||||
LENG = 3
|
||||
LoadTable("DSDT", "uTEST", "TESTTABL", "", "", 0)
|
||||
}
|
||||
|
||||
// Should be unreachable, we expect the Load above to abort us
|
||||
OK += 1
|
||||
Return (0)
|
||||
}
|
||||
|
||||
Name (SSDT, Buffer {
|
||||
0x53, 0x53, 0x44, 0x54, 0x2a, 0x00, 0x00, 0x00,
|
||||
0x01, 0x89, 0x75, 0x54, 0x45, 0x53, 0x54, 0x00,
|
||||
0x42, 0x41, 0x44, 0x54, 0x42, 0x4c, 0x00, 0x00,
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0x49, 0x4e, 0x54, 0x4c,
|
||||
0x28, 0x06, 0x23, 0x20, 0x70, 0x0d, 0x3f, 0x00,
|
||||
0x5b, 0x31
|
||||
})
|
||||
Name (OK, 0)
|
||||
Name (TYPE, 0)
|
||||
|
||||
Method (MAIN) {
|
||||
// Make the size something bogus
|
||||
SSDT[4] = 0x11
|
||||
SSDT[5] = 0
|
||||
SSDT[6] = 0
|
||||
SSDT[7] = 0
|
||||
|
||||
// Try Load'ing a bogus length SSDT
|
||||
TYPE = 0
|
||||
Local0 = LoadTable("DSDT", "uTEST", "TESTTABL", "", "", 0)
|
||||
|
||||
// Now try LoadTable ourselves, after corrupting our own length
|
||||
TYPE = 1
|
||||
Local0 = LoadTable("DSDT", "uTEST", "TESTTABL", "", "", 0)
|
||||
|
||||
// Expect the above to fail
|
||||
if (Local0 || OK) {
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Return (0)
|
||||
}
|
||||
}
|
70
kernel/hal/x86_64/uACPI/tests/test-cases/table-overrides.asl
Normal file
70
kernel/hal/x86_64/uACPI/tests/test-cases/table-overrides.asl
Normal file
@ -0,0 +1,70 @@
|
||||
// Name: Table overrides work
|
||||
// Expect: int => 0
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
/*
|
||||
* We expect this table to be denied by the test-runner because it denies
|
||||
* anything with "DENYTABL" in OEM table id.
|
||||
*
|
||||
* DefinitionBlock ("x.aml", "SSDT", 1, "uTEST", "DENYTABL", 0xF0F0F0F0)
|
||||
* {
|
||||
* Name (BUG, 1)
|
||||
* }
|
||||
*/
|
||||
Name (TAB0, Buffer {
|
||||
0x53, 0x53, 0x44, 0x54, 0x2a, 0x00, 0x00, 0x00,
|
||||
0x01, 0xe1, 0x75, 0x54, 0x45, 0x53, 0x54, 0x00,
|
||||
0x44, 0x45, 0x4e, 0x59, 0x54, 0x41, 0x42, 0x4c,
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0x49, 0x4e, 0x54, 0x4c,
|
||||
0x28, 0x06, 0x23, 0x20, 0x08, 0x42, 0x55, 0x47,
|
||||
0x5f, 0x01
|
||||
})
|
||||
|
||||
/*
|
||||
* We expect this table to be overriden by the test-runner because it
|
||||
* overrides anything with "OVERTABL" in OEM table id. The override it
|
||||
* provides has a Name(VAL, "TestRunner")
|
||||
*
|
||||
* DefinitionBlock ("x.aml", "SSDT", 1, "uTEST", "OVERTABL", 0xF0F0F0F0)
|
||||
* {
|
||||
* Name (VAL, "Hello")
|
||||
* }
|
||||
*/
|
||||
Name (TAB1, Buffer {
|
||||
0x53, 0x53, 0x44, 0x54, 0x30, 0x00, 0x00, 0x00,
|
||||
0x01, 0xcd, 0x75, 0x54, 0x45, 0x53, 0x54, 0x00,
|
||||
0x4f, 0x56, 0x45, 0x52, 0x54, 0x41, 0x42, 0x4c,
|
||||
0xf0, 0xf0, 0xf0, 0xf0, 0x49, 0x4e, 0x54, 0x4c,
|
||||
0x25, 0x09, 0x20, 0x20, 0x08, 0x56, 0x41, 0x4c,
|
||||
0x5f, 0x0d, 0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x00
|
||||
})
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Load(TAB0, Local0)
|
||||
If (Local0) {
|
||||
Debug = "Table was not denied load"
|
||||
Return (0xDEAD)
|
||||
}
|
||||
|
||||
If (CondRefOf(BUG)) {
|
||||
Debug = "Table was not loaded but the BUG object exists"
|
||||
Return (0xDEAD)
|
||||
}
|
||||
|
||||
Load(TAB1, Local0)
|
||||
If (!Local0) {
|
||||
Debug = "Failed to load table"
|
||||
Return (0xDEAD)
|
||||
}
|
||||
|
||||
If (VAL != "TestRunner") {
|
||||
Printf("Table didn't get overriden correctly: expected %o got %o",
|
||||
"TestRunner", VAL)
|
||||
Return (0xDEAD)
|
||||
}
|
||||
|
||||
Return (0)
|
||||
}
|
||||
}
|
113
kernel/hal/x86_64/uACPI/tests/test-cases/to-integer.asl
Normal file
113
kernel/hal/x86_64/uACPI/tests/test-cases/to-integer.asl
Normal file
@ -0,0 +1,113 @@
|
||||
// Name: ToInteger produces correct results
|
||||
// Expect: int => 0
|
||||
|
||||
DefinitionBlock ("", "SSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Name(FCNT, 0)
|
||||
|
||||
Method (CHEK, 3)
|
||||
{
|
||||
If (Arg0 != Arg1) {
|
||||
FCNT++
|
||||
Printf("On line %o: invalid number %o, expected %o",
|
||||
ToDecimalString(Arg2), ToHexString(Arg0), ToHexString(Arg1))
|
||||
}
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = ToInteger(123)
|
||||
Local1 = 123
|
||||
CHEK(Local0, Local1, __LINE__)
|
||||
|
||||
Local0 = ToInteger("123")
|
||||
Local1 = 123
|
||||
CHEK(Local0, Local1, __LINE__)
|
||||
|
||||
Local0 = ToInteger(" \t\t\t\v 123")
|
||||
Local1 = 123
|
||||
CHEK(Local0, Local1, __LINE__)
|
||||
|
||||
Local0 = ToInteger("123abcd")
|
||||
Local1 = 123
|
||||
CHEK(Local0, Local1, __LINE__)
|
||||
|
||||
Local0 = ToInteger("0x123abcd")
|
||||
Local1 = 0x123abcd
|
||||
CHEK(Local0, Local1, __LINE__)
|
||||
|
||||
Local0 = ToInteger("")
|
||||
Local1 = 0
|
||||
CHEK(Local0, Local1, __LINE__)
|
||||
|
||||
Local0 = ToInteger("0X")
|
||||
Local1 = 0
|
||||
CHEK(Local0, Local1, __LINE__)
|
||||
|
||||
Local0 = ToInteger("0x")
|
||||
Local1 = 0
|
||||
CHEK(Local0, Local1, __LINE__)
|
||||
|
||||
Local0 = ToInteger("0")
|
||||
Local1 = 0
|
||||
CHEK(Local0, Local1, __LINE__)
|
||||
|
||||
Local0 = ToInteger("0xDeAdBeeF")
|
||||
Local1 = 0xDEADBEEF
|
||||
CHEK(Local0, Local1, __LINE__)
|
||||
|
||||
Local0 = ToInteger("0XDeAdBeeFCafeBabeHelloWorld")
|
||||
Local1 = 0xDEADBEEFCAFEBABE
|
||||
CHEK(Local0, Local1, __LINE__)
|
||||
|
||||
Local0 = ToInteger(Buffer { 0xDE, 0xAD, 0xBE, 0xEF })
|
||||
Local1 = 0xEFBEADDE
|
||||
CHEK(Local0, Local1, __LINE__)
|
||||
|
||||
Local0 = ToInteger(Buffer { 1 })
|
||||
Local1 = 1
|
||||
CHEK(Local0, Local1, __LINE__)
|
||||
|
||||
Local0 = ToInteger(Buffer { 0 })
|
||||
Local1 = 0
|
||||
CHEK(Local0, Local1, __LINE__)
|
||||
|
||||
|
||||
Local0 = ToInteger(Buffer { 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE, 0xBA, 0xBE })
|
||||
Local1 = 0xBEBAFECAEFBEADDE
|
||||
CHEK(Local0, Local1, __LINE__)
|
||||
|
||||
// These are incompatible with ACPICA, skip if it's detected
|
||||
If (ToHexString(0xF) == "0xF") {
|
||||
Local0 = ToInteger("99999999999999999999999999999999999999999999999")
|
||||
Local1 = 0xFFFFFFFFFFFFFFFF
|
||||
CHEK(Local0, Local1, __LINE__)
|
||||
|
||||
Local0 = ToInteger("0xDEADBEEFCAFEBABE1")
|
||||
Local1 = 0xFFFFFFFFFFFFFFFF
|
||||
CHEK(Local0, Local1, __LINE__)
|
||||
|
||||
Local0 = ToInteger("+123")
|
||||
Local1 = 123
|
||||
CHEK(Local0, Local1, __LINE__)
|
||||
|
||||
Local0 = ToInteger("-123")
|
||||
Local1 = 0xFFFFFFFFFFFFFF85
|
||||
CHEK(Local0, Local1, __LINE__)
|
||||
|
||||
Local0 = ToInteger("-0xDEADBEF HELLOWORLD")
|
||||
Local1 = 0xFFFFFFFFF2152411
|
||||
CHEK(Local0, Local1, __LINE__)
|
||||
|
||||
Local0 = ToInteger("+0XC0D\t123")
|
||||
Local1 = 0xC0D
|
||||
CHEK(Local0, Local1, __LINE__)
|
||||
|
||||
Local0 = ToInteger("0123")
|
||||
Local1 = 83
|
||||
CHEK(Local0, Local1, __LINE__)
|
||||
}
|
||||
|
||||
Return (FCNT)
|
||||
}
|
||||
}
|
99
kernel/hal/x86_64/uACPI/tests/test-cases/to-x.asl
Normal file
99
kernel/hal/x86_64/uACPI/tests/test-cases/to-x.asl
Normal file
@ -0,0 +1,99 @@
|
||||
// Name: ToX produces correct results
|
||||
// Expect: int => 0
|
||||
|
||||
DefinitionBlock ("", "SSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Name(FCNT, 0)
|
||||
|
||||
Method (CHEK, 2)
|
||||
{
|
||||
If (ObjectType(Arg0) == 3) {
|
||||
Arg0 = ToHexString(Arg0)
|
||||
}
|
||||
|
||||
If (ObjectType(Arg1) == 3) {
|
||||
Arg1 = ToHexString(Arg1)
|
||||
}
|
||||
|
||||
If (Arg0 != Arg1) {
|
||||
FCNT++
|
||||
Printf("Invalid string %o, expected %o", Arg0, Arg1)
|
||||
}
|
||||
}
|
||||
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
// Dec string
|
||||
Local0 = ToDecimalString(123)
|
||||
Local1 = "123"
|
||||
CHEK(Local0, Local1)
|
||||
|
||||
Local0 = ToDecimalString(Buffer { 1, 2, 222, 33, 45, 192, 3, 255 })
|
||||
Local1 = "1,2,222,33,45,192,3,255"
|
||||
CHEK(Local0, Local1)
|
||||
|
||||
Local0 = ToDecimalString("")
|
||||
Local1 = ""
|
||||
CHEK(Local0, Local1)
|
||||
|
||||
Local0 = ToDecimalString("123")
|
||||
Local1 = "123"
|
||||
CHEK(Local0, Local1)
|
||||
|
||||
Local0 = ToDecimalString(0xFFFFFFFFFFFFFFFF)
|
||||
Local1 = "18446744073709551615"
|
||||
CHEK(Local0, Local1)
|
||||
|
||||
// Hex string
|
||||
Local0 = ToHexString(123)
|
||||
Local1 = "0x7B"
|
||||
CHEK(Local0, Local1)
|
||||
|
||||
Local0 = ToHexString(Buffer { 1, 2, 222, 33, 45, 192, 3, 255 })
|
||||
Local1 = "0x01,0x02,0xDE,0x21,0x2D,0xC0,0x03,0xFF"
|
||||
CHEK(Local0, Local1)
|
||||
|
||||
Local0 = ToHexString("")
|
||||
Local1 = ""
|
||||
CHEK(Local0, Local1)
|
||||
|
||||
Local0 = ToHexString("123")
|
||||
Local1 = "123"
|
||||
CHEK(Local0, Local1)
|
||||
|
||||
Local0 = ToHexString(0xF)
|
||||
Local1 = "0xF"
|
||||
CHEK(Local0, Local1)
|
||||
|
||||
Local0 = ToHexString(0xFF)
|
||||
Local1 = "0xFF"
|
||||
CHEK(Local0, Local1)
|
||||
|
||||
Local0 = ToHexString(0xFFF)
|
||||
Local1 = "0xFFF"
|
||||
CHEK(Local0, Local1)
|
||||
|
||||
Local0 = ToHexString(0xFFFFF)
|
||||
Local1 = "0xFFFFF"
|
||||
CHEK(Local0, Local1)
|
||||
|
||||
Local0 = ToHexString(0xFFFFFFFFFFFFFFFF)
|
||||
Local1 = "0xFFFFFFFFFFFFFFFF"
|
||||
CHEK(Local0, Local1)
|
||||
|
||||
// Buffer
|
||||
Local0 = ToBuffer(Buffer { 1, 2, 3 })
|
||||
Local1 = Buffer { 1, 2, 3 }
|
||||
CHEK(Local0, Local1)
|
||||
|
||||
Local0 = ToBuffer("Hello")
|
||||
Local1 = Buffer { 0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x00 }
|
||||
CHEK(Local0, Local1)
|
||||
|
||||
Local0 = ToBuffer(0xDEADBEEFCAFEBABE)
|
||||
Local1 = Buffer { 0xBE, 0xBA, 0xFE, 0xCA, 0xEF, 0xBE, 0xAD, 0xDE }
|
||||
CHEK(Local0, Local1)
|
||||
|
||||
Return (FCNT)
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
// Name: Unresolved paths don't error out when needed
|
||||
// Expect: int => 1
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = Package {
|
||||
321,
|
||||
PATH.THAT.DOES.NOT_.EXIS.T,
|
||||
123,
|
||||
\OK,
|
||||
\MAIN,
|
||||
}
|
||||
Debug = Local0
|
||||
|
||||
If (CondRefOf(ANOT.HER_.PATH.THAT.DOES.NOT.EXIS.T, Local0) ||
|
||||
CondRefOf(\TEST) || CondRefOf(^TEST) || CondRefOf(^TEST.JEST) ||
|
||||
CondRefOf(\TEST.JEST)) {
|
||||
Return (0)
|
||||
}
|
||||
|
||||
If (CondRefOf(^MAIN, Local1)) {
|
||||
Debug = Local1
|
||||
Return (1)
|
||||
}
|
||||
|
||||
Return (0)
|
||||
}
|
||||
}
|
24
kernel/hal/x86_64/uACPI/tests/test-cases/while-break.asl
Normal file
24
kernel/hal/x86_64/uACPI/tests/test-cases/while-break.asl
Normal file
@ -0,0 +1,24 @@
|
||||
// Name: While With Break
|
||||
// Expect: int => 10
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = 1
|
||||
Local1 = 10
|
||||
|
||||
While (Local0) {
|
||||
If (Local1--) {
|
||||
Debug = "Incrementing Local0"
|
||||
Local0++
|
||||
Debug = Local0
|
||||
} Else {
|
||||
Debug = "Local1 is 0, breaking"
|
||||
Break
|
||||
}
|
||||
}
|
||||
|
||||
Return(Local0)
|
||||
}
|
||||
}
|
25
kernel/hal/x86_64/uACPI/tests/test-cases/while-continue.asl
Normal file
25
kernel/hal/x86_64/uACPI/tests/test-cases/while-continue.asl
Normal file
@ -0,0 +1,25 @@
|
||||
// Name: While With Continue
|
||||
// Expect: int => 10
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = 1
|
||||
Local1 = 10
|
||||
|
||||
While (Local0) {
|
||||
If (Local1--) {
|
||||
Debug = "Incrementing Local0 & continuing"
|
||||
Local0++
|
||||
Debug = Local0
|
||||
Continue
|
||||
}
|
||||
|
||||
Debug = "Local1 is 0, breaking"
|
||||
Break
|
||||
}
|
||||
|
||||
Return(Local0)
|
||||
}
|
||||
}
|
20
kernel/hal/x86_64/uACPI/tests/test-cases/while-dec-inc.asl
Normal file
20
kernel/hal/x86_64/uACPI/tests/test-cases/while-dec-inc.asl
Normal file
@ -0,0 +1,20 @@
|
||||
// Name: Increment/Decrement With While
|
||||
// Expect: int => 10
|
||||
|
||||
DefinitionBlock ("", "DSDT", 2, "uTEST", "TESTTABL", 0xF0F0F0F0)
|
||||
{
|
||||
Method (MAIN, 0, NotSerialized)
|
||||
{
|
||||
Local0 = 1
|
||||
Local1 = 10
|
||||
|
||||
While (Local1--) {
|
||||
Debug = "Iteration"
|
||||
Debug = Local0
|
||||
|
||||
Local0++
|
||||
}
|
||||
|
||||
Return(Local0)
|
||||
}
|
||||
}
|
0
kernel/hal/x86_64/uACPI/tests/utilities/__init__.py
Normal file
0
kernel/hal/x86_64/uACPI/tests/utilities/__init__.py
Normal file
217
kernel/hal/x86_64/uACPI/tests/utilities/asl.py
Normal file
217
kernel/hal/x86_64/uACPI/tests/utilities/asl.py
Normal file
@ -0,0 +1,217 @@
|
||||
import os
|
||||
import subprocess
|
||||
from typing import List, Optional, Union
|
||||
|
||||
|
||||
class ASL:
|
||||
@staticmethod
|
||||
def definition_block(kind: str, revision: int) -> str:
|
||||
block = "DefinitionBlock "
|
||||
block += f'("", "{kind}", {revision}, '
|
||||
block += '"uTEST", "TESTTABL", 0xF0F0F0F0)'
|
||||
|
||||
return block
|
||||
|
||||
@staticmethod
|
||||
def name(name: str, term_arg: Union[str, int]) -> str:
|
||||
return f"Name({name}, {term_arg})"
|
||||
|
||||
@staticmethod
|
||||
def buffer(
|
||||
initializers: Optional[List[int]] = None,
|
||||
count: Optional[int] = None
|
||||
) -> str:
|
||||
if count is not None:
|
||||
buf_len = count
|
||||
elif initializers is not None:
|
||||
buf_len = len(initializers)
|
||||
else:
|
||||
buf_len = 0
|
||||
|
||||
buf = f"Buffer({buf_len})"
|
||||
|
||||
buf += " { "
|
||||
if initializers is not None:
|
||||
buf += ", ".join([str(x) for x in initializers])
|
||||
buf += " }"
|
||||
|
||||
return buf
|
||||
|
||||
@staticmethod
|
||||
def method(name: str, num_args: Optional[int] = None) -> str:
|
||||
method = f"Method ({name}"
|
||||
if num_args is not None:
|
||||
method += f", {num_args}"
|
||||
method += ")"
|
||||
|
||||
return method
|
||||
|
||||
@staticmethod
|
||||
def invoke(name: str, args: List[str] = []) -> str:
|
||||
invocation = f"{name}("
|
||||
invocation += ", ".join(args)
|
||||
invocation += ")"
|
||||
return invocation
|
||||
|
||||
@staticmethod
|
||||
def end_block() -> str:
|
||||
return "}"
|
||||
|
||||
@staticmethod
|
||||
def assign(dst: str, src: str) -> str:
|
||||
return f"{dst} = {src}"
|
||||
|
||||
@staticmethod
|
||||
def increment(name: str) -> str:
|
||||
return f"{name}++"
|
||||
|
||||
@staticmethod
|
||||
def create_field(buf: str, idx: int, field_size: int,
|
||||
field_name: str) -> str:
|
||||
return f"CreateField({buf}, {idx}, {field_size}, {field_name})"
|
||||
|
||||
@staticmethod
|
||||
def iff(arg: str) -> str:
|
||||
return f"If ({arg})"
|
||||
|
||||
@staticmethod
|
||||
def elsee() -> str:
|
||||
return "Else"
|
||||
|
||||
@staticmethod
|
||||
def equal(arg0: str, arg1: str) -> str:
|
||||
return f"{arg0} == {arg1}"
|
||||
|
||||
@staticmethod
|
||||
def returnn(arg: str) -> str:
|
||||
return f"Return ({arg})"
|
||||
|
||||
|
||||
class ASLSource:
|
||||
def __init__(self, revision: int = 0):
|
||||
self.lines: List[str] = []
|
||||
self.revision = revision
|
||||
self.indentation = 0
|
||||
|
||||
self.l(ASL.definition_block("DSDT", 2))
|
||||
self.block_begin()
|
||||
|
||||
def l(self, line: str) -> None:
|
||||
line = " " * (self.indentation * 4) + line
|
||||
self.lines.append(line)
|
||||
|
||||
def block_begin(self) -> None:
|
||||
self.l("{")
|
||||
self.indentation += 1
|
||||
|
||||
def block_end(self) -> None:
|
||||
self.indentation -= 1
|
||||
self.l("}\n")
|
||||
|
||||
def iff(self, arg: str) -> None:
|
||||
self.l(ASL.iff(arg) + " {")
|
||||
self.indentation += 1
|
||||
|
||||
def elsee(self) -> None:
|
||||
self.indentation -= 1
|
||||
self.l("} Else {")
|
||||
self.indentation += 1
|
||||
|
||||
def finalize(self) -> None:
|
||||
self.block_end()
|
||||
|
||||
def dump(self, path: str) -> None:
|
||||
with open(path, "w") as f:
|
||||
f.write("\n".join(self.lines))
|
||||
|
||||
def dump_as_test_case(
|
||||
self, path: str, case_name: str,
|
||||
expected_type: str, expected_value: Union[str, int]
|
||||
) -> None:
|
||||
with open(path, "w") as f:
|
||||
f.write(f"// Name: (generated) {case_name}\n")
|
||||
f.write(f"// Expect: {expected_type} => {expected_value}\n")
|
||||
f.write("\n".join(self.lines))
|
||||
|
||||
@staticmethod
|
||||
def compile(path: str, compiler: str, bin_dir: str) -> str:
|
||||
case_aml_name = os.path.basename(path).rsplit(".", 1)[0] + ".aml"
|
||||
out_case = os.path.join(bin_dir, case_aml_name)
|
||||
|
||||
ignored_warnings = [
|
||||
# Warning 3144 Method Local is set but never used
|
||||
"-vw", "3144",
|
||||
# Remark 2098 Recursive method call
|
||||
"-vw", "2098",
|
||||
|
||||
# Invalid type [Reference] found, RefOf operator requires
|
||||
# [Integer|String|Buffer|Package|FieldUnit|Device|Event|
|
||||
# Method|Mutex|Region|Power|Processor|Thermal|BufferField|
|
||||
# DdbHandle|DebugObject]
|
||||
"-vw", "6058",
|
||||
|
||||
# One or more objects within the Pathname do not exist
|
||||
"-vw", "6161",
|
||||
# Too few arguments
|
||||
"-vw", "6005",
|
||||
# Called method returns no value
|
||||
"-vw", "6080",
|
||||
# Object does not exist
|
||||
"-vw", "6084",
|
||||
|
||||
# Not a control method, cannot invoke
|
||||
"-vw", "6086",
|
||||
|
||||
# Object is not referenced
|
||||
"-vw", "2089",
|
||||
|
||||
# Creation of named objects within a method is highly inefficient
|
||||
"-vw", "2173",
|
||||
|
||||
# Existing object has invalid type for Scope operator
|
||||
"-vw", "6117",
|
||||
|
||||
# Switch expression is not a static Integer/Buffer/String data
|
||||
"-vw", "3124",
|
||||
|
||||
# Static OperationRegion should be declared outside control method
|
||||
"-vw", "3175",
|
||||
|
||||
# Missing dependency
|
||||
# (for some reason it has two different error codes)
|
||||
"-vw", "3141",
|
||||
"-vw", "6141",
|
||||
|
||||
# Field Unit extends beyond region limit
|
||||
"-vw", "6031",
|
||||
|
||||
# Name already exists in scope
|
||||
"-vw", "6074",
|
||||
|
||||
# Object not found or not accessible from current scope
|
||||
"-vw", "6085",
|
||||
|
||||
# Legacy Processor() keyword detected. Use Device() keyword instead
|
||||
"-vw", "3168",
|
||||
|
||||
# Local or Arg used outside a control method
|
||||
"-vw", "2067",
|
||||
]
|
||||
|
||||
args = [compiler, *ignored_warnings, "-oa", "-p", out_case, path]
|
||||
proc = subprocess.Popen(args, stdout=subprocess.PIPE,
|
||||
stderr=subprocess.PIPE,
|
||||
universal_newlines=True)
|
||||
|
||||
proc.wait(10)
|
||||
|
||||
stdout = proc.stdout
|
||||
assert stdout
|
||||
stderr = proc.stderr
|
||||
assert stderr
|
||||
|
||||
if proc.returncode != 0:
|
||||
raise RuntimeError(f"Compiler error:\nstdout:\n{stdout.read()}"
|
||||
f"\nstderr:\n{stderr.read()}")
|
||||
|
||||
return out_case
|
Reference in New Issue
Block a user