From 81ebec368bd7c8b53661fe4da4db83ee433f0811 Mon Sep 17 00:00:00 2001 From: Yaya48 Date: Tue, 6 Oct 2026 19:44:05 +0200 Subject: [PATCH] IOS LLE: IPC trace prints filesystem IOCTL paths (StarletOS phase 11 M1e) Co-Authored-By: Claude Opus 5.5 --- Source/Core/Core/HW/WII_IPC.cpp | 51 ++++++++++++++++++++++++++++++--- docs/StarletOS_Checkpoint.json | 11 +++++-- docs/StarletOS_Handoff.md | 13 +++++++++ 3 files changed, 69 insertions(+), 6 deletions(-) diff --git a/Source/Core/Core/HW/WII_IPC.cpp b/Source/Core/Core/HW/WII_IPC.cpp index 8ff62c5526..3c1d5c7fc5 100644 --- a/Source/Core/Core/HW/WII_IPC.cpp +++ b/Source/Core/Core/HW/WII_IPC.cpp @@ -3,6 +3,7 @@ #include "Core/HW/WII_IPC.h" +#include #include #include @@ -148,10 +149,11 @@ void WiiIPC::Shutdown() namespace { -// StarletOS phase 11 (proposal L2): with DOLPHIN_IPC_TRACE=1 while the original IOS runs on the -// emulated Starlet, each IPC request Broadway posts (X1) and each reply Starlet posts (Y1) is -// logged with its metadata only: the command, the descriptor and the five argument words (an -// OPEN's path), then the reply's result. Buffer contents are never read. +// StarletOS phase 11 (proposal L2): with DOLPHIN_IPC_TRACE=1 while the emulated Starlet runs +// (the original IOS or a bootstrap ELF), each IPC request Broadway posts (X1) and each reply +// Starlet posts (Y1) is logged with its metadata only: the command, the descriptor and the five +// argument words (an OPEN's path), then the reply's result. Proposal M1e adds the paths of the +// filesystem IOCTLs. No other buffer content is read. bool IPCTraceEnabled() { static const bool enabled = [] { @@ -161,6 +163,45 @@ bool IPCTraceEnabled() return enabled; } +// A NUL-terminated absolute path of printable bytes in a 64-byte field, or "" otherwise. +std::string TracePath(Memory::MemoryManager& memory, u32 address) +{ + if (memory.GetPointerForRange(address, 64) == nullptr) + return {}; + const std::string path = memory.GetString(address, 64); + if (path.empty() || path.size() >= 64 || path[0] != '/' || + !std::ranges::all_of(path, [](char c) { return c >= 0x20 && c < 0x7f; })) + return {}; + return path; +} + +// The paths a filesystem request names, by its input shape: a 64-byte path (DELETE, GET_ATTR), +// a 76-byte attribute record with the path at +6 (CREATE_DIR, CREATE_FILE, SET_ATTR), two +// 64-byte paths (RENAME), or an IOCTLV whose first input vector is a 64-byte path (READ_DIR, +// GET_USAGE). " F -" when the field holds no valid path. +std::string TraceFilesystemPaths(Memory::MemoryManager& memory, u32 command, const u32* arg) +{ + const auto field = [&memory](u32 address) { + const std::string path = TracePath(memory, address); + return path.empty() ? std::string("-") : path; + }; + if (command == 6) + { + if (arg[2] == 0x40) + return " F " + field(arg[1]); + if (arg[2] == 0x4c) + return " F " + field(arg[1] + 6); + if (arg[2] == 0x80) + return " F " + field(arg[1]) + " > " + field(arg[1] + 0x40); + } + else if (command == 7 && arg[1] != 0 && memory.GetPointerForRange(arg[3], 8) != nullptr && + memory.Read_U32(arg[3] + 4) == 0x40) + { + return " F " + field(memory.Read_U32(arg[3])); + } + return {}; +} + void TraceIPCRequest(Core::System& system, u32 address) { auto& memory = system.GetMemory(); @@ -177,6 +218,8 @@ void TraceIPCRequest(Core::System& system, u32 address) std::string path; if (command == 1 && memory.GetPointerForRange(arg[0], 64) != nullptr) path = " P " + memory.GetString(arg[0], 64); + else + path = TraceFilesystemPaths(memory, command, arg); NOTICE_LOG_FMT(WII_IPC, "IPCTRACE RQ {:08x} C {} FD {} A {:08x} {:08x} {:08x} {:08x} {:08x}{}", address, command, static_cast(fd), arg[0], arg[1], arg[2], arg[3], arg[4], path); diff --git a/docs/StarletOS_Checkpoint.json b/docs/StarletOS_Checkpoint.json index d3f11fbf70..cf46e49348 100644 --- a/docs/StarletOS_Checkpoint.json +++ b/docs/StarletOS_Checkpoint.json @@ -48,8 +48,8 @@ }, { "path": "Source/Core/Core/HW/WII_IPC.cpp", - "sha256": "e216d272f7653b4650481a3335989a86550eee3d90aa7e6c7f06bb1ce87822e1", - "bytes": 21443 + "sha256": "c3faf948533d494243caa229730dac8a8161144647aad22d219f1b4c9f727030", + "bytes": 23116 }, { "path": "Source/Core/Core/IOS/Starlet/ARMCore.cpp", @@ -144,6 +144,13 @@ "Source/Core/Core/IOS/Starlet/StarletMemory.cpp", "Source/Core/Core/IOS/Starlet/StarletMemory.h" ] + }, + { + "recordedAt": "2026-10-06", + "purpose": "StarletOS Phase 11 proposal M1e: the IPC trace also prints the paths named by filesystem IOCTLs (64-byte path, 76-byte record at +6, rename pair, first IOCTLV vector of 64 bytes); paths only", + "files": [ + "Source/Core/Core/HW/WII_IPC.cpp" + ] } ] } diff --git a/docs/StarletOS_Handoff.md b/docs/StarletOS_Handoff.md index cef65d341a..90e8030d2b 100644 --- a/docs/StarletOS_Handoff.md +++ b/docs/StarletOS_Handoff.md @@ -159,3 +159,16 @@ with Revolution instead of the original IOS, to see where Broadway stops. Next: the companion's M1b (smoke test with the variable, no window) and M1c (the user launches the Mii Channel under Revolution in the X11 window). + +## Filesystem paths in the IPC trace — 2026-10-06 + +Companion proposal M1e (approved): under Revolution in the window the System +Menu's save before a launch got -106 on its second CREATE_DIR, and no trace +had the path. `IPCTRACE RQ` lines now end with ` F ` for IOCTLs whose +input is a 64-byte path (DELETE, GET_ATTR), a 76-byte attribute record (path +at +6: CREATE_DIR, CREATE_FILE, SET_ATTR) or two paths (` F a > b`, RENAME), +and for IOCTLVs whose first input vector is 64 bytes (READ_DIR, GET_USAGE); +` F -` when that field holds no valid path. Read from memory when X1 is +rung, like the OPEN path; nothing else of the buffers. Checked headless under +Revolution: `/shared2/test2`, `/title/00000001/00000002/data/cache.dat`, the +GET_USAGE directories. 95 Starlet tests passed.