From 409720b91a58d4eff79d959ca00f65ee4ad4246d Mon Sep 17 00:00:00 2001 From: John Peterson Date: Sat, 29 Nov 2008 08:49:22 +0000 Subject: [PATCH] Wii IPC file handling: Made some comments and changes to try to locate the Mario Kart and SSBB errors, in case they are file handling errors git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@1327 8ced0084-cf51-0410-be5f-012b33b47a6e --- Source/Core/Common/Src/FileUtil.cpp | 9 + Source/Core/Common/Src/FileUtil.h | 1 + Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp | 208 +++++++++++++++--- .../Core/Src/IPC_HLE/WII_IPC_HLE_Device.h | 17 +- .../Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp | 23 +- .../Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.h | 1 + .../Src/IPC_HLE/WII_IPC_HLE_Device_fs.cpp | 19 +- 7 files changed, 230 insertions(+), 48 deletions(-) diff --git a/Source/Core/Common/Src/FileUtil.cpp b/Source/Core/Common/Src/FileUtil.cpp index e3401387ac..60bee857e1 100644 --- a/Source/Core/Common/Src/FileUtil.cpp +++ b/Source/Core/Common/Src/FileUtil.cpp @@ -172,6 +172,15 @@ bool Rename(const char *srcFilename, const char *destFilename) return (rename(srcFilename, destFilename) == 0); } +bool Copy(const char *srcFilename, const char *destFilename) +{ +#ifdef _WIN32 + return CopyFile(srcFilename, destFilename, FALSE); +#else + +#endif +} + std::string GetUserDirectory() { #ifdef _WIN32 diff --git a/Source/Core/Common/Src/FileUtil.h b/Source/Core/Common/Src/FileUtil.h index 74f1ed5592..9f19e0a404 100644 --- a/Source/Core/Common/Src/FileUtil.h +++ b/Source/Core/Common/Src/FileUtil.h @@ -44,6 +44,7 @@ bool CreateDir(const char *filename); bool Delete(const char *filename); bool DeleteDir(const char *filename); bool Rename(const char *srcFilename, const char *destFilename); +bool Copy(const char *srcFilename, const char *destFilename); u64 GetSize(const char *filename); std::string GetUserDirectory(); bool CreateEmptyFile(const char *filename); diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp index a9e9a79275..af655e8bae 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE.cpp @@ -15,6 +15,31 @@ // Official SVN repository and contact information can be found at // http://code.google.com/p/dolphin-emu/ + + +// ======================================================= +// File description +// ------------- +/* This is the main Wii IPC file that handles all incoming IPC calls and directs them + to the right function. + + IPC basics: + + Return values for file handles: All IPC calls will generate a return value to 0x04, + in case of success they are + Open: DeviceID + Close: 0 + Read: Bytes read + Write: Bytes written + Seek: Seek position + Ioctl: 0 (in addition to that there may be messages to the out buffers) + Ioctlv: 0 (in addition to that there may be messages to the out buffers) + They will also generate a true or false return for UpdateInterrupts() in WII_IPC.cpp. */ +// ============= + + + + #include #include #include @@ -32,6 +57,8 @@ #include "WII_IPC_HLE_Device_usb.h" #include "WII_IPC_HLE_Device_sdio_slot0.h" +#include "FileUtil.h" // For Copy +#include "../Core.h" #include "../HW/CPU.h" #include "../HW/Memmap.h" #include "../HW/WII_IPC.h" @@ -59,6 +86,10 @@ TDeviceMap g_DeviceMap; u32 g_LastDeviceID = 0x13370000; + +// =================================================== +/* General IPC functions */ +// ---------------- void Init() { _dbg_assert_msg_(WII_IPC, g_DeviceMap.empty(), "DeviceMap isnt empty on init"); @@ -108,7 +139,13 @@ void DeleteDeviceByID(u32 ID) g_DeviceMap.erase(ID); } } +// ================ + +// =================================================== +/* This is called from COMMAND_OPEN_DEVICE. Here we either create a new device + or open a new file handle. */ +// ---------------- IWII_IPC_HLE_Device* CreateDevice(u32 _DeviceID, const std::string& _rDeviceName) { // scan device name and create the right one ^^ @@ -162,8 +199,8 @@ IWII_IPC_HLE_Device* CreateDevice(u32 _DeviceID, const std::string& _rDeviceName } } else - { - LOGV(WII_IPC_FILEIO, 0, "FS: New pDevice %s", _rDeviceName.c_str()); + { + LOGV(WII_IPC_FILEIO, 0, "IOP: Create Device %s", _rDeviceName.c_str()); pDevice = new CWII_IPC_HLE_Device_FileIO(_DeviceID, _rDeviceName); } @@ -174,6 +211,11 @@ std::list m_Ack; std::queue > m_ReplyQueue; void ExecuteCommand(u32 _Address); + + +// =================================================== +/* This generates some kind of acknowledgment. This function is called from? */ +// ---------------- bool AckCommand(u32 _Address) { Debugger::PrintCallstack(LogTypes::WII_IPC_HLE); @@ -196,6 +238,28 @@ bool AckCommand(u32 _Address) return true; } +// Let the game read the setting.txt file +void CopySettingsFile(std::string DeviceName) +{ + std::string Source; + if(Core::GetStartupParameter().bNTSC) + Source = "Sys/Wii/setting-usa.txt"; + else + Source = "Sys/Wii/setting-eur.txt"; + + std::string Target = "User/Wii" + DeviceName; + + if (File::Copy(Source.c_str(), Target.c_str())) + { + LOG(WII_IPC_FILEIO, "FS: Copied %s to %s", Source.c_str(), Target.c_str()); + } + else + { + LOG(WII_IPC_FILEIO, "Could not copy %s to %s", Source.c_str(), Target.c_str()); + PanicAlert("Could not copy %s to %s", Source.c_str(), Target.c_str()); + } +} + void ExecuteCommand(u32 _Address) { @@ -223,21 +287,20 @@ void ExecuteCommand(u32 _Address) { case COMMAND_OPEN_DEVICE: { - // HLE - Create a new HLE device + LOG(WII_IPC_FILEIO, "==================================================================="); + /* Create a new HLE device. The Mode and DeviceName is given to us but we + generate a DeviceID to be used for access to this device until it is Closed. */ std::string DeviceName; Memory::GetString(DeviceName, Memory::Read_U32(_Address + 0xC)); - u32 Mode = Memory::Read_U32(_Address+0x10); + // The game may try to read setting.txt here, in that case copy it so it can read it + if(DeviceName.find("setting.txt") != std::string::npos) CopySettingsFile(DeviceName); + + u32 Mode = Memory::Read_U32(_Address + 0x10); u32 DeviceID = GetDeviceIDByName(DeviceName); - /* TEMPORARY SOLUTION: For some reason no file was written after a ReOpen in - Mario Galaxy and Mario Kart Wii so I had to do a Open instead */ - if (DeviceID == 0 - || DeviceName.find(".bin") != std::string::npos // Do Open instead for common - || DeviceName.find(".dat") != std::string::npos // save game file types - || DeviceName.find(".vff") != std::string::npos - || DeviceName.find(".mod") != std::string::npos - ) + /* The device has already been opened and was not closed, reuse the same DeviceID. */ + if (DeviceID == 0) { // create the new device // alternatively we could pre create all devices and put them in a directory tree structure @@ -248,36 +311,80 @@ void ExecuteCommand(u32 _Address) g_LastDeviceID++; GenerateReply = pDevice->Open(_Address, Mode); - LOG(WII_IPC_HLE, "IOP: Open (Device=%s, Mode=%i)", pDevice->GetDeviceName().c_str(), Mode); + if(pDevice->GetDeviceName().find("/dev/") == std::string::npos + || pDevice->GetDeviceName().c_str() == std::string("/dev/fs")) + { + LOG(WII_IPC_FILEIO, "IOP: Open (Device=%s, DeviceID=%08x, Mode=%i, GenerateReply=%i)", + pDevice->GetDeviceName().c_str(), CurrentDeviceID, Mode, (int)GenerateReply); + } + else + { + LOG(WII_IPC_HLE, "IOP: Open (Device=%s, Mode=%i)", + pDevice->GetDeviceName().c_str(), Mode); + } } else { #ifdef LOGGING IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID); #endif + /* If we return -6 here after a Open > Failed > CREATE_FILE > ReOpen call + sequence Mario Galaxy and Mario Kart Wii will not start writing to the file, + it will just (seemingly) wait for one or two seconds and then give an error + message. So I'm trying to return the DeviceID instead to make it write to the file. + (Which was most likely the reason it created the file in the first place.) */ - // we have already opened this device - Memory::Write_U32(u32(-6), _Address + 4); - GenerateReply = true; + if(DeviceName.find("/dev/") == std::string::npos) + { + LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)", + pDevice->GetDeviceName().c_str(), DeviceID, Mode); - LOG(WII_IPC_HLE, "IOP: ReOpen (Device=%s, Mode=%i)", pDevice->GetDeviceName().c_str(), Mode); + u32 Mode = Memory::Read_U32(_Address + 0x10); + + /* We may not have a file handle at this point, in Mario Kart I got a + Open > Failed > ... other stuff > ReOpen call sequence, in that case + we have no file and no file handle, so we call Open again to basically + get a -106 error so that the game call CreateFile and then ReOpen again. */ + if(pDevice->ReturnFileHandle()) + Memory::Write_U32(DeviceID, _Address + 4); + else + GenerateReply = pDevice->Open(_Address, Mode); + } + else + { + LOG(WII_IPC_HLE, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)", + pDevice->GetDeviceName().c_str(), pDevice->GetDeviceID(), Mode); + // We have already opened this device, return -6 + Memory::Write_U32(u32(-6), _Address + 4); + } + GenerateReply = true; } } break; case COMMAND_CLOSE_DEVICE: { - u32 DeviceID = Memory::Read_U32(_Address+8); + u32 DeviceID = Memory::Read_U32(_Address + 8); IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(DeviceID); if (pDevice != NULL) { pDevice->Close(_Address); - LOG(WII_IPC_HLE, "IOP: Close (Device=%s ID=0x%08x)", pDevice->GetDeviceName().c_str(), DeviceID); + /* Write log + if(pDevice->GetDeviceName().find("/dev/") == std::string::npos + || pDevice->GetDeviceName().c_str() == std::string("/dev/fs")) { + LOG(WII_IPC_FILEIO, "IOP: Close (Device=%s ID=0x%08x)", + pDevice->GetDeviceName().c_str(), DeviceID); + LOG(WII_IPC_FILEIO, "==================================================================="); + } else { + LOG(WII_IPC_HLE, "IOP: Close (Device=%s ID=0x%08x)", + pDevice->GetDeviceName().c_str(), DeviceID); }*/ + /* Delete the device when CLOSE is called, this does not effect + GenerateReply() for any other purpose than the logging because + it's a true / false only function */ DeleteDeviceByID(DeviceID); - GenerateReply = true; } } @@ -334,24 +441,52 @@ void ExecuteCommand(u32 _Address) break; } - // seems that the org hw overwrites the command after it has been executed - Memory::Write_U32(8, _Address); + /* It seems that the original hardware overwrites the command after it has been + executed. We write 8 which is not any valid command. */ + Memory::Write_U32(8, _Address); + // Generate a reply to the IPC command if (GenerateReply) { - u32 DeviceID = Memory::Read_U32(_Address+8); - + // Get device id + u32 DeviceID = Memory::Read_U32(_Address + 8); IWII_IPC_HLE_Device* pDevice = NULL; + + // Get the device from the device map if (g_DeviceMap.find(DeviceID) != g_DeviceMap.end()) pDevice = g_DeviceMap[DeviceID]; if (pDevice != NULL) - m_ReplyQueue.push(std::pair(_Address, pDevice->GetDeviceName())); + { + /* Write log + u32 Mode = Memory::Read_U32(_Address + 0x10); + if(pDevice->GetDeviceName().find("/dev/") == std::string::npos + || pDevice->GetDeviceName().c_str() == std::string("/dev/fs")) + { + LOGV(WII_IPC_FILEIO, 1, "IOP: GenerateReply (Device=%s, DeviceID=%08x, Mode=%i)", + pDevice->GetDeviceName().c_str(), pDevice->GetDeviceID(), Mode); + } + else + { + LOG(WII_IPC_HLE, "IOP: GenerateReply (Device=%s, DeviceID=%08x, Mode=%i)", + pDevice->GetDeviceName().c_str(), pDevice->GetDeviceID(), Mode); + } */ + + // Write reply, this will later be executed in Update() + m_ReplyQueue.push(std::pair(_Address, pDevice->GetDeviceName())); + } else - m_ReplyQueue.push(std::pair(_Address, "unknown")); + { + m_ReplyQueue.push(std::pair(_Address, "unknown")); + } } } + +// =================================================== +/* This is called continouosly and WII_IPCInterface::IsReady() is controlled from + WII_IPC.cpp. */ +// ---------------- void Update() { if (WII_IPCInterface::IsReady()) @@ -368,21 +503,38 @@ void Update() ++itr; } - // check if we have to execute an acknowledged command + // Check if we have to execute an acknowledge command... if (!m_ReplyQueue.empty()) { - LOGV(WII_IPC_HLE, 1, "-- Generate Reply %s (0x%08x)", m_ReplyQueue.front().second.c_str(), m_ReplyQueue.front().first); + /* Write one log for files and one for devices + if(m_ReplyQueue.front().second.find("unknown") == std::string::npos + && (m_ReplyQueue.front().second.find("/dev/") == std::string::npos + || m_ReplyQueue.front().second.c_str() == std::string("/dev/fs"))) + { + LOGV(WII_IPC_FILEIO, 1, "-- Update() Reply %s (0x%08x)", + m_ReplyQueue.front().second.c_str(), m_ReplyQueue.front().first); + } + else + { + LOGV(WII_IPC_HLE, 1, "-- Update() Reply %s (0x%08x)", + m_ReplyQueue.front().second.c_str(), m_ReplyQueue.front().first); + } */ + + WII_IPCInterface::GenerateReply(m_ReplyQueue.front().first); m_ReplyQueue.pop(); return; } + // ...no we don't, we can now execute the IPC command if (m_ReplyQueue.empty() && !m_Ack.empty()) { u32 _Address = m_Ack.front(); m_Ack.pop_front(); ExecuteCommand(_Address); LOGV(WII_IPC_HLE, 1, "-- Generate Ack (0x%08x)", _Address); + + // Go back to WII_IPC.cpp and generate an acknowledgement WII_IPCInterface::GenerateAck(_Address); } } diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device.h index 4a4eae4688..80222d859a 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device.h @@ -47,6 +47,17 @@ public: virtual u32 Update() { return 0; } + virtual bool ReturnFileHandle() { return false; } + //FILE* ReturnFileHandle() const { return m_pFileHandle; } + + +private: + + // STATE_TO_SAVE + std::string m_Name; + u32 m_DeviceID; + + protected: // =================================================== @@ -183,12 +194,6 @@ protected: } } -private: - - // STATE_TO_SAVE - std::string m_Name; - u32 m_DeviceID; - }; #endif diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp index e75f836bd9..8c6f08cc51 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.cpp @@ -21,6 +21,9 @@ #include "WII_IPC_HLE_Device_FileIO.h" +// =================================================== +/* This is used by several of the FileIO and /dev/fs/ functions */ +// ---------------- std::string HLE_IPC_BuildFilename(const char* _pFilename, int _size) { char Buffer[128]; @@ -37,7 +40,7 @@ std::string HLE_IPC_BuildFilename(const char* _pFilename, int _size) /// ---------------------------------------------------------------- - +// The FileIO class CWII_IPC_HLE_Device_FileIO::CWII_IPC_HLE_Device_FileIO(u32 _DeviceID, const std::string& _rDeviceName ) @@ -59,7 +62,8 @@ CWII_IPC_HLE_Device_FileIO::~CWII_IPC_HLE_Device_FileIO() bool CWII_IPC_HLE_Device_FileIO::Close(u32 _CommandAddress) { - LOG(WII_IPC_FILEIO, "FileIO: Close %s", GetDeviceName().c_str()); + u32 DeviceID = Memory::Read_U32(_CommandAddress + 8); + LOG(WII_IPC_FILEIO, "FileIO: Close %s (DeviceID=%08x)", GetDeviceName().c_str(), DeviceID); // Close always return 0 for success Memory::Write_U32(0, _CommandAddress + 4); @@ -70,7 +74,7 @@ CWII_IPC_HLE_Device_FileIO::Close(u32 _CommandAddress) bool CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode) { - LOG(WII_IPC_FILEIO, "==================================================================="); + //LOG(WII_IPC_FILEIO, "==================================================================="); u32 ReturnValue = 0; @@ -113,7 +117,7 @@ CWII_IPC_HLE_Device_FileIO::Open(u32 _CommandAddress, u32 _Mode) } Memory::Write_U32(ReturnValue, _CommandAddress+4); - LOG(WII_IPC_FILEIO, "==================================================================="); + //LOG(WII_IPC_FILEIO, "==================================================================="); return true; } @@ -174,7 +178,7 @@ CWII_IPC_HLE_Device_FileIO::Write(u32 _CommandAddress) { u32 ReturnValue = 0; u32 Address = Memory::Read_U32(_CommandAddress +0xC); - u32 Size = Memory::Read_U32(_CommandAddress +0x10); + u32 Size = Memory::Read_U32(_CommandAddress +0x10); LOG(WII_IPC_FILEIO, "FileIO: Write Addr: 0x%08x Size: %i (Device=%s)", Address, Size, GetDeviceName().c_str()); @@ -233,3 +237,12 @@ CWII_IPC_HLE_Device_FileIO::IOCtl(u32 _CommandAddress) return true; } + +bool +CWII_IPC_HLE_Device_FileIO::ReturnFileHandle() +{ + if(m_pFileHandle == NULL) + return false; + else + return true; +} \ No newline at end of file diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.h index 9deb3b65c2..1b12f9f2ce 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_FileIO.h @@ -34,6 +34,7 @@ public: bool Read(u32 _CommandAddress); bool Write(u32 _CommandAddress); bool IOCtl(u32 _CommandAddress); + bool ReturnFileHandle(); private: diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_fs.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_fs.cpp index 98844de7f9..2ff5057de5 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_fs.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_fs.cpp @@ -71,7 +71,8 @@ bool CWII_IPC_HLE_Device_fs::Open(u32 _CommandAddress, u32 _Mode) bool CWII_IPC_HLE_Device_fs::IOCtl(u32 _CommandAddress) { - LOG(WII_IPC_FILEIO, "FS: IOCtl (Device=%s)", GetDeviceName().c_str()); + //u32 DeviceID = Memory::Read_U32(_CommandAddress + 8); + //LOG(WII_IPC_FILEIO, "FS: IOCtl (Device=%s, DeviceID=%08x)", GetDeviceName().c_str(), DeviceID); u32 Parameter = Memory::Read_U32(_CommandAddress + 0xC); u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10); @@ -354,7 +355,7 @@ s32 CWII_IPC_HLE_Device_fs::ExecuteCommand(u32 _Parameter, u32 _BufferIn, u32 _B case CREATE_FILE: { - LOGV(WII_IPC_FILEIO, 0, "=============================================================="); + //LOGV(WII_IPC_FILEIO, 0, "=============================================================="); _dbg_assert_(WII_IPC_FILEIO, _BufferOutSize == 0); u32 Addr = _BufferIn; @@ -369,12 +370,12 @@ s32 CWII_IPC_HLE_Device_fs::ExecuteCommand(u32 _Parameter, u32 _BufferIn, u32 _B u8 Attributes = Memory::Read_U8(Addr); Addr++; LOGV(WII_IPC_FILEIO, 0, "FS: CreateFile %s", Filename.c_str()); - LOG(WII_IPC_FILEIO, " OwnerID: 0x08%x", OwnerID); - LOG(WII_IPC_FILEIO, " GroupID: 0x04%x", GroupID); - LOG(WII_IPC_FILEIO, " OwnerPerm: 0x02%x", OwnerPerm); - LOG(WII_IPC_FILEIO, " GroupPerm: 0x02%x", GroupPerm); - LOG(WII_IPC_FILEIO, " OtherPerm: 0x02%x", OtherPerm); - LOG(WII_IPC_FILEIO, " Attributes: 0x02%x", Attributes); + LOG(WII_IPC_FILEIO, " OwnerID: 0x%08x", OwnerID); + LOG(WII_IPC_FILEIO, " GroupID: 0x%04x", GroupID); + LOG(WII_IPC_FILEIO, " OwnerPerm: 0x%02x", OwnerPerm); + LOG(WII_IPC_FILEIO, " GroupPerm: 0x%02x", GroupPerm); + LOG(WII_IPC_FILEIO, " OtherPerm: 0x%02x", OtherPerm); + LOG(WII_IPC_FILEIO, " Attributes: 0x%02x", Attributes); // check if the file allready exist if (File::Exists(Filename.c_str())) @@ -401,7 +402,7 @@ s32 CWII_IPC_HLE_Device_fs::ExecuteCommand(u32 _Parameter, u32 _BufferIn, u32 _B PanicAlert("CWII_IPC_HLE_Device_fs::IOCtl: ni 0x%x", _Parameter); break; } - LOGV(WII_IPC_FILEIO, 0, "=============================================================="); + //LOGV(WII_IPC_FILEIO, 0, "=============================================================="); return FS_RESULT_FATAL; }