136 lines
5.5 KiB
Python
136 lines
5.5 KiB
Python
#!/usr/bin/env python3
|
|
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
"""Conservative source/build audit for the Phase-0 non-rendering boundary."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import json
|
|
import re
|
|
from pathlib import Path
|
|
|
|
|
|
FORBIDDEN_CALLS = (
|
|
r"\bsceGnm[A-Za-z0-9_]*\s*\(",
|
|
r"\bsceVideoOutSubmitFlip\s*\(",
|
|
r"\b(mmap|mprotect|ioctl)\s*\(",
|
|
)
|
|
|
|
FORBIDDEN_TERMS = (
|
|
"MMIO",
|
|
"SCE_PROSPERO_SDK_DIR", # should exist only in the external SDK, not project code
|
|
"smu_",
|
|
"fan_control",
|
|
"clock_boost",
|
|
)
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--root", type=Path, required=True)
|
|
args = parser.parse_args()
|
|
root = args.root.resolve()
|
|
errors: list[str] = []
|
|
|
|
phase0_sources = (
|
|
sorted((root / "src").rglob("*.c"))
|
|
+ sorted((root / "adapters").rglob("*.c"))
|
|
+ sorted((root / "samples/capability_probe").rglob("*.c"))
|
|
)
|
|
all_sources = phase0_sources + sorted(
|
|
(root / "samples/phase1_videoout_clear").rglob("*.c")
|
|
)
|
|
combined = "\n".join(path.read_text(encoding="utf-8") for path in all_sources)
|
|
|
|
for pattern in FORBIDDEN_CALLS:
|
|
if re.search(pattern, combined):
|
|
errors.append(f"forbidden Phase-0 call expression matched: {pattern}")
|
|
for term in FORBIDDEN_TERMS:
|
|
if term.lower() in combined.lower():
|
|
errors.append(f"forbidden Phase-0 implementation term: {term}")
|
|
|
|
platform = (root / "src/backends/ps5/probe_platform.c").read_text(encoding="utf-8")
|
|
if platform.count("dlsym(") != 1:
|
|
errors.append("PS5 loader must contain exactly one dlsym call site")
|
|
if "address = dlsym(" not in platform or "address = NULL;" not in platform:
|
|
errors.append("resolved address must be local and explicitly discarded")
|
|
if re.search(r"\([^\n;]*\(\s*\*[^)]*\)\s*\)\s*dlsym", platform):
|
|
errors.append("dlsym result is cast to a callable function pointer")
|
|
if "fprintf" in platform or "%p" in combined:
|
|
errors.append("platform shim must not log addresses or loader details")
|
|
|
|
cmake = (root / "CMakeLists.txt").read_text(encoding="utf-8")
|
|
for term in ("prospero-deploy", "PS5_HOST", "PS5_PORT", "add_custom_target(deploy",
|
|
"add_custom_target(upload", "add_custom_target(run"):
|
|
if term.lower() in cmake.lower():
|
|
errors.append(f"deployment behavior in build graph: {term}")
|
|
if 'set(CHIMERA_GFX_PS5_ALLOWED_FIRMWARE "NONE"' not in cmake:
|
|
errors.append("default firmware gate is not NONE")
|
|
if 'option(CHIMERA_GFX_BUILD_PHASE1_VIDEOOUT_CLEAR' not in cmake:
|
|
errors.append("Phase-1 candidate does not have an explicit build gate")
|
|
if 'option(CHIMERA_GFX_BUILD_PS5_MINIMAL_STARTUP' not in cmake:
|
|
errors.append("Phase-0.5 minimal startup lacks an explicit build gate")
|
|
if "no minimal PS5 ELF may be built" not in cmake:
|
|
errors.append("Phase-0.5 minimal startup is not explicitly blocked")
|
|
|
|
phase1 = (root / "samples/phase1_videoout_clear/main.c").read_text(
|
|
encoding="utf-8"
|
|
)
|
|
gate_position = phase1.find("if (!chimera_gfx_firmware_gate_allows(")
|
|
init_position = phase1.find("SDL_Init(SDL_INIT_VIDEO)")
|
|
present_position = phase1.find("SDL_UpdateWindowSurface(window)")
|
|
if min(gate_position, init_position, present_position) < 0:
|
|
errors.append("Phase-1 source is missing its reviewed gate/init/present sequence")
|
|
elif not gate_position < init_position < present_position:
|
|
errors.append("Phase-1 firmware gate must precede SDL init and present")
|
|
if "SDL2main" in cmake:
|
|
errors.append("Phase-1 target must not link the pre-gate SDL2main wrapper")
|
|
if any((root / "samples/clear_screen").rglob("*.c")):
|
|
errors.append("legacy clear-screen placeholder unexpectedly contains source")
|
|
|
|
compatibility = (root / "FIRMWARE_COMPATIBILITY.md").read_text(encoding="utf-8")
|
|
if "| _none_ |" not in compatibility or "| `9.60` |" not in compatibility:
|
|
errors.append("firmware compatibility table lacks NONE or exact 9.60 rows")
|
|
if '"firmware_allowlist": ["9.60"]' not in (
|
|
root / "manifests/ps5_gnm_symbols.json"
|
|
).read_text(encoding="utf-8"):
|
|
errors.append("discovery-only firmware allowlist is not exactly 9.60")
|
|
|
|
denylist = json.loads(
|
|
(root / "manifests/artifact-denylist.json").read_text(encoding="utf-8")
|
|
)
|
|
blocked_hash = (
|
|
"4be1c17b4964f2b68c39b5145bc4af4619c32512d60269ecf5c39728b390fa63"
|
|
)
|
|
entries = denylist.get("entries", [])
|
|
if len(entries) != 1 or entries[0].get("sha256") != blocked_hash:
|
|
errors.append("permanent firmware-9.60 artifact denial is absent")
|
|
elif (
|
|
entries[0].get("permanent") is not True
|
|
or entries[0].get("execution_eligible") is not False
|
|
):
|
|
errors.append("firmware-9.60 artifact denial is not permanent and ineligible")
|
|
|
|
artifact_manifest = json.loads(
|
|
(
|
|
root
|
|
/ "manifests/artifacts/chimera-gfx-capability-probe-0.1.0-fw-9.60.json"
|
|
).read_text(encoding="utf-8")
|
|
)
|
|
if artifact_manifest["execution"].get("execution_eligible") is not False:
|
|
errors.append("firmware-9.60 artifact manifest is not execution-ineligible")
|
|
|
|
if errors:
|
|
for error in errors:
|
|
print(f"safety audit failed: {error}")
|
|
return 1
|
|
print(
|
|
f"Phase-0/disabled-Phase-1 safety audit passed across "
|
|
f"{len(all_sources)} C source files"
|
|
)
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
raise SystemExit(main())
|