Merge investigate-sub-824aba98/diagnostic (KRNBUG-IO-001)
This commit is contained in:
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"instructions": 50000004,
|
"instructions": 50000000,
|
||||||
"imports": 407416,
|
"imports": 407362,
|
||||||
"unimpl": 0,
|
"unimpl": 0,
|
||||||
"draws": 0,
|
"draws": 0,
|
||||||
"swaps": 2,
|
"swaps": 2,
|
||||||
|
|||||||
@@ -943,6 +943,23 @@ fn nt_read_file(ctx: &mut PpcContext, mem: &GuestMemory, state: &mut KernelState
|
|||||||
};
|
};
|
||||||
|
|
||||||
let total = *size;
|
let total = *size;
|
||||||
|
|
||||||
|
// Synthesized empty files (system partition opens like
|
||||||
|
// `\Device\Harddisk0\partition0` that miss the disc-VFS) act as
|
||||||
|
// NullDevice handles. Canary's `NullFile::ReadSync` returns
|
||||||
|
// `X_STATUS_SUCCESS` with `bytes_read=0` and never touches the buffer
|
||||||
|
// ([null_file.cc:24-31](xenia-canary/src/xenia/vfs/devices/null_file.cc));
|
||||||
|
// Sylpheed's cache loader at `sub_824A9710` reads 1024 B from offset
|
||||||
|
// 2048, expects success, then validates a `"Josh"` magic — falling back
|
||||||
|
// to the recreate path if the buffer (already zeroed by the caller via
|
||||||
|
// `memset(sp+208, 0, 1024)`) doesn't match.
|
||||||
|
if data.is_empty() && total == 0 {
|
||||||
|
write_io_status_block(mem, io_status_block, STATUS_SUCCESS as u32, 0);
|
||||||
|
ctx.gpr[3] = STATUS_SUCCESS;
|
||||||
|
signal_io_completion_event(state, event_handle);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if start_pos >= total {
|
if start_pos >= total {
|
||||||
write_io_status_block(mem, io_status_block, STATUS_END_OF_FILE as u32, 0);
|
write_io_status_block(mem, io_status_block, STATUS_END_OF_FILE as u32, 0);
|
||||||
ctx.gpr[3] = STATUS_END_OF_FILE;
|
ctx.gpr[3] = STATUS_END_OF_FILE;
|
||||||
@@ -3980,6 +3997,44 @@ mod tests {
|
|||||||
assert_eq!(ctx.gpr[3], 0, "STATUS_SUCCESS expected with null event");
|
assert_eq!(ctx.gpr[3], 0, "STATUS_SUCCESS expected with null event");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Synthesized empty files (system-partition opens like
|
||||||
|
/// `\Device\Harddisk0\partition0` that miss the disc-VFS) act as
|
||||||
|
/// canary's `NullDevice`: any `NtReadFile` returns `STATUS_SUCCESS`
|
||||||
|
/// with `information=0` and the buffer untouched. Sylpheed's
|
||||||
|
/// cache-loader at `sub_824A9710` reads 1024 B from offset 2048 then
|
||||||
|
/// validates a `"Josh"` magic — falling back to the recreate path
|
||||||
|
/// when the (caller-zeroed) buffer doesn't match.
|
||||||
|
#[test]
|
||||||
|
fn nt_read_file_synth_empty_file_returns_success_with_zero_bytes() {
|
||||||
|
let (mut ctx, mut mem, mut state) = fresh();
|
||||||
|
let synth = make_file(&mut state, Vec::new());
|
||||||
|
// Pre-fill the buffer with a sentinel; canary's NullDevice never
|
||||||
|
// touches it, so the post-read bytes must be unchanged.
|
||||||
|
let buf: u32 = 0x4000_0100;
|
||||||
|
for i in 0..16u32 {
|
||||||
|
mem.write_u8(buf + i, 0xAB);
|
||||||
|
}
|
||||||
|
let evt = make_event(&mut state);
|
||||||
|
// Read 1024 B from offset 2048 — exactly the cache-catalog read.
|
||||||
|
let offset_ptr: u32 = 0x4000_0080;
|
||||||
|
mem.write_u64(offset_ptr, 2048);
|
||||||
|
ctx.gpr[3] = synth as u64;
|
||||||
|
ctx.gpr[4] = evt as u64;
|
||||||
|
ctx.gpr[7] = 0x4000_0000;
|
||||||
|
ctx.gpr[8] = buf as u64;
|
||||||
|
ctx.gpr[9] = 1024;
|
||||||
|
ctx.gpr[10] = offset_ptr as u64;
|
||||||
|
nt_read_file(&mut ctx, &mut mem, &mut state);
|
||||||
|
assert_eq!(ctx.gpr[3], 0, "STATUS_SUCCESS for synth-empty read");
|
||||||
|
for i in 0..16u32 {
|
||||||
|
assert_eq!(mem.read_u8(buf + i), 0xAB, "buffer at +{} must be untouched", i);
|
||||||
|
}
|
||||||
|
// IOSB.information must be 0 (matches NullFile bytes_read).
|
||||||
|
assert_eq!(mem.read_u32(0x4000_0000), 0, "iosb.status = 0");
|
||||||
|
assert_eq!(mem.read_u32(0x4000_0004), 0, "iosb.information = 0");
|
||||||
|
assert!(event_signaled(&state, evt), "synth-empty read must signal completion");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn nt_write_file_signals_completion_event() {
|
fn nt_write_file_signals_completion_event() {
|
||||||
let (mut ctx, mut mem, mut state) = fresh();
|
let (mut ctx, mut mem, mut state) = fresh();
|
||||||
|
|||||||
Reference in New Issue
Block a user