Files
2026-10-19 18:49:31 +08:00

63 lines
3.7 KiB
Python

#!/usr/bin/env python3
"""Check real CPU registration, timer dispatch, missing-GIC refusal and 4K commpages."""
import argparse
import json
from pathlib import Path
import subprocess
import sys
ROOT = Path(__file__).resolve().parents[1]
parser = argparse.ArgumentParser(description=__doc__)
parser.add_argument('--check-existing', action='store_true')
args = parser.parse_args()
start_symbol = '__ZN6ArmCpu5startEP9IOService'
cases = {
'start': ('darwinboot-pthread-armcpu-start', ['--break-symbol', start_symbol, '--finish-function']),
'timer': ('darwinboot-armcpu-timer', ['--break-symbol', '_rtclock_intr', '--finish-function']),
'missing_gic': ('darwinboot-armcpu-missing-gic', ['--missing-gic', '--break-symbol', start_symbol, '--finish-function']),
'commpage': ('darwinboot-armcpu-bsd-commpage', ['--break-symbol', '_bsd_init', '--check-commpage']),
}
reports = {}
for name, (directory, options) in cases.items():
output = ROOT / 'build' / directory
if not args.check_existing:
subprocess.run([sys.executable, ROOT / 'scripts/probe-darwinboot-xnu.py', '--armvirt', '--armcpu',
'--require-crypto14', '--output', output, *options], check=True)
reports[name] = json.loads((output / 'gdb-stop.json').read_text())
if len({report['kernel_sha256'] for report in reports.values()}) != 1:
raise SystemExit('CPU checks must use the same kernel')
for report in reports.values():
if (not report['native_4k_mmu_observed'] or not report['crypto14_initialization_observed']
or report.get('bounded_timeout_interrupted')):
raise SystemExit('Native 4K, real crypto and reached milestones are required')
pthread = report['pthread_globals']
if (pthread['_source_pthread_status'] != 0 or not pthread['_pthread_functions']
or not pthread['_pthread519_pthread_kern']):
raise SystemExit('Real pthread registration and callback exchange are required')
for name in ('start', 'timer', 'missing_gic'):
if reports[name]['pc'] != reports[name].get('function_return_target'):
raise SystemExit(f'{name} did not return to its actual caller')
start = reports['start']
if int(start['x0'], 16) != 1:
raise SystemExit('CPU start did not return true')
for name in ('start', 'timer'):
cpu = reports[name]['armcpu_globals']
if any(cpu[key] != 1 for key in ('_armcpu_registered', '_armcpu_gic_ready', '_gCPUsRunning')):
raise SystemExit(f'{name}: real CPU/GIC initialization incomplete')
if reports['timer']['armcpu_globals']['_armcpu_timer_interrupts'] < 1:
raise SystemExit('No real timer interrupt dispatched through rtclock_intr')
bad = reports['missing_gic']
if int(bad['x0'], 16) != 0 or any(bad['armcpu_globals'].values()):
raise SystemExit('Absent GIC must reject start without registering a running CPU')
if reports['commpage']['commpage_user64_shifts'] != {'_commpage_rw_addr': 12, '_commpage_kernel_ro_addr': 12}:
raise SystemExit('Both real user64 commpage aliases must advertise native 4K')
result = {'kernel_sha256': start['kernel_sha256'], 'cpu_start_returned_true': True,
'real_pthread_registration': True, 'rtclock_intr_returned': True,
'timer_interrupts': reports['timer']['armcpu_globals']['_armcpu_timer_interrupts'],
'missing_gic_refused': True, 'native_4k_observed': True,
'legacy_and_ro_commpage_user64_shifts': [12, 12],
'ipi_delivery_verified': False, 'hardware_boot_demonstrated': False,
'ipados_userspace_boot_demonstrated': False}
(ROOT / 'build/armcpu/test-report.json').write_text(json.dumps(result, indent=2) + '\n')
print('PASS: real CPU/pthread registration, timer dispatch/return, missing-GIC refusal, native 4K commpages')