mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
A tester's Namco Museum 50th Anniversary crash on an M2 iPad turned out to be memory corruption rather than anything to do with the software renderer he thought he was hitting. The store that died was a softmem write through a page table entry whose high word had gone from 1 to 2. ProtMode_Manual is 2, it is a u32, and it lives at offset four of an eight byte record, so something had written a protection mode over the top half of a vtlbdata.pmap pointer. It comes from the fastmem branch of HandlePageFault. PSM resolves the whole physical map rather than just main RAM, so a fault on VU memory arrives here with an offset far past the end of m_PageProtectInfo, which is a fixed 8192 entries. Nothing checked that. The read alone is out of bounds, and when the aliased value happens to equal ProtMode_Write the handler carries on into mmap_ClearCpuBlock and writes. The branch twenty lines below has always had the bound check; this one never did, and now does the same thing. Nothing real is suppressed by it. Anything PSM resolves outside main RAM is ROM or VU memory, neither of which is ever under EE write protection, so the right answer for those faults is the else branch that was already there, handing them to the backpatcher. mmap_MarkCountedRamPage had the same unbounded index and a signed int on top of it, which went negative and indexed backwards whenever the pointer landed below Main. Clang has been warning about that conversion the whole time. Bounded the same way as mmap_GetRamPageInfo, and the warning goes with it. No caller reaches either case today since they all come through mmap_GetRamPageInfo first, so that half is closing a trap rather than fixing live breakage. A lot had to line up, which is why it lasted this long. 16K pages mean VU0 memory can never be folded into fastmem so it faults on every touch, the arena base makes the aliased half read as exactly ProtMode_Write so the guard passes because of what it is corrupting, and the game has to touch VU0 memory from the EE and then reprogram the TLB to spread the poisoned entry around. It writes once and stops, so it leaves nothing behind in the log.