Files
xenia-rs/crates/xenia-vfs/src/device.rs
MechaCat02 b20c99f141 [Subsystem-fixes] 6 verified ours-vs-canary divergence fixes
From the 2026-06-12 5-subsystem differential audit. All verified against
canary as oracle; 660/660 workspace tests green (655 + 5 new).

1. nt_create_event polarity (exports.rs) — `manual_reset = gpr[5] != 0`
   was INVERTED. Canary xboxkrnl_threading.cc:668 `Initialize(!event_type,..)`
   + xevent.cc:41 (type 0 = NotificationEvent = manual, type 1 = Sync = auto).
   Now `== 0`. Was the dormant 2.AI fix on chore/portable-snapshot, never
   merged. The Ke-path was already correct; only the Nt-path was wrong.

2. 2.AF deadline drain (main.rs coord_pre_round) — expired KeWait/KeDelay
   deadlines never fired under load because advance_to_next_wake_if_due was
   only called in coord_idle_advance (no-Ready-threads path). Added a
   per-round drain loop; covers BOTH lockstep and parallel outer loops since
   both call coord_pre_round. Was the dormant 2.AF fix, never merged.

3. handle slab-recycle ABA guard (state.rs + scheduler.rs) — release_handle_slot
   (my round-34 regression) recycled a closed slot even with a thread still
   parked on it, risking a stale-waiter wake when the slot is re-minted. Added
   Scheduler::any_thread_waiting_on; decline to recycle a still-waited slot.

4. vpkpx pixel-pack (vmx.rs) — wrong field mapping (~100% mismatch). Now
   exact canary ppc_emit_altivec.cc:1795 shift/mask (red 6b out[15:10] from
   w[24:19], green out[9:5] from w[14:10], blue out[4:0] from w[7:3]; no
   fabricated alpha bit). +unit test.

5. VFS GDFX attribute plumbing (vfs/*, exports.rs query fns) — VfsEntry now
   carries the real on-disc attribute byte (GDFX dirent +12, canary
   disc_image_device.cc:136/154) instead of inferring directory-ness from
   path shape. Query exports report the real FILE_ATTRIBUTE_* bits. Candidate
   driver of the XamShowDirtyDiscErrorUI gate. +tests.

6. MmGetPhysicalAddress region-aware mirror (exports.rs) — flat 0x1FFFFFFF
   mask missed canary's +0x1000 host_address_offset for 0xE0000000+ mirror
   (memory.cc:2317). Read-only query; proven byte-identical 50M digest. +test.

Investigated and intentionally NOT changed:
- zero-on-recommit: no-op; ours has no region-reuse path (bump allocators,
  free is a stub).
- 32-bit ALU writeback truncation (PPCBUG-020): documented-deliberate; premise
  (MSR.SF=0) is questionable but flipping it is out of scope here.
- KeSetEvent/NtSetEvent return value: ours returns true previous state
  (hardware-faithful); canary returns constant 1 — NOT an ours bug.

sylpheed_n50m golden will need re-baselining (legit behavior change).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-12 14:57:38 +02:00

59 lines
1.8 KiB
Rust

use crate::{VfsDevice, VfsEntry, VfsError};
use std::path::{Path, PathBuf};
/// Host filesystem pass-through device.
pub struct HostPathDevice {
name: String,
root: PathBuf,
}
impl HostPathDevice {
pub fn new(name: impl Into<String>, root: impl AsRef<Path>) -> Self {
Self {
name: name.into(),
root: root.as_ref().to_path_buf(),
}
}
}
impl VfsDevice for HostPathDevice {
fn name(&self) -> &str {
&self.name
}
fn list_root(&self) -> Result<Vec<VfsEntry>, VfsError> {
let mut entries = Vec::new();
for entry in std::fs::read_dir(&self.root)? {
let entry = entry?;
let metadata = entry.metadata()?;
entries.push(VfsEntry {
name: entry.file_name().to_string_lossy().into_owned(),
is_directory: metadata.is_dir(),
size: metadata.len(),
offset: 0,
// Host FS carries no Xbox attribute byte; synthesise the
// DIRECTORY/NORMAL split like canary's HostPathDevice.
attributes: if metadata.is_dir() { 0x10 } else { 0x80 },
});
}
Ok(entries)
}
fn read_file(&self, path: &str) -> Result<Vec<u8>, VfsError> {
let full_path = self.root.join(path);
std::fs::read(&full_path).map_err(VfsError::from)
}
fn stat(&self, path: &str) -> Result<VfsEntry, VfsError> {
let full_path = self.root.join(path);
let metadata = std::fs::metadata(&full_path)?;
Ok(VfsEntry {
name: path.to_string(),
is_directory: metadata.is_dir(),
size: metadata.len(),
offset: 0,
attributes: if metadata.is_dir() { 0x10 } else { 0x80 },
})
}
}