diff --git a/docs/re/BACKLOG.md b/docs/re/BACKLOG.md index 7b555fe5..8b96969c 100644 --- a/docs/re/BACKLOG.md +++ b/docs/re/BACKLOG.md @@ -6,6 +6,18 @@ unknown, what evidence exists, and what the first step would be. Move an item in --- +## ✅✅ SOLVED — the mission freeze was a modal sign-in dialog (2026-08-26) + +`XamShowSigninUI` opens a modal dialog and `xeXamDispatchDialog` blocks the +calling guest thread on `fence.Wait()` until it is dismissed — which nothing in a +scripted run ever does. **Fix: pass `--logged_profile_slot_0_xuid=…`.** Same +route, one variable: screen id goes from stuck at **4 forever** to +**4 → 5 → 6 → 8 → 9 → 10**, allocation failures 1 → **0**, guest throws 1 → **0**, +guest churn 0.000 % → **1.006 %**. +It hid for so long because `--log_mask=13` (used by every script here) +**disables kernel logging**, the one category that names the dialog. +See [`mission-freeze-signin-dialog.md`](mission-freeze-signin-dialog.md). + ## 🔴 ~~BLOCKER — the mission freeze is a software-rendering hang~~ WITHDRAWN (2026-08-26) > **Withdrawn the same day.** Driving the null backend blind to the *same* screen diff --git a/docs/re/mission-freeze-signin-dialog.md b/docs/re/mission-freeze-signin-dialog.md new file mode 100644 index 00000000..32d819bf --- /dev/null +++ b/docs/re/mission-freeze-signin-dialog.md @@ -0,0 +1,69 @@ +# ✅✅ The freeze is `XamShowSigninUI` — a modal dialog nobody can dismiss + +**Root-caused 2026-08-26**, after a long chain of wrong answers recorded in +[`mission-freeze-heap-exhaustion.md`](mission-freeze-heap-exhaustion.md). + +## The mechanism, from Xenia's source + +Every Xam UI dialog goes through `xeXamDispatchDialog` (`xam_ui.cc:60`), and the +calling **guest thread blocks**: + +```cpp +xe::threading::Fence fence; +if (app_context.CallInUIThreadSynchronous( + [&dialog, &fence]() { dialog->Then(&fence); })) { + fence.Wait(); // <- the guest thread stops here until dismissed +``` + +With kernel logging enabled (`--log_mask=0`; note **`log_mask` disables** +categories, so the `--log_mask=13` used throughout this corpus hides exactly +this), the last kernel call before the freeze is: + + d> F8000008 XamShowSigninUI(00000001, 00000001) + +The game asks for a signed-in profile, Xenia opens a modal sign-in dialog, and +the guest waits on the fence **forever** — nothing in a scripted run dismisses an +ImGui dialog. + +That accounts for every symptom at once: `Main XThread` **futex-blocked at 0 ms +CPU** rather than spinning; the emulator alive and healthy; no guest progress; no +faults; and independence from both the GPU backend and the allocation outcome. + +## ✅ The fix, and the before/after + +`run-canary` accepts `--logged_profile_slot_0_xuid=B13EBABEBABEBABE`. Same route, +same inputs, one variable changed: + +| | without a profile | **with `--logged_profile_slot_0_xuid`** | +|---|---|---| +| screen id reached | **4, forever** | **4 → 5 → 6 → 8 → 9 → 10** | +| `XamShowSigninUI` | **called** | not called | +| allocation failures | 1 | **0** | +| guest throws | 1 | **0** | +| guest churn | 0.000 % (19 B of 8 MB) | **1.006 %** (81 KB of 8 MB) | + +The game walks through six further screens where it previously sat at one +forever. `XamShowDeviceSelectorUI` is then requested, but +`storage_selection_dialog` defaults to **false**, so that dialog is not shown and +does not block. + +## 🔴 Why this took so long — and what it invalidates + +The `--log_mask=13` used by every script in this corpus **disables kernel +logging**, which is the one category that names the dialog. Without it the freeze +presents as a bare futex block with no explanation, which is why it was +attributed in turn to a heap leak, allocation rounding, `MmQueryStatistics`, a +build regression, the navigation route, the savegame, shader compilation, an +infinite guest loop, and finally the software rasterizer — each refuted in its +own section. + +⚠️ The nearest miss is worth recording: `challenge-mission-gate.md` reported +Xenia showing a *"Disc Read Error"* on this failure. That is a **different** +dialog (`XamShowDirtyDiscErrorUI`), and it calls `exit(1)` — "This is death, and +should never return" — so it cannot be our freeze, whose process stays alive. +Checking that distinction is what led to the dialog mechanism. + +❔ Still open: a mission has not been reached yet — `DEF_VTABLE` / `INST_VTABLE` +scans are still 0 at screen 10, so the remaining screens are menus (mission +select, briefing, ready room). That is now ordinary navigation work, not a +blocker.