runtime: fix boot freeze from overlay-loader init race + discovery gap

Two deterministic boot hangs (WWF SmackDown! 2, SLUS-01234):

1. overlay_loader_dispatch()/is_candidate()/call_native() ran during
   early BIOS kernel init (0xBFC0DB10 memcard polling loop) before
   overlay_loader_init() built the range-index structures, walking
   uninitialized lists until a PC=0 trap (froze at cycle 208195 every
   boot). Guard all three entry points on s_active.

2. Code at 0x800D1F28 (boot-text populated by bulk host transfer that
   bypassed the RAM write-marking hooks) was neither compiled, dirty,
   nor overlay -> unknown-dispatch fail at frame 1340. Add a fallback:
   an address above overlay_region_floor whose word decodes as valid
   MIPS is marked executable and handed to the dirty-RAM interpreter.

Validated 5/5 reproducible boots, 2000+ frame sustained runs.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Martin Penkava
2026-07-12 16:54:02 +02:00
parent df4cc5c70a
commit e6809ccf7d
2 changed files with 18 additions and 2 deletions
+14 -1
View File
@@ -279,6 +279,7 @@ extern void psx_dispatch_call(CPUState* cpu, uint32_t addr, uint32_t return_addr
/* Forward decls from memory.c — used to read instruction bytes. */
extern uint8_t *memory_get_ram_ptr(void);
extern void dirty_ram_mark_executable_range(uint32_t phys, uint32_t len);
/* MIPS instruction field decoders. */
static inline uint32_t op_field (uint32_t i) { return (i >> 26) & 0x3Fu; }
@@ -2210,7 +2211,19 @@ static int dirty_ram_dispatch_inner(CPUState* cpu, uint32_t addr, uint32_t stop_
}
#define OV_FPLOG_RET1() do { if (_ovfp) overlay_fp_log(addr, _in_regs, cpu, 0); return 1; } while (0)
if (!dirty_ram_is_dirty(phys) && !clean_game_text_miss) return 0;
if (!dirty_ram_is_dirty(phys) && !clean_game_text_miss) {
/* Some games populate post-EXE overlays through bulk host transfers that
* do not pass through the normal RAM write hooks. A real control transfer
* to decodable code above the configured boot-EXE text end is sufficient
* evidence that the page is executable; mark it so local overlay flow can
* remain in the interpreter. Invalid/data targets still fail dispatch. */
if (phys < (2u * 1024u * 1024u) && phys >= g_overlay_region_floor &&
dirty_ram_word_looks_decodable(fetch_word(phys))) {
dirty_ram_mark_executable_range(phys, 4u);
} else {
return 0;
}
}
/* Interp-pressure signal for variant-capture automation (step 2.8):
* counts dispatches the interpreter actually handles inside a capture
+4 -1
View File
@@ -2298,6 +2298,7 @@ static int overlay_find_by_range(uint32_t phys) {
int overlay_loader_dispatch(CPUState *cpu, uint32_t addr) {
uint32_t phys = addr & 0x1FFFFFFFu;
if (!s_active) return 0;
int lazy_loaded = 0;
retry_candidates:
int head = idx_head(phys);
@@ -2791,6 +2792,7 @@ static FpEnt s_fp[FP_CAP];
static uint64_t s_fp_seq = 0;
int overlay_loader_is_candidate(uint32_t phys) {
if (!s_active) return 0;
phys &= 0x1FFFFFFFu;
return idx_head(phys) >= 0 || lazy_has_exact_entry(phys);
}
@@ -3137,7 +3139,8 @@ void overlay_fp_log(uint32_t addr, const uint32_t *in_regs,
* leaks (root cause of the dwarf->overworld native blue screen).
* Returns 1 iff a native candidate ran. */
int overlay_loader_call_native(CPUState *cpu, uint32_t addr) {
if (!s_native_exec) return 0; /* interp mode: keep the legacy inline path */
if (!s_active || !s_native_exec)
return 0; /* inactive/interp mode: keep the legacy inline path */
uint32_t phys = addr & 0x1FFFFFFFu;
if (idx_head(phys) < 0 && !lazy_has_exact_entry(phys))
return 0; /* neither a registered nor an exact cached entry */