handoff: VSync/event-wedge fixes + iterate 2.A–2.BC research notes
Source changes (dormant parity infra, retained from iterate 2.AI/2.AO): - xenia-kernel/exports.rs: nt_create_event manual_reset polarity + related event wiring - xenia-gpu/mmio_region.rs: D1MODE_VBLANK_VLINE_STATUS hardcode parity Also lands the audit-runs/ analysis notes (.md/.txt/.json digests) for the iterate 2.x VSync/0x10e8/0x1004 wedge investigation. Raw trace dumps (.jsonl/.gz/.csv/.stdout) and agent worktrees (.claude/) are gitignored as regenerable local artifacts — see memory + HANDOFF for the running findings. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
206
audit-runs/audit-069-wait-signal-producer/fix-canary.diff
Normal file
206
audit-runs/audit-069-wait-signal-producer/fix-canary.diff
Normal file
@@ -0,0 +1,206 @@
|
||||
diff --git a/src/xenia/cpu/cpu_flags.cc b/src/xenia/cpu/cpu_flags.cc
|
||||
index 3ff067e15..e024bfb26 100644
|
||||
--- a/src/xenia/cpu/cpu_flags.cc
|
||||
+++ b/src/xenia/cpu/cpu_flags.cc
|
||||
@@ -57,3 +57,98 @@ DEFINE_bool(break_condition_truncate, true, "truncate value to 32-bits", "CPU");
|
||||
|
||||
DEFINE_bool(break_on_debugbreak, true, "int3 on JITed __debugbreak requests.",
|
||||
"CPU");
|
||||
+
|
||||
+// AUDIT-DEMO: smoke marker (memory entry: emulator.cc:225,283). Always-on bool.
|
||||
+DEFINE_bool(audit_demo_setup_trace, true,
|
||||
+ "Audit smoke marker: log AUDIT-DEMO-SETUP-BEGIN at emulator setup.",
|
||||
+ "Audit");
|
||||
+
|
||||
+// AUDIT-061: comma-separated list of guest PCs to log on each fire.
|
||||
+// Format: "0xPC1,0xPC2,..." (max 32 PCs). Each fire emits
|
||||
+// AUDIT-061-BR pc=X lr=X cr0=LGE cr6=LGE r3=X r4=X r5=X r6=X r31=X tid=N.
|
||||
+// Default empty (off); no perf cost when empty.
|
||||
+DEFINE_string(audit_61_branch_probe_pcs, "",
|
||||
+ "AUDIT-061: CSV of guest PCs to trace (cr0/cr6 + regs/tid).",
|
||||
+ "Audit");
|
||||
+
|
||||
+// AUDIT-067: comma-separated list of u32 values to watch. When non-empty,
|
||||
+// every 4-byte guest store (stw/stwu/stwx/stwux/stmw) emits a runtime
|
||||
+// equality check; matches log AUDIT-067-VAL pc=X lr=X val=X dst=X r3..r6 r31 tid=N.
|
||||
+// Max 4 values. Default empty (off); zero overhead when empty.
|
||||
+DEFINE_string(audit_67_value_watch, "",
|
||||
+ "AUDIT-067: CSV of u32 values (max 4) — log every guest "
|
||||
+ "store whose value matches.",
|
||||
+ "Audit");
|
||||
+
|
||||
+// AUDIT-068: host-side memory-write watch. See cpu_flags.h header for format.
|
||||
+// Mirrors AUDIT-067 but covers host-side writes (xe::store_and_swap<T>,
|
||||
+// Memory::Zero/Fill/Copy). Empty default = zero cost.
|
||||
+DEFINE_string(audit_68_host_mem_watch_values, "",
|
||||
+ "AUDIT-068: CSV of u32 values (max 8) — log every host-side "
|
||||
+ "guest-memory write whose value matches.",
|
||||
+ "Audit");
|
||||
+DEFINE_string(audit_68_host_mem_watch_addrs, "",
|
||||
+ "AUDIT-068: CSV of guest VAs or VA ranges 'START-END' (max 8) "
|
||||
+ "— log every host-side guest-memory write whose guest VA falls "
|
||||
+ "within the configured set.",
|
||||
+ "Audit");
|
||||
+
|
||||
+// AUDIT-068 Session 3: read-mode probe. See cpu_flags.h for format.
|
||||
+DEFINE_string(audit_68_host_mem_read_probe, "",
|
||||
+ "AUDIT-068 Session 3: CSV of 'VA:SIZE:PERIOD_NS' tuples (max 8) "
|
||||
+ "— a dedicated poll thread reads the value at each VA every "
|
||||
+ "PERIOD_NS and emits AUDIT-068-READ-CHANGE on transition.",
|
||||
+ "Audit");
|
||||
+
|
||||
+// AUDIT-069: see cpu_flags.h header. Empty default = zero cost.
|
||||
+DEFINE_string(audit_69_event_signal_watch, "",
|
||||
+ "AUDIT-069: CSV of guest event-handle IDs (max 4) — log each "
|
||||
+ "XEvent::Set / Ke*Event / Nt*Event fire whose target matches.",
|
||||
+ "Audit");
|
||||
+DEFINE_string(audit_69_event_signal_native_ptr, "",
|
||||
+ "AUDIT-069: CSV of guest event native VAs (X_KEVENT*) (max 4) "
|
||||
+ "— log each set fire whose native pointer matches.",
|
||||
+ "Audit");
|
||||
+DEFINE_bool(audit_69_log_all_sets, false,
|
||||
+ "AUDIT-069: when true, log EVERY XEvent::Set/Pulse fire (used "
|
||||
+ "for one-run wait→signal correlation across handle drift). "
|
||||
+ "Default false; use only with --mute=true.",
|
||||
+ "Audit");
|
||||
+
|
||||
+// Phase A — see kernel/event_log.h.
|
||||
+DEFINE_string(phase_a_event_log_path, "",
|
||||
+ "Phase A: write schema-v1 JSONL event log to this path. "
|
||||
+ "Empty (default) = disabled.",
|
||||
+ "Audit");
|
||||
+DEFINE_bool(phase_a_event_log_mem_writes, false,
|
||||
+ "Phase A: include mem.write events in the JSONL log. RESERVED — "
|
||||
+ "not wired in this phase. Default false.",
|
||||
+ "Audit");
|
||||
+
|
||||
+// Phase D Stage 1 — see kernel/event_log.h `EmitContentionObserved`.
|
||||
+DEFINE_bool(kernel_emit_contention, false,
|
||||
+ "Phase D Stage 1: emit `contention.observed` events when "
|
||||
+ "RtlEnterCriticalSection's spin loop is exhausted and the call "
|
||||
+ "falls through to xeKeWaitForSingleObject. Default false (zero "
|
||||
+ "cost when disabled). Requires --phase_a_event_log_path to be "
|
||||
+ "set as well.",
|
||||
+ "Audit");
|
||||
+
|
||||
+// Phase B — see kernel/phase_b_snapshot.h.
|
||||
+DEFINE_string(phase_b_snapshot_dir, "",
|
||||
+ "Phase B: write 5-file structured state snapshot to "
|
||||
+ "<dir>/canary/ at the moment immediately before the first "
|
||||
+ "guest PPC instruction of entry_point. Empty (default) = "
|
||||
+ "disabled, zero overhead.",
|
||||
+ "Audit");
|
||||
+DEFINE_bool(phase_b_snapshot_and_exit, false,
|
||||
+ "Phase B: after writing the snapshot, exit the process "
|
||||
+ "immediately (std::_Exit(0)) so re-runs are byte-deterministic.",
|
||||
+ "Audit");
|
||||
+DEFINE_bool(phase_b_dump_section_content, false,
|
||||
+ "Phase B: in memory.json, populate section_contents[].content_b64 "
|
||||
+ "with raw bytes of every committed XEX-image region. Default "
|
||||
+ "false — per-region SHA-256 is enough for the routine diff; "
|
||||
+ "this is the escape hatch for the STOP-and-report condition "
|
||||
+ "(image_loaded_sha256 mismatch).",
|
||||
+ "Audit");
|
||||
diff --git a/src/xenia/cpu/cpu_flags.h b/src/xenia/cpu/cpu_flags.h
|
||||
index 38c4f98ba..cf5719b8b 100644
|
||||
--- a/src/xenia/cpu/cpu_flags.h
|
||||
+++ b/src/xenia/cpu/cpu_flags.h
|
||||
@@ -35,4 +35,66 @@ DECLARE_bool(break_condition_truncate);
|
||||
|
||||
DECLARE_bool(break_on_debugbreak);
|
||||
|
||||
+// AUDIT-DEMO smoke marker.
|
||||
+DECLARE_bool(audit_demo_setup_trace);
|
||||
+
|
||||
+// AUDIT-061: multi-PC branch probe — emits one log line per fire with
|
||||
+// (pc, lr, cr0 LGE, cr6 LGE, r3, r4, r5, r6, r31, tid). CSV of guest PCs.
|
||||
+DECLARE_string(audit_61_branch_probe_pcs);
|
||||
+
|
||||
+// AUDIT-067: value-watch — emit a log line for each 32-bit guest store whose
|
||||
+// value-to-be-stored matches any configured value. CSV of u32 values
|
||||
+// ("0xDEADBEEF,..."), max 4 entries. Default empty (off); zero cost when empty.
|
||||
+DECLARE_string(audit_67_value_watch);
|
||||
+
|
||||
+// AUDIT-068: host-side memory-write watch — emit a log line for each host-side
|
||||
+// write to guest memory whose VALUE matches any configured u32 value, or whose
|
||||
+// guest VA falls within any configured ADDR or ADDR-range. Mirrors AUDIT-067
|
||||
+// but covers the host-side write paths (xe::store_and_swap<T>, Memory::Zero/
|
||||
+// Fill/Copy) that AUDIT-067's JIT store-opcode hooks cannot see.
|
||||
+//
|
||||
+// VALUES: CSV of u32 values, max 8 entries; e.g. "0x8200A208,0x8200A928".
|
||||
+// ADDRS: CSV of guest VAs or VA ranges, max 8 entries; range form is
|
||||
+// "0xSTART-0xEND" (inclusive). e.g. "0x42500000-0x42600000,0xBCE25340".
|
||||
+// Default empty (off); zero cost on the hot path when both are empty.
|
||||
+DECLARE_string(audit_68_host_mem_watch_values);
|
||||
+DECLARE_string(audit_68_host_mem_watch_addrs);
|
||||
+
|
||||
+// AUDIT-068 Session 3: read-mode probe. CSV of "VA:SIZE:PERIOD_NS" tuples
|
||||
+// (max 8). A dedicated low-priority thread polls each VA every PERIOD_NS and
|
||||
+// emits AUDIT-068-READ-CHANGE when the value transitions. SIZE in {1,2,4,8}.
|
||||
+// Example: "0xBCE25340:4:1000000" = poll u32 at 0xBCE25340 every 1 ms.
|
||||
+// Default empty (off); the poll thread is not spawned when empty.
|
||||
+DECLARE_string(audit_68_host_mem_read_probe);
|
||||
+
|
||||
+// AUDIT-069: event-signal watch. CSV of guest handle IDs (e.g. "0xF8000098")
|
||||
+// to log on every XEvent::Set / KeSetEvent / NtSetEvent / KePulseEvent /
|
||||
+// NtPulseEvent fire whose target matches. Max 4 entries. Default empty (off);
|
||||
+// zero cost on the hot path when empty.
|
||||
+DECLARE_string(audit_69_event_signal_watch);
|
||||
+// AUDIT-069: event-signal watch by native guest VA (X_KEVENT*). CSV of guest
|
||||
+// VAs (max 4). Default empty (off). Use when the handle id varies across
|
||||
+// boots but the native dispatcher pointer is stable.
|
||||
+DECLARE_string(audit_69_event_signal_native_ptr);
|
||||
+// AUDIT-069: when true, log EVERY XEvent::Set / XEvent::Pulse fire (subject
|
||||
+// to the slowpath gate). Use only with --mute=true and short windows — high
|
||||
+// volume. Default false (off).
|
||||
+DECLARE_bool(audit_69_log_all_sets);
|
||||
+
|
||||
+// Phase A: JSONL event-log emitter path. When non-empty, the engine writes
|
||||
+// schema-v1 JSONL events to this file. Empty (default) = no overhead, no
|
||||
+// behavior change. Schema: xenia-rs/audit-runs/phase-a-diff-harness/schema-v1.md
|
||||
+DECLARE_string(phase_a_event_log_path);
|
||||
+DECLARE_bool(phase_a_event_log_mem_writes);
|
||||
+
|
||||
+// Phase B: initial-state snapshot. When the dir cvar is non-empty, the
|
||||
+// engine writes a five-file structured state snapshot (cpu_state.json,
|
||||
+// memory.json, kernel.json, vfs.json, config.json, plus manifest.json) to
|
||||
+// `<dir>/canary/` at the moment immediately before the first guest PPC
|
||||
+// instruction of the XEX entry_point executes. See
|
||||
+// `xenia-rs/audit-runs/phase-b-state-equivalence/`.
|
||||
+DECLARE_string(phase_b_snapshot_dir);
|
||||
+DECLARE_bool(phase_b_snapshot_and_exit);
|
||||
+DECLARE_bool(phase_b_dump_section_content);
|
||||
+
|
||||
#endif // XENIA_CPU_CPU_FLAGS_H_
|
||||
diff --git a/src/xenia/kernel/xevent.cc b/src/xenia/kernel/xevent.cc
|
||||
index b583bf732..f8bf47952 100644
|
||||
--- a/src/xenia/kernel/xevent.cc
|
||||
+++ b/src/xenia/kernel/xevent.cc
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
#include "xenia/base/byte_stream.h"
|
||||
#include "xenia/base/logging.h"
|
||||
+#include "xenia/kernel/audit_69_event_signal_watch.h"
|
||||
|
||||
namespace xe {
|
||||
namespace kernel {
|
||||
@@ -58,12 +59,19 @@ void XEvent::InitializeNative(void* native_ptr, X_DISPATCH_HEADER* header) {
|
||||
}
|
||||
|
||||
int32_t XEvent::Set(uint32_t priority_increment, bool wait) {
|
||||
+ // AUDIT-069: log event-signal fires whose target matches the configured
|
||||
+ // handle ID or native VA. Hot path is a single relaxed atomic load when
|
||||
+ // the cvars are empty (default).
|
||||
+ audit_69::check_event_set(this->handle(), this->guest_object(),
|
||||
+ "XEvent::Set");
|
||||
set_priority_increment(priority_increment);
|
||||
event_->Set();
|
||||
return 1;
|
||||
}
|
||||
|
||||
int32_t XEvent::Pulse(uint32_t priority_increment, bool wait) {
|
||||
+ audit_69::check_event_set(this->handle(), this->guest_object(),
|
||||
+ "XEvent::Pulse");
|
||||
set_priority_increment(priority_increment);
|
||||
event_->Pulse();
|
||||
return 1;
|
||||
Reference in New Issue
Block a user