fix(kernel): KRNBUG-IO-004 — real XamNotifyCreateListener + XNotifyGetNext per canary

Canary's RegisterNotifyListener (kernel_state.cc:1013-1033) auto-enqueues four
startup notifications on the first listener whose mask covers kXNotifySystem
(SystemUI=0x09 + SystemSignInChanged=0x0A) and kXNotifyLive
(LiveConnectionChanged=0x02000001 + LiveLinkStateChanged=0x02000003). XNotifyGetNext
(xam_notify.cc:22-96) pops the queue with mask + version filtering on enqueue per
xnotifylistener.cc:38-51. Our prior stubs returned 0 forever; the dispatch loop
at 0x822f1be8 in sub_822F1AA8 was thus bypassed indefinitely.

Implementation:
- KernelObject::NotifyListener { mask, max_version, queue, waiters } variant.
- KernelState::has_notified_startup + has_notified_live_startup gates.
- xam_notify_create_listener: mask=r3 (qword), max_version=r4 (clamped <=10),
  alloc handle, conditional 4-tuple startup enqueue.
- xnotify_get_next: handle/match_id/id_ptr/param_ptr in r3..r6; pop_front
  (or scan-by-id), with mask + version filter applied at enqueue time.
- 5 unit tests covering: full-mask 4 startup notifications, second-listener
  no re-fire, system-only mask filtering, max_version=0 too-new drop,
  unknown handle returning 0.

Tests: 594 -> 599. Lockstep `-n 100M` instructions=100000012 deterministic
across 2 reruns; bit-identical run-to-run diff.

Cascade (verified at -n 500M):
- dispatch arm 0x822f1be8 fires; sub_82173DC8 entered.
- 3/21 renderer-cluster L1 PCs newly reached: 0x822c6870 (2 workers),
  0x824563e0, 0x823ddb50.
- canary-only export delta 7 -> 3 (reclassified to fired:
  KeResetEvent, ObCreateSymbolicLink, XamTaskCloseHandle, XamTaskSchedule).
- worker thread count 18 -> 20.
- signal_attempts on handle 0x15e0 = 1 (primary=1), was 0.
- draws=0 still expected at this step.

LOC: 119 (97 impl + 22 scaffolding pattern matches across main.rs / objects.rs
/ state.rs) <= 120.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-05-06 16:55:51 +02:00
parent 50a488776f
commit b78e6fd205
4 changed files with 225 additions and 9 deletions

View File

@@ -101,6 +101,12 @@ pub struct KernelState {
/// privilege numbers have already produced a `tracing::info!` line so
/// the import-hot path doesn't spam at -n 500M.
pub xex_priv_logged: std::collections::HashSet<u32>,
/// Whether the first listener whose mask covers `kXNotifySystem` has
/// been registered — gate for the two startup system notifications
/// per `kernel_state.cc:1020-1025`.
pub has_notified_startup: bool,
/// Same for `kXNotifyLive` per `kernel_state.cc:1026-1032`.
pub has_notified_live_startup: bool,
/// Next thread ID. M2.4: atomic.
pub next_thread_id: std::sync::atomic::AtomicU32,
/// Virtual file system for NtCreateFile/NtReadFile/etc. The app mounts
@@ -269,6 +275,8 @@ impl KernelState {
image_base: 0,
xex_system_flags: 0,
xex_priv_logged: std::collections::HashSet::new(),
has_notified_startup: false,
has_notified_live_startup: false,
next_thread_id: AtomicU32::new(1),
vfs: None,
ui: None,