mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 02:11:36 -04:00
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:
@@ -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
|
||||
|
||||
@@ -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 */
|
||||
|
||||
Reference in New Issue
Block a user