Compare commits
20 Commits
cc9ebbb5e7
...
iterate-4A
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ed2615b9b0 | ||
|
|
dc3de9dbc4 | ||
|
|
f51c7c8ca9 | ||
|
|
6b248d71e9 | ||
|
|
5950dc86d5 | ||
|
|
0becc9185a | ||
|
|
e3cc6d11d0 | ||
|
|
4b78c67605 | ||
|
|
2c17a511f7 | ||
|
|
5d5dc5dd89 | ||
|
|
da0509b4ac | ||
|
|
d91311c486 | ||
|
|
704e87a2a4 | ||
|
|
6475f4ba97 | ||
|
|
15d0d7e0bd | ||
|
|
56dbf52a5f | ||
|
|
cc7ff58cb0 | ||
|
|
07cd272412 | ||
|
|
ac289bca5e | ||
|
|
e07f93ed0a |
241
Cargo.lock
generated
241
Cargo.lock
generated
@@ -87,6 +87,12 @@ dependencies = [
|
||||
"equator",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "allocator-api2"
|
||||
version = "0.2.21"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||
|
||||
[[package]]
|
||||
name = "android-activity"
|
||||
version = "0.6.1"
|
||||
@@ -521,6 +527,9 @@ name = "bumpalo"
|
||||
version = "3.20.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bytecheck"
|
||||
@@ -874,6 +883,167 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-assembler-x64"
|
||||
version = "0.128.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50a04121a197fde2fe896f8e7cac9812fc41ed6ee9c63e1906090f9f497845f6"
|
||||
dependencies = [
|
||||
"cranelift-assembler-x64-meta",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-assembler-x64-meta"
|
||||
version = "0.128.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a09e699a94f477303820fb2167024f091543d6240783a2d3b01a3f21c42bc744"
|
||||
dependencies = [
|
||||
"cranelift-srcgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-bforest"
|
||||
version = "0.128.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f07732c662a9755529e332d86f8c5842171f6e98ba4d5976a178043dad838654"
|
||||
dependencies = [
|
||||
"cranelift-entity",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-bitset"
|
||||
version = "0.128.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "18391da761cf362a06def7a7cf11474d79e55801dd34c2e9ba105b33dc0aef88"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen"
|
||||
version = "0.128.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b3a09b3042c69810d255aef59ddc3b3e4c0644d1d90ecfd6e3837798cc88a3c"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"cranelift-assembler-x64",
|
||||
"cranelift-bforest",
|
||||
"cranelift-bitset",
|
||||
"cranelift-codegen-meta",
|
||||
"cranelift-codegen-shared",
|
||||
"cranelift-control",
|
||||
"cranelift-entity",
|
||||
"cranelift-isle",
|
||||
"gimli",
|
||||
"hashbrown 0.15.5",
|
||||
"log",
|
||||
"regalloc2",
|
||||
"rustc-hash 2.1.2",
|
||||
"serde",
|
||||
"smallvec",
|
||||
"target-lexicon",
|
||||
"wasmtime-internal-math",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-meta"
|
||||
version = "0.128.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "75817926ec812241889208d1b190cadb7fedded4592a4bb01b8524babb9e4849"
|
||||
dependencies = [
|
||||
"cranelift-assembler-x64-meta",
|
||||
"cranelift-codegen-shared",
|
||||
"cranelift-srcgen",
|
||||
"heck",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-codegen-shared"
|
||||
version = "0.128.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "859158f87a59476476eda3884d883c32e08a143cf3d315095533b362a3250a63"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-control"
|
||||
version = "0.128.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "03b65a9aec442d715cbf54d14548b8f395476c09cef7abe03e104a378291ab88"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-entity"
|
||||
version = "0.128.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8334c99a7e86060c24028732efd23bac84585770dcb752329c69f135d64f2fc1"
|
||||
dependencies = [
|
||||
"cranelift-bitset",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-frontend"
|
||||
version = "0.128.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "43ac6c095aa5b3e845d7ca3461e67e2b65249eb5401477a5ff9100369b745111"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"log",
|
||||
"smallvec",
|
||||
"target-lexicon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-isle"
|
||||
version = "0.128.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "69d3d992870ed4f0f2e82e2175275cb3a123a46e9660c6558c46417b822c91fa"
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-jit"
|
||||
version = "0.128.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "807781e9097feba24c31fc8d85a217c2fbfc6c8b72a87da8717c056dc8b24a87"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
"cranelift-control",
|
||||
"cranelift-entity",
|
||||
"cranelift-module",
|
||||
"cranelift-native",
|
||||
"libc",
|
||||
"log",
|
||||
"region",
|
||||
"target-lexicon",
|
||||
"wasmtime-internal-jit-icache-coherence",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-module"
|
||||
version = "0.128.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6a588624367124596cb07c324fa865a4894200aede7fe933e817816188ace52"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cranelift-codegen",
|
||||
"cranelift-control",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-native"
|
||||
version = "0.128.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ee32e36beaf80f309edb535274cfe0349e1c5cf5799ba2d9f42e828285c6b52e"
|
||||
dependencies = [
|
||||
"cranelift-codegen",
|
||||
"libc",
|
||||
"target-lexicon",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cranelift-srcgen"
|
||||
version = "0.128.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "903adeaf4938e60209a97b53a2e4326cd2d356aab9764a1934630204bae381c9"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.5.0"
|
||||
@@ -1359,6 +1529,11 @@ name = "gimli"
|
||||
version = "0.32.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e629b9b98ef3dd8afe6ca2bd0f89306cec16d43d907889945bc5d6687f2f13c7"
|
||||
dependencies = [
|
||||
"fallible-iterator",
|
||||
"indexmap",
|
||||
"stable_deref_trait",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gl_generator"
|
||||
@@ -2127,6 +2302,15 @@ version = "0.1.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154"
|
||||
|
||||
[[package]]
|
||||
name = "mach2"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d640282b302c0bb0a2a8e0233ead9035e3bed871f0b7e81fe4a1ec829765db44"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "malloc_buf"
|
||||
version = "0.0.6"
|
||||
@@ -3183,6 +3367,20 @@ dependencies = [
|
||||
"bitflags 2.11.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regalloc2"
|
||||
version = "0.13.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "08effbc1fa53aaebff69521a5c05640523fab037b34a4a2c109506bc938246fa"
|
||||
dependencies = [
|
||||
"allocator-api2",
|
||||
"bumpalo",
|
||||
"hashbrown 0.15.5",
|
||||
"log",
|
||||
"rustc-hash 2.1.2",
|
||||
"smallvec",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.12.3"
|
||||
@@ -3212,6 +3410,18 @@ version = "0.8.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
||||
|
||||
[[package]]
|
||||
name = "region"
|
||||
version = "3.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6b6ebd13bc009aef9cd476c1310d49ac354d36e240cf1bd753290f3dc7199a7"
|
||||
dependencies = [
|
||||
"bitflags 1.3.2",
|
||||
"libc",
|
||||
"mach2",
|
||||
"windows-sys 0.52.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rend"
|
||||
version = "0.4.2"
|
||||
@@ -3808,6 +4018,12 @@ dependencies = [
|
||||
"xattr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "target-lexicon"
|
||||
version = "0.13.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
|
||||
|
||||
[[package]]
|
||||
name = "tempfile"
|
||||
version = "3.27.0"
|
||||
@@ -4378,6 +4594,27 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-internal-jit-icache-coherence"
|
||||
version = "41.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4b96df23179ae16d54fb3a420f84ffe4383ec9dd06fad3e5bc782f85f66e8e08"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"windows-sys 0.61.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wasmtime-internal-math"
|
||||
version = "41.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86d1380926682b44c383e9a67f47e7a95e60c6d3fa8c072294dab2c7de6168a0"
|
||||
dependencies = [
|
||||
"libm",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "wayland-backend"
|
||||
version = "0.3.15"
|
||||
@@ -5071,6 +5308,10 @@ name = "xenia-cpu"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"bitflags 2.11.0",
|
||||
"cranelift-codegen",
|
||||
"cranelift-frontend",
|
||||
"cranelift-jit",
|
||||
"cranelift-module",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"thiserror 2.0.18",
|
||||
|
||||
121
RE_SYMBOLS.md
Normal file
121
RE_SYMBOLS.md
Normal file
@@ -0,0 +1,121 @@
|
||||
# Project Sylpheed — reverse-engineered symbol map
|
||||
|
||||
Durable record of guest functions/data in the retail title (`default.xex`,
|
||||
base `0x82000000`) that have been positively identified by RE. Addresses are
|
||||
guest virtual addresses. This is the source of truth for names; the DuckDB
|
||||
`sylpheed.db` (this dir) `functions.name` column can be re-stamped from here
|
||||
with `apply_re_symbols.sql` (names are wiped on a full DB regen).
|
||||
|
||||
Confidence: **H** = behaviour proven (reproduced/verified against data), **M** =
|
||||
strongly inferred from disassembly, **L** = tentative.
|
||||
|
||||
## Archive (IPFB `.pak`) subsystem
|
||||
|
||||
| Address | Name | Conf | Description |
|
||||
|---|---|---|---|
|
||||
| `0x824609C8` | `Pak_FindEntryByName` | H | Look up a TOC entry by path. Args `(r3 = pak object, r4 = char* path)`. Calls `Pak_HashPathName(path)`, then binary-searches the sorted 12-byte TOC (base `pak+4`, count `pak+8`, stride 12; compares the 32-bit `name_hash`). Returns the matching record pointer or 0. |
|
||||
| `0x82460928` | `Pak_HashPathName` | H | Duplicate `r3 = char* path`, lowercase it in place (`Str_ToLowerAscii`), hash with `Sylph_NameHash`, free the copy, return the 32-bit hash. This is the path→key bridge. |
|
||||
| `0x82455C78` | `Sylph_NameHash` | H | The IPFB TOC / cache-path name-hash. See [Name-hash](#name-hash-sylph_namehash). Input must already be lowercased. `r3 = char*` → `r3 = u32 hash`. |
|
||||
| `0x825F4F90` | `Str_ToLowerAscii` | H | In-place ASCII lowercase (`A`–`Z` → `+0x20`); other bytes pass through. `r3 = char*`. (When `r3 == 0` it takes an unrelated init branch.) |
|
||||
| `0x824607B0` | `Pak_IsIPFBHeader` | H | Validate an IPFB header. Loads the header's first word and checks it equals `"IPFB"` (`0x49504642`) via a delta trick: `first_word - 0x49504620 == 0x22` (`'B' - ' '`). `r5 = header ptr`. Returns bool-ish in `r3`. |
|
||||
| `0x82460AD0`… | *(pak header parse, unregistered container)* | M | The pak-open/validate path around `0x82460DC0`–`0x82460EC4` builds an expected-header template (`"IPFB"`, `0x10000000` flags) on the stack and calls `Pak_IsIPFBHeader`. Function-boundary detection missed the enclosing frame (entry ≈ `0x82460E34`). |
|
||||
| `0x82458508` | `Archive_StreamReadCrc32` | M | Streaming block reader that validates content with a reflected CRC-32 (init `0xFFFFFFFF`, final `~`, table at `g_Crc32Table`). Compares the computed CRC to a stored expected value (`state+144`). This is a **content-integrity** CRC, *not* the name-hash. |
|
||||
| `0x828992F0` | `g_Crc32Table` (data) | H | 256-entry reflected CRC-32 lookup table. Referenced only by `Archive_StreamReadCrc32` and its sibling loop at `0x82457AF8`. |
|
||||
|
||||
## IDXD reflective serialization framework
|
||||
|
||||
Generic tagged-object (de)serializer shared by ~15 object families (craft,
|
||||
weapon, message/character, effects, …). The `.pak` IDXD payloads are read
|
||||
through this.
|
||||
|
||||
| Address | Name | Conf | Description |
|
||||
|---|---|---|---|
|
||||
| `0x824486C0` | `IdxdLoad_Dispatch` | M | Entry: reads the magic and dispatches across variants `IDXD` (`0x49445844`), `IDX2`, `IDX3`, `IDXC`, `IXUD` → the matching parser. **15 callers** (one per object family). The target object is passed in `r3` — already constructed (defaults set) by the caller. |
|
||||
| `0x82448D00` | `IdxdLoad_Variant2` | M | Sibling variant loader (also materializes the `IDXD` magic). |
|
||||
| `0x82449640` | `Idxd_Parse` | M | The IDXD body parser: skips a BOM, then loops the string pool — per field, reads the name token, `Reflect_FindFieldIndex`, then dispatches on the **value's first char** (jump table at `0x824497F8`, index `firstchar - 0x22`) to type-specific writers. Only fields **present** in the pool are written. |
|
||||
| `0x8244A2F0` | `Reflect_FindFieldIndex` | M | Look up a field-name string in a global name-vector at `0x820B4F18` (std::vector-like: count `+20`, data `+24`/SSO), via a `strncmp`-style compare (`0x825EDCE0`). Returns index or `-1`. |
|
||||
| `0x8244A4B0` | `Reflect_SetField` | L | Apply a value to `object` using its per-instance property registry at `object+64` and a config string at `0x820B4F28`. |
|
||||
| `0x820B4F18` | `g_FieldNameRegistry` (data) | L | Global reflection name-vector (runtime-built) used by `Reflect_FindFieldIndex`. |
|
||||
|
||||
**Defaulted fields:** a field is written to the IDXD pool only when it differs
|
||||
from its default, so `Idxd_Parse` never sets defaulted fields — their values are
|
||||
established by each **type's constructor** (in the 15 `IdxdLoad_Dispatch`
|
||||
callers) before load, via this same registry. Recovering them statically means
|
||||
reversing those constructors and joining `field-name → struct-offset →
|
||||
default-store`; a runtime dump of a loaded object's registry gives
|
||||
`name → value` directly. (Open — see below.)
|
||||
|
||||
## 3D resource subsystem
|
||||
|
||||
| Address | Name | Conf | Description |
|
||||
|---|---|---|---|
|
||||
| `0x82640290` | `Res3D_LoadMeshChunk` | L | 3D-resource loader: walks 12-byte records, checks chunk tags (`0x1A22AA26`, `0x2DA2AA24`), and copies `float` triples (x/y/z vertices) via `lfs`/`stfs`. Part of the DefTables/`machines\<model>\…` mesh path. |
|
||||
|
||||
## Name-hash (`Sylph_NameHash`)
|
||||
|
||||
Per-byte Barrett-reduced polynomial hash over the **lowercased** name:
|
||||
|
||||
```
|
||||
A = 0 ; B = 0
|
||||
for each (sign-extended) byte c of the lowercased name:
|
||||
A = (A << 8) + c # 32-bit
|
||||
A = A - (((A * 0x8003_1493) >> 32) rol 9 & 0x1FF) * 0x00FF_F9D7 # A mod 0x00FF_F9D7 (no final fixup)
|
||||
B = B + c
|
||||
hash = ((B & 0xFF) << 24) | (A & 0x00FF_FFFF)
|
||||
```
|
||||
|
||||
- Modulus `0x00FF_F9D7`, reciprocal `0x8003_1493` (the `mulhwu`/`mullw` Barrett step).
|
||||
- Low 24 bits = modular polynomial hash; top byte = 8-bit additive checksum of the bytes.
|
||||
- No trailing conditional subtract — the value is defined by the exact op sequence.
|
||||
- Faithful Rust reproduction: `sylpheed-formats/src/hash.rs` (`name_hash`).
|
||||
|
||||
**Verified** against retail TOCs: `name_hash("files.tbl") == 0x8342_1153`,
|
||||
`name_hash("eng\\weapon.tbl") == 0x900C_8DCD`, `name_hash("eng\\strings.tbl") == 0x10C8_0B87`,
|
||||
`name_hash("jpn\\weapon.tbl") == 0x9E85_FEFF`.
|
||||
|
||||
## TOC key path conventions (preimages)
|
||||
|
||||
The 32-bit TOC key is `name_hash` of a **backslash** path with the entry's
|
||||
internal identity string. Confirmed schemes:
|
||||
|
||||
| Scheme | Example | Where |
|
||||
|---|---|---|
|
||||
| `unit\<ID>.tbl` | `unit\UN_f001_TCAF_DeltaSaber_T_EX5.tbl` → `0x7C96296C` | craft/ship entries in `GP_MAIN_GAME_*.pak` |
|
||||
| `weapon\<ID>.tbl` | `weapon\Weapon_DSaber_P_wep_26_Missile.tbl` | weapon entries |
|
||||
| `message\<ID>.tbl` | `message\CharacterCARL.tbl` | character/dialog entries |
|
||||
| `effect\<ID>.tbl` | — | effect definitions |
|
||||
| `<lang>\<name>.tbl` | `eng\weapon.tbl`, `jpn\strings.tbl` | localized loadout/text tables |
|
||||
| `<name>.tbl` | `files.tbl` | root manifest / DefTables resource entries |
|
||||
|
||||
`<ID>` = the entry's internal `ID` field (IDXD string pool). Craft/weapon
|
||||
entries also self-describe by content, so stats are readable without the key.
|
||||
|
||||
Coverage with these schemes (IDXD entries, whole-pool ID extraction):
|
||||
GP_MAIN_GAME_E 308/1004 (≈31%), DefTables 804/1425 (≈56%). Shipped in
|
||||
`sylpheed-formats` (`hash::recover_toc_name`, `pak list` prints resolved
|
||||
paths). The unresolved remainder use deeper cross-referenced directory
|
||||
paths (e.g. per-mission dialog `MSG_*` entries) — a later hunt, not an
|
||||
extraction limit.
|
||||
|
||||
## Open threads
|
||||
|
||||
- **Defaulted IDXD fields.** A field is omitted from the pool exactly when it
|
||||
equals the schema default, so present values are all *overrides* and the
|
||||
defaults cannot be inferred from them. Gap is large: across the 534 craft
|
||||
(`schema 0x43FAA517`) entries, explicit-presence is `Acceleration` 42%,
|
||||
`MaximumVelocity` 51%, `Turn_AngularVelocity` 31%, `FCSRange` 34%,
|
||||
`ShieldRatio` 49% (`Size_X` 100%, `HP` 85%). So 40–70% of craft rely on
|
||||
unknown defaults for core flight/defense stats.
|
||||
- Ruled out: the big 16-byte-record binary node table inside a craft IDXD is
|
||||
**spatial/mesh data**, not defaults (not keyed by `name_hash(field_key)`).
|
||||
- `schema_hash` is **not** a code immediate and **not** `name_hash(typename)`.
|
||||
- Defaults are set by each type's **constructor** (one per `IdxdLoad_Dispatch`
|
||||
caller) via the reflection registry, not by `Idxd_Parse`.
|
||||
- **Two finish routes.** (A, static) reverse the craft constructor: read its
|
||||
field registrations (`name → offset`) and default-init stores
|
||||
(`offset → value`), join them — heavy, and offset↔name correlation is
|
||||
error-prone. (B, runtime) dump a loaded craft object's registry
|
||||
(`obj+64`) / struct from xenia-rs or Canary — a fully-loaded craft already
|
||||
holds every default; one dump yields `name → value`. **B is the efficient
|
||||
finish** given the framework is generic; A's framework map above is the
|
||||
prerequisite either way.
|
||||
20
apply_re_symbols.sql
Normal file
20
apply_re_symbols.sql
Normal file
@@ -0,0 +1,20 @@
|
||||
-- Re-stamp reverse-engineered function names onto sylpheed.db.
|
||||
-- Source of truth: docs/RE_SYMBOLS.md. Re-run after any full DB regen
|
||||
-- (regen wipes functions.name back to sub_XXXX).
|
||||
-- python3 -c "import duckdb; duckdb.connect('sylpheed.db').execute(open('apply_re_symbols.sql').read())"
|
||||
-- Addresses are decimal (DuckDB rejects 0x literals in some contexts); hex in comments.
|
||||
|
||||
UPDATE functions SET name = 'Pak_FindEntryByName' WHERE address = 2185628104; -- 0x824609C8
|
||||
UPDATE functions SET name = 'Pak_HashPathName' WHERE address = 2185627944; -- 0x82460928
|
||||
UPDATE functions SET name = 'Sylph_NameHash' WHERE address = 2185583736; -- 0x82455C78
|
||||
UPDATE functions SET name = 'Str_ToLowerAscii' WHERE address = 2187284368; -- 0x825F4F90
|
||||
UPDATE functions SET name = 'Pak_IsIPFBHeader' WHERE address = 2185627568; -- 0x824607B0
|
||||
UPDATE functions SET name = 'Archive_StreamReadCrc32' WHERE address = 2185594120; -- 0x82458508
|
||||
UPDATE functions SET name = 'Res3D_LoadMeshChunk' WHERE address = 2187592336; -- 0x82640290
|
||||
|
||||
-- IDXD reflective serialization framework (defaulted-field hunt, 2026-07-09)
|
||||
UPDATE functions SET name = 'IdxdLoad_Dispatch' WHERE address = 2185529024; -- 0x824486C0 (magic dispatch IDXD/IDX2/IDX3/IDXC/IXUD; 15 callers)
|
||||
UPDATE functions SET name = 'IdxdLoad_Variant2' WHERE address = 2185530624; -- 0x82448D00 (sibling variant loader)
|
||||
UPDATE functions SET name = 'Idxd_Parse' WHERE address = 2185532992; -- 0x82449640 (tokenize pool; per-field lookup+set)
|
||||
UPDATE functions SET name = 'Reflect_FindFieldIndex' WHERE address = 2185536240; -- 0x8244A2F0 (field-name -> index in name-vector @0x820B4F18)
|
||||
UPDATE functions SET name = 'Reflect_SetField' WHERE address = 2185536688; -- 0x8244A4B0 (apply value via object registry @obj+64)
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,281 +0,0 @@
|
||||
# Canary-Only Export Fix Queue (audit-006)
|
||||
|
||||
- Status: **POST-KE-001 (2026-05-06): 2 canary-only (XamUserReadProfileSettings DROPPED post-XamUserGetSigninState landing earlier; KE-001 unsuspended audio workers but KeReleaseSemaphore producer is downstream-gated and did NOT fire).** `KeResumeThread` is now a real impl per canary `xboxkrnl_threading.cc:216-227` (KRNBUG-KE-001, branch `ke-resume-thread/p0-canary-mirror`). Cascade A passed: tids 9 (entry=0x824D2878) and 10 (entry=0x824D2940) leave Suspended → run prologue → park on `WaitAny` for audio buffer-completion semaphores `0x828A3254` / `0x828A3230`. Cascade B partial: `NtSetEvent 667→3334` (5×) but `KeReleaseSemaphore=0` and `XAudioSubmitRenderDriverFrame=0` — workers stuck before the producer. Cascade C predicted 2→1, actual 2→2 (`ExTerminateThread`, `KeReleaseSemaphore` both still canary-only). Cascade D: `--pc-probe=0x82184318,0x82184374` armed — neither fires; `--dump-addr=0x828F4070` no DUMP lines; γ-cluster blocker unchanged; signal_attempts on 0x1004/0x100c/0x1020/0x15e4 still 0. swaps=2 draws=0 plateau intact. Lockstep `instructions=100000003 imports=987516` deterministic ×2. Goldens re-baselined `sylpheed_n50m.json instructions 50000003→50000011, imports 407255→407247`. See KRNBUG-KE-001 in `audit-findings.md`.
|
||||
|
||||
- Prior status (superseded by KE-001): **POST-IO-004 (2026-05-06): 7 → 3 canary-only.** Real `XamNotifyCreateListener` + `XNotifyGetNext` landed (KRNBUG-IO-004). Dispatch arm at `0x822f1be8` now fires; `sub_82173DC8` runs in a tight loop on tid=1; renderer-cluster L1 entries `0x822c6870`, `0x824563e0`, `0x823ddb50` are reached for the first time. 4 reclassified RE-FIRES (now reached): `KeResetEvent`, `ObCreateSymbolicLink`, `XamTaskCloseHandle`, `XamTaskSchedule`. Still canary-only: `ExTerminateThread`, `KeReleaseSemaphore`, `XamUserReadProfileSettings` — all REAL_BUT_UNREACHED at the new boot horizon. Worker count 18 → 20. signal_attempts on 0x15e0 = 1 (was 0). draws=0 still expected at this step. See KRNBUG-IO-004 in `audit-findings.md` and `project_xenia_rs_io_004_xnotify_listener_2026_05_06.md`.
|
||||
|
||||
- Prior status (superseded by IO-004): **AUDIT-009 (2026-05-05): GATE IS HIGHER THAN THE CLUSTER ITSELF.** AUDIT-008's β-hypothesis (gate sits among the 5 callers of `sub_821800D8` in 0x82287000-0x82292FFF) is **falsified**: a 21-PC `--branch-probe` (the 6 parents + 5 shims + dispatcher + 9 audit-005 producer-callsites) shows **0/21 firings** at -n 500M (`audit-runs/audit-009/probe-500m.err`). The whole 0x82287000-0x82294000 cluster is unreached. Static analysis: the cluster's level-1 root functions (`sub_82293448`, `sub_822919C8`) have **zero non-call xrefs in sylpheed.db** — they are reached only via vtable / function-pointer that's never written. Main parks at `sub_822F1AA8` frame-poll loop forever (1.49M XNotifyGetNext iterations). Three canary-only exports (`ExTerminateThread`, `KeReleaseSemaphore`, `XamUserReadProfileSettings`) remain REAL_BUT_UNREACHED — same as audit-008. **DO NOT pull from this queue.** Next-session probe set: cluster L1 roots + new thread entry trampolines (0x822c6870 / 0x824563e0 / 0x823dde30 / 0x823ddb50) + main's frame-poll callees + main's post-poll continuation list. See KRNBUG-AUDIT-009 in `audit-findings.md` and `project_xenia_rs_audit_009_renderer_unreached_2026_05_05.md`.
|
||||
|
||||
- Prior status (superseded by AUDIT-009): **AUDIT-008 MODEL RESET (2026-05-05).** 0x100c worker IS spawned post-IO-003 as tid=3 (ctx=0x828F3D08), 0x1004 as tid=11, 0x15e0 as tid=17. AUDIT-008 hypothesized the gate among the 5 non-create-chain callers of `sub_821800D8` whose parents live in 0x82287000-0x82292FFF. AUDIT-009 falsified that — those parents are themselves never entered, so the gate is one level above.
|
||||
|
||||
- Prior status (superseded by AUDIT-008): **PARTIAL CASCADE (2026-05-04, post-KRNBUG-IO-003). 7 → 3 canary-only exports.** `NtDeviceIoControlFile` real impl landed; the priv-11 query (`XexCheckExecutablePrivilege(0xB)`) and `XamTaskSchedule` now fire. **Reclassified (now firing on our side):** `KeResetEvent`, `ObCreateSymbolicLink`, `XamTaskCloseHandle`, `XamTaskSchedule`. **Bonus pickups:** `XeCryptSha`, `XeKeysConsolePrivateKeySign` (both 0→1 — were not on the canary-only list because they were already in `ours_exports` but unreached). **Still canary-only:** `ExTerminateThread`, `KeReleaseSemaphore`, `XamUserReadProfileSettings`. ~~Worker thread spawn count unchanged at 19; handle 0x100c remains UNCREATED.~~ (audit-008: 0x100c worker IS spawned, claim was wrong.) See KRNBUG-IO-003 in `audit-findings.md` and `project_xenia_rs_io_003_ioctl_2026_05_04.md`.
|
||||
|
||||
- Prior status (now superseded): **SUPERSEDED by AUDIT-007 (2026-05-04). Real gate identified: `NtDeviceIoControlFile` (FsCtlCode=0x74004) is `stub_success` at `crates/xenia-kernel/src/exports.rs:90`. Game-side `sub_824ABD88:0x824abea8-ac` reads `[out_buf+8]` of the IOCTL response, finds zero (stub doesn't write OUT), assigns hardcoded `0xC0000034` (STATUS_OBJECT_NAME_NOT_FOUND); caller `sub_824A9710` exits at `0x824a9944` before priv-11. Tier 4 entries remain parked, classification unchanged (still REAL_BUT_UNREACHED), awaiting KRNBUG-IO-003. See `project_xenia_rs_audit_007_branch_probe_2026_05_04.md` for the runtime trace + decisive proof.**
|
||||
|
||||
- Prior status: **PARTIAL — KRNBUG-IO-002 landed, but predicted cascade did NOT fire (7 → 7). Tier 0 marked superseded; Tier 4 entries STILL parked. Re-audit needed to find the real upstream gate.**
|
||||
- Pre-state: master HEAD `556a8c3`, exports diff captured 2026-05-04
|
||||
- Post-IO-002 state: branch `xboxkrnl-vol-allocunit/p0-65536-cluster`, fresh 500 M trace at `audit-runs/post-IO-002/`. Canary-only kernel exports remain identical: `{ExTerminateThread, KeReleaseSemaphore, KeResetEvent, ObCreateSymbolicLink, XamTaskCloseHandle, XamTaskSchedule, XamUserReadProfileSettings}`.
|
||||
- Inputs:
|
||||
- `canary.log` (348720 B, identical to audit-005 oracle, canary build `9467c77f0`)
|
||||
- `ours.log` (692 MB, 5.6 M trace lines, run at 17:20–17:21 today, post-IO-001)
|
||||
- Tooling: `diff.py` + plain `comm -23` set-difference on extracted call names
|
||||
|
||||
## Headline finding
|
||||
|
||||
**7/7 canary-only entries classify as REAL_BUT_UNREACHED or STUB_BUT_UNREACHED.**
|
||||
Per the audit-006 spec stop condition ("if two-thirds of entries are
|
||||
REAL_BUT_UNREACHED, the problem isn't stubs — it's an upstream gate"),
|
||||
the next session should **NOT** pull a Tier-1 entry from this queue.
|
||||
Instead, it should fix the gate.
|
||||
|
||||
The gate is **KRNBUG-IO-002**: our `nt_query_volume_information_file`
|
||||
class-3 (FileFsSizeInformation) returns alloc_unit = 1 × 2048 = 2048,
|
||||
but Sylpheed's `main(1, 0x10000, 0xFF000)` expects alloc_unit = 65536
|
||||
(see `project_xenia_rs_io_nullfile_2026_05_04.md`).
|
||||
Sylpheed's verifier `sub_824ABA98` rejects 2048, propagates failure to
|
||||
`sub_824A9710`, which exits early before its `XexCheckExecutablePrivilege(0xB)`
|
||||
call site. Canary fires the priv-11 query *and* the entire downstream
|
||||
cluster (`XamTaskSchedule` → Cache0 callback thread → 0x100c worker spawn
|
||||
→ display-init pump → profile-settings cascade); we fire none of it.
|
||||
|
||||
Direct evidence (telemetry):
|
||||
- Our `XexCheckExecutablePrivilege` count = **1** (priv=0xA only).
|
||||
Canary count = **2** (priv=0xA + priv=0xB).
|
||||
- All 7 canary-only entries have ours-side count = **0** at -n 500M.
|
||||
- Our trace ends with main thread (hw=0) parked on `XNotifyGetNext +
|
||||
NtWaitForSingleObjectEx(0x10f4, lr=0x824ac578)` and hw=1 parked on
|
||||
`NtWaitForMultipleObjectsEx(lr=0x824ab214) + cs=0x828f3e70` —
|
||||
classic post-cache-recreate spin.
|
||||
- The 44 `NtWriteFile` calls in ours.log (cache zero-fill) are followed by
|
||||
more NtClose / NtCreateFile cycles, but `XexCheckExecutablePrivilege(0xB)`
|
||||
never fires → priv-11 site in `sub_824A9710` is unreached.
|
||||
- Memory's predicted `0xC000014F` does not yet appear in ours.log; first
|
||||
cache-related error is `0xC0000034` (OBJECT_NAME_NOT_FOUND) from
|
||||
`lr=0x824a97e4`. This still fits the gate hypothesis: the recreate path
|
||||
is reached, completes its writes, re-opens, queries volume info, and
|
||||
the *game-side* verifier rejects our reply silently (no kernel error).
|
||||
|
||||
---
|
||||
|
||||
## Tier 0 — upstream gate (SUPERSEDED 2026-05-04 — fix landed but cascade did NOT fire)
|
||||
|
||||
### KRNBUG-IO-002 — `nt_query_volume_information_file` block size — **LANDED, gate hypothesis FALSIFIED**
|
||||
|
||||
**Outcome:** the block-size literals at `exports.rs:1255-1256` were corrected
|
||||
to canary's NullDevice values (`sectors_per_unit=0x80, bytes_per_sector=0x200`,
|
||||
product `0x10000`). 591 → 592 tests, lockstep `instructions=100000010, swaps=2,
|
||||
draws=0` deterministic across two reruns (`audit-runs/post-IO-002/lock_n100m_run{1,2}.json`).
|
||||
sylpheed_n50m oracle still matches its existing golden (no observable change at -n 50M).
|
||||
|
||||
**However, the predicted cascade DID NOT fire.** Set-difference on a fresh
|
||||
500 M trace (`audit-runs/post-IO-002/ours.log`) produces the **identical**
|
||||
seven-entry canary-only set audit-006 captured pre-fix:
|
||||
|
||||
```
|
||||
ExTerminateThread, KeReleaseSemaphore, KeResetEvent,
|
||||
ObCreateSymbolicLink, XamTaskCloseHandle, XamTaskSchedule,
|
||||
XamUserReadProfileSettings
|
||||
```
|
||||
|
||||
`XexCheckExecutablePrivilege` count remains **1** (priv=0xA only, priv=0xB
|
||||
unreached). `XamTaskSchedule` count remains **0**. Worker thread spawns
|
||||
fell from 19 → 18 (within noise — single thread variance per call-site
|
||||
breakdown: `lr=0x824ac5f0×15 + 0x824cd984×1 + 0x824d2e68×2`). The 16
|
||||
NtQueryVolumeInformationFile call sites in `ours.log` all originate from
|
||||
a single LR `0x82611f38` — meaning the `audit-006` premise that
|
||||
`sub_824ABA98`/`sub_824A9710` consume the volume-info reply at the
|
||||
priv-11 gate may be **incorrect**, or the gate consumes a *different*
|
||||
information class entirely.
|
||||
|
||||
**Stop-condition triggered.** Per the IO-002 task brief, this session does
|
||||
not pivot to a second fix. The fix is correct (it makes our reply
|
||||
byte-identical to canary's NullDevice and survives every test we have);
|
||||
it is just not load-bearing for the priv-11 gate. The branch landed as a
|
||||
strict no-op at our current boot horizon — kept because it's correct and
|
||||
unblocks no regression.
|
||||
|
||||
**Next-session next gate hypothesis (untested):**
|
||||
- The audit-005 disasm of `sub_824ABA98` may have mis-attributed the consumer
|
||||
of bytes_per_sector. The IO-001 trace decisively located the failure at
|
||||
the `NtReadFile` inside `sub_824A9710`, not at any volume-info site.
|
||||
Re-read the `sub_824A9710` disasm with that in mind.
|
||||
- Volume-info LR `0x82611f38` is far downstream of the priv-10/priv-11
|
||||
cluster (the calls *complete* successfully — they don't gate anything
|
||||
visible). The actual gate may be `nt_query_information_file`,
|
||||
`nt_query_full_attributes_file`, an FsCtl IOCTL, or a different
|
||||
alloc-unit query path.
|
||||
- Per AUDIT-005 instrumentation, the priv-11 site at `sub_824A9710` PC
|
||||
cluster has **never fired** in any session. Probe `sub_824A9710` entry
|
||||
with `--pc-probe` and trace which conditional exits the function before
|
||||
the priv-11 query — that's the real gate.
|
||||
|
||||
---
|
||||
|
||||
### KRNBUG-IO-002 — `nt_query_volume_information_file` block size (original spec, kept for archaeology)
|
||||
|
||||
- **Where in our code:** `crates/xenia-kernel/src/exports.rs:1241-1269` (function
|
||||
`nt_query_volume_information_file`).
|
||||
- **Classification:** `REAL_BUT_BUGGY`. Registered at exports.rs:100, called
|
||||
16× in ours.log (16× in canary.log too — call counts match), returns
|
||||
`STATUS_SUCCESS`, but the FileFsSizeInformation payload is wrong.
|
||||
- **Bug:** class=3 branch writes `(total=0x100000, free=0,
|
||||
sectors_per_unit=1, bytes_per_sector=2048)`. Product = 2048 bytes per
|
||||
cluster.
|
||||
- **Canary reference:**
|
||||
- Entry function `NtQueryVolumeInformationFile_entry` at
|
||||
`xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_io_info.cc:323` (case
|
||||
`XFileFsSizeInformation` at lines 355–365). Canary delegates to per-device
|
||||
methods on `file->device()`.
|
||||
- `NullDevice` (the device backing `\Device\Harddisk0\Cache0`) returns
|
||||
`sectors_per_allocation_unit() = 0x80` and `bytes_per_sector() = 0x200`
|
||||
at `xenia-canary/src/xenia/vfs/devices/null_device.h:38-46`. Product =
|
||||
65536, matching Sylpheed's expectation.
|
||||
- Other device backings (HostPath, DiscImage, DiscZArchive) all return
|
||||
`(1, 0x200)` = 512. Sylpheed's first volume query at this site is
|
||||
against Cache0 (NullDevice), so the relevant value is 65536.
|
||||
- **Fix sketch (minimum):** in the class=3 branch, change the two writes to
|
||||
`mem.write_u32(info+16, 128); mem.write_u32(info+20, 512);` (and reduce
|
||||
TotalAllocationUnits accordingly so the disk size remains plausible —
|
||||
e.g. 0x10 units × 128 sectors × 512 bytes ≈ 1 MB, matching NullDevice).
|
||||
Total diff ≤ 4 lines.
|
||||
- **Fix sketch (proper, deferred until the cluster fires reliably):**
|
||||
introduce a per-handle device-info lookup so HostPath / DiscImage paths
|
||||
return their canary-correct values too. Skipped for now because Sylpheed
|
||||
only queries Cache0 at this gate.
|
||||
- **Expected observable post-fix:**
|
||||
- `XexCheckExecutablePrivilege` count: 1 → 2.
|
||||
- `XamTaskSchedule` count: 0 → 1 (callback=0x824A93C8, message=0x828A28F0).
|
||||
- `kernel.calls{XamTaskSchedule}` finally non-zero — closes the
|
||||
APUBUG-PRODUCER-001 / XAMBUG-PRODUCER-001 producer hunt that
|
||||
falsified XAudio + XamTaskSchedule producer hypotheses.
|
||||
- Spawn of the Cache0 callback thread (XThread::Execute thid 7 in
|
||||
canary, our equivalent to come).
|
||||
- Inside that thread: `StfsCreateDevice` (still undefined extern in
|
||||
canary too — does not block) + `ObCreateSymbolicLink` +
|
||||
`ExRegisterTitleTerminateNotification`.
|
||||
- Back on main: `KeResetEvent(0x8287094C)`, `NtCreateEvent`,
|
||||
`ExCreateThread(entry=0x82181830, ctx=0x828F3D08)` — and `0x82181830`
|
||||
is the worker entry for **dispatcher 0x100c**, one of the four
|
||||
parked-handle producers (per
|
||||
`project_xenia_rs_producer_stack_trace_2026_05_03.md`). Spawning
|
||||
that worker should advance handle 0x100c's `signal_attempts`
|
||||
counter off zero.
|
||||
- Eventually (further into the boot): `XamUserGetXUID`,
|
||||
`XamUserReadProfileSettings`, `XamContentCreateEnumerator`,
|
||||
`KeReleaseSemaphore` display-pump (268+ calls in canary at this
|
||||
horizon).
|
||||
- **Risk:** low. Two-line value change. NullDevice is the only device
|
||||
Sylpheed asks about at this gate; other devices are not yet hit.
|
||||
- **Effort:** trivial.
|
||||
- **Dependencies:** none. Land directly.
|
||||
- **Verification chain:** `cargo test -p xenia-kernel`,
|
||||
then `cargo run --release -p xenia-app -- exec sylpheed.iso -n 500_000_000`
|
||||
with kernel-call tracing on, then re-run audit-006's set-difference;
|
||||
expect canary-only count to drop from 7 toward 0 as the cluster fires.
|
||||
|
||||
---
|
||||
|
||||
## Tier 4 — REAL_BUT_UNREACHED / STUB_BUT_UNREACHED — do not fix yet
|
||||
|
||||
These are downstream of Tier 0. Reachability is blocked on KRNBUG-IO-002
|
||||
landing. After IO-002 lands, re-derive this list — most entries should
|
||||
have moved off, and any survivors will be classifiable on real evidence.
|
||||
|
||||
| # | Export | Ordinal | Library | Our state | Canary impl | Canary calls (at horizon) | Cascade rank |
|
||||
|---|--------|---------|---------|-----------|-------------|---------------------------|--------------|
|
||||
| 1 | `XamTaskSchedule` | 0x01AF | xam | REAL_BUT_UNREACHED (`xam_task_schedule`, xam.rs:213) | `xam_task.cc:43-80` | 1 (gate-pivot call) | upstream-of-cluster — fires the entire post-IO-002 cascade |
|
||||
| 2 | `XamTaskCloseHandle` | 0x01B1 | xam | STUB_BUT_UNREACHED (`stub_success`, xam.rs:33) | `xam_task.cc:83-93` (one-liner: `NtClose` + last-error) | 1 | low (cleanup after #1) |
|
||||
| 3 | `KeResetEvent` | 0x8F | xboxkrnl | REAL_BUT_UNREACHED (`ke_reset_event`, exports.rs:3172) | `xboxkrnl_threading.cc:566` | 1 | medium — clears 0x8287094C right before ExCreateThread(0x82181830) on main |
|
||||
| 4 | `ObCreateSymbolicLink` | 0x0103 | xboxkrnl | STUB_BUT_UNREACHED (`stub_success`, exports.rs:121) | `xboxkrnl_ob.cc:351` | 1 | low — Cache0-symlink registration; cosmetic for Sylpheed boot |
|
||||
| 5 | `KeReleaseSemaphore` | 0x88 | xboxkrnl | REAL_BUT_UNREACHED (`ke_release_semaphore`, exports.rs:3280) | `xboxkrnl_threading.cc:724` | 268 | high (in volume) — display-init pump on the post-cluster main loop |
|
||||
| 6 | `ExTerminateThread` | 0x19 | xboxkrnl | REAL_BUT_UNREACHED (`ex_terminate_thread`, exports.rs:312) | `xboxkrnl_threading.cc:173` | 2 | low — thread cleanup on Cache0 / profile threads |
|
||||
| 7 | `XamUserReadProfileSettings` | 0x0219 | xam | REAL_BUT_UNREACHED (`xam_user_read_profile_settings`, xam.rs:327) | `xam_user.cc:329` | 2 | medium — gates the `XamUserGetXUID → profile load` flow far downstream |
|
||||
|
||||
**Why every entry above is Tier 4 (not Tier 1):**
|
||||
|
||||
- Each entry's first call in `canary.log` falls **after** line 1210
|
||||
(`XamTaskSchedule(824A93C8, ...)`), which is the gate-pivot call.
|
||||
- Our trace contains zero of any of the seven, despite running 500 M
|
||||
instructions and reaching the post-cache-recreate horizon.
|
||||
- Six of the seven are already real implementations. The two stubs
|
||||
(`XamTaskCloseHandle`, `ObCreateSymbolicLink`) are minor cleanups; even
|
||||
upgrading them would not move boot progress until #1 (`XamTaskSchedule`)
|
||||
fires.
|
||||
- Therefore: fixing any of these in isolation is wasted effort. They
|
||||
should be re-classified after KRNBUG-IO-002 lands and the priv-11 /
|
||||
Cache0 callback chain runs.
|
||||
|
||||
---
|
||||
|
||||
## Tier 1 / 2 / 3 — empty for this audit
|
||||
|
||||
No entry qualifies as Tier 1 or Tier 2 in the current state. The single
|
||||
high-cascade fix worth pulling next is the Tier-0 gate (KRNBUG-IO-002),
|
||||
which is **not itself a canary-only export** — it's a wrong-value bug in
|
||||
an export both sides call, so the diff.py based set-difference doesn't
|
||||
surface it. That is exactly why audit-006 was scoped this way: to confirm
|
||||
the gate hypothesis from `project_xenia_rs_io_nullfile_2026_05_04.md`
|
||||
before another implementation session is started.
|
||||
|
||||
---
|
||||
|
||||
## Cross-check vs IO-001 snapshot
|
||||
|
||||
IO-001 memory recorded these 7 still-canary-only exports:
|
||||
> ExTerminateThread, KeReleaseSemaphore, KeResetEvent, ObCreateSymbolicLink,
|
||||
> XamTaskCloseHandle, XamTaskSchedule, XamUserReadProfileSettings.
|
||||
|
||||
Audit-006 set-difference produces the **identical** 7, in 1:1
|
||||
correspondence. No new canary-only export has appeared since IO-001
|
||||
landed; no entry has moved off. Cascade is still parked at the same gate.
|
||||
|
||||
The `XeCryptSha`, `XeKeysConsolePrivateKeySign`, and `NtDeviceIoControlFile`
|
||||
entries that IO-001 was credited with unblocking are confirmed: ours
|
||||
calls them 1, 1, 2 times respectively (canary calls them 1, 1, 2 — exact
|
||||
match). They are correctly off the canary-only list.
|
||||
|
||||
---
|
||||
|
||||
## Methodology notes
|
||||
|
||||
1. **"Cascade rank" definition:** estimated by where the export's first
|
||||
canary call falls in the boot sequence and how many downstream code
|
||||
paths depend on it. "high" = upstream-of-cluster (XamTaskSchedule).
|
||||
"medium" = intermediate (KeResetEvent, profile cascade).
|
||||
"low" = leaf cleanup or cosmetic (XamTaskCloseHandle, ObCreateSymbolicLink).
|
||||
Rank only matters once Tier 0 is landed; until then everything is parked.
|
||||
2. **Reachability oracle:** binary `grep -c "call=NAME"` against ours.log
|
||||
at -n 500M. Zero counts are conclusive for "unreached" because tracing
|
||||
is unconditional.
|
||||
3. **Canary log freshness:** the log is from 17:34 (3 h before this
|
||||
audit) but is byte-identical to audit-005's input — canary's behavior
|
||||
is deterministic given the same ROM and the canary build header
|
||||
(`canary_experimental@9467c77f0 on May 2 2026`) hasn't changed.
|
||||
Re-running through Lutris is unnecessary.
|
||||
4. **Gate confirmation:** memory predicted block-size mismatch as the
|
||||
IO-002 blocker; this audit confirmed it by eliminating the alternative
|
||||
(no Tier-1-eligible canary-only export exists in the current 7-entry
|
||||
list). The 0xC000014F status memory predicted is not yet visible in
|
||||
ours.log because the recreate path completes the writes — the
|
||||
verifier inside `sub_824ABA98` rejects the volume-info reply at the
|
||||
game level (no kernel error logged).
|
||||
5. **What this queue is *not*:** a list of fixes to land. The audit-006
|
||||
discipline was scoping; the discipline of subsequent sessions is to
|
||||
re-run audit-006's diff after IO-002, then either close audit-006 (if
|
||||
the cluster fires through and all 7 entries drop) or open audit-007
|
||||
on whatever new canary-only set surfaces.
|
||||
|
||||
---
|
||||
|
||||
## Recommended next session
|
||||
|
||||
**KRNBUG-IO-002 (block-size fix), one-shot.** Two-line edit at
|
||||
`crates/xenia-kernel/src/exports.rs:1255-1256`. Verify the cluster fires
|
||||
by re-running audit-006's set-difference; expect 7 → 0 (or close to 0)
|
||||
canary-only entries. If new entries surface in either direction, that's
|
||||
audit-007's input.
|
||||
|
||||
**Do not** open this queue's Tier 4 entries before IO-002 closes. Their
|
||||
classification is pending; their fix sketches will look very different
|
||||
once they're observably called and their actual return values can be
|
||||
compared to canary.
|
||||
@@ -1,131 +0,0 @@
|
||||
# AUDIT-059 — handle disambiguation (iterate 2.BD)
|
||||
|
||||
**Date:** 2026-06-06. **Engines:** ours `target/release/xenia-rs -n 50M` (3.9 s wall, 50M instr, 40k import calls), canary Wine `xenia_canary.exe --mute=true --audit_handle_lifecycle=true` (~35 s wall, 34k log lines, 0 fatals).
|
||||
|
||||
## Verdict — HANDOFF's wedge handles are stale
|
||||
|
||||
HANDOFF said: *"opt_callback signals 0x108c, tid=1 wedges on 0x10e8."* Both IDs are now `<UNCREATED>` in ours, along with `0x1090 / 0x10dc / 0x10fc / 0x1104` (also in HANDOFF's adjacent list). The allocation order shifted since that snapshot.
|
||||
|
||||
## Real wedges, current code state
|
||||
|
||||
| Handle | Kind | Engine state | Waiter | Notes |
|
||||
|---|---|---|---|---|
|
||||
| **0x12a4** | `<UNCREATED>` | `<AUDIT_BLIND>`, waiters=1 | **tid=1 main**, pc=0x824ac578 | Wait went via `do_wait_single` but creation never hit `NtCreateEvent` — `KeInitializeEvent` path. **This is the iterate-2.BC wedge** (recorded as "0x10e8" in HANDOFF — same site, different ID). |
|
||||
| **0x12ac** | Event/Auto | `<NO_SIGNALS_DESPITE_WAITS>`, waiters=1 | **tid=13** silph UI cluster, pc=0x824ac578 lr=0x821cb1e0 | Frame trail: `0x821cb1e0 → 0x821cbae0 → 0x821cc454 → 0x821c4f18 → 0x82174a80`. Frames 3-5 carry `silph::UImpl@GamePart_Title` / `silph::VGamePart_Title` vtables — **audit-049's cluster, unchanged**. |
|
||||
| 0x12b8 | Event/Auto | NO_SIGNALS, waiters=1 | (tid TBD) | Sibling, 0xC bytes from 0x12ac. |
|
||||
| 0x1020 | Event/Manual | NO_SIGNALS, waiters=1 | — | γ-class. |
|
||||
| 0x1040 | Event/Auto | NO_SIGNALS, waits=32 (hot poll) | — | Heavy wait, no signal. |
|
||||
| 0x10a8 | Event/Auto | NO_SIGNALS, waits=7 | — | γ-class. |
|
||||
| 0x10e4 | Event/Manual | NO_SIGNALS, waiters=1, waits=2 | — | γ-class. |
|
||||
|
||||
**Working handles** (sanity baseline): 0x1028 (Sema, 8 waits / 7 signals / 7 wakes), 0x10d0 (Sema, 2 waits / 1 signal / 1 wake), 0x10f0 (Event/Auto, 1/1/1 ✓ marked `<SUSPECT>` but actually fine), 0x10e0 (Event/Manual, 32 primary signals from somewhere).
|
||||
|
||||
## GPU interrupt delivery — the iterate-2.BC delta confirmed
|
||||
|
||||
| Engine | gpu.interrupt.delivered (vsync) | EmulateCPInterruptDPC / vblank pump |
|
||||
|---|---:|---:|
|
||||
| **ours** | 54 (source=0) + 1 (source=1) | — |
|
||||
| **canary** | — | **4712** in 30 s ≈ 157 Hz |
|
||||
|
||||
**~87× ratio.** Confirms HANDOFF's diagnosis: ours' victim-thread injector dies once guest threads all park; canary's host frame-limiter thread keeps firing regardless.
|
||||
|
||||
## Canary signaler attribution
|
||||
|
||||
Top KeSetEvent guest_ptrs in canary (30 s window):
|
||||
|
||||
| guest_ptr | KeSetEvent fires | Inferred role |
|
||||
|---|---:|---|
|
||||
| `0x828A3254` | 5729 | Audio host-pump worker (per AUDIT-032: `r3=0x828A3230` region) |
|
||||
| `0x828A3244` | 5728 | Audio host-pump sibling |
|
||||
| `0x828A3244` + 16-byte stride | — | Static XEX-image audio event struct |
|
||||
| `0xBCE25234` | 1301 | **silph UI cluster PKEVENT** (heap-allocated, 0x10 stride). Likely ours' 0x12ac analog. |
|
||||
| `0xBCE25214 / 0xBCE25244 / 0xBCE25224` | 648 / 603 / 603 | Sibling silph UI PKEVENTs (0x10 stride struct). Likely ours' 0x12a4 / 0x12b8 / 0x1040 analogs. |
|
||||
|
||||
Ours signals every one of those equivalents **0 times**.
|
||||
|
||||
## Round 2 — LR-extended probes name the producer
|
||||
|
||||
Extended the canary probes with guest-LR capture (5 sites in `xboxkrnl_threading.cc`, 10 LOC). Re-ran the harness. Now each `KeSetEvent` line carries the guest function that signaled the event. Result for the silph UI cluster:
|
||||
|
||||
| PKEVENT | KeSetEvent count | Producer LR(s) |
|
||||
|---|---:|---|
|
||||
| `0xBCE25214` | 574 | `0x82508510` (single producer) |
|
||||
| `0xBCE25224` | 565 | `0x82508358` (single producer) |
|
||||
| `0xBCE25234` | 1153 | `0x82506C90` (579) + `0x82508524` (574) |
|
||||
| `0xBCE25244` | 570 | `0x82506F9C` (single producer) |
|
||||
| `0xBCE25284` | 1 | `0x82507ABC` (one-shot 5th-worker init?) |
|
||||
|
||||
All 6 producer LRs sit in `0x82506000–0x82509000`. **This is exactly the `sub_825070F0` worker thread cluster** that audit-057/058 already named:
|
||||
|
||||
> *audit-057: "sub_825070F0 (4 missing, initializes 4 workers w/ shared ctx 0xBCE25340, entries 0x82506528/58/88/B8)"*
|
||||
|
||||
The 4 worker entries (`0x82506528/58/88/B8`) are inside `sub_82506xxx` — exactly where the producer LRs `0x82506C90`/`0x82506F9C` live. The other producer LRs `0x825083xx` / `0x825085xx` are in downstream callees (workers call deeper code which itself calls KeSetEvent).
|
||||
|
||||
For comparison the audio host-pump pair gets a single sharp producer too:
|
||||
- `0x828A3254` × 5271 ← `lr=0x824D2A44`
|
||||
- `0x828A3244` × 5271 ← `lr=0x824D292C`
|
||||
|
||||
(These match AUDIT-032's PC `0x824D229C / r3=0x828A3230` region — already-understood audio host-pump.)
|
||||
|
||||
## Verdict — 2.BE is INSUFFICIENT for the silph UI wedge
|
||||
|
||||
The silph UI PKEVENTs are signaled exclusively by threads spawned by `sub_825070F0`. Per audit-057/058, **`sub_825070F0` fires 0× in ours** — those 4 worker threads never spawn. Therefore the PKEVENTs are never signaled. Therefore tid=13 (`0x12ac` in ours) wedges forever.
|
||||
|
||||
**`sub_825070F0`'s call chain is gated by the audit-009 "unreachability island"** — a CRT-driven fnptr-array bootstrap that ours fails to enumerate. VSync delivery is irrelevant to that bootstrap; the host frame-limiter thread does not drive CRT initializers.
|
||||
|
||||
Therefore:
|
||||
- **2.BE alone CANNOT unwedge tid=13.** It will close the 54-vs-4712 VSync delivery gap and may unblock things downstream of vsync, but the silph UI wedge has an independent missing-signaler root cause.
|
||||
- **2.BE may still unwedge tid=1 main on `0x12a4`** — that wait went via `KeInitializeEvent` (handle never hit `NtCreateEvent` in ours, hence `<AUDIT_BLIND>`). Whether `0x12a4`'s signaler depends on VSync is unknown without further probing.
|
||||
|
||||
## Implications for next moves
|
||||
|
||||
A single fix won't take us to draws > 0. We need at least two:
|
||||
|
||||
1. **2.BE (VSync delivery)** — still worth landing for the architectural correctness it brings, AND because it's the only fix that can unwedge tid=1 main's `0x12a4` if that's vsync-derived. ~60–80 LOC per Agent C's plan.
|
||||
2. **2.BF (sub_825070F0 activation)** — this is the audit-058 unfinished business. Options:
|
||||
- (a) **Static work:** trace canary's CRT-driven fnptr-array path that activates the silph UI bootstrap; backport the missing init into ours. High info, slow. Requires more probing.
|
||||
- (b) **Direct synthetic spawn:** ours injects host-side `ExCreateThread` calls for the 4 worker entries at boot completion, mirroring AUDIT-048's audio-host-pump precedent. Pragmatic; ~40 LOC; risks getting context (`0xBCE25340`) wrong.
|
||||
|
||||
A possible third move:
|
||||
|
||||
3. **Re-probe with LR on Wait paths** (we already added it but didn't grep for it) — to tell us whether tid=1's wait on `0x12a4` is the same LR as `sub_825070F0`-chain or a totally different signaler. If different, it's a 3rd missing producer.
|
||||
|
||||
## Round 4 — wait-side guest LR via one-frame back-chain walk
|
||||
|
||||
After fixing the PPC stack-walk offset (Xbox 360 stores saved LR at `[prev_sp - 8]`, not the `+4` AIX convention), wait-side LR comes through cleanly.
|
||||
|
||||
**Canary's top wait sites:**
|
||||
|
||||
| canary handle | wait count | guest_lr | LR region | mapping |
|
||||
|---|---:|---|---|---|
|
||||
| `F800005C` | 1635 | `0x8216EE14` | kernel early-boot infra | unrelated |
|
||||
| `F800000C` | 1597 | `0x824AFFC4` | xboxkrnl wrapper (scheduler / work-queue?) | unrelated |
|
||||
| **`F80000DC`** | **476** | **`0x821C7D3C`** | **silph::UImpl/GamePart** | **= ours' 0x12ac silph UI wedge** |
|
||||
| `F80000B0` | 6 across | `0x821CBAE0` + `0x821CC19C` + `0x822DFE2x/D0` | **exact match with audit-049's frame trail** | sibling silph UI wait |
|
||||
|
||||
Identity proof: ours' audit-049 frame trail for the silph UI wedge was `0x821cb1e0 / 0x821cbae0 / 0x821cc454 / 0x821c4f18 / 0x82174a80`. Round 4 captures `0x821CBAE0` and `0x821CC19C` (adjacent PCs) as wait LRs in canary — same cluster, same code.
|
||||
|
||||
**Refined verdict.** ours' `0x12a4` (tid=1 main, AUDIT_BLIND) and `0x12ac` (tid=13 silph UI) are 8 bytes apart — likely sibling KEVENT fields in the same silph UI struct. canary's analogs are in the `F80000xx` namespace, similarly clustered. The single fix that addresses both:
|
||||
|
||||
> **2.BF (b)** — synthetic host-side spawn of `sub_825070F0`'s 4 workers at the audit-058-identified context (`0xBCE25340`), entries `0x82506528/58/88/B8`. Once those workers run, they signal the silph UI PKEVENT cluster, unwedging BOTH tid=1 main and tid=13 silph UI in one shot.
|
||||
|
||||
2.BE (host-driven VSync ISR delivery) becomes follow-on work after the UI bootstrap completes and frame pacing actually matters.
|
||||
|
||||
## Open questions for iterate 2.BD′ / 2.BE planning
|
||||
|
||||
1. **Does 2.BE alone unwedge tid=13?** Cheapest verification path: land 2.BE and re-run audit-059, see whether `0x12ac` signal count goes 0 → non-zero.
|
||||
2. **What is the LR-pattern of canary's `KeSetEvent guest_ptr=0xBCE25234` callers?** The current probe doesn't capture LR — extending the cvar to do so on a filtered subset would let us name the producer function in canary's namespace.
|
||||
3. **Does the GPU frame-limiter's CP interrupt actually walk into the silph UI cluster?** I.e., does `EmulateCPInterruptDPC` → `interrupt_callback` → guest code ever hit `sub_821CB030` or its callees? An LR probe inside `EmulateCPInterruptDPC` would answer this.
|
||||
|
||||
## Artifacts
|
||||
|
||||
- `canary.log` 2.2 MB / 34,095 lines / 32,977 AUDIT-HLC lines
|
||||
- `canary.stdout` 2.2 MB (duplicate of canary.log due to log_file fallback)
|
||||
- `canary.stderr` 8.4 KB (Wine diagnostics)
|
||||
- `ours.log` 479 lines (focus ledger + thread diagnostics + final state)
|
||||
- `ours.stderr` 317 lines (kernel-call counters)
|
||||
- `vkd3d-proton.cache.write` 15 KB (build artifact, ignored)
|
||||
|
||||
Commits in play (xenia-canary, fork-local only):
|
||||
- `03362b59f` cross-build-wine (cross-compile toolchain)
|
||||
- `d031d7c51` audit-handle-lifecycle-probes (this audit's probes)
|
||||
@@ -1,116 +0,0 @@
|
||||
# Round 34 — silph_ui_synth.rs (cluster B sibling) — DEFERRED PLAN
|
||||
|
||||
## Background
|
||||
|
||||
Rounds 23-33 drove γ-cluster #2 down to the actual gate: **`sub_821741C8`** (silph worker-dispatch loop) fires 0× in ours / 471× in canary (tid=6). It's invoked via dynamic vtable slot 9 from `sub_821752C0` thunk. The vtable writer is in the audit-050 unreachability island — there's no static caller chain to hook into.
|
||||
|
||||
The fix shape is a synth module analogous to `silph_synth.rs` (rounds 18-21):
|
||||
- Synthesize a singleton-like object with the right vtable
|
||||
- Spawn a guest thread at the right entry with this object as r3
|
||||
- Let the dispatch chain do the rest
|
||||
|
||||
Rounds 18-21 took 4 rounds to land cluster A's analog and ended at "workers run live but idle" because of missing foreign-pointer fields. Cluster B will face similar challenges.
|
||||
|
||||
## Sub-round breakdown (estimated 5-8 rounds)
|
||||
|
||||
### 34.α — Probe canary's dispatcher singleton (1 round)
|
||||
Capture canary's runtime state at `sub_821741C8` entry:
|
||||
- `r3 = 0xBCA44C00` (canary tid=6's dispatcher singleton)
|
||||
- Dump `r3..r3+0x80` to identify all fields
|
||||
- Note vtable address at `[r3+0]`
|
||||
|
||||
```bash
|
||||
WINEDEBUG=-all wine xenia_canary.exe --mute=true --audit_handle_lifecycle=true \
|
||||
--audit_jit_prolog_pc=0x821741C8 --audit_jit_prolog_r3_bytes=128 \
|
||||
--audit_jit_prolog_mem_dump=<vtable_va_from_r3+0> \
|
||||
...
|
||||
```
|
||||
|
||||
### 34.β — Probe full vtable layout (1 round)
|
||||
Read the vtable bytes statically from the PE (canary's `[r3+0]` IS a static XEX VA — same trick as round 21):
|
||||
- Read 32-64 slots from PE at file offset = vtable VA - 0x82000000
|
||||
- Confirm slot 9 = `sub_821C7CB8` and `vtable+0x24` thunk to `sub_821741C8`
|
||||
- Look at all other slots — do any reference deep guest code that needs more init?
|
||||
|
||||
Cross-reference each slot's DB reach. If a slot is the dispatcher's own method body, it'll be called from within the chain — needs to exist.
|
||||
|
||||
### 34.γ — Skeleton synth + thread spawn (1 round)
|
||||
Create `crates/xenia-kernel/src/silph_ui_synth.rs` mirroring `silph_synth.rs` structure:
|
||||
```rust
|
||||
pub fn spawn_silph_ui_dispatcher(state: &mut KernelState, mem: &GuestMemory, scheduler: &mut Scheduler) -> Result<u32, &'static str> {
|
||||
if state.silph_ui_synth_done { return Ok(state.silph_ui_synth_ctx); }
|
||||
|
||||
// Allocate ~0x100-0x200 bytes for the dispatcher singleton
|
||||
let ctx = state.heap_alloc(0x200, 16)?;
|
||||
mem.write_zeros(ctx, 0x200);
|
||||
|
||||
// Install static-XEX vtable at [+0]
|
||||
mem.write_u32(ctx + 0x00, VTABLE_VA); // discovered in 34.β
|
||||
|
||||
// Other init fields from 34.α dump
|
||||
// ...
|
||||
|
||||
// Spawn dispatcher thread at sub_821748F0 with r3=ctx
|
||||
scheduler.spawn(SpawnParams{
|
||||
entry: 0x821748F0,
|
||||
start_context: ctx,
|
||||
create_suspended: false,
|
||||
...
|
||||
})?;
|
||||
|
||||
state.silph_ui_synth_done = true;
|
||||
state.silph_ui_synth_ctx = ctx;
|
||||
Ok(ctx)
|
||||
}
|
||||
```
|
||||
|
||||
Hook point: first reach of `sub_821CB030` in the existing silph factory chain (the call site that should normally trigger this dispatcher's creation in canary).
|
||||
|
||||
Add 3-mode env gate: `XENIA_SILPH_UI_SYNTH={unset|=suspend|=1}`.
|
||||
|
||||
### 34.δ — Run + diagnose first crash (1 round)
|
||||
Almost certainly crashes on a NULL deref of one of the singleton's fields. Use round 19's pattern:
|
||||
- Probe at thread entry + early BB heads
|
||||
- Identify the offset that's accessed
|
||||
- Compare to canary's value at that offset
|
||||
|
||||
### 34.ε..η — Iterate on field fills (2-4 rounds)
|
||||
Each crash identifies one more required field. Fill it. Re-run. Continue until workers idle (verdict D analog).
|
||||
|
||||
### 34.θ — Producer-side seeding (1 round)
|
||||
Even with the dispatcher running, work-items may not flow. Per round 32 it's pool 3 that's starved (271 fires in canary). The producers are `sub_821CBEA8 / sub_821D24A0 / sub_821CD458` — they may need their own bootstrap. Probe what triggers them in canary.
|
||||
|
||||
## Verification at each stage
|
||||
|
||||
After every commit:
|
||||
- `cargo test --release --workspace` — 765/765 must pass
|
||||
- `XENIA_CACHE_PERSIST=1 XENIA_SILPH_UI_SYNTH=1 ./target/release/xenia-rs exec <ISO> -n 50000000 --trace-handles-focus=0x1218,0x1224,0x12a4,0x12ac`
|
||||
- Check:
|
||||
- No crash
|
||||
- `sub_821741C8` fires
|
||||
- `sub_82450b68` r4=3 fires increase
|
||||
- Handle 0x1224 / 0x1218 transition out of NO_SIGNALS_DESPITE_WAITS
|
||||
- Eventually: `VdSwap > 1, draws > 0`
|
||||
|
||||
## Risk register
|
||||
|
||||
- **High**: dispatcher singleton may require many more fields than the analog WorkerCtx (rounds 18-21 needed 8 KEVENTs + ring + descriptors + index table; UI dispatcher likely has similar scope)
|
||||
- **High**: foreign-arena pointers in canary's heap (similar to round 19's `[+0x28/+0x2C/+0x30]`) may need their own synthesis
|
||||
- **Medium**: cluster B's worker may itself spawn threads which need contexts which need... cascading scope
|
||||
- **Low**: workspace tests breaking (probe infrastructure is solid)
|
||||
- **Low**: existing iterate-2BE work regressing (it's on a separate branch)
|
||||
|
||||
## Off-ramps
|
||||
|
||||
If we hit a wall at any sub-round, the off-ramps are:
|
||||
1. Land the infrastructure as opt-in (rounds 18-21 pattern) and ship cluster A + cluster B both as opt-in env vars
|
||||
2. Drop cluster B entirely and PR the iterate-2BE work to master (production-ready architectural fix)
|
||||
3. Pivot to lockstep diff of inflate function (round 30 hypothesis (i)) if cluster B keeps producing crash-fix layers
|
||||
|
||||
## Branch plan
|
||||
|
||||
New branch: `iterate-2BF/silph-ui-synth` off `iterate-2BF/synthetic-silph-spawn` HEAD `40f208e`. Each sub-round = 1 commit. All commits opt-in via env var; default behavior unchanged.
|
||||
|
||||
## When ready to execute
|
||||
|
||||
Dispatch with the prompt at the round-33 agent's recommendation, starting at sub-round 34.α.
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,66 +0,0 @@
|
||||
AUDIT-PC-PROBE pc=0x8216ea68 tid=1 hw=0 cycle=5362918 lr=0x824ab8e0 r3=0x00000000 r11=0x00000000 [r3+0]=0x00000000 [[r3+0]+24]=0x00000000 [r3+0x0C]=0x00000000 [r3+0x30]=0x00000000
|
||||
AUDIT-PC-PROBE pc=0x822f1aa8 tid=1 hw=0 cycle=6181256 lr=0x8216ee14 r3=0x40d09a40 r11=0x40111910 [r3+0]=0x00000021 [[r3+0]+24]=0x00000000 [r3+0x0C]=0x40541a40 [r3+0x30]=0x00000000
|
||||
AUDIT-PC-PROBE pc=0x822f1b38 tid=1 hw=0 cycle=6181641 lr=0x822f1b38 r3=0x00000001 r11=0x824b0000 [r3+0]=0x00000000 [[r3+0]+24]=0x00000000 [r3+0x0C]=0x00000000 [r3+0x30]=0x00000000
|
||||
AUDIT-PC-PROBE pc=0x821746b0 tid=1 hw=0 cycle=9229300 lr=0x82173c38 r3=0x40ba9a80 r11=0x00000000 [r3+0]=0x40111910 [[r3+0]+24]=0x00000000 [r3+0x0C]=0x00000000 [r3+0x30]=0x00000000
|
||||
AUDIT-PC-PROBE pc=0x821748f0 tid=13 hw=1 cycle=0 lr=0xbcbcbcbc r3=0x4024a840 r11=0x00000000 [r3+0]=0x40ba9a80 [[r3+0]+24]=0x00000000 [r3+0x0C]=0x00000000 [r3+0x30]=0x4250dec0
|
||||
|
||||
=== Final State ===
|
||||
PC: 0x00000000
|
||||
LR: 0xbcbcbcbc
|
||||
CTR: 0x00000000
|
||||
CR: 0x00000000
|
||||
XER: CA=0 OV=0 SO=0
|
||||
|
||||
=== Thread diagnostics ===
|
||||
hw=0 idx=0 tid=1 state=Blocked(WaitAny { handles: [4208], deadline: None }) pc=0x824ac578 lr=0x824ac578 sp=0x700ff6e0
|
||||
r0=0x82153bf0 r3=0x00000000 r4=0x00000001 r5=0x00000000 r6=0x00000000 r7=0x03a72328
|
||||
r8=0x43b77284 r9=0x43b77328 r10=0x00000001 r11=0x00000103 r12=0x82173c64 r13=0x7fff0000
|
||||
hw=0 idx=1 tid=11 state=Blocked(WaitAny { handles: [2190094916, 2190094880], deadline: None }) pc=0x824d2a94 lr=0x824d2a94 sp=0x71497d90
|
||||
r0=0x00000000 r3=0x00000000 r4=0x71497de0 r5=0x00000001 r6=0x00000003 r7=0x00000001
|
||||
r8=0x00000000 r9=0x00000000 r10=0x71497df0 r11=0x828a3244 r12=0xbcbcbcbc r13=0x4b9f1000
|
||||
hw=1 idx=0 tid=2 state=Blocked(WaitAny { handles: [2189887804], deadline: None }) pc=0x824a95f8 lr=0x824a95f8 sp=0x710ffd20
|
||||
r0=0x0000030c r3=0x00000000 r4=0x00000003 r5=0x00000001 r6=0x00000000 r7=0x00000000
|
||||
r8=0x00000001 r9=0x6f000000 r10=0x824a9178 r11=0x82870000 r12=0x824a94f0 r13=0x4acc3000
|
||||
hw=1 idx=1 tid=13 state=Blocked(WaitAny { handles: [4216], deadline: None }) pc=0x824ac578 lr=0x824ac578 sp=0x715a7a20
|
||||
r0=0x821511d0 r3=0x00000000 r4=0x00000001 r5=0x00000000 r6=0x00000000 r7=0x03a723d0
|
||||
r8=0x43b77334 r9=0x43b77334 r10=0x40541f80 r11=0x00000001 r12=0x821cb1e0 r13=0x4d1d4000
|
||||
hw=2 idx=0 tid=7 state=Blocked(WaitAny { handles: [1111821148], deadline: Some(42946672) }) pc=0x824cd4f4 lr=0x824cd4f4 sp=0x71187e60
|
||||
r0=0x00000000 r3=0x00000000 r4=0x00000003 r5=0x00000001 r6=0x00000000 r7=0x71187eb0
|
||||
r8=0x00000000 r9=0x00000000 r10=0x00000002 r11=0x00000002 r12=0xbcbcbcbc r13=0x4b1d6000
|
||||
hw=2 idx=1 tid=8 state=Blocked(WaitAny { handles: [4176, 4128], deadline: None }) pc=0x824ab214 lr=0x824ab214 sp=0x71287c90
|
||||
r0=0x00000000 r3=0x00000000 r4=0x71287cf0 r5=0x00000001 r6=0x00000001 r7=0x00000000
|
||||
r8=0x00000000 r9=0x00009030 r10=0x00000002 r11=0x00000020 r12=0x822f1ff0 r13=0x4b90a000
|
||||
hw=3 idx=0 tid=4 state=Blocked(WaitAny { handles: [4120], deadline: None }) pc=0x824ac578 lr=0x824ac578 sp=0x7112fb80
|
||||
r0=0x821511a0 r3=0x00000000 r4=0x00000001 r5=0x00000000 r6=0x00000000 r7=0x03a723d0
|
||||
r8=0x43b7732c r9=0x828f0000 r10=0x00000008 r11=0x00000000 r12=0x8245a660 r13=0x4adc6000
|
||||
hw=3 idx=1 tid=5 state=Blocked(WaitAny { handles: [4224], deadline: None }) pc=0x824ac578 lr=0x824ac578 sp=0x7116fbe0
|
||||
r0=0x821511a0 r3=0x00000000 r4=0x00000001 r5=0x00000000 r6=0x00000000 r7=0x03a723d0
|
||||
r8=0x43b7732c r9=0x828f0000 r10=0x00000001 r11=0x00000000 r12=0x82458b34 r13=0x4adc8000
|
||||
hw=4 idx=0 tid=9 state=Ready pc=0x824d140c lr=0x824d22b4 sp=0x71387df0
|
||||
r0=0x00000000 r3=0x4250dedc r4=0x4250e040 r5=0x00000001 r6=0x00000000 r7=0x00000000
|
||||
r8=0x4b9ec000 r9=0x01010000 r10=0x01010000 r11=0x00000000 r12=0x824d22a8 r13=0x4b9ec000
|
||||
hw=5 idx=0 tid=3 state=Blocked(WaitAny { handles: [4112], deadline: None }) pc=0x824ac578 lr=0x824ac578 sp=0x7111fdf0
|
||||
r0=0x82153bf0 r3=0x00000000 r4=0x00000001 r5=0x00000000 r6=0x00000000 r7=0x00000a10
|
||||
r8=0x00000010 r9=0x00000000 r10=0x00009030 r11=0x00000000 r12=0x82181988 r13=0x4adc4000
|
||||
hw=5 idx=1 tid=6 state=Ready pc=0x824ab214 lr=0x824ab214 sp=0x7117fc60
|
||||
r0=0x821511a0 r3=0x00000001 r4=0x7117fcc0 r5=0x00000001 r6=0x00000001 r7=0x00000000
|
||||
r8=0x7117fcb0 r9=0x00009030 r10=0x00000002 r11=0x00000020 r12=0x82458d68 r13=0x4adca000
|
||||
hw=5 idx=2 tid=10 state=Ready pc=0x824d1404 lr=0x824d22b4 sp=0x71487e00
|
||||
r0=0x00000000 r3=0x4250dedc r4=0x4250e040 r5=0x00000001 r6=0x00000000 r7=0x00000000
|
||||
r8=0x4b9ee000 r9=0x01010000 r10=0x01010000 r11=0x00000000 r12=0x824d22a8 r13=0x4b9ee000
|
||||
hw=5 idx=3 tid=12 state=Ready pc=0x824aa6a4 lr=0x824aa6a4 sp=0x714a7da0
|
||||
r0=0x00000000 r3=0x000000ff r4=0x00000020 r5=0x714a7df4 r6=0x00000000 r7=0x00000000
|
||||
r8=0x00000000 r9=0x00000000 r10=0x00000000 r11=0x00000001 r12=0x8217898c r13=0x4d1d2000
|
||||
|
||||
-- Handle waiter lists --
|
||||
handle=0x00001020 Semaphore(0/2147483647) waiters(tid)=[8]
|
||||
handle=0x42450b5c Event(sig=false, mr=true) waiters(tid)=[7]
|
||||
handle=0x828a3244 Event(sig=false, mr=false) waiters(tid)=[11]
|
||||
handle=0x00001018 Semaphore(0/2147483647) waiters(tid)=[4]
|
||||
handle=0x8287093c Event(sig=false, mr=false) waiters(tid)=[2]
|
||||
handle=0x00001070 Thread(id=13, exit=None) waiters(tid)=[1]
|
||||
handle=0x00001080 Event(sig=false, mr=false) waiters(tid)=[5]
|
||||
handle=0x00001078 Event(sig=false, mr=false) waiters(tid)=[13]
|
||||
handle=0x828a3220 Event(sig=false, mr=true) waiters(tid)=[11]
|
||||
handle=0x00001050 Event(sig=false, mr=true) waiters(tid)=[8]
|
||||
handle=0x00001010 Event(sig=false, mr=true) waiters(tid)=[3]
|
||||
@@ -1,167 +0,0 @@
|
||||
# Round-A1..A4 findings — canary tid=6 spawn chain & divergence frontier
|
||||
|
||||
## Anchor reframe (round-37 misread corrected)
|
||||
|
||||
The "factory/registry layer divergence at [0x828E1F08]" framing is falsified.
|
||||
Both engines install the SAME static-XEX `.rdata` vtable `0x820A183C` at the
|
||||
singleton's `[+0]`. The instance VAs differ only because of ε-class allocator
|
||||
divergence (audit-043).
|
||||
|
||||
| Probe | Canary | Ours |
|
||||
|----------------------------|----------------------|----------------------|
|
||||
| `[0x828E1F08]` | 0xBC22C910 (heap) | 0x40111910 (heap) |
|
||||
| `[[0x828E1F08]+0]` vtable | 0x820A183C | 0x820A183C (SAME) |
|
||||
| `vtable[+0]` thunk | 0x82175330 | 0x82175330 (SAME) |
|
||||
| `vtable[+8]` thunk | 0x82175340 → b sub_821741C8 | SAME (vtable bytes from XEX `.rdata`) |
|
||||
|
||||
The thunks at 0x82175330+ are 8-byte `lwz r3, 8(r3); b <real_method>`
|
||||
trampolines. Slot 2 (`+0x08`) is the worker dispatch entry that round 33
|
||||
identified as 471× in canary tid=6 / 0× in ours.
|
||||
|
||||
## A.1 — Canary dispatcher loop is in sub_822F1AA8 on tid=6
|
||||
|
||||
Probe `--audit_jit_prolog_pc=0x821741C8 --audit_jit_prolog_r3_bytes=256` on
|
||||
canary (35 s):
|
||||
|
||||
- ~1678 fires of sub_821741C8 on **tid=6**
|
||||
- r3 at entry = `0xBCCC4A80` (the inner sub-object of the silph::UImpl
|
||||
singleton — extracted via the thunk's `lwz r3, 8(r3)`)
|
||||
- LR at entry = `0x822F1D5C` (return PC after the `bctrl` at 0x822F1D58 inside
|
||||
sub_822F1AA8)
|
||||
- Singleton's `[+C0..+D0]` UTF-16 spells "HF Frequency" (a UI label)
|
||||
|
||||
The dispatch site in canary (the `bctrl`) is at PC 0x822F1D58 inside
|
||||
sub_822F1AA8:
|
||||
```
|
||||
0x822F1D40: lwz r3, 7944(r25) ; r3 = [r25+0x1F08] = [0x828E1F08]
|
||||
0x822F1D4C: lwz r11, 0(r3) ; vtable
|
||||
0x822F1D50: lwz r11, 8(r11) ; vtable[+8] = thunk 0x82175340
|
||||
0x822F1D54: mtctr r11
|
||||
0x822F1D58: bctrl ; → 0x82175340 → b 0x821741C8
|
||||
```
|
||||
|
||||
## A.2 — Canary tid=6 spawn site is sub_821746B0 at PC 0x82174824
|
||||
|
||||
Enumeration of `ExCreateThread` calls in canary (35 s, 21 unique tuples):
|
||||
|
||||
```
|
||||
entry=821748F0 start_ctx=BC365700 lr=824AC5F0 guest_lr=82174828 ← silph dispatcher #1
|
||||
entry=821748F0 start_ctx=BC366DA0 lr=824AC5F0 guest_lr=82174828 ← silph dispatcher #2
|
||||
```
|
||||
|
||||
PC `0x82174824` is the `bl 0x82172370` (the `ExCreateThread` thunk) inside
|
||||
`sub_821746B0`. The setup is:
|
||||
```
|
||||
0x8217480C: lis r11, 0x8217
|
||||
0x82174810: li r7, 0
|
||||
0x82174814: li r6, 4 ; priority
|
||||
0x82174818: mr r5, r29 ; start_ctx
|
||||
0x8217481C: addi r4, r11, 18672 ; r4 = 0x821748F0 (entry)
|
||||
0x82174820: li r3, 0
|
||||
0x82174824: bl 0x82172370 ; ExCreateThread
|
||||
```
|
||||
|
||||
The entry `0x821748F0` is a thread main that calls `bl 0x821749C0` (the
|
||||
inner dispatch).
|
||||
|
||||
## A.3 — sub_822F1AA8 spawns a SECOND thread at 0x822F1B08
|
||||
|
||||
The dispatch-loop function `sub_822F1AA8` itself ALSO spawns a thread at
|
||||
PC 0x822F1B08 with entry=`sub_822F1EE0` and `start_ctx=BCE24A40`:
|
||||
```
|
||||
0x822F1AEC: lis r11, 0x822F
|
||||
0x822F1AFC: addi r4, r11, 7904 ; r4 = 0x822F1EE0
|
||||
0x822F1B08: bl 0x82172370 ; ExCreateThread
|
||||
```
|
||||
|
||||
sub_822F1EE0 → sub_822F1F20 contains its own atomic state-machine + wait loop.
|
||||
|
||||
## A.3' — sub_822F1AA8 has exactly 2 callers, both in sub_8216EA68
|
||||
|
||||
```
|
||||
source=0x8216ECCC source_func=0x8216EA68 kind=call
|
||||
source=0x8216EE10 source_func=0x8216EA68 kind=call
|
||||
```
|
||||
|
||||
So sub_8216EA68 is the only function that drives sub_822F1AA8.
|
||||
|
||||
## A.4 — Ours' divergence is INSIDE the spawned thread, NOT at the spawn
|
||||
|
||||
Mirror-probed ours at `sub_821746B0` body BB heads (parallel mode, 50M
|
||||
instructions, XENIA_CACHE_PERSIST=1):
|
||||
|
||||
| PC | Fires | Notes |
|
||||
|-------------|-------|------------------------------------------------|
|
||||
| 0x821746B0 | 1 | Entry. r3=0x40ba9a80 |
|
||||
| 0x821746E0 | 1 | After `bl 0x8284DCFC` (critical-section) |
|
||||
| 0x82174798 | 1 | After the early `beq` (r28==0 branch) |
|
||||
| 0x821747B8 | 1 | **Past the gate**: `[0x828E2B14]=0x40105000` non-NULL; `bl 0x82150EF8` returned r3=0x4024a840 (NON-NULL) |
|
||||
| 0x821747D8 | 1 | After the inner `bl 0x821723F0` |
|
||||
| 0x8217480C | 1 | Enters the spawn block |
|
||||
| 0x82174828 | 1 | **Post-`bl ExCreateThread`**, r3=0x1070 = thread handle |
|
||||
|
||||
**OURS DOES SPAWN THE THREAD VIA THIS SITE.** The returned handle 0x1070 is
|
||||
**tid=13's thread handle** (per round 37 final state). So **ours' tid=13 IS
|
||||
the same logical thread as canary's tid=6** — spawned by the identical call
|
||||
site with the same entry (0x821748F0).
|
||||
|
||||
## A.4 — Divergence is INSIDE the spawned thread's body
|
||||
|
||||
Round 37's frame trail for ours' tid=13 wedge:
|
||||
`0x821CB1E0 → 0x821CBAE0 → 0x821CC454 → 0x821C4F18 → 0x82174A80`
|
||||
|
||||
The LAST frame `0x82174A80` is **inside sub_821749C0** (= the inner dispatch
|
||||
called from sub_821748F0). It's right after the vtable dispatch at
|
||||
0x82174A78 (`bctrl` on `[r30+vtable][+16]`):
|
||||
|
||||
```
|
||||
0x82174a64: mr r3, r30 ; r3 = some object
|
||||
0x82174a68: lwz r11, 0(r30)
|
||||
0x82174a6c: lwz r4, 4(r29)
|
||||
0x82174a70: lwz r5, 8(r31)
|
||||
0x82174a74: lwz r11, 16(r11) ; r11 = vtable[+0x10]
|
||||
0x82174a78: mtctr r11
|
||||
0x82174a7c: bctrl ; dispatch
|
||||
0x82174a80: lwz r3, 0(r29) ; ← wedge frame top (LR after bctrl)
|
||||
```
|
||||
|
||||
So `sub_821749C0`'s vtable[+0x10] dispatch on tid=13/tid=6's `r30` object
|
||||
lands at audit-049 territory in ours (chain through sub_821CB030+0x128 that
|
||||
ends waiting forever on handle 0x1078). In canary, the same dispatch on the
|
||||
same object SHOULD land somewhere that ultimately reaches sub_822F1AA8's
|
||||
dispatch loop and runs sub_821741C8 1678× via vtable[+8].
|
||||
|
||||
**The object `r30` is the result of `bl 0x821CF3F0`** at PC 0x821749DC. So
|
||||
sub_821CF3F0 returns a registry-lookup object; the vtable on this object's
|
||||
slot +0x10 method's body determines whether the thread wedges or runs.
|
||||
|
||||
## Phase B classification
|
||||
|
||||
Class 3 — **Missing init-time precondition**. Ours reaches the spawn site,
|
||||
ours' tid=13 enters the chain, ours' tid=13 enters sub_821749C0, but the
|
||||
vtable[+0x10] dispatch at PC 0x82174A78 in ours lands in audit-049 territory
|
||||
(wait forever on 0x1078) rather than continuing through the canonical chain
|
||||
toward sub_822F1AA8's outer dispatch loop.
|
||||
|
||||
Possible classes to refine in next round:
|
||||
- **3a**: same vtable but state-dependent — `r30`'s field at a specific offset
|
||||
differs in ours vs canary, causing the method body to take a different
|
||||
branch.
|
||||
- **3b**: the vtable in `r30` is DIFFERENT in ours vs canary (e.g., ours has
|
||||
a base-class vtable but canary has a derived-class vtable).
|
||||
- **4**: synthesis fallback — spawn a SECOND thread that runs sub_822F1AA8's
|
||||
dispatch loop directly, bypassing the wedged sub_821749C0 chain.
|
||||
|
||||
## Next probe (A.4.5)
|
||||
|
||||
Probe both engines at sub_821749C0 entry filtering tid=13 (ours) / tid=6
|
||||
(canary), capturing:
|
||||
- `r3` and `r4` at entry (the factory-output object and the ctx)
|
||||
- After the `bl 0x821CF3F0` at 0x821749DC: capture r30 (= sub_821CF3F0
|
||||
return — the object whose vtable is dispatched at 0x82174A78)
|
||||
- At PC 0x82174A78 (the divergent bctrl): r30 + r30+0 (vtable) + vtable[+0x10]
|
||||
(the dispatch target)
|
||||
|
||||
If ours and canary have IDENTICAL `vtable[+0x10]` targets but the method
|
||||
body's behavior differs → class 3a (state divergence). If targets differ →
|
||||
class 3b (vtable identity divergence).
|
||||
@@ -1,91 +0,0 @@
|
||||
AUDIT-PC-PROBE pc=0x821746b0 tid=1 hw=0 cycle=9228833 lr=0x82173c38 r3=0x40ba9a80 r11=0x00000000 [r3+0]=0x40111910 [[r3+0]+24]=0x00000000 [r3+0x0C]=0x00000000 [r3+0x30]=0x00000000
|
||||
AUDIT-MEM-READ addr=0x828e2b14 val=0x40105000 vtable=0x40105004 vtable[0]=0x40105008 vtable[24]=0x40105020 pc=0x821746b0 tid=1 cycle=9228833
|
||||
AUDIT-PC-PROBE pc=0x821746e0 tid=1 hw=0 cycle=9228856 lr=0x821746e0 r3=0x00000000 r11=0x00000000 [r3+0]=0x00000000 [[r3+0]+24]=0x00000000 [r3+0x0C]=0x00000000 [r3+0x30]=0x00000000
|
||||
AUDIT-MEM-READ addr=0x828e2b14 val=0x40105000 vtable=0x40105004 vtable[0]=0x40105008 vtable[24]=0x40105020 pc=0x821746e0 tid=1 cycle=9228856
|
||||
AUDIT-PC-PROBE pc=0x82174798 tid=1 hw=0 cycle=9228859 lr=0x821746e0 r3=0x00000000 r11=0x00000000 [r3+0]=0x00000000 [[r3+0]+24]=0x00000000 [r3+0x0C]=0x00000000 [r3+0x30]=0x00000000
|
||||
AUDIT-MEM-READ addr=0x828e2b14 val=0x40105000 vtable=0x40105004 vtable[0]=0x40105008 vtable[24]=0x40105020 pc=0x82174798 tid=1 cycle=9228859
|
||||
AUDIT-PC-PROBE pc=0x821747b8 tid=1 hw=0 cycle=9229012 lr=0x821747ac r3=0x4024a840 r11=0x4024a840 [r3+0]=0x4024ace0 [[r3+0]+24]=0x43777290 [r3+0x0C]=0x4024a820 [r3+0x30]=0x4250dec0
|
||||
AUDIT-MEM-READ addr=0x828e2b14 val=0x40105000 vtable=0x40105004 vtable[0]=0x40105008 vtable[24]=0x40105020 pc=0x821747b8 tid=1 cycle=9229012
|
||||
AUDIT-PC-PROBE pc=0x821747d8 tid=1 hw=0 cycle=9229440 lr=0x821747cc r3=0x4024a840 r11=0xffffffff [r3+0]=0x40ba9a80 [[r3+0]+24]=0x00000000 [r3+0x0C]=0x00000000 [r3+0x30]=0x4250dec0
|
||||
AUDIT-MEM-READ addr=0x828e2b14 val=0x40105000 vtable=0x40105004 vtable[0]=0x40105008 vtable[24]=0x40105020 pc=0x821747d8 tid=1 cycle=9229440
|
||||
AUDIT-PC-PROBE pc=0x8217480c tid=1 hw=0 cycle=9229443 lr=0x821747cc r3=0x4024a840 r11=0xffffffff [r3+0]=0x40ba9a80 [[r3+0]+24]=0x00000000 [r3+0x0C]=0x00000000 [r3+0x30]=0x4250dec0
|
||||
AUDIT-MEM-READ addr=0x828e2b14 val=0x40105000 vtable=0x40105004 vtable[0]=0x40105008 vtable[24]=0x40105020 pc=0x8217480c tid=1 cycle=9229443
|
||||
AUDIT-PC-PROBE pc=0x82174828 tid=1 hw=0 cycle=9229509 lr=0x82174828 r3=0x00001070 r11=0x824b0000 [r3+0]=0x00000000 [[r3+0]+24]=0x00000000 [r3+0x0C]=0x00000000 [r3+0x30]=0x00000000
|
||||
AUDIT-MEM-READ addr=0x828e2b14 val=0x40105000 vtable=0x40105004 vtable[0]=0x40105008 vtable[24]=0x40105020 pc=0x82174828 tid=1 cycle=9229509
|
||||
|
||||
=== Final State ===
|
||||
PC: 0x824ac578
|
||||
LR: 0x824ac578
|
||||
CTR: 0x82153bf0
|
||||
CR: 0x24000028
|
||||
XER: CA=0 OV=0 SO=0
|
||||
r0 : 0x0000000082153bf0
|
||||
r1 : 0x00000000700ff6e0
|
||||
r2 : 0x0000000020000000
|
||||
r4 : 0x0000000000000001
|
||||
r7 : 0x0000000003a72328
|
||||
r8 : 0x0000000043b77284
|
||||
r9 : 0x0000000043b77328
|
||||
r10: 0x0000000000000001
|
||||
r11: 0x0000000000000103
|
||||
r12: 0x0000000082173c64
|
||||
r13: 0x000000007fff0000
|
||||
r18: 0x0000000040d09a7c
|
||||
r23: 0x00000000828f3844
|
||||
r26: 0x000000004024a620
|
||||
r27: 0x00000000820a17a8
|
||||
r31: 0x0000000000001070
|
||||
|
||||
=== Thread diagnostics ===
|
||||
hw=0 idx=0 tid=1 state=Blocked(WaitAny { handles: [4208], deadline: None }) pc=0x824ac578 lr=0x824ac578 sp=0x700ff6e0
|
||||
r0=0x82153bf0 r3=0x00000000 r4=0x00000001 r5=0x00000000 r6=0x00000000 r7=0x03a72328
|
||||
r8=0x43b77284 r9=0x43b77328 r10=0x00000001 r11=0x00000103 r12=0x82173c64 r13=0x7fff0000
|
||||
hw=0 idx=1 tid=11 state=Blocked(WaitAny { handles: [2190094916, 2190094880], deadline: None }) pc=0x824d2a94 lr=0x824d2a94 sp=0x71497d90
|
||||
r0=0x00000000 r3=0x00000000 r4=0x71497de0 r5=0x00000001 r6=0x00000003 r7=0x00000001
|
||||
r8=0x00000000 r9=0x00000000 r10=0x71497df0 r11=0x828a3244 r12=0xbcbcbcbc r13=0x4b9f1000
|
||||
hw=1 idx=0 tid=2 state=Blocked(WaitAny { handles: [2189887804], deadline: None }) pc=0x824a95f8 lr=0x824a95f8 sp=0x710ffd20
|
||||
r0=0x0000030c r3=0x00000000 r4=0x00000003 r5=0x00000001 r6=0x00000000 r7=0x00000000
|
||||
r8=0x00000001 r9=0x6f000000 r10=0x824a9178 r11=0x82870000 r12=0x824a94f0 r13=0x4acc3000
|
||||
hw=1 idx=1 tid=13 state=Blocked(WaitAny { handles: [4216], deadline: None }) pc=0x824ac578 lr=0x824ac578 sp=0x715a7a20
|
||||
r0=0x821511d0 r3=0x00000000 r4=0x00000001 r5=0x00000000 r6=0x00000000 r7=0x03a723d0
|
||||
r8=0x43b77334 r9=0x43b77334 r10=0x40541f80 r11=0x00000001 r12=0x821cb1e0 r13=0x4d1d4000
|
||||
hw=2 idx=0 tid=7 state=Blocked(WaitAny { handles: [1111821148], deadline: Some(42946672) }) pc=0x824cd4f4 lr=0x824cd4f4 sp=0x71187e60
|
||||
r0=0x00000000 r3=0x00000000 r4=0x00000003 r5=0x00000001 r6=0x00000000 r7=0x71187eb0
|
||||
r8=0x00000000 r9=0x00000000 r10=0x00000002 r11=0x00000002 r12=0xbcbcbcbc r13=0x4b1d6000
|
||||
hw=2 idx=1 tid=8 state=Blocked(WaitAny { handles: [4176, 4132], deadline: None }) pc=0x824ab214 lr=0x824ab214 sp=0x71287c90
|
||||
r0=0x00000000 r3=0x00000000 r4=0x71287cf0 r5=0x00000001 r6=0x00000001 r7=0x00000000
|
||||
r8=0x00000000 r9=0x00009030 r10=0x00000002 r11=0x00000020 r12=0x822f1ff0 r13=0x4b90a000
|
||||
hw=3 idx=0 tid=4 state=Blocked(WaitAny { handles: [4120], deadline: None }) pc=0x824ac578 lr=0x824ac578 sp=0x7112fb80
|
||||
r0=0x821511a0 r3=0x00000000 r4=0x00000001 r5=0x00000000 r6=0x00000000 r7=0x03a723d0
|
||||
r8=0x43b7732c r9=0x828f0000 r10=0x00000008 r11=0x00000000 r12=0x8245a660 r13=0x4adc6000
|
||||
hw=3 idx=1 tid=5 state=Blocked(WaitAny { handles: [4224], deadline: None }) pc=0x824ac578 lr=0x824ac578 sp=0x7116fbe0
|
||||
r0=0x821511a0 r3=0x00000000 r4=0x00000001 r5=0x00000000 r6=0x00000000 r7=0x03a723d0
|
||||
r8=0x43b7732c r9=0x828f0000 r10=0x00000001 r11=0x00000000 r12=0x82458b34 r13=0x4adc8000
|
||||
hw=4 idx=0 tid=9 state=Ready pc=0x824d140c lr=0x824d22b4 sp=0x71387df0
|
||||
r0=0x00000000 r3=0x4250dedc r4=0x4250e040 r5=0x00000001 r6=0x00000000 r7=0x00000000
|
||||
r8=0x4b9ec000 r9=0x01010000 r10=0x01010000 r11=0x00000000 r12=0x824d22a8 r13=0x4b9ec000
|
||||
hw=5 idx=0 tid=3 state=Blocked(WaitAny { handles: [4112], deadline: None }) pc=0x824ac578 lr=0x824ac578 sp=0x7111fdf0
|
||||
r0=0x82153bf0 r3=0x00000000 r4=0x00000001 r5=0x00000000 r6=0x00000000 r7=0x00000a10
|
||||
r8=0x00000010 r9=0x00000000 r10=0x00009030 r11=0x00000000 r12=0x82181988 r13=0x4adc4000
|
||||
hw=5 idx=1 tid=6 state=Ready pc=0x824ab214 lr=0x824ab214 sp=0x7117fc60
|
||||
r0=0x821511a0 r3=0x00000001 r4=0x7117fcc0 r5=0x00000001 r6=0x00000001 r7=0x00000000
|
||||
r8=0x7117fcb0 r9=0x00009030 r10=0x00000002 r11=0x00000020 r12=0x82458d68 r13=0x4adca000
|
||||
hw=5 idx=2 tid=10 state=Ready pc=0x824d140c lr=0x824d22b4 sp=0x71487e00
|
||||
r0=0x00000000 r3=0x4250dedc r4=0x4250e040 r5=0x00000001 r6=0x00000000 r7=0x00000000
|
||||
r8=0x4b9ee000 r9=0x01010000 r10=0x01010000 r11=0x00000000 r12=0x824d22a8 r13=0x4b9ee000
|
||||
hw=5 idx=3 tid=12 state=Ready pc=0x824aa6a4 lr=0x824aa6a4 sp=0x714a7da0
|
||||
r0=0x00000000 r3=0x000000ff r4=0x00000020 r5=0x714a7df4 r6=0x00000000 r7=0x00000000
|
||||
r8=0x00000000 r9=0x00000000 r10=0x00000000 r11=0x00000001 r12=0x8217898c r13=0x4d1d2000
|
||||
|
||||
-- Handle waiter lists --
|
||||
handle=0x00001024 Semaphore(0/2147483647) waiters(tid)=[8]
|
||||
handle=0x00001010 Event(sig=false, mr=true) waiters(tid)=[3]
|
||||
handle=0x00001070 Thread(id=13, exit=None) waiters(tid)=[1]
|
||||
handle=0x00001080 Event(sig=false, mr=false) waiters(tid)=[5]
|
||||
handle=0x828a3244 Event(sig=false, mr=false) waiters(tid)=[11]
|
||||
handle=0x00001018 Semaphore(0/2147483647) waiters(tid)=[4]
|
||||
handle=0x00001050 Event(sig=false, mr=true) waiters(tid)=[8]
|
||||
handle=0x00001078 Event(sig=false, mr=false) waiters(tid)=[13]
|
||||
handle=0x8287093c Event(sig=false, mr=false) waiters(tid)=[2]
|
||||
handle=0x828a3220 Event(sig=false, mr=true) waiters(tid)=[11]
|
||||
handle=0x42450b5c Event(sig=false, mr=true) waiters(tid)=[7]
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,136 +0,0 @@
|
||||
# Phase A synthesis — canary tid=6 IS the main thread; the wedge is sub_822F1AA8's loop exit
|
||||
|
||||
## Top-line finding
|
||||
|
||||
**Canary's `tid=6` is canary's main thread.** Confirmed by probing `entry_point`
|
||||
(`sub_824AB748`) with `--audit_jit_prolog_pc=0x824AB748`: fires 1× on
|
||||
`tid=00000006` with `lr=BCBCBCBC` (= OS-initial / no caller). Ours numbers
|
||||
its main thread `tid=1`. Same logical thread; different label.
|
||||
|
||||
Therefore "tid=6 fires sub_821741C8 471×" (round 33) means **the main thread**
|
||||
loops inside `sub_822F1AA8` firing `sub_821741C8` ~1678×/30s in canary. In
|
||||
ours, the main thread (tid=1) runs `sub_822F1AA8` ONCE, exits the loop, and
|
||||
proceeds to thread-join on the spawned init thread (handle 0x1070 = tid=13),
|
||||
which is itself blocked forever on handle 0x1078.
|
||||
|
||||
## Call chain (identical in both engines, different runtime behavior)
|
||||
|
||||
```
|
||||
entry_point (sub_824AB748)
|
||||
│
|
||||
├─ sub_824ACB38 CRT-driven fnptr-array iterator (audit-050 region)
|
||||
├─ ...
|
||||
└─ sub_8216EA68 Many local calls including:
|
||||
├─ ExCreateThread(entry=sub_8217F0F8 ...) ; sibling thread
|
||||
├─ sub_822F1AA8(controller=...) ; FIRST call (PC 0x8216ECCC)
|
||||
└─ sub_822F1AA8(controller=0xBCE24A40 canary / ; SECOND call (PC 0x8216EE10)
|
||||
0x40d09a40 ours) ↑ this is the loop
|
||||
```
|
||||
|
||||
The SECOND call is what runs the dispatcher loop. Its LR = 0x8216EE14.
|
||||
Confirmed in both engines.
|
||||
|
||||
## sub_822F1AA8 loop structure
|
||||
|
||||
```
|
||||
0x822F1AA8: entry, r30 = r3 (controller)
|
||||
0x822F1AEC-0x822F1B08: ExCreateThread(entry=sub_822F1EE0, ctx=r30) → r29 = handle
|
||||
0x822F1B30-0x822F1B34: bl 0x824AA8B0(r3=r29) ; ?
|
||||
0x822F1B38-0x822F1B4C: first bctrl → vtable[+0] of [0x828E1F08]
|
||||
0x822F1B50-0x822F1B74: setup, bl 0x824AA330 INFINITE wait on [r22+32]
|
||||
0x822F1B80-0x822F1BA8: post-wait setup; [r30+0] |= 0x2
|
||||
0x822F1BB0-0x822F1BBC: TOP-OF-LOOP CHECK: if [r30+0] & 0x10000000 → goto 0x822F1E10 (exit)
|
||||
0x822F1BCC..0x822F1DEC: loop body (includes the vtable[+8] bctrl → sub_821741C8 at PC 0x822F1D58)
|
||||
0x822F1DEC-0x822F1DFC: bl 0x824AA330 INFINITE wait on [r23+0]
|
||||
0x822F1E00-0x822F1E0C: END-OF-ITERATION CHECK: if [r30+0] & 0x10000000 == 0 → goto 0x822F1BCC (re-loop)
|
||||
0x822F1E10-0x822F1E18: EXIT: [r30+0] |= 0x02000000 (set MSB-6 = LSB-25)
|
||||
0x822F1E1C-0x822F1E24: release something via bl 0x824AA2F0
|
||||
0x822F1E28-0x822F1E30: bl 0x824AA330 INFINITE on [r30+28] = SPAWNED THREAD HANDLE (thread join!)
|
||||
0x822F1E40: bl 0x824AA3E0
|
||||
0x822F1E44-0x822F1E5C: final cleanup: vtable[+24] bctrl on [0x828E1F08]
|
||||
0x822F1E60-0x822F1E78: [r30+0] = 0, then [r30+0] |= 1; bl 0x824567E0
|
||||
0x822F1E7C-0x822F1E88: epilogue
|
||||
```
|
||||
|
||||
**Loop exit gate**: `[r30+0] & 0x10000000` (bit 28 LSB / bit 3 MSB). Set →
|
||||
exit. Both top-of-loop check (0x822F1BBC) and end-of-iteration check
|
||||
(0x822F1E0C) gate on the same bit.
|
||||
|
||||
## What's different between engines
|
||||
|
||||
| Engine | [r30+0] at entry | Loop iterations | Exits sub_822F1AA8? |
|
||||
|--------|------------------|------------------|----------------------|
|
||||
| canary | 0x21 (per probe) | ~1678+ in 30s | NO (stays in loop) |
|
||||
| ours | 0x21 (per probe) | 0 (probes show none of the loop-body PCs fire after entry) | YES (exits quickly) |
|
||||
|
||||
Both engines have `[r30+0]=0x21` at entry — bit 28 NOT set. After the `ori
|
||||
r11, r11, 0x2` at 0x822F1B90, both should have `[r30+0]=0x23`. Bit 28 still
|
||||
not set.
|
||||
|
||||
So **some code sets bit 28 on [r30+0] between sub_822F1AA8 entry and the
|
||||
loop check** in ours but not in canary.
|
||||
|
||||
Mem-watch on 0x40d09a40 (ours' controller VA) shows **zero guest writes** in
|
||||
my 50M-instruction parallel run. Possible reasons:
|
||||
- The setter writes from kernel/runtime code that mem-watch doesn't capture
|
||||
(kernel-host store, not guest JIT store)
|
||||
- The setter writes via a computed alias (different VA but same backing)
|
||||
- The bit IS set via a probe-quantum-elided JIT store
|
||||
|
||||
## Phase B classification
|
||||
|
||||
**Class 3a — state-divergence on the controller object**. The vtable
|
||||
identity is the same (round-37 confirmed `0x820A183C` in both). The
|
||||
controller object's bit 28 of `[+0]` evolves differently during the setup
|
||||
between sub_822F1AA8 entry and the loop check.
|
||||
|
||||
Class 4 (synthesis) is now LESS attractive: ours' main thread DOES reach
|
||||
sub_822F1AA8 with the right controller. We don't need to spawn the
|
||||
dispatcher — we need to PREVENT the main thread from exiting the loop.
|
||||
|
||||
## Pragmatic next step — JIT instrumentation to find bit-28 setter
|
||||
|
||||
Most direct diagnostic: add a JIT hook in xenia-cpu that, for guest stores
|
||||
in the range [0x822F1AA8, 0x822F1E10), captures the guest PC + the written
|
||||
value when the store would set bit 28 of any address. This identifies the
|
||||
exact PC that sets the loop-exit bit.
|
||||
|
||||
Alternative: extend `--mem-watch` to also capture kernel-side stores by
|
||||
hooking the GuestMemory write path at the kernel-state level.
|
||||
|
||||
Even simpler: add a one-shot `--bit-watch=ADDR:MASK` cvar that fires when
|
||||
the value at ADDR has any bit in MASK transition from 0→1, regardless of
|
||||
who wrote it. This is the cleanest diagnostic for this exact pattern.
|
||||
|
||||
## Fix shape (when bit-28 setter is identified)
|
||||
|
||||
If the bit-28 setter is inside the vtable[+0] dispatch chain at 0x822F1B4C
|
||||
(target sub_82173990), then the fix might be a state-init issue in the
|
||||
kernel/runtime.
|
||||
|
||||
If the bit-28 setter is inside the inner wait or one of the kernel calls
|
||||
(`bl 0x824AA8B0`, `bl 0x824AA330`), the fix might be a missing event signal
|
||||
or a wrong handle-state evolution.
|
||||
|
||||
If we can't identify the setter cleanly, the synthesis fallback is to
|
||||
**inject a kernel-side hook that clears bit 28 of [r30+0] on every entry to
|
||||
sub_822F1AA8's bit-check site (0x822F1BB0)**. Crude but should keep the
|
||||
main thread in the loop.
|
||||
|
||||
## Why this is a clearer wedge picture than rounds 22-33
|
||||
|
||||
Rounds 22-33 chased the audit-049 wedge from various angles. The diagnoses
|
||||
landed on different layers:
|
||||
- R22: "wrong cluster targeted" (cluster A vs B)
|
||||
- R26-30: "state-machine progression bug"
|
||||
- R32-33: "pool 3 starvation; bootstrap walk-back"
|
||||
|
||||
This round establishes the simplest possible framing:
|
||||
|
||||
> **Canary's main thread loops forever in a dispatcher; ours' main thread
|
||||
> exits the loop after one setup phase. The exit is gated by a single bit
|
||||
> on the controller's flag word.**
|
||||
|
||||
If bit 28 of `[controller+0]` could be permanently cleared, ours' main
|
||||
thread would stay in the loop, sub_821741C8 would dispatch, signals would
|
||||
flow, tid=13 would complete, draws would happen.
|
||||
@@ -1,79 +0,0 @@
|
||||
AUDIT-PC-PROBE pc=0x822f1aa8 tid=1 hw=0 cycle=6180796 lr=0x8216ee14 r3=0x40d09a40 r11=0x40111910 [r3+0]=0x00000021 [[r3+0]+24]=0x00000000 [r3+0x0C]=0x40541a40 [r3+0x30]=0x00000000
|
||||
AUDIT-PC-PROBE pc=0x822f1b38 tid=1 hw=0 cycle=6181181 lr=0x822f1b38 r3=0x00000001 r11=0x824b0000 [r3+0]=0x00000000 [[r3+0]+24]=0x00000000 [r3+0x0C]=0x00000000 [r3+0x30]=0x00000000
|
||||
|
||||
=== Final State ===
|
||||
PC: 0x824ac578
|
||||
LR: 0x824ac578
|
||||
CTR: 0x82153bf0
|
||||
CR: 0x24000028
|
||||
XER: CA=0 OV=0 SO=0
|
||||
r0 : 0x0000000082153bf0
|
||||
r1 : 0x00000000700ff6e0
|
||||
r2 : 0x0000000020000000
|
||||
r4 : 0x0000000000000001
|
||||
r7 : 0x0000000003a72328
|
||||
r8 : 0x0000000043b77284
|
||||
r9 : 0x0000000043b77328
|
||||
r10: 0x0000000000000001
|
||||
r11: 0x0000000000000103
|
||||
r12: 0x0000000082173c64
|
||||
r13: 0x000000007fff0000
|
||||
r18: 0x0000000040d09a7c
|
||||
r23: 0x00000000828f3844
|
||||
r26: 0x000000004024a4e0
|
||||
r27: 0x00000000820a17a8
|
||||
r31: 0x0000000000001070
|
||||
|
||||
=== Thread diagnostics ===
|
||||
hw=0 idx=0 tid=1 state=Blocked(WaitAny { handles: [4208], deadline: None }) pc=0x824ac578 lr=0x824ac578 sp=0x700ff6e0
|
||||
r0=0x82153bf0 r3=0x00000000 r4=0x00000001 r5=0x00000000 r6=0x00000000 r7=0x03a72328
|
||||
r8=0x43b77284 r9=0x43b77328 r10=0x00000001 r11=0x00000103 r12=0x82173c64 r13=0x7fff0000
|
||||
hw=0 idx=1 tid=11 state=Blocked(WaitAny { handles: [2190094916, 2190094880], deadline: None }) pc=0x824d2a94 lr=0x824d2a94 sp=0x71497d90
|
||||
r0=0x00000000 r3=0x00000000 r4=0x71497de0 r5=0x00000001 r6=0x00000003 r7=0x00000001
|
||||
r8=0x00000000 r9=0x00000000 r10=0x71497df0 r11=0x828a3244 r12=0xbcbcbcbc r13=0x4b9f1000
|
||||
hw=1 idx=0 tid=2 state=Blocked(WaitAny { handles: [2189887804], deadline: None }) pc=0x824a95f8 lr=0x824a95f8 sp=0x710ffd20
|
||||
r0=0x0000030c r3=0x00000000 r4=0x00000003 r5=0x00000001 r6=0x00000000 r7=0x00000000
|
||||
r8=0x00000001 r9=0x6f000000 r10=0x824a9178 r11=0x82870000 r12=0x824a94f0 r13=0x4acc3000
|
||||
hw=1 idx=1 tid=13 state=Blocked(WaitAny { handles: [4216], deadline: None }) pc=0x824ac578 lr=0x824ac578 sp=0x715a7a20
|
||||
r0=0x821511d0 r3=0x00000000 r4=0x00000001 r5=0x00000000 r6=0x00000000 r7=0x03a723d0
|
||||
r8=0x43b77334 r9=0x43b77334 r10=0x40541f80 r11=0x00000001 r12=0x821cb1e0 r13=0x4d1d4000
|
||||
hw=2 idx=0 tid=7 state=Blocked(WaitAny { handles: [1111821148], deadline: Some(42946672) }) pc=0x824cd4f4 lr=0x824cd4f4 sp=0x71187e60
|
||||
r0=0x00000000 r3=0x00000000 r4=0x00000003 r5=0x00000001 r6=0x00000000 r7=0x71187eb0
|
||||
r8=0x00000000 r9=0x00000000 r10=0x00000002 r11=0x00000002 r12=0xbcbcbcbc r13=0x4b1d6000
|
||||
hw=2 idx=1 tid=8 state=Blocked(WaitAny { handles: [4176, 4132], deadline: None }) pc=0x824ab214 lr=0x824ab214 sp=0x71287c90
|
||||
r0=0x00000000 r3=0x00000000 r4=0x71287cf0 r5=0x00000001 r6=0x00000001 r7=0x00000000
|
||||
r8=0x00000000 r9=0x00009030 r10=0x00000002 r11=0x00000020 r12=0x822f1ff0 r13=0x4b90a000
|
||||
hw=3 idx=0 tid=4 state=Blocked(WaitAny { handles: [4120], deadline: None }) pc=0x824ac578 lr=0x824ac578 sp=0x7112fb80
|
||||
r0=0x821511a0 r3=0x00000000 r4=0x00000001 r5=0x00000000 r6=0x00000000 r7=0x03a723d0
|
||||
r8=0x43b7732c r9=0x828f0000 r10=0x00000008 r11=0x00000000 r12=0x8245a660 r13=0x4adc6000
|
||||
hw=3 idx=1 tid=5 state=Blocked(WaitAny { handles: [4224], deadline: None }) pc=0x824ac578 lr=0x824ac578 sp=0x7116fbe0
|
||||
r0=0x821511a0 r3=0x00000000 r4=0x00000001 r5=0x00000000 r6=0x00000000 r7=0x03a723d0
|
||||
r8=0x43b7732c r9=0x828f0000 r10=0x00000001 r11=0x00000000 r12=0x82458b34 r13=0x4adc8000
|
||||
hw=4 idx=0 tid=9 state=Ready pc=0x824d1404 lr=0x824d22b4 sp=0x71387df0
|
||||
r0=0x00000000 r3=0x4250dedc r4=0x4250e040 r5=0x00000001 r6=0x00000000 r7=0x00000000
|
||||
r8=0x4b9ec000 r9=0x01010000 r10=0x01010000 r11=0x00000000 r12=0x824d22a8 r13=0x4b9ec000
|
||||
hw=5 idx=0 tid=3 state=Blocked(WaitAny { handles: [4112], deadline: None }) pc=0x824ac578 lr=0x824ac578 sp=0x7111fdf0
|
||||
r0=0x82153bf0 r3=0x00000000 r4=0x00000001 r5=0x00000000 r6=0x00000000 r7=0x00000a10
|
||||
r8=0x00000010 r9=0x00000000 r10=0x00009030 r11=0x00000000 r12=0x82181988 r13=0x4adc4000
|
||||
hw=5 idx=1 tid=6 state=Ready pc=0x824ab214 lr=0x824ab214 sp=0x7117fc60
|
||||
r0=0x821511a0 r3=0x00000001 r4=0x7117fcc0 r5=0x00000001 r6=0x00000001 r7=0x00000000
|
||||
r8=0x7117fcb0 r9=0x00009030 r10=0x00000002 r11=0x00000020 r12=0x82458d68 r13=0x4adca000
|
||||
hw=5 idx=2 tid=10 state=Ready pc=0x824d1404 lr=0x824d22b4 sp=0x71487e00
|
||||
r0=0x00000000 r3=0x4250dedc r4=0x4250e040 r5=0x00000001 r6=0x00000000 r7=0x00000000
|
||||
r8=0x4b9ee000 r9=0x01010000 r10=0x01010000 r11=0x00000000 r12=0x824d22a8 r13=0x4b9ee000
|
||||
hw=5 idx=3 tid=12 state=Ready pc=0x824aa6a4 lr=0x824aa6a4 sp=0x714a7da0
|
||||
r0=0x00000000 r3=0x000000ff r4=0x00000020 r5=0x714a7df4 r6=0x00000000 r7=0x00000000
|
||||
r8=0x00000000 r9=0x00000000 r10=0x00000000 r11=0x00000001 r12=0x8217898c r13=0x4d1d2000
|
||||
|
||||
-- Handle waiter lists --
|
||||
handle=0x00001018 Semaphore(0/2147483647) waiters(tid)=[4]
|
||||
handle=0x8287093c Event(sig=false, mr=false) waiters(tid)=[2]
|
||||
handle=0x00001070 Thread(id=13, exit=None) waiters(tid)=[1]
|
||||
handle=0x42450b5c Event(sig=false, mr=true) waiters(tid)=[7]
|
||||
handle=0x00001078 Event(sig=false, mr=false) waiters(tid)=[13]
|
||||
handle=0x00001080 Event(sig=false, mr=false) waiters(tid)=[5]
|
||||
handle=0x828a3244 Event(sig=false, mr=false) waiters(tid)=[11]
|
||||
handle=0x00001024 Semaphore(0/2147483647) waiters(tid)=[8]
|
||||
handle=0x828a3220 Event(sig=false, mr=true) waiters(tid)=[11]
|
||||
handle=0x00001010 Event(sig=false, mr=true) waiters(tid)=[3]
|
||||
handle=0x00001050 Event(sig=false, mr=true) waiters(tid)=[8]
|
||||
@@ -1,127 +0,0 @@
|
||||
# Phase C.1 — Validation refutes Phase A's bit-28 setter hypothesis
|
||||
|
||||
## TL;DR
|
||||
|
||||
Phase A claimed: "bit 28 of `[0x40d09a40]` (controller word) gets set in ours, causing sub_822F1AA8's dispatcher loop to exit early; candidate setter is `sub_821B55D8` at PC `0x821B5DA4`."
|
||||
|
||||
**Phase C.1 falsifies this in 4 sub-rounds:**
|
||||
|
||||
1. **`sub_821B55D8` is dead code** in both engines — its `XamInputSetState` wrapper `sub_824AA858` fires 0× in both.
|
||||
2. **`[0x40d09a40]` is never set to anything with bit 28** — `--dump-addr` at end of run shows `+0x00 = 0x00000021`, the entry value. Bit 28 is NEVER set.
|
||||
3. **The actual wedge is at the `bcctrl` at PC `0x822F1B4C`** (inside sub_822F1AA8 setup, BEFORE the dispatcher loop). tid=1 never reaches the loop top-check.
|
||||
4. **The bcctrl calls `sub_82173990`** (vtable[0] of the dispatcher singleton at `[0x828E1F08]`), which eventually waits for tid=13 to terminate. tid=13 wedges in the audit-049 silph::UImpl@GamePart_Title chain on handle `0x1078`.
|
||||
|
||||
The C.2 force-clear POC (the planned next step) would have **zero effect** because bit 28 is never set. Skipped per plan stopping criterion.
|
||||
|
||||
## Probe-fire counts (ours, 50M-instr parallel)
|
||||
|
||||
| PC | sub-round | fires | meaning |
|
||||
|---|---|---|---|
|
||||
| `0x821B55D8` (Phase A candidate fn entry) | 1 | **0** | function never reached → β/γ |
|
||||
| `0x821B5D98,DA0,DAC,D48` (loop BB heads) | 1 | **0** | function never reached |
|
||||
| `0x822F1AA8` (sub_822F1AA8 entry) | 2,3,4 | 2-3 | reached |
|
||||
| `0x822F1B38` (post-`bl 0x824AA8B0`) | 4 | 2 | reached |
|
||||
| `0x822F1B50` (post-`bcctrl`) | 4 | **0** | **bcctrl never returns** |
|
||||
| `0x822F1B60,B78,B80,BBC` (loop setup/top) | 3 | 0 | unreachable past bcctrl |
|
||||
| `0x822F1E10` (loop exit cleanup) | 2 | 0 | loop never entered, never exited |
|
||||
| `0x822F1E34` (post-thread-join) | 2 | 0 | never reached |
|
||||
| `0x82173990` (vtable[0] target) | 4 | 2 | called via bcctrl, r3=singleton (LR=0x822F1B50) |
|
||||
| `0x821748F0` (tid=13 entry) | 4 | 2 | tid=13 runs |
|
||||
| `0x821C4EB0` (silph::UImpl@GamePart_Title) | 4 | 2 | audit-009/049 reached on tid=13 |
|
||||
| `0x82457388,0x824574C0,0x82457408,0x82457490` (other oris candidates) | 2 | 0 | unreachable |
|
||||
|
||||
## Canary probe results
|
||||
|
||||
| PC | fires | meaning |
|
||||
|---|---|---|
|
||||
| `0x824AA858` (XamInputSetState wrapper) | **0** | sub_821B55D8 chain is dead code in CANARY too |
|
||||
| `0x822F1B50` (post-bcctrl, attempted) | **0** | canary's JitProlog only fires at function entries, so not directly testable; but per audit round-33 sub_821741C8 fires 471× in canary → bcctrl DOES return in canary |
|
||||
|
||||
## Critical evidence: `--dump-addr=0x40d09a40` at end of run
|
||||
|
||||
```
|
||||
addr=0x40d09a40
|
||||
+0x00: 00 00 00 21 00 00 00 01 42 44 df 00 40 54 1a 40
|
||||
^^^^^^^^^^^ ^^^^^^^^^^^
|
||||
+0x10: 40 54 1b 40 40 54 1b 80 40 54 1b c0 00 00 10 54
|
||||
+0x20: 00 00 00 00 40 24 a8 20 00 00 00 08 00 00 00 00
|
||||
```
|
||||
|
||||
- `[+0x00] = 0x00000021` ← bit 28 (mask 0x10000000) is NOT SET. Same value as at sub_822F1AA8 entry.
|
||||
- `[+0x1c] = 0x00001054` ← spawned init thread handle (= tid=8's thread handle, NOT 0x1070)
|
||||
- Thread state: tid=1 waits on handle `0x1070`, tid=13 waits on handle `0x1078`.
|
||||
|
||||
Handle `0x1070` is **tid=13's thread handle** (per stderr: `ExCreateThread: tid=13 handle=0x1070 entry=0x821748f0 ctx=0x4024a840 suspended=true`). So tid=1's wait at the wedge point is a **thread-join on tid=13**, NOT a thread-join on the dispatcher init thread (tid=8, handle 0x1054).
|
||||
|
||||
## Wedge path (corrected)
|
||||
|
||||
```
|
||||
entry_point (sub_824AB748) [tid=1 main]
|
||||
└─ sub_8216EA68
|
||||
└─ sub_822F1AA8(controller=0x40d09a40) [LR=0x8216EE14]
|
||||
├─ ExCreateThread(entry=sub_822F1EE0, ctx=controller) [PC 0x822F1B08]
|
||||
│ ⇒ tid=8 spawn, handle=0x1054 (suspended)
|
||||
├─ bl 0x824AA8B0 (no-op probe) [PC 0x822F1B34]
|
||||
└─ bcctrl on vtable[+0] of [0x828E1F08] singleton [PC 0x822F1B4C]
|
||||
│
|
||||
└─ sub_82173990(r3=singleton) [r3=0x40ba9a80, vtable=0x40111910]
|
||||
└─ ... (768-byte function with ≥18 calls; calls sub_82448AA0, sub_824AA7A0,
|
||||
sub_82448BC8, sub_82448C50, sub_8216F218, sub_8217C850, sub_82178E50,
|
||||
sub_821835E0, ...)
|
||||
└─ ... → KeWaitForSingleObject INFINITE on handle 0x1070
|
||||
(= tid=13's thread handle, thread-join)
|
||||
⇒ WEDGE — tid=13 never exits
|
||||
|
||||
(Concurrently — spawned somewhere else, not from sub_822F1AA8:)
|
||||
[tid=13, spawn-handle=0x1070, ctx=0x4024a840]
|
||||
└─ sub_821748F0 (worker boilerplate, entry from ExCreateThread)
|
||||
├─ sub_82172798, sub_82172818
|
||||
└─ sub_821749C0
|
||||
└─ sub_821CF3F0
|
||||
└─ ... → sub_821C4EB0 (UImpl@GamePart_Title@silph) [audit-009/049!]
|
||||
└─ ... → sub_821CB030 (creates KEVENT at +0x128)
|
||||
⇒ KeWaitForSingleObject INFINITE on handle 0x1078
|
||||
⇒ WEDGE — handle 0x1078 is never signaled in ours
|
||||
```
|
||||
|
||||
## Why Phase A's hypothesis is wrong
|
||||
|
||||
Phase A:
|
||||
1. Disassembled sub_822F1AA8's body, observed the bit-28 loop-exit check at `0x822F1BB8` and end-of-iter check at `0x822F1E0C`.
|
||||
2. Mem-watch on `0x40d09a40` showed zero stores → inferred "the setter writes via some path mem-watch doesn't capture."
|
||||
3. DB-scanned `oris ?, ?, 0x1000` (49 sites), found `sub_821B55D8 + 0x821B5DA4` with pattern `bl sub_824AA858 ; if r3 == 0xAA: oris r11, 0x1000 ; stw`.
|
||||
4. Concluded `sub_821B55D8` was the setter.
|
||||
|
||||
What Phase A missed:
|
||||
- Mem-watch's 0-stores result was correct: **NO setter exists**. Bit 28 is never set in either engine. The mem-watch null-result was a hint that the bit-28 hypothesis itself was wrong, but Phase A interpreted it as "mem-watch misses something."
|
||||
- The disasm-based hypothesis was visually compelling (a loop iterating arrays and setting bit 28 when a kernel call returns 0xAA) but never verified runtime.
|
||||
- `sub_821B55D8` is itself dead code in both engines.
|
||||
|
||||
## Reading-error class #19: disasm-pattern-match without runtime verification
|
||||
|
||||
When scanning for a hypothesized signal source via DB pattern-match (`oris ?, ?, 0x1000`), the analyst must run a probe to verify the suspected site is *both reached* and *takes the suspected path* before declaring it the cause. Phase A bypassed both checks. The single `--dump-addr=0x40d09a40` flag in sub-round 2 (literally 4 keystrokes added to the existing probe command) revealed the central assumption was wrong.
|
||||
|
||||
## Real divergence (handed to next session)
|
||||
|
||||
This is the **same wedge as audit-049/058/059**: tid=13 wedges in the silph::UImpl@GamePart_Title cluster on handle `0x1078`. tid=1 wedges on tid=13's thread-handle (`0x1070`) inside `sub_82173990`'s call chain.
|
||||
|
||||
`sub_82173990` is vtable[0] of the dispatcher singleton at `[0x828E1F08]`. It's a 768-byte function with ≥18 calls; the actual wait site is somewhere down its tree. To localize where in `sub_82173990` the wait happens, probe its BB heads + the `KeWaitForSingleObject` thunks (`sub_824AA330`, `sub_824AA708`).
|
||||
|
||||
The fix-shape is **NOT** "force-clear bit 28." The fix-shape is **"signal handle 0x1078 in the audit-049 cluster, or short-circuit tid=13's wait."** Round 22 (silph_synth.rs) attempted the cluster-A version of this. Cluster B (silph::UImpl) needs its own synthesis or a kernel-side signal of handle 0x1078.
|
||||
|
||||
## Phase C verdict
|
||||
|
||||
- C.1: 4 sub-rounds executed (within budget).
|
||||
- C.2: **NOT EXECUTED** — POC would be no-op since bit 28 is never set. Per plan stopping criterion, do not proceed to C.2 blind when C.1 refutes the diagnosis.
|
||||
- C.3: not applicable.
|
||||
- Branch state: no source changes. Audit artifacts only.
|
||||
|
||||
## Files in this directory
|
||||
|
||||
- `ours-c1-probe.log/stderr` — sub-round 1, probe at sub_821B55D8 BB heads (0 fires)
|
||||
- `ours-sr2-confirm-bit28.log/stderr` — sub-round 2, probe loop top/exit + dump-addr (bit 28 NEVER SET)
|
||||
- `ours-sr3-wait-trace.log/stderr` — sub-round 3, probe wait site + handle 0x1070 trace
|
||||
- `ours-sr4-bcctrl-trace.log/stderr` — sub-round 4, probe pre/post bcctrl + sub_82173990 entry + tid=13 entry (decisive)
|
||||
- canary side in `../round-C1-setter-validation-canary/`:
|
||||
- `canary-824AA858.log` — XamInputSetState wrapper fires 0× in canary too
|
||||
- `canary-822F1B50.log` — JitProlog can't probe at BB-internal PCs (function-entry-only)
|
||||
@@ -1,144 +0,0 @@
|
||||
# Phase D — Audit-049 Auto-Signal POC — FINDINGS
|
||||
|
||||
**Branch**: `iterate-2C/silph-ui-spawn-trace` (extends Phase C `481591f`)
|
||||
**Date**: 2026-06-11
|
||||
**Sub-rounds**: D2.SR1 → D2.SR4 (4/4 used)
|
||||
**Verdict**: **B — partial unwedge**
|
||||
|
||||
## Mission
|
||||
|
||||
Phase C diagnosed the audit-049 wedge as tid=13 (silph::UImpl@GamePart_Title) waiting INFINITE on a KEVENT created at `sub_821CB030+0x128` (`lr=0x821cb15c`, post-bl PC). The Phase D POC tests this diagnosis by hooking `NtCreateEvent` from that exact call site and auto-signaling the resulting handle after a configurable delay (`XENIA_SILPH_UI_AUTOSIGNAL_DELAY` instructions).
|
||||
|
||||
If tid=13 unblocks, the diagnosis is confirmed. If new wedges or new threads appear downstream, even better — that's actual game progression past the wedge.
|
||||
|
||||
## Result summary
|
||||
|
||||
| Symptom | SR2/SR3 baseline | SR4 (POC firing) |
|
||||
|---|---|---|
|
||||
| `silph autosignal: scheduled handle=0x1078 caller_lr=0x821cb15c` | yes (SR2/SR3) | yes |
|
||||
| `silph autosignal: firing handle=0x1078` | NO | **yes (cycle 16326209)** |
|
||||
| handle 0x1078 final | `signaled=false waiters=1 <NO_SIGNALS_DESPITE_WAITS>` | `signal_attempts=1 waiters=0` |
|
||||
| tid=13 final state | `Blocked(WaitAny[0x1078])` | **`Ready` pc=0x824a9108** |
|
||||
| tid=1 final state | `Blocked(WaitAny[0x1070])` thread-join | `Blocked(WaitAny[0x1070])` (tid=13 not yet exited) |
|
||||
| ExCreateThread total | 10 | **12 (+tid=14, +tid=15)** |
|
||||
| New downstream wedges | none past 0x1078 | **0x1084 (Event/Auto), 0x1088 (Event/Manual)** |
|
||||
| `cxx_throw` runtime_error decoded | none | **yes, stack depth 6, top L0=0x82612b50 → L4=sub_82450B60+0x1A8 → L6=sub_82450a50** |
|
||||
| VdSwap | 1 | 1 |
|
||||
| gpu.interrupt.delivered{source=0} | 6393 | 4539 (different trajectory, no draws) |
|
||||
|
||||
**Conclusion**: tid=13 unwedged cleanly from the audit-049 wait, spawned two follow-on threads (tid=14 entry=`silph` ctx=`0x40929c00`, tid=15 a worker), and progressed deep enough into the silph::UImpl state machine to throw a `runtime_error` from sub_82450a50 → sub_82450B60+0x1A8 (the dispatcher cluster from round 26). The auto-signal **is not** the proper signaler — it lets tid=13 proceed but downstream state-machine invariants the missing real signaler would have established are not in place, so the dispatcher trips on a "not-registered instance" lookup.
|
||||
|
||||
This is a **clean confirmation** of the Phase C diagnosis: the wedge handle, the wait site, and the LR filter are all correct. The fix shape is:
|
||||
- Either: synthesize the missing signaler properly (cluster-B silph_ui_synth.rs analogue from R33's deferred plan)
|
||||
- Or: track what the auto-signal needed to write into the work-item state (`[+8]` field per R26) BEFORE signaling, so the dispatcher's BST lookup succeeds
|
||||
|
||||
## Sub-round detail
|
||||
|
||||
### D2.SR1 — initial run, hook never fires (wrong LR filter)
|
||||
|
||||
Filter checked `creator_lr ∈ [0x821CB15C, 0x821CB160]` against `ctx.lr` at `nt_create_event` entry. But `ctx.lr` is the **thunk wrapper return slot** (`0x824a9f6c`), not the guest caller's post-bl PC. Confirmed via handle-audit `created stack` dump: frame 0 lr=`0x824a9f6c`, frame 1 lr=`0x821cb15c`. The guest caller's LR lives one frame up the PPC EABI back-chain.
|
||||
|
||||
Diagnosis classification: **D (filter mismatch)**. Reading-error class #20 (new).
|
||||
|
||||
### D2.SR2 — frame-1-LR fix; hook schedules, never fires
|
||||
|
||||
Refactored `maybe_register_silph_autosignal` to take `(ctx, mem)`, walk back-chain via existing `walk_guest_back_chain` (1 step), match the saved LR. Hook now fires:
|
||||
|
||||
```
|
||||
silph autosignal: scheduled handle=0x1078 caller_lr=0x821cb15c for cycle 10000 (now=0, delay=10000)
|
||||
```
|
||||
|
||||
But no "firing" log appears, and tid=13 stays Blocked. Classification: **D (drain site never reached)**.
|
||||
|
||||
### D2.SR3 — diagnostic added; confirms drain site never visited
|
||||
|
||||
Added a one-shot info-level "tick (first visit, none due)" log inside `fire_due_silph_autosignals` when pending is non-empty but nothing due. Re-ran. **The tick-diagnostic never fired either** — proving the function isn't being called at all in `--parallel` mode.
|
||||
|
||||
Root cause: `--parallel` dispatches to `run_execution_parallel` (line 2928 of main.rs), which has its own outer loop at line 3186. My Phase D wiring only touched the lockstep path at line 2763. Classification: **D (wrong code path wired)**.
|
||||
|
||||
### D2.SR4 — parallel-path wiring added; hook fires; tid=13 unblocks
|
||||
|
||||
Added the same `set_now_cycle_hint` + `fire_due_silph_autosignals` calls inside the parallel outer loop, right after `coord_pre_round` (and under the same `kernel_arc` guard, so no extra locking). Re-built, re-ran.
|
||||
|
||||
Now all three log lines appear:
|
||||
|
||||
```
|
||||
silph autosignal: scheduled handle=0x1078 caller_lr=0x821cb15c for cycle 16326202 (now=16316202, delay=10000)
|
||||
silph autosignal: tick (first visit, none due) now=16316213 pending=1 first_deadline=16326202
|
||||
silph autosignal: firing handle=0x1078 prev_signaled=Some(false) at cycle 16326209
|
||||
```
|
||||
|
||||
`now=16316202` at schedule time confirms `set_now_cycle_hint` is wired through correctly (the parallel path was simply never visited in SR2/SR3). Fire at cycle 16326209 = deadline 16326202 + 7-cycle scheduler granularity. Diagnostic classification: **B (partial unwedge — new waits and cxx_throw downstream)**.
|
||||
|
||||
## Code shape
|
||||
|
||||
POC is ~70 LOC across four files, all env-gated. Default off.
|
||||
|
||||
| File | Change | Lines |
|
||||
|---|---|---|
|
||||
| `crates/xenia-cpu/src/scheduler.rs` | `GuestThread.start_entry/start_context` fields; `spawn()` populates; `current_thread_entry_and_ctx()` helper | +18 |
|
||||
| `crates/xenia-kernel/src/state.rs` | `AutoSignalPending` struct; `silph_autosignal_*` fields; `set_now_cycle_hint`, `maybe_register_silph_autosignal`, `fire_due_silph_autosignals` methods | +95 |
|
||||
| `crates/xenia-kernel/src/exports.rs` | Hook in `nt_create_event` | +3 |
|
||||
| `crates/xenia-app/src/main.rs` | Fire-site wiring in lockstep loop (line 2788) **and** parallel loop (line 3215) | +12 |
|
||||
|
||||
Tests stay green at **655/655**.
|
||||
|
||||
## Reading-error class #20 (new)
|
||||
|
||||
**`ctx.lr` at kernel export entry ≠ guest caller's post-bl PC.** When a guest `bl` calls an export thunk, the thunk-wrapper has its own frame between the guest caller and the export body. At export-body entry, `ctx.lr` holds the *wrapper's* return slot, not the guest caller's post-bl PC.
|
||||
|
||||
To match a specific guest call site by LR, the export must walk one step up the back-chain (`walk_guest_back_chain(ctx.gpr[1], ctx.lr, mem, 2)`) and use `frames[1].lr`.
|
||||
|
||||
SR1 burned one full sub-round on this. Detect early in future POCs by comparing `ctx.lr` against the handle-audit's `created stack` frame dump for a known-good event (e.g. one created from a labelled site).
|
||||
|
||||
## Reading-error class #21 (new)
|
||||
|
||||
**`--parallel` and lockstep have separate outer loops in main.rs.** They share `coord_pre_round` (carved out exactly for this reason), but anything wired adjacent to that call site only takes effect on the path it's wired on. Lockstep is `run_execution` (line 2706, outer loop at 2763). Parallel is `run_execution_parallel` (line 2928, outer loop at 3186).
|
||||
|
||||
Per-round hooks added for a specific build mode must be wired in **both** paths. SR2/SR3 burned two sub-rounds on this.
|
||||
|
||||
## Files modified + LR mapping (for follow-up sessions)
|
||||
|
||||
**Wedge handle creation** (confirmed by handle-audit dump):
|
||||
```
|
||||
created cycle=0 tid=13 lr=0x824a9f6c [src=NtCreateEvent thunk return]
|
||||
created stack (6 frames):
|
||||
[ 0] fp=0x715a7a10 lr=0x824a9f6c ← ctx.lr at nt_create_event
|
||||
[ 1] fp=0x715a7aa0 lr=0x821cb15c ← guest caller's post-bl PC (filter on this)
|
||||
[ 2] fp=0x715a7bd0 lr=0x821cbae0 ← sub_821CBA08 frame
|
||||
[ 3] fp=0x715a7cd0 lr=0x821cc454 ← sub_821CC3F8 frame
|
||||
[ 4] fp=0x715a7d60 lr=0x821c4f18 ← sub_821C4EB0 frame (silph::UImpl@GamePart_Title)
|
||||
[ 5] fp=0x715a7e00 lr=0x82174a80 ← sub_821748F0 trampoline frame
|
||||
```
|
||||
|
||||
**Downstream cxx_throw stack** (after auto-signal fires, tid=5 throws runtime_error):
|
||||
```
|
||||
L0 lr=0x82612b50 std::exception throw path
|
||||
L1 lr=0x825f2444
|
||||
L2 lr=0x824547e8
|
||||
L3 lr=0x82451418
|
||||
L4 lr=0x82450d08 ← sub_82450B60+0x1A8 (dispatcher, audit-059 R26)
|
||||
L5 lr=0x82450b34
|
||||
L6 lr=0x82450a50 ← sub_82450a50 (worker dispatch)
|
||||
|
||||
cxx_throw runtime_error decoded magic=0x19930520
|
||||
cxx_throw BST ceil search candidate_key=0x828e2b2c match_found=false
|
||||
cxx_throw lhs (not-registered instance) lhs=0x715a7af0
|
||||
```
|
||||
|
||||
This confirms the dispatcher reached audit-049 territory (R26's `sub_82450B60+0x1A8` PC `0x82450D08`), looked up a runtime instance in its BST keyed by VA, and the instance was never registered. **The auto-signal bypassed an upstream registration step** the real signaler would have driven.
|
||||
|
||||
## Recommendation
|
||||
|
||||
Ship the POC env-gated (default off; no behavior change unless opted in). The verdict-B success makes it a useful diagnostic flag for future audit-049 work: future investigations can set `XENIA_SILPH_UI_AUTOSIGNAL_DELAY=10000` to skip the wedge and probe downstream behavior without first writing the proper signaler.
|
||||
|
||||
Long-term fix path remains the R33 silph_ui_synth.rs analogue: synthesize the missing signaler + its precondition state (BST instance registration at `0x715a7af0`-equivalent, work-item state `[+8]` per R26). The auto-signal POC is **not** the final fix — it confirms diagnosis but doesn't honor the dispatcher's BST registry invariant.
|
||||
|
||||
## Artifacts
|
||||
|
||||
- `poc-sr1.log`, `poc-sr1.stderr` — initial run, filter mismatch (D)
|
||||
- `poc-sr2.log`, `poc-sr2.stderr` — frame-1-LR fix, no fire (D)
|
||||
- `poc-sr3.log`, `poc-sr3.stderr` — diagnostic added, no fire (D, parallel path unwired)
|
||||
- `poc-sr4.log`, `poc-sr4.stderr` — parallel-path wired, **fires + partial unwedge (B)**
|
||||
|
||||
All `.log`/`.stderr` files are `.gitignore`d; this `FINDINGS.md` is the only artifact-side commit.
|
||||
@@ -1,200 +0,0 @@
|
||||
0x82450b60: lwz r18, 9792(r31)
|
||||
0x82450b64: lwz r16, 13880(r14)
|
||||
0x82450b68: mflr r12
|
||||
0x82450b6c: bl 0x825F0F74
|
||||
0x82450b70: subi r31, r1, 176
|
||||
0x82450b74: stwu r1, -176(r1)
|
||||
0x82450b78: mr r29, r4
|
||||
0x82450b7c: mr r27, r3
|
||||
0x82450b80: cmpwi cr6, r29, 5
|
||||
0x82450b84: bne cr6, 0x82450B94
|
||||
0x82450b88: addi r28, r27, 196
|
||||
0x82450b8c: addi r26, r27, 28
|
||||
0x82450b90: b 0x82450BAC
|
||||
0x82450b94: slwi r11, r29, 2
|
||||
0x82450b98: mr r26, r27
|
||||
0x82450b9c: add r11, r29, r11
|
||||
0x82450ba0: slwi r11, r11, 2
|
||||
0x82450ba4: add r11, r11, r27
|
||||
0x82450ba8: addi r28, r11, 96
|
||||
0x82450bac: addi r23, r27, 56
|
||||
0x82450bb0: mr r3, r23
|
||||
0x82450bb4: stw r23, 84(r31)
|
||||
0x82450bb8: bl 0x8284DCFC
|
||||
0x82450bbc: mr r3, r26
|
||||
0x82450bc0: bl 0x8284DCFC
|
||||
0x82450bc4: lwz r7, 16(r28)
|
||||
0x82450bc8: cntlzw r11, r7
|
||||
0x82450bcc: extrwi r11, r11, 1, 26
|
||||
0x82450bd0: cmplwi cr6, r11, 0x0
|
||||
0x82450bd4: beq cr6, 0x82450BEC
|
||||
0x82450bd8: mr r3, r26
|
||||
0x82450bdc: bl 0x8284DD0C
|
||||
0x82450be0: mr r3, r23
|
||||
0x82450be4: bl 0x8284DD0C
|
||||
0x82450be8: b 0x82450EE8
|
||||
0x82450bec: lwz r11, 12(r28)
|
||||
0x82450bf0: lwz r9, 8(r28)
|
||||
0x82450bf4: srwi r10, r11, 2
|
||||
0x82450bf8: clrlwi r8, r11, 30
|
||||
0x82450bfc: cmplw cr6, r9, r10
|
||||
0x82450c00: bgt cr6, 0x82450C08
|
||||
0x82450c04: sub r10, r10, r9
|
||||
0x82450c08: lwz r9, 4(r28)
|
||||
0x82450c0c: slwi r10, r10, 2
|
||||
0x82450c10: slwi r8, r8, 2
|
||||
0x82450c14: lwz r6, 8(r28)
|
||||
0x82450c18: addi r11, r11, 1
|
||||
0x82450c1c: slwi r6, r6, 2
|
||||
0x82450c20: li r24, 0
|
||||
0x82450c24: lwzx r10, r10, r9
|
||||
0x82450c28: cmplw cr6, r6, r11
|
||||
0x82450c2c: lwzx r30, r10, r8
|
||||
0x82450c30: stw r11, 12(r28)
|
||||
0x82450c34: stw r30, 80(r31)
|
||||
0x82450c38: bgt cr6, 0x82450C40
|
||||
0x82450c3c: stw r24, 12(r28)
|
||||
0x82450c40: subic. r11, r7, 1
|
||||
0x82450c44: stw r11, 16(r28)
|
||||
0x82450c48: bne 0x82450C50
|
||||
0x82450c4c: stw r24, 12(r28)
|
||||
0x82450c50: addi r25, r27, 28
|
||||
0x82450c54: mr r3, r25
|
||||
0x82450c58: bl 0x8284DCFC
|
||||
0x82450c5c: mr r3, r25
|
||||
0x82450c60: stw r30, 216(r27)
|
||||
0x82450c64: bl 0x8284DD0C
|
||||
0x82450c68: mr r3, r26
|
||||
0x82450c6c: bl 0x8284DD0C
|
||||
0x82450c70: lwz r11, 28(r30)
|
||||
0x82450c74: clrlwi r11, r11, 31
|
||||
0x82450c78: cmplwi cr6, r11, 0x0
|
||||
0x82450c7c: bne cr6, 0x82450D30
|
||||
0x82450c80: lwz r11, 8(r30)
|
||||
0x82450c84: cmplwi cr6, r11, 0x1
|
||||
0x82450c88: blt cr6, 0x82450CE4
|
||||
0x82450c8c: bne cr6, 0x82450D3C
|
||||
0x82450c90: lwz r11, 28(r30)
|
||||
0x82450c94: rlwinm r11, r11, 0, 29, 29
|
||||
0x82450c98: cmplwi cr6, r11, 0x0
|
||||
0x82450c9c: beq cr6, 0x82450CB0
|
||||
0x82450ca0: mr r4, r30
|
||||
0x82450ca4: mr r3, r27
|
||||
0x82450ca8: bl 0x824510E0
|
||||
0x82450cac: b 0x82450CBC
|
||||
0x82450cb0: mr r4, r30
|
||||
0x82450cb4: mr r3, r27
|
||||
0x82450cb8: bl 0x824517B0
|
||||
0x82450cbc: stw r29, 220(r27)
|
||||
0x82450cc0: bl 0x824AA830
|
||||
0x82450cc4: mr r11, r3
|
||||
0x82450cc8: lwz r3, 92(r27)
|
||||
0x82450ccc: li r5, 0
|
||||
0x82450cd0: addi r11, r11, 66
|
||||
0x82450cd4: li r4, 1
|
||||
0x82450cd8: stw r11, 224(r27)
|
||||
0x82450cdc: bl 0x824AB158
|
||||
0x82450ce0: b 0x82450D3C
|
||||
0x82450ce4: lwz r11, 28(r30)
|
||||
0x82450ce8: mr r4, r30
|
||||
0x82450cec: mr r3, r27
|
||||
0x82450cf0: rlwinm r11, r11, 0, 29, 29
|
||||
0x82450cf4: cmplwi cr6, r11, 0x0
|
||||
0x82450cf8: beq cr6, 0x82450D04
|
||||
0x82450cfc: bl 0x82450F68
|
||||
0x82450d00: b 0x82450D08
|
||||
0x82450d04: bl 0x82451238
|
||||
0x82450d08: stw r29, 220(r27)
|
||||
0x82450d0c: bl 0x824AA830
|
||||
0x82450d10: mr r11, r3
|
||||
0x82450d14: lwz r3, 92(r27)
|
||||
0x82450d18: li r5, 0
|
||||
0x82450d1c: addi r11, r11, 66
|
||||
0x82450d20: li r4, 1
|
||||
0x82450d24: stw r11, 224(r27)
|
||||
0x82450d28: bl 0x824AB158
|
||||
0x82450d2c: b 0x82450D3C
|
||||
0x82450d30: lwz r11, 28(r30)
|
||||
0x82450d34: ori r11, r11, 0x2
|
||||
0x82450d38: stw r11, 28(r30)
|
||||
0x82450d3c: lwz r11, 8(r30)
|
||||
0x82450d40: mr r29, r24
|
||||
0x82450d44: cmpwi cr6, r11, 2
|
||||
0x82450d48: blt cr6, 0x82450E08
|
||||
0x82450d4c: cmpwi cr6, r11, 3
|
||||
0x82450d50: ble cr6, 0x82450DA0
|
||||
0x82450d54: cmpwi cr6, r11, 4
|
||||
0x82450d58: bne cr6, 0x82450E08
|
||||
0x82450d5c: lwz r11, 28(r30)
|
||||
0x82450d60: rlwinm r11, r11, 0, 29, 29
|
||||
0x82450d64: cmplwi cr6, r11, 0x0
|
||||
0x82450d68: bne cr6, 0x82450D98
|
||||
0x82450d6c: lwz r29, 36(r30)
|
||||
0x82450d70: mr r3, r29
|
||||
0x82450d74: lwz r11, 0(r29)
|
||||
0x82450d78: lwz r11, 4(r11)
|
||||
0x82450d7c: mtctr r11
|
||||
0x82450d80: bctrl
|
||||
0x82450d84: clrlwi r11, r3, 24
|
||||
0x82450d88: cmplwi cr6, r11, 0x0
|
||||
0x82450d8c: beq cr6, 0x82450D98
|
||||
0x82450d90: mr r3, r29
|
||||
0x82450d94: bl 0x8244FB38
|
||||
0x82450d98: li r29, 1
|
||||
0x82450d9c: b 0x82450E28
|
||||
0x82450da0: addi r3, r30, 40
|
||||
0x82450da4: bl 0x82451DB8
|
||||
0x82450da8: lwz r11, 32(r30)
|
||||
0x82450dac: cmplwi cr6, r11, 0x0
|
||||
0x82450db0: beq cr6, 0x82450DCC
|
||||
0x82450db4: rlwinm r11, r11, 0, 0, 31
|
||||
0x82450db8: lwz r10, 4(r30)
|
||||
0x82450dbc: lwz r11, 4(r11)
|
||||
0x82450dc0: cmplw cr6, r10, r11
|
||||
0x82450dc4: li r11, 1
|
||||
0x82450dc8: beq cr6, 0x82450DD0
|
||||
0x82450dcc: mr r11, r24
|
||||
0x82450dd0: clrlwi r11, r11, 24
|
||||
0x82450dd4: cmplwi cr6, r11, 0x0
|
||||
0x82450dd8: beq cr6, 0x82450E00
|
||||
0x82450ddc: lwz r4, 8(r30)
|
||||
0x82450de0: lwz r5, 0(r30)
|
||||
0x82450de4: lwz r3, 32(r30)
|
||||
0x82450de8: cmpwi cr6, r4, 1
|
||||
0x82450dec: ble cr6, 0x82450DFC
|
||||
0x82450df0: bl 0x8245D9D8
|
||||
0x82450df4: li r29, 1
|
||||
0x82450df8: b 0x82450E28
|
||||
0x82450dfc: stw r4, 8(r3)
|
||||
0x82450e00: li r29, 1
|
||||
0x82450e04: b 0x82450E28
|
||||
0x82450e08: mr r3, r26
|
||||
0x82450e0c: stw r26, 88(r31)
|
||||
0x82450e10: bl 0x8284DCFC
|
||||
0x82450e14: addi r4, r31, 80
|
||||
0x82450e18: mr r3, r28
|
||||
0x82450e1c: bl 0x823232C0
|
||||
0x82450e20: mr r3, r26
|
||||
0x82450e24: bl 0x8284DD0C
|
||||
0x82450e28: clrlwi r11, r29, 24
|
||||
0x82450e2c: cmplwi cr6, r11, 0x0
|
||||
0x82450e30: beq cr6, 0x82450ECC
|
||||
0x82450e34: lwz r11, 28(r30)
|
||||
0x82450e38: rlwinm r11, r11, 0, 30, 30
|
||||
0x82450e3c: cmplwi cr6, r11, 0x0
|
||||
0x82450e40: beq cr6, 0x82450E68
|
||||
0x82450e44: mr r3, r26
|
||||
0x82450e48: stw r26, 88(r31)
|
||||
0x82450e4c: bl 0x8284DCFC
|
||||
0x82450e50: addi r4, r31, 80
|
||||
0x82450e54: mr r3, r28
|
||||
0x82450e58: bl 0x823232C0
|
||||
0x82450e5c: mr r3, r26
|
||||
0x82450e60: bl 0x8284DD0C
|
||||
0x82450e64: b 0x82450ECC
|
||||
0x82450e68: lwz r11, 40(r30)
|
||||
0x82450e6c: cmplwi cr6, r11, 0x0
|
||||
0x82450e70: beq cr6, 0x82450EA4
|
||||
0x82450e74: rlwinm r3, r11, 0, 0, 31
|
||||
0x82450e78: bl 0x82458A70
|
||||
0x82450e7c: lwz r29, 40(r30)
|
||||
@@ -1,80 +0,0 @@
|
||||
0x82451238: mflr r12
|
||||
0x8245123c: li r0, 0
|
||||
0x82451240: stw r0, 4(r1)
|
||||
0x82451244: bl 0x825F0F80
|
||||
0x82451248: subi r31, r1, 160
|
||||
0x8245124c: stwu r1, -160(r1)
|
||||
0x82451250: mr r30, r4
|
||||
0x82451254: li r9, 1
|
||||
0x82451258: lwz r10, 32(r30)
|
||||
0x8245125c: stw r30, 188(r31)
|
||||
0x82451260: stw r9, 8(r30)
|
||||
0x82451264: cmplwi cr6, r10, 0x0
|
||||
0x82451268: beq cr6, 0x82451288
|
||||
0x8245126c: lwz r11, 4(r30)
|
||||
0x82451270: lwz r8, 4(r10)
|
||||
0x82451274: cmplw cr6, r11, r8
|
||||
0x82451278: bne cr6, 0x82451288
|
||||
0x8245127c: mr r11, r9
|
||||
0x82451280: li r26, 0
|
||||
0x82451284: b 0x82451290
|
||||
0x82451288: li r26, 0
|
||||
0x8245128c: mr r11, r26
|
||||
0x82451290: clrlwi r11, r11, 24
|
||||
0x82451294: cmplwi cr6, r11, 0x0
|
||||
0x82451298: beq cr6, 0x824512A0
|
||||
0x8245129c: stw r9, 8(r10)
|
||||
0x824512a0: lwz r3, 36(r30)
|
||||
0x824512a4: lwz r11, 0(r3)
|
||||
0x824512a8: lwz r11, 32(r11)
|
||||
0x824512ac: mtctr r11
|
||||
0x824512b0: bctrl
|
||||
0x824512b4: mr r27, r3
|
||||
0x824512b8: stw r26, 84(r31)
|
||||
0x824512bc: stw r27, 96(r31)
|
||||
0x824512c0: bl 0x82454498
|
||||
0x824512c4: addi r4, r31, 84
|
||||
0x824512c8: bl 0x82454580
|
||||
0x824512cc: stw r26, 92(r31)
|
||||
0x824512d0: addi r11, r27, 2047
|
||||
0x824512d4: lis r10, 0x2
|
||||
0x824512d8: clrrwi r11, r11, 11
|
||||
0x824512dc: cmplw cr6, r11, r10
|
||||
0x824512e0: stw r11, 100(r31)
|
||||
0x824512e4: ble cr6, 0x824512F4
|
||||
0x824512e8: lis r11, 0x8207
|
||||
0x824512ec: addi r11, r11, 6724
|
||||
0x824512f0: b 0x824512F8
|
||||
0x824512f4: addi r11, r31, 100
|
||||
0x824512f8: addi r3, r31, 84
|
||||
0x824512fc: lwz r4, 0(r11)
|
||||
0x82451300: bl 0x82454B08
|
||||
0x82451304: mr r8, r8
|
||||
0x82451308: mr r28, r3
|
||||
0x8245130c: stw r28, 92(r31)
|
||||
0x82451310: b 0x82451324
|
||||
0x82451314: lwz r30, 188(r31)
|
||||
0x82451318: lwz r27, 96(r31)
|
||||
0x8245131c: li r26, 0
|
||||
0x82451320: lwz r28, 92(r31)
|
||||
0x82451324: addi r3, r31, 84
|
||||
0x82451328: bl 0x82454AA0
|
||||
0x8245132c: mr r29, r3
|
||||
0x82451330: cmplwi cr6, r28, 0x0
|
||||
0x82451334: beq cr6, 0x82451684
|
||||
0x82451338: lwz r3, 36(r30)
|
||||
0x8245133c: li r8, 0
|
||||
0x82451340: addi r7, r31, 88
|
||||
0x82451344: mr r6, r29
|
||||
0x82451348: mr r5, r29
|
||||
0x8245134c: mr r4, r28
|
||||
0x82451350: lwz r11, 0(r3)
|
||||
0x82451354: lwz r11, 28(r11)
|
||||
0x82451358: mtctr r11
|
||||
0x8245135c: bctrl
|
||||
0x82451360: clrlwi r11, r3, 24
|
||||
0x82451364: cmplwi cr6, r11, 0x0
|
||||
0x82451368: beq cr6, 0x82451684
|
||||
0x8245136c: lwz r11, 28(r30)
|
||||
0x82451370: rlwinm r11, r11, 0, 28, 28
|
||||
0x82451374: cmplwi cr6, r11, 0x0
|
||||
@@ -1,52 +0,0 @@
|
||||
=== Fire counts ===
|
||||
ours: 3
|
||||
canary: 7
|
||||
|
||||
=== Per-LR breakdown ===
|
||||
ours:
|
||||
lr=0x82458674: 3
|
||||
canary:
|
||||
lr=0x82457bd4: 2
|
||||
lr=0x82458674: 5
|
||||
|
||||
=== Side-by-side first 5 fires (entry registers) ===
|
||||
|
||||
--- fire #0 ---
|
||||
ours: tid=6 cycle=363 lr=0x82458674 r3=0x40ba9ac0
|
||||
dump: 419fecda 000007f6 00000000 41d7dd10 00001688 00000000 00000000 41f5dd80 82457958 823f53f0 00000000 00000000 00000001 00000000 00000000 4024a5c0
|
||||
canary: tid=11 cycle=<unk> lr=0x82458674 r3=0xbccc4ac0 r4=0x00000000 r5=0x00000001 r6=0x00000001 r7=0x00000000
|
||||
dump: bdb19cda 000007f6 00000000 bde98d10 00001688 00000000 00000000 be078d80 82457958 823f53f0 00000000 00000000 00000001 00000000 00000000 bc365760
|
||||
|
||||
--- fire #1 ---
|
||||
ours: tid=6 cycle=140548 lr=0x82458674 r3=0x40ba9b80
|
||||
dump: 42c0f09a 00018ff6 00000000 43777210 0004d055 00000000 00000000 41f60d80 82457958 823f53f0 00000000 00000000 00000001 00000000 00000000 4024a960
|
||||
canary: tid=11 cycle=<unk> lr=0x82458674 r3=0xbccc4b80 r4=0x00000000 r5=0x00000001 r6=0x00000001 r7=0x00000000
|
||||
dump: bed2a09a 00018ff6 00000000 bf892210 0004d055 00000000 00000000 be07bd80 82457958 823f53f0 00000000 00000000 00000001 00000000 00000000 bc365840
|
||||
|
||||
--- fire #2 ---
|
||||
ours: tid=6 cycle=5957876 lr=0x82458674 r3=0x40ba9b80
|
||||
dump: 419fecda 000007f6 00000000 414f5f70 000003b9 00000000 00000000 41f60d80 82457958 823f53f0 00000000 00000040 00000001 00000000 00000000 4024a980
|
||||
canary: tid=11 cycle=<unk> lr=0x82458674 r3=0xbccc4b80 r4=0x00000000 r5=0x00000001 r6=0x00000001 r7=0x00000000
|
||||
dump: bdb19cda 000007f6 00000000 bd610b90 000003b9 00000000 00000000 be07bd80 82457958 823f53f0 00000000 00000040 00000001 00000000 00000000 bc365860
|
||||
|
||||
--- fire #3 ---
|
||||
ours: <no fire>
|
||||
canary: tid=11 cycle=<unk> lr=0x82458674 r3=0xbccc5300 r4=0x00000000 r5=0x00000001 r6=0x00000001 r7=0x00000000
|
||||
dump: bdb1acda 000007f6 00000000 bce24ed0 00000167 00000000 00000000 be07bd80 82457958 823f53f0 00000000 00000000 00000001 00000000 00000000 bc365f40
|
||||
|
||||
--- fire #4 ---
|
||||
ours: <no fire>
|
||||
canary: tid=6 cycle=<unk> lr=0x82457bd4 r3=0x701cf3c0 r4=0x00000004 r5=0x00002530 r6=0x00008000 r7=0x00000001
|
||||
dump: be95af9a 0000c170 00000000 b2050010 000681e9 00000000 00000000 be07bd80 82457958 823f53f0 00000000 0000c17a 00000001 701cf4e0 00000000 be95af90
|
||||
|
||||
=== Equivalence check: u32 lanes at +0x04 and +0x10 (work-item magic + counter) ===
|
||||
Both fields are stable identifiers across engines (host VAs differ but data should match).
|
||||
|
||||
Index of fields:
|
||||
[+0x04] = work-item 'size?' (looks like a length field)
|
||||
[+0x10] = state counter (per round 30, this is [+128/4 ?]) — but in dump it's u32[4]
|
||||
|
||||
ours [+04,+10]: [(2038, 5768), (102390, 315477), (2038, 953)]
|
||||
canary [+04,+10]: [(2038, 5768), (102390, 315477), (2038, 953), (2038, 359), (49520, 426473), (232195, 999643), (6134, 13763)]
|
||||
|
||||
ours fires whose [+04,+10] match a canary fire: 3/3
|
||||
@@ -1,175 +0,0 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Round 35 lockstep diff: align sub_8280AD40 entry fires between
|
||||
ours (--audit-pc-probe-hex AUDIT-PC-PROBE / AUDIT-R3-DUMP) and
|
||||
canary (AUDIT-HLC JitProlog).
|
||||
|
||||
Outputs side-by-side rendering of:
|
||||
- per-fire entry register snapshot (r3..r10, lr)
|
||||
- 64-byte r3 dump (u32 lanes, big-endian)
|
||||
Alignment is by tid + invocation order (no input-equivalence required).
|
||||
"""
|
||||
import re
|
||||
import sys
|
||||
import os
|
||||
|
||||
THIS_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||
OURS_LOG = os.path.join(THIS_DIR, "ours.log")
|
||||
CANARY_LOG = os.path.join(
|
||||
os.path.dirname(THIS_DIR), "round35-lockstep-inflate-canary", "canary.log"
|
||||
)
|
||||
|
||||
PC_TARGET = 0x8280AD40
|
||||
|
||||
|
||||
def parse_ours(path):
|
||||
"""Pair AUDIT-PC-PROBE lines with their following AUDIT-R3-DUMP lines."""
|
||||
fires = []
|
||||
cur = None
|
||||
with open(path) as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if line.startswith("AUDIT-PC-PROBE"):
|
||||
m = re.search(
|
||||
r"pc=0x([0-9a-f]+) tid=(\d+) hw=\d+ cycle=(\d+) lr=0x([0-9a-f]+) r3=0x([0-9a-f]+) r11=0x([0-9a-f]+)",
|
||||
line,
|
||||
)
|
||||
if not m:
|
||||
continue
|
||||
pc = int(m.group(1), 16)
|
||||
if pc != PC_TARGET:
|
||||
cur = None
|
||||
continue
|
||||
cur = {
|
||||
"tid": int(m.group(2)),
|
||||
"cycle": int(m.group(3)),
|
||||
"lr": int(m.group(4), 16),
|
||||
"r3": int(m.group(5), 16),
|
||||
"dump": [],
|
||||
}
|
||||
fires.append(cur)
|
||||
elif line.startswith("AUDIT-R3-DUMP") and cur is not None:
|
||||
lanes = re.findall(r"\+0x[0-9a-f]+=0x([0-9a-f]+)", line)
|
||||
cur["dump"] = [int(x, 16) for x in lanes]
|
||||
cur = None
|
||||
return fires
|
||||
|
||||
|
||||
def parse_canary(path):
|
||||
"""Pair AUDIT-HLC JitProlog header lines with following r3+NN dump lines."""
|
||||
fires = []
|
||||
cur = None
|
||||
hdr_re = re.compile(
|
||||
r"AUDIT-HLC JitProlog pc=8280AD40 tid=([0-9A-F]+) r3=([0-9A-F]+) r4=([0-9A-F]+) "
|
||||
r"r5=([0-9A-F]+) r6=([0-9A-F]+) r7=([0-9A-F]+) r8=([0-9A-F]+) r9=([0-9A-F]+) r10=([0-9A-F]+) lr=([0-9A-F]+)"
|
||||
)
|
||||
dump_re = re.compile(
|
||||
r"AUDIT-HLC JitProlog pc=8280AD40 r3\+([0-9A-F]+): ([0-9A-F]+) ([0-9A-F]+) ([0-9A-F]+) ([0-9A-F]+)"
|
||||
)
|
||||
with open(path) as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
m = hdr_re.search(line)
|
||||
if m:
|
||||
cur = {
|
||||
"tid": int(m.group(1), 16),
|
||||
"r3": int(m.group(2), 16),
|
||||
"r4": int(m.group(3), 16),
|
||||
"r5": int(m.group(4), 16),
|
||||
"r6": int(m.group(5), 16),
|
||||
"r7": int(m.group(6), 16),
|
||||
"r8": int(m.group(7), 16),
|
||||
"r9": int(m.group(8), 16),
|
||||
"r10": int(m.group(9), 16),
|
||||
"lr": int(m.group(10), 16),
|
||||
"dump": [],
|
||||
}
|
||||
fires.append(cur)
|
||||
continue
|
||||
m = dump_re.search(line)
|
||||
if m and cur is not None:
|
||||
off = int(m.group(1), 16)
|
||||
for i in range(4):
|
||||
word = int(m.group(2 + i), 16)
|
||||
# extend dump to fit
|
||||
idx = off // 4 + i
|
||||
while len(cur["dump"]) <= idx:
|
||||
cur["dump"].append(0)
|
||||
cur["dump"][idx] = word
|
||||
return fires
|
||||
|
||||
|
||||
def fmt_dump(d):
|
||||
return " ".join(f"{w:08x}" for w in d[:16])
|
||||
|
||||
|
||||
def main():
|
||||
ours = parse_ours(OURS_LOG)
|
||||
canary = parse_canary(CANARY_LOG)
|
||||
|
||||
print(f"=== Fire counts ===")
|
||||
print(f" ours: {len(ours)}")
|
||||
print(f" canary: {len(canary)}")
|
||||
print()
|
||||
|
||||
print(f"=== Per-LR breakdown ===")
|
||||
for label, fires in (("ours", ours), ("canary", canary)):
|
||||
lr_counts = {}
|
||||
for f in fires:
|
||||
lr_counts[f["lr"]] = lr_counts.get(f["lr"], 0) + 1
|
||||
print(f" {label}:")
|
||||
for lr, n in sorted(lr_counts.items()):
|
||||
print(f" lr=0x{lr:08x}: {n}")
|
||||
print()
|
||||
|
||||
print(f"=== Side-by-side first 5 fires (entry registers) ===")
|
||||
n = max(len(ours), len(canary))
|
||||
n = min(n, 5)
|
||||
for i in range(n):
|
||||
print(f"\n--- fire #{i} ---")
|
||||
if i < len(ours):
|
||||
f = ours[i]
|
||||
print(
|
||||
f" ours: tid={f['tid']:<3} cycle={f['cycle']:<10} lr=0x{f['lr']:08x} r3=0x{f['r3']:08x}"
|
||||
)
|
||||
print(f" dump: {fmt_dump(f['dump'])}")
|
||||
else:
|
||||
print(f" ours: <no fire>")
|
||||
if i < len(canary):
|
||||
f = canary[i]
|
||||
print(
|
||||
f" canary: tid={f['tid']:<3} cycle=<unk> lr=0x{f['lr']:08x} r3=0x{f['r3']:08x} "
|
||||
f"r4=0x{f['r4']:08x} r5=0x{f['r5']:08x} r6=0x{f['r6']:08x} r7=0x{f['r7']:08x}"
|
||||
)
|
||||
print(f" dump: {fmt_dump(f['dump'])}")
|
||||
else:
|
||||
print(f" canary: <no fire>")
|
||||
|
||||
print()
|
||||
print("=== Equivalence check: u32 lanes at +0x04 and +0x10 (work-item magic + counter) ===")
|
||||
print(" Both fields are stable identifiers across engines (host VAs differ but data should match).")
|
||||
print()
|
||||
print(" Index of fields:")
|
||||
print(" [+0x04] = work-item 'size?' (looks like a length field)")
|
||||
print(" [+0x10] = state counter (per round 30, this is [+128/4 ?]) — but in dump it's u32[4]")
|
||||
print()
|
||||
# +0x04 is dump[1], +0x10 is dump[4]
|
||||
ours_keys = [(f["dump"][1], f["dump"][4]) if len(f["dump"]) > 4 else None for f in ours]
|
||||
canary_keys = [(f["dump"][1], f["dump"][4]) if len(f["dump"]) > 4 else None for f in canary]
|
||||
print(f" ours [+04,+10]: {ours_keys}")
|
||||
print(f" canary [+04,+10]: {canary_keys}")
|
||||
print()
|
||||
# Cross-match: every ours key should appear in canary (canary is a superset)
|
||||
matched = []
|
||||
unmatched_ours = []
|
||||
for k in ours_keys:
|
||||
if k in canary_keys:
|
||||
matched.append(k)
|
||||
else:
|
||||
unmatched_ours.append(k)
|
||||
print(f" ours fires whose [+04,+10] match a canary fire: {len(matched)}/{len(ours)}")
|
||||
if unmatched_ours:
|
||||
print(f" ours fires with NO canary match: {unmatched_ours}")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -1,17 +0,0 @@
|
||||
K> F8000008 AUDIT-HLC JitProlog pc=821741C8 tid=00000006 r3=BCCC4A80 r4=00000018 r5=828F3888 r6=701CF924 r7=82456F00 r8=00000000 r9=00000000 r10=00000018 lr=822F1D5C
|
||||
K> F8000008 AUDIT-HLC JitProlog pc=821741C8 r3+00: BC22C910 00010004 00000000 000003E8
|
||||
K> F8000008 AUDIT-HLC JitProlog pc=821741C8 r3+10: 0101FFFF 00000000 00000000 01010000
|
||||
K> F8000008 AUDIT-HLC JitProlog pc=821741C8 r3+20: FFFFFFFF 00000000 00000000 00000000
|
||||
K> F8000008 AUDIT-HLC JitProlog pc=821741C8 r3+30: 00000000 BC365BC0 00000000 00000000
|
||||
K> F8000008 AUDIT-HLC JitProlog pc=821741C8 r3+40: 00000000 00000000 00000000 BDE9A398
|
||||
K> F8000008 AUDIT-HLC JitProlog pc=821741C8 r3+50: BC365560 00000000 00000000 00000000
|
||||
K> F8000008 AUDIT-HLC JitProlog pc=821741C8 r3+60: 00000000 00000000 00000000 01010040
|
||||
K> F8000008 AUDIT-HLC JitProlog pc=821741C8 r3+70: 00000000 00000000 00000000 FFFFFFFF
|
||||
K> F8000008 AUDIT-HLC JitProlog pc=821741C8 r3+80: 00000000 00000000 00000000 BC22C930
|
||||
K> F8000008 AUDIT-HLC JitProlog pc=821741C8 r3+90: 00000000 00000001 00000800 00000000
|
||||
K> F8000008 AUDIT-HLC JitProlog pc=821741C8 r3+A0: F800004C 00000000 00000000 BC365220
|
||||
K> F8000008 AUDIT-HLC JitProlog pc=821741C8 r3+B0: BC3655C0 00000000 00000000 00000000
|
||||
K> F8000008 AUDIT-HLC JitProlog pc=821741C8 r3+C0: 00CC0048 00460020 00460072 00650071
|
||||
K> F8000008 AUDIT-HLC JitProlog pc=821741C8 r3+D0: 00750065 006E0063 00790000 01010000
|
||||
K> F8000008 AUDIT-HLC JitProlog pc=821741C8 r3+E0: 00000000 00000000 00000000 FFFFFFFF
|
||||
K> F8000008 AUDIT-HLC JitProlog pc=821741C8 r3+F0: 00000000 00000000 00000000 BD610B80
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,89 +0,0 @@
|
||||
warn: CreateDXGIFactory2: Ignoring flags
|
||||
info: Game: xenia_canary.exe
|
||||
info: DXVK: v2.7.1
|
||||
info: Build: x86_64 gcc 15.1.0
|
||||
info: Vulkan: Found vkGetInstanceProcAddr in winevulkan.dll @ 0x6ffffbd84000
|
||||
info: Extension providers:
|
||||
info: Platform WSI
|
||||
info: OpenVR
|
||||
info: OpenVR: could not open registry key, status 2
|
||||
info: OpenVR: Failed to locate module
|
||||
info: OpenXR
|
||||
info: Enabled instance extensions:
|
||||
info: VK_EXT_surface_maintenance1
|
||||
info: VK_KHR_get_surface_capabilities2
|
||||
info: VK_KHR_surface
|
||||
info: VK_KHR_win32_surface
|
||||
info: Found device: NVIDIA GeForce GTX 1070 Ti (NVIDIA 580.159.3)
|
||||
info: Found device: llvmpipe (LLVM 20.1.2, 256 bits) (llvmpipe 25.2.8)
|
||||
info: Skipping: Software driver
|
||||
info: DXGI: Hiding actual GPU, reporting:
|
||||
info: vendor ID: 0x1002
|
||||
info: device ID: 0x73df
|
||||
warn: DxgiAdapter::QueryInterface: Unknown interface query
|
||||
warn: f0db4c7f-fe5a-42a2-bd62-f2a6cf6fc83e
|
||||
564.236:00dc:013c:info:vkd3d-proton:vkd3d_instance_apply_application_workarounds: Program name: "xenia_canary.exe" (hash: c099ade372da5277)
|
||||
564.236:00dc:013c:info:vkd3d-proton:vkd3d_instance_deduce_config_flags_from_environment: shader_cache is used, global_pipeline_cache is enforced.
|
||||
564.236:00dc:013c:info:vkd3d-proton:vkd3d_config_flags_init_once: VKD3D_CONFIG=''.
|
||||
564.240:00dc:013c:info:vkd3d-proton:vkd3d_get_vk_version: vkd3d-proton - applicationVersion: 3.0.1.
|
||||
564.240:00dc:013c:info:vkd3d-proton:vkd3d_instance_init: vkd3d-proton - build: 3b10bd7a7ec6a73.
|
||||
564.399:00dc:013c:info:vkd3d-proton:vkd3d_init_device_caps: Not all relevant pipeline stages are supported by EXT_dgc. Skipping.
|
||||
564.825:00dc:013c:info:vkd3d-proton:vkd3d_memory_info_decide_hvv_usage: Topology: Device heaps are split. Assuming small BAR situation.
|
||||
564.825:00dc:013c:info:vkd3d-proton:vkd3d_memory_info_upload_hvv_memory_properties: Topology: HVV usage is not allowed, using HOST_COHERENT for UPLOAD.
|
||||
564.827:00dc:013c:info:vkd3d-proton:vkd3d_bindless_state_get_bindless_flags: Device does not support VK_EXT_mutable_descriptor_type (or VALVE).
|
||||
564.827:00dc:013c:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
564.827:00dc:013c:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
564.827:00dc:013c:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
564.827:00dc:013c:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
564.827:00dc:013c:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
564.827:00dc:013c:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
564.827:00dc:013c:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
564.839:00dc:013c:info:vkd3d-proton:d3d12_device_caps_init_shader_model: Enabling support for SM 6.6.
|
||||
564.839:00dc:013c:fixme:vkd3d-proton:d3d12_device_caps_init_feature_options1: TotalLaneCount = 2432, may be inaccurate.
|
||||
564.839:00dc:013c:info:vkd3d-proton:d3d12_device_determine_ray_tracing_tier: DXR support enabled.
|
||||
564.840:00dc:013c:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Remapping VKD3D_SHADER_CACHE to: vkd3d-proton.cache.
|
||||
564.840:00dc:013c:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Attempting to load disk cache from: vkd3d-proton.cache.
|
||||
564.843:00dc:0154:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Performing async setup of stream archive ...
|
||||
564.844:00dc:0154:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_merge: Promoting write cache to read cache. No need to merge any disk caches.
|
||||
564.844:00dc:0154:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Merging pipeline libraries took 1.012 ms.
|
||||
564.845:00dc:0154:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Mapping read-only cache took 0.607 ms.
|
||||
564.845:00dc:0154:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Parsing stream archive took 0.370 ms.
|
||||
564.845:00dc:0154:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Done performing async setup of stream archive.
|
||||
564.903:00dc:013c:info:vkd3d-proton:vkd3d_get_vk_version: vkd3d-proton - applicationVersion: 3.0.1.
|
||||
564.903:00dc:013c:info:vkd3d-proton:vkd3d_instance_init: vkd3d-proton - build: 3b10bd7a7ec6a73.
|
||||
564.946:00dc:013c:info:vkd3d-proton:vkd3d_init_device_caps: Not all relevant pipeline stages are supported by EXT_dgc. Skipping.
|
||||
565.065:00dc:013c:info:vkd3d-proton:vkd3d_memory_info_decide_hvv_usage: Topology: Device heaps are split. Assuming small BAR situation.
|
||||
565.065:00dc:013c:info:vkd3d-proton:vkd3d_memory_info_upload_hvv_memory_properties: Topology: HVV usage is not allowed, using HOST_COHERENT for UPLOAD.
|
||||
565.066:00dc:013c:info:vkd3d-proton:vkd3d_bindless_state_get_bindless_flags: Device does not support VK_EXT_mutable_descriptor_type (or VALVE).
|
||||
565.066:00dc:013c:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
565.066:00dc:013c:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
565.066:00dc:013c:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
565.066:00dc:013c:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
565.066:00dc:013c:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
565.066:00dc:013c:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
565.066:00dc:013c:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
565.067:00dc:013c:info:vkd3d-proton:d3d12_device_caps_init_shader_model: Enabling support for SM 6.6.
|
||||
565.067:00dc:013c:fixme:vkd3d-proton:d3d12_device_caps_init_feature_options1: TotalLaneCount = 2432, may be inaccurate.
|
||||
565.067:00dc:013c:info:vkd3d-proton:d3d12_device_determine_ray_tracing_tier: DXR support enabled.
|
||||
565.067:00dc:013c:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Remapping VKD3D_SHADER_CACHE to: vkd3d-proton.cache.
|
||||
565.067:00dc:013c:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Attempting to load disk cache from: vkd3d-proton.cache.
|
||||
565.068:00dc:015c:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Performing async setup of stream archive ...
|
||||
565.068:00dc:015c:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_merge: No write cache exists. No need to merge any disk caches.
|
||||
565.068:00dc:015c:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Merging pipeline libraries took 0.136 ms.
|
||||
565.068:00dc:015c:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Mapping read-only cache took 0.221 ms.
|
||||
565.069:00dc:015c:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Parsing stream archive took 0.031 ms.
|
||||
565.069:00dc:015c:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Done performing async setup of stream archive.
|
||||
565.075:00dc:013c:fixme:vkd3d-proton:d3d12_command_queue_init: Ignoring priority 0x64.
|
||||
warn: DXGIGetDebugInterface1: Stub
|
||||
info: DXGI: Hiding actual GPU, reporting:
|
||||
info: vendor ID: 0x1002
|
||||
info: device ID: 0x73df
|
||||
565.173:00dc:00e0:info:vkd3d-proton:dxgi_vk_swap_chain_init: Creating swapchain (1280 x 720), BufferCount = 3.
|
||||
565.194:00dc:00e0:info:vkd3d-proton:dxgi_vk_swap_chain_init_sync_objects: Ensure maximum latency of 3 frames with KHR_present_wait.
|
||||
565.195:00dc:00e0:info:vkd3d-proton:dxgi_vk_swap_chain_init_sleep_state: Timer interval is 1.0 ms.
|
||||
warn: DXGI: MakeWindowAssociation: Ignoring flags
|
||||
warn: DxgiOutput::WaitForVBlank: Inaccurate
|
||||
info: Setting timer interval to 1000 us
|
||||
565.773:00dc:0164:info:vkd3d-proton:dxgi_vk_swap_chain_recreate_swapchain_in_present_task: Got 3 swapchain images.
|
||||
566.349:00dc:016c:fixme:vkd3d-proton:vkd3d_texture_view_desc_fixup: Remapping 2D to 2D_ARRAY. Needs Vulkan spec tightening to match D3D12 properly.
|
||||
566.387:00dc:0164:info:vkd3d-proton:dxgi_vk_swap_chain_recreate_swapchain_in_present_task: Got 3 swapchain images.
|
||||
@@ -1,89 +0,0 @@
|
||||
warn: CreateDXGIFactory2: Ignoring flags
|
||||
info: Game: xenia_canary.exe
|
||||
info: DXVK: v2.7.1
|
||||
info: Build: x86_64 gcc 15.1.0
|
||||
info: Vulkan: Found vkGetInstanceProcAddr in winevulkan.dll @ 0x6ffffbfb4000
|
||||
info: Extension providers:
|
||||
info: Platform WSI
|
||||
info: OpenVR
|
||||
info: OpenVR: could not open registry key, status 2
|
||||
info: OpenVR: Failed to locate module
|
||||
info: OpenXR
|
||||
info: Enabled instance extensions:
|
||||
info: VK_EXT_surface_maintenance1
|
||||
info: VK_KHR_get_surface_capabilities2
|
||||
info: VK_KHR_surface
|
||||
info: VK_KHR_win32_surface
|
||||
info: Found device: NVIDIA GeForce GTX 1070 Ti (NVIDIA 580.159.3)
|
||||
info: Found device: llvmpipe (LLVM 20.1.2, 256 bits) (llvmpipe 25.2.8)
|
||||
info: Skipping: Software driver
|
||||
info: DXGI: Hiding actual GPU, reporting:
|
||||
info: vendor ID: 0x1002
|
||||
info: device ID: 0x73df
|
||||
warn: DxgiAdapter::QueryInterface: Unknown interface query
|
||||
warn: f0db4c7f-fe5a-42a2-bd62-f2a6cf6fc83e
|
||||
805.907:00d0:0124:info:vkd3d-proton:vkd3d_instance_apply_application_workarounds: Program name: "xenia_canary.exe" (hash: c099ade372da5277)
|
||||
805.907:00d0:0124:info:vkd3d-proton:vkd3d_instance_deduce_config_flags_from_environment: shader_cache is used, global_pipeline_cache is enforced.
|
||||
805.907:00d0:0124:info:vkd3d-proton:vkd3d_config_flags_init_once: VKD3D_CONFIG=''.
|
||||
805.910:00d0:0124:info:vkd3d-proton:vkd3d_get_vk_version: vkd3d-proton - applicationVersion: 3.0.1.
|
||||
805.910:00d0:0124:info:vkd3d-proton:vkd3d_instance_init: vkd3d-proton - build: 3b10bd7a7ec6a73.
|
||||
805.955:00d0:0124:info:vkd3d-proton:vkd3d_init_device_caps: Not all relevant pipeline stages are supported by EXT_dgc. Skipping.
|
||||
806.100:00d0:0124:info:vkd3d-proton:vkd3d_memory_info_decide_hvv_usage: Topology: Device heaps are split. Assuming small BAR situation.
|
||||
806.100:00d0:0124:info:vkd3d-proton:vkd3d_memory_info_upload_hvv_memory_properties: Topology: HVV usage is not allowed, using HOST_COHERENT for UPLOAD.
|
||||
806.101:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_get_bindless_flags: Device does not support VK_EXT_mutable_descriptor_type (or VALVE).
|
||||
806.101:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
806.101:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
806.101:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
806.101:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
806.101:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
806.101:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
806.101:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
806.105:00d0:0124:info:vkd3d-proton:d3d12_device_caps_init_shader_model: Enabling support for SM 6.6.
|
||||
806.105:00d0:0124:fixme:vkd3d-proton:d3d12_device_caps_init_feature_options1: TotalLaneCount = 2432, may be inaccurate.
|
||||
806.105:00d0:0124:info:vkd3d-proton:d3d12_device_determine_ray_tracing_tier: DXR support enabled.
|
||||
806.105:00d0:0124:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Remapping VKD3D_SHADER_CACHE to: vkd3d-proton.cache.
|
||||
806.105:00d0:0124:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Attempting to load disk cache from: vkd3d-proton.cache.
|
||||
806.106:00d0:013c:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Performing async setup of stream archive ...
|
||||
806.106:00d0:013c:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_merge: No write cache exists. No need to merge any disk caches.
|
||||
806.106:00d0:013c:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Merging pipeline libraries took 0.161 ms.
|
||||
806.107:00d0:013c:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Mapping read-only cache took 0.185 ms.
|
||||
806.107:00d0:013c:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Parsing stream archive took 0.028 ms.
|
||||
806.107:00d0:013c:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Done performing async setup of stream archive.
|
||||
806.154:00d0:0124:info:vkd3d-proton:vkd3d_get_vk_version: vkd3d-proton - applicationVersion: 3.0.1.
|
||||
806.154:00d0:0124:info:vkd3d-proton:vkd3d_instance_init: vkd3d-proton - build: 3b10bd7a7ec6a73.
|
||||
806.197:00d0:0124:info:vkd3d-proton:vkd3d_init_device_caps: Not all relevant pipeline stages are supported by EXT_dgc. Skipping.
|
||||
806.310:00d0:0124:info:vkd3d-proton:vkd3d_memory_info_decide_hvv_usage: Topology: Device heaps are split. Assuming small BAR situation.
|
||||
806.310:00d0:0124:info:vkd3d-proton:vkd3d_memory_info_upload_hvv_memory_properties: Topology: HVV usage is not allowed, using HOST_COHERENT for UPLOAD.
|
||||
806.310:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_get_bindless_flags: Device does not support VK_EXT_mutable_descriptor_type (or VALVE).
|
||||
806.310:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
806.310:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
806.310:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
806.310:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
806.310:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
806.310:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
806.310:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
806.312:00d0:0124:info:vkd3d-proton:d3d12_device_caps_init_shader_model: Enabling support for SM 6.6.
|
||||
806.312:00d0:0124:fixme:vkd3d-proton:d3d12_device_caps_init_feature_options1: TotalLaneCount = 2432, may be inaccurate.
|
||||
806.312:00d0:0124:info:vkd3d-proton:d3d12_device_determine_ray_tracing_tier: DXR support enabled.
|
||||
806.312:00d0:0124:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Remapping VKD3D_SHADER_CACHE to: vkd3d-proton.cache.
|
||||
806.312:00d0:0124:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Attempting to load disk cache from: vkd3d-proton.cache.
|
||||
806.313:00d0:0144:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Performing async setup of stream archive ...
|
||||
806.313:00d0:0144:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_merge: No write cache exists. No need to merge any disk caches.
|
||||
806.313:00d0:0144:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Merging pipeline libraries took 0.156 ms.
|
||||
806.314:00d0:0144:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Mapping read-only cache took 0.659 ms.
|
||||
806.314:00d0:0144:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Parsing stream archive took 0.035 ms.
|
||||
806.314:00d0:0144:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Done performing async setup of stream archive.
|
||||
806.319:00d0:0124:fixme:vkd3d-proton:d3d12_command_queue_init: Ignoring priority 0x64.
|
||||
warn: DXGIGetDebugInterface1: Stub
|
||||
info: DXGI: Hiding actual GPU, reporting:
|
||||
info: vendor ID: 0x1002
|
||||
info: device ID: 0x73df
|
||||
806.408:00d0:00d4:info:vkd3d-proton:dxgi_vk_swap_chain_init: Creating swapchain (1280 x 720), BufferCount = 3.
|
||||
806.422:00d0:00d4:info:vkd3d-proton:dxgi_vk_swap_chain_init_sync_objects: Ensure maximum latency of 3 frames with KHR_present_wait.
|
||||
806.423:00d0:00d4:info:vkd3d-proton:dxgi_vk_swap_chain_init_sleep_state: Timer interval is 1.0 ms.
|
||||
warn: DXGI: MakeWindowAssociation: Ignoring flags
|
||||
warn: DxgiOutput::WaitForVBlank: Inaccurate
|
||||
info: Setting timer interval to 1000 us
|
||||
806.948:00d0:014c:info:vkd3d-proton:dxgi_vk_swap_chain_recreate_swapchain_in_present_task: Got 3 swapchain images.
|
||||
807.499:00d0:0154:fixme:vkd3d-proton:vkd3d_texture_view_desc_fixup: Remapping 2D to 2D_ARRAY. Needs Vulkan spec tightening to match D3D12 properly.
|
||||
807.521:00d0:014c:info:vkd3d-proton:dxgi_vk_swap_chain_recreate_swapchain_in_present_task: Got 3 swapchain images.
|
||||
@@ -1,89 +0,0 @@
|
||||
warn: CreateDXGIFactory2: Ignoring flags
|
||||
info: Game: xenia_canary.exe
|
||||
info: DXVK: v2.7.1
|
||||
info: Build: x86_64 gcc 15.1.0
|
||||
info: Vulkan: Found vkGetInstanceProcAddr in winevulkan.dll @ 0x6ffffbfb4000
|
||||
info: Extension providers:
|
||||
info: Platform WSI
|
||||
info: OpenVR
|
||||
info: OpenVR: could not open registry key, status 2
|
||||
info: OpenVR: Failed to locate module
|
||||
info: OpenXR
|
||||
info: Enabled instance extensions:
|
||||
info: VK_EXT_surface_maintenance1
|
||||
info: VK_KHR_get_surface_capabilities2
|
||||
info: VK_KHR_surface
|
||||
info: VK_KHR_win32_surface
|
||||
info: Found device: NVIDIA GeForce GTX 1070 Ti (NVIDIA 580.159.3)
|
||||
info: Found device: llvmpipe (LLVM 20.1.2, 256 bits) (llvmpipe 25.2.8)
|
||||
info: Skipping: Software driver
|
||||
info: DXGI: Hiding actual GPU, reporting:
|
||||
info: vendor ID: 0x1002
|
||||
info: device ID: 0x73df
|
||||
warn: DxgiAdapter::QueryInterface: Unknown interface query
|
||||
warn: f0db4c7f-fe5a-42a2-bd62-f2a6cf6fc83e
|
||||
893.096:00d4:0128:info:vkd3d-proton:vkd3d_instance_apply_application_workarounds: Program name: "xenia_canary.exe" (hash: c099ade372da5277)
|
||||
893.096:00d4:0128:info:vkd3d-proton:vkd3d_instance_deduce_config_flags_from_environment: shader_cache is used, global_pipeline_cache is enforced.
|
||||
893.096:00d4:0128:info:vkd3d-proton:vkd3d_config_flags_init_once: VKD3D_CONFIG=''.
|
||||
893.099:00d4:0128:info:vkd3d-proton:vkd3d_get_vk_version: vkd3d-proton - applicationVersion: 3.0.1.
|
||||
893.099:00d4:0128:info:vkd3d-proton:vkd3d_instance_init: vkd3d-proton - build: 3b10bd7a7ec6a73.
|
||||
893.145:00d4:0128:info:vkd3d-proton:vkd3d_init_device_caps: Not all relevant pipeline stages are supported by EXT_dgc. Skipping.
|
||||
893.308:00d4:0128:info:vkd3d-proton:vkd3d_memory_info_decide_hvv_usage: Topology: Device heaps are split. Assuming small BAR situation.
|
||||
893.308:00d4:0128:info:vkd3d-proton:vkd3d_memory_info_upload_hvv_memory_properties: Topology: HVV usage is not allowed, using HOST_COHERENT for UPLOAD.
|
||||
893.308:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_get_bindless_flags: Device does not support VK_EXT_mutable_descriptor_type (or VALVE).
|
||||
893.308:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
893.308:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
893.308:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
893.308:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
893.308:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
893.308:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
893.308:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
893.310:00d4:0128:info:vkd3d-proton:d3d12_device_caps_init_shader_model: Enabling support for SM 6.6.
|
||||
893.310:00d4:0128:fixme:vkd3d-proton:d3d12_device_caps_init_feature_options1: TotalLaneCount = 2432, may be inaccurate.
|
||||
893.310:00d4:0128:info:vkd3d-proton:d3d12_device_determine_ray_tracing_tier: DXR support enabled.
|
||||
893.310:00d4:0128:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Remapping VKD3D_SHADER_CACHE to: vkd3d-proton.cache.
|
||||
893.310:00d4:0128:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Attempting to load disk cache from: vkd3d-proton.cache.
|
||||
893.311:00d4:0140:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Performing async setup of stream archive ...
|
||||
893.311:00d4:0140:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_merge: No write cache exists. No need to merge any disk caches.
|
||||
893.311:00d4:0140:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Merging pipeline libraries took 0.187 ms.
|
||||
893.312:00d4:0140:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Mapping read-only cache took 0.161 ms.
|
||||
893.312:00d4:0140:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Parsing stream archive took 0.040 ms.
|
||||
893.312:00d4:0140:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Done performing async setup of stream archive.
|
||||
893.360:00d4:0128:info:vkd3d-proton:vkd3d_get_vk_version: vkd3d-proton - applicationVersion: 3.0.1.
|
||||
893.360:00d4:0128:info:vkd3d-proton:vkd3d_instance_init: vkd3d-proton - build: 3b10bd7a7ec6a73.
|
||||
893.405:00d4:0128:info:vkd3d-proton:vkd3d_init_device_caps: Not all relevant pipeline stages are supported by EXT_dgc. Skipping.
|
||||
893.520:00d4:0128:info:vkd3d-proton:vkd3d_memory_info_decide_hvv_usage: Topology: Device heaps are split. Assuming small BAR situation.
|
||||
893.520:00d4:0128:info:vkd3d-proton:vkd3d_memory_info_upload_hvv_memory_properties: Topology: HVV usage is not allowed, using HOST_COHERENT for UPLOAD.
|
||||
893.520:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_get_bindless_flags: Device does not support VK_EXT_mutable_descriptor_type (or VALVE).
|
||||
893.520:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
893.520:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
893.520:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
893.520:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
893.520:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
893.520:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
893.520:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
893.522:00d4:0128:info:vkd3d-proton:d3d12_device_caps_init_shader_model: Enabling support for SM 6.6.
|
||||
893.522:00d4:0128:fixme:vkd3d-proton:d3d12_device_caps_init_feature_options1: TotalLaneCount = 2432, may be inaccurate.
|
||||
893.522:00d4:0128:info:vkd3d-proton:d3d12_device_determine_ray_tracing_tier: DXR support enabled.
|
||||
893.522:00d4:0128:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Remapping VKD3D_SHADER_CACHE to: vkd3d-proton.cache.
|
||||
893.522:00d4:0128:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Attempting to load disk cache from: vkd3d-proton.cache.
|
||||
893.523:00d4:0148:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Performing async setup of stream archive ...
|
||||
893.523:00d4:0148:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_merge: No write cache exists. No need to merge any disk caches.
|
||||
893.523:00d4:0148:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Merging pipeline libraries took 0.153 ms.
|
||||
893.523:00d4:0148:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Mapping read-only cache took 0.199 ms.
|
||||
893.523:00d4:0148:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Parsing stream archive took 0.034 ms.
|
||||
893.523:00d4:0148:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Done performing async setup of stream archive.
|
||||
893.529:00d4:0128:fixme:vkd3d-proton:d3d12_command_queue_init: Ignoring priority 0x64.
|
||||
warn: DXGIGetDebugInterface1: Stub
|
||||
info: DXGI: Hiding actual GPU, reporting:
|
||||
info: vendor ID: 0x1002
|
||||
info: device ID: 0x73df
|
||||
893.622:00d4:00d8:info:vkd3d-proton:dxgi_vk_swap_chain_init: Creating swapchain (1280 x 720), BufferCount = 3.
|
||||
893.631:00d4:00d8:info:vkd3d-proton:dxgi_vk_swap_chain_init_sync_objects: Ensure maximum latency of 3 frames with KHR_present_wait.
|
||||
893.632:00d4:00d8:info:vkd3d-proton:dxgi_vk_swap_chain_init_sleep_state: Timer interval is 1.0 ms.
|
||||
warn: DXGI: MakeWindowAssociation: Ignoring flags
|
||||
warn: DxgiOutput::WaitForVBlank: Inaccurate
|
||||
info: Setting timer interval to 1000 us
|
||||
894.203:00d4:0150:info:vkd3d-proton:dxgi_vk_swap_chain_recreate_swapchain_in_present_task: Got 3 swapchain images.
|
||||
894.705:00d4:0158:fixme:vkd3d-proton:vkd3d_texture_view_desc_fixup: Remapping 2D to 2D_ARRAY. Needs Vulkan spec tightening to match D3D12 properly.
|
||||
894.727:00d4:0150:info:vkd3d-proton:dxgi_vk_swap_chain_recreate_swapchain_in_present_task: Got 3 swapchain images.
|
||||
@@ -1,89 +0,0 @@
|
||||
warn: CreateDXGIFactory2: Ignoring flags
|
||||
info: Game: xenia_canary.exe
|
||||
info: DXVK: v2.7.1
|
||||
info: Build: x86_64 gcc 15.1.0
|
||||
info: Vulkan: Found vkGetInstanceProcAddr in winevulkan.dll @ 0x6ffffbfb4000
|
||||
info: Extension providers:
|
||||
info: Platform WSI
|
||||
info: OpenVR
|
||||
info: OpenVR: could not open registry key, status 2
|
||||
info: OpenVR: Failed to locate module
|
||||
info: OpenXR
|
||||
info: Enabled instance extensions:
|
||||
info: VK_EXT_surface_maintenance1
|
||||
info: VK_KHR_get_surface_capabilities2
|
||||
info: VK_KHR_surface
|
||||
info: VK_KHR_win32_surface
|
||||
info: Found device: NVIDIA GeForce GTX 1070 Ti (NVIDIA 580.159.3)
|
||||
info: Found device: llvmpipe (LLVM 20.1.2, 256 bits) (llvmpipe 25.2.8)
|
||||
info: Skipping: Software driver
|
||||
info: DXGI: Hiding actual GPU, reporting:
|
||||
info: vendor ID: 0x1002
|
||||
info: device ID: 0x73df
|
||||
warn: DxgiAdapter::QueryInterface: Unknown interface query
|
||||
warn: f0db4c7f-fe5a-42a2-bd62-f2a6cf6fc83e
|
||||
956.778:00d0:0124:info:vkd3d-proton:vkd3d_instance_apply_application_workarounds: Program name: "xenia_canary.exe" (hash: c099ade372da5277)
|
||||
956.778:00d0:0124:info:vkd3d-proton:vkd3d_instance_deduce_config_flags_from_environment: shader_cache is used, global_pipeline_cache is enforced.
|
||||
956.778:00d0:0124:info:vkd3d-proton:vkd3d_config_flags_init_once: VKD3D_CONFIG=''.
|
||||
956.781:00d0:0124:info:vkd3d-proton:vkd3d_get_vk_version: vkd3d-proton - applicationVersion: 3.0.1.
|
||||
956.781:00d0:0124:info:vkd3d-proton:vkd3d_instance_init: vkd3d-proton - build: 3b10bd7a7ec6a73.
|
||||
956.826:00d0:0124:info:vkd3d-proton:vkd3d_init_device_caps: Not all relevant pipeline stages are supported by EXT_dgc. Skipping.
|
||||
956.983:00d0:0124:info:vkd3d-proton:vkd3d_memory_info_decide_hvv_usage: Topology: Device heaps are split. Assuming small BAR situation.
|
||||
956.983:00d0:0124:info:vkd3d-proton:vkd3d_memory_info_upload_hvv_memory_properties: Topology: HVV usage is not allowed, using HOST_COHERENT for UPLOAD.
|
||||
956.983:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_get_bindless_flags: Device does not support VK_EXT_mutable_descriptor_type (or VALVE).
|
||||
956.983:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
956.983:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
956.983:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
956.983:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
956.983:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
956.983:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
956.983:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
956.985:00d0:0124:info:vkd3d-proton:d3d12_device_caps_init_shader_model: Enabling support for SM 6.6.
|
||||
956.985:00d0:0124:fixme:vkd3d-proton:d3d12_device_caps_init_feature_options1: TotalLaneCount = 2432, may be inaccurate.
|
||||
956.985:00d0:0124:info:vkd3d-proton:d3d12_device_determine_ray_tracing_tier: DXR support enabled.
|
||||
956.985:00d0:0124:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Remapping VKD3D_SHADER_CACHE to: vkd3d-proton.cache.
|
||||
956.985:00d0:0124:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Attempting to load disk cache from: vkd3d-proton.cache.
|
||||
956.985:00d0:013c:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Performing async setup of stream archive ...
|
||||
956.986:00d0:013c:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_merge: No write cache exists. No need to merge any disk caches.
|
||||
956.986:00d0:013c:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Merging pipeline libraries took 0.171 ms.
|
||||
956.986:00d0:013c:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Mapping read-only cache took 0.269 ms.
|
||||
956.986:00d0:013c:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Parsing stream archive took 0.028 ms.
|
||||
956.986:00d0:013c:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Done performing async setup of stream archive.
|
||||
957.031:00d0:0124:info:vkd3d-proton:vkd3d_get_vk_version: vkd3d-proton - applicationVersion: 3.0.1.
|
||||
957.031:00d0:0124:info:vkd3d-proton:vkd3d_instance_init: vkd3d-proton - build: 3b10bd7a7ec6a73.
|
||||
957.075:00d0:0124:info:vkd3d-proton:vkd3d_init_device_caps: Not all relevant pipeline stages are supported by EXT_dgc. Skipping.
|
||||
957.186:00d0:0124:info:vkd3d-proton:vkd3d_memory_info_decide_hvv_usage: Topology: Device heaps are split. Assuming small BAR situation.
|
||||
957.186:00d0:0124:info:vkd3d-proton:vkd3d_memory_info_upload_hvv_memory_properties: Topology: HVV usage is not allowed, using HOST_COHERENT for UPLOAD.
|
||||
957.186:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_get_bindless_flags: Device does not support VK_EXT_mutable_descriptor_type (or VALVE).
|
||||
957.186:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
957.186:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
957.186:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
957.186:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
957.186:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
957.186:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
957.186:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
957.188:00d0:0124:info:vkd3d-proton:d3d12_device_caps_init_shader_model: Enabling support for SM 6.6.
|
||||
957.188:00d0:0124:fixme:vkd3d-proton:d3d12_device_caps_init_feature_options1: TotalLaneCount = 2432, may be inaccurate.
|
||||
957.188:00d0:0124:info:vkd3d-proton:d3d12_device_determine_ray_tracing_tier: DXR support enabled.
|
||||
957.188:00d0:0124:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Remapping VKD3D_SHADER_CACHE to: vkd3d-proton.cache.
|
||||
957.188:00d0:0124:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Attempting to load disk cache from: vkd3d-proton.cache.
|
||||
957.188:00d0:0144:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Performing async setup of stream archive ...
|
||||
957.188:00d0:0144:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_merge: No write cache exists. No need to merge any disk caches.
|
||||
957.189:00d0:0144:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Merging pipeline libraries took 0.172 ms.
|
||||
957.189:00d0:0144:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Mapping read-only cache took 0.231 ms.
|
||||
957.189:00d0:0144:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Parsing stream archive took 0.029 ms.
|
||||
957.189:00d0:0144:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Done performing async setup of stream archive.
|
||||
957.195:00d0:0124:fixme:vkd3d-proton:d3d12_command_queue_init: Ignoring priority 0x64.
|
||||
warn: DXGIGetDebugInterface1: Stub
|
||||
info: DXGI: Hiding actual GPU, reporting:
|
||||
info: vendor ID: 0x1002
|
||||
info: device ID: 0x73df
|
||||
957.285:00d0:00d4:info:vkd3d-proton:dxgi_vk_swap_chain_init: Creating swapchain (1280 x 720), BufferCount = 3.
|
||||
957.295:00d0:00d4:info:vkd3d-proton:dxgi_vk_swap_chain_init_sync_objects: Ensure maximum latency of 3 frames with KHR_present_wait.
|
||||
957.295:00d0:00d4:info:vkd3d-proton:dxgi_vk_swap_chain_init_sleep_state: Timer interval is 1.0 ms.
|
||||
warn: DXGI: MakeWindowAssociation: Ignoring flags
|
||||
warn: DxgiOutput::WaitForVBlank: Inaccurate
|
||||
info: Setting timer interval to 1000 us
|
||||
957.806:00d0:014c:info:vkd3d-proton:dxgi_vk_swap_chain_recreate_swapchain_in_present_task: Got 3 swapchain images.
|
||||
958.343:00d0:0154:fixme:vkd3d-proton:vkd3d_texture_view_desc_fixup: Remapping 2D to 2D_ARRAY. Needs Vulkan spec tightening to match D3D12 properly.
|
||||
958.382:00d0:014c:info:vkd3d-proton:dxgi_vk_swap_chain_recreate_swapchain_in_present_task: Got 3 swapchain images.
|
||||
@@ -1,89 +0,0 @@
|
||||
warn: CreateDXGIFactory2: Ignoring flags
|
||||
info: Game: xenia_canary.exe
|
||||
info: DXVK: v2.7.1
|
||||
info: Build: x86_64 gcc 15.1.0
|
||||
info: Vulkan: Found vkGetInstanceProcAddr in winevulkan.dll @ 0x6ffffbfb4000
|
||||
info: Extension providers:
|
||||
info: Platform WSI
|
||||
info: OpenVR
|
||||
info: OpenVR: could not open registry key, status 2
|
||||
info: OpenVR: Failed to locate module
|
||||
info: OpenXR
|
||||
info: Enabled instance extensions:
|
||||
info: VK_EXT_surface_maintenance1
|
||||
info: VK_KHR_get_surface_capabilities2
|
||||
info: VK_KHR_surface
|
||||
info: VK_KHR_win32_surface
|
||||
info: Found device: NVIDIA GeForce GTX 1070 Ti (NVIDIA 580.159.3)
|
||||
info: Found device: llvmpipe (LLVM 20.1.2, 256 bits) (llvmpipe 25.2.8)
|
||||
info: Skipping: Software driver
|
||||
info: DXGI: Hiding actual GPU, reporting:
|
||||
info: vendor ID: 0x1002
|
||||
info: device ID: 0x73df
|
||||
warn: DxgiAdapter::QueryInterface: Unknown interface query
|
||||
warn: f0db4c7f-fe5a-42a2-bd62-f2a6cf6fc83e
|
||||
1217.108:00d4:0128:info:vkd3d-proton:vkd3d_instance_apply_application_workarounds: Program name: "xenia_canary.exe" (hash: c099ade372da5277)
|
||||
1217.108:00d4:0128:info:vkd3d-proton:vkd3d_instance_deduce_config_flags_from_environment: shader_cache is used, global_pipeline_cache is enforced.
|
||||
1217.108:00d4:0128:info:vkd3d-proton:vkd3d_config_flags_init_once: VKD3D_CONFIG=''.
|
||||
1217.111:00d4:0128:info:vkd3d-proton:vkd3d_get_vk_version: vkd3d-proton - applicationVersion: 3.0.1.
|
||||
1217.111:00d4:0128:info:vkd3d-proton:vkd3d_instance_init: vkd3d-proton - build: 3b10bd7a7ec6a73.
|
||||
1217.160:00d4:0128:info:vkd3d-proton:vkd3d_init_device_caps: Not all relevant pipeline stages are supported by EXT_dgc. Skipping.
|
||||
1217.307:00d4:0128:info:vkd3d-proton:vkd3d_memory_info_decide_hvv_usage: Topology: Device heaps are split. Assuming small BAR situation.
|
||||
1217.307:00d4:0128:info:vkd3d-proton:vkd3d_memory_info_upload_hvv_memory_properties: Topology: HVV usage is not allowed, using HOST_COHERENT for UPLOAD.
|
||||
1217.307:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_get_bindless_flags: Device does not support VK_EXT_mutable_descriptor_type (or VALVE).
|
||||
1217.307:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1217.307:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1217.307:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1217.307:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1217.307:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1217.307:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1217.307:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1217.309:00d4:0128:info:vkd3d-proton:d3d12_device_caps_init_shader_model: Enabling support for SM 6.6.
|
||||
1217.309:00d4:0128:fixme:vkd3d-proton:d3d12_device_caps_init_feature_options1: TotalLaneCount = 2432, may be inaccurate.
|
||||
1217.309:00d4:0128:info:vkd3d-proton:d3d12_device_determine_ray_tracing_tier: DXR support enabled.
|
||||
1217.309:00d4:0128:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Remapping VKD3D_SHADER_CACHE to: vkd3d-proton.cache.
|
||||
1217.309:00d4:0128:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Attempting to load disk cache from: vkd3d-proton.cache.
|
||||
1217.310:00d4:0140:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Performing async setup of stream archive ...
|
||||
1217.310:00d4:0140:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_merge: No write cache exists. No need to merge any disk caches.
|
||||
1217.310:00d4:0140:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Merging pipeline libraries took 0.166 ms.
|
||||
1217.310:00d4:0140:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Mapping read-only cache took 0.173 ms.
|
||||
1217.310:00d4:0140:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Parsing stream archive took 0.031 ms.
|
||||
1217.310:00d4:0140:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Done performing async setup of stream archive.
|
||||
1217.360:00d4:0128:info:vkd3d-proton:vkd3d_get_vk_version: vkd3d-proton - applicationVersion: 3.0.1.
|
||||
1217.360:00d4:0128:info:vkd3d-proton:vkd3d_instance_init: vkd3d-proton - build: 3b10bd7a7ec6a73.
|
||||
1217.403:00d4:0128:info:vkd3d-proton:vkd3d_init_device_caps: Not all relevant pipeline stages are supported by EXT_dgc. Skipping.
|
||||
1217.515:00d4:0128:info:vkd3d-proton:vkd3d_memory_info_decide_hvv_usage: Topology: Device heaps are split. Assuming small BAR situation.
|
||||
1217.515:00d4:0128:info:vkd3d-proton:vkd3d_memory_info_upload_hvv_memory_properties: Topology: HVV usage is not allowed, using HOST_COHERENT for UPLOAD.
|
||||
1217.515:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_get_bindless_flags: Device does not support VK_EXT_mutable_descriptor_type (or VALVE).
|
||||
1217.515:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1217.515:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1217.515:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1217.515:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1217.515:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1217.515:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1217.515:00d4:0128:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1217.516:00d4:0128:info:vkd3d-proton:d3d12_device_caps_init_shader_model: Enabling support for SM 6.6.
|
||||
1217.516:00d4:0128:fixme:vkd3d-proton:d3d12_device_caps_init_feature_options1: TotalLaneCount = 2432, may be inaccurate.
|
||||
1217.516:00d4:0128:info:vkd3d-proton:d3d12_device_determine_ray_tracing_tier: DXR support enabled.
|
||||
1217.516:00d4:0128:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Remapping VKD3D_SHADER_CACHE to: vkd3d-proton.cache.
|
||||
1217.516:00d4:0128:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Attempting to load disk cache from: vkd3d-proton.cache.
|
||||
1217.517:00d4:0148:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Performing async setup of stream archive ...
|
||||
1217.517:00d4:0148:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_merge: No write cache exists. No need to merge any disk caches.
|
||||
1217.517:00d4:0148:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Merging pipeline libraries took 0.157 ms.
|
||||
1217.517:00d4:0148:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Mapping read-only cache took 0.208 ms.
|
||||
1217.518:00d4:0148:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Parsing stream archive took 0.032 ms.
|
||||
1217.518:00d4:0148:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Done performing async setup of stream archive.
|
||||
1217.524:00d4:0128:fixme:vkd3d-proton:d3d12_command_queue_init: Ignoring priority 0x64.
|
||||
warn: DXGIGetDebugInterface1: Stub
|
||||
info: DXGI: Hiding actual GPU, reporting:
|
||||
info: vendor ID: 0x1002
|
||||
info: device ID: 0x73df
|
||||
1217.612:00d4:00d8:info:vkd3d-proton:dxgi_vk_swap_chain_init: Creating swapchain (1280 x 720), BufferCount = 3.
|
||||
1217.622:00d4:00d8:info:vkd3d-proton:dxgi_vk_swap_chain_init_sync_objects: Ensure maximum latency of 3 frames with KHR_present_wait.
|
||||
1217.622:00d4:00d8:info:vkd3d-proton:dxgi_vk_swap_chain_init_sleep_state: Timer interval is 1.0 ms.
|
||||
warn: DXGI: MakeWindowAssociation: Ignoring flags
|
||||
warn: DxgiOutput::WaitForVBlank: Inaccurate
|
||||
info: Setting timer interval to 1000 us
|
||||
1218.136:00d4:0150:info:vkd3d-proton:dxgi_vk_swap_chain_recreate_swapchain_in_present_task: Got 3 swapchain images.
|
||||
1218.678:00d4:0158:fixme:vkd3d-proton:vkd3d_texture_view_desc_fixup: Remapping 2D to 2D_ARRAY. Needs Vulkan spec tightening to match D3D12 properly.
|
||||
1218.699:00d4:0150:info:vkd3d-proton:dxgi_vk_swap_chain_recreate_swapchain_in_present_task: Got 3 swapchain images.
|
||||
@@ -1,89 +0,0 @@
|
||||
warn: CreateDXGIFactory2: Ignoring flags
|
||||
info: Game: xenia_canary.exe
|
||||
info: DXVK: v2.7.1
|
||||
info: Build: x86_64 gcc 15.1.0
|
||||
info: Vulkan: Found vkGetInstanceProcAddr in winevulkan.dll @ 0x6ffffbfb4000
|
||||
info: Extension providers:
|
||||
info: Platform WSI
|
||||
info: OpenVR
|
||||
info: OpenVR: could not open registry key, status 2
|
||||
info: OpenVR: Failed to locate module
|
||||
info: OpenXR
|
||||
info: Enabled instance extensions:
|
||||
info: VK_EXT_surface_maintenance1
|
||||
info: VK_KHR_get_surface_capabilities2
|
||||
info: VK_KHR_surface
|
||||
info: VK_KHR_win32_surface
|
||||
info: Found device: NVIDIA GeForce GTX 1070 Ti (NVIDIA 580.159.3)
|
||||
info: Found device: llvmpipe (LLVM 20.1.2, 256 bits) (llvmpipe 25.2.8)
|
||||
info: Skipping: Software driver
|
||||
info: DXGI: Hiding actual GPU, reporting:
|
||||
info: vendor ID: 0x1002
|
||||
info: device ID: 0x73df
|
||||
warn: DxgiAdapter::QueryInterface: Unknown interface query
|
||||
warn: f0db4c7f-fe5a-42a2-bd62-f2a6cf6fc83e
|
||||
1413.916:00d0:0124:info:vkd3d-proton:vkd3d_instance_apply_application_workarounds: Program name: "xenia_canary.exe" (hash: c099ade372da5277)
|
||||
1413.916:00d0:0124:info:vkd3d-proton:vkd3d_instance_deduce_config_flags_from_environment: shader_cache is used, global_pipeline_cache is enforced.
|
||||
1413.916:00d0:0124:info:vkd3d-proton:vkd3d_config_flags_init_once: VKD3D_CONFIG=''.
|
||||
1413.919:00d0:0124:info:vkd3d-proton:vkd3d_get_vk_version: vkd3d-proton - applicationVersion: 3.0.1.
|
||||
1413.919:00d0:0124:info:vkd3d-proton:vkd3d_instance_init: vkd3d-proton - build: 3b10bd7a7ec6a73.
|
||||
1413.963:00d0:0124:info:vkd3d-proton:vkd3d_init_device_caps: Not all relevant pipeline stages are supported by EXT_dgc. Skipping.
|
||||
1414.109:00d0:0124:info:vkd3d-proton:vkd3d_memory_info_decide_hvv_usage: Topology: Device heaps are split. Assuming small BAR situation.
|
||||
1414.109:00d0:0124:info:vkd3d-proton:vkd3d_memory_info_upload_hvv_memory_properties: Topology: HVV usage is not allowed, using HOST_COHERENT for UPLOAD.
|
||||
1414.109:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_get_bindless_flags: Device does not support VK_EXT_mutable_descriptor_type (or VALVE).
|
||||
1414.109:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1414.109:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1414.109:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1414.109:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1414.109:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1414.109:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1414.109:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1414.111:00d0:0124:info:vkd3d-proton:d3d12_device_caps_init_shader_model: Enabling support for SM 6.6.
|
||||
1414.111:00d0:0124:fixme:vkd3d-proton:d3d12_device_caps_init_feature_options1: TotalLaneCount = 2432, may be inaccurate.
|
||||
1414.111:00d0:0124:info:vkd3d-proton:d3d12_device_determine_ray_tracing_tier: DXR support enabled.
|
||||
1414.111:00d0:0124:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Remapping VKD3D_SHADER_CACHE to: vkd3d-proton.cache.
|
||||
1414.111:00d0:0124:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Attempting to load disk cache from: vkd3d-proton.cache.
|
||||
1414.112:00d0:013c:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Performing async setup of stream archive ...
|
||||
1414.112:00d0:013c:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_merge: No write cache exists. No need to merge any disk caches.
|
||||
1414.112:00d0:013c:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Merging pipeline libraries took 0.173 ms.
|
||||
1414.113:00d0:013c:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Mapping read-only cache took 0.276 ms.
|
||||
1414.113:00d0:013c:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Parsing stream archive took 0.029 ms.
|
||||
1414.113:00d0:013c:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Done performing async setup of stream archive.
|
||||
1414.157:00d0:0124:info:vkd3d-proton:vkd3d_get_vk_version: vkd3d-proton - applicationVersion: 3.0.1.
|
||||
1414.157:00d0:0124:info:vkd3d-proton:vkd3d_instance_init: vkd3d-proton - build: 3b10bd7a7ec6a73.
|
||||
1414.199:00d0:0124:info:vkd3d-proton:vkd3d_init_device_caps: Not all relevant pipeline stages are supported by EXT_dgc. Skipping.
|
||||
1414.310:00d0:0124:info:vkd3d-proton:vkd3d_memory_info_decide_hvv_usage: Topology: Device heaps are split. Assuming small BAR situation.
|
||||
1414.310:00d0:0124:info:vkd3d-proton:vkd3d_memory_info_upload_hvv_memory_properties: Topology: HVV usage is not allowed, using HOST_COHERENT for UPLOAD.
|
||||
1414.311:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_get_bindless_flags: Device does not support VK_EXT_mutable_descriptor_type (or VALVE).
|
||||
1414.311:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1414.311:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1414.311:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1414.311:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1414.311:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1414.311:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1414.311:00d0:0124:info:vkd3d-proton:vkd3d_bindless_state_add_binding: Device supports VK_EXT_descriptor_buffer!
|
||||
1414.312:00d0:0124:info:vkd3d-proton:d3d12_device_caps_init_shader_model: Enabling support for SM 6.6.
|
||||
1414.312:00d0:0124:fixme:vkd3d-proton:d3d12_device_caps_init_feature_options1: TotalLaneCount = 2432, may be inaccurate.
|
||||
1414.312:00d0:0124:info:vkd3d-proton:d3d12_device_determine_ray_tracing_tier: DXR support enabled.
|
||||
1414.312:00d0:0124:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Remapping VKD3D_SHADER_CACHE to: vkd3d-proton.cache.
|
||||
1414.312:00d0:0124:info:vkd3d-proton:vkd3d_pipeline_library_init_disk_cache: Attempting to load disk cache from: vkd3d-proton.cache.
|
||||
1414.313:00d0:0144:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Performing async setup of stream archive ...
|
||||
1414.313:00d0:0144:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_merge: No write cache exists. No need to merge any disk caches.
|
||||
1414.313:00d0:0144:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Merging pipeline libraries took 0.158 ms.
|
||||
1414.313:00d0:0144:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Mapping read-only cache took 0.256 ms.
|
||||
1414.313:00d0:0144:info:vkd3d-proton:vkd3d_pipeline_library_disk_cache_initial_setup: Parsing stream archive took 0.031 ms.
|
||||
1414.313:00d0:0144:info:vkd3d-proton:vkd3d_pipeline_library_disk_thread_main: Done performing async setup of stream archive.
|
||||
1414.319:00d0:0124:fixme:vkd3d-proton:d3d12_command_queue_init: Ignoring priority 0x64.
|
||||
warn: DXGIGetDebugInterface1: Stub
|
||||
info: DXGI: Hiding actual GPU, reporting:
|
||||
info: vendor ID: 0x1002
|
||||
info: device ID: 0x73df
|
||||
1414.406:00d0:00d4:info:vkd3d-proton:dxgi_vk_swap_chain_init: Creating swapchain (1280 x 720), BufferCount = 3.
|
||||
1414.416:00d0:00d4:info:vkd3d-proton:dxgi_vk_swap_chain_init_sync_objects: Ensure maximum latency of 3 frames with KHR_present_wait.
|
||||
1414.416:00d0:00d4:info:vkd3d-proton:dxgi_vk_swap_chain_init_sleep_state: Timer interval is 1.0 ms.
|
||||
warn: DXGI: MakeWindowAssociation: Ignoring flags
|
||||
warn: DxgiOutput::WaitForVBlank: Inaccurate
|
||||
info: Setting timer interval to 1000 us
|
||||
1414.927:00d0:014c:info:vkd3d-proton:dxgi_vk_swap_chain_recreate_swapchain_in_present_task: Got 3 swapchain images.
|
||||
1415.477:00d0:0154:fixme:vkd3d-proton:vkd3d_texture_view_desc_fixup: Remapping 2D to 2D_ARRAY. Needs Vulkan spec tightening to match D3D12 properly.
|
||||
1415.500:00d0:014c:info:vkd3d-proton:dxgi_vk_swap_chain_recreate_swapchain_in_present_task: Got 3 swapchain images.
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -2479,6 +2479,10 @@ struct WorkerCtx {
|
||||
hw_id: u8,
|
||||
block_cache: xenia_cpu::block_cache::BlockCache,
|
||||
decode_cache: xenia_cpu::decoder::DecodeCache,
|
||||
/// Compiled-block cache (Cranelift JIT). Keyed identically to `block_cache`
|
||||
/// on `(start_pc, page_version)`; owns the JIT module and thus the native
|
||||
/// code. Only consulted on the `XENIA_JIT` / `XENIA_JIT_DIFF` paths.
|
||||
jit_cache: xenia_cpu::jit::JitCache,
|
||||
force_per_instr: bool,
|
||||
}
|
||||
|
||||
@@ -2488,6 +2492,7 @@ impl WorkerCtx {
|
||||
hw_id,
|
||||
block_cache: xenia_cpu::block_cache::BlockCache::new(),
|
||||
decode_cache: xenia_cpu::decoder::DecodeCache::new(),
|
||||
jit_cache: xenia_cpu::jit::JitCache::new(),
|
||||
force_per_instr,
|
||||
}
|
||||
}
|
||||
@@ -3001,10 +3006,20 @@ fn worker_epilogue(
|
||||
/// swaps / packets track the one-block baseline), then a sharp cliff at
|
||||
/// ~384 collapses the present loop (a producer/consumer boot handoff
|
||||
/// starves when one slot runs too long without returning to the round).
|
||||
/// 128 sits 3× below that cliff with ~1.65× boot-to-splash speedup — a
|
||||
/// deliberately conservative pick (correctness over the last few %). The
|
||||
/// `XENIA_SUPERBLOCK_BUDGET` env var overrides it for further tuning.
|
||||
const SUPERBLOCK_INSTR_BUDGET: u64 = 128;
|
||||
///
|
||||
/// Re-tuned against the INTRO-VIDEO workload (2026-07-06, XENIA_PROFILE
|
||||
/// attribution): the per-slot-visit tax (worker_prologue + worker_epilogue)
|
||||
/// was ~22% of movie wall, and raising the budget cuts slot-visits ~in
|
||||
/// proportion (chains are NOT break-limited here — 128→192 dropped visits
|
||||
/// 27.4M→18.9M, −31%; 128→256 −44%). But the movie's decode pipeline is more
|
||||
/// timing-sensitive than boot: at 256 the decode worker tid25 (0x82506588)
|
||||
/// INTERMITTENTLY fails to resume (1-of-2 runs) and the feeder loop weakens
|
||||
/// (source-read 27→5-11) — a scheduling race the coarser interleaving exposes.
|
||||
/// 192 is the sweet spot: 3/3 runs byte-identical (source-read=21,
|
||||
/// tid25-resume=1, ADVreads=30) with ~−7% movie wall, and it stays well below
|
||||
/// the 384 boot cliff. Do NOT raise past 192 without re-validating tid25
|
||||
/// resume across several runs. `XENIA_SUPERBLOCK_BUDGET` overrides for A/B.
|
||||
const SUPERBLOCK_INSTR_BUDGET: u64 = 192;
|
||||
|
||||
/// Effective superblock budget. Defaults to [`SUPERBLOCK_INSTR_BUDGET`];
|
||||
/// `XENIA_SUPERBLOCK_BUDGET` overrides it (A/B tuning without a rebuild).
|
||||
@@ -3068,6 +3083,26 @@ fn run_superblock(
|
||||
|
||||
let budget = superblock_budget();
|
||||
|
||||
// Install the JIT superblock-chaining config once per run (idempotent). The
|
||||
// gate is deliberately conservative and stable for a run: chaining requires
|
||||
// `XENIA_JIT_CHAIN`, the diff harness OFF (a multi-block superblock can't be
|
||||
// compared against one interpreter step), and NO diagnostic probes / mem-watch
|
||||
// armed (chaining runs several blocks natively without the per-block-entry
|
||||
// observation the Heisenbug fix fires inside this loop — so chaining and
|
||||
// probes are mutually exclusive). Probes/mem-watch are env-armed at startup,
|
||||
// so evaluating this once is sound; a cached block never has to change shape.
|
||||
if !wc.jit_cache.is_configured() {
|
||||
let chain_enabled = xenia_cpu::recompiler::chain_requested()
|
||||
&& xenia_cpu::recompiler::jit_enabled()
|
||||
&& !xenia_cpu::recompiler::diff_enabled()
|
||||
&& !kernel.any_probe_active()
|
||||
&& !mem.has_mem_watch();
|
||||
wc.jit_cache.set_chain_config(xenia_cpu::jit::ChainConfig {
|
||||
enabled: chain_enabled,
|
||||
thunk_band: kernel.thunk_band(),
|
||||
});
|
||||
}
|
||||
|
||||
// Heisenbug fix (toolkit audit, 2026-06-21): probes and mem-watch are
|
||||
// OBSERVE-ONLY diagnostics and must NOT change guest scheduling. The
|
||||
// previous implementation disabled superblock chaining whenever any
|
||||
@@ -3129,7 +3164,22 @@ fn run_superblock(
|
||||
let _prof_t0 = xenia_gpu::prof::is_on().then(std::time::Instant::now);
|
||||
let result = {
|
||||
let ctx = kernel.scheduler.ctx_mut_ref(thread_ref);
|
||||
step_block(ctx, mem, block)
|
||||
// JIT seam (M0). run_superblock's chain-loop + stop-conditions are
|
||||
// unchanged; only the block body is routed:
|
||||
// - XENIA_JIT_DIFF: interpreter authoritative + JIT checked in-process,
|
||||
// - XENIA_JIT: JIT authoritative (M0 = interpreter fallback),
|
||||
// - else: interpreter directly.
|
||||
if xenia_cpu::recompiler::diff_enabled() {
|
||||
xenia_cpu::recompiler::diff_step(ctx, mem, block, &mut wc.jit_cache)
|
||||
} else if xenia_cpu::recompiler::jit_enabled() {
|
||||
// Hand the JIT the remaining budget so a superblock stops
|
||||
// chaining at exactly the same instruction count the runner
|
||||
// would (`total_executed >= budget`).
|
||||
let remaining = budget.saturating_sub(total_executed);
|
||||
xenia_cpu::recompiler::run_block(ctx, mem, block, &mut wc.jit_cache, remaining)
|
||||
} else {
|
||||
step_block(ctx, mem, block)
|
||||
}
|
||||
};
|
||||
let executed = kernel
|
||||
.scheduler
|
||||
@@ -3194,6 +3244,12 @@ fn run_superblock(
|
||||
}
|
||||
};
|
||||
|
||||
let _ep_pt = xenia_gpu::prof::is_on().then(|| {
|
||||
xenia_gpu::prof::ScopeTimer::new(
|
||||
&xenia_gpu::prof::EPILOGUE_NS,
|
||||
&xenia_gpu::prof::EPILOGUE_CALLS,
|
||||
)
|
||||
});
|
||||
worker_epilogue(
|
||||
wc,
|
||||
kernel,
|
||||
@@ -3302,6 +3358,8 @@ fn run_execution(
|
||||
// then drain any pending auto-signals whose deadline has passed.
|
||||
// Both calls are no-ops when `XENIA_SILPH_UI_AUTOSIGNAL_DELAY`
|
||||
// is unset (the pending queue stays empty).
|
||||
let _round_pt = xenia_gpu::prof::is_on()
|
||||
.then(|| xenia_gpu::prof::ScopeTimer::new(&xenia_gpu::prof::ROUND_NS, &xenia_gpu::prof::ROUND_CALLS));
|
||||
kernel.set_now_cycle_hint(stats.instruction_count);
|
||||
// Drive the coherent monotonic "now" the kernel deadline-arithmetic
|
||||
// reads (`KernelState::now_basis_at` -> `Scheduler::global_clock`)
|
||||
@@ -3336,6 +3394,7 @@ fn run_execution(
|
||||
// a reusable stack array instead of allocating a fresh Vec per round.
|
||||
kernel.scheduler.begin_round();
|
||||
let order_n = kernel.scheduler.round_schedule_into(&mut order_buf);
|
||||
drop(_round_pt); // end per-round tax measurement at the schedule boundary
|
||||
let order = &order_buf[..order_n];
|
||||
|
||||
if order.is_empty() {
|
||||
@@ -3360,7 +3419,13 @@ fn run_execution(
|
||||
|
||||
for &hw_id in order {
|
||||
let wc = &mut workers[hw_id as usize];
|
||||
match worker_prologue(
|
||||
let _pro_pt = xenia_gpu::prof::is_on().then(|| {
|
||||
xenia_gpu::prof::ScopeTimer::new(
|
||||
&xenia_gpu::prof::PROLOGUE_NS,
|
||||
&xenia_gpu::prof::PROLOGUE_CALLS,
|
||||
)
|
||||
});
|
||||
let prologue_outcome = worker_prologue(
|
||||
wc,
|
||||
kernel,
|
||||
mem,
|
||||
@@ -3368,7 +3433,9 @@ fn run_execution(
|
||||
&mut db_writer,
|
||||
thunk_map,
|
||||
&mut stats,
|
||||
) {
|
||||
);
|
||||
drop(_pro_pt);
|
||||
match prologue_outcome {
|
||||
PrologueOutcome::Continue => continue,
|
||||
PrologueOutcome::BreakOuter => break 'outer,
|
||||
PrologueOutcome::StepBlock {
|
||||
@@ -3385,7 +3452,13 @@ fn run_execution(
|
||||
// the per-round (timebase / coord / round_schedule)
|
||||
// and per-slot (prologue) tax over hundreds of
|
||||
// instructions instead of ~6. See `run_superblock`.
|
||||
match run_superblock(
|
||||
let _sb_pt = xenia_gpu::prof::is_on().then(|| {
|
||||
xenia_gpu::prof::ScopeTimer::new(
|
||||
&xenia_gpu::prof::RUNSB_NS,
|
||||
&xenia_gpu::prof::RUNSB_CALLS,
|
||||
)
|
||||
});
|
||||
let sb_outcome = run_superblock(
|
||||
wc,
|
||||
kernel,
|
||||
mem,
|
||||
@@ -3396,7 +3469,9 @@ fn run_execution(
|
||||
thread_ref,
|
||||
block_ptr,
|
||||
pc_before,
|
||||
) {
|
||||
);
|
||||
drop(_sb_pt);
|
||||
match sb_outcome {
|
||||
SlotOutcome::Continue => continue,
|
||||
SlotOutcome::BreakOuter => break 'outer,
|
||||
}
|
||||
@@ -4348,6 +4423,12 @@ fn dump_thread_diagnostic(
|
||||
if xenia_gpu::prof::enabled() {
|
||||
xenia_gpu::prof::report(0);
|
||||
}
|
||||
// JIT differential harness: checked/skipped/mismatch tally at clean exit.
|
||||
xenia_cpu::recompiler::report_diff_summary();
|
||||
// JIT native-vs-interpreted block coverage at clean exit.
|
||||
xenia_cpu::recompiler::report_jit_summary();
|
||||
// JIT opcode-frequency histogram (XENIA_JIT_HIST) — drives M1 coverage.
|
||||
xenia_cpu::recompiler::report_histogram();
|
||||
|
||||
// STEP-10 diagnostic (observe-only, env-gated `XENIA_DUMP_SLOTS=1`).
|
||||
// Prints each scheduler slot's full runqueue with the fields needed to
|
||||
|
||||
@@ -10,6 +10,10 @@ xenia-memory = { workspace = true }
|
||||
tracing = { workspace = true }
|
||||
bitflags = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
cranelift-jit = "0.128.4"
|
||||
cranelift-frontend = "0.128.4"
|
||||
cranelift-module = "0.128.4"
|
||||
cranelift-codegen = "0.128.4"
|
||||
|
||||
[dev-dependencies]
|
||||
serde = { workspace = true }
|
||||
|
||||
@@ -191,7 +191,12 @@ impl BlockCache {
|
||||
/// included as the last instruction),
|
||||
/// - reaching [`MAX_BLOCK_INSTRS`],
|
||||
/// - the next PC would cross a 4 KiB guest page boundary.
|
||||
fn build_block(start_pc: u32, mem: &dyn MemoryAccess, page_version: u64) -> DecodedBlock {
|
||||
///
|
||||
/// Exposed to the JIT ([`crate::jit`]) so the superblock compiler can build
|
||||
/// the transient successor blocks of a chain without a `BlockCache` (they are
|
||||
/// consumed at compile time, not cached). Same walk the cache uses, so a
|
||||
/// superblock's blocks are byte-identical to the ones the interpreter runs.
|
||||
pub fn build_block(start_pc: u32, mem: &dyn MemoryAccess, page_version: u64) -> DecodedBlock {
|
||||
let mut instrs: Vec<DecodedInstr> = Vec::with_capacity(8);
|
||||
let page_base = start_pc & GUEST_PAGE_MASK;
|
||||
let mut cur = start_pc;
|
||||
|
||||
@@ -62,6 +62,11 @@ pub const VSCR_SAT_MASK: u32 = 0x0000_0001;
|
||||
|
||||
/// PowerPC processor context. Holds all register state for one guest thread.
|
||||
/// Mirrors PPCContext from ppc_context.h, minus JIT-specific fields.
|
||||
// `Clone` supports the recompiler's differential harness, which snapshots a
|
||||
// context to run the JIT speculatively against the interpreter. Cloning shares
|
||||
// the `reservation_table` Arc; the harness clears it on the speculative copy so
|
||||
// a speculative lwarx/stwcx cannot perturb the authoritative reservation state.
|
||||
#[derive(Clone)]
|
||||
#[repr(C, align(64))]
|
||||
pub struct PpcContext {
|
||||
// General purpose registers (R0-R31)
|
||||
|
||||
@@ -214,7 +214,11 @@ pub fn step_block(
|
||||
}
|
||||
|
||||
/// Execute a decoded instruction, updating context and memory.
|
||||
fn execute(ctx: &mut PpcContext, mem: &dyn MemoryAccess, instr: &DecodedInstr) -> StepResult {
|
||||
///
|
||||
/// `pub(crate)` so the recompiler ([`crate::recompiler`]) can reuse the exact
|
||||
/// per-opcode semantics as its interpreter-fallback path — the JIT lowers from
|
||||
/// this same source of truth, and uncompiled opcodes route straight back here.
|
||||
pub(crate) fn execute(ctx: &mut PpcContext, mem: &dyn MemoryAccess, instr: &DecodedInstr) -> StepResult {
|
||||
match instr.opcode {
|
||||
// ===== ALU: Immediate =====
|
||||
PpcOpcode::addi => {
|
||||
|
||||
2537
crates/xenia-cpu/src/jit.rs
Normal file
2537
crates/xenia-cpu/src/jit.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -5,9 +5,11 @@ pub mod dispatch_rec;
|
||||
pub mod disasm;
|
||||
pub mod fpscr;
|
||||
pub mod interpreter;
|
||||
pub mod jit;
|
||||
pub mod opcode;
|
||||
pub mod overflow;
|
||||
pub mod phaser;
|
||||
pub mod recompiler;
|
||||
pub mod reservation;
|
||||
pub mod scheduler;
|
||||
pub mod trap;
|
||||
|
||||
445
crates/xenia-cpu/src/recompiler.rs
Normal file
445
crates/xenia-cpu/src/recompiler.rs
Normal file
@@ -0,0 +1,445 @@
|
||||
//! PPC block recompiler (JIT) — **M0 foundation**.
|
||||
//!
|
||||
//! This is the seam a staged block-recompiler plugs into. M0 ships **no real
|
||||
//! codegen**: [`run_block`] executes a block by falling back to the
|
||||
//! interpreter's [`crate::interpreter::execute`] for every instruction, so it
|
||||
//! is bit-identical to [`crate::interpreter::step_block`] by construction. Its
|
||||
//! purpose is to prove the integration seam and the **differential harness**
|
||||
//! before any lowering exists. Later stages replace the per-instruction
|
||||
//! fallback with lowered ops (closure-threaded, then Cranelift machine code)
|
||||
//! opcode-by-opcode, each gated through the harness below.
|
||||
//!
|
||||
//! ## Determinism is the whole game
|
||||
//! `cycle_count`/`timebase` are bumped once per guest instruction and drive the
|
||||
//! IPM clock the movie/scheduler depend on. [`run_block`] reproduces
|
||||
//! `step_block`'s counting and stop semantics **exactly**. The interpreter is
|
||||
//! the permanent reference oracle; the recompiler must never diverge from it.
|
||||
//!
|
||||
//! ## Differential harness (`XENIA_JIT_DIFF`) — in-process
|
||||
//! The guest is only *coarsely* deterministic: `coord_idle_advance` ticks vsync
|
||||
//! from wall-clock when the scheduler idles, so vblank ISRs land at
|
||||
//! wall-clock-dependent instruction boundaries and two separate runs are **not**
|
||||
//! bit-identical. Comparing across runs would measure that jitter, not JIT
|
||||
//! divergence. So the harness is **in-process** ([`diff_step`]):
|
||||
//!
|
||||
//! * the **interpreter is authoritative** — it drives the real context and
|
||||
//! memory, so a JIT bug can never corrupt the run;
|
||||
//! * the **JIT runs speculatively** on a *clone* of the pre-block context
|
||||
//! against an [`OverlayMemory`] (writes buffered, reads fall through to real
|
||||
//! *pre-block* memory), then its registers are compared to the
|
||||
//! interpreter's;
|
||||
//! * blocks that touch **MMIO** (a device callback can't be run twice) or are
|
||||
//! **`sync_sensitive`** (reservation/barrier ops share cross-thread state)
|
||||
//! are skipped, not compared.
|
||||
//!
|
||||
//! Run with `XENIA_JIT_DIFF=1`; [`report_diff_summary`] prints checked/skipped/
|
||||
//! mismatch counts at exit. Zero mismatches ⇒ the recompiler matches the
|
||||
//! interpreter on every comparable block.
|
||||
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::collections::HashMap;
|
||||
use std::sync::atomic::{AtomicU64, AtomicU8, Ordering};
|
||||
|
||||
use crate::block_cache::DecodedBlock;
|
||||
use crate::context::PpcContext;
|
||||
use crate::interpreter::{execute, step_block, StepResult};
|
||||
use crate::jit::{JitCache, MemEnv, RET_CONTINUE};
|
||||
use crate::opcode::PpcOpcode;
|
||||
use xenia_memory::MemoryAccess;
|
||||
|
||||
/// Cached env gate. 0 = uninitialised, 1 = on, 2 = off.
|
||||
#[inline]
|
||||
fn cached_flag(cell: &AtomicU8, var: &str) -> bool {
|
||||
match cell.load(Ordering::Relaxed) {
|
||||
1 => true,
|
||||
2 => false,
|
||||
_ => {
|
||||
let on = std::env::var_os(var).is_some();
|
||||
cell.store(if on { 1 } else { 2 }, Ordering::Relaxed);
|
||||
on
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// `XENIA_JIT` — route block execution through the recompiler instead of the
|
||||
/// interpreter's `step_block`. Opt-in; cheap cached check on the hot path.
|
||||
#[inline]
|
||||
pub fn jit_enabled() -> bool {
|
||||
static F: AtomicU8 = AtomicU8::new(0);
|
||||
cached_flag(&F, "XENIA_JIT")
|
||||
}
|
||||
|
||||
/// `XENIA_JIT_DIFF` — enable the in-process differential harness ([`diff_step`]).
|
||||
#[inline]
|
||||
pub fn diff_enabled() -> bool {
|
||||
static F: AtomicU8 = AtomicU8::new(0);
|
||||
cached_flag(&F, "XENIA_JIT_DIFF")
|
||||
}
|
||||
|
||||
/// `XENIA_JIT_CHAIN` — enable native superblock chaining (the JIT compiles a
|
||||
/// chain of same-page blocks into one function with direct block-to-block
|
||||
/// jumps). This is only the *env request*; the scheduler additionally requires
|
||||
/// the diff harness OFF and no diagnostic probes / mem-watch armed before it
|
||||
/// actually enables chaining (see the config install in `run_superblock`).
|
||||
#[inline]
|
||||
pub fn chain_requested() -> bool {
|
||||
static F: AtomicU8 = AtomicU8::new(0);
|
||||
cached_flag(&F, "XENIA_JIT_CHAIN")
|
||||
}
|
||||
|
||||
// ---- opcode histogram (XENIA_JIT_HIST) — data-drives M1 coverage ---------
|
||||
|
||||
#[inline]
|
||||
fn hist_enabled() -> bool {
|
||||
static F: AtomicU8 = AtomicU8::new(0);
|
||||
cached_flag(&F, "XENIA_JIT_HIST")
|
||||
}
|
||||
|
||||
thread_local! {
|
||||
static HIST: RefCell<HashMap<PpcOpcode, u64>> = RefCell::new(HashMap::new());
|
||||
static HIST_TICK: Cell<u32> = const { Cell::new(0) };
|
||||
}
|
||||
|
||||
/// Sample 1-in-16 instructions — relative opcode frequencies are unbiased at
|
||||
/// this rate and the HashMap cost stops dominating the run.
|
||||
#[inline]
|
||||
fn hist_tally(op: PpcOpcode) {
|
||||
let t = HIST_TICK.with(|c| {
|
||||
let n = c.get().wrapping_add(1);
|
||||
c.set(n);
|
||||
n
|
||||
});
|
||||
if t & 0xF == 0 {
|
||||
HIST.with(|h| *h.borrow_mut().entry(op).or_insert(0) += 1);
|
||||
}
|
||||
}
|
||||
|
||||
/// Print the opcode-frequency histogram (top 40 + cumulative %), so M1 coverage
|
||||
/// targets the opcodes that actually dominate boot+movie execution.
|
||||
pub fn report_histogram() {
|
||||
if !hist_enabled() {
|
||||
return;
|
||||
}
|
||||
let mut v: Vec<(PpcOpcode, u64)> =
|
||||
HIST.with(|h| h.borrow().iter().map(|(&k, &c)| (k, c)).collect());
|
||||
v.sort_by(|a, b| b.1.cmp(&a.1));
|
||||
let total: u64 = v.iter().map(|(_, c)| c).sum();
|
||||
eprintln!("=== JIT opcode histogram (total={total}, {} distinct) ===", v.len());
|
||||
let mut cum = 0u64;
|
||||
for (i, (op, c)) in v.iter().take(40).enumerate() {
|
||||
cum += c;
|
||||
eprintln!(
|
||||
" {:>2}. {:<14?} {:>12} {:>5.1}% cum {:>5.1}%",
|
||||
i + 1,
|
||||
op,
|
||||
c,
|
||||
100.0 * *c as f64 / total as f64,
|
||||
100.0 * cum as f64 / total as f64
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Coverage telemetry: blocks executed as native code vs interpreted (uncovered).
|
||||
static JIT_COMPILED_RUN: AtomicU64 = AtomicU64::new(0);
|
||||
static JIT_INTERP_RUN: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
/// Execute one decoded block, natively if it is fully covered, else via the
|
||||
/// interpreter fallback.
|
||||
///
|
||||
/// If [`JitCache::get_or_compile`] returns a compiled entry point, the whole
|
||||
/// block runs as native code (which advances `pc`/`cycle_count`/`timebase`
|
||||
/// exactly like the interpreter — validated by the diff harness). Otherwise
|
||||
/// this is byte-for-byte the same loop as [`crate::interpreter::step_block`]:
|
||||
/// bump `cycle_count`/`timebase` per instruction, bail on the first
|
||||
/// non-`Continue` result, and stop on a PC discontinuity (only the terminator
|
||||
/// may branch).
|
||||
pub fn run_block(
|
||||
ctx: &mut PpcContext,
|
||||
mem: &dyn MemoryAccess,
|
||||
block: &DecodedBlock,
|
||||
jit: &mut JitCache,
|
||||
remaining_budget: u64,
|
||||
) -> StepResult {
|
||||
if let Some(f) = jit.get_or_compile(block, mem) {
|
||||
// NB: under superblock chaining one call runs *several* guest blocks,
|
||||
// so this counter (and the coverage %) undercounts native guest blocks
|
||||
// vs the per-block `JIT_INTERP_RUN`. It stays a native-vs-interpreted
|
||||
// *call* ratio; treat the chained coverage % as a floor.
|
||||
JIT_COMPILED_RUN.fetch_add(1, Ordering::Relaxed);
|
||||
let env = jit.mem_env(mem);
|
||||
// `remaining_budget` bounds a superblock's internal chaining; a
|
||||
// single-block compilation ignores it. A compiled (super)block always
|
||||
// runs to completion and returns `Continue` — covered ops never branch
|
||||
// out / fault, and the chain only ever stops at a clean block boundary.
|
||||
let raw = f(ctx as *mut PpcContext, &env as *const MemEnv, remaining_budget);
|
||||
debug_assert_eq!(raw, RET_CONTINUE, "covered block returned non-Continue");
|
||||
return StepResult::Continue;
|
||||
}
|
||||
JIT_INTERP_RUN.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
let hist = hist_enabled();
|
||||
let mut result = StepResult::Continue;
|
||||
for instr in &block.instrs {
|
||||
let expected_next = instr.addr.wrapping_add(4);
|
||||
if hist {
|
||||
hist_tally(instr.opcode);
|
||||
}
|
||||
// M0 fallback: identical to the interpreter. Future stages dispatch
|
||||
// lowered ops here and only fall back for uncompiled opcodes.
|
||||
result = execute(ctx, mem, instr);
|
||||
ctx.cycle_count += 1;
|
||||
ctx.timebase += 1;
|
||||
if !matches!(result, StepResult::Continue) {
|
||||
return result;
|
||||
}
|
||||
if ctx.pc != expected_next {
|
||||
break;
|
||||
}
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
// ---- in-process differential harness -------------------------------------
|
||||
|
||||
static CHECKED: AtomicU64 = AtomicU64::new(0);
|
||||
static SKIPPED: AtomicU64 = AtomicU64::new(0);
|
||||
static MISMATCH: AtomicU64 = AtomicU64::new(0);
|
||||
const MAX_MISMATCH_PRINTS: u64 = 20;
|
||||
|
||||
/// Run one block under the differential harness. The **interpreter is
|
||||
/// authoritative** (drives `ctx`+`mem`); the JIT runs speculatively on a clone
|
||||
/// against an overlay and its registers are compared. Returns the interpreter's
|
||||
/// `StepResult`.
|
||||
pub fn diff_step(
|
||||
ctx: &mut PpcContext,
|
||||
mem: &dyn MemoryAccess,
|
||||
block: &DecodedBlock,
|
||||
jit: &mut JitCache,
|
||||
) -> StepResult {
|
||||
// Reservation/barrier blocks share cross-thread state; don't speculate.
|
||||
if block.sync_sensitive {
|
||||
SKIPPED.fetch_add(1, Ordering::Relaxed);
|
||||
return step_block(ctx, mem, block);
|
||||
}
|
||||
|
||||
// Speculative JIT run on a clone against buffered/overlay memory. Runs
|
||||
// BEFORE the authoritative interpreter so its reads see pre-block memory.
|
||||
let mut cand = ctx.clone();
|
||||
cand.reservation_table = None; // never touch the shared reservation table
|
||||
let overlay = OverlayMemory::new(mem);
|
||||
// Chaining is disabled under the diff harness (a multi-block superblock
|
||||
// can't be compared against one interpreter `step_block`), so this always
|
||||
// runs a single block; the budget is irrelevant.
|
||||
let _ = run_block(&mut cand, &overlay, block, jit, u64::MAX);
|
||||
let touched_mmio = overlay.touched_mmio.get();
|
||||
|
||||
// Authoritative interpreter run: commits real ctx + memory.
|
||||
let auth = step_block(ctx, mem, block);
|
||||
|
||||
if touched_mmio {
|
||||
SKIPPED.fetch_add(1, Ordering::Relaxed);
|
||||
} else {
|
||||
CHECKED.fetch_add(1, Ordering::Relaxed);
|
||||
compare(&cand, ctx, block.start_pc);
|
||||
}
|
||||
auth
|
||||
}
|
||||
|
||||
/// Compare speculative-JIT (`cand`) vs authoritative-interpreter (`auth`)
|
||||
/// register state. Reports the first [`MAX_MISMATCH_PRINTS`] divergent blocks.
|
||||
/// Covers the integer + FP + control state (M0/M1 scope); vector regs join when
|
||||
/// VMX opcodes are lowered.
|
||||
fn compare(cand: &PpcContext, auth: &PpcContext, start_pc: u32) {
|
||||
let mut diffs: Vec<String> = Vec::new();
|
||||
for i in 0..32 {
|
||||
if cand.gpr[i] != auth.gpr[i] {
|
||||
diffs.push(format!("r{i} jit={:#018x} int={:#018x}", cand.gpr[i], auth.gpr[i]));
|
||||
}
|
||||
}
|
||||
for i in 0..32 {
|
||||
if cand.fpr[i].to_bits() != auth.fpr[i].to_bits() {
|
||||
diffs.push(format!(
|
||||
"f{i} jit={:#018x} int={:#018x}",
|
||||
cand.fpr[i].to_bits(),
|
||||
auth.fpr[i].to_bits()
|
||||
));
|
||||
}
|
||||
}
|
||||
if cand.lr != auth.lr {
|
||||
diffs.push(format!("lr jit={:#x} int={:#x}", cand.lr, auth.lr));
|
||||
}
|
||||
if cand.ctr != auth.ctr {
|
||||
diffs.push(format!("ctr jit={:#x} int={:#x}", cand.ctr, auth.ctr));
|
||||
}
|
||||
if cand.pc != auth.pc {
|
||||
diffs.push(format!("pc jit={:#x} int={:#x}", cand.pc, auth.pc));
|
||||
}
|
||||
for i in 0..8 {
|
||||
if cand.cr[i].as_u8() != auth.cr[i].as_u8() {
|
||||
diffs.push(format!("cr{i} jit={:#x} int={:#x}", cand.cr[i].as_u8(), auth.cr[i].as_u8()));
|
||||
}
|
||||
}
|
||||
if (cand.xer_ca, cand.xer_ov, cand.xer_so, cand.xer_tbc)
|
||||
!= (auth.xer_ca, auth.xer_ov, auth.xer_so, auth.xer_tbc)
|
||||
{
|
||||
diffs.push("xer".into());
|
||||
}
|
||||
if cand.fpscr != auth.fpscr {
|
||||
diffs.push(format!("fpscr jit={:#x} int={:#x}", cand.fpscr, auth.fpscr));
|
||||
}
|
||||
if cand.cycle_count != auth.cycle_count {
|
||||
diffs.push(format!("cycles jit={} int={}", cand.cycle_count, auth.cycle_count));
|
||||
}
|
||||
|
||||
if !diffs.is_empty() {
|
||||
let n = MISMATCH.fetch_add(1, Ordering::Relaxed);
|
||||
if n < MAX_MISMATCH_PRINTS {
|
||||
eprintln!("JIT-DIFF MISMATCH block={start_pc:#010x}: {}", diffs.join(", "));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Print checked/skipped/mismatch tallies (call at clean exit).
|
||||
pub fn report_diff_summary() {
|
||||
if !diff_enabled() {
|
||||
return;
|
||||
}
|
||||
let (c, s, m) = (
|
||||
CHECKED.load(Ordering::Relaxed),
|
||||
SKIPPED.load(Ordering::Relaxed),
|
||||
MISMATCH.load(Ordering::Relaxed),
|
||||
);
|
||||
eprintln!(
|
||||
"=== JIT-DIFF SUMMARY: checked={c} skipped(mmio/sync)={s} MISMATCHES={m} — {} ===",
|
||||
if m == 0 { "CLEAN ✓" } else { "DIVERGENCE ✗" }
|
||||
);
|
||||
}
|
||||
|
||||
/// Print native-vs-interpreted block coverage (call at clean exit). Shown
|
||||
/// whenever the JIT is engaged (`XENIA_JIT` or `XENIA_JIT_DIFF`) so we can see
|
||||
/// how much of the real boot+movie workload the current covered set captures.
|
||||
pub fn report_jit_summary() {
|
||||
if !jit_enabled() && !diff_enabled() {
|
||||
return;
|
||||
}
|
||||
let compiled = JIT_COMPILED_RUN.load(Ordering::Relaxed);
|
||||
let interp = JIT_INTERP_RUN.load(Ordering::Relaxed);
|
||||
let total = compiled + interp;
|
||||
let pct = if total == 0 { 0.0 } else { 100.0 * compiled as f64 / total as f64 };
|
||||
eprintln!(
|
||||
"=== JIT COVERAGE: native blocks={compiled} interpreted={interp} ({pct:.2}% of {total} block-runs native) ==="
|
||||
);
|
||||
}
|
||||
|
||||
// ---- overlay memory (speculative-write buffer) ---------------------------
|
||||
|
||||
/// A [`MemoryAccess`] wrapper for speculative JIT execution: reads fall through
|
||||
/// to the real (pre-block) memory, writes are buffered in a byte-granular
|
||||
/// overlay (never committed), and any MMIO touch sets `touched_mmio` so the
|
||||
/// caller can skip comparing that block. Big-endian byte order throughout,
|
||||
/// matching `GuestMemory`.
|
||||
struct OverlayMemory<'a> {
|
||||
real: &'a dyn MemoryAccess,
|
||||
overlay: RefCell<HashMap<u32, u8>>,
|
||||
touched_mmio: Cell<bool>,
|
||||
}
|
||||
|
||||
impl<'a> OverlayMemory<'a> {
|
||||
fn new(real: &'a dyn MemoryAccess) -> Self {
|
||||
Self { real, overlay: RefCell::new(HashMap::new()), touched_mmio: Cell::new(false) }
|
||||
}
|
||||
#[inline]
|
||||
fn rb(&self, addr: u32) -> u8 {
|
||||
match self.overlay.borrow().get(&addr) {
|
||||
Some(&b) => b,
|
||||
None => self.real.read_u8(addr),
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn wb(&self, addr: u32, b: u8) {
|
||||
self.overlay.borrow_mut().insert(addr, b);
|
||||
}
|
||||
/// Returns true (and flags the block) if `addr` is MMIO — callers must not
|
||||
/// touch it speculatively.
|
||||
#[inline]
|
||||
fn is_mmio_stop(&self, addr: u32) -> bool {
|
||||
if self.real.is_mmio(addr) {
|
||||
self.touched_mmio.set(true);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> MemoryAccess for OverlayMemory<'a> {
|
||||
fn read_u8(&self, a: u32) -> u8 {
|
||||
if self.is_mmio_stop(a) {
|
||||
return 0;
|
||||
}
|
||||
self.rb(a)
|
||||
}
|
||||
fn read_u16(&self, a: u32) -> u16 {
|
||||
if self.is_mmio_stop(a) {
|
||||
return 0;
|
||||
}
|
||||
((self.rb(a) as u16) << 8) | self.rb(a.wrapping_add(1)) as u16
|
||||
}
|
||||
fn read_u32(&self, a: u32) -> u32 {
|
||||
if self.is_mmio_stop(a) {
|
||||
return 0;
|
||||
}
|
||||
((self.rb(a) as u32) << 24)
|
||||
| ((self.rb(a.wrapping_add(1)) as u32) << 16)
|
||||
| ((self.rb(a.wrapping_add(2)) as u32) << 8)
|
||||
| self.rb(a.wrapping_add(3)) as u32
|
||||
}
|
||||
fn read_u64(&self, a: u32) -> u64 {
|
||||
if self.is_mmio_stop(a) {
|
||||
return 0;
|
||||
}
|
||||
let hi = self.read_u32(a) as u64;
|
||||
let lo = self.read_u32(a.wrapping_add(4)) as u64;
|
||||
(hi << 32) | lo
|
||||
}
|
||||
fn write_u8(&self, a: u32, v: u8) {
|
||||
if self.is_mmio_stop(a) {
|
||||
return;
|
||||
}
|
||||
self.wb(a, v);
|
||||
}
|
||||
fn write_u16(&self, a: u32, v: u16) {
|
||||
if self.is_mmio_stop(a) {
|
||||
return;
|
||||
}
|
||||
self.wb(a, (v >> 8) as u8);
|
||||
self.wb(a.wrapping_add(1), v as u8);
|
||||
}
|
||||
fn write_u32(&self, a: u32, v: u32) {
|
||||
if self.is_mmio_stop(a) {
|
||||
return;
|
||||
}
|
||||
self.wb(a, (v >> 24) as u8);
|
||||
self.wb(a.wrapping_add(1), (v >> 16) as u8);
|
||||
self.wb(a.wrapping_add(2), (v >> 8) as u8);
|
||||
self.wb(a.wrapping_add(3), v as u8);
|
||||
}
|
||||
fn write_u64(&self, a: u32, v: u64) {
|
||||
self.write_u32(a, (v >> 32) as u32);
|
||||
self.write_u32(a.wrapping_add(4), v as u32);
|
||||
}
|
||||
// execute() never calls translate/translate_mut for real memory (only the
|
||||
// test mock does), so returning None is safe here.
|
||||
fn translate(&self, _a: u32) -> Option<*const u8> {
|
||||
None
|
||||
}
|
||||
fn translate_mut(&self, _a: u32) -> Option<*mut u8> {
|
||||
None
|
||||
}
|
||||
fn page_version(&self, a: u32) -> u64 {
|
||||
self.real.page_version(a)
|
||||
}
|
||||
fn is_mmio(&self, a: u32) -> bool {
|
||||
self.real.is_mmio(a)
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,16 @@ pub static KERNEL_CALLS: AtomicU64 = AtomicU64::new(0);
|
||||
pub static BUILD_NS: AtomicU64 = AtomicU64::new(0); // block decode / cache lookup
|
||||
pub static BUILD_CALLS: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
// Top-level lockstep-loop attribution (sums to ~100% with idle/GPU-pacer):
|
||||
pub static ROUND_NS: AtomicU64 = AtomicU64::new(0); // per-round tax (clock/timestamp/isr/schedule)
|
||||
pub static ROUND_CALLS: AtomicU64 = AtomicU64::new(0);
|
||||
pub static PROLOGUE_NS: AtomicU64 = AtomicU64::new(0); // worker_prologue (⊇ KERNEL)
|
||||
pub static PROLOGUE_CALLS: AtomicU64 = AtomicU64::new(0);
|
||||
pub static RUNSB_NS: AtomicU64 = AtomicU64::new(0); // run_superblock (⊇ STEP + chain BUILD + EPILOGUE)
|
||||
pub static RUNSB_CALLS: AtomicU64 = AtomicU64::new(0);
|
||||
pub static EPILOGUE_NS: AtomicU64 = AtomicU64::new(0); // worker_epilogue (subset of RUNSB)
|
||||
pub static EPILOGUE_CALLS: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
/// Cached on/off state so the per-block hot path never touches the
|
||||
/// environment. 0 = uninitialised, 1 = on, 2 = off.
|
||||
static ENABLED: std::sync::atomic::AtomicU8 = std::sync::atomic::AtomicU8::new(0);
|
||||
@@ -142,52 +152,43 @@ pub fn report(_ignored: u64) {
|
||||
} else {
|
||||
step_instr as f64 / (step_ns as f64 / 1e3) // instr / us = MIPS
|
||||
};
|
||||
eprintln!("=== XENIA_PROFILE (wall {:.1} ms) ===", ms(wall_ns));
|
||||
eprintln!(
|
||||
" interp step_block : {:>10.1} ms {:>5.1}% ({} calls, {} instr, {:.1} MIPS)",
|
||||
ms(step_ns),
|
||||
pct(step_ns),
|
||||
g(&STEP_CALLS),
|
||||
step_instr,
|
||||
mips
|
||||
);
|
||||
eprintln!(
|
||||
" texture decode+up : {:>10.1} ms {:>5.1}% ({} calls, {} MiB)",
|
||||
ms(tex_ns),
|
||||
pct(tex_ns),
|
||||
g(&TEXDEC_CALLS),
|
||||
g(&TEXDEC_BYTES) / (1024 * 1024)
|
||||
);
|
||||
eprintln!(
|
||||
" host draw submit : {:>10.1} ms {:>5.1}% ({} calls)",
|
||||
ms(draw_ns),
|
||||
pct(draw_ns),
|
||||
g(&DRAW_CALLS)
|
||||
);
|
||||
let kern_ns = g(&KERNEL_NS);
|
||||
let build_ns = g(&BUILD_NS);
|
||||
let round_ns = g(&ROUND_NS);
|
||||
let prologue_ns = g(&PROLOGUE_NS);
|
||||
let runsb_ns = g(&RUNSB_NS);
|
||||
let epilogue_ns = g(&EPILOGUE_NS);
|
||||
// Derived leftovers (honest lumping — see comments):
|
||||
// runsb_other = chain-loop body (arithmetic/stop-checks) + in-chain block lookups
|
||||
// prologue_other = block lookup (first block) + scheduler bookkeeping
|
||||
let runsb_other = runsb_ns.saturating_sub(step_ns).saturating_sub(epilogue_ns);
|
||||
let prologue_other = prologue_ns.saturating_sub(kern_ns);
|
||||
let line = |label: &str, ns: u64, extra: &str| {
|
||||
eprintln!(" {:<20}{:>10.1} ms {:>5.1}% {}", label, ms(ns), pct(ns), extra);
|
||||
};
|
||||
eprintln!("=== XENIA_PROFILE (wall {:.1} ms) ===", ms(wall_ns));
|
||||
eprintln!(" -- TOP LEVEL (single-thread lockstep loop; sums ~100%) --");
|
||||
line("per-round tax", round_ns, &format!("({} rounds)", g(&ROUND_CALLS)));
|
||||
line("worker_prologue", prologue_ns, &format!("({} visits)", g(&PROLOGUE_CALLS)));
|
||||
line("run_superblock", runsb_ns, &format!("({} visits)", g(&RUNSB_CALLS)));
|
||||
let top = round_ns + prologue_ns + runsb_ns;
|
||||
eprintln!(
|
||||
" kernel HLE export : {:>10.1} ms {:>5.1}% ({} calls)",
|
||||
ms(kern_ns),
|
||||
pct(kern_ns),
|
||||
g(&KERNEL_CALLS)
|
||||
" ---- top accounted {:.1}% ; idle/GPU-pacer/misc {:.1}%",
|
||||
pct(top),
|
||||
pct(wall_ns.saturating_sub(top))
|
||||
);
|
||||
eprintln!(
|
||||
" block decode/cache: {:>10.1} ms {:>5.1}% ({} calls)",
|
||||
ms(build_ns),
|
||||
pct(build_ns),
|
||||
g(&BUILD_CALLS)
|
||||
);
|
||||
eprintln!(
|
||||
" frontbuffer present: {:>9.1} ms {:>5.1}% ({} calls)",
|
||||
ms(pres_ns),
|
||||
pct(pres_ns),
|
||||
g(&PRESENT_CALLS)
|
||||
);
|
||||
let accounted = step_ns + tex_ns + draw_ns + pres_ns + kern_ns + build_ns;
|
||||
eprintln!(
|
||||
" ---- accounted {:.1}% ; remainder (locks/kernel/scheduler/idle) {:.1}%",
|
||||
pct(accounted),
|
||||
pct(wall_ns.saturating_sub(accounted))
|
||||
eprintln!(" -- SUB-ATTRIBUTION --");
|
||||
line(
|
||||
"interp step_block",
|
||||
step_ns,
|
||||
&format!("[in run_superblock] ({} calls, {} instr, {:.1} MIPS)", g(&STEP_CALLS), step_instr, mips),
|
||||
);
|
||||
line("worker_epilogue", epilogue_ns, "[in run_superblock]");
|
||||
line("run_superblock other", runsb_other, "[chain-loop body + in-chain lookups]");
|
||||
line("kernel HLE export", kern_ns, &format!("[in worker_prologue] ({} calls)", g(&KERNEL_CALLS)));
|
||||
line("worker_prologue other", prologue_other, "[first-block lookup + sched bookkeeping]");
|
||||
line("block decode/cache", build_ns, &format!("[split across prologue+runsb] ({} calls)", g(&BUILD_CALLS)));
|
||||
line("texture decode+up", tex_ns, &format!("({} calls, {} MiB)", g(&TEXDEC_CALLS), g(&TEXDEC_BYTES) / (1024 * 1024)));
|
||||
line("host draw submit", draw_ns, &format!("({} calls)", g(&DRAW_CALLS)));
|
||||
line("frontbuffer present", pres_ns, &format!("({} calls)", g(&PRESENT_CALLS)));
|
||||
}
|
||||
|
||||
@@ -648,6 +648,14 @@ impl KernelState {
|
||||
}
|
||||
}
|
||||
|
||||
/// The import-thunk address band `(lo, hi)` (inclusive), or `None` if no
|
||||
/// thunks are registered. Exposed so the JIT superblock compiler can refuse
|
||||
/// to chain into the thunk band (those PCs need the full worker-prologue
|
||||
/// dispatch, so the chain must stop and hand back to the round).
|
||||
pub fn thunk_band(&self) -> Option<(u32, u32)> {
|
||||
self.thunk_addr_band
|
||||
}
|
||||
|
||||
/// Resolve a `(module, ordinal)` to its registered thunk address.
|
||||
pub fn resolve_thunk(&self, module: ModuleId, ordinal: u16) -> Option<u32> {
|
||||
self.thunks_by_ordinal.get(&(module, ordinal)).copied()
|
||||
|
||||
@@ -1,3 +1,34 @@
|
||||
/// Raw pointers/constants a JIT needs to inline the load fast-path (skip the
|
||||
/// trait-object call). Only the real [`crate::heap::GuestMemory`] exposes this;
|
||||
/// wrappers that intercept accesses (e.g. the recompiler's speculative overlay)
|
||||
/// return `None` from [`MemoryAccess::fast_mem`] so the JIT falls back to the
|
||||
/// trait-object slow path and their interception is preserved.
|
||||
///
|
||||
/// The flat mapping means a guest address `a` translates to `membase + a`. A
|
||||
/// load is safe to inline only when `a` is **not** MMIO and its page is
|
||||
/// committed: `(a & mmio_mask) != mmio_value` AND page-table entry
|
||||
/// `page_table[a >> 12]` has the COMMIT bit (bit 49). Unmapped pages are
|
||||
/// `PROT_NONE`, so the committed check must precede the raw load.
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct FastMem {
|
||||
/// Base of the flat 4 GiB guest mapping. `membase + guest_addr` is the host
|
||||
/// address. Never null for a real mapping (used by the JIT as the
|
||||
/// "inline enabled" sentinel).
|
||||
pub membase: *mut u8,
|
||||
/// Base of the per-page allocation table (`AtomicU64` entries, reinterpreted
|
||||
/// as `u64`). Entry `page_table[addr >> 12]` bit 49 = COMMIT.
|
||||
pub page_table: *const u64,
|
||||
/// MMIO fast-reject mask/value: `(addr & mask) == value` is the *necessary*
|
||||
/// condition for `addr` to be MMIO, so `!=` proves non-MMIO.
|
||||
pub mmio_mask: u32,
|
||||
pub mmio_value: u32,
|
||||
/// Pointer to the monotonic MMIO-access counter (`AtomicU64` as `*const
|
||||
/// u64`). A superblock JIT samples this across a block boundary to detect an
|
||||
/// MMIO touch and stop chaining there (preserving the interpreter's
|
||||
/// fine-grained MMIO ordering).
|
||||
pub mmio_count: *const u64,
|
||||
}
|
||||
|
||||
/// Trait for all guest memory access. Every load/store goes through this,
|
||||
/// enabling MMIO checking and debugger observation on every access.
|
||||
/// This is the key abstraction that eliminates the need for MMIO exception handlers.
|
||||
@@ -48,6 +79,24 @@ pub trait MemoryAccess {
|
||||
}
|
||||
}
|
||||
|
||||
/// True if `addr` falls in an MMIO region (a load/store there invokes a
|
||||
/// device callback with side effects rather than touching backing RAM).
|
||||
///
|
||||
/// Default `false` (mock memories have no MMIO). `GuestMemory` overrides it.
|
||||
/// Used by the recompiler's differential harness to *skip* comparing blocks
|
||||
/// that touch MMIO — a device callback cannot be safely executed twice.
|
||||
fn is_mmio(&self, _addr: u32) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
/// Raw pointers/constants for a JIT to inline the load fast-path, or `None`
|
||||
/// to force the trait-object slow path. Default `None` (mock memories and
|
||||
/// interception wrappers have no flat mapping to expose). `GuestMemory`
|
||||
/// overrides it. See [`FastMem`].
|
||||
fn fast_mem(&self) -> Option<FastMem> {
|
||||
None
|
||||
}
|
||||
|
||||
/// Get a direct host pointer for the given guest address.
|
||||
/// Returns None if the address is invalid or in an MMIO region.
|
||||
fn translate(&self, addr: u32) -> Option<*const u8>;
|
||||
|
||||
@@ -504,6 +504,25 @@ impl GuestMemory {
|
||||
}
|
||||
|
||||
impl MemoryAccess for GuestMemory {
|
||||
#[inline]
|
||||
fn is_mmio(&self, addr: u32) -> bool {
|
||||
self.find_mmio(addr).is_some()
|
||||
}
|
||||
|
||||
fn fast_mem(&self) -> Option<crate::access::FastMem> {
|
||||
Some(crate::access::FastMem {
|
||||
membase: self.membase,
|
||||
// AtomicU64 is #[repr(transparent)] over u64, so the element pointer
|
||||
// reinterprets directly. The JIT reads entries with a plain load —
|
||||
// sound because alloc publishes each entry before the guest can
|
||||
// access the page (single-thread lockstep; x86 loads are acquire).
|
||||
page_table: self.page_table.as_ptr() as *const u64,
|
||||
mmio_mask: self.mmio_aperture_mask,
|
||||
mmio_value: self.mmio_aperture_value,
|
||||
mmio_count: &self.mmio_access_count as *const AtomicU64 as *const u64,
|
||||
})
|
||||
}
|
||||
|
||||
// Tier-3 perf: `#[inline]` on the hot read/write paths lets LLVM
|
||||
// fold the MMIO + mapping checks into the interpreter's load/store
|
||||
// handlers, hoisting the "not-MMIO, mapped" branch out of the loop
|
||||
|
||||
@@ -7,7 +7,7 @@ mod platform;
|
||||
|
||||
use thiserror::Error;
|
||||
|
||||
pub use access::MemoryAccess;
|
||||
pub use access::{FastMem, MemoryAccess};
|
||||
pub use heap::{set_writer_ctx, GuestMemory, HeapType};
|
||||
pub use mmio::MmioRegion;
|
||||
pub use page_table::PageEntry;
|
||||
|
||||
Reference in New Issue
Block a user