Gate snapshots by build-selected implementation identity

This commit is contained in:
Matthew Stanley
2026-10-08 16:38:45 -07:00
parent 5d7837e991
commit edb78e8391
4 changed files with 28 additions and 4 deletions
+7
View File
@@ -118,6 +118,13 @@ if(BUILD_TESTING)
target_link_options(boot_state_handoff_test PRIVATE -flto -Wl,--gc-sections)
target_link_libraries(boot_state_handoff_test PRIVATE ZLIB::ZLIB)
add_test(NAME boot_state_handoff_test COMMAND boot_state_handoff_test)
add_executable(boot_state_impl_tag_test tests/test_boot_state_handoff.c)
target_include_directories(boot_state_impl_tag_test PRIVATE include src)
target_compile_definitions(boot_state_impl_tag_test PRIVATE PSX_COSIM=1 PSX_SAVESTATE_IMPL_TAG=0x54474801u)
target_compile_options(boot_state_impl_tag_test PRIVATE -O2 -flto -ffunction-sections -fdata-sections -UNDEBUG)
target_link_options(boot_state_impl_tag_test PRIVATE -flto -Wl,--gc-sections)
target_link_libraries(boot_state_impl_tag_test PRIVATE ZLIB::ZLIB)
add_test(NAME boot_state_impl_tag_test COMMAND boot_state_impl_tag_test)
add_executable(static_match_cache_test tests/test_static_match_cache.c
src/overlay_loader.c src/crc32.c)
+1 -1
View File
@@ -66,7 +66,7 @@ typedef struct {
uint32_t entry_pc; /* game PS-EXE entry PC */
uint32_t codegen_hash; /* PSX_OVERLAY_CODEGEN_HASH (auto-gen by cmake) */
int32_t abi_tag; /* PSX_OVERLAY_ABI_TAG (abi version | flavor<<16) */
uint32_t codegen_ver; /* PSX_OVERLAY_CODEGEN_VER */
uint32_t codegen_ver; /* codegen version XOR build PSX_SAVESTATE_IMPL_TAG */
/* ---- layout ---- */
uint32_t section_count; /* number of sections that follow */
uint32_t reserved; /* v8: enhancement-memory layout cookie; vanilla 0 */
+10 -3
View File
@@ -2,6 +2,13 @@
#include "fntrace.h"
#include "mod_memory.h"
#include "overlay_api.h" /* PSX_OVERLAY_CODEGEN_HASH / _ABI_TAG / _CODEGEN_VER */
/* Build-selected HLE may use private execution boundaries. Zero preserves
* the existing snapshot key for titles that do not select an implementation. */
#ifndef PSX_SAVESTATE_IMPL_TAG
#define PSX_SAVESTATE_IMPL_TAG 0u
#endif
#define BOOT_STATE_IMPLEMENTATION_KEY ((uint32_t)PSX_OVERLAY_CODEGEN_VER ^ (uint32_t)PSX_SAVESTATE_IMPL_TAG)
#include "dirty_ram_interp.h"
#include "gpu.h" /* gpu_get_vram — CPU-auth mirror under dual-raster */
#include "gpu_render.h" /* gr_vram_transfer_in / gr_vram_transfer_out */
@@ -390,7 +397,7 @@ static int boot_state_save_to(BsOut* o, const CPUState* cpu,
h.entry_pc = entry_pc;
h.codegen_hash = (uint32_t)PSX_OVERLAY_CODEGEN_HASH;
h.abi_tag = (int32_t)PSX_OVERLAY_ABI_TAG;
h.codegen_ver = (uint32_t)PSX_OVERLAY_CODEGEN_VER;
h.codegen_ver = BOOT_STATE_IMPLEMENTATION_KEY;
h.section_count = 17 + (psx_mod_memory_snapshot_bytes() ? 1u : 0u);
ok = write_header_le(o, &h);
@@ -870,9 +877,9 @@ int boot_state_check_buffer(const uint8_t* file, size_t file_len,
(int)h.abi_tag, (int)PSX_OVERLAY_ABI_TAG);
boot_state_append_reason(reason, reason_cap, part);
}
if (h.codegen_ver != (uint32_t)PSX_OVERLAY_CODEGEN_VER) {
if (h.codegen_ver != BOOT_STATE_IMPLEMENTATION_KEY) {
snprintf(part, sizeof(part), "codegen_ver=%u(want %u)",
(unsigned)h.codegen_ver, (unsigned)PSX_OVERLAY_CODEGEN_VER);
(unsigned)h.codegen_ver, (unsigned)BOOT_STATE_IMPLEMENTATION_KEY);
boot_state_append_reason(reason, reason_cap, part);
}
+10
View File
@@ -68,6 +68,16 @@ int main(void) {
/* Malformed, missing and duplicate phase sections must reject before
* changing CPU, RAM or the previously active handoff latch. */
cpu.pc=0xdeadbeef; ram[0x100]=0x55; fntrace_restore_game_started(!started);
/* A different build-selected implementation must reject atomically,
* including when its only difference is an HLE execution boundary. */
PstR key_reader; uint32_t implementation_key;
pst_r_init(&key_reader, saved + 24, 4);
assert(pst_r_u32(&key_reader, &implementation_key));
assert(implementation_key == BOOT_STATE_IMPLEMENTATION_KEY);
u32(saved + 24, implementation_key ^ 0x54474801u);
assert(!boot_state_load_buffer(saved,len,123,0x801b0000,&cpu));
assert(cpu.pc==0xdeadbeef && ram[0x100]==0x55 && fntrace_is_game_started()==!started);
u32(saved + 24, implementation_key);
saved[len-4]=2;
assert(!boot_state_load_buffer(saved,len,123,0x801b0000,&cpu));
saved[len-4]=started;