Files
UniXNU/scripts/check-smmu4k-live.py

140 lines
7.7 KiB
Python

#!/usr/bin/env python3
"""Bounded host qualification of real native4K leaf updates; no device access."""
import hashlib
import json
import re
import struct
import subprocess
import sys
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT / 'kits/XnuPrelink'))
from native_prelink import macho
kit = ROOT / 'kits/ArmSmmu4K'
out = ROOT / 'build/arm-smmu-4k-live'
out.mkdir(parents=True, exist_ok=True)
(out / 'report.json').unlink(missing_ok=True)
def sha(path):
return hashlib.sha256(path.read_bytes()).hexdigest()
# This existing checker extracts the actual pinned Linux descriptor algorithm
# into ignored build storage. Its source validation and oracle are reused,
# rather than committing a copy of the GPL source or our own expected bits.
subprocess.run([sys.executable, ROOT / 'scripts/check-smmu4k-permissions.py'],
check=True, timeout=60)
permission_out = ROOT / 'build/arm-smmu-4k-permissions'
permission_report = json.loads((permission_out / 'report.json').read_text())
oracle = permission_out / 'original-permissions.c'
if sha(oracle) != permission_report['oracle_sha256']:
raise SystemExit('Original descriptor oracle identity differs')
sources = [kit / (name + '.c') for name in
['ArmSmmu4KContext', 'ArmSmmu4KProgram', 'ArmSmmu4KLive', 'ArmSmmu4KStreams']]
test = out / 'test-live'
subprocess.run(['xcrun', 'clang', '-std=c11', '-O2', '-Wall', '-Wextra',
'-Werror', '-fsanitize=address,undefined', *sources,
kit / 'test_live.c', oracle, '-o', test], check=True, timeout=60)
host = subprocess.run([test], check=True, capture_output=True, text=True, timeout=60)
print(host.stdout, end='')
counts = re.search(r'(\d+) native4K lower/upper mapping profiles, (\d+) I/O/cache/timeout/mutation failures, (\d+) physical graph mutations', host.stdout)
if not counts or int(counts[1]) != 3264:
raise SystemExit('Expected independent profile coverage absent')
pairs = re.search(r'(\d+) dual-region native4K profiles and (\d+) dual-region failure/alias/isolation controls', host.stdout)
if not pairs or tuple(map(int,pairs.groups())) != (1632,342):
raise SystemExit('Expected dual-region coverage absent')
batches = re.search(r'(\d+) batched scattered-page map/unmap transactions', host.stdout)
if not batches or int(batches[1]) != 185:
raise SystemExit('Expected batched update coverage absent')
if not re.search(r'PASS: 6 on-demand table controls', host.stdout):
raise SystemExit('Expected on-demand table coverage absent')
alias_test = out / 'test-alias'
subprocess.run(['xcrun', 'clang', '-std=c11', '-O2', '-Wall', '-Wextra', '-Werror', '-fsanitize=address,undefined',
'-DARM_SMMU4K_TEST_COVERAGE', '-fsanitize-coverage=trace-pc-guard',
'-I', kit, kit / 'test_alias.c', *[s for s in sources if s.stem != 'ArmSmmu4KLive'], '-o', alias_test], check=True, timeout=60)
alias = subprocess.run([alias_test], check=True, capture_output=True, text=True, timeout=120)
print(alias.stdout, end='')
if not re.search(r'PASS: 15000 sorted alias checks', alias.stdout):
raise SystemExit('Expected sorted alias coverage absent')
if 'PASS: mixed-size alias gap/long-range controls and bounded compiler-coverage work' not in alias.stdout:
raise SystemExit('Expected bounded mixed-size alias controls absent')
(out / 'host.log').write_text(host.stdout + alias.stdout)
flags = ['-target', 'arm64-apple-ios17.0', '-O2', '-Wall', '-Wextra', '-Werror',
'-Wno-incompatible-sysroot', '-ffreestanding', '-mgeneral-regs-only']
objects = []
imports = {}
provided = set()
for source in sources:
obj = out / (source.stem + '.o')
subprocess.run(['xcrun', 'clang', *flags, '-std=c11', '-c', source, '-o', obj],
check=True, timeout=30)
raw = obj.read_bytes()
info = macho(raw)
version = next(at for command, at, _ in info['commands'] if command == 0x32)
if (struct.unpack_from('<4I', raw) != (0xfeedfacf, 0x100000c, 0, 1)
or struct.unpack_from('<II', raw, version + 8) != (2, 0x110000)):
raise SystemExit('Ordinary ARM64 subtype0 / iOS17 object required')
imports[obj.name] = subprocess.check_output(['xcrun', 'nm', '-u', obj], text=True).split()
provided.update(line.split()[-1] for line in subprocess.check_output(
['xcrun', 'nm', '-gU', obj], text=True).splitlines() if line.split())
objects.append(obj)
analysis = subprocess.run(['xcrun', 'clang', *flags, '-std=c11', '--analyze',
'-Xanalyzer', '-analyzer-output=text', source,
'-o', out / (source.stem + '.plist')],
check=True, capture_output=True, text=True, timeout=30)
if analysis.stderr.strip():
raise SystemExit('Static analysis diagnostic: ' + analysis.stderr)
unexpected = set(sum(imports.values(), [])) - provided - {
'___stack_chk_fail', '___stack_chk_guard', '_memcpy', '_memset'}
if unexpected:
raise SystemExit('Unexpected runtime imports: ' + repr(unexpected))
boundary = out / 'boundary.cpp'
boundary.write_text('''#include "ArmSmmu4KLive.h"
extern "C" ArmSmmu4KStatus live_boundary(const ArmSmmu4KLiveArena *arena,
ArmSmmu4KLiveState *state,const ArmSmmu4KIo *io,unsigned bank,
const ArmSmmu4KContextConfig *context,const ArmSmmu4KLiveVisibility *visibility,
const ArmSmmu4KRange *before,size_t count,const ArmSmmu4KRange *change,
unsigned map,ArmSmmu4KLiveResult *result) {
return ArmSmmu4KLiveUpdate(arena,state,io,bank,context,visibility,before,count,change,map,1000,result);
}
''')
consumer = out / 'boundary.o'
subprocess.run(['xcrun', 'clang++', *flags, '-std=c++17', '-I', kit, '-c',
boundary, '-o', consumer], check=True, timeout=30)
boundary_imports = set(subprocess.check_output(['xcrun', 'nm', '-u', consumer], text=True).split())
if boundary_imports - {'___stack_chk_fail', '___stack_chk_guard'} != {'_ArmSmmu4KLiveUpdate'}:
raise SystemExit('Actual native C++/C boundary differs')
archive = out / 'libArmSmmu4KLive.a'
subprocess.run(['xcrun', 'ar', 'rcs', archive, *objects], check=True, timeout=30)
assembly = out / 'ArmSmmu4KLive.s'
subprocess.run(['xcrun', 'clang', *flags, '-std=c11', '-S', kit / 'ArmSmmu4KLive.c', '-o', assembly],
check=True, timeout=30)
asm = assembly.read_text()
if not re.search(r'\bstr\s+x\d+,\s*\[', asm) or not re.search(r'\bldr\s+x\d+,\s*\[', asm):
raise SystemExit('Actual aligned native descriptor loads/stores absent')
report = dict(
passed=True, checker_sha256=sha(Path(__file__)),
linux_revision=permission_report['linux_revision'],
pinned_sources=permission_report['pinned_sources'], oracle_sha256=sha(oracle),
sources={str(p.relative_to(ROOT)): sha(p) for p in
[*sources, *[s.with_suffix('.h') for s in sources],
kit / 'ArmSmmu4K.h', kit / 'test_live.c']},
host_profiles=int(counts[1]), host_failure_controls=int(counts[2]),
host_descriptor_mutations=int(counts[3]), host_asan_ubsan=True,
dual_region_profiles=int(pairs[1]),dual_region_failure_controls=int(pairs[2]),
ordinary_arm64_ios17=True, general_registers_only=True, static_analysis_pass=True,
objects={p.name: sha(p) for p in objects}, archive_sha256=sha(archive),
undefined_imports=imports, boundary_imports=sorted(boundary_imports),
translation_granule_bytes=4096, actual_descriptor_load_store_code=True,
software_fixture_only=True, physical_table_ownership_qualified=False,
hardware_cache_visibility_qualified=False, active_gpu_context_qualified=False,
hardware_tlb_qualified=False, gpu_execution_qualified=False, gpu_fences_qualified=False)
(out / 'report.json').write_text(json.dumps(report, indent=2) + '\n')
print('PASS: direct native4K leaf updates, bounded real register synchronization, ARM64/iOS17 archive and C++ boundary; host fixtures only')