diff --git a/audit-findings.md b/audit-findings.md index 5bb09cf..8010165 100644 --- a/audit-findings.md +++ b/audit-findings.md @@ -517,7 +517,7 @@ and severely thin test coverage (PPCBUG-055). ### PPCBUG-053 — CTR zero-test uses 64-bit compare; should use 32-bit in `bcx`/`bclrx` - **Severity**: MEDIUM (effectively HIGH given unfixed PPCBUG-001..031 GPR pollution) -- **Status**: open +- **Status**: applied (3d8e2ce, 2026-05-02) - **Locations**: `interpreter.rs:849` (`bcx` `ctr_ok`), `interpreter.rs:879` (`bclrx` `ctr_ok`) - **Symptom**: `ctx.ctr != 0` compares all 64 bits. In 32-bit ABI the CTR is logically 32-bit. Canary explicitly truncates to 32 bits: `ctr = f.Truncate(ctr, INT32_TYPE)`. When CTR upper @@ -541,7 +541,7 @@ and severely thin test coverage (PPCBUG-055). ### PPCBUG-054 — `mtspr CTR` writeback not truncated to 32 bits - **Severity**: MEDIUM -- **Status**: open +- **Status**: applied (3d8e2ce, 2026-05-02) - **Location**: `interpreter.rs:1411` - **Symptom**: `crate::context::spr::CTR => ctx.ctr = val` writes the full 64-bit GPR to CTR. Acts as a firewall gap: any upstream 64-bit GPR pollution flows directly into CTR, where it @@ -2602,7 +2602,7 @@ entries in decode_op6. ### PPCBUG-424 — vmaddfp128: operand swap — computes VA×VB+VD instead of VA×VD+VB - **Severity**: HIGH -- **Status**: open +- **Status**: applied (52ece4b, 2026-05-02) - **Location**: `interpreter.rs:1771` (`r[i] = ai.mul_add(bi, di)`) - **Symptom**: Canary (ppc_emit_altivec.cc:806-809) documents `(VD) <- (VA × VD) + VB` and routes as `MulAdd(VA, VD, VB)`. Xenia-rs reads VA, VB, VD then computes @@ -2614,7 +2614,7 @@ entries in decode_op6. ### PPCBUG-425 — vmaddcfp128: operand swap — computes VD×VB+VA instead of VA×VD+VB - **Severity**: HIGH -- **Status**: open +- **Status**: applied (52ece4b, 2026-05-02) - **Location**: `interpreter.rs:4065` (`r[i] = di.mul_add(bi, ai)`) - **Symptom**: Canary (ppc_emit_altivec.cc:819) documents `(VD) <- (VA × VD) + VB`. Xenia-rs computes `VD × VB + VA`. Both the first multiplicand and the addend are wrong. @@ -2850,7 +2850,7 @@ gap). **3 LOW** test-coverage gaps. ### PPCBUG-510 — `stvewx128` stores all 16 bytes instead of one word; 12-byte memory corruption (HIGH) - **Severity**: HIGH -- **Status**: open +- **Status**: applied (cedee3c, 2026-05-02) - **Location**: interpreter.rs:2776-2781 - **Symptom**: Uses `& !0xF` (16-byte alignment) then stores all 16 bytes of the vector. ISA semantics: word-align EA, extract the word lane `(EA & 0xF) >> 2`, store 4 bytes only. @@ -3240,7 +3240,7 @@ has the wrong extraction. The disassembler was written independently and got the ### PPCBUG-640 — `fmt_bc`: pure `bdnz`/`bdz` emits `bdnzge`/`bdzge` (spurious condition suffix) (HIGH) - **Severity**: HIGH -- **Status**: open +- **Status**: applied (d4f6ea7, 2026-05-02) - **Location**: `disasm.rs:829-834` - **Symptom**: For `bcx` with BO=16 (`bdnz`: decrement CTR, branch if CTR≠0, CR ignored): - `decr = (16 & 4) == 0` = true @@ -3363,7 +3363,7 @@ has the wrong extraction. The disassembler was written independently and got the ### PPCBUG-649 — Golden fixture for `lwsync` pins wrong output (no ext_mnemonic) (LOW) - **Severity**: LOW (test coverage gap) -- **Status**: open +- **Status**: applied (2be25bd, 2026-05-02) - **Location**: `tests/golden/extended_mnemonics.json`, entry "lwsync" - **Symptom**: Fixture has `mnemonic: "sync"` and no `ext_mnemonic`. After PPCBUG-088/641 fix, expected output is `mnemonic: "sync"`, `ext_mnemonic: "lwsync"`. Current fixture @@ -3372,7 +3372,7 @@ has the wrong extraction. The disassembler was written independently and got the ### PPCBUG-650 — Golden fixtures for `bdnz`/`bdz` pin wrong extended mnemonic (LOW) - **Severity**: LOW (companion to PPCBUG-640) -- **Status**: open +- **Status**: applied (d4f6ea7, 2026-05-02) - **Location**: `tests/golden/extended_mnemonics.json`, rows "bdnz 0x82000040" and "bdz 0x82000040" - **Symptom**: Both rows have `ext_mnemonic: "bdnzge"` and `ext_mnemonic: "bdzge"`. After PPCBUG-640 fix, correct values are `"bdnz"` and `"bdz"`. diff --git a/audit-report-2026-04-29.md b/audit-report-2026-04-29.md index 7ff7667..75a6b12 100644 --- a/audit-report-2026-04-29.md +++ b/audit-report-2026-04-29.md @@ -338,6 +338,33 @@ After applying Phase 1 alone, run `xenia-rs check sylpheed.iso -n 4B --parallel` --- +### P3 — Isolated HIGH bugs (merged 2026-05-02, HEAD f3ebaba) + +**PPCBUGs fixed**: 053+054 (coupled CTR 32-bit), 424+425 (vmaddfp128/vmaddcfp128 operand swap), 510 (stvewx128 corruption), 640+650 (bdnz/bdz suffix), 641+649 (sync/lwsync), **700 (NEW)**. + +**Batches**: +- Batch 1: PPCBUG-510 — stvewx128 16-byte corruption fixed (word-align EA, extract lane, write 4 bytes) +- Batch 2: PPCBUG-424+425 + PPCBUG-700 partial (va128 PPC[11-15] partial fix) — vmaddfp128/vmaddcfp128 operand swap to VA*VD+VB +- Batch 3: PPCBUG-053+054 — bcx/bclrx 32-bit CTR compare + mtspr CTR truncation +- Batch 4: PPCBUG-640+650 — fmt_bc spurious bdnzge/bdzge suffix gated on `!uncond` +- Batch 5: PPCBUG-641+649 — sync/lwsync L-field disambiguation +- Phase review fix: **PPCBUG-700 (NEW)** — VMX128 register accessors (va128/vb128/vd128/vx128r_rc_bit) rewritten to canary's bitfield positions. Audit's "confirmed-clean" line-2958 assessment was based on miscounting LSB-first packed C++ bitfields. Per canary (`xenia-canary/src/xenia/cpu/ppc/ppc_decode_data.h:484-663`): + - VA128 = PPC[11-15] | PPC[26]<<5 | PPC[21]<<6 (3 fields, 7 bits) + - VB128 = PPC[16-20] | PPC[30-31]<<5 + - VD128 = PPC[6-10] | PPC[28-29]<<5 + - VX128_R Rc = PPC[25] (host bit 6) — NOT PPC[27] as PPCBUG-422 prescribed + Affects 30+ VMX128 opcodes; production game code with VR>=32 was silently mis-decoded. Speculative `key4_dt` dot-form dispatch in `decode_op6` removed (canary has no separate dot-form opcodes for VX128_R). New PPCBUG-700 entry added to `audit-findings.md` Phase C4 invalidating audit line 2958. + +**Gate results**: +- `cargo test --workspace --release`: **470 passed, 0 failed** (up from 467 baseline at P3 start; 3 new CTR regression tests added) +- Independent code reviewer: 1 BLOCKING issue (PPCBUG-700 above) — addressed before merge +- `-n 100M` lockstep smoke: ISO not in CI; checked locally during development +- **Acid test** `-n 4B --parallel --reservations-table`: **deferred to end of all phases** per user direction + +**Conclusion**: All P3 fixes applied + reviewed + reviewer's blocking concern resolved. Phase 3 also produced one HIGH discovery (PPCBUG-700) that the audit had missed. Total fixes: 6 commits, 7 distinct PPCBUG groups. Next: P4 — 32-bit ABI writeback truncation sweep, ~30 IDs across 4a-4d sub-sections. + +--- + ## Index — every PPCBUG referenced (in numerical order) This list intentionally includes every ID found in `audit-findings.md` so nothing is dropped. For each entry's full description / file:line / fix snippet / test recommendation, see the corresponding `### PPCBUG-NNN` heading in `audit-findings.md`.