From 88ca60aa0ead11673dc6015fded06ea3712caf06 Mon Sep 17 00:00:00 2001 From: Sylpheed RE agent Date: Wed, 26 Aug 2026 15:22:32 +0000 Subject: [PATCH] re: the allocation failure is NOT the freeze -- two patched builds say so Rebuilt canary twice to test the freeze, and the result demotes my own headline. 1. The game does not size anything from MmQueryStatistics. Xenia reports kernel_pages = 1 MB under a comment admitting the numbers are guessed, and the game really does call the export -- sub_82612420 converts total_physical_pages and title.available_pages to bytes, and its caller holds available-bytes in r23 while creating render surfaces. Patched it to 32 MB, twice the shortfall, and rebuilt: 122 allocations, 484.5 MB ever, 379.5 MB live in 84 blocks, failing at "free 28969/131072" -- byte-identical to stock. A 32x change moved nothing. Refuted; reverted. 2. The ~19 MB the ledger could not see is Xenia's own startup reservation: memory.cc:240 pins 16 MB of the parent heap for GPU writeback before the guest runs, and vC0000000's parent IS the 512 MB physical heap. 16 MB is more than the 14.84 MB shortfall. 3. Shrinking that reservation to 1 MB removes the failure completely -- zero AllocRange failures, zero guest throws -- AND THE GAME STILL FREEZES. Verified with a single emulator after killing the stale one: three frames at rmse 0.00, an 8 MB guest slab unchanged over 3 s, 389% CPU on 3 running threads. The ledger shows it dying EARLIER, stopping at the 32 MB doubling step where stock reached 64 MB, so shrinking a live GPU region hangs the GPU instead. Reverted. So "the freeze is the refused 128 MB allocation" was too strong. The refusal is real and Xenia's 16 MB reservation is the swing factor that decides it, but the guest hangs without it too, at an earlier point. The refusal is one way this stage load dies, not the cause. Also recorded: --eh_dispatch, --mem_watch and --audio are all named in this corpus's own scripts and docs and NONE exists in this build. Each is silently rejected, which blocks boot rather than warning. --- .../data/heap-ledger-gpu-writeback-probe.txt | 183 ++++++++++++++++++ docs/re/mission-freeze-heap-exhaustion.md | 82 ++++++++ 2 files changed, 265 insertions(+) create mode 100644 docs/re/data/heap-ledger-gpu-writeback-probe.txt diff --git a/docs/re/data/heap-ledger-gpu-writeback-probe.txt b/docs/re/data/heap-ledger-gpu-writeback-probe.txt new file mode 100644 index 00000000..fea6ab4d --- /dev/null +++ b/docs/re/data/heap-ledger-gpu-writeback-probe.txt @@ -0,0 +1,183 @@ +d> F8000008 MmAllocatePhysicalMemoryEx = BC220000 Size: 03A80000 +d> F8000008 MmAllocatePhysicalMemoryEx = BC1A0000 Size: 00080000 +d> F8000008 MmAllocatePhysicalMemoryEx = B50C0000 Size: 070E0000 +d> F800002C MmFreePhysicalMemory(00000000, BE078D80) +d> F8000044 MmFreePhysicalMemory(00000000, BDB18CC0) +d> F800002C MmFreePhysicalMemory(00000000, BC79C900) +d> F800002C MmFreePhysicalMemory(00000000, BCA44980) +d> F800002C MmFreePhysicalMemory(00000000, BCD24A00) +d> F800002C MmFreePhysicalMemory(00000000, BCE24A40) +d> F800002C MmFreePhysicalMemory(00000000, BD17CAC0) +d> F800002C MmFreePhysicalMemory(00000000, BD8E0C00) +d> F800002C MmFreePhysicalMemory(00000000, BDA60C40) +d> F800002C MmFreePhysicalMemory(00000000, BDFB8D40) +d> F8000008 MmFreePhysicalMemory(00000000, BD07CA80) +d> F8000008 MmAllocatePhysicalMemoryEx = B50B0000 Size: 00010000 +d> F8000008 MmAllocatePhysicalMemoryEx = B4CB0000 Size: 00400000 +d> F8000008 MmAllocatePhysicalMemoryEx = FFCA8000 Size: 00001000 +d> F8000008 MmAllocatePhysicalMemoryEx = B4910000 Size: 003A0000 +d> F8000008 MmAllocatePhysicalMemoryEx = B4570000 Size: 003A0000 +d> F8000008 MmFreePhysicalMemory(00000001, B4560000) +d> F8000044 MmFreePhysicalMemory(00000000, BED2A080) +d> F8000008 MmAllocatePhysicalMemoryEx = B4490000 Size: 000E0000 +d> F8000008 MmAllocatePhysicalMemoryEx = B3540000 Size: 00F50000 +d> F8000044 MmFreePhysicalMemory(00000000, BF26A0C0) +d> F8000008 MmAllocatePhysicalMemoryEx = B2CB0000 Size: 00890000 +d> F8000044 MmFreePhysicalMemory(00000000, BE94CF80) +d> F8000044 MmFreePhysicalMemory(00000000, BF36A100) +d> F8000044 MmAllocatePhysicalMemoryEx = B2A10000 Size: 002A0000 +d> F8000044 MmAllocatePhysicalMemoryEx = B2770000 Size: 002A0000 +d> F8000044 MmFreePhysicalMemory(00000000, B2770000) +d> F8000044 MmFreePhysicalMemory(00000000, BE88CF40) +d> F8000044 MmAllocatePhysicalMemoryEx = B28B0000 Size: 00160000 +d> F8000044 MmAllocatePhysicalMemoryEx = B2750000 Size: 00160000 +d> F8000044 MmFreePhysicalMemory(00000000, B2750000) +d> F8000094 MmAllocatePhysicalMemoryEx = B26F0000 Size: 001C0000 +d> F8000044 MmFreePhysicalMemory(00000000, BEA7A040) +d> F8000094 MmAllocatePhysicalMemoryEx = B20C0000 Size: 00630000 +d> F8000094 MmAllocatePhysicalMemoryEx = B2070000 Size: 00050000 +d> F8000044 MmFreePhysicalMemory(00000000, BE4E8E40) +d> F8000044 MmFreePhysicalMemory(00000000, BE378DC0) +d> F8000008 MmAllocatePhysicalMemoryEx = B2000000 Size: 00070000 +d> F8000008 MmAllocatePhysicalMemoryEx = B1C30000 Size: 003D0000 +d> F8000008 MmFreePhysicalMemory(00000000, B2000000) +d> F8000008 MmAllocatePhysicalMemoryEx = B1B30000 Size: 00100000 +d> F8000008 MmFreePhysicalMemory(00000000, B1B30000) +d> F8000008 MmAllocatePhysicalMemoryEx = B1B30000 Size: 00100000 +d> F8000008 MmAllocatePhysicalMemoryEx = B1A30000 Size: 00100000 +d> F8000008 MmAllocatePhysicalMemoryEx = B1980000 Size: 000B0000 +d> F8000008 MmAllocatePhysicalMemoryEx = B2040000 Size: 00030000 +d> F8000008 MmAllocatePhysicalMemoryEx = B1890000 Size: 000F0000 +d> F8000008 MmAllocatePhysicalMemoryEx = B1840000 Size: 00050000 +d> F8000008 MmAllocatePhysicalMemoryEx = B17F0000 Size: 00050000 +d> F8000008 MmAllocatePhysicalMemoryEx = B1700000 Size: 000F0000 +d> F8000008 MmAllocatePhysicalMemoryEx = B16B0000 Size: 00050000 +d> F8000008 MmAllocatePhysicalMemoryEx = B1660000 Size: 00050000 +d> F8000008 MmAllocatePhysicalMemoryEx = B1570000 Size: 000F0000 +d> F8000008 MmAllocatePhysicalMemoryEx = B1520000 Size: 00050000 +d> F8000008 MmAllocatePhysicalMemoryEx = B14D0000 Size: 00050000 +d> F8000008 MmAllocatePhysicalMemoryEx = B0E30000 Size: 006A0000 +d> F800015C MmAllocatePhysicalMemoryEx = B0DA0000 Size: 00090000 +d> F800015C MmAllocatePhysicalMemoryEx = B0D10000 Size: 00090000 +d> F800015C MmAllocatePhysicalMemoryEx = B0C80000 Size: 00090000 +d> F800015C MmAllocatePhysicalMemoryEx = B0BF0000 Size: 00090000 +d> F800015C MmAllocatePhysicalMemoryEx = B0B60000 Size: 00090000 +d> F800015C MmAllocatePhysicalMemoryEx = B0AD0000 Size: 00090000 +d> F800015C MmAllocatePhysicalMemoryEx = B0A40000 Size: 00090000 +d> F800015C MmAllocatePhysicalMemoryEx = B09B0000 Size: 00090000 +d> F8000008 MmFreePhysicalMemory(00000000, B0E30000) +d> F8000008 MmFreePhysicalMemory(00000000, B1B30000) +d> F8000008 MmFreePhysicalMemory(00000000, B2040000) +d> F8000008 MmFreePhysicalMemory(00000000, B1980000) +d> F8000008 MmFreePhysicalMemory(00000000, B09B0000) +d> F8000008 MmFreePhysicalMemory(00000000, B0C80000) +d> F8000008 MmFreePhysicalMemory(00000000, B0A40000) +d> F8000008 MmFreePhysicalMemory(00000000, B0AD0000) +d> F8000008 MmFreePhysicalMemory(00000000, B0D10000) +d> F8000008 MmFreePhysicalMemory(00000000, B0DA0000) +d> F8000008 MmFreePhysicalMemory(00000000, B0B60000) +d> F8000008 MmFreePhysicalMemory(00000000, B0BF0000) +d> F8000008 MmFreePhysicalMemory(00000000, B1A30000) +d> F8000008 MmFreePhysicalMemory(00000000, B1890000) +d> F8000008 MmFreePhysicalMemory(00000000, B1840000) +d> F8000008 MmFreePhysicalMemory(00000000, B17F0000) +d> F8000008 MmFreePhysicalMemory(00000000, B1700000) +d> F8000008 MmFreePhysicalMemory(00000000, B16B0000) +d> F8000008 MmFreePhysicalMemory(00000000, B1660000) +d> F8000008 MmFreePhysicalMemory(00000000, B1570000) +d> F8000008 MmFreePhysicalMemory(00000000, B1520000) +d> F8000008 MmFreePhysicalMemory(00000000, B14D0000) +d> F8000008 MmFreePhysicalMemory(00000000, BE4B0E00) +d> F8000008 MmAllocatePhysicalMemoryEx = B1450000 Size: 007E0000 +d> F8000008 MmAllocatePhysicalMemoryEx = B1060000 Size: 003F0000 +d> F8000008 MmAllocatePhysicalMemoryEx = B0C70000 Size: 003F0000 +d> F8000008 MmAllocatePhysicalMemoryEx = B0970000 Size: 00300000 +d> F8000008 MmAllocatePhysicalMemoryEx = B0870000 Size: 00100000 +d> F8000008 MmAllocatePhysicalMemoryEx = B0730000 Size: 00140000 +d> F8000008 MmAllocatePhysicalMemoryEx = B0620000 Size: 00110000 +d> F8000008 MmAllocatePhysicalMemoryEx = B0590000 Size: 00090000 +d> F8000008 MmAllocatePhysicalMemoryEx = B0480000 Size: 00110000 +d> F8000008 MmAllocatePhysicalMemoryEx = B03F0000 Size: 00090000 +d> F8000008 MmAllocatePhysicalMemoryEx = B02E0000 Size: 00110000 +d> F8000008 MmAllocatePhysicalMemoryEx = B0250000 Size: 00090000 +d> F8000008 MmAllocatePhysicalMemoryEx = B0140000 Size: 00110000 +d> F8000008 MmAllocatePhysicalMemoryEx = B00B0000 Size: 00090000 +d> F8000008 MmAllocatePhysicalMemoryEx = AFDB0000 Size: 00300000 +d> F8000008 MmAllocatePhysicalMemoryEx = AFCB0000 Size: 00100000 +d> F8000008 MmAllocatePhysicalMemoryEx = AFB70000 Size: 00140000 +d> F8000008 MmAllocatePhysicalMemoryEx = AFA60000 Size: 00110000 +d> F8000008 MmAllocatePhysicalMemoryEx = AF9D0000 Size: 00090000 +d> F8000008 MmAllocatePhysicalMemoryEx = AF8C0000 Size: 00110000 +d> F8000008 MmAllocatePhysicalMemoryEx = AF830000 Size: 00090000 +d> F8000008 MmAllocatePhysicalMemoryEx = AF720000 Size: 00110000 +d> F8000008 MmAllocatePhysicalMemoryEx = AF690000 Size: 00090000 +d> F8000008 MmAllocatePhysicalMemoryEx = AF580000 Size: 00110000 +d> F8000008 MmAllocatePhysicalMemoryEx = AF4F0000 Size: 00090000 +d> F8000008 MmAllocatePhysicalMemoryEx = AF1F0000 Size: 00300000 +d> F8000008 MmAllocatePhysicalMemoryEx = AF0F0000 Size: 00100000 +d> F8000008 MmAllocatePhysicalMemoryEx = AEFB0000 Size: 00140000 +d> F8000008 MmAllocatePhysicalMemoryEx = AEEA0000 Size: 00110000 +d> F8000008 MmAllocatePhysicalMemoryEx = AEE10000 Size: 00090000 +d> F8000008 MmAllocatePhysicalMemoryEx = AED00000 Size: 00110000 +d> F8000008 MmAllocatePhysicalMemoryEx = AEC70000 Size: 00090000 +d> F8000008 MmAllocatePhysicalMemoryEx = AEB60000 Size: 00110000 +d> F8000008 MmAllocatePhysicalMemoryEx = AEAD0000 Size: 00090000 +d> F8000008 MmAllocatePhysicalMemoryEx = AE9C0000 Size: 00110000 +d> F8000008 MmAllocatePhysicalMemoryEx = AE930000 Size: 00090000 +d> F8000008 MmAllocatePhysicalMemoryEx = AE540000 Size: 003F0000 +d> F8000008 MmAllocatePhysicalMemoryEx = B2020000 Size: 00050000 +d> F8000008 MmAllocatePhysicalMemoryEx = ADE00000 Size: 00740000 +d> F8000008 MmAllocatePhysicalMemoryEx = ADD80000 Size: 00080000 +d> F8000008 MmAllocatePhysicalMemoryEx = AD640000 Size: 00740000 +d> F8000008 MmAllocatePhysicalMemoryEx = AD2A0000 Size: 003A0000 +d> F8000008 MmAllocatePhysicalMemoryEx = AD220000 Size: 00080000 +d> F8000008 MmAllocatePhysicalMemoryEx = B2010000 Size: 00010000 +d> F8000008 MmAllocatePhysicalMemoryEx = AD1D0000 Size: 00050000 +d> F8000008 MmAllocatePhysicalMemoryEx = AD180000 Size: 00050000 +d> F8000008 MmAllocatePhysicalMemoryEx = AD130000 Size: 00050000 +d> F8000008 MmAllocatePhysicalMemoryEx = B2000000 Size: 00010000 +d> F8000008 MmAllocatePhysicalMemoryEx = AD120000 Size: 00010000 +d> F8000008 MmAllocatePhysicalMemoryEx = AD0E0000 Size: 00040000 +d> F8000008 MmAllocatePhysicalMemoryEx = AD0A0000 Size: 00040000 +d> F8000008 MmAllocatePhysicalMemoryEx = AD060000 Size: 00040000 +d> F8000008 MmAllocatePhysicalMemoryEx = AD020000 Size: 00040000 +d> F8000008 MmAllocatePhysicalMemoryEx = ACFE0000 Size: 00040000 +d> F8000008 MmAllocatePhysicalMemoryEx = ACFA0000 Size: 00040000 +d> F8000008 MmAllocatePhysicalMemoryEx = ACF60000 Size: 00040000 +d> F8000008 MmAllocatePhysicalMemoryEx = ACF20000 Size: 00040000 +d> F8000008 MmAllocatePhysicalMemoryEx = ACEE0000 Size: 00040000 +d> F8000008 MmAllocatePhysicalMemoryEx = ACEA0000 Size: 00040000 +d> F8000008 MmAllocatePhysicalMemoryEx = ACE60000 Size: 00040000 +d> F8000008 MmAllocatePhysicalMemoryEx = ACE20000 Size: 00040000 +d> F8000008 MmAllocatePhysicalMemoryEx = ACD20000 Size: 00100000 +d> F8000008 MmFreePhysicalMemory(00000000, ACD20000) +d> F8000008 MmAllocatePhysicalMemoryEx = ACD20000 Size: 00100000 +d> F8000008 MmFreePhysicalMemory(00000000, ACD20000) +d> F8000008 MmAllocatePhysicalMemoryEx = ACDD0000 Size: 00050000 +d> F8000008 MmAllocatePhysicalMemoryEx = ACDC0000 Size: 00010000 +d> F8000008 MmAllocatePhysicalMemoryEx = ACCC0000 Size: 00100000 +d> F8000008 MmFreePhysicalMemory(00000000, ACCC0000) +d> F8000008 MmAllocatePhysicalMemoryEx = AC200000 Size: 00BC0000 +d> F8000008 MmAllocatePhysicalMemoryEx = ABE30000 Size: 003D0000 +d> F8000008 MmAllocatePhysicalMemoryEx = ABA60000 Size: 003D0000 +d> F8000008 MmAllocatePhysicalMemoryEx = AB690000 Size: 003D0000 +d> F8000008 MmAllocatePhysicalMemoryEx = AB2C0000 Size: 003D0000 +d> F8000008 MmFreePhysicalMemory(00000000, AC200000) +d> F8000008 MmFreePhysicalMemory(00000000, B2A10000) +d> F8000008 MmFreePhysicalMemory(00000000, BE7A8F00) +d> F8000008 MmFreePhysicalMemory(00000000, BDA98C80) +d> F8000008 MmAllocatePhysicalMemoryEx = B2C30000 Size: 00080000 +d> F8000008 MmAllocatePhysicalMemoryEx = B2B30000 Size: 00100000 +d> F8000008 MmFreePhysicalMemory(00000000, B2C30000) +d> F8000008 MmAllocatePhysicalMemoryEx = ACBC0000 Size: 00200000 +d> F8000008 MmFreePhysicalMemory(00000000, B2B30000) +d> F8000008 MmAllocatePhysicalMemoryEx = AC7C0000 Size: 00400000 +d> F8000008 MmFreePhysicalMemory(00000000, ACBC0000) +d> F8000008 MmAllocatePhysicalMemoryEx = AAAC0000 Size: 00800000 +d> F8000008 MmFreePhysicalMemory(00000000, AC7C0000) +d> F8000008 MmAllocatePhysicalMemoryEx = A9AC0000 Size: 01000000 +d> F8000008 MmFreePhysicalMemory(00000000, AAAC0000) +d> F8000008 MmAllocatePhysicalMemoryEx = A7AC0000 Size: 02000000 +d> F8000008 MmFreePhysicalMemory(00000000, A9AC0000) +d> F8000008 MmAllocatePhysicalMemoryEx = A3AC0000 Size: 04000000 +d> F8000008 MmFreePhysicalMemory(00000000, A7AC0000) diff --git a/docs/re/mission-freeze-heap-exhaustion.md b/docs/re/mission-freeze-heap-exhaustion.md index f987340b..74cfd5b4 100644 --- a/docs/re/mission-freeze-heap-exhaustion.md +++ b/docs/re/mission-freeze-heap-exhaustion.md @@ -310,3 +310,85 @@ Not fixed. The remaining candidates, in the order I would try them: be probing sizes by doubling. 3. **Reach flight another way.** The tutorial loads less; two attempts timed out before reaching it, and that is unfinished rather than refuted. + +--- + +# Two patched builds, and 🔴 the allocation failure is **not** the freeze + +**2026-08-26.** Both hypotheses about *why* the request is 128 MB, and the one +fix that removed the failure, were tested against a rebuilt canary. Result: the +oracle is still broken, and the headline above is now known to be incomplete. + +## 🔴 The game does not size anything from `MmQueryStatistics` + +`xeMmQueryStatistics` reports `kernel_pages = 0x100` — **1 MB** — under a comment +that admits *"These numbers are mostly guessed"*. A real console reserves far +more, so Xenia over-reports `title.available_pages`. The game **does** import and +call it: the only xref is `sub_82612440`, inside `sub_82612420`, which converts +`total_physical_pages` and `title.available_pages` to bytes and stores them in +its own struct; its caller keeps available-bytes in `r23` and then creates +1280×800 and 640×400 surfaces. That looked like over-reporting driving +over-allocation. + +Patched `kernel_pages` `0x100` → `0x2000` (1 MB → 32 MB, twice the shortfall) and +rebuilt: + +| | allocs | ever allocated | live at failure | failure line | +|---|---|---|---|---| +| stock (1 MB) | 122 | 484.5 MB | 379.5 MB / 84 blocks | `free 28969/131072` | +| patched (32 MB) | 122 | 484.5 MB | 379.5 MB / 84 blocks | `free 28969/131072` | + +**Byte-identical.** A 32× change in reported kernel memory changed nothing. +Refuted, and the patch was reverted. + +## ✅ The missing ~19 MB is Xenia's fixed startup reservations + +`memory.cc:240` reserves **16 MB** of the parent heap before the guest runs: + +```cpp +heaps_.vC0000000.AllocFixed(0xC0000000, 0x01000000, 32, ...); // GPU writeback +``` + +`vC0000000`'s parent **is** the 512 MB physical heap, so this comes straight off +the guest's budget — and 16 MB is larger than the 14.84 MB shortfall. That +accounts for nearly all of the 19.3 MB the ledger could not see. + +## 🔴 Shrinking it removes the allocation failure — and the game still freezes + +Patched that reservation `0x01000000` → `0x00100000` (16 MB → 1 MB) and rebuilt. +The stage load then completes with **zero** allocation failures and **zero** +`Guest attempted to throw` — the 128 MB request is gone. + +**And the game is still frozen.** Verified with one emulator running (the stale +one killed first): three frames at rmse 0.00, an 8 MB guest slab with 0 bytes +changed over 3 s, 389 % CPU across 3 running threads. + +Worse, the ledger says it froze **earlier**: the doubling sequence now stops at +**32 MB** (`A7AC0000 Size: 02000000`), where the stock build reached 64 MB before +failing at 128. Shrinking a live GPU region evidently hangs the GPU instead. The +probe was reverted. +[`data/heap-ledger-gpu-writeback-probe.txt`](data/heap-ledger-gpu-writeback-probe.txt). + +## 🔴 What this costs the earlier conclusion + +The section above says the freeze **is** the refused 128 MB allocation. That is +now **too strong**. Removing the refusal does not remove the freeze. The honest +statement is: + +* the 128 MB refusal is **real** and reproducible, and Xenia's fixed 16 MB + reservation is the swing factor that decides it; +* but the guest also hangs **without** it, at an earlier point, so the refusal is + at best *one* of the ways this stage load dies, not the single cause. + +❔ Still open, and the oracle remains unreliable: what hangs the guest when the +allocation succeeds. The stock build's `Guest attempted to throw a C++ exception!` +gave a mechanism for one path; the patched build reaches no exception at all, so +the other path needs its own diagnosis — the `log_stuck_waits` instrumentation +already on the canary branch is the obvious next tool. + +## 🔴 Three flags in this corpus's scripts do not exist in this build + +Checked with the 209-vs-67 000 byte log signature for a rejected argument: +`--eh_dispatch` (named in `newgame_path.sh` and `title-crash-stl-tree.md`), +`--mem_watch` (passed by `newgame_path.sh`), and `--audio`. All three are +silently rejected, which blocks boot entirely rather than warning.