mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 18:25:35 -04:00
60919f5a87
Bundled releases link OpenBIOS only; retail-BIOS-derived C never ships.
"Bring your own BIOS" now works without it: when a dump matching a shipped
profile (psx_bios_known_images.h) is selected, the runtime builds that
backend on the player's machine with the overlay toolchain the release
already carries, caches it, and loads it as one more registered backend.
- runtime/include/psx_bios_module.h: the module contract. An overlay-style
self-contained shared library (no imports from the executable) exporting
psx_bios_module_{abi,codegen_hash,init,backend}; reaches the runtime only
through OverlayCallbacks plus a new PsxBiosModuleCallbacks table (traps,
dirty-RAM/kernel-bless probes, fntrace, log_probe) and pointer aliases of
the globals the generated dispatcher touches. Its #defines rewrite the
emitter's own extern lines, so the generated C compiles unchanged.
- runtime/include/psx_bios_module_glue.c.inc: module-side forwarders and the
four exports, compiled after overlay_dispatch_preamble.c.inc.
- runtime/src/psx_bios_module.c: host side. Cache path
<exe>/cache/bios/<os-arch>/bm<abi>_<codegen hash>_f<flavor>/<STEM>_<crc>,
ABI + codegen-hash gated load, callback fill, and a blocking build via
overlay_toolchain/bios_module_build.py (gcc via compiler.txt or PATH,
else tcc), then psx_bios_register().
- psx_bios_backend.c: the registry is now a mutable table seeded from the
CMake-generated psx_bios_builtin_registry by a constructor, with
psx_bios_register(); every existing walker keeps working.
- main.cpp: validate_bios_for_launch acquires a module (announcing a first
build) before declaring a mismatch; discovery accepts a buildable dump;
the launcher verify reports it usable ("ready" / "compiled on first
launch") with no Generate & rebuild; the BIOS row shows whenever the
toolchain is present; bundled_only respects module support.
- emitter: the CPS-marker constructor is not emitted in a module build.
- overlay_api.h: OverlayCallbacks gains a struct tag;
overlay_loader_callbacks() exposes the host table before loader init.
- tools/bios_module_build.py (ships in the toolchain): identity + profile
SHA-256 gate, staged emitter tree, emit, three-TU compile, ctypes
self-check, atomic publish. release_stage.py stages psxrecomp-bios, every
bios/*.toml, the seeds and the builder into overlay_toolchain/.
- Tests: runtime/tests/test_bios_module_host.c against three fake modules
(good / wrong ABI / wrong hash) on real dlopen; recompiler/tests/
test_bios_module_build.py builds the bundled OpenBIOS end to end and reads
the descriptor back; guards extended.
Verified on Twisted Metal 4 (bundled build + staged toolchain, headless):
first launch with --bios SCPH1001.BIN builds and loads the module and boots
on image=SCPH-1001; the second launch loads it from cache.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
56 lines
2.8 KiB
Python
56 lines
2.8 KiB
Python
#!/usr/bin/env python3
|
|
"""Guard bundled-only BIOS selection against stale hidden player paths."""
|
|
|
|
from pathlib import Path
|
|
|
|
|
|
ROOT = Path(__file__).resolve().parents[2]
|
|
MAIN = (ROOT / "runtime" / "src" / "main.cpp").read_text(encoding="utf-8")
|
|
|
|
# A bundled-only product must bypass both explicit and cached player paths
|
|
# before validate_bios_for_launch can produce an impossible mismatch dialog.
|
|
assert "const bool bundled_only =" in MAIN
|
|
assert "if (!bundled_only) {" in MAIN
|
|
assert MAIN.index("if (!bundled_only) {") < MAIN.index(
|
|
"if (!chosen.empty() && std::filesystem::exists(chosen))"
|
|
)
|
|
|
|
# The launcher must derive persistence from linked capabilities, not from the
|
|
# active image: psx_bios_image is deliberately zeroed until selection occurs.
|
|
assert "const bool bios_choice_supported =" in MAIN
|
|
assert "if (bios_choice_supported && ls.bios_path[0])" in MAIN
|
|
assert "ls.bios_path[0] && !psx_bios_image.image_bundled" not in MAIN
|
|
|
|
# A shipped bundled build links OpenBIOS only and carries no CLI, sources or
|
|
# toolchain. Its BIOS row must not be forced on, and a retail pick must not be
|
|
# answered with "Generate & rebuild": that offer is only real when the codegen
|
|
# host wired Generate (prepare_with_progress) or nothing is linked yet.
|
|
HOST = (ROOT / "host" / "psxrecomp_codegen_host.c").read_text(encoding="utf-8")
|
|
assert "gi->has_bios = 1;" not in HOST
|
|
assert MAIN.count("gi.has_bios = 1;") == 0
|
|
assert MAIN.count("g_lnch_can_regen = gi.prepare_with_progress != nullptr") == 2
|
|
assert MAIN.count("gi.has_bios = (psx_bios_has_selectable() || g_lnch_can_regen ||") == 2
|
|
assert "if (g_lnch_can_regen) {" in MAIN
|
|
assert MAIN.index("if (g_lnch_can_regen) {") < MAIN.index(
|
|
'"Generate & rebuild to switch (or use OpenBIOS)."')
|
|
assert "cannot be selected. Clear the BIOS field to play." in MAIN
|
|
|
|
# Loadable BIOS backends (psx_bios_module.h): a bundled build with the
|
|
# toolchain beside it can BUILD a retail backend from the player's dump, so a
|
|
# player choice is meaningful there, discovery accepts a known dump, and the
|
|
# launcher verify reports the dump usable without offering Generate & rebuild.
|
|
assert "psx_bios_module_acquire(" in MAIN
|
|
assert "psx_bios_module_is_cached(" in MAIN
|
|
assert "psx_bios_has_selectable() != 0 || bios_module_supported_here();" in MAIN
|
|
assert MAIN.count("psx_bios_module_supported(") >= 4
|
|
assert "Preparing your BIOS" in MAIN
|
|
# The registry is mutable and seeded from the builtins before main().
|
|
BACKEND = (ROOT / "runtime" / "src" / "psx_bios_backend.c").read_text(encoding="utf-8")
|
|
assert "int psx_bios_register(const PsxBiosBackend *backend)" in BACKEND
|
|
assert "psx_bios_registry_ctor" in BACKEND
|
|
CMAKE = (ROOT / "runtime" / "runtime.cmake").read_text(encoding="utf-8")
|
|
assert "psx_bios_builtin_registry[]" in CMAKE
|
|
assert "psx_bios_module.c" in CMAKE
|
|
|
|
print("BIOS selection capability guards passed")
|