import json from pathlib import Path import subprocess import sys import tempfile scope = Path(sys.argv[1]).resolve() disk = Path(sys.argv[2]).resolve() with tempfile.TemporaryDirectory(prefix="scopeguest") as directory: root = Path(directory) transcript = root / "transcript" command = [ "qemu-system-x86_64", "-machine", "pc,accel=tcg", "-cpu", "max", "-m", "32M", "-display", "none", "-serial", "none", "-monitor", "none", "-no-reboot", "-drive", f"format=raw,file={disk}", "-debugcon", f"file:{transcript}", "-device", "isa-debug-exit,iobase=0xf4,iosize=0x04", ] try: result = subprocess.run(command, capture_output=True, text=True, timeout=45) except subprocess.TimeoutExpired: print(transcript.read_text()[-2000:] if transcript.exists() else "no guest output", file=sys.stderr) raise assert result.returncode == 33, (result.returncode, result.stderr, transcript.read_text()[-2000:]) lines = transcript.read_text().splitlines() assert lines[-1] == "done", "guest did not finish" current = None checks = 0 discrepancies = 0 for line in lines: if line.startswith("begin "): _, name, access, address, privilege = line.split() current = [] elif line.startswith("context ") or line.startswith("page "): assert current is not None current.append(line) elif line.startswith("observed "): _, vector, error = line.split() observed = int(vector), int(error) elif line == "end": assert current is not None source = root / "source" capture = root / "capture" source.write_text("\n".join(current) + "\n") subprocess.run([str(scope), "import", str(source), str(capture), "--source", f"qemu guest case {name}"], check=True, capture_output=True, text=True) result = subprocess.run([str(scope), "explain", str(capture), address, "--access", ["read", "write", "execute"][int(access)], "--privilege", privilege, "--json"], capture_output=True, text=True, timeout=10) assert result.returncode in (0, 1), (name, result.stderr) prediction = json.loads(result.stdout)["result"] if prediction["status"] == "mapped": predicted = 0, 0 else: predicted = prediction["fault"]["vector"], prediction["fault"]["error_code"] if observed != predicted: known = name in {"reserved", "nxe", "alignment", "pml"} and observed == (14, predicted[1] & ~1) and predicted == (14, 9) assert known, (name, "observed", observed, "predicted", predicted, prediction) discrepancies += 1 print(f"{name}: known tcg discrepancy, observed=0x{observed[1]:x} architectural=0x{predicted[1]:x}") else: print(f"{name}: vector={observed[0]} error=0x{observed[1]:x}") checks += 1 current = None assert checks == 31, checks print(f"{checks - discrepancies} exact guest comparisons, {discrepancies} reserved-bit tcg discrepancies")